LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - pkt_flow_info.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 471 1274 37.0 %
Date: 2026-08-03 02:19:58 Functions: 33 46 71.7 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14