Line data Source code
1 : /*
2 : * Copyright (c) 2013-2024 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : * Copyright (c) 2024 Elena Zizganova
5 : */
6 :
7 :
8 : #include "base/os.h"
9 : #include <arpa/inet.h>
10 : #include <netinet/in.h>
11 :
12 : #include "base/address_util.h"
13 : #include "route/route.h"
14 :
15 : #include "cmn/agent_cmn.h"
16 : #include "init/agent_param.h"
17 : #include "oper/ecmp.h"
18 : #include "oper/interface_common.h"
19 : #include "oper/metadata_ip.h"
20 : #include "oper/nexthop.h"
21 : #include "oper/route_common.h"
22 : #include "oper/path_preference.h"
23 : #include "oper/vrf.h"
24 : #include "oper/sg.h"
25 : #include "oper/global_vrouter.h"
26 : #include "oper/operdb_init.h"
27 : #include "oper/tunnel_nh.h"
28 : #include "oper/bgp_as_service.h"
29 : #include "oper/health_check.h"
30 :
31 : #include "filter/packet_header.h"
32 : #include "filter/acl.h"
33 :
34 : #include "pkt/proto.h"
35 : #include "pkt/proto_handler.h"
36 : #include "pkt/pkt_handler.h"
37 : #include "pkt/flow_mgmt.h"
38 : #include "pkt/flow_proto.h"
39 : #include "pkt/pkt_sandesh_flow.h"
40 : #include "cmn/agent_stats.h"
41 : #include <vrouter/ksync/flowtable_ksync.h>
42 : #include <vrouter/ksync/ksync_init.h>
43 :
44 : #include <services/services_init.h>
45 : #include <services/metadata_proxy.h>
46 :
47 : const Ip4Address PktFlowInfo::kDefaultIpv4;
48 : const Ip6Address PktFlowInfo::kDefaultIpv6;
49 :
50 15 : static void LogError(const PktInfo *pkt, const PktFlowInfo *flow_info,
51 : const char *str) {
52 15 : if (pkt->family == Address::INET || pkt->family == Address::INET6) {
53 15 : FLOW_TRACE(DetailErr, pkt->agent_hdr.cmd_param, pkt->agent_hdr.ifindex,
54 : pkt->agent_hdr.vrf, pkt->ip_saddr.to_string(),
55 : pkt->ip_daddr.to_string(), str, flow_info->l3_flow);
56 : } else {
57 0 : assert(0);
58 : }
59 15 : }
60 :
61 : // VRF changed for the packet. Treat it as Layer3 packet from now.
62 : // Note:
63 : // Features like service chain are supported only for Layer3. Bridge
64 : // entries are not leaked into the new VRF and any bridge entry lookup
65 : // into new VRF will also Fail. So, even VRouter will treat packets
66 : // as L3 after VRF transaltion.
67 1 : void PktFlowInfo::ChangeVrf(const PktInfo *pkt, PktControlInfo *info,
68 : const VrfEntry *vrf) {
69 1 : l3_flow = true;
70 1 : }
71 :
72 341 : void PktFlowInfo::UpdateRoute(const AgentRoute **rt, const VrfEntry *vrf,
73 : const IpAddress &ip, const MacAddress &mac,
74 : FlowRouteRefMap &ref_map) {
75 341 : if (*rt != NULL && (*rt)->GetTableType() != Agent::BRIDGE)
76 47 : ref_map[(*rt)->vrf_id()] = RouteToPrefixLen(*rt);
77 341 : if (l3_flow) {
78 263 : *rt = FlowEntry::GetUcRoute(vrf, ip);
79 : } else {
80 78 : *rt = FlowEntry::GetL2Route(vrf, mac);
81 78 : if (*rt != NULL) {
82 : const BridgeRouteEntry *bridge_rt =
83 69 : dynamic_cast<const BridgeRouteEntry *>(*rt);
84 69 : if (bridge_rt != NULL) {
85 69 : BridgeRouteEntry *temp = const_cast<BridgeRouteEntry*>(bridge_rt);
86 69 : AgentRoute *route = FlowEntry::GetUcRoute(vrf, ip);
87 : const InetUnicastRouteEntry *inet_rt =
88 69 : dynamic_cast<const InetUnicastRouteEntry *>(route);
89 69 : if (inet_rt != NULL) {
90 61 : temp->set_prefix_length(inet_rt->prefix_length());
91 : } else {
92 8 : temp->set_prefix_length(-1); // -1 = 255 invalid plen for both v4 and v6
93 : }
94 : }
95 : }
96 : }
97 341 : if (*rt == NULL)
98 90 : ref_map[vrf->vrf_id()] = 0;
99 341 : }
100 :
101 55 : uint8_t PktFlowInfo::RouteToPrefixLen(const AgentRoute *route) {
102 55 : if (route == NULL) {
103 4 : return 0;
104 : }
105 :
106 : const InetUnicastRouteEntry *inet_rt =
107 51 : dynamic_cast<const InetUnicastRouteEntry *>(route);
108 51 : if (inet_rt != NULL) {
109 51 : return inet_rt->prefix_length();
110 : }
111 :
112 : const BridgeRouteEntry *l2_rt =
113 0 : dynamic_cast<const BridgeRouteEntry *>(route);
114 0 : if (l2_rt) {
115 0 : return l2_rt->prefix_address().bit_len();
116 : }
117 :
118 0 : assert(0);
119 : return -1;
120 : }
121 :
122 : // Traffic from IPFabric to VM is treated as EGRESS
123 : // Any other traffic is INGRESS
124 202 : bool PktFlowInfo::ComputeDirection(const Interface *intf) {
125 202 : bool ret = true;
126 202 : if (intf->type() == Interface::PHYSICAL) {
127 66 : ret = false;
128 : }
129 202 : return ret;
130 : }
131 :
132 :
133 : // Get VRF corresponding to a NH
134 4 : static uint32_t NhToVrf(const NextHop *nh) {
135 4 : const VrfEntry *vrf = NULL;
136 4 : if (nh == NULL)
137 0 : return VrfEntry::kInvalidIndex;
138 4 : switch (nh->GetType()) {
139 0 : case NextHop::COMPOSITE: {
140 0 : vrf = (static_cast<const CompositeNH *>(nh))->vrf();
141 0 : break;
142 : }
143 4 : case NextHop::NextHop::INTERFACE: {
144 : const Interface *intf =
145 4 : (static_cast<const InterfaceNH *>(nh))->GetInterface();
146 4 : if (intf)
147 4 : vrf = intf->vrf();
148 4 : break;
149 : }
150 0 : default:
151 0 : break;
152 : }
153 :
154 4 : if (vrf == NULL)
155 0 : return VrfEntry::kInvalidIndex;
156 :
157 4 : if (!vrf->IsActive())
158 0 : return VrfEntry::kInvalidIndex;
159 :
160 4 : return vrf->vrf_id();
161 : }
162 :
163 66 : static bool IsVgwOrVmInterface(const Interface *intf) {
164 66 : if (intf->type() == Interface::VM_INTERFACE)
165 66 : return true;
166 :
167 0 : if (intf->type() == Interface::INET) {
168 0 : const InetInterface *inet = static_cast<const InetInterface *>(intf);
169 0 : if (inet->sub_type() == InetInterface::SIMPLE_GATEWAY)
170 0 : return true;
171 : }
172 0 : return false;
173 : }
174 :
175 161 : static bool PickEcmpMember(const Agent *agent, const NextHop **nh,
176 : const PktInfo *pkt, PktFlowInfo *info,
177 : const EcmpLoadBalance &ecmp_load_balance) {
178 161 : const CompositeNH *comp_nh = dynamic_cast<const CompositeNH *>(*nh);
179 : // ECMP supported only if composite-type is ECMP or LOCAL_ECMP or LU_ECMP
180 276 : if (comp_nh == NULL ||
181 115 : (comp_nh->composite_nh_type() != Composite::ECMP &&
182 53 : comp_nh->composite_nh_type() != Composite::LOCAL_ECMP &&
183 0 : comp_nh->composite_nh_type() != Composite::LU_ECMP)) {
184 99 : info->out_component_nh_idx = CompositeNH::kInvalidComponentNHIdx;
185 99 : return true;
186 : }
187 62 : info->ecmp = true;
188 : // If this is flow revluation,
189 : // 1. If flow transitions from non-ECMP to ECMP, the old-nh will be first
190 : // member in the composite-nh. So set affinity-nh index to 0
191 : // 2. If flow is already ECMP, the out-component-nh-idx is retained as
192 : // affinity
193 62 : if (pkt->type == PktType::MESSAGE &&
194 6 : info->out_component_nh_idx == CompositeNH::kInvalidComponentNHIdx) {
195 2 : info->out_component_nh_idx = 0;
196 : }
197 :
198 : // Compute out_component_nh_idx,
199 : // 1. In case of non-ECMP to ECMP transition, component-nh-index and
200 : // in-turn affinity-nh is set to 0
201 : // 2. In case of MESSAGE, the old component-nh-index is used as affinity-nh
202 : // 3. In case of new flows, new index is allocated
203 : //
204 : // If affinity-nh is set but points to deleted NH, then affinity is ignored
205 : // and new index is allocated
206 62 : info->out_component_nh_idx =
207 62 : comp_nh->PickMember(pkt->hash(agent, ecmp_load_balance),
208 : info->out_component_nh_idx,
209 62 : info->ingress);
210 62 : *nh = comp_nh->GetNH(info->out_component_nh_idx);
211 : // nh can be NULL if out_component_nh_index is invalid
212 : // this index is returned as invalid from the above function
213 : // when composite nexthop is having inactive/NULL
214 : // component nexthops or no local nexthops if traffic
215 : // is coming from fabric
216 62 : if ((*nh) && ((*nh)->GetType() == NextHop::COMPOSITE)) {
217 : // this is suboptimal solution to pick component NH in
218 : // 2 level ecmp. ideally hashing should be independent for
219 : // VPN level ecmp and label inet ecmp. label inet ecmp relies on
220 : // underlay node information which is not available in packet
221 : // if pkt originates from local VM, so using same ecmp index
222 : // to get component nh for both vpn and label inet ecmp
223 : // this results in either (0,0) or (1,1)
224 : // TODO:find optimum solution to address this
225 0 : const CompositeNH *comp_composite_nh =
226 : static_cast<const CompositeNH *>(*nh);
227 0 : if (comp_composite_nh->composite_nh_type() == Composite::LU_ECMP) {
228 0 : *nh = comp_composite_nh->GetNH(info->out_component_nh_idx);
229 : }
230 : }
231 :
232 : // TODO: Should we re-hash here?
233 62 : if (!(*nh) || (*nh)->IsActive() == false) {
234 0 : return false;
235 : }
236 62 : return true;
237 : }
238 :
239 : // Get interface from a NH. Also, decode ECMP information from NH
240 : // Responsible to set following fields,
241 : // out->nh_ : outgoing Nexthop Index. Will also be used to set reverse flow-key
242 : // out->vrf_ : VRF to be used after flow processing. Value set here can
243 : // potentially get overridden later
244 : // TODO: Revisit the use of vrf_, dest_vrf and nat_vrf
245 : // force_vmport means, we want destination to be VM_INTERFACE only
246 : // This is to avoid routing across fabric interface itself
247 161 : static bool NhDecode(const Agent *agent, const NextHop *nh, const PktInfo *pkt,
248 : PktFlowInfo *info, PktControlInfo *in,
249 : PktControlInfo *out, bool force_vmport,
250 : const EcmpLoadBalance &ecmp_load_balance) {
251 161 : bool ret = true;
252 :
253 161 : if (!nh->IsActive())
254 0 : return false;
255 :
256 : // If nh is Composite, pick the ECMP first. The nh index and vrf used
257 : // in reverse flow will depend on the ECMP member picked
258 161 : if (PickEcmpMember(agent, &nh, pkt, info, ecmp_load_balance) == false) {
259 0 : return false;
260 : }
261 :
262 : // Pick out going attributes based on the NH selected above
263 161 : switch (nh->GetType()) {
264 116 : case NextHop::INTERFACE:
265 116 : out->intf_ = static_cast<const InterfaceNH*>(nh)->GetInterface();
266 116 : if (out->intf_->type() == Interface::VM_INTERFACE) {
267 : //Local flow, pick destination interface
268 : //nexthop as reverse flow key
269 116 : if (out->intf_->flow_key_nh() == NULL)
270 0 : return false;
271 116 : out->nh_ = out->intf_->flow_key_nh()->id();
272 116 : out->vrf_ = static_cast<const InterfaceNH*>(nh)->GetVrf();
273 : const VmInterface *vm_port =
274 116 : dynamic_cast<const VmInterface *>(out->intf_);
275 116 : if (vm_port != NULL) {
276 116 : VrfEntry *alias_vrf = vm_port->GetAliasIpVrf(pkt->ip_daddr);
277 116 : if (alias_vrf != NULL) {
278 0 : out->vrf_ = alias_vrf;
279 : // translate to alias ip vrf for destination, unless
280 : // overriden by translation due to NAT or ACL
281 0 : info->dest_vrf = alias_vrf->vrf_id();
282 0 : info->alias_ip_flow = true;
283 : }
284 : }
285 0 : } else if (out->intf_->type() == Interface::PACKET) {
286 : //Packet destined to pkt interface, packet originating
287 : //from pkt0 interface will use destination interface as key
288 0 : out->nh_ = in->nh_;
289 : } else {
290 : // Most likely a GATEWAY interface.
291 : // Remote flow, use source interface as nexthop key
292 0 : out->nh_ = nh->id();
293 0 : out->vrf_ = static_cast<const InterfaceNH*>(nh)->GetVrf();
294 : }
295 116 : break;
296 :
297 0 : case NextHop::RECEIVE:
298 0 : assert(info->l3_flow == true);
299 0 : out->intf_ = static_cast<const ReceiveNH *>(nh)->GetInterface();
300 0 : out->vrf_ = out->intf_->vrf();
301 0 : if (out->intf_->vrf()->forwarding_vrf()) {
302 0 : out->vrf_ = out->intf_->vrf()->forwarding_vrf();
303 : }
304 0 : out->nh_ = out->intf_->flow_key_nh()->id();
305 0 : break;
306 :
307 0 : case NextHop::VLAN: {
308 0 : assert(info->l3_flow == true);
309 0 : const VlanNH *vlan_nh = static_cast<const VlanNH*>(nh);
310 0 : out->intf_ = vlan_nh->GetInterface();
311 0 : out->vlan_nh_ = true;
312 0 : out->vlan_tag_ = vlan_nh->GetVlanTag();
313 0 : out->vrf_ = vlan_nh->GetVrf();
314 0 : out->nh_ = nh->id();
315 0 : break;
316 : }
317 :
318 : // Destination present on remote-compute node. The reverse traffic will
319 : // have MPLS label. The MPLS label can point to
320 : // 1. In case of non-ECMP, label will points to local interface
321 : // 2. In case of ECMP, label will point to ECMP of local-composite members
322 : // Setup the NH for reverse flow appropriately
323 45 : case NextHop::TUNNEL: {
324 : // out->intf_ is invalid for packets going out on tunnel. Reset it.
325 45 : out->intf_ = NULL;
326 :
327 : // Packet going out on tunnel. Assume NH in reverse flow is same as
328 : // that of forward flow. It can be over-written down if route for
329 : // source-ip is ECMP
330 45 : if (info->port_allocated == false) {
331 45 : out->nh_ = in->nh_;
332 : }
333 :
334 : // The NH in reverse flow can change only if ECMP-NH is used. There is
335 : // no ECMP for layer2 flows
336 45 : if (info->l3_flow == false) {
337 9 : break;
338 : }
339 :
340 : // If source-ip is in ECMP, reverse flow would use ECMP-NH as key
341 : const InetUnicastRouteEntry *rt =
342 36 : dynamic_cast<const InetUnicastRouteEntry *>(in->rt_);
343 36 : if (rt == NULL) {
344 0 : break;
345 : }
346 :
347 : // Get only local-NH from route
348 36 : const NextHop *local_nh = EcmpData::GetLocalNextHop(rt);
349 36 : if (local_nh && local_nh->IsActive() == false) {
350 0 : LogError(pkt, info, "Invalid or Inactive local nexthop ");
351 0 : info->short_flow = true;
352 0 : info->short_flow_reason = FlowEntry::SHORT_UNAVIALABLE_INTERFACE;
353 0 : break;
354 : }
355 :
356 : // Change NH in reverse flow if route points to composite-NH
357 36 : const CompositeNH *comp_nh = dynamic_cast<const CompositeNH *>
358 36 : (local_nh);
359 36 : if (comp_nh != NULL) {
360 0 : out->nh_ = comp_nh->id();
361 : }
362 36 : break;
363 : }
364 :
365 : // COMPOSITE is valid only for multicast traffic. We simply forward
366 : // multicast traffic and its mostly unidirectional. nh_ used in reverse
367 : // flow woule not matter really
368 0 : case NextHop::COMPOSITE: {
369 0 : out->nh_ = nh->id();
370 0 : out->intf_ = NULL;
371 0 : break;
372 : }
373 :
374 : // VRF Nexthop means traffic came as tunnelled packet and interface is
375 : // gateway kind of interface. It also means ARP is not yet resolved for the
376 : // dest-ip (otherwise we should have it ARP-NH). Let out->nh_ to be same as
377 : // in->nh_. It will be modified later when ARP is resolved
378 0 : case NextHop::VRF: {
379 0 : const VrfNH *vrf_nh = static_cast<const VrfNH *>(nh);
380 0 : out->vrf_ = vrf_nh->GetVrf();
381 :
382 : // Bug solution: 1 hypervisor 2 of the network
383 : // Does not block incoming icmp/udp traffic, as the acl on the out interface is not checked due to the absence of this interface
384 : // Find this interface here
385 0 : const InetUnicastRouteEntry* rt = out->vrf_->GetUcRoute(pkt->ip_daddr);
386 0 : if (rt && rt->GetActiveNextHop()) {
387 0 : const NextHop *rt_nh = rt->GetActiveNextHop();
388 0 : if (rt_nh->GetType() == NextHop::INTERFACE) {
389 0 : out->intf_ = static_cast<const InterfaceNH*>(rt_nh)->GetInterface();
390 0 : if (out->intf_->type() == Interface::VM_INTERFACE) {
391 0 : out->nh_ = out->intf_->flow_key_nh()->id();
392 : }
393 : }
394 : }
395 :
396 0 : break;
397 : }
398 :
399 : // ARP Nexthop means outgoing interface is gateway kind of interface with
400 : // ARP already resolved
401 0 : case NextHop::ARP: {
402 0 : assert(info->l3_flow == true);
403 0 : const ArpNH *arp_nh = static_cast<const ArpNH *>(nh);
404 0 : if (in->intf_->type() == Interface::VM_INTERFACE) {
405 0 : const VmInterface *vm_intf =
406 : static_cast<const VmInterface *>(in->intf_);
407 0 : if (vm_intf->vmi_type() == VmInterface::VHOST) {
408 0 : out->nh_ = in->intf_->flow_key_nh()->id();
409 0 : out->intf_ = in->intf_;
410 0 : } else if (vm_intf->device_type() == VmInterface::LOCAL_DEVICE) {
411 0 : out->nh_ = arp_nh->id();
412 0 : out->intf_ = arp_nh->GetInterface();
413 : }
414 : } else {
415 0 : out->intf_ = arp_nh->GetInterface();
416 : }
417 0 : out->vrf_ = arp_nh->GetVrf();
418 0 : break;
419 : }
420 :
421 : // RESOLVE Nexthop means traffic came from gateway interface and destined
422 : // to another gateway interface
423 0 : case NextHop::RESOLVE: {
424 0 : assert(info->l3_flow == true);
425 0 : const ResolveNH *rsl_nh = static_cast<const ResolveNH *>(nh);
426 0 : out->nh_ = rsl_nh->get_interface()->flow_key_nh()->id();
427 0 : out->intf_ = rsl_nh->get_interface();
428 0 : break;
429 : }
430 :
431 0 : default:
432 0 : out->intf_ = NULL;
433 0 : break;
434 : }
435 :
436 161 : if (out->intf_) {
437 116 : if (!out->intf_->IsActive()) {
438 0 : out->intf_ = NULL;
439 0 : ret = false;
440 116 : } else if (force_vmport && IsVgwOrVmInterface(out->intf_) == false) {
441 0 : out->intf_ = NULL;
442 0 : out->vrf_ = NULL;
443 0 : ret = true;
444 : }
445 : }
446 :
447 161 : if (out->vrf_ && (out->vrf_->IsActive() == false)) {
448 0 : out->vrf_ = NULL;
449 0 : ret = false;
450 : }
451 :
452 161 : return ret;
453 : }
454 :
455 : // Decode route and get Interface / ECMP information
456 95 : static bool RouteToOutInfo(const Agent *agent, const AgentRoute *rt,
457 : const PktInfo *pkt, PktFlowInfo *info,
458 : PktControlInfo *in, PktControlInfo *out) {
459 95 : const AgentPath *path = rt->GetActivePath();
460 95 : if (path == NULL)
461 0 : return false;
462 :
463 : const NextHop *nh = static_cast<const NextHop *>
464 95 : (path->ComputeNextHop(info->agent));
465 95 : if (nh == NULL)
466 0 : return false;
467 :
468 95 : if (nh->IsActive() == false) {
469 0 : return false;
470 : }
471 :
472 95 : return NhDecode(agent, nh, pkt, info, in, out, false,
473 95 : path->ecmp_load_balance());
474 : }
475 :
476 136 : static const VnEntry *InterfaceToVn(const Interface *intf) {
477 136 : if (intf->type() != Interface::VM_INTERFACE)
478 1 : return NULL;
479 :
480 135 : const VmInterface *vm_port = static_cast<const VmInterface *>(intf);
481 135 : return vm_port->vn();
482 : }
483 :
484 97 : static bool IntfHasFloatingIp(PktFlowInfo *pkt_info, const Interface *intf,
485 : Address::Family family) {
486 97 : if (!intf || intf->type() != Interface::VM_INTERFACE)
487 1 : return false;
488 :
489 96 : return static_cast<const VmInterface *>(intf)->HasFloatingIp(family);
490 : }
491 :
492 113 : static bool IsLinkLocalRoute(Agent *agent, const AgentRoute *rt,
493 : uint32_t sport, uint32_t dport) {
494 : //Local CN and BGP has been allowed for testing purpose.
495 113 : if ((sport == BgpAsAService::DefaultBgpPort) ||
496 : (dport == BgpAsAService::DefaultBgpPort))
497 0 : return false;
498 :
499 113 : const AgentPath *path = rt->GetActivePath();
500 113 : if (path && path->peer() == agent->link_local_peer())
501 0 : return true;
502 :
503 113 : return false;
504 : }
505 :
506 74 : bool PktFlowInfo::IsBgpRouterServiceRoute(const AgentRoute *in_rt,
507 : const AgentRoute *out_rt,
508 : const Interface *intf,
509 : uint32_t sport,
510 : uint32_t dport) {
511 74 : if (bgp_router_service_flow)
512 0 : return true;
513 :
514 74 : if (intf == NULL || in_rt == NULL || out_rt == NULL)
515 15 : return false;
516 :
517 59 : if ((sport != BgpAsAService::DefaultBgpPort) &&
518 : (dport != BgpAsAService::DefaultBgpPort))
519 59 : return false;
520 :
521 0 : if (intf->type() == Interface::VM_INTERFACE) {
522 : const VmInterface *vm_intf =
523 0 : dynamic_cast<const VmInterface *>(intf);
524 : const InetUnicastRouteEntry *in_inet_rt =
525 0 : dynamic_cast<const InetUnicastRouteEntry *>(in_rt);
526 : const InetUnicastRouteEntry *out_inet_rt =
527 0 : dynamic_cast<const InetUnicastRouteEntry *>(out_rt);
528 0 : if (in_inet_rt == NULL || out_inet_rt == NULL)
529 0 : return false;
530 0 : if (agent->oper_db()->bgp_as_a_service()->
531 0 : IsBgpService(vm_intf, in_inet_rt->prefix_address(), out_inet_rt->prefix_address())) {
532 0 : bgp_router_service_flow = true;
533 0 : return true;
534 : }
535 : }
536 :
537 0 : return false;
538 : }
539 :
540 4 : static const VnListType *RouteToVn(const AgentRoute *rt) {
541 4 : const AgentPath *path = NULL;
542 4 : if (rt) {
543 3 : path = rt->GetActivePath();
544 : }
545 4 : if (path == NULL) {
546 1 : return &(Agent::NullStringList());
547 : }
548 :
549 3 : return &path->dest_vn_list();
550 : }
551 :
552 111 : bool PktFlowInfo::RouteAllowNatLookupCommon(const AgentRoute *rt,
553 : uint32_t sport,
554 : uint32_t dport,
555 : const Interface *intf) {
556 : // No NAT for bridge routes
557 111 : if (dynamic_cast<const BridgeRouteEntry *>(rt) != NULL)
558 37 : return false;
559 :
560 74 : if (rt != NULL && IsLinkLocalRoute(agent, rt, sport, dport)) {
561 : // skip NAT lookup if found route has link local peer.
562 0 : return false;
563 : }
564 :
565 74 : return true;
566 : }
567 :
568 45 : bool PktFlowInfo::IngressRouteAllowNatLookup(const AgentRoute *in_rt,
569 : const AgentRoute *out_rt,
570 : uint32_t sport,
571 : uint32_t dport,
572 : const Interface *intf) {
573 45 : if (RouteAllowNatLookupCommon(out_rt, sport, dport, intf) == false) {
574 16 : return false;
575 : }
576 :
577 29 : if (IsBgpRouterServiceRoute(in_rt, out_rt, intf, sport, dport)) {
578 : // skip NAT lookup if found route has link local peer.
579 0 : return false;
580 : }
581 :
582 29 : return true;
583 : }
584 :
585 66 : bool PktFlowInfo::EgressRouteAllowNatLookup(const AgentRoute *in_rt,
586 : const AgentRoute *out_rt,
587 : uint32_t sport,
588 : uint32_t dport,
589 : const Interface *intf) {
590 66 : if (RouteAllowNatLookupCommon(out_rt, sport, dport, intf) == false) {
591 21 : return false;
592 : }
593 :
594 45 : return true;
595 : }
596 :
597 45 : void PktFlowInfo::CheckLinkLocal(const PktInfo *pkt) {
598 45 : if (!l3_flow && pkt->ip_daddr.is_v4()) {
599 : uint16_t nat_port;
600 18 : Ip4Address nat_server;
601 18 : std::string service_name;
602 18 : GlobalVrouter *global_vrouter = agent->oper_db()->global_vrouter();
603 18 : if (global_vrouter->FindLinkLocalService(pkt->ip_daddr,
604 18 : pkt->dport, &service_name,
605 : &nat_server, &nat_port)) {
606 : // it is link local service request, treat it as l3
607 0 : l3_flow = true;
608 : }
609 18 : }
610 45 : }
611 :
612 0 : void PktFlowInfo::LinkLocalServiceFromVm(const PktInfo *pkt, PktControlInfo *in,
613 : PktControlInfo *out) {
614 :
615 0 : const VmInterface *vm_port =
616 : static_cast<const VmInterface *>(in->intf_);
617 :
618 : uint16_t nat_port;
619 0 : Ip4Address nat_server4;
620 0 : IpAddress nat_server;
621 0 : std::string service_name;
622 0 : if (!agent->oper_db()->global_vrouter()->FindLinkLocalService
623 0 : (pkt->ip_daddr, pkt->dport, &service_name, &nat_server4,
624 : &nat_port)) {
625 : // link local service not configured, drop the request
626 0 : in->rt_ = NULL;
627 0 : out->rt_ = NULL;
628 0 : return;
629 : }
630 :
631 0 : out->vrf_ = agent->vrf_table()->FindVrfFromName(agent->fabric_vrf_name());
632 0 : dest_vrf = out->vrf_->vrf_id();
633 :
634 0 : MetadataProxy *metadata_proxy = NULL;
635 0 : metadata_proxy = agent ?
636 0 : (agent->services() ? agent->services()->metadataproxy() : NULL) : NULL;
637 0 : if (metadata_proxy && pkt &&
638 0 : pkt->ip_saddr.is_v6() &&
639 0 : pkt->ip_daddr.is_v6()) {
640 0 : Ip6Address ll_ip = pkt->ip_saddr.to_v6();
641 : // Announce the route to the interface LL address
642 0 : metadata_proxy->AdvertiseMetaDataLinkLocalRoutes(vm_port,
643 : ll_ip, in->vrf_);
644 : }
645 :
646 : // Set NAT flow fields
647 0 : if (pkt->ip_daddr.is_v4()) {
648 0 : linklocal_flow = true;
649 0 : nat_done = true;
650 0 : underlay_flow = false;
651 0 : if (nat_server4 == agent->router_id()) {
652 : // In case of metadata or when link local destination is local host,
653 : // set VM's metadata address as NAT source address. This is required
654 : // to avoid response from the linklocal service being looped back and
655 : // the packet not coming to vrouter for reverse NAT.
656 : // Destination would be local host (FindLinkLocalService returns this)
657 0 : nat_ip_saddr = vm_port->mdata_ip_addr();
658 : // Services such as metadata will run on compute_node_ip. Set nat
659 : // address to compute_node_ip
660 0 : nat_server4 = agent->compute_node_ip();
661 0 : nat_sport = pkt->sport;
662 : } else {
663 0 : nat_ip_saddr = agent->router_id();
664 : // we bind to a local port & use it as NAT source port (cannot use
665 : // incoming src port); init here and bind in Add;
666 0 : nat_sport = 0;
667 0 : linklocal_bind_local_port = true;
668 : }
669 0 : nat_server = nat_server4;
670 : } else {
671 0 : if (nat_server4 == agent->router_id()) {
672 0 : linklocal_flow = true;
673 0 : nat_done = true;
674 0 : underlay_flow = false;
675 0 : nat_server = metadata_proxy ?
676 0 : metadata_proxy->Ipv6ServiceAddress() :
677 0 : Ip6Address::from_string("::");
678 0 : nat_ip_saddr = vm_port->mdata_ip6_addr();
679 0 : nat_sport = pkt->sport;
680 : }
681 : }
682 :
683 0 : nat_ip_daddr = nat_server;
684 0 : nat_dport = nat_port;
685 :
686 0 : nat_vrf = dest_vrf;
687 0 : nat_dest_vrf = vm_port->vrf_id();
688 :
689 0 : out->rt_ = FlowEntry::GetUcRoute(out->vrf_, nat_server);
690 0 : return;
691 0 : }
692 :
693 0 : void PktFlowInfo::LinkLocalServiceFromHost(const PktInfo *pkt, PktControlInfo *in,
694 : PktControlInfo *out) {
695 0 : if (RouteToOutInfo(agent, out->rt_, pkt, this, in, out) == false) {
696 0 : return;
697 : }
698 :
699 : // Link local services supported only for IPv4 for now
700 0 : if (pkt->family != Address::INET) {
701 0 : in->rt_ = NULL;
702 0 : out->rt_ = NULL;
703 0 : return;
704 : }
705 :
706 0 : const VmInterface *vm_port =
707 : static_cast<const VmInterface *>(out->intf_);
708 0 : if (vm_port == NULL) {
709 : // Force implicit deny
710 0 : in->rt_ = NULL;
711 0 : out->rt_ = NULL;
712 0 : return;
713 : }
714 :
715 : // Check if packet is destined to metadata of interface
716 0 : MetaDataIp *mip = vm_port->GetMetaDataIp(pkt->ip_daddr.to_v4());
717 0 : if (mip == NULL) {
718 : // Force implicit deny
719 0 : in->rt_ = NULL;
720 0 : out->rt_ = NULL;
721 0 : return;
722 : }
723 :
724 0 : dest_vrf = vm_port->vrf_id();
725 0 : out->vrf_ = vm_port->vrf();
726 :
727 : //If the destination route is ECMP set component index
728 : //This component index would be used only for forwarding
729 : //the first packet in flow (HOLD flow flushing)
730 0 : InetUnicastRouteEntry *out_rt = NULL;
731 0 : if (out->vrf_) {
732 : out_rt = static_cast<InetUnicastRouteEntry *>(
733 0 : FlowEntry::GetUcRoute(out->vrf_, mip->destination_ip()));
734 0 : if (out_rt) {
735 0 : const NextHop *anh = out_rt->GetActiveNextHop();
736 0 : if (anh && anh->GetType() == NextHop::COMPOSITE) {
737 0 : const CompositeNH *comp_nh =
738 : static_cast<const CompositeNH *>(anh);
739 0 : ComponentNH component_nh(vm_port->label(), vm_port->flow_key_nh());
740 0 : comp_nh->GetIndex(component_nh, out_component_nh_idx);
741 0 : }
742 : }
743 : }
744 :
745 0 : linklocal_flow = true;
746 0 : nat_done = true;
747 0 : underlay_flow = false;
748 : // Get NAT source/destination IP from MetadataIP retrieved from interface
749 0 : nat_ip_saddr = mip->service_ip();
750 0 : nat_ip_daddr = mip->destination_ip();
751 0 : if (nat_ip_saddr == IpAddress(kDefaultIpv4) ||
752 0 : nat_ip_saddr == IpAddress(kDefaultIpv6) ||
753 0 : nat_ip_daddr == IpAddress(kDefaultIpv4) ||
754 0 : nat_ip_daddr == IpAddress(kDefaultIpv6)) {
755 : // Failed to find associated source or destination address
756 : // Force implicit deny
757 0 : in->rt_ = NULL;
758 0 : out->rt_ = NULL;
759 0 : return;
760 : }
761 :
762 0 : nat_dport = pkt->dport;
763 0 : if (pkt->sport == agent->metadata_server_port()) {
764 0 : nat_sport = METADATA_NAT_PORT;
765 : } else {
766 0 : nat_sport = pkt->sport;
767 : }
768 0 : nat_vrf = dest_vrf;
769 0 : nat_dest_vrf = pkt->vrf;
770 0 : return;
771 : }
772 :
773 0 : void PktFlowInfo::LinkLocalServiceTranslate(const PktInfo *pkt, PktControlInfo *in,
774 : PktControlInfo *out) {
775 0 : const VmInterface *vm_intf = dynamic_cast<const VmInterface *>(in->intf_);
776 0 : if (vm_intf->vmi_type() != VmInterface::VHOST) {
777 0 : LinkLocalServiceFromVm(pkt, in, out);
778 : } else {
779 0 : LinkLocalServiceFromHost(pkt, in, out);
780 : }
781 0 : }
782 :
783 0 : void PktFlowInfo::BgpRouterServiceFromVm(const PktInfo *pkt, PktControlInfo *in,
784 : PktControlInfo *out) {
785 :
786 : // Link local services supported only for IPv4 for now
787 0 : if (pkt->family != Address::INET) {
788 0 : in->rt_ = NULL;
789 0 : out->rt_ = NULL;
790 0 : return;
791 : }
792 :
793 0 : const VmInterface *vm_port =
794 : static_cast<const VmInterface *>(in->intf_);
795 :
796 0 : const VnEntry *vn = static_cast<const VnEntry *>(vm_port->vn());
797 0 : uint32_t sport = 0;
798 0 : uint32_t dport = 0;
799 0 : IpAddress nat_server = IpAddress();
800 :
801 0 : if (vn == NULL) {
802 0 : in->rt_ = NULL;
803 0 : out->rt_ = NULL;
804 0 : return;
805 : }
806 :
807 0 : if (agent->oper_db()->bgp_as_a_service()->
808 0 : GetBgpRouterServiceDestination(vm_port,
809 0 : pkt->ip_saddr.to_v4(),
810 0 : pkt->ip_daddr.to_v4(),
811 : &nat_server,
812 0 : &sport, &dport) == false) {
813 0 : return;
814 : }
815 :
816 0 : out->vrf_ = agent->vrf_table()->FindVrfFromName(agent->fabric_vrf_name());
817 0 : dest_vrf = out->vrf_->vrf_id();
818 :
819 0 : nat_done = true;
820 : //Populate NAT
821 0 : nat_ip_saddr = agent->router_id();
822 0 : nat_ip_daddr = nat_server;
823 0 : nat_sport = sport;
824 0 : nat_dport = dport;
825 0 : if ((nat_ip_daddr == agent->router_id()) &&
826 0 : (nat_ip_daddr == nat_ip_saddr)) {
827 0 : boost::system::error_code ec;
828 : //TODO may be use MDATA well known address.
829 0 : nat_ip_saddr = vm_port->mdata_ip_addr();
830 : }
831 :
832 0 : nat_vrf = dest_vrf;
833 0 : nat_dest_vrf = vm_port->vrf_id();
834 :
835 :
836 0 : out->rt_ = FlowEntry::GetUcRoute(out->vrf_, nat_server);
837 0 : out->intf_ = agent->vhost_interface();
838 0 : out->nh_ = out->intf_->flow_key_nh()->id();
839 0 : ttl = pkt->ttl;
840 0 : return;
841 : }
842 :
843 0 : void PktFlowInfo::BgpRouterServiceTranslate(const PktInfo *pkt,
844 : PktControlInfo *in,
845 : PktControlInfo *out) {
846 0 : if (in->intf_->type() == Interface::VM_INTERFACE) {
847 0 : BgpRouterServiceFromVm(pkt, in, out);
848 : }
849 0 : }
850 :
851 : // DestNAT for packets entering into a VM with floating-ip.
852 : // Can come here in two paths,
853 : // - Packet originated on local vm.
854 : // - Packet originated from remote vm
855 45 : void PktFlowInfo::FloatingIpDNat(const PktInfo *pkt, PktControlInfo *in,
856 : PktControlInfo *out) {
857 45 : const VmInterface *vm_port =
858 : static_cast<const VmInterface *>(out->intf_);
859 : const VmInterface::FloatingIpSet &fip_list =
860 45 : vm_port->floating_ip_list().list_;
861 :
862 : // We must NAT if the IP-DA is not same as Primary-IP on interface
863 45 : if (pkt->ip_daddr.is_v4()) {
864 45 : if (pkt->ip_daddr.to_v4() == vm_port->primary_ip_addr()) {
865 6 : return;
866 : }
867 : }
868 39 : if (pkt->ip_daddr.is_v6()) {
869 0 : if (pkt->ip_daddr.to_v6() == vm_port->primary_ip6_addr()) {
870 0 : return;
871 : }
872 : }
873 :
874 : // Look for matching floating-ip
875 39 : VmInterface::FloatingIpSet::const_iterator it = fip_list.begin();
876 39 : for ( ; it != fip_list.end(); ++it) {
877 :
878 39 : if (it->vrf_.get() == NULL) {
879 0 : continue;
880 : }
881 :
882 39 : if (pkt->ip_daddr != it->floating_ip_) {
883 0 : continue;
884 : }
885 :
886 : // Check if floating-ip direction matches
887 39 : if (it->AllowDNat() == false) {
888 0 : continue;
889 : }
890 :
891 39 : break;
892 : }
893 :
894 39 : if (it == fip_list.end()) {
895 : // No matching floating ip for destination-ip
896 0 : return;
897 : }
898 39 : in->vn_ = NULL;
899 39 : if (nat_done == false) {
900 : // lookup for source route in FIP VRF for egress flows only
901 : // because for source route VRF is always present for ingress flows
902 : // so there is no need to update source route with route lookup
903 : // in FIP's VRF
904 39 : if(!ingress) {
905 36 : UpdateRoute(&in->rt_, it->vrf_.get(), pkt->ip_saddr, pkt->smac,
906 36 : flow_source_plen_map);
907 : }
908 39 : nat_dest_vrf = it->vrf_.get()->vrf_id();
909 : }
910 39 : UpdateRoute(&out->rt_, it->vrf_.get(), pkt->ip_daddr, pkt->dmac,
911 39 : flow_dest_plen_map);
912 39 : out->vn_ = it->vn_.get();
913 39 : VrfEntry *alias_vrf = vm_port->GetAliasIpVrf(it->GetFixedIp(vm_port));
914 39 : if (alias_vrf == NULL) {
915 39 : dest_vrf = out->intf_->vrf()->vrf_id();
916 : } else {
917 0 : dest_vrf = alias_vrf->vrf_id();
918 : }
919 :
920 39 : underlay_flow = false;
921 39 : if (VrfTranslate(pkt, in, out, pkt->ip_saddr, true) == false) {
922 0 : return;
923 : }
924 :
925 39 : if (underlay_flow) {
926 0 : if (pkt->ip_daddr.is_v6()) {
927 0 : return;
928 : }
929 0 : if (it->vrf_->forwarding_vrf()) {
930 : //Pick the underlay ip-fabric VRF for forwarding
931 0 : nat_dest_vrf = it->vrf_->forwarding_vrf()->vrf_id();
932 : }
933 0 : if (out->intf_->vrf()->forwarding_vrf()) {
934 0 : dest_vrf = out->intf_->vrf()->forwarding_vrf()->vrf_id();
935 : }
936 : }
937 :
938 : // Force packet to be treated as L3-flow in such case
939 : // Flow is already marked as l3-flow by the time we are here. But, there is
940 : // an exception in case of DNat.
941 : // - In normal cases, packet hits bridge entry with receive-nh
942 : // - If native-vrf and floating-ip vrf are same, the bridge entry points
943 : // to interface-nh instead of receive nh.
944 39 : l3_flow = true;
945 : // Translate the Dest-IP
946 39 : if (nat_done == false)
947 39 : nat_ip_saddr = pkt->ip_saddr;
948 39 : nat_ip_daddr = it->fixed_ip_;
949 39 : if (it->port_map_enabled()) {
950 0 : int32_t map_port = it->GetDstPortMap(pkt->ip_proto, pkt->dport);
951 0 : if (map_port < 0) {
952 0 : short_flow = true;
953 0 : short_flow_reason = FlowEntry::SHORT_PORT_MAP_DROP;
954 : } else {
955 0 : nat_dport = map_port;
956 : }
957 : } else {
958 39 : nat_dport = pkt->dport;
959 : }
960 39 : nat_sport = pkt->sport;
961 39 : nat_vrf = dest_vrf;
962 39 : nat_done = true;
963 :
964 39 : if (in->rt_) {
965 39 : flow_source_vrf = static_cast<const AgentRoute *>(in->rt_)->vrf_id();
966 : } else {
967 0 : flow_source_vrf = VrfEntry::kInvalidIndex;
968 : }
969 39 : flow_dest_vrf = it->vrf_.get()->vrf_id();
970 :
971 : // Update fields required for floating-IP stats accounting
972 39 : fip_dnat = true;
973 :
974 39 : return;
975 : }
976 :
977 4 : void PktFlowInfo::FloatingIpSNat(const PktInfo *pkt, PktControlInfo *in,
978 : PktControlInfo *out) {
979 4 : const VmInterface *intf =
980 : static_cast<const VmInterface *>(in->intf_);
981 4 : const VmInterface::FloatingIpSet &fip_list = intf->floating_ip_list().list_;
982 4 : VmInterface::FloatingIpSet::const_iterator it = fip_list.begin();
983 4 : VmInterface::FloatingIpSet::const_iterator fip_it = fip_list.end();
984 4 : const AgentRoute *rt = out->rt_;
985 4 : uint8_t rt_plen = 0;
986 4 : if (rt) {
987 0 : rt_plen = RouteToPrefixLen(rt);
988 : }
989 4 : bool change = false;
990 : // Find Floating-IP matching destination-ip
991 8 : for ( ; it != fip_list.end(); ++it) {
992 4 : if (it->vrf_.get() == NULL) {
993 0 : continue;
994 : }
995 :
996 4 : if (it->fixed_ip_ != IpAddress() && (pkt->ip_saddr != it->fixed_ip_)) {
997 0 : continue;
998 : }
999 :
1000 : // Check if floating-ip direction matches
1001 4 : if (it->AllowSNat() == false) {
1002 0 : continue;
1003 : }
1004 :
1005 4 : const AgentRoute *rt_match = FlowEntry::GetUcRoute(it->vrf_.get(),
1006 4 : pkt->ip_daddr);
1007 4 : if (rt_match == NULL) {
1008 0 : flow_dest_plen_map[it->vrf_.get()->vrf_id()] = 0;
1009 0 : continue;
1010 : }
1011 : // found the route match
1012 : // prefer the route with longest prefix match
1013 : // if prefix length is same prefer route from rt(original out->rt_)
1014 : // if routes are from fip of difference VRF, prefer the one with lower name.
1015 : // if both the selected and current FIP is from same vrf prefer the one with lower ip addr.
1016 4 : uint8_t rt_match_plen = RouteToPrefixLen(rt_match);
1017 4 : if (rt != NULL && rt_plen >= rt_match_plen) {
1018 0 : flow_dest_plen_map[rt_match->vrf_id()] = rt_match_plen;
1019 0 : continue;
1020 : }
1021 4 : uint8_t out_rt_plen = RouteToPrefixLen(out->rt_);
1022 4 : if (out->rt_ == NULL || rt_match_plen > out_rt_plen) {
1023 4 : change = true;
1024 0 : } else if (rt_match_plen == out_rt_plen) {
1025 0 : if (it->port_nat()) {
1026 0 : change = false;
1027 0 : } else if (fip_it == fip_list.end()) {
1028 0 : change = true;
1029 0 : } else if (rt_match->vrf()->GetName() < out->rt_->vrf()->GetName()) {
1030 0 : change = true;
1031 0 : } else if (rt_match->vrf()->GetName() == out->rt_->vrf()->GetName() &&
1032 0 : it->floating_ip_ < fip_it->floating_ip_) {
1033 0 : change = true;
1034 : }
1035 : }
1036 :
1037 4 : if (change) {
1038 4 : if (out->rt_ != NULL) {
1039 0 : flow_dest_plen_map[out->rt_->vrf_id()] = out_rt_plen;
1040 : }
1041 4 : out->rt_ = rt_match;
1042 4 : fip_it = it;
1043 4 : change = false;
1044 : } else {
1045 0 : flow_dest_plen_map[rt_match->vrf_id()] = rt_match_plen;
1046 : }
1047 : }
1048 :
1049 4 : if (out->rt_ == rt) {
1050 : // No change in route, no floating-ip found
1051 0 : return;
1052 : }
1053 :
1054 : //Populate in->vn, used for VRF translate ACL lookup
1055 4 : in->vn_ = fip_it->vn_.get();
1056 :
1057 : // Floating-ip found. We will change src-ip to floating-ip. Recompute route
1058 : // for new source-ip. All policy decisions will be based on this new route
1059 4 : UpdateRoute(&in->rt_, fip_it->vrf_.get(), fip_it->floating_ip_, pkt->smac,
1060 4 : flow_source_plen_map);
1061 4 : if (in->rt_ == NULL) {
1062 0 : return;
1063 : }
1064 :
1065 4 : underlay_flow = false;
1066 4 : if (VrfTranslate(pkt, in, out, fip_it->floating_ip_, true) == false) {
1067 0 : return;
1068 : }
1069 4 : if (out->rt_ == NULL || in->rt_ == NULL) {
1070 : //If After VRF translation, ingress route or
1071 : //egress route is NULL, mark the flow as short flow
1072 0 : return;
1073 : }
1074 :
1075 : // Compute out-intf and ECMP info from out-route
1076 4 : if (RouteToOutInfo(agent, out->rt_, pkt, this, in, out) == false) {
1077 0 : return;
1078 : }
1079 :
1080 4 : dest_vrf = out->rt_->vrf_id();
1081 : // Setup reverse flow to translate sip.
1082 4 : nat_done = true;
1083 4 : nat_ip_saddr = fip_it->floating_ip_;
1084 4 : nat_ip_daddr = pkt->ip_daddr;
1085 4 : if (fip_it->port_map_enabled()) {
1086 0 : int32_t map_port = fip_it->GetSrcPortMap(pkt->ip_proto, pkt->sport);
1087 0 : if (map_port < 0) {
1088 0 : short_flow = true;
1089 0 : short_flow_reason = FlowEntry::SHORT_PORT_MAP_DROP;
1090 : } else {
1091 0 : nat_sport = map_port;
1092 : }
1093 4 : } else if (fip_it->port_nat()) {
1094 0 : FlowKey key(in->nh_, pkt->ip_saddr, pkt->ip_daddr, pkt->ip_proto,
1095 0 : pkt->sport, pkt->dport);
1096 0 : if (fip_it->floating_ip_ == pkt->ip_daddr) {
1097 0 : nat_sport = pkt->sport;
1098 0 : nat_ip_saddr = intf->mdata_ip_addr();
1099 : } else {
1100 0 : nat_sport =
1101 0 : agent->GetFlowProto()->port_table_manager()->Allocate(key);
1102 0 : if (nat_sport == 0) {
1103 0 : short_flow = true;
1104 0 : short_flow_reason = FlowEntry::SHORT_PORT_MAP_DROP;
1105 0 : nat_done = false;
1106 0 : out->nh_ = in->nh_;
1107 0 : return;
1108 : } else {
1109 0 : port_allocated = true;
1110 : }
1111 : }
1112 0 : out->nh_ = agent->vhost_interface()->flow_key_nh()->id();
1113 : } else {
1114 4 : nat_sport = pkt->sport;
1115 : }
1116 4 : nat_dport = pkt->dport;
1117 :
1118 : // Compute VRF for reverse flow
1119 4 : if (out->intf_) {
1120 : // Egress-vm present on same compute node, take VRF from vm-port
1121 0 : nat_vrf = out->vrf_->vrf_id();
1122 0 : out->vn_ = InterfaceToVn(out->intf_);
1123 : } else {
1124 : // Egress-vm is remote. Find VRF from the NH for source-ip
1125 4 : nat_vrf = NhToVrf(in->rt_->GetActiveNextHop());
1126 : }
1127 :
1128 : // Dest VRF for reverse flow is In-Port VRF
1129 4 : nat_dest_vrf = in->vrf_->vrf_id();
1130 :
1131 4 : flow_source_vrf = pkt->vrf;
1132 4 : if (out->rt_) {
1133 4 : flow_dest_vrf = dest_vrf;
1134 : } else {
1135 0 : flow_dest_vrf = VrfEntry::kInvalidIndex;
1136 : }
1137 : // Update fields required for floating-IP stats accounting
1138 4 : snat_fip = nat_ip_saddr;
1139 4 : fip_snat = true;
1140 4 : return;
1141 : }
1142 :
1143 : //Check if both source and destination route support Native Encap
1144 : //if yes use underlay forwarding (no change)
1145 : //Else Do a VRF translate to interface VRF
1146 110 : void PktFlowInfo::ChangeEncapToOverlay(const VmInterface *intf,
1147 : const PktInfo *pkt,
1148 : PktControlInfo *in,
1149 : PktControlInfo *out) {
1150 :
1151 110 : if (l3_flow == false) {
1152 39 : return;
1153 : }
1154 :
1155 71 : bool can_be_underlay_flow = false;
1156 71 : if (intf->vrf() && intf->vrf()->forwarding_vrf() &&
1157 0 : intf->vrf()->forwarding_vrf() != intf->vrf()) {
1158 0 : can_be_underlay_flow = true;
1159 : }
1160 :
1161 : //Route needs to be check because out interface might
1162 : //not be populated, if destination uses native forwarding
1163 : //then also we need to do vrf translate
1164 71 : if (out->rt_) {
1165 : const InterfaceNH *intf_nh =
1166 28 : dynamic_cast<const InterfaceNH *>(out->rt_->GetActiveNextHop());
1167 28 : if (intf_nh) {
1168 13 : const Interface *out_itf = intf_nh->GetInterface();
1169 13 : if (out_itf->vrf() && out_itf->vrf()->forwarding_vrf() &&
1170 0 : out_itf->vrf()->forwarding_vrf() != out_itf->vrf()) {
1171 0 : can_be_underlay_flow = true;
1172 : }
1173 : }
1174 : }
1175 :
1176 71 : if (can_be_underlay_flow == false) {
1177 71 : return;
1178 : }
1179 :
1180 0 : const AgentRoute *src_rt = FlowEntry::GetUcRoute(intf->vrf(),
1181 0 : pkt->ip_saddr);
1182 0 : const AgentRoute *dst_rt = FlowEntry::GetUcRoute(intf->vrf(),
1183 0 : pkt->ip_daddr);
1184 :
1185 0 : if (src_rt == NULL || dst_rt == NULL) {
1186 0 : overlay_route_not_found = true;
1187 0 : return;
1188 : }
1189 :
1190 0 : overlay_route_not_found = false;
1191 0 : uint32_t src_tunnel_bmap = src_rt->GetActivePath()->tunnel_bmap();
1192 0 : uint32_t dst_tunnel_bmap = dst_rt->GetActivePath()->tunnel_bmap();
1193 :
1194 0 : if ((src_tunnel_bmap & (1 << TunnelType::NATIVE)) &&
1195 0 : (dst_tunnel_bmap & (1 << TunnelType::NATIVE))) {
1196 0 : underlay_flow = true;
1197 : //Set policy VRF for route tracking
1198 0 : src_policy_vrf = intf->vrf()->vrf_id();
1199 0 : dst_policy_vrf = intf->vrf()->vrf_id();
1200 0 : src_vn = RouteToVn(src_rt);
1201 0 : dst_vn = RouteToVn(dst_rt);
1202 0 : return;
1203 : }
1204 :
1205 0 : const VrfEntry *vrf = intf->vrf();
1206 0 : ChangeVrf(pkt, out, vrf);
1207 0 : dest_vrf = vrf->vrf_id();
1208 0 : alias_ip_flow = true;
1209 0 : UpdateRoute(&out->rt_, vrf, pkt->ip_daddr, pkt->dmac,
1210 0 : flow_dest_plen_map);
1211 0 : UpdateRoute(&in->rt_, vrf, pkt->ip_saddr, pkt->smac,
1212 0 : flow_source_plen_map);
1213 : }
1214 :
1215 43 : void PktFlowInfo::ChangeFloatingIpEncap(const PktInfo *pkt,
1216 : PktControlInfo *in,
1217 : PktControlInfo *out) {
1218 43 : if (in->rt_ == NULL || out->rt_ == NULL) {
1219 0 : return;
1220 : }
1221 :
1222 43 : overlay_route_not_found = false;
1223 43 : const InetUnicastRouteEntry *src =
1224 : static_cast<const InetUnicastRouteEntry *>(in->rt_);
1225 43 : const IpAddress src_ip = src->prefix_address();
1226 :
1227 43 : const InetUnicastRouteEntry *dst =
1228 : static_cast<const InetUnicastRouteEntry *>(out->rt_);
1229 43 : const IpAddress dst_ip = dst->prefix_address();
1230 :
1231 43 : uint32_t src_tunnel_bmap = in->rt_->GetActivePath()->tunnel_bmap();
1232 43 : uint32_t dst_tunnel_bmap = out->rt_->GetActivePath()->tunnel_bmap();
1233 :
1234 43 : if ((src_tunnel_bmap & (1 << TunnelType::NATIVE)) &&
1235 0 : (dst_tunnel_bmap & (1 << TunnelType::NATIVE))) {
1236 :
1237 0 : underlay_flow = true;
1238 0 : src_vn = RouteToVn(in->rt_);
1239 0 : dst_vn = RouteToVn(out->rt_);
1240 :
1241 0 : if (nat_done == false) {
1242 0 : src_policy_vrf = in->rt_->vrf()->vrf_id();
1243 : }
1244 0 : dst_policy_vrf = out->rt_->vrf()->vrf_id();
1245 0 : const VrfEntry *vrf = agent->fabric_vrf();
1246 0 : ChangeVrf(pkt, out, vrf);
1247 0 : UpdateRoute(&out->rt_, vrf, dst_ip, pkt->dmac,
1248 0 : flow_dest_plen_map);
1249 0 : UpdateRoute(&in->rt_, vrf, src_ip, pkt->smac,
1250 0 : flow_source_plen_map);
1251 : }
1252 : }
1253 :
1254 153 : void PktFlowInfo::ChangeEncap(const VmInterface *intf, const PktInfo *pkt,
1255 : PktControlInfo *in, PktControlInfo *out,
1256 : bool nat_flow) {
1257 153 : if (nat_flow) {
1258 43 : ChangeFloatingIpEncap(pkt, in, out);
1259 : } else {
1260 110 : ChangeEncapToOverlay(intf, pkt, in, out);
1261 : }
1262 153 : }
1263 :
1264 154 : bool PktFlowInfo::VrfTranslate(const PktInfo *pkt, PktControlInfo *in,
1265 : PktControlInfo *out, const IpAddress &src_ip,
1266 : bool nat_flow) {
1267 154 : const Interface *intf = NULL;
1268 154 : if (ingress) {
1269 52 : intf = in->intf_;
1270 : } else {
1271 102 : intf = out->intf_;
1272 : }
1273 154 : if (!intf || intf->type() != Interface::VM_INTERFACE) {
1274 1 : return true;
1275 : }
1276 :
1277 153 : const VmInterface *vm_intf = static_cast<const VmInterface *>(intf);
1278 : //If interface has a VRF assign rule, choose the acl and match the
1279 : //packet, else get the acl attached to VN and try matching the packet to
1280 : //network acl
1281 :
1282 153 : ChangeEncap(vm_intf, pkt, in, out, nat_flow);
1283 :
1284 153 : const AclDBEntry *acl = NULL;
1285 153 : if (nat_flow == false) {
1286 110 : acl = vm_intf->vrf_assign_acl();
1287 : }
1288 : //In case of floating IP translation, dont apply
1289 : //interface VRF assign rule
1290 153 : if (acl == NULL) {
1291 153 : if (ingress && in->vn_) {
1292 : //Check if the network ACL is present
1293 48 : acl = in->vn_->GetAcl();
1294 105 : } else if (out->vn_) {
1295 105 : acl = out->vn_->GetAcl();
1296 : }
1297 : }
1298 :
1299 153 : if (!acl) {
1300 151 : return true;
1301 : }
1302 :
1303 2 : PacketHeader hdr;
1304 2 : hdr.vrf = pkt->vrf;
1305 2 : hdr.src_ip = src_ip;
1306 2 : hdr.dst_ip = pkt->ip_daddr;
1307 :
1308 2 : hdr.protocol = pkt->ip_proto;
1309 2 : if (hdr.protocol == IPPROTO_UDP || hdr.protocol == IPPROTO_TCP) {
1310 0 : hdr.src_port = pkt->sport;
1311 0 : hdr.dst_port = pkt->dport;
1312 : } else {
1313 2 : hdr.src_port = 0;
1314 2 : hdr.dst_port = 0;
1315 : }
1316 2 : hdr.src_policy_id = RouteToVn(in->rt_);
1317 2 : hdr.dst_policy_id = RouteToVn(out->rt_);
1318 :
1319 2 : if (underlay_flow) {
1320 0 : hdr.src_policy_id = src_vn;
1321 0 : hdr.dst_policy_id = dst_vn;
1322 : }
1323 :
1324 2 : if (in->rt_) {
1325 2 : const AgentPath *path = in->rt_->GetActivePath();
1326 2 : hdr.src_sg_id_l = &(path->sg_list());
1327 : }
1328 2 : if (out->rt_) {
1329 1 : const AgentPath *path = out->rt_->GetActivePath();
1330 1 : hdr.dst_sg_id_l = &(path->sg_list());
1331 : }
1332 :
1333 2 : MatchAclParams match_acl_param;
1334 2 : if (!acl->PacketMatch(hdr, match_acl_param, NULL)) {
1335 1 : return true;
1336 : }
1337 :
1338 1 : if (match_acl_param.action_info.vrf_translate_action_.vrf_name() != "") {
1339 1 : VrfKey key(match_acl_param.action_info.vrf_translate_action_.vrf_name());
1340 1 : const VrfEntry *vrf = static_cast<const VrfEntry*>
1341 1 : (agent->vrf_table()->FindActiveEntry(&key));
1342 1 : if (vrf == NULL) {
1343 0 : short_flow = true;
1344 0 : short_flow_reason = FlowEntry::SHORT_UNAVIALABLE_VRF;
1345 0 : in->rt_ = NULL;
1346 0 : out->rt_ = NULL;
1347 0 : return false;
1348 : }
1349 :
1350 1 : ChangeVrf(pkt, out, vrf);
1351 1 : UpdateRoute(&out->rt_, vrf, pkt->ip_daddr, pkt->dmac,
1352 1 : flow_dest_plen_map);
1353 1 : UpdateRoute(&in->rt_, vrf, hdr.src_ip, pkt->smac,
1354 1 : flow_source_plen_map);
1355 1 : underlay_flow = false;
1356 1 : }
1357 1 : return true;
1358 2 : }
1359 :
1360 : // Changes VRF of in/out routes in case of DNAT and
1361 : // VRF NH pointing to Interface NH in the routing VRF instance
1362 45 : void PktFlowInfo::NatVxlanVrfTranslate(const PktInfo *pkt, PktControlInfo *in,
1363 : PktControlInfo *out) {
1364 45 : if (out == NULL ||
1365 45 : in == NULL ||
1366 45 : out->rt_ == NULL ||
1367 126 : in->vrf_ == NULL ||
1368 36 : in->vrf_->routing_vrf()) {
1369 9 : return;
1370 : }
1371 :
1372 36 : const NextHop *nh = out->rt_->GetActiveNextHop();
1373 36 : if (nh == NULL || nh->GetType() != NextHop::VRF) {
1374 36 : return;
1375 : }
1376 :
1377 0 : const VrfNH *vrf_nh = static_cast<const VrfNH *>(nh);
1378 0 : const VrfEntry *vrf = vrf_nh->GetVrf();
1379 0 : if (vrf == NULL || vrf->routing_vrf() == false) {
1380 0 : return;
1381 : }
1382 :
1383 0 : InetUnicastRouteEntry *inet_rt = vrf->GetUcRoute(pkt->ip_daddr);
1384 0 : const NextHop *rt_nh = inet_rt ?
1385 0 : inet_rt->GetActiveNextHop() : NULL;
1386 0 : if (rt_nh == NULL || (rt_nh->GetType() != NextHop::INTERFACE && rt_nh->GetType() != NextHop::COMPOSITE)) {
1387 0 : return;
1388 : }
1389 :
1390 0 : if (rt_nh->GetType() == NextHop::INTERFACE){
1391 : const Interface *intf = static_cast<const InterfaceNH*>
1392 0 : (rt_nh)->GetInterface();
1393 0 : if (intf == NULL || intf->type() != Interface::VM_INTERFACE ||
1394 0 : static_cast<const VmInterface*>(intf)->FloatingIpCount() == 0) {
1395 0 : return;
1396 : }
1397 : }
1398 0 : if (rt_nh->GetType() == NextHop::COMPOSITE){
1399 0 : const CompositeNH *composite_nh = static_cast<const CompositeNH*>(rt_nh);
1400 0 : uint32_t comp_nh_count = composite_nh->ComponentNHCount();
1401 0 : for (uint32_t i=0; i < comp_nh_count; i++) {
1402 0 : const NextHop * c_nh = composite_nh->GetNH(i);
1403 0 : if (c_nh == NULL){
1404 0 : continue;
1405 : } else {
1406 0 : const Interface *intf = static_cast<const InterfaceNH*>(c_nh)->GetInterface();
1407 0 : if (intf == NULL || intf->type() != Interface::VM_INTERFACE ||
1408 0 : static_cast<const VmInterface*>(intf)->FloatingIpCount() == 0) {
1409 0 : return;
1410 : }
1411 : }
1412 : }
1413 : }
1414 :
1415 0 : ChangeVrf(pkt, out, vrf);
1416 0 : UpdateRoute(&out->rt_, vrf, pkt->ip_daddr, pkt->dmac,
1417 0 : flow_dest_plen_map);
1418 0 : UpdateRoute(&in->rt_, vrf, pkt->ip_saddr, pkt->smac,
1419 0 : flow_source_plen_map);
1420 : }
1421 :
1422 45 : void PktFlowInfo::IngressProcess(const PktInfo *pkt, PktControlInfo *in,
1423 : PktControlInfo *out) {
1424 : // Flow packets are expected only on VMPort interfaces
1425 46 : if (in->intf_->type() != Interface::VM_INTERFACE &&
1426 1 : in->intf_->type() != Interface::INET) {
1427 0 : LogError(pkt, this, "Unexpected packet on Non-VM interface");
1428 0 : return;
1429 : }
1430 :
1431 : const VmInterface *vm_port =
1432 45 : dynamic_cast<const VmInterface *>(in->intf_);
1433 45 : if (vm_port != NULL) {
1434 44 : VrfEntry *alias_vrf = vm_port->GetAliasIpVrf(pkt->ip_saddr);
1435 44 : if (alias_vrf != NULL) {
1436 0 : in->vrf_ = alias_vrf;
1437 : // translate to alias ip vrf for destination, unless overriden by
1438 : // translation due to NAT or ACL
1439 0 : dest_vrf = alias_vrf->vrf_id();
1440 0 : alias_ip_flow = true;
1441 : }
1442 : }
1443 :
1444 : // We always expect route for source-ip for ingress flows.
1445 : // If route not present, return from here so that a short flow is added
1446 45 : UpdateRoute(&in->rt_, in->vrf_, pkt->ip_saddr, pkt->smac,
1447 45 : flow_source_plen_map);
1448 45 : in->vn_ = InterfaceToVn(in->intf_);
1449 :
1450 : // Consider linklocal service requests as l3 always
1451 45 : CheckLinkLocal(pkt);
1452 :
1453 : // Compute Out-VRF and Route for dest-ip
1454 45 : out->vrf_ = in->vrf_;
1455 45 : UpdateRoute(&out->rt_, out->vrf_, pkt->ip_daddr, pkt->dmac,
1456 45 : flow_dest_plen_map);
1457 :
1458 : // Change VRF if a packet travels between a bridge and the
1459 : // routing VRF instances with destination pointed by FIP
1460 45 : NatVxlanVrfTranslate(pkt, in, out);
1461 :
1462 : //Native VRF of the interface and acl assigned vrf would have
1463 : //exact same route with different nexthop, hence if both ingress
1464 : //route and egress route are present in native vrf, acl match condition
1465 : //can be applied
1466 45 : if (VrfTranslate(pkt, in, out, pkt->ip_saddr, false) == false) {
1467 0 : return;
1468 : }
1469 :
1470 45 : if (out->rt_) {
1471 : // Compute out-intf and ECMP info from out-route
1472 36 : if (RouteToOutInfo(agent, out->rt_, pkt, this, in, out)) {
1473 36 : if (out->intf_) {
1474 25 : out->vn_ = InterfaceToVn(out->intf_);
1475 : //In case of alias IP destination VRF would
1476 : //be already while NHDecode or if its underlay
1477 : //to overlay transition then encap change takes
1478 : //care of it.
1479 : //In case of VM using ip-fabric for forwarding
1480 : //NH would be set with VRF as ip-fabric which
1481 : //would mean local IPV6 traffic would be forwarded
1482 : //in ip-fabric VRF which is not needed
1483 25 : if (out->vrf_ && alias_ip_flow == false) {
1484 25 : dest_vrf = out->vrf_->vrf_id();
1485 : }
1486 : }
1487 : }
1488 : }
1489 :
1490 45 : if (IngressRouteAllowNatLookup(in->rt_,
1491 : out->rt_,
1492 45 : pkt->sport,
1493 45 : pkt->dport,
1494 : in->intf_)) {
1495 : // If interface has floating IP, check if we have more specific route in
1496 : // public VN (floating IP)
1497 29 : if (l3_flow && IntfHasFloatingIp(this, in->intf_, pkt->family)) {
1498 4 : FloatingIpSNat(pkt, in, out);
1499 : }
1500 : }
1501 :
1502 45 : if (out->rt_ != NULL) {
1503 : // Route is present. If IP-DA is a floating-ip, we need DNAT
1504 40 : if (RouteToOutInfo(agent, out->rt_, pkt, this, in, out)) {
1505 40 : if (out->intf_ && IntfHasFloatingIp(this, out->intf_, pkt->family)) {
1506 4 : FloatingIpDNat(pkt, in, out);
1507 : }
1508 : }
1509 : }
1510 :
1511 : // Packets needing linklocal service will have route added by LinkLocal peer
1512 90 : if ((in->rt_ && IsLinkLocalRoute(agent, in->rt_, pkt->sport, pkt->dport)) ||
1513 85 : (out->rt_ && IsLinkLocalRoute(agent, out->rt_,
1514 40 : pkt->sport, pkt->dport))) {
1515 0 : LinkLocalServiceTranslate(pkt, in, out);
1516 : }
1517 :
1518 : //Packets needing bgp router service handling
1519 45 : if (IsBgpRouterServiceRoute(in->rt_, out->rt_,
1520 45 : in->intf_, pkt->sport,
1521 45 : pkt->dport)) {
1522 0 : BgpRouterServiceTranslate(pkt, in, out);
1523 : }
1524 :
1525 : // If out-interface was not found, get it based on out-route
1526 45 : if (out->intf_ == NULL && out->rt_) {
1527 15 : RouteToOutInfo(agent, out->rt_, pkt, this, in, out);
1528 : }
1529 45 : if (out->rt_) {
1530 40 : const NextHop* nh = out->rt_->GetActiveNextHop();
1531 40 : if (nh && nh->GetType() == NextHop::COMPOSITE) {
1532 9 : const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
1533 9 : nh = comp_nh->GetNH(out_component_nh_idx);
1534 : }
1535 :
1536 40 : if (nh && nh->GetType() == NextHop::TUNNEL) {
1537 15 : const TunnelNH* tunnel_nh = static_cast<const TunnelNH *>(nh);
1538 15 : const Ip4Address *ip = tunnel_nh->GetDip();
1539 15 : if (ip) {
1540 15 : peer_vrouter = ip->to_string();
1541 15 : tunnel_type = tunnel_nh->GetTunnelType();
1542 : }
1543 : } else {
1544 25 : peer_vrouter = agent->router_id().to_string();
1545 : }
1546 : }
1547 :
1548 : //In case of distributed SNAT we dont want policy to be applied based
1549 : //on translated FIP route. hence change ingress route to VM's actual
1550 : //route and also the source policy VRF
1551 45 : if (port_allocated && short_flow == false) {
1552 0 : UpdateRoute(&in->rt_, in->vrf_, pkt->ip_saddr, pkt->smac,
1553 0 : flow_source_plen_map);
1554 0 : in->vn_ = InterfaceToVn(in->intf_);
1555 0 : src_policy_vrf = in->intf_->vrf()->vrf_id();
1556 : }
1557 :
1558 45 : return;
1559 : }
1560 :
1561 66 : const NextHop *PktFlowInfo::TunnelToNexthop(const PktInfo *pkt) {
1562 66 : tunnel_type = pkt->tunnel.type;
1563 73 : if (tunnel_type.GetType() == TunnelType::MPLS_GRE ||
1564 7 : tunnel_type.GetType() == TunnelType::MPLS_UDP) {
1565 59 : MplsLabel *mpls = agent->mpls_table()->FindMplsLabel(pkt->tunnel.label);
1566 59 : if (mpls == NULL) {
1567 0 : LogError(pkt, this, "Invalid Label in egress flow");
1568 0 : return NULL;
1569 : }
1570 59 : return mpls->nexthop();
1571 7 : } else if (tunnel_type.GetType() == TunnelType::VXLAN) {
1572 7 : VxLanTable *table = static_cast<VxLanTable *>(agent->vxlan_table());
1573 7 : VxLanId *vxlan = table->FindNoLock(pkt->tunnel.vxlan_id);
1574 7 : if (vxlan == NULL) {
1575 0 : LogError(pkt, this, "Invalid vxlan in egress flow");
1576 0 : return NULL;
1577 : }
1578 :
1579 7 : const VrfNH *nh = dynamic_cast<const VrfNH *>(vxlan->nexthop());
1580 7 : if (nh == NULL)
1581 0 : return NULL;
1582 :
1583 7 : const VrfEntry *vrf = nh->GetVrf();
1584 7 : if (vrf == NULL)
1585 0 : return NULL;
1586 :
1587 7 : AgentRoute *rt = NULL;
1588 7 : if (vrf->vn()->vxlan_routing_vn()) {
1589 0 : rt = FlowEntry::GetUcRoute(vrf, pkt->ip_daddr);
1590 : } else {
1591 : // In case of VXLAN, the NH points to VrfNH. Need to do route lookup
1592 : // on dmac to find the real nexthop
1593 7 : rt = FlowEntry::GetL2Route(vrf, pkt->dmac);
1594 : }
1595 7 : if (rt != NULL) {
1596 7 : return rt->GetActiveNextHop();
1597 : }
1598 :
1599 0 : return NULL;
1600 : } else {
1601 0 : AgentRoute *rt = FlowEntry::GetUcRoute(agent->fabric_vrf(),
1602 0 : pkt->ip_daddr);
1603 0 : if (rt != NULL) {
1604 0 : return rt->GetActiveNextHop();
1605 : }
1606 :
1607 :
1608 0 : LogError(pkt, this, "Invalid tunnel type in egress flow");
1609 0 : return NULL;
1610 : }
1611 :
1612 : return NULL;
1613 : }
1614 :
1615 66 : void PktFlowInfo::EgressProcess(const PktInfo *pkt, PktControlInfo *in,
1616 : PktControlInfo *out) {
1617 66 : peer_vrouter = Ip4Address(pkt->tunnel.ip_saddr).to_string();
1618 :
1619 66 : const NextHop *nh = TunnelToNexthop(pkt);
1620 66 : if (nh == NULL) {
1621 0 : return;
1622 : }
1623 66 : if((nh->GetType() == NextHop::ARP) && (l3_flow == false)) {
1624 0 : LOG(ERROR, "PktFlowInfo::EgressProcess: ARP nexthop and l3_flow "
1625 : " false, DROP this frame. module " << pkt->module << " type "
1626 : << pkt->type << " family " << pkt->family << " vrf " <<pkt->vrf
1627 : << " tunnel_type " << pkt->tunnel.type.GetType()<< " ifindex "
1628 : << pkt->agent_hdr.ifindex << " sip " << pkt->ip_saddr.to_string()
1629 : << " dip " << pkt->ip_daddr.to_string() << " proto " << pkt->ip_proto
1630 : << " sport " << pkt->sport << " dport " <<pkt->dport<<" l3_label "
1631 : << pkt->l3_label);
1632 0 : return;
1633 : }
1634 66 : const CompositeNH *comp_nh = dynamic_cast<const CompositeNH *>(nh);
1635 66 : EcmpLoadBalance ecmp_load_balance;
1636 66 : if (comp_nh != NULL) {
1637 38 : UpdateRoute(&out->rt_, comp_nh->vrf(), pkt->ip_daddr, pkt->dmac,
1638 38 : flow_dest_plen_map);
1639 38 : if (out->rt_ && out->rt_->GetActivePath()) {
1640 38 : ecmp_load_balance = out->rt_->GetActivePath()->ecmp_load_balance();
1641 : }
1642 : }
1643 :
1644 : //Delay hash pick up till route is picked.
1645 66 : if (NhDecode(agent, nh, pkt, this, in, out, true,
1646 66 : ecmp_load_balance) == false) {
1647 0 : return;
1648 : }
1649 :
1650 66 : if (out->intf_ && out->intf_->type() == Interface::VM_INTERFACE) {
1651 66 : const VmInterface *vm_intf = static_cast<const VmInterface *>(out->intf_);
1652 66 : if (vm_intf->IsFloatingIp(pkt->ip_daddr)) {
1653 36 : l3_flow = true;
1654 : } else {
1655 30 : VrfEntry *alias_vrf = vm_intf->GetAliasIpVrf(pkt->ip_daddr);
1656 30 : if (alias_vrf != NULL) {
1657 0 : out->vrf_ = alias_vrf;
1658 : // translate to alias ip vrf for destination, unless overriden by
1659 : // translation due to NAT or ACL
1660 0 : dest_vrf = alias_vrf->vrf_id();
1661 0 : alias_ip_flow = true;
1662 : }
1663 : }
1664 : }
1665 :
1666 66 : if (out->vrf_ == NULL) {
1667 0 : return;
1668 : }
1669 :
1670 66 : UpdateRoute(&out->rt_, out->vrf_, pkt->ip_daddr, pkt->dmac,
1671 66 : flow_dest_plen_map);
1672 66 : UpdateRoute(&in->rt_, out->vrf_, pkt->ip_saddr, pkt->smac,
1673 66 : flow_source_plen_map);
1674 :
1675 66 : if (out->intf_) {
1676 66 : out->vn_ = InterfaceToVn(out->intf_);
1677 : }
1678 :
1679 : //Apply vrf translate ACL to get ingress route
1680 66 : if (VrfTranslate(pkt, in, out, pkt->ip_saddr, false) == false) {
1681 0 : return;
1682 : }
1683 :
1684 66 : if (EgressRouteAllowNatLookup(in->rt_,
1685 : out->rt_,
1686 66 : pkt->sport,
1687 66 : pkt->dport,
1688 : out->intf_)) {
1689 : // If interface has floating IP, check if destination is one of the
1690 : // configured floating IP.
1691 45 : if (IntfHasFloatingIp(this, out->intf_, pkt->family)) {
1692 41 : FloatingIpDNat(pkt, in, out);
1693 : }
1694 : }
1695 :
1696 66 : if (out->rt_) {
1697 66 : if (ecmp && out->rt_->GetActivePath()) {
1698 38 : const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
1699 38 : if (out_component_nh_idx == CompositeNH::kInvalidComponentNHIdx) {
1700 0 : out_component_nh_idx = comp_nh->hash(pkt->
1701 0 : hash(agent, out->rt_->GetActivePath()->
1702 0 : ecmp_load_balance()), ingress);
1703 : }
1704 : }
1705 66 : const NextHop *anh = out->rt_->GetActiveNextHop();
1706 132 : if ((anh) && (anh->GetType() == NextHop::ARP ||
1707 66 : anh->GetType() == NextHop::RESOLVE)) {
1708 : //If a packet came with mpls label pointing to
1709 : //vrf NH, then we need to do a route lookup
1710 : //and set the nexthop for reverse flow properly
1711 : //as mpls pointed NH would not be used for reverse flow
1712 0 : if (RouteToOutInfo(agent, out->rt_, pkt, this, in, out)) {
1713 0 : if (out->intf_) {
1714 0 : out->vn_ = InterfaceToVn(out->intf_);
1715 : }
1716 : }
1717 : }
1718 : }
1719 :
1720 66 : return;
1721 66 : }
1722 :
1723 39 : bool PktFlowInfo::UnknownUnicastFlow(const PktInfo *pkt,
1724 : const PktControlInfo *in,
1725 : const PktControlInfo *out) {
1726 39 : bool ret = false;
1727 39 : if (ingress && out->rt_ == NULL && in->rt_) {
1728 2 : const VmInterface *vm_intf =
1729 : static_cast<const VmInterface *>(in->intf_);
1730 : //If interface has flag to flood unknown unicast
1731 : //and destination route is not present
1732 : //mark the flow for forward
1733 2 : if (vm_intf->flood_unknown_unicast()) {
1734 0 : flood_unknown_unicast = true;
1735 0 : flow_source_vrf = flow_dest_vrf =
1736 0 : static_cast<const AgentRoute *>(in->rt_)->vrf_id();
1737 0 : ret = true;
1738 : }
1739 39 : } else if (in->rt_ == NULL && out->rt_) {
1740 : //This packet should not be ideally trapped
1741 : //from vrouter for flow setup.
1742 : //VxLAN nexthop would be set with flag
1743 : //to flood multicast, hence we would
1744 : //hit all broadcast multicast route and
1745 : //packet would never be trapped for flow setup
1746 7 : tunnel_type = pkt->tunnel.type;
1747 7 : if (tunnel_type.GetType() == TunnelType::VXLAN) {
1748 2 : VxLanTable *table = static_cast<VxLanTable *>(agent->vxlan_table());
1749 2 : VxLanId *vxlan = table->FindNoLock(pkt->tunnel.vxlan_id);
1750 2 : if (vxlan && vxlan->nexthop()) {
1751 : const VrfNH *vrf_nh =
1752 2 : static_cast<const VrfNH *>(vxlan->nexthop());
1753 2 : if (vrf_nh->flood_unknown_unicast()) {
1754 0 : flow_source_vrf = flow_dest_vrf =
1755 0 : static_cast<const AgentRoute *>(out->rt_)->vrf_id();
1756 0 : flood_unknown_unicast = true;
1757 0 : ret = true;
1758 : }
1759 : }
1760 : }
1761 : }
1762 39 : return ret;
1763 : }
1764 :
1765 : // Ignore in case of BFD health check
1766 112 : bool IsValidationDisabled(Agent *agent, const PktInfo *pkt,
1767 : const Interface *interface) {
1768 112 : if (!interface)
1769 1 : return false;
1770 : return ((agent->pkt()->pkt_handler()->
1771 222 : IsBFDHealthCheckPacket(pkt, interface)) ||
1772 : (agent->pkt()->pkt_handler()->
1773 222 : IsSegmentHealthCheckPacket(pkt, interface)));
1774 : }
1775 :
1776 : // Basic config validations for the flow
1777 112 : bool PktFlowInfo::ValidateConfig(const PktInfo *pkt, PktControlInfo *in) {
1778 112 : disable_validation = IsValidationDisabled(agent, pkt, in->intf_);
1779 :
1780 112 : if (agent->tsn_enabled()) {
1781 0 : short_flow = true;
1782 0 : short_flow_reason = FlowEntry::SHORT_FLOW_ON_TSN;
1783 0 : return false;
1784 : }
1785 :
1786 112 : if (in->intf_ == NULL) {
1787 1 : LogError(pkt, this, "Invalid interface");
1788 1 : short_flow = true;
1789 1 : short_flow_reason = FlowEntry::SHORT_UNAVIALABLE_INTERFACE;
1790 1 : return false;
1791 : }
1792 :
1793 111 : const VmInterface *vm_intf = dynamic_cast<const VmInterface *>(in->intf_);
1794 111 : if (l3_flow == true && !disable_validation) {
1795 26 : if (vm_intf && in->intf_->ip_active(pkt->family) == false &&
1796 98 : (pkt->ip_saddr.is_v6() && !pkt->ip_saddr.to_v6().is_link_local()) &&
1797 72 : (pkt->ip_daddr.is_v6() && !pkt->ip_daddr.to_v6().is_link_local())) {
1798 0 : in->intf_ = NULL;
1799 0 : LogError(pkt, this, "IP protocol inactive on interface");
1800 0 : short_flow = true;
1801 0 : short_flow_reason = FlowEntry::SHORT_UNAVIALABLE_INTERFACE;
1802 0 : return false;
1803 : }
1804 :
1805 72 : if (vm_intf && vm_intf->layer3_forwarding() == false) {
1806 0 : LogError(pkt, this, "IP service not enabled for interface");
1807 0 : short_flow = true;
1808 0 : short_flow_reason = FlowEntry::SHORT_IPV4_FWD_DIS;
1809 0 : return false;
1810 : }
1811 : }
1812 :
1813 111 : if (l3_flow == false && !disable_validation) {
1814 39 : if (in->intf_->l2_active() == false) {
1815 0 : in->intf_ = NULL;
1816 0 : LogError(pkt, this, "L2 inactive on interface");
1817 0 : short_flow = true;
1818 0 : short_flow_reason = FlowEntry::SHORT_UNAVIALABLE_INTERFACE;
1819 0 : return false;
1820 : }
1821 :
1822 39 : if (vm_intf && vm_intf->bridging() == false) {
1823 0 : LogError(pkt, this, "Bridge service not enabled for interface");
1824 0 : short_flow = true;
1825 0 : short_flow_reason = FlowEntry::SHORT_IPV4_FWD_DIS;
1826 0 : return false;
1827 : }
1828 : }
1829 :
1830 111 : if (in->vrf_ == NULL || in->vrf_->IsActive() == false) {
1831 0 : in->vrf_ = NULL;
1832 0 : LogError(pkt, this, "Invalid or Inactive VRF");
1833 0 : short_flow = true;
1834 0 : short_flow_reason = FlowEntry::SHORT_UNAVIALABLE_VRF;
1835 0 : return false;
1836 : }
1837 :
1838 111 : return true;
1839 : }
1840 :
1841 112 : bool PktFlowInfo::Process(const PktInfo *pkt, PktControlInfo *in,
1842 : PktControlInfo *out) {
1843 112 : in->intf_ = agent->interface_table()->FindInterface(pkt->agent_hdr.ifindex);
1844 112 : out->nh_ = in->nh_ = pkt->agent_hdr.nh;
1845 112 : in->vrf_ = agent->vrf_table()->FindVrfFromId(pkt->agent_hdr.vrf);
1846 :
1847 112 : if (ValidateConfig(pkt, in) == false) {
1848 1 : return false;
1849 : }
1850 :
1851 : //By default assume destination vrf and source vrf to be same
1852 111 : dest_vrf = pkt->vrf;
1853 : // Compute direction of flow based on in-interface
1854 111 : ingress = ComputeDirection(in->intf_);
1855 111 : if (ingress) {
1856 45 : IngressProcess(pkt, in, out);
1857 : } else {
1858 66 : EgressProcess(pkt, in, out);
1859 : }
1860 :
1861 111 : if (l3_flow == false) {
1862 39 : if (UnknownUnicastFlow(pkt, in, out) == true) {
1863 0 : return true;
1864 : }
1865 : }
1866 :
1867 111 : if (nat_done && ((pkt->ignore_address == VmInterface::IGNORE_SOURCE) ||
1868 43 : (pkt->ignore_address == VmInterface::IGNORE_DESTINATION) || (pkt->is_fat_flow_src_prefix) ||
1869 43 : (pkt->is_fat_flow_dst_prefix))) {
1870 : /* Fat flow not supported for NAT flows */
1871 0 : LogError(pkt, this, "Flow : Fat-flow and NAT cannot co-exist");
1872 0 : short_flow = true;
1873 0 : short_flow_reason = FlowEntry::SHORT_FAT_FLOW_NAT_CONFLICT;
1874 0 : return false;
1875 : }
1876 :
1877 111 : if (!disable_validation) {
1878 111 : if (in->rt_ == NULL || in->rt_->IsDeleted()) {
1879 9 : LogError(pkt, this, "Flow : No route for Src-IP");
1880 9 : short_flow = true;
1881 9 : short_flow_reason = FlowEntry::SHORT_NO_SRC_ROUTE;
1882 9 : return false;
1883 : }
1884 :
1885 102 : if (out->rt_ == NULL || out->rt_->IsDeleted()) {
1886 5 : LogError(pkt, this, "Flow : No route for Dst-IP");
1887 5 : short_flow = true;
1888 5 : short_flow_reason = FlowEntry::SHORT_NO_DST_ROUTE;
1889 5 : return false;
1890 : }
1891 :
1892 97 : flow_source_vrf = static_cast<const AgentRoute *>(in->rt_)->vrf_id();
1893 97 : flow_dest_vrf = out->rt_->vrf_id();
1894 : } else {
1895 0 : flow_source_vrf = flow_dest_vrf = in->vrf_->vrf_id();
1896 : }
1897 :
1898 97 : if (overlay_route_not_found) {
1899 0 : LogError(pkt, this, "Flow : Overlay route not found");
1900 0 : short_flow = true;
1901 0 : short_flow_reason = FlowEntry::SHORT_NO_DST_ROUTE;
1902 0 : return false;
1903 : }
1904 :
1905 : //If source is ECMP, establish a reverse flow pointing
1906 : //to the component index
1907 194 : if (in->rt_ && in->rt_->GetActiveNextHop() &&
1908 97 : in->rt_->GetActiveNextHop()->GetType() == NextHop::COMPOSITE) {
1909 6 : ecmp = true;
1910 : }
1911 :
1912 194 : if (out->rt_ && out->rt_->GetActiveNextHop() &&
1913 97 : out->rt_->GetActiveNextHop()->GetType() == NextHop::COMPOSITE) {
1914 47 : ecmp = true;
1915 : }
1916 :
1917 97 : return true;
1918 : }
1919 :
1920 : // A flow can mean that traffic is seen on an interface. The path preference
1921 : // module can potentially be interested in this event. Check and generate
1922 : // traffic seen event
1923 112 : void PktFlowInfo::GenerateTrafficSeen(const PktInfo *pkt,
1924 : const PktControlInfo *in) {
1925 : // Traffic seen should not be generated for MESSAGE
1926 112 : if (pkt->type == PktType::MESSAGE) {
1927 92 : return;
1928 : }
1929 :
1930 : // Dont generate Traffic seen for egress flows or short or linklocal flows
1931 75 : if (ingress == false || short_flow || linklocal_flow) {
1932 55 : return;
1933 : }
1934 :
1935 : // TODO : No need for one more route lookup
1936 20 : const AgentRoute *rt = NULL;
1937 20 : bool enqueue_traffic_seen = false;
1938 20 : const VmInterface *vm_intf = dynamic_cast<const VmInterface *>(in->intf_);
1939 :
1940 20 : IpAddress sip = pkt->ip_saddr;
1941 20 : if (pkt->family == Address::INET ||
1942 0 : pkt->family == Address::INET6) {
1943 20 : if (l3_flow) {
1944 13 : rt = in->rt_;
1945 7 : } else if (in->vrf_) {
1946 7 : rt = FlowEntry::GetUcRoute(in->vrf_, sip);
1947 : }
1948 : }
1949 20 : uint8_t plen = 0;
1950 : // Generate event if route was waiting for traffic
1951 20 : if (rt && rt->WaitForTraffic()) {
1952 6 : enqueue_traffic_seen = true;
1953 6 : plen = rt->prefix_length();
1954 14 : } else if (vm_intf) {
1955 : //L3 route is not in wait for traffic state
1956 : //EVPN route could be in wait for traffic, if yes
1957 : //enqueue traffic seen
1958 14 : rt = FlowEntry::GetEvpnRoute(in->vrf_, pkt->smac, sip,
1959 : vm_intf->ethernet_tag());
1960 14 : if (rt && rt->WaitForTraffic()) {
1961 1 : const EvpnRouteEntry *evpn_rt = static_cast<const EvpnRouteEntry *>
1962 : (rt);
1963 1 : plen = evpn_rt->prefix_length();
1964 1 : enqueue_traffic_seen = true;
1965 : } else {
1966 13 : IpAddress addr;
1967 13 : rt = FlowEntry::GetEvpnRoute(in->vrf_, pkt->smac, addr,
1968 : vm_intf->ethernet_tag());
1969 13 : if (rt && rt->WaitForTraffic()) {
1970 1 : plen = 32;
1971 1 : if (pkt->family == Address::INET6) {
1972 0 : plen = 128;
1973 : }
1974 1 : enqueue_traffic_seen = true;
1975 : }
1976 : }
1977 :
1978 : }
1979 :
1980 20 : if (enqueue_traffic_seen) {
1981 8 : flow_table->agent()->oper_db()->route_preference_module()->
1982 16 : EnqueueTrafficSeen(sip, plen, in->intf_->id(),
1983 8 : pkt->vrf, pkt->smac);
1984 : }
1985 : }
1986 :
1987 : // Apply flow limits for in and out VMs
1988 112 : void PktFlowInfo::ApplyFlowLimits(const PktControlInfo *in,
1989 : const PktControlInfo *out) {
1990 : // Ignore flow limit checks for flow-update and short-flows
1991 112 : if (short_flow || pkt->type == PktType::MESSAGE) {
1992 42 : return;
1993 : }
1994 :
1995 70 : bool limit_exceeded = false;
1996 : uint32_t vmi_max_flows;
1997 70 : if (in->intf_ && (in->intf_->type() == Interface::VM_INTERFACE)) {
1998 19 : const VmInterface *vm_intf =
1999 19 : dynamic_cast<const VmInterface *>(in->intf_);
2000 19 : if (vm_intf) {
2001 19 : uint32_t maxv = std::max(vm_intf->max_flows(),
2002 19 : agent->global_max_vmi_flows());
2003 19 : uint32_t minv = std::min(vm_intf->max_flows(),
2004 19 : agent->global_max_vmi_flows());
2005 19 : vmi_max_flows =
2006 19 : minv * (vm_intf->max_flows() != FLOWS_LIMIT_UNLIMITED &&
2007 0 : agent->global_max_vmi_flows() != FLOWS_LIMIT_UNLIMITED) +
2008 19 : maxv * ((vm_intf->max_flows() != FLOWS_LIMIT_UNLIMITED) !=
2009 19 : (agent->global_max_vmi_flows() != FLOWS_LIMIT_UNLIMITED));
2010 19 : if (vmi_max_flows != FLOWS_LIMIT_UNLIMITED) {
2011 0 : if ((vm_intf->flow_count() + 2) > vmi_max_flows) {
2012 0 : limit_exceeded = true;
2013 : }
2014 : }
2015 : }
2016 : }
2017 :
2018 70 : if (out->intf_ && (out->intf_->type() == Interface::VM_INTERFACE)) {
2019 60 : const VmInterface *vm_intf =
2020 60 : dynamic_cast<const VmInterface *>(out->intf_);
2021 60 : if (vm_intf) {
2022 60 : uint32_t maxv = std::max(vm_intf->max_flows(),
2023 60 : agent->global_max_vmi_flows());
2024 60 : uint32_t minv = std::min(vm_intf->max_flows(),
2025 60 : agent->global_max_vmi_flows());
2026 60 : vmi_max_flows =
2027 60 : minv * (vm_intf->max_flows() != FLOWS_LIMIT_UNLIMITED &&
2028 0 : agent->global_max_vmi_flows() != FLOWS_LIMIT_UNLIMITED) +
2029 60 : maxv * ((vm_intf->max_flows() != FLOWS_LIMIT_UNLIMITED) !=
2030 60 : (agent->global_max_vmi_flows() != FLOWS_LIMIT_UNLIMITED));
2031 60 : if (vmi_max_flows != FLOWS_LIMIT_UNLIMITED) {
2032 0 : if ((vm_intf->flow_count() + 2) > vmi_max_flows) {
2033 0 : limit_exceeded = true;
2034 : }
2035 : }
2036 : }
2037 : }
2038 :
2039 140 : if (agent->max_vm_flows() && (!limit_exceeded) &&
2040 70 : (in->vm_ && ((in->vm_->flow_count() + 2) > agent->max_vm_flows()))) {
2041 0 : limit_exceeded = true;
2042 : }
2043 :
2044 140 : if (agent->max_vm_flows() && (!limit_exceeded) &&
2045 70 : (out->vm_ && ((out->vm_->flow_count() + 2) > agent->max_vm_flows()))) {
2046 0 : limit_exceeded = true;
2047 : }
2048 :
2049 70 : if (limit_exceeded) {
2050 0 : agent->stats()->incr_flow_drop_due_to_max_limit();
2051 0 : short_flow = true;
2052 0 : short_flow_reason = FlowEntry::SHORT_FLOW_LIMIT;
2053 0 : return;
2054 : }
2055 :
2056 70 : if (linklocal_bind_local_port == false)
2057 70 : return;
2058 :
2059 : // Apply limits for link-local flows
2060 0 : if (agent->pkt()->get_flow_proto()->linklocal_flow_count() >=
2061 0 : agent->params()->linklocal_system_flows()) {
2062 0 : limit_exceeded = true;
2063 : }
2064 :
2065 : // Check per-vm linklocal flow-limits if specified
2066 0 : if ((agent->params()->linklocal_vm_flows() !=
2067 0 : agent->params()->linklocal_system_flows())) {
2068 0 : if (in->vm_ && in->vm_->linklocal_flow_count() >=
2069 0 : agent->params()->linklocal_vm_flows()) {
2070 0 : limit_exceeded = true;
2071 : }
2072 : }
2073 :
2074 0 : if (limit_exceeded) {
2075 0 : agent->stats()->incr_flow_drop_due_to_max_limit();
2076 0 : short_flow = true;
2077 0 : short_flow_reason = FlowEntry::SHORT_LINKLOCAL_SRC_NAT;
2078 0 : return;
2079 : }
2080 :
2081 0 : return;
2082 : }
2083 :
2084 112 : void PktFlowInfo::LinkLocalPortBind(const PktInfo *pkt,
2085 : const PktControlInfo *in,
2086 : FlowEntry *flow) {
2087 112 : assert(flow->in_vm_flow_ref()->fd() == VmFlowRef::kInvalidFd);
2088 112 : if (linklocal_bind_local_port == false)
2089 112 : return;
2090 :
2091 : // link-local service flow. Initialize nat-sport to original src-port.
2092 : // It will be over-ridden if socket could be allocated later
2093 0 : nat_sport = pkt->sport;
2094 :
2095 : // Dont allocate FD for short flows
2096 0 : if (short_flow)
2097 0 : return;
2098 :
2099 0 : if (flow->in_vm_flow_ref()->AllocateFd(agent, pkt->ip_proto) == false) {
2100 : // Could not allocate FD. Make it short flow
2101 0 : agent->stats()->incr_flow_drop_due_to_max_limit();
2102 0 : short_flow = true;
2103 0 : short_flow_reason = FlowEntry::SHORT_LINKLOCAL_SRC_NAT;
2104 0 : return;
2105 : }
2106 0 : nat_sport = flow->in_vm_flow_ref()->port();
2107 :
2108 0 : return;
2109 : }
2110 :
2111 75 : void PktFlowInfo::UpdateEvictedFlowStats(const PktInfo *pkt) {
2112 75 : Agent *agent = flow_table->agent();
2113 75 : KSyncFlowIndexManager *imgr = agent->ksync()->ksync_flow_index_manager();
2114 75 : FlowEntryPtr flow = imgr->FindByIndex(pkt->agent_hdr.cmd_param);
2115 150 : FlowMgmtManager *mgr = agent->pkt()->flow_mgmt_manager(
2116 75 : flow_table->table_index());
2117 :
2118 : /* Enqueue stats update request with UUID of the flow */
2119 75 : if (flow.get() && flow->deleted() == false) {
2120 72 : mgr->FlowStatsUpdateEvent(flow.get(), pkt->agent_hdr.cmd_param_2,
2121 36 : pkt->agent_hdr.cmd_param_3,
2122 36 : pkt->agent_hdr.cmd_param_4, flow->uuid());
2123 : }
2124 75 : }
2125 :
2126 112 : void PktFlowInfo::Add(const PktInfo *pkt, PktControlInfo *in,
2127 : PktControlInfo *out) {
2128 112 : bool update = false;
2129 112 : if (pkt->type != PktType::MESSAGE &&
2130 75 : pkt->agent_hdr.cmd == AgentHdr::TRAP_FLOW_MISS) {
2131 75 : if (pkt->agent_hdr.cmd_param != FlowEntry::kInvalidFlowHandle) {
2132 75 : UpdateEvictedFlowStats(pkt);
2133 : }
2134 : }
2135 :
2136 112 : if ((pkt->type == PktType::MESSAGE &&
2137 37 : pkt->agent_hdr.cmd == AgentHdr::TRAP_FLOW_MISS)) {
2138 37 : update = true;
2139 : }
2140 :
2141 : // Generate traffic seen event for path preference module
2142 112 : GenerateTrafficSeen(pkt, in);
2143 112 : IpAddress sip = pkt->ip_saddr;
2144 112 : IpAddress dip = pkt->ip_daddr;
2145 112 : if (pkt->ignore_address == VmInterface::IGNORE_SOURCE) {
2146 0 : if (ingress) {
2147 0 : sip = FamilyToAddress(pkt->family);
2148 : } else {
2149 0 : dip = FamilyToAddress(pkt->family);
2150 : }
2151 112 : } else if (pkt->ignore_address == VmInterface::IGNORE_DESTINATION) {
2152 0 : if (ingress) {
2153 0 : dip = FamilyToAddress(pkt->family);
2154 : } else {
2155 0 : sip = FamilyToAddress(pkt->family);
2156 : }
2157 : }
2158 :
2159 112 : if (pkt->is_fat_flow_src_prefix) {
2160 0 : sip = pkt->ip_ff_src_prefix;
2161 : }
2162 112 : if (pkt->is_fat_flow_dst_prefix) {
2163 0 : dip = pkt->ip_ff_dst_prefix;
2164 : }
2165 :
2166 112 : FlowKey key(in->nh_, sip, dip, pkt->ip_proto, pkt->sport, pkt->dport);
2167 112 : FlowEntryPtr flow = FlowEntry::Allocate(key, flow_table);
2168 :
2169 112 : ApplyFlowLimits(in, out);
2170 112 : LinkLocalPortBind(pkt, in, flow.get());
2171 :
2172 : // rflow for newly allocated entry should always be NULL
2173 112 : FlowEntryPtr rflow = flow->reverse_flow_entry();
2174 112 : assert(rflow == NULL);
2175 :
2176 : uint16_t r_sport;
2177 : uint16_t r_dport;
2178 112 : if ((pkt->family == Address::INET && pkt->ip_proto == IPPROTO_ICMP) ||
2179 82 : (pkt->family == Address::INET6 && pkt->ip_proto == IPPROTO_ICMPV6)) {
2180 30 : r_sport = pkt->sport;
2181 30 : r_dport = pkt->dport;
2182 82 : } else if (nat_done) {
2183 32 : r_sport = nat_dport;
2184 32 : r_dport = nat_sport;
2185 : } else {
2186 50 : r_sport = pkt->dport;
2187 50 : r_dport = pkt->sport;
2188 : }
2189 :
2190 : // Allocate reverse flow
2191 112 : if (nat_done) {
2192 43 : FlowKey rkey(out->nh_, nat_ip_daddr, nat_ip_saddr, pkt->ip_proto,
2193 43 : r_sport, r_dport);
2194 43 : rflow = FlowEntry::Allocate(rkey, flow_table);
2195 : } else {
2196 69 : if (pkt->same_port_number && (in->nh_ == out->nh_)) {
2197 : /* When source and destination ports are same and FatFlow is
2198 : * configured for that port, always mask source port for both
2199 : * forward and reverse flows */
2200 0 : r_sport = pkt->sport;
2201 0 : r_dport = pkt->dport;
2202 : }
2203 69 : FlowKey rkey(out->nh_, dip, sip, pkt->ip_proto, r_sport, r_dport);
2204 69 : rflow = FlowEntry::Allocate(rkey, flow_table);
2205 : }
2206 :
2207 112 : bool swap_flows = false;
2208 : // If this is message processing, then retain forward and reverse flows
2209 139 : if (pkt->type == PktType::MESSAGE && !short_flow &&
2210 139 : flow_entry->is_flags_set(FlowEntry::ReverseFlow)) {
2211 : // for cases where we need to swap flows rflow should always
2212 : // be Non-NULL
2213 0 : assert(rflow != NULL);
2214 0 : swap_flows = true;
2215 : }
2216 :
2217 112 : tcp_ack = pkt->tcp_ack;
2218 112 : flow->InitFwdFlow(this, pkt, in, out, rflow.get(), agent);
2219 112 : if (rflow != NULL) {
2220 112 : rflow->InitRevFlow(this, pkt, out, in, flow.get(), agent);
2221 : }
2222 :
2223 112 : flow->GetPolicyInfo();
2224 112 : if (rflow != NULL) {
2225 112 : rflow->GetPolicyInfo();
2226 : }
2227 :
2228 112 : flow->ResyncFlow();
2229 112 : if (rflow != NULL) {
2230 112 : rflow->ResyncFlow();
2231 : }
2232 :
2233 : // RPF computation can be done only after policy processing.
2234 : // Do RPF computation now
2235 112 : flow->RpfUpdate();
2236 112 : if (rflow)
2237 112 : rflow->RpfUpdate();
2238 :
2239 : /* Fip stats info in not updated in InitFwdFlow and InitRevFlow because
2240 : * both forward and reverse flows are not not linked to each other yet.
2241 : * We need both forward and reverse flows to update Fip stats info */
2242 112 : UpdateFipStatsInfo(flow.get(), rflow.get(), pkt, in, out);
2243 :
2244 112 : FlowEntry *tmp = swap_flows ? rflow.get() : flow.get();
2245 112 : if (update) {
2246 37 : agent->pkt()->get_flow_proto()->UpdateFlow(tmp);
2247 : } else {
2248 75 : agent->pkt()->get_flow_proto()->AddFlow(tmp);
2249 : }
2250 112 : }
2251 :
2252 112 : void PktFlowInfo::UpdateFipStatsInfo
2253 : (FlowEntry *flow, FlowEntry *rflow, const PktInfo *pkt,
2254 : const PktControlInfo *in, const PktControlInfo *out) {
2255 :
2256 112 : if (pkt->family != Address::INET) {
2257 : //TODO: v6 handling
2258 0 : return;
2259 : }
2260 : uint32_t intf_id, r_intf_id;
2261 : uint32_t fip, r_fip;
2262 112 : intf_id = Interface::kInvalidIndex;
2263 112 : r_intf_id = Interface::kInvalidIndex;
2264 112 : fip = 0;
2265 112 : r_fip = 0;
2266 112 : if (fip_snat && fip_dnat && rflow != NULL) {
2267 : /* This is the case where Source and Destination VMs (part of
2268 : * same compute node) have floating-IP assigned to each of them from
2269 : * a common VN and then each of these VMs send traffic to other VM by
2270 : * addressing the other VM's Floating IP. In this case both SNAT and
2271 : * DNAT flags will be set. We identify SNAT and DNAT flows by
2272 : * inspecting IP of forward and reverse flows and update Fip stats
2273 : * info based on that. */
2274 0 : const FlowKey *nat_key = &(rflow->key());
2275 0 : if (flow->key().src_addr != nat_key->dst_addr) {
2276 : //SNAT case
2277 0 : fip = snat_fip.to_v4().to_ulong();
2278 0 : intf_id = in->intf_->id();
2279 0 : } else if (flow->key().dst_addr != nat_key->src_addr) {
2280 : //DNAT case
2281 0 : fip = flow->key().dst_addr.to_v4().to_ulong();
2282 0 : intf_id = out->intf_->id();
2283 : }
2284 0 : nat_key = &(flow->key());
2285 0 : if (rflow->key().src_addr != nat_key->dst_addr) {
2286 : //SNAT case
2287 0 : r_fip = snat_fip.to_v4().to_ulong();
2288 0 : r_intf_id = in->intf_->id();
2289 0 : } else if (rflow->key().dst_addr != nat_key->src_addr) {
2290 : //DNAT case
2291 0 : r_fip = rflow->key().dst_addr.to_v4().to_ulong();
2292 0 : r_intf_id = out->intf_->id();
2293 : }
2294 112 : } else if (fip_snat) {
2295 4 : fip = r_fip = nat_ip_saddr.to_v4().to_ulong();
2296 4 : intf_id = r_intf_id = in->intf_->id();
2297 108 : } else if (fip_dnat) {
2298 39 : fip = r_fip = pkt->ip_daddr.to_v4().to_ulong();
2299 39 : intf_id = r_intf_id = out->intf_->id();
2300 : }
2301 :
2302 112 : if (fip_snat || fip_dnat) {
2303 43 : flow->UpdateFipStatsInfo(fip, intf_id, agent);
2304 43 : if (rflow != NULL) {
2305 43 : rflow->UpdateFipStatsInfo(r_fip, r_intf_id, agent);
2306 : }
2307 : }
2308 : }
2309 :
2310 75 : void PktFlowInfo::SetPktInfo(boost::shared_ptr<PktInfo> pkt_info) {
2311 75 : family = pkt_info->family;
2312 75 : pkt = pkt_info;
2313 75 : }
2314 :
2315 0 : IpAddress PktFlowInfo::FamilyToAddress(Address::Family family) {
2316 0 : if (pkt->family == Address::INET6) {
2317 0 : return Ip6Address();
2318 : }
2319 0 : return Ip4Address();
2320 : }
|