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