LCOV - code coverage report
Current view: top level - vnsw/agent/vrouter/ksync - route_ksync.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 701 802 87.4 %
Date: 2026-09-28 02:13:17 Functions: 70 73 95.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <boost/asio.hpp>
       6             : #include <boost/bind/bind.hpp>
       7             : 
       8             : #include <base/logging.h>
       9             : #include <db/db_entry.h>
      10             : #include <db/db_table.h>
      11             : #include <db/db_table_partition.h>
      12             : #include <ksync/ksync_index.h>
      13             : #include <ksync/ksync_entry.h>
      14             : #include <ksync/ksync_object.h>
      15             : #include <ksync/ksync_netlink.h>
      16             : #include <ksync/ksync_sock.h>
      17             : 
      18             : #include "cmn/agent.h"
      19             : #include "oper/interface_common.h"
      20             : #include "oper/tunnel_nh.h"
      21             : #include "oper/nexthop.h"
      22             : #include "oper/route_common.h"
      23             : #include "oper/mirror_table.h"
      24             : #include "oper/agent_route_walker.h"
      25             : #include "oper/hbf.h"
      26             : 
      27             : #include "vrouter/ksync/interface_ksync.h"
      28             : #include "vrouter/ksync/nexthop_ksync.h"
      29             : #include "vrouter/ksync/route_ksync.h"
      30             : 
      31             : #include "ksync_init.h"
      32             : #include "vr_types.h"
      33             : #include "vr_defs.h"
      34             : #include "vr_nexthop.h"
      35             : #include "vr_vrf_table.h"
      36             : 
      37             : using namespace boost::placeholders;
      38             : 
      39          92 : RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj,
      40             :                                  const RouteKSyncEntry *entry,
      41          92 :                                  uint32_t index) :
      42          92 :     KSyncNetlinkDBEntry(index), ksync_obj_(obj),
      43          92 :     rt_type_(entry->rt_type_), vrf_id_(entry->vrf_id_),
      44          92 :     addr_(entry->addr_), src_addr_(entry->src_addr_), mac_(entry->mac_),
      45          92 :     prefix_len_(entry->prefix_len_), nh_(entry->nh_), label_(entry->label_),
      46          92 :     proxy_arp_(false), flood_dhcp_(entry->flood_dhcp_),
      47          92 :     address_string_(entry->address_string_),
      48          92 :     tunnel_type_(entry->tunnel_type_),
      49          92 :     wait_for_traffic_(entry->wait_for_traffic_),
      50          92 :     local_vm_peer_route_(entry->local_vm_peer_route_),
      51          92 :     flood_(entry->flood_), ethernet_tag_(entry->ethernet_tag_),
      52          92 :     layer2_control_word_(entry->layer2_control_word_),
      53          92 :     is_learnt_route_(entry->is_learnt_route_) {
      54          92 : }
      55             : 
      56          52 : RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj, const AgentRoute *rt) :
      57          52 :     KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
      58          52 :     vrf_id_(rt->vrf_id()), mac_(), nh_(NULL), label_(0), proxy_arp_(false),
      59          52 :     flood_dhcp_(false), tunnel_type_(TunnelType::DefaultType()),
      60          52 :     wait_for_traffic_(false), local_vm_peer_route_(false),
      61          52 :     flood_(false), ethernet_tag_(0), layer2_control_word_(false),
      62         104 :     is_learnt_route_(false) {
      63          52 :     boost::system::error_code ec;
      64          52 :     rt_type_ = rt->GetTableType();
      65          52 :     switch (rt_type_) {
      66          23 :     case Agent::INET4_UNICAST: {
      67          23 :           const InetUnicastRouteEntry *uc_rt =
      68             :               static_cast<const InetUnicastRouteEntry *>(rt);
      69          23 :           addr_ = uc_rt->prefix_address();
      70          23 :           src_addr_ = IpAddress::from_string("0.0.0.0", ec).to_v4();
      71          23 :           prefix_len_ = uc_rt->prefix_length();
      72          23 :           AgentPath *local_vm_path = uc_rt->FindLocalVmPortPath();
      73          23 :           if (local_vm_path && local_vm_path->IsDynamicLearntRoute()) {
      74           0 :               is_learnt_route_ = true;
      75             :           }
      76             : 
      77          23 :           break;
      78             :     }
      79           5 :     case Agent::INET6_UNICAST: {
      80           5 :           const InetUnicastRouteEntry *uc_rt =
      81             :               static_cast<const InetUnicastRouteEntry *>(rt);
      82           5 :           addr_ = uc_rt->prefix_address();
      83           5 :           src_addr_ = Ip6Address();
      84           5 :           prefix_len_ = uc_rt->prefix_length();
      85           5 :           break;
      86             :     }
      87           0 :     case Agent::INET4_MULTICAST: {
      88           0 :           const Inet4MulticastRouteEntry *mc_rt =
      89             :               static_cast<const Inet4MulticastRouteEntry *>(rt);
      90           0 :           addr_ = mc_rt->dest_ip_addr();
      91           0 :           src_addr_ = mc_rt->src_ip_addr();
      92           0 :           prefix_len_ = 32;
      93           0 :           break;
      94             :     }
      95          24 :     case Agent::BRIDGE: {
      96          24 :           const BridgeRouteEntry *l2_rt =
      97             :               static_cast<const BridgeRouteEntry *>(rt);
      98          24 :           mac_ = l2_rt->prefix_address();
      99          24 :           prefix_len_ = 0;
     100          24 :           break;
     101             :     }
     102           0 :     default: {
     103           0 :           assert(0);
     104             :     }
     105             :     }
     106          52 :     address_string_ = rt->GetAddressString();
     107          52 : }
     108             : 
     109         236 : RouteKSyncEntry::~RouteKSyncEntry() {
     110         236 : }
     111             : 
     112        1462 : KSyncDBObject *RouteKSyncEntry::GetObject() const {
     113        1462 :     return ksync_obj_;
     114             : }
     115             : 
     116        3145 : bool RouteKSyncEntry::UcIsLess(const KSyncEntry &rhs) const {
     117        3145 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     118        3145 :     if (vrf_id_ != entry.vrf_id_) {
     119           0 :         return vrf_id_ < entry.vrf_id_;
     120             :     }
     121             : 
     122        3145 :     if (addr_ != entry.addr_) {
     123        2972 :         return addr_ < entry.addr_;
     124             :     }
     125             : 
     126         173 :     return (prefix_len_ < entry.prefix_len_);
     127             : }
     128             : 
     129           0 : bool RouteKSyncEntry::McIsLess(const KSyncEntry &rhs) const {
     130           0 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     131           0 :     if (vrf_id_ != entry.vrf_id_) {
     132           0 :         return vrf_id_ < entry.vrf_id_;
     133             :     }
     134             : 
     135           0 :     if (src_addr_ != entry.src_addr_) {
     136           0 :         return src_addr_ < entry.src_addr_;
     137             :     }
     138             : 
     139           0 :     return (addr_ < entry.addr_);
     140             : }
     141             : 
     142         184 : bool RouteKSyncEntry::L2IsLess(const KSyncEntry &rhs) const {
     143         184 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     144             : 
     145         184 :     if (vrf_id_ != entry.vrf_id_) {
     146           0 :         return vrf_id_ < entry.vrf_id_;
     147             :     }
     148             : 
     149         184 :     return mac_ < entry.mac_;
     150             : }
     151             : 
     152        3329 : bool RouteKSyncEntry::IsLess(const KSyncEntry &rhs) const {
     153        3329 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     154        3329 :     if (rt_type_ != entry.rt_type_)
     155           0 :         return rt_type_ < entry.rt_type_;
     156             : 
     157             :     //First unicast
     158        3329 :     if ((rt_type_ == Agent::INET4_UNICAST) ||
     159        1520 :         (rt_type_ == Agent::INET6_UNICAST)) {
     160        3145 :         return UcIsLess(rhs);
     161             :     }
     162             : 
     163         184 :     if (rt_type_ == Agent::BRIDGE) {
     164         184 :         return L2IsLess(rhs);
     165             :     }
     166             : 
     167           0 :     return McIsLess(rhs);
     168             : }
     169             : 
     170         385 : static std::string RouteTypeToString(Agent::RouteTableType type) {
     171         385 :     switch (type) {
     172         173 :     case Agent::INET4_UNICAST:
     173         173 :         return "INET4_UNICAST";
     174             :         break;
     175          36 :     case Agent::INET6_UNICAST:
     176          36 :         return "INET6_UNICAST";
     177             :         break;
     178           0 :     case Agent::INET4_MULTICAST:
     179           0 :         return "INET_MULTICAST";
     180             :         break;
     181         176 :     case Agent::BRIDGE:
     182         176 :         return "BRIDGE";
     183             :         break;
     184           0 :     default:
     185           0 :         break;
     186             :     }
     187             : 
     188           0 :     assert(0);
     189             :     return "";
     190             : }
     191             : 
     192         274 : std::string RouteKSyncEntry::ToString() const {
     193         274 :     std::stringstream s;
     194             :     NHKSyncEntry *nexthop;
     195         274 :     nexthop = nh();
     196             : 
     197         274 :     s << "Type : " << RouteTypeToString(rt_type_) << " ";
     198             :     const VrfEntry* vrf =
     199         274 :         ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
     200         274 :     if (vrf) {
     201         242 :         s << "Route Vrf : " << vrf->GetName() << " ";
     202             :     }
     203         274 :     s << address_string_ << "/" << prefix_len_ << " Type:" << rt_type_;
     204             : 
     205             : 
     206         274 :     s << " Label : " << label_;
     207         274 :     s << " Tunnel Type: " << tunnel_type_;
     208             : 
     209         274 :     if (nexthop) {
     210         256 :         s << nexthop->ToString();
     211             :     } else {
     212          18 :         s << " NextHop : <NULL>";
     213             :     }
     214             : 
     215         274 :     s << " Mac: " << mac_.ToString();
     216         274 :     s << " Flood DHCP:" << flood_dhcp_;
     217         548 :     return s.str();
     218         274 : }
     219             : 
     220             : // Check if NH points to a service-chain interface or a Gateway interface
     221          74 : static bool IsGatewayOrServiceInterface(const NextHop *nh) {
     222          98 :     if (nh->GetType() != NextHop::INTERFACE &&
     223          98 :         nh->GetType() != NextHop::VLAN && nh->GetType() != NextHop::ARP)
     224          19 :         return false;
     225             : 
     226          55 :     const Interface *intf = NULL;
     227          55 :     if (nh->GetType() == NextHop::INTERFACE) {
     228          50 :         intf = (static_cast<const InterfaceNH *>(nh))->GetInterface();
     229          50 :         if (intf->type() == Interface::PACKET)
     230           4 :             return true;
     231           5 :     } else if (nh->GetType() == NextHop::VLAN) {
     232           0 :         intf = (static_cast<const VlanNH *>(nh))->GetInterface();
     233           5 :     } else if (nh->GetType() == NextHop::ARP) {
     234           5 :         intf = (static_cast<const ArpNH *>(nh))->GetInterface();
     235             :     }
     236             : 
     237          51 :     const VmInterface *vmi = dynamic_cast<const VmInterface *>(intf);
     238          51 :     if (vmi == NULL)
     239           0 :         return false;
     240             : 
     241          51 :     if (vmi->HasServiceVlan())
     242           0 :         return true;
     243          51 :     if (vmi->device_type() == VmInterface::LOCAL_DEVICE)
     244           9 :         return true;
     245             : 
     246          42 :     return false;
     247             : }
     248             : 
     249             : // Set the flood_ and proxy_arp_ flag for the route
     250             : // flood_ flag says that ARP packets hitting route should be flooded
     251             : // proxy_arp_ flag says VRouter should do proxy ARP
     252             : //
     253             : // The flags are set based on NH and Interface-type
     254          57 : bool RouteKSyncEntry::BuildArpFlags(const DBEntry *e, const AgentPath *path,
     255             :                                     const MacAddress &mac) {
     256          57 :     bool ret = false;
     257             : 
     258             :     //Route flags for inet4 and inet6
     259          57 :     if ((rt_type_ != Agent::INET6_UNICAST) &&
     260          52 :         (rt_type_ != Agent::INET4_UNICAST))
     261           0 :         return false;
     262             : 
     263          57 :     Agent *agent = ksync_obj_->ksync()->agent();
     264          57 :     const InetUnicastRouteEntry *rt =
     265             :         static_cast<const InetUnicastRouteEntry *>(e);
     266             : 
     267             :     // Assume no flood and proxy_arp by default
     268          57 :     bool flood = false;
     269          57 :     bool proxy_arp = false;
     270          57 :     const NextHop *nh = rt->GetActiveNextHop();
     271             : 
     272          57 :     if (nh == NULL) {
     273           0 :         return false;
     274             :     }
     275          57 :     switch (nh->GetType()) {
     276           1 :     case NextHop::RESOLVE:
     277             :         // RESOLVE NH can be used by Gateway Interface or Fabric VRF
     278             :         // VRouter does not honour flood_ and proxy_arp_ flag for Fabric VRF
     279             :         // We dont want to flood ARP on Gateway Interface
     280           1 :         if (rt->vrf()->GetName() != agent->fabric_vrf_name()) {
     281           0 :             proxy_arp = true;
     282             :         }
     283           1 :         break;
     284             : 
     285             : 
     286           0 :     case NextHop::COMPOSITE:
     287             :         // ECMP flows have composite NH. We want to do routing for ECMP flows
     288             :         // So, set proxy_arp flag
     289           0 :         proxy_arp = true;
     290           0 :         break;
     291             : 
     292           2 :     case NextHop::TUNNEL:
     293             :         {
     294             :             // set proxy arp flag for MPLS VPN routes
     295             :             // these routes' nexthop is either labelled tunnel or
     296             :             // composite of labelled tunnel nexthops
     297           2 :             const TunnelNH *tunnel_nh = static_cast<const TunnelNH *>(nh);
     298           2 :             if (tunnel_nh->GetTunnelType().GetType() ==
     299             :                                     TunnelType::MPLS_OVER_MPLS) {
     300           0 :                 proxy_arp = true;
     301           0 :                 break;
     302             :                 // other tunnel cases should be evaluated under
     303             :                 // default case
     304             :             }
     305             :         }
     306             : 
     307             :     default:
     308             : 
     309          56 :         if (mac != MacAddress::ZeroMac()) {
     310             :             // Proxy-ARP without flood if mac-stitching is present
     311          18 :             proxy_arp = true;
     312          18 :             flood = false;
     313          18 :             break;
     314             :         }
     315             : 
     316             :         // MAC stitching not present.
     317             :         // If interface belongs to service-chain or Gateway, we want packet to
     318             :         // be routed. Following config ensures routing,
     319             :         //     - Enable Proxy
     320             :         //     - Disable Flood-bit
     321             :         //     - Dont do MAC Stitching (in RouteNeedsMacBinding)
     322          38 :         if (IsGatewayOrServiceInterface(nh) == true) {
     323           9 :             proxy_arp = true;
     324           9 :             flood = false;
     325           9 :             break;
     326             :         }
     327             : 
     328          29 :         AgentPath *local_vm_path = rt->FindLocalVmPortPath();
     329          29 :         if (local_vm_path != NULL) {
     330           7 :             if (local_vm_path->is_health_check_service()) {
     331             :                 // for local vm path exported by health check service
     332             :                 // set proxy arp to be true to arp with vrouter MAC
     333           0 :                 proxy_arp = true;
     334           0 :                 flood = false;
     335             :             } else {
     336             :                 // Local port without MAC stitching should only be a transition
     337             :                 // case. In the meanwhile, flood ARP so that VM can respond
     338             :                 // Note: In case VN is in L3 forwarding mode flags will be reset
     339             :                 // This is done below when VN entry is extracted.
     340           7 :                 proxy_arp_ = false;
     341           7 :                 flood = true;
     342             :             }
     343             :         } else {
     344             :             // Non local-route. Set flags based on the route
     345          22 :             proxy_arp = rt->proxy_arp();
     346          22 :             flood = rt->ipam_host_route();
     347             :         }
     348          29 :         break;
     349             :     }
     350             : 
     351             :     // There is an exception for IPAM subnet routes.
     352             :     // IPAM subnet routes always result in flood of ARP even if the route
     353             :     // is ECMP (resulting from gateway routes)
     354          57 :     if (rt->ipam_subnet_route()) {
     355           8 :         proxy_arp = false;
     356           8 :         flood = true;
     357             :     }
     358             : 
     359             :     // If the route crosses a VN, we want packet to be routed. So, override
     360             :     // the flags set above and set only Proxy flag
     361             :     // When L2 forwarding mode is disabled, reset the proxy arp to true and flood
     362             :     // of arp to false.
     363          57 :     VnEntry *vn= rt->vrf()->vn();
     364          68 :     if (vn == NULL || !path->dest_vn_match(vn->GetName()) ||
     365         125 :         (path->dest_vn_list().size() > 1) ||
     366          34 :         (vn->bridging() == false)) {
     367          23 :         proxy_arp = true;
     368          23 :         flood = false;
     369             :     }
     370             : 
     371             :     //If VN is running in l2 mode, then any l3 route installed should
     372             :     //have flood flag set for ARP.
     373          57 :     if (vn && (vn->layer3_forwarding() == false)) {
     374           0 :         proxy_arp = false;
     375           0 :         flood = true;
     376             :     }
     377             : 
     378             :     // VRouter does not honour flood/proxy_arp flags for fabric-vrf
     379          57 :     if (rt->vrf()->GetName() == agent->fabric_vrf_name()) {
     380          26 :         if (mac != MacAddress() || nh->GetType() == NextHop::INTERFACE ||
     381           9 :             nh->GetType() == NextHop::COMPOSITE) {
     382           8 :             proxy_arp = true;
     383             :         } else {
     384           9 :             proxy_arp = false;
     385             :         }
     386          17 :         flood = false;
     387             :     }
     388             : 
     389          57 :     if (proxy_arp != proxy_arp_) {
     390          16 :         proxy_arp_ = proxy_arp;
     391          16 :         ret = true;
     392             :     }
     393             : 
     394          57 :     if (flood != flood_) {
     395          12 :         flood_ = flood;
     396          12 :         ret = true;
     397             :     }
     398          57 :     return ret;
     399             : }
     400             : 
     401             : //Uses internal API to extract path.
     402         107 : const NextHop *RouteKSyncEntry::GetActiveNextHop(const AgentRoute *route) const {
     403         107 :     const AgentPath *path = GetActivePath(route);
     404         107 :     if (path == NULL)
     405           0 :         return NULL;
     406         107 :     return path->ComputeNextHop(ksync_obj_->ksync()->agent());
     407             : }
     408             : 
     409             : //Returns the usable path.
     410             : //In case of bridge tables the path contains reference path which
     411             : //has all the data. This path known as evpn_path is a level of indirection
     412             : //to leaked path from MAC+IP route.
     413         214 : const AgentPath *RouteKSyncEntry::GetActivePath(const AgentRoute *route) const {
     414         214 :     const AgentPath *path = route->GetActivePath();
     415         214 :     return path;
     416             : }
     417             : 
     418         107 : bool RouteKSyncEntry::Sync(DBEntry *e) {
     419         107 :     bool ret = false;
     420         107 :     Agent *agent = ksync_obj_->ksync()->agent();
     421         107 :     const AgentRoute *route = static_cast<AgentRoute *>(e);
     422             : 
     423         107 :     const AgentPath *path = GetActivePath(route);
     424         107 :     if (path->peer() == agent->local_vm_peer())
     425          12 :         local_vm_peer_route_ = true;
     426             :     else
     427          95 :         local_vm_peer_route_ = false;
     428             : 
     429         107 :     NHKSyncObject *nh_object = ksync_obj_->ksync()->nh_ksync_obj();
     430         107 :     NHKSyncEntry *old_nh = nh();
     431             : 
     432         107 :     const NextHop *tmp = NULL;
     433         107 :     tmp = GetActiveNextHop(route);
     434             : 
     435             :     // NHs should not be delete marked here. Interface NHs are an exception. If
     436             :     // an NH is found to be delete marked here, dont go ahead and initialize the
     437             :     // ksync entry with a delete marked NH. Make the route ksync entry use the
     438             :     // Discard NH's ksync entry until an update is received for the route.
     439         266 :     if (tmp == NULL ||
     440         159 :         ((tmp->GetType() != NextHop::INTERFACE) && tmp->IsDeleted())) {
     441           0 :         DiscardNHKey key;
     442           0 :         tmp = static_cast<NextHop *>(agent->nexthop_table()->
     443           0 :              FindActiveEntry(&key));
     444           0 :     }
     445         107 :     NHKSyncEntry nexthop(nh_object, tmp);
     446         107 :     nh_ = static_cast<NHKSyncEntry *>(nh_object->GetReference(&nexthop));
     447         107 :     if (old_nh != nh()) {
     448          55 :         ret = true;
     449             :     }
     450             : 
     451             :     //Bother for label for unicast and bridge routes
     452         107 :     if (rt_type_ != Agent::INET4_MULTICAST) {
     453         107 :         uint32_t old_label = label_;
     454             : 
     455         107 :         if (route->is_multicast()) {
     456          19 :             label_ = path->vxlan_id();
     457             :         } else {
     458          88 :             label_ = path->GetActiveLabel();
     459             :         }
     460         107 :         if (label_ != old_label) {
     461          36 :             ret = true;
     462             :         }
     463             : 
     464         107 :         if (tunnel_type_ != path->GetTunnelType()) {
     465           9 :             tunnel_type_ = path->GetTunnelType();
     466           9 :             ret = true;
     467             :         }
     468             :     }
     469             : 
     470         107 :     if (wait_for_traffic_ != route->WaitForTraffic()) {
     471          48 :         wait_for_traffic_ =  route->WaitForTraffic();
     472          48 :         ret = true;
     473             :     }
     474             : 
     475         107 :     if (route->GetActivePath()) {
     476         107 :         if (layer2_control_word_ != route->GetActivePath()->layer2_control_word()) {
     477           0 :             layer2_control_word_ = route->GetActivePath()->layer2_control_word();
     478           0 :             ret = true;
     479             :         }
     480             :     }
     481             : 
     482         107 :     if (rt_type_ == Agent::INET4_UNICAST || rt_type_ == Agent::INET6_UNICAST) {
     483          57 :         VrfKSyncObject *obj = ksync_obj_->ksync()->vrf_ksync_obj();
     484          57 :         const InetUnicastRouteEntry *uc_rt =
     485             :             static_cast<const InetUnicastRouteEntry *>(e);
     486          57 :         MacAddress mac = MacAddress::ZeroMac();
     487          57 :         bool wait_for_traffic = false;
     488             : 
     489          57 :         if (obj->RouteNeedsMacBinding(uc_rt)) {
     490          32 :             mac = obj->GetIpMacBinding(uc_rt->vrf(), addr_, uc_rt);
     491          32 :             wait_for_traffic = obj->GetIpMacWaitForTraffic(uc_rt->vrf(), addr_);
     492             :         }
     493             : 
     494          57 :         if (wait_for_traffic_ == false &&
     495           2 :             wait_for_traffic_ != wait_for_traffic) {
     496           2 :             wait_for_traffic_ = wait_for_traffic;
     497           2 :             ret = true;
     498             :         }
     499             : 
     500          57 :         if (mac != mac_) {
     501           4 :             mac_ = mac;
     502           4 :             ret = true;
     503             :         }
     504             : 
     505          57 :         if (BuildArpFlags(e, path, mac_))
     506          24 :             ret = true;
     507             :     }
     508             : 
     509         107 :     if (rt_type_ == Agent::BRIDGE) {
     510          50 :         const BridgeRouteEntry *l2_rt =
     511             :             static_cast<const BridgeRouteEntry *>(route);
     512             : 
     513             :         //First search for v4
     514          50 :         const MacVmBindingPath *dhcp_path = l2_rt->FindMacVmBindingPath();
     515          50 :         bool flood_dhcp = true; // Flood DHCP if MacVmBindingPath is not present
     516          50 :         if (dhcp_path)
     517          12 :             flood_dhcp = dhcp_path->flood_dhcp();
     518             : 
     519          50 :         if (flood_dhcp_ != flood_dhcp) {
     520          17 :             flood_dhcp_ = flood_dhcp;
     521          17 :             ret = true;
     522             :         }
     523             :     }
     524             : 
     525         107 :     return ret;
     526         107 : }
     527             : 
     528         111 : void RouteKSyncEntry::FillObjectLog(sandesh_op::type type,
     529             :                                     KSyncRouteInfo &info) const {
     530         111 :     if (type == sandesh_op::ADD) {
     531          65 :         info.set_operation("ADD/CHANGE");
     532             :     } else {
     533          46 :         info.set_operation("DELETE");
     534             :     }
     535             : 
     536         111 :     info.set_addr(address_string_);
     537         111 :     info.set_plen(prefix_len_);
     538         111 :     info.set_vrf(vrf_id_);
     539             : 
     540         111 :     if (nh()) {
     541          93 :         info.set_nh_idx(nh()->nh_id());
     542          93 :         if (nh()->type() == NextHop::TUNNEL) {
     543           2 :             info.set_label(label_);
     544             :         }
     545             :     } else {
     546          18 :         info.set_nh_idx(NH_DISCARD_ID);
     547             :     }
     548             : 
     549         111 :     info.set_mac(mac_.ToString());
     550         111 :     info.set_type(RouteTypeToString(rt_type_));
     551         111 : }
     552             : 
     553         111 : int RouteKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen,
     554             :                             char *buf, int buf_len) {
     555         111 :     vr_route_req encoder;
     556             :     int encode_len;
     557         111 :     NHKSyncEntry *nexthop = nh();
     558             : 
     559         111 :     encoder.set_h_op(op);
     560         111 :     encoder.set_rtr_rid(0);
     561         111 :     encoder.set_rtr_vrf_id(vrf_id_);
     562         111 :     if (rt_type_ != Agent::BRIDGE) {
     563          62 :         if (addr_.is_v4()) {
     564          52 :             encoder.set_rtr_family(AF_INET);
     565          52 :             Ip4Address::bytes_type bytes = addr_.to_v4().to_bytes();
     566          52 :             std::vector<int8_t> rtr_prefix(bytes.begin(), bytes.end());
     567          52 :             encoder.set_rtr_prefix(rtr_prefix);
     568          62 :         } else if (addr_.is_v6()) {
     569          10 :             encoder.set_rtr_family(AF_INET6);
     570          10 :             Ip6Address::bytes_type bytes = addr_.to_v6().to_bytes();
     571          10 :             std::vector<int8_t> rtr_prefix(bytes.begin(), bytes.end());
     572          10 :             encoder.set_rtr_prefix(rtr_prefix);
     573          10 :         }
     574          62 :         encoder.set_rtr_prefix_len(prefix_len_);
     575          62 :         if (mac_ != MacAddress::ZeroMac()) {
     576          12 :             if ((addr_.is_v4() && prefix_len_ != 32) ||
     577           6 :                 (addr_.is_v6() && prefix_len_ != 128)) {
     578           0 :                 LOG(ERROR, "Unexpected MAC stitching for route "
     579             :                     << ToString());
     580           0 :                 mac_ = MacAddress::ZeroMac();
     581             :             }
     582             :             std::vector<int8_t> mac((int8_t *)mac_,
     583           6 :                                     (int8_t *)mac_ + mac_.size());
     584           6 :             encoder.set_rtr_mac(mac);
     585           6 :         }
     586             :     } else {
     587          49 :         encoder.set_rtr_family(AF_BRIDGE);
     588             :         //TODO add support for mac
     589             :         std::vector<int8_t> mac((int8_t *)mac_,
     590          49 :                                 (int8_t *)mac_ + mac_.size());
     591          49 :         encoder.set_rtr_mac(mac);
     592          49 :     }
     593             : 
     594         111 :     int label = 0;
     595         111 :     int flags = 0;
     596         111 :     if (rt_type_ != Agent::INET4_MULTICAST) {
     597             :         // if next hop is tunnel
     598             :         // or nexthop is composite and composite type is LU_ECMP, then
     599             :         // label is valid
     600         214 :         if (nexthop != NULL && ((nexthop->type() == NextHop::TUNNEL) ||
     601         103 :                     ((nexthop->type() == NextHop::COMPOSITE) &&
     602          12 :                     (nexthop->CompositeType() == Composite::LU_ECMP)))) {
     603           2 :             label = label_;
     604           2 :             flags |= VR_RT_LABEL_VALID_FLAG;
     605             :         }
     606             :     }
     607             : 
     608         111 :     if (rt_type_ == Agent::BRIDGE) {
     609          49 :         label = label_;
     610          86 :         if (nexthop != NULL && ((nexthop->type() == NextHop::COMPOSITE) ||
     611          37 :                                (nexthop->type() == NextHop::TUNNEL))) {
     612          12 :             flags |= VR_BE_LABEL_VALID_FLAG;
     613             :         }
     614          49 :         if (flood_dhcp_) {
     615          42 :             flags |= VR_BE_FLOOD_DHCP_FLAG;
     616             :         }
     617          49 :         if (ksync_obj_->ksync()->agent()->tsn_no_forwarding_enabled()) {
     618           0 :             flags |= VR_BE_EVPN_CONTROL_PROCESSING_FLAG;
     619             :         }
     620             :     } else {
     621             : 
     622          62 :         if (proxy_arp_) {
     623          18 :             flags |= VR_RT_ARP_PROXY_FLAG;
     624             :         }
     625             : 
     626          62 :         if (wait_for_traffic_) {
     627          44 :             flags |= VR_RT_ARP_TRAP_FLAG;
     628             :         }
     629             : 
     630          62 :         if (flood_) {
     631          14 :             flags |= VR_RT_ARP_FLOOD_FLAG;
     632             :         }
     633             :        
     634          62 :         if (is_learnt_route_) {
     635           0 :             flags |= VR_RT_MAC_IP_LEARNT_FLAG;
     636             :         }
     637             : 
     638             :     }
     639             : 
     640         111 :     if (layer2_control_word_) {
     641           0 :         flags |= VR_BE_L2_CONTROL_DATA_FLAG;
     642             :     }
     643             : 
     644         111 :     encoder.set_rtr_label_flags(flags);
     645         111 :     encoder.set_rtr_label(label);
     646         111 :     if (nexthop != NULL) {
     647          93 :         encoder.set_rtr_nh_id(nexthop->nh_id());
     648             :     } else {
     649          18 :         encoder.set_rtr_nh_id(NH_DISCARD_ID);
     650             :     }
     651             : 
     652         111 :     if (op == sandesh_op::DEL) {
     653          46 :         encoder.set_rtr_replace_plen(replace_plen);
     654             :     }
     655             : 
     656         111 :     int error = 0;
     657         111 :     encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
     658         111 :     assert(error == 0);
     659         111 :     assert(encode_len <= buf_len);
     660         111 :     return encode_len;
     661         111 : }
     662             : 
     663             : 
     664          46 : int RouteKSyncEntry::AddMsg(char *buf, int buf_len) {
     665          46 :     KSyncRouteInfo info;
     666          46 :     FillObjectLog(sandesh_op::ADD, info);
     667          46 :     KSYNC_TRACE(Route, GetObject(), info);
     668          92 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     669          46 : }
     670             : 
     671          19 : int RouteKSyncEntry::ChangeMsg(char *buf, int buf_len){
     672          19 :     KSyncRouteInfo info;
     673          19 :     FillObjectLog(sandesh_op::ADD, info);
     674          19 :     KSYNC_TRACE(Route, GetObject(), info);
     675             : 
     676          38 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     677          19 : }
     678             : 
     679          46 : int RouteKSyncEntry::DeleteMsg(char *buf, int buf_len) {
     680             : 
     681          46 :     RouteKSyncEntry key(ksync_obj_, this, KSyncEntry::kInvalidIndex);
     682          46 :     KSyncEntry *found = NULL;
     683          46 :     RouteKSyncEntry *route = NULL;
     684          46 :     NHKSyncEntry *ksync_nh = NULL;
     685             : 
     686             :     // IF multicast or bridge delete unconditionally
     687          46 :     if ((rt_type_ == Agent::BRIDGE) ||
     688          28 :         (rt_type_ == Agent::INET4_MULTICAST)) {
     689          18 :         return DeleteInternal(nh(), NULL, buf, buf_len);
     690             :     }
     691             : 
     692             :     // For INET routes, we need to give replacement NH and prefixlen
     693        1018 :     for (int plen = (prefix_len() - 1); plen >= 0; plen--) {
     694             : 
     695        1000 :         if (addr_.is_v4()) {
     696         480 :             Ip4Address addr = Address::GetIp4SubnetAddress(addr_.to_v4(), plen);
     697         480 :             key.set_ip(addr);
     698         520 :         } else if (addr_.is_v6()) {
     699         520 :             Ip6Address addr = Address::GetIp6SubnetAddress(addr_.to_v6(), plen);
     700         520 :             key.set_ip(addr);
     701             :         }
     702             : 
     703        1000 :         key.set_prefix_len(plen);
     704        1000 :         found = GetObject()->Find(&key);
     705             : 
     706        1000 :         if (found) {
     707          13 :             route = static_cast<RouteKSyncEntry *>(found);
     708          13 :             if (route->IsResolved()) {
     709          10 :                 ksync_nh = route->nh();
     710          10 :                 if(ksync_nh) {
     711          10 :                     return DeleteInternal(ksync_nh, route, buf, buf_len);
     712             :                 }
     713           0 :                 ksync_nh = NULL;
     714             :             }
     715             :         }
     716             :     }
     717             : 
     718             :     /* If better route is not found, send discardNH for route */
     719          18 :     return DeleteInternal(NULL, NULL, buf, buf_len);
     720          46 : }
     721             : 
     722          46 : uint8_t RouteKSyncEntry::CopyReplacementData(NHKSyncEntry *nexthop,
     723             :                                              RouteKSyncEntry *new_rt) {
     724          46 :     uint8_t new_plen = 0;
     725          46 :     nh_ = nexthop;
     726          46 :     if (new_rt == NULL) {
     727          36 :         label_ = 0;
     728          36 :         proxy_arp_ = false;
     729          36 :         flood_ = false;
     730          36 :         wait_for_traffic_ = false;
     731             :         // mac_ is key for bridge entries and modifying it will corrut the
     732             :         // KSync tree. So, reset mac in case of non-bridge entries only
     733          36 :         if (rt_type_ != Agent::BRIDGE) {
     734          18 :             mac_ = MacAddress::ZeroMac();
     735             :         }
     736          36 :         is_learnt_route_ = false;
     737             :     } else {
     738          10 :         label_ = new_rt->label();
     739          10 :         new_plen = new_rt->prefix_len();
     740          10 :         proxy_arp_ = new_rt->proxy_arp();
     741          10 :         flood_ = new_rt->flood();
     742          10 :         wait_for_traffic_ = new_rt->wait_for_traffic();
     743          10 :         mac_ = new_rt->mac();
     744          10 :         is_learnt_route_ = new_rt->IsLearntRoute();
     745             :     }
     746          46 :     return new_plen;
     747             : }
     748             : 
     749          46 : int RouteKSyncEntry::DeleteInternal(NHKSyncEntry *nexthop,
     750             :                                     RouteKSyncEntry *new_rt,
     751             :                                     char *buf, int buf_len) {
     752          46 :     uint8_t replace_plen = CopyReplacementData(nexthop, new_rt);
     753          46 :     KSyncRouteInfo info;
     754          46 :     FillObjectLog(sandesh_op::DEL, info);
     755          46 :     KSYNC_TRACE(Route, GetObject(), info);
     756             : 
     757          92 :     return Encode(sandesh_op::DEL, replace_plen, buf, buf_len);
     758          46 : }
     759             : 
     760         117 : KSyncEntry *RouteKSyncEntry::UnresolvedReference() {
     761         117 :     NHKSyncEntry *nexthop = nh();
     762         117 :     if (!nexthop->IsResolvedAndInSync()) {
     763          52 :         return nexthop;
     764             :     }
     765             : 
     766          65 :     if ((rt_type_ == Agent::INET4_UNICAST) ||
     767          36 :         (rt_type_ == Agent::INET6_UNICAST)) {
     768          34 :         if (!mac_.IsZero()) {
     769             :             //Get Vrf and bridge ksync object
     770           6 :             VrfKSyncObject *vrf_obj = ksync_obj_->ksync()->vrf_ksync_obj();
     771             :             VrfEntry* vrf =
     772           6 :                 ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
     773           6 :             if (vrf) {
     774             :                 VrfKSyncObject::VrfState *state =
     775             :                     static_cast<VrfKSyncObject::VrfState *>
     776           6 :                     (vrf->GetState(vrf->get_table(),
     777             :                                    vrf_obj->vrf_listener_id()));
     778           6 :                 RouteKSyncObject* bridge_ksync_obj = state->bridge_route_table_;
     779           6 :                 BridgeRouteEntry tmp_l2_rt(vrf, mac_, Peer::EVPN_PEER, false);
     780           6 :                 RouteKSyncEntry key(bridge_ksync_obj, &tmp_l2_rt);
     781             :                 RouteKSyncEntry *mac_route_reference =
     782             :                     static_cast<RouteKSyncEntry *>(bridge_ksync_obj->
     783           6 :                                                    GetReference(&key));
     784             :                 //Get the ksync entry for stitched mac
     785             :                 //else mark dependancy on same.
     786           6 :                 if (!mac_route_reference->IsResolved())
     787           0 :                     return mac_route_reference;
     788           6 :             } else {
     789             :                 // clear the mac_ to avoid failure in programming vrouter
     790           0 :                 mac_ = MacAddress::ZeroMac();
     791             :             }
     792             :         }
     793             :     }
     794             : 
     795          65 :     return NULL;
     796             : }
     797             : 
     798          16 : RouteKSyncObject::RouteKSyncObject(KSync *ksync, AgentRouteTable *rt_table):
     799          16 :     KSyncDBObject("KSync Route"), ksync_(ksync), marked_delete_(false),
     800          16 :     table_delete_ref_(this, rt_table->deleter()) {
     801          16 :     rt_table_ = rt_table;
     802          16 :     RegisterDb(rt_table);
     803          16 : }
     804             : 
     805          32 : RouteKSyncObject::~RouteKSyncObject() {
     806          16 :     UnregisterDb(GetDBTable());
     807          16 :     table_delete_ref_.Reset(NULL);
     808          32 : }
     809             : 
     810             : KSyncDBObject::DBFilterResp
     811         109 : RouteKSyncObject::DBEntryFilter(const DBEntry *entry,
     812             :                                 const KSyncDBEntry *ksync) {
     813         109 :     const AgentRoute *route = static_cast<const AgentRoute *>(entry);
     814             :     // Ignore Add/Change notifications when VRF is deleted
     815         109 :     if (route->vrf()->IsDeleted() == true) {
     816           2 :         return DBFilterIgnore;
     817             :     }
     818             : 
     819         107 :     if (route->GetActivePath()->inactive())
     820           0 :         return DBFilterIgnore;
     821         107 :     return DBFilterAccept;
     822             : }
     823             : 
     824          46 : KSyncEntry *RouteKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
     825          46 :     const RouteKSyncEntry *route = static_cast<const RouteKSyncEntry *>(entry);
     826          46 :     RouteKSyncEntry *ksync = new RouteKSyncEntry(this, route, index);
     827          46 :     return static_cast<KSyncEntry *>(ksync);
     828             : }
     829             : 
     830          46 : KSyncEntry *RouteKSyncObject::DBToKSyncEntry(const DBEntry *e) {
     831          46 :     const AgentRoute *route = static_cast<const AgentRoute *>(e);
     832          46 :     RouteKSyncEntry *key = new RouteKSyncEntry(this, route);
     833          46 :     return static_cast<KSyncEntry *>(key);
     834             : }
     835             : 
     836          20 : void RouteKSyncObject::Unregister() {
     837          20 :     if (IsEmpty() == true && marked_delete_ == true) {
     838          16 :         KSYNC_TRACE(Trace, this, "Destroying ksync object: "\
     839             :                     + rt_table_->name());
     840          16 :         KSyncObjectManager::Unregister(this);
     841             :     }
     842          20 : }
     843             : 
     844          16 : void RouteKSyncObject::ManagedDelete() {
     845          16 :     marked_delete_ = true;
     846          16 :     Unregister();
     847          16 : }
     848             : 
     849          10 : void RouteKSyncObject::EmptyTable() {
     850          10 :     if (marked_delete_ == true) {
     851           4 :         Unregister();
     852             :     }
     853          10 : }
     854             : 
     855           4 : VrfKSyncEntry::VrfKSyncEntry(VrfKSyncObject *obj, const VrfEntry *entry) :
     856           4 :     KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
     857           4 :     vrf_id_(entry->vrf_id()), hbf_rintf_(entry->hbf_rintf()),
     858           8 :     hbf_lintf_(entry->hbf_lintf()) {
     859           4 : }
     860             : 
     861           4 : VrfKSyncEntry::VrfKSyncEntry(VrfKSyncObject *obj,
     862             :                              const VrfKSyncEntry *entry,
     863           4 :                              uint32_t index) :
     864             :     KSyncNetlinkDBEntry(index),
     865           4 :     vrf_id_(entry->vrf_id()), hbf_rintf_(entry->hbf_rintf()),
     866           8 :     hbf_lintf_(entry->hbf_lintf()) {
     867           4 :         ksync_obj_ = static_cast<VrfKSyncObject*>(entry->GetObject());
     868           4 : }
     869             : 
     870          16 : VrfKSyncEntry::~VrfKSyncEntry() {
     871          16 : }
     872             : 
     873          24 : KSyncDBObject *VrfKSyncEntry::GetObject() const {
     874          24 :         return ksync_obj_;
     875             : }
     876             : 
     877          23 : bool VrfKSyncEntry::IsLess(const KSyncEntry &rhs) const {
     878          23 :     const VrfKSyncEntry &entry = static_cast<const VrfKSyncEntry &> (rhs);
     879             : 
     880          23 :     if (vrf_id_ == entry.vrf_id()) {
     881           8 :         if (hbf_rintf_ == entry.hbf_rintf()) {
     882           8 :             return (hbf_lintf_ < entry.hbf_lintf());
     883             :         } else {
     884           0 :             return (hbf_rintf_ < entry.hbf_rintf());
     885             :         }
     886             :     } else {
     887          15 :         return (vrf_id_ < entry.vrf_id());
     888             :     }
     889             : }
     890             : 
     891          16 : std::string VrfKSyncEntry::ToString() const {
     892          16 :     std::stringstream s;
     893          16 :     s << "Vrf id: " << vrf_id() << " hbf lintf: " << hbf_lintf() <<
     894          16 :         " hbf rintf: " << hbf_rintf();
     895          32 :     return s.str();
     896          16 : }
     897             : 
     898           2 : bool VrfKSyncEntry::Sync(DBEntry* e) {
     899           2 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
     900             : 
     901           4 :     if ((vrf->hbf_rintf() != hbf_rintf_) ||
     902           2 :         (vrf->hbf_lintf() != hbf_lintf_)) {
     903           0 :         hbf_rintf_ = vrf->hbf_rintf();
     904           0 :         hbf_lintf_ = vrf->hbf_lintf();
     905           0 :         return true;
     906             :     }
     907             : 
     908           2 :     return false;
     909             : }
     910             : 
     911           8 : int VrfKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen,
     912             :                             char *buf, int buf_len) {
     913           8 :     vr_vrf_req encoder;
     914             :     int encode_len;
     915             : 
     916           8 :     encoder.set_h_op(op);
     917           8 :     encoder.set_vrf_idx(vrf_id_);
     918           8 :     encoder.set_vrf_hbfr_vif_idx(hbf_rintf_);
     919           8 :     encoder.set_vrf_hbfl_vif_idx(hbf_lintf_);
     920           8 :     encoder.set_vrf_flags(VRF_FLAG_HBF_L_VALID|VRF_FLAG_HBF_R_VALID);
     921             : 
     922           8 :     std::stringstream ss;
     923           8 :     ss << "Encoding VrfKSyncEntry, vrf_id_ " << vrf_id_ <<
     924           8 :          " hbf_rintf_ " << hbf_rintf_ << " hbf_lintf_ " << hbf_lintf_;
     925           8 :     HBFTRACE(Trace, ss.str());
     926             : 
     927           8 :     int error = 0;
     928           8 :     encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
     929           8 :     assert(error == 0);
     930           8 :     assert(encode_len <= buf_len);
     931           8 :     return encode_len;
     932           8 : }
     933             : 
     934           8 : void VrfKSyncEntry::FillObjectLog(sandesh_op::type type,
     935             :                                     KSyncVrfInfo &info) const {
     936           8 :     if (type == sandesh_op::ADD) {
     937           4 :         info.set_operation("ADD/CHANGE");
     938             :     } else {
     939           4 :         info.set_operation("DELETE");
     940             :     }
     941             : 
     942           8 :     info.set_vrf_id(vrf_id_);
     943           8 :     info.set_hbf_rintf(hbf_rintf_);
     944           8 :     info.set_hbf_lintf(hbf_lintf_);
     945           8 : }
     946             : 
     947           4 : int VrfKSyncEntry::AddMsg(char *buf, int buf_len) {
     948           4 :     KSyncVrfInfo info;
     949           4 :     FillObjectLog(sandesh_op::ADD, info);
     950           4 :     KSYNC_TRACE(Vrf, GetObject(), info);
     951           8 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     952           4 : }
     953             : 
     954           0 : int VrfKSyncEntry::ChangeMsg(char *buf, int buf_len){
     955           0 :     KSyncVrfInfo info;
     956           0 :     FillObjectLog(sandesh_op::ADD, info);
     957           0 :     KSYNC_TRACE(Vrf, GetObject(), info);
     958             : 
     959           0 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     960           0 : }
     961             : 
     962           4 : int VrfKSyncEntry::DeleteMsg(char *buf, int buf_len) {
     963           4 :     KSyncVrfInfo info;
     964           4 :     FillObjectLog(sandesh_op::DEL, info);
     965           4 :     KSYNC_TRACE(Vrf, GetObject(), info);
     966             : 
     967           8 :     return Encode(sandesh_op::DEL, 0, buf, buf_len);
     968           4 : }
     969             : 
     970           4 : KSyncEntry *VrfKSyncEntry::UnresolvedReference() {
     971           4 :     return NULL; // TODO: check this
     972             : }
     973             : 
     974           4 : VrfKSyncObject::VrfState::VrfState(Agent *agent) :
     975           4 :     DBState(), seen_(false),
     976           4 :     evpn_rt_table_listener_id_(DBTableBase::kInvalidId) {
     977           4 :     ksync_route_walker_.reset(new KSyncRouteWalker(agent, this));
     978             :     agent->oper_db()->agent_route_walk_manager()->
     979           4 :         RegisterWalker(static_cast<AgentRouteWalker *>
     980             :                        (ksync_route_walker_.get()));
     981           4 : }
     982             : 
     983           4 : KSyncEntry *VrfKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
     984           4 :     const VrfKSyncEntry *vrf = static_cast<const VrfKSyncEntry *>(entry);
     985           4 :     VrfKSyncEntry *ksync = new VrfKSyncEntry(this, vrf, index);
     986           4 :     return static_cast<KSyncEntry *>(ksync);
     987             : }
     988             : 
     989           4 : KSyncEntry *VrfKSyncObject::DBToKSyncEntry(const DBEntry* e) {
     990           4 :     const VrfEntry *vrf = static_cast<const VrfEntry *>(e);
     991           4 :     VrfKSyncEntry *key = new VrfKSyncEntry(this, vrf);
     992           4 :     return static_cast<KSyncEntry *>(key);
     993             : }
     994             : 
     995          37 : void VrfKSyncObject::VrfNotify(DBTablePartBase *partition, DBEntryBase *e) {
     996          37 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
     997             :     VrfState *state = static_cast<VrfState *>
     998          37 :         (vrf->GetState(partition->parent(), vrf_listener_id_));
     999          37 :     if (vrf->IsDeleted()) {
    1000          31 :         if (state) {
    1001           4 :             UnRegisterEvpnRouteTableListener(vrf, state);
    1002           4 :             vrf->ClearState(partition->parent(), vrf_listener_id_);
    1003           4 :             (static_cast<KSyncRouteWalker *>(state->ksync_route_walker_.get()))->EnqueueDelete();
    1004             : 
    1005           4 :             if (state->ksync_->IsDeleted() == false) {
    1006           4 :                 if (state->ksync_->GetDBEntry() != NULL) {
    1007           4 :                     state->ksync_->SetDBEntry(NULL);
    1008             :                 }
    1009           4 :                 NotifyEvent(state->ksync_, KSyncEntry::DEL_REQ);
    1010             :             }
    1011             : 
    1012           4 :             delete state;
    1013             :         }
    1014          31 :         return;
    1015             :     }
    1016             : 
    1017           6 :     if (state == NULL) {
    1018           4 :         state = new VrfState(ksync_->agent());
    1019           4 :         state->seen_ = true;
    1020             : 
    1021             :         // Create ksync entry for VRF
    1022             :         KSyncEntry *key;
    1023           4 :         key = DBToKSyncEntry(vrf);
    1024           4 :         state->ksync_ = static_cast<VrfKSyncEntry *>(CreateImpl(key));
    1025           4 :         delete key;
    1026           4 :         vrf->SetState(partition->parent(), vrf_listener_id_, state);
    1027           4 :         state->ksync_->SetDBEntry(vrf);
    1028           4 :         NotifyEvent(state->ksync_, KSyncEntry::ADD_CHANGE_REQ);
    1029             : 
    1030             :         // Get Inet4 Route table and register with KSync
    1031             :         AgentRouteTable *rt_table = static_cast<AgentRouteTable *>(vrf->
    1032           4 :                           GetInet4UnicastRouteTable());
    1033           4 :         state->inet4_uc_route_table_ = new RouteKSyncObject(ksync_, rt_table);
    1034             : 
    1035             :         // Get Inet6 Route table and register with KSync
    1036             :         rt_table = static_cast<AgentRouteTable *>(vrf->
    1037           4 :                           GetInet6UnicastRouteTable());
    1038           4 :         state->inet6_uc_route_table_ = new RouteKSyncObject(ksync_, rt_table);
    1039             : 
    1040             :         // Get Layer 2 Route table and register with KSync
    1041             :         rt_table = static_cast<AgentRouteTable *>(vrf->
    1042           4 :                           GetBridgeRouteTable());
    1043           4 :         state->bridge_route_table_ = new RouteKSyncObject(ksync_, rt_table);
    1044             : 
    1045             :         //Now for multicast table. Ksync object for multicast table is
    1046             :         //not maintained in vrf list
    1047             :         //TODO Enhance ksyncobject for UC/MC, currently there is only one entry
    1048             :         //in MC so just use the UC object for time being.
    1049             :         rt_table = static_cast<AgentRouteTable *>(vrf->
    1050           4 :                           GetInet4MulticastRouteTable());
    1051           4 :         state->inet4_mc_route_table_ = new RouteKSyncObject(ksync_, rt_table);
    1052             : 
    1053             :         //Add EVPN route table listener to update IP MAC binding table.
    1054             :         rt_table = static_cast<AgentRouteTable *>(vrf->
    1055           4 :                                                   GetEvpnRouteTable());
    1056           4 :         KSYNC_TRACE(Trace, state->inet4_uc_route_table_,
    1057             :                     "Subscribing to route table "\
    1058             :                     + vrf->GetName());
    1059           4 :         if (state->evpn_rt_table_listener_id_ == DBTableBase::kInvalidId) {
    1060           4 :             state->evpn_rt_table_listener_id_ =
    1061           4 :                 rt_table->Register(boost::bind(&VrfKSyncObject::EvpnRouteTableNotify,
    1062             :                                            this, _1, _2));
    1063             :         }
    1064           4 :         (static_cast<KSyncRouteWalker *>(state->ksync_route_walker_.get()))->
    1065           4 :             NotifyRoutes(vrf);
    1066             :     } else {
    1067           2 :         VrfKSyncEntry* ksync = state->ksync_;
    1068           2 :         if (ksync->Sync(vrf) || ksync->IsDeleted()) {
    1069           0 :             NotifyEvent(ksync, KSyncEntry::ADD_CHANGE_REQ);
    1070             :         }
    1071             :     }
    1072             : }
    1073             : 
    1074          33 : void VrfKSyncObject::EvpnRouteTableNotify(DBTablePartBase *partition,
    1075             :                                           DBEntryBase *e) {
    1076          33 :     const EvpnRouteEntry *evpn_rt = static_cast<const EvpnRouteEntry *>(e);
    1077             : 
    1078          33 :     if (evpn_rt->IsType5())
    1079           0 :         return;
    1080             : 
    1081          33 :     if (evpn_rt->IsDeleted()) {
    1082           9 :         DelIpMacBinding(evpn_rt->vrf(), evpn_rt->prefix_address(),
    1083             :                         evpn_rt->mac(), evpn_rt->ethernet_tag());
    1084             :     } else {
    1085          24 :         AddIpMacBinding(evpn_rt->vrf(), evpn_rt->prefix_address(),
    1086             :                         evpn_rt->mac(),
    1087             :                         evpn_rt->ethernet_tag(),
    1088          24 :                         evpn_rt->GetActivePath()->path_preference().preference(),
    1089          24 :                         evpn_rt->WaitForTraffic());
    1090             :     }
    1091          33 :     return;
    1092             : }
    1093             : 
    1094           4 : void VrfKSyncObject::UnRegisterEvpnRouteTableListener(const VrfEntry *vrf,
    1095             :                                                       VrfState *state) {
    1096           4 :     if (state->evpn_rt_table_listener_id_ == DBTableBase::kInvalidId)
    1097           0 :         return;
    1098             : 
    1099             :     AgentRouteTable *rt_table = static_cast<AgentRouteTable *>(vrf->
    1100           4 :                                             GetEvpnRouteTable());
    1101           4 :     rt_table->Unregister(state->evpn_rt_table_listener_id_);
    1102           4 :     state->evpn_rt_table_listener_id_ = DBTableBase::kInvalidId;
    1103             : }
    1104             : 
    1105           1 : VrfKSyncObject::VrfKSyncObject(KSync *ksync) :
    1106           1 :     KSyncDBObject("KSync Vrf"), ksync_(ksync), marked_delete_(false) {
    1107           1 :     vrf_table_ = ksync_->agent()->vrf_table();
    1108           1 : }
    1109             : 
    1110           2 : VrfKSyncObject::~VrfKSyncObject() {
    1111           2 : }
    1112             : 
    1113           1 : void VrfKSyncObject::RegisterDBClients() {
    1114           1 :     vrf_listener_id_ = ksync_->agent()->vrf_table()->Register
    1115           1 :             (boost::bind(&VrfKSyncObject::VrfNotify, this, _1, _2));
    1116           1 : }
    1117             : 
    1118           0 : void VrfKSyncObject::Shutdown() {
    1119           0 :     ksync_->agent()->vrf_table()->Unregister(vrf_listener_id_);
    1120           0 :     vrf_listener_id_ = -1;
    1121           0 : }
    1122             : 
    1123         111 : void vr_route_req::Process(SandeshContext *context) {
    1124         111 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    1125         111 :     ioc->RouteMsgHandler(this);
    1126         111 : }
    1127             : 
    1128           8 : void vr_vrf_req::Process(SandeshContext *context) {
    1129           8 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    1130           8 :     ioc->VrfMsgHandler(this);
    1131           8 : }
    1132             : 
    1133             : /****************************************************************************
    1134             :  * Methods to stitch IP and MAC addresses. The KSync object maintains mapping
    1135             :  * between IP <-> MAC in ip_mac_binding_ tree. The table is built based on
    1136             :  * Evpn routes.
    1137             :  *
    1138             :  * When an Inet route is notified, if it needs MAC Stitching, the MAC to
    1139             :  * stitch is found from the ip_mac_binding_ tree
    1140             :  *
    1141             :  * Any change to ip_mac_binding_ tree will also result in re-evaluation of
    1142             :  * Inet4/Inet6 route that may potentially have stitching changed
    1143             :  ****************************************************************************/
    1144             : 
    1145             : // Compute if a route needs IP-MAC binding. A route needs IP-MAC binding if,
    1146             : // 1. The NH points to interface or Tunnel-NH
    1147             : // 2. NH does not belong to Service-Chain Interface
    1148             : // 3. NH does not belong to Gateway Interface
    1149             : // to interface or tunnel-nh
    1150          57 : bool VrfKSyncObject::RouteNeedsMacBinding(const InetUnicastRouteEntry *rt) {
    1151          57 :     if (rt->prefix_address().is_v4() && rt->prefix_length() != 32)
    1152          13 :         return false;
    1153             : 
    1154          44 :     if (rt->prefix_address().is_v6() && rt->prefix_length() != 128)
    1155           1 :         return false;
    1156             : 
    1157          43 :     VnEntry *vn = NULL;
    1158          43 :     if (rt->vrf() != ksync_->agent()->fabric_vrf()) {
    1159             :         //Check if VN is enabled for bridging, if not then skip mac binding.
    1160          30 :         VnEntry *vn= rt->vrf()->vn();
    1161          30 :         if (vn == NULL || (vn->bridging() == false))
    1162           4 :             return false;
    1163             :     }
    1164             : 
    1165             :     // If the route crosses a VN, we want packet to be routed. So, override
    1166          39 :     const NextHop *nh = rt->GetActiveNextHop();
    1167          39 :     if (nh == NULL)
    1168           0 :         return false;
    1169             : 
    1170          46 :     if (nh->GetType() != NextHop::INTERFACE &&
    1171          12 :         nh->GetType() != NextHop::TUNNEL &&
    1172          10 :         nh->GetType() != NextHop::VLAN &&
    1173          51 :         nh->GetType() != NextHop::VRF &&
    1174           5 :         nh->GetType() != NextHop::ARP)
    1175           3 :         return false;
    1176             : 
    1177          36 :     if (IsGatewayOrServiceInterface(nh) == true)
    1178           4 :         return false;
    1179             : 
    1180          32 :     if (nh->GetType() == NextHop::ARP &&
    1181          32 :         rt->GetActivePath()->gw_ip() == Ip4Address(0)) {
    1182           0 :         return false;
    1183             :     }
    1184             : 
    1185          32 :     if (nh->GetType() == NextHop::ARP && nh->IsValid() == false) {
    1186           0 :         return false;
    1187             :     }
    1188             : 
    1189             :     //Is this a IPAM gateway? It may happen that better path is present pointing
    1190             :     //to tunnel. In this case IPAM gateway path will not be active path and
    1191             :     //identifying same will be missed. Stitching has to be avoided on non-TSN
    1192             :     //node.
    1193             :     //This has to be done only when layer3 forwarding is enabled on VN,
    1194             :     //else mac binding should be done irrespective of IPAM gateway.
    1195          32 :     if (vn && vn->layer3_forwarding()) {
    1196           0 :         const Agent *agent = ksync()->agent();
    1197           0 :         if (agent->tsn_enabled() == false) {
    1198           0 :             const AgentPath *path = rt->FindPath(agent->local_peer());
    1199           0 :             nh = path ? path->nexthop() : NULL;
    1200             :         }
    1201           0 :         if (nh && (IsGatewayOrServiceInterface(nh) == true))
    1202           0 :             return false;
    1203             :     }
    1204             : 
    1205          32 :     return true;
    1206             : }
    1207             : 
    1208             : // Notify change to KSync entry of InetUnicast Route
    1209          33 : void VrfKSyncObject::NotifyUcRoute(VrfEntry *vrf, VrfState *state,
    1210             :                                    const IpAddress &ip) {
    1211          33 :     InetUnicastAgentRouteTable *table = NULL;
    1212          33 :     if (ip.is_v4()) {
    1213          33 :         table = vrf->GetInet4UnicastRouteTable();
    1214             :     } else {
    1215           0 :         table = vrf->GetInet6UnicastRouteTable();
    1216             :     }
    1217             : 
    1218          33 :     InetUnicastRouteEntry *rt = table->FindLPM(ip);
    1219          33 :     if (rt == NULL || rt->IsDeleted())
    1220          20 :         return;
    1221             : 
    1222          13 :     if (rt->GetTableType() == Agent::INET4_UNICAST) {
    1223          13 :         state->inet4_uc_route_table_->Notify(rt->get_table_partition(), rt);
    1224           0 :     } else if (rt->GetTableType() == Agent::INET6_UNICAST) {
    1225           0 :         state->inet6_uc_route_table_->Notify(rt->get_table_partition(), rt);
    1226             :     }
    1227             : }
    1228             : 
    1229          24 : void VrfKSyncObject::AddIpMacBinding(VrfEntry *vrf, const IpAddress &ip,
    1230             :                                      const MacAddress &mac,
    1231             :                                      uint32_t ethernet_tag,
    1232             :                                      uint32_t pref,
    1233             :                                      bool wait_for_traffic) {
    1234             :     VrfState *state = static_cast<VrfState *>
    1235          24 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1236          24 :     if (state == NULL)
    1237           0 :         return;
    1238             : 
    1239             :     IpToMacBinding::iterator it =
    1240          24 :         state->ip_mac_binding_.find(std::make_pair(ip, ethernet_tag));
    1241             : 
    1242          24 :     PathPreference path_pref(0, pref, wait_for_traffic, false);
    1243          24 :     if (it == state->ip_mac_binding_.end()) {
    1244           7 :         MacBinding mac_binding(mac, path_pref);
    1245           7 :         state->ip_mac_binding_.insert(std::pair<IpToMacBindingKey, MacBinding>
    1246           7 :                 (std::make_pair(ip, ethernet_tag), mac_binding));
    1247           7 :     } else {
    1248          17 :         it->second.set_mac(path_pref, mac);
    1249             :     }
    1250             : 
    1251          24 :     NotifyUcRoute(vrf, state, ip);
    1252          24 : }
    1253             : 
    1254           9 : void VrfKSyncObject::DelIpMacBinding(VrfEntry *vrf, const IpAddress &ip,
    1255             :                                      const MacAddress &mac,
    1256             :                                      uint32_t ethernet_tag) {
    1257             :     VrfState *state = static_cast<VrfState *>
    1258           9 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1259           9 :     if (state == NULL)
    1260           0 :         return;
    1261             : 
    1262             :     IpToMacBinding::iterator it =
    1263           9 :         state->ip_mac_binding_.find(std::make_pair(ip, ethernet_tag));
    1264           9 :     if (it != state->ip_mac_binding_.end()) {
    1265           9 :         it->second.reset_mac(mac);
    1266           9 :         if (it->second.can_erase()) {
    1267           7 :             state->ip_mac_binding_.erase(std::make_pair(ip, ethernet_tag));
    1268             :         }
    1269             :     }
    1270           9 :     NotifyUcRoute(vrf, state, ip);
    1271             : }
    1272             : 
    1273          32 : bool VrfKSyncObject::GetIpMacWaitForTraffic(VrfEntry *vrf,
    1274             :                                             const IpAddress &ip) const {
    1275             :     VrfState *state = static_cast<VrfState *>
    1276          32 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1277          32 :     if (state == NULL) {
    1278           0 :         return false;
    1279             :     }
    1280             : 
    1281             :     IpToMacBinding::const_iterator it =
    1282          32 :         state->ip_mac_binding_.lower_bound(std::make_pair(ip, 0));
    1283          50 :     if (it == state->ip_mac_binding_.end() ||
    1284          18 :         (it->first.first != ip)) {
    1285          14 :         return false;
    1286             :     }
    1287             : 
    1288          18 :     return  it->second.WaitForTraffic();
    1289             : }
    1290             : 
    1291          32 : MacAddress VrfKSyncObject::GetIpMacBinding(VrfEntry *vrf,
    1292             :                                            const IpAddress &ip,
    1293             :                                            const InetUnicastRouteEntry *rt)
    1294             :                                            const {
    1295             :     VrfState *state = static_cast<VrfState *>
    1296          32 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1297          32 :     if (state == NULL)
    1298           0 :         return MacAddress::ZeroMac();
    1299             : 
    1300          32 :     if (vrf->GetName() == ksync_->agent()->fabric_vrf_name()) {
    1301           8 :         if (rt->GetActivePath()->gw_ip() != Ip4Address(0)) {
    1302             :             const ArpNH *arp_nh =
    1303           0 :                 dynamic_cast<const ArpNH *>(rt->GetActiveNextHop());
    1304           0 :             if (arp_nh) {
    1305           0 :                 return arp_nh->GetMac();
    1306             :             }
    1307             :         }
    1308             :     }
    1309             : 
    1310             :     IpToMacBinding::const_iterator it =
    1311          32 :         state->ip_mac_binding_.lower_bound(std::make_pair(ip, 0));
    1312          50 :     if (it == state->ip_mac_binding_.end() ||
    1313          18 :         (it->first.first != ip)) {
    1314          14 :         return MacAddress::ZeroMac();
    1315             :     }
    1316             : 
    1317          18 :     return it->second.get_mac();
    1318             : }
    1319             : 
    1320           4 : KSyncRouteWalker::KSyncRouteWalker(Agent *agent, VrfKSyncObject::VrfState *state) :
    1321           4 :     AgentRouteWalker("ksyncroutewalker", agent), state_(state),
    1322           4 :     marked_for_deletion_(false) {
    1323           4 : }
    1324             : 
    1325           8 : KSyncRouteWalker::~KSyncRouteWalker() {
    1326           8 : }
    1327             : 
    1328          20 : bool IsStatePresent(AgentRoute *route, DBTableBase::ListenerId id,
    1329             :                     DBTablePartBase *partition) {
    1330          20 :     DBState *state = route->GetState(partition->parent(), id);
    1331          20 :     return (state != NULL);
    1332             : }
    1333             : 
    1334           4 : void KSyncRouteWalker::EnqueueDelete() {
    1335           4 :     marked_for_deletion_ = true;
    1336           4 :     mgr()->ReleaseWalker(static_cast<AgentRouteWalker *>(this));
    1337           4 : }
    1338             : 
    1339          22 : bool KSyncRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
    1340             :                                       DBEntryBase *e) {
    1341          22 :     if (marked_for_deletion_)
    1342           0 :         return true;
    1343             : 
    1344          22 :     AgentRoute *route = static_cast<AgentRoute *>(e);
    1345             : 
    1346          22 :     switch (route->GetTableType()) {
    1347           7 :     case Agent::INET4_UNICAST: {
    1348           7 :         if (IsStatePresent(route, state_->inet4_uc_route_table_->id(),
    1349           7 :                            partition) == false) {
    1350           0 :             state_->inet4_uc_route_table_->Notify(partition, route);
    1351             :         }
    1352           7 :         break;
    1353             :     }
    1354           1 :     case Agent::INET6_UNICAST: {
    1355           1 :         if (IsStatePresent(route, state_->inet6_uc_route_table_->id(),
    1356           1 :                            partition) == false) {
    1357           0 :             state_->inet6_uc_route_table_->Notify(partition, route);
    1358             :         }
    1359           1 :         break;
    1360             :     }
    1361           0 :     case Agent::INET4_MULTICAST: {
    1362           0 :         if (IsStatePresent(route, state_->inet4_mc_route_table_->id(),
    1363           0 :                            partition) == false) {
    1364           0 :             state_->inet4_mc_route_table_->Notify(partition, route);
    1365             :         }
    1366           0 :         break;
    1367             :     }
    1368          12 :     case Agent::BRIDGE: {
    1369          12 :         if (IsStatePresent(route, state_->bridge_route_table_->id(),
    1370          12 :                            partition) == false) {
    1371           0 :             state_->bridge_route_table_->Notify(partition, route);
    1372             :         }
    1373          12 :         break;
    1374             :     }
    1375           2 :     default: {
    1376           2 :         break;
    1377             :     }
    1378             :     }
    1379          22 :     return true;
    1380             : }
    1381             : 
    1382           4 : void KSyncRouteWalker::NotifyRoutes(VrfEntry *vrf) {
    1383           4 :     if (marked_for_deletion_ == false)
    1384           4 :         StartRouteWalk(vrf);
    1385           4 : }

Generated by: LCOV version 1.14