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: 704 1274 55.3 %
Date: 2026-11-09 02:10:49 Functions: 40 46 87.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14