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: 704 802 87.8 %
Date: 2026-09-07 02:14:47 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         252 : RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj,
      40             :                                  const RouteKSyncEntry *entry,
      41         252 :                                  uint32_t index) :
      42         252 :     KSyncNetlinkDBEntry(index), ksync_obj_(obj),
      43         252 :     rt_type_(entry->rt_type_), vrf_id_(entry->vrf_id_),
      44         252 :     addr_(entry->addr_), src_addr_(entry->src_addr_), mac_(entry->mac_),
      45         252 :     prefix_len_(entry->prefix_len_), nh_(entry->nh_), label_(entry->label_),
      46         252 :     proxy_arp_(false), flood_dhcp_(entry->flood_dhcp_),
      47         252 :     address_string_(entry->address_string_),
      48         252 :     tunnel_type_(entry->tunnel_type_),
      49         252 :     wait_for_traffic_(entry->wait_for_traffic_),
      50         252 :     local_vm_peer_route_(entry->local_vm_peer_route_),
      51         252 :     flood_(entry->flood_), ethernet_tag_(entry->ethernet_tag_),
      52         252 :     layer2_control_word_(entry->layer2_control_word_),
      53         252 :     is_learnt_route_(entry->is_learnt_route_) {
      54         252 : }
      55             : 
      56         136 : RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj, const AgentRoute *rt) :
      57         136 :     KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
      58         136 :     vrf_id_(rt->vrf_id()), mac_(), nh_(NULL), label_(0), proxy_arp_(false),
      59         136 :     flood_dhcp_(false), tunnel_type_(TunnelType::DefaultType()),
      60         136 :     wait_for_traffic_(false), local_vm_peer_route_(false),
      61         136 :     flood_(false), ethernet_tag_(0), layer2_control_word_(false),
      62         272 :     is_learnt_route_(false) {
      63         136 :     boost::system::error_code ec;
      64         136 :     rt_type_ = rt->GetTableType();
      65         136 :     switch (rt_type_) {
      66          43 :     case Agent::INET4_UNICAST: {
      67          43 :           const InetUnicastRouteEntry *uc_rt =
      68             :               static_cast<const InetUnicastRouteEntry *>(rt);
      69          43 :           addr_ = uc_rt->prefix_address();
      70          43 :           src_addr_ = IpAddress::from_string("0.0.0.0", ec).to_v4();
      71          43 :           prefix_len_ = uc_rt->prefix_length();
      72          43 :           AgentPath *local_vm_path = uc_rt->FindLocalVmPortPath();
      73          43 :           if (local_vm_path && local_vm_path->IsDynamicLearntRoute()) {
      74           0 :               is_learnt_route_ = true;
      75             :           }
      76             : 
      77          43 :           break;
      78             :     }
      79          26 :     case Agent::INET6_UNICAST: {
      80          26 :           const InetUnicastRouteEntry *uc_rt =
      81             :               static_cast<const InetUnicastRouteEntry *>(rt);
      82          26 :           addr_ = uc_rt->prefix_address();
      83          26 :           src_addr_ = Ip6Address();
      84          26 :           prefix_len_ = uc_rt->prefix_length();
      85          26 :           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          67 :     case Agent::BRIDGE: {
      96          67 :           const BridgeRouteEntry *l2_rt =
      97             :               static_cast<const BridgeRouteEntry *>(rt);
      98          67 :           mac_ = l2_rt->prefix_address();
      99          67 :           prefix_len_ = 0;
     100          67 :           break;
     101             :     }
     102           0 :     default: {
     103           0 :           assert(0);
     104             :     }
     105             :     }
     106         136 :     address_string_ = rt->GetAddressString();
     107         136 : }
     108             : 
     109         640 : RouteKSyncEntry::~RouteKSyncEntry() {
     110         640 : }
     111             : 
     112        5503 : KSyncDBObject *RouteKSyncEntry::GetObject() const {
     113        5503 :     return ksync_obj_;
     114             : }
     115             : 
     116       13023 : bool RouteKSyncEntry::UcIsLess(const KSyncEntry &rhs) const {
     117       13023 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     118       13023 :     if (vrf_id_ != entry.vrf_id_) {
     119           0 :         return vrf_id_ < entry.vrf_id_;
     120             :     }
     121             : 
     122       13023 :     if (addr_ != entry.addr_) {
     123       12613 :         return addr_ < entry.addr_;
     124             :     }
     125             : 
     126         410 :     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         632 : bool RouteKSyncEntry::L2IsLess(const KSyncEntry &rhs) const {
     143         632 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     144             : 
     145         632 :     if (vrf_id_ != entry.vrf_id_) {
     146           0 :         return vrf_id_ < entry.vrf_id_;
     147             :     }
     148             : 
     149         632 :     return mac_ < entry.mac_;
     150             : }
     151             : 
     152       13655 : bool RouteKSyncEntry::IsLess(const KSyncEntry &rhs) const {
     153       13655 :     const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
     154       13655 :     if (rt_type_ != entry.rt_type_)
     155           0 :         return rt_type_ < entry.rt_type_;
     156             : 
     157             :     //First unicast
     158       13655 :     if ((rt_type_ == Agent::INET4_UNICAST) ||
     159       10078 :         (rt_type_ == Agent::INET6_UNICAST)) {
     160       13023 :         return UcIsLess(rhs);
     161             :     }
     162             : 
     163         632 :     if (rt_type_ == Agent::BRIDGE) {
     164         632 :         return L2IsLess(rhs);
     165             :     }
     166             : 
     167           0 :     return McIsLess(rhs);
     168             : }
     169             : 
     170        1108 : static std::string RouteTypeToString(Agent::RouteTableType type) {
     171        1108 :     switch (type) {
     172         433 :     case Agent::INET4_UNICAST:
     173         433 :         return "INET4_UNICAST";
     174             :         break;
     175         171 :     case Agent::INET6_UNICAST:
     176         171 :         return "INET6_UNICAST";
     177             :         break;
     178           0 :     case Agent::INET4_MULTICAST:
     179           0 :         return "INET_MULTICAST";
     180             :         break;
     181         504 :     case Agent::BRIDGE:
     182         504 :         return "BRIDGE";
     183             :         break;
     184           0 :     default:
     185           0 :         break;
     186             :     }
     187             : 
     188           0 :     assert(0);
     189             :     return "";
     190             : }
     191             : 
     192         792 : std::string RouteKSyncEntry::ToString() const {
     193         792 :     std::stringstream s;
     194             :     NHKSyncEntry *nexthop;
     195         792 :     nexthop = nh();
     196             : 
     197         792 :     s << "Type : " << RouteTypeToString(rt_type_) << " ";
     198             :     const VrfEntry* vrf =
     199         792 :         ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
     200         792 :     if (vrf) {
     201         702 :         s << "Route Vrf : " << vrf->GetName() << " ";
     202             :     }
     203         792 :     s << address_string_ << "/" << prefix_len_ << " Type:" << rt_type_;
     204             : 
     205             : 
     206         792 :     s << " Label : " << label_;
     207         792 :     s << " Tunnel Type: " << tunnel_type_;
     208             : 
     209         792 :     if (nexthop) {
     210         746 :         s << nexthop->ToString();
     211             :     } else {
     212          46 :         s << " NextHop : <NULL>";
     213             :     }
     214             : 
     215         792 :     s << " Mac: " << mac_.ToString();
     216         792 :     s << " Flood DHCP:" << flood_dhcp_;
     217        1584 :     return s.str();
     218         792 : }
     219             : 
     220             : // Check if NH points to a service-chain interface or a Gateway interface
     221         259 : static bool IsGatewayOrServiceInterface(const NextHop *nh) {
     222         314 :     if (nh->GetType() != NextHop::INTERFACE &&
     223         314 :         nh->GetType() != NextHop::VLAN && nh->GetType() != NextHop::ARP)
     224          38 :         return false;
     225             : 
     226         221 :     const Interface *intf = NULL;
     227         221 :     if (nh->GetType() == NextHop::INTERFACE) {
     228         204 :         intf = (static_cast<const InterfaceNH *>(nh))->GetInterface();
     229         204 :         if (intf->type() == Interface::PACKET)
     230          65 :             return true;
     231          17 :     } else if (nh->GetType() == NextHop::VLAN) {
     232           0 :         intf = (static_cast<const VlanNH *>(nh))->GetInterface();
     233          17 :     } else if (nh->GetType() == NextHop::ARP) {
     234          17 :         intf = (static_cast<const ArpNH *>(nh))->GetInterface();
     235             :     }
     236             : 
     237         156 :     const VmInterface *vmi = dynamic_cast<const VmInterface *>(intf);
     238         156 :     if (vmi == NULL)
     239          14 :         return false;
     240             : 
     241         142 :     if (vmi->HasServiceVlan())
     242           0 :         return true;
     243         142 :     if (vmi->device_type() == VmInterface::LOCAL_DEVICE)
     244          13 :         return true;
     245             : 
     246         129 :     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         211 : bool RouteKSyncEntry::BuildArpFlags(const DBEntry *e, const AgentPath *path,
     255             :                                     const MacAddress &mac) {
     256         211 :     bool ret = false;
     257             : 
     258             :     //Route flags for inet4 and inet6
     259         211 :     if ((rt_type_ != Agent::INET6_UNICAST) &&
     260         165 :         (rt_type_ != Agent::INET4_UNICAST))
     261           0 :         return false;
     262             : 
     263         211 :     Agent *agent = ksync_obj_->ksync()->agent();
     264         211 :     const InetUnicastRouteEntry *rt =
     265             :         static_cast<const InetUnicastRouteEntry *>(e);
     266             : 
     267             :     // Assume no flood and proxy_arp by default
     268         211 :     bool flood = false;
     269         211 :     bool proxy_arp = false;
     270         211 :     const NextHop *nh = rt->GetActiveNextHop();
     271             : 
     272         211 :     if (nh == NULL) {
     273           0 :         return false;
     274             :     }
     275         211 :     switch (nh->GetType()) {
     276           3 :     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           3 :         if (rt->vrf()->GetName() != agent->fabric_vrf_name()) {
     281           0 :             proxy_arp = true;
     282             :         }
     283           3 :         break;
     284             : 
     285             : 
     286           9 :     case NextHop::COMPOSITE:
     287             :         // ECMP flows have composite NH. We want to do routing for ECMP flows
     288             :         // So, set proxy_arp flag
     289           9 :         proxy_arp = true;
     290           9 :         break;
     291             : 
     292           4 :     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           4 :             const TunnelNH *tunnel_nh = static_cast<const TunnelNH *>(nh);
     298           4 :             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         199 :         if (mac != MacAddress::ZeroMac()) {
     310             :             // Proxy-ARP without flood if mac-stitching is present
     311          26 :             proxy_arp = true;
     312          26 :             flood = false;
     313          26 :             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         173 :         if (IsGatewayOrServiceInterface(nh) == true) {
     323          49 :             proxy_arp = true;
     324          49 :             flood = false;
     325          49 :             break;
     326             :         }
     327             : 
     328         124 :         AgentPath *local_vm_path = rt->FindLocalVmPortPath();
     329         124 :         if (local_vm_path != NULL) {
     330          58 :             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          58 :                 proxy_arp_ = false;
     341          58 :                 flood = true;
     342             :             }
     343             :         } else {
     344             :             // Non local-route. Set flags based on the route
     345          66 :             proxy_arp = rt->proxy_arp();
     346          66 :             flood = rt->ipam_host_route();
     347             :         }
     348         124 :         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         211 :     if (rt->ipam_subnet_route()) {
     355          19 :         proxy_arp = false;
     356          19 :         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         211 :     VnEntry *vn= rt->vrf()->vn();
     364         148 :     if (vn == NULL || !path->dest_vn_match(vn->GetName()) ||
     365         359 :         (path->dest_vn_list().size() > 1) ||
     366          74 :         (vn->bridging() == false)) {
     367         137 :         proxy_arp = true;
     368         137 :         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         211 :     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         211 :     if (rt->vrf()->GetName() == agent->fabric_vrf_name()) {
     380          78 :         if (mac != MacAddress() || nh->GetType() == NextHop::INTERFACE ||
     381          26 :             nh->GetType() == NextHop::COMPOSITE) {
     382          26 :             proxy_arp = true;
     383             :         } else {
     384          26 :             proxy_arp = false;
     385             :         }
     386          52 :         flood = false;
     387             :     }
     388             : 
     389         211 :     if (proxy_arp != proxy_arp_) {
     390         104 :         proxy_arp_ = proxy_arp;
     391         104 :         ret = true;
     392             :     }
     393             : 
     394         211 :     if (flood != flood_) {
     395           6 :         flood_ = flood;
     396           6 :         ret = true;
     397             :     }
     398         211 :     return ret;
     399             : }
     400             : 
     401             : //Uses internal API to extract path.
     402         376 : const NextHop *RouteKSyncEntry::GetActiveNextHop(const AgentRoute *route) const {
     403         376 :     const AgentPath *path = GetActivePath(route);
     404         376 :     if (path == NULL)
     405           0 :         return NULL;
     406         376 :     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         752 : const AgentPath *RouteKSyncEntry::GetActivePath(const AgentRoute *route) const {
     414         752 :     const AgentPath *path = route->GetActivePath();
     415         752 :     return path;
     416             : }
     417             : 
     418         376 : bool RouteKSyncEntry::Sync(DBEntry *e) {
     419         376 :     bool ret = false;
     420         376 :     Agent *agent = ksync_obj_->ksync()->agent();
     421         376 :     const AgentRoute *route = static_cast<AgentRoute *>(e);
     422             : 
     423         376 :     const AgentPath *path = GetActivePath(route);
     424         376 :     if (path->peer() == agent->local_vm_peer())
     425          37 :         local_vm_peer_route_ = true;
     426             :     else
     427         339 :         local_vm_peer_route_ = false;
     428             : 
     429         376 :     NHKSyncObject *nh_object = ksync_obj_->ksync()->nh_ksync_obj();
     430         376 :     NHKSyncEntry *old_nh = nh();
     431             : 
     432         376 :     const NextHop *tmp = NULL;
     433         376 :     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         907 :     if (tmp == NULL ||
     440         531 :         ((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         376 :     NHKSyncEntry nexthop(nh_object, tmp);
     446         376 :     nh_ = static_cast<NHKSyncEntry *>(nh_object->GetReference(&nexthop));
     447         376 :     if (old_nh != nh()) {
     448         155 :         ret = true;
     449             :     }
     450             : 
     451             :     //Bother for label for unicast and bridge routes
     452         376 :     if (rt_type_ != Agent::INET4_MULTICAST) {
     453         376 :         uint32_t old_label = label_;
     454             : 
     455         376 :         if (route->is_multicast()) {
     456          46 :             label_ = path->vxlan_id();
     457             :         } else {
     458         330 :             label_ = path->GetActiveLabel();
     459             :         }
     460         376 :         if (label_ != old_label) {
     461         111 :             ret = true;
     462             :         }
     463             : 
     464         376 :         if (tunnel_type_ != path->GetTunnelType()) {
     465          18 :             tunnel_type_ = path->GetTunnelType();
     466          18 :             ret = true;
     467             :         }
     468             :     }
     469             : 
     470         376 :     if (wait_for_traffic_ != route->WaitForTraffic()) {
     471         134 :         wait_for_traffic_ =  route->WaitForTraffic();
     472         134 :         ret = true;
     473             :     }
     474             : 
     475         376 :     if (route->GetActivePath()) {
     476         376 :         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         376 :     if (rt_type_ == Agent::INET4_UNICAST || rt_type_ == Agent::INET6_UNICAST) {
     483         211 :         VrfKSyncObject *obj = ksync_obj_->ksync()->vrf_ksync_obj();
     484         211 :         const InetUnicastRouteEntry *uc_rt =
     485             :             static_cast<const InetUnicastRouteEntry *>(e);
     486         211 :         MacAddress mac = MacAddress::ZeroMac();
     487         211 :         bool wait_for_traffic = false;
     488             : 
     489         211 :         if (obj->RouteNeedsMacBinding(uc_rt)) {
     490          53 :             mac = obj->GetIpMacBinding(uc_rt->vrf(), addr_, uc_rt);
     491          53 :             wait_for_traffic = obj->GetIpMacWaitForTraffic(uc_rt->vrf(), addr_);
     492             :         }
     493             : 
     494         211 :         if (wait_for_traffic_ == false &&
     495          20 :             wait_for_traffic_ != wait_for_traffic) {
     496           0 :             wait_for_traffic_ = wait_for_traffic;
     497           0 :             ret = true;
     498             :         }
     499             : 
     500         211 :         if (mac != mac_) {
     501           5 :             mac_ = mac;
     502           5 :             ret = true;
     503             :         }
     504             : 
     505         211 :         if (BuildArpFlags(e, path, mac_))
     506         109 :             ret = true;
     507             :     }
     508             : 
     509         376 :     if (rt_type_ == Agent::BRIDGE) {
     510         165 :         const BridgeRouteEntry *l2_rt =
     511             :             static_cast<const BridgeRouteEntry *>(route);
     512             : 
     513             :         //First search for v4
     514         165 :         const MacVmBindingPath *dhcp_path = l2_rt->FindMacVmBindingPath();
     515         165 :         bool flood_dhcp = true; // Flood DHCP if MacVmBindingPath is not present
     516         165 :         if (dhcp_path)
     517          50 :             flood_dhcp = dhcp_path->flood_dhcp();
     518             : 
     519         165 :         if (flood_dhcp_ != flood_dhcp) {
     520          48 :             flood_dhcp_ = flood_dhcp;
     521          48 :             ret = true;
     522             :         }
     523             :     }
     524             : 
     525         376 :     return ret;
     526         376 : }
     527             : 
     528         316 : void RouteKSyncEntry::FillObjectLog(sandesh_op::type type,
     529             :                                     KSyncRouteInfo &info) const {
     530         316 :     if (type == sandesh_op::ADD) {
     531         190 :         info.set_operation("ADD/CHANGE");
     532             :     } else {
     533         126 :         info.set_operation("DELETE");
     534             :     }
     535             : 
     536         316 :     info.set_addr(address_string_);
     537         316 :     info.set_plen(prefix_len_);
     538         316 :     info.set_vrf(vrf_id_);
     539             : 
     540         316 :     if (nh()) {
     541         270 :         info.set_nh_idx(nh()->nh_id());
     542         270 :         if (nh()->type() == NextHop::TUNNEL) {
     543          17 :             info.set_label(label_);
     544             :         }
     545             :     } else {
     546          46 :         info.set_nh_idx(NH_DISCARD_ID);
     547             :     }
     548             : 
     549         316 :     info.set_mac(mac_.ToString());
     550         316 :     info.set_type(RouteTypeToString(rt_type_));
     551         316 : }
     552             : 
     553         316 : int RouteKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen,
     554             :                             char *buf, int buf_len) {
     555         316 :     vr_route_req encoder;
     556             :     int encode_len;
     557         316 :     NHKSyncEntry *nexthop = nh();
     558             : 
     559         316 :     encoder.set_h_op(op);
     560         316 :     encoder.set_rtr_rid(0);
     561         316 :     encoder.set_rtr_vrf_id(vrf_id_);
     562         316 :     if (rt_type_ != Agent::BRIDGE) {
     563         176 :         if (addr_.is_v4()) {
     564         124 :             encoder.set_rtr_family(AF_INET);
     565         124 :             Ip4Address::bytes_type bytes = addr_.to_v4().to_bytes();
     566         124 :             std::vector<int8_t> rtr_prefix(bytes.begin(), bytes.end());
     567         124 :             encoder.set_rtr_prefix(rtr_prefix);
     568         176 :         } else if (addr_.is_v6()) {
     569          52 :             encoder.set_rtr_family(AF_INET6);
     570          52 :             Ip6Address::bytes_type bytes = addr_.to_v6().to_bytes();
     571          52 :             std::vector<int8_t> rtr_prefix(bytes.begin(), bytes.end());
     572          52 :             encoder.set_rtr_prefix(rtr_prefix);
     573          52 :         }
     574         176 :         encoder.set_rtr_prefix_len(prefix_len_);
     575         176 :         if (mac_ != MacAddress::ZeroMac()) {
     576          10 :             if ((addr_.is_v4() && prefix_len_ != 32) ||
     577           5 :                 (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           5 :                                     (int8_t *)mac_ + mac_.size());
     584           5 :             encoder.set_rtr_mac(mac);
     585           5 :         }
     586             :     } else {
     587         140 :         encoder.set_rtr_family(AF_BRIDGE);
     588             :         //TODO add support for mac
     589             :         std::vector<int8_t> mac((int8_t *)mac_,
     590         140 :                                 (int8_t *)mac_ + mac_.size());
     591         140 :         encoder.set_rtr_mac(mac);
     592         140 :     }
     593             : 
     594         316 :     int label = 0;
     595         316 :     int flags = 0;
     596         316 :     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         608 :         if (nexthop != NULL && ((nexthop->type() == NextHop::TUNNEL) ||
     601         292 :                     ((nexthop->type() == NextHop::COMPOSITE) &&
     602          39 :                     (nexthop->CompositeType() == Composite::LU_ECMP)))) {
     603          17 :             label = label_;
     604          17 :             flags |= VR_RT_LABEL_VALID_FLAG;
     605             :         }
     606             :     }
     607             : 
     608         316 :     if (rt_type_ == Agent::BRIDGE) {
     609         140 :         label = label_;
     610         245 :         if (nexthop != NULL && ((nexthop->type() == NextHop::COMPOSITE) ||
     611         105 :                                (nexthop->type() == NextHop::TUNNEL))) {
     612          48 :             flags |= VR_BE_LABEL_VALID_FLAG;
     613             :         }
     614         140 :         if (flood_dhcp_) {
     615         114 :             flags |= VR_BE_FLOOD_DHCP_FLAG;
     616             :         }
     617         140 :         if (ksync_obj_->ksync()->agent()->tsn_no_forwarding_enabled()) {
     618           0 :             flags |= VR_BE_EVPN_CONTROL_PROCESSING_FLAG;
     619             :         }
     620             :     } else {
     621             : 
     622         176 :         if (proxy_arp_) {
     623          94 :             flags |= VR_RT_ARP_PROXY_FLAG;
     624             :         }
     625             : 
     626         176 :         if (wait_for_traffic_) {
     627         113 :             flags |= VR_RT_ARP_TRAP_FLAG;
     628             :         }
     629             : 
     630         176 :         if (flood_) {
     631          16 :             flags |= VR_RT_ARP_FLOOD_FLAG;
     632             :         }
     633             :        
     634         176 :         if (is_learnt_route_) {
     635           0 :             flags |= VR_RT_MAC_IP_LEARNT_FLAG;
     636             :         }
     637             : 
     638             :     }
     639             : 
     640         316 :     if (layer2_control_word_) {
     641           0 :         flags |= VR_BE_L2_CONTROL_DATA_FLAG;
     642             :     }
     643             : 
     644         316 :     encoder.set_rtr_label_flags(flags);
     645         316 :     encoder.set_rtr_label(label);
     646         316 :     if (nexthop != NULL) {
     647         270 :         encoder.set_rtr_nh_id(nexthop->nh_id());
     648             :     } else {
     649          46 :         encoder.set_rtr_nh_id(NH_DISCARD_ID);
     650             :     }
     651             : 
     652         316 :     if (op == sandesh_op::DEL) {
     653         126 :         encoder.set_rtr_replace_plen(replace_plen);
     654             :     }
     655             : 
     656         316 :     int error = 0;
     657         316 :     encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
     658         316 :     assert(error == 0);
     659         316 :     assert(encode_len <= buf_len);
     660         316 :     return encode_len;
     661         316 : }
     662             : 
     663             : 
     664         126 : int RouteKSyncEntry::AddMsg(char *buf, int buf_len) {
     665         126 :     KSyncRouteInfo info;
     666         126 :     FillObjectLog(sandesh_op::ADD, info);
     667         126 :     KSYNC_TRACE(Route, GetObject(), info);
     668         252 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     669         126 : }
     670             : 
     671          64 : int RouteKSyncEntry::ChangeMsg(char *buf, int buf_len){
     672          64 :     KSyncRouteInfo info;
     673          64 :     FillObjectLog(sandesh_op::ADD, info);
     674          64 :     KSYNC_TRACE(Route, GetObject(), info);
     675             : 
     676         128 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     677          64 : }
     678             : 
     679         126 : int RouteKSyncEntry::DeleteMsg(char *buf, int buf_len) {
     680             : 
     681         126 :     RouteKSyncEntry key(ksync_obj_, this, KSyncEntry::kInvalidIndex);
     682         126 :     KSyncEntry *found = NULL;
     683         126 :     RouteKSyncEntry *route = NULL;
     684         126 :     NHKSyncEntry *ksync_nh = NULL;
     685             : 
     686             :     // IF multicast or bridge delete unconditionally
     687         126 :     if ((rt_type_ == Agent::BRIDGE) ||
     688          69 :         (rt_type_ == Agent::INET4_MULTICAST)) {
     689          57 :         return DeleteInternal(nh(), NULL, buf, buf_len);
     690             :     }
     691             : 
     692             :     // For INET routes, we need to give replacement NH and prefixlen
     693        4230 :     for (int plen = (prefix_len() - 1); plen >= 0; plen--) {
     694             : 
     695        4184 :         if (addr_.is_v4()) {
     696         976 :             Ip4Address addr = Address::GetIp4SubnetAddress(addr_.to_v4(), plen);
     697         976 :             key.set_ip(addr);
     698        3208 :         } else if (addr_.is_v6()) {
     699        3208 :             Ip6Address addr = Address::GetIp6SubnetAddress(addr_.to_v6(), plen);
     700        3208 :             key.set_ip(addr);
     701             :         }
     702             : 
     703        4184 :         key.set_prefix_len(plen);
     704        4184 :         found = GetObject()->Find(&key);
     705             : 
     706        4184 :         if (found) {
     707          27 :             route = static_cast<RouteKSyncEntry *>(found);
     708          27 :             if (route->IsResolved()) {
     709          23 :                 ksync_nh = route->nh();
     710          23 :                 if(ksync_nh) {
     711          23 :                     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          46 :     return DeleteInternal(NULL, NULL, buf, buf_len);
     720         126 : }
     721             : 
     722         126 : uint8_t RouteKSyncEntry::CopyReplacementData(NHKSyncEntry *nexthop,
     723             :                                              RouteKSyncEntry *new_rt) {
     724         126 :     uint8_t new_plen = 0;
     725         126 :     nh_ = nexthop;
     726         126 :     if (new_rt == NULL) {
     727         103 :         label_ = 0;
     728         103 :         proxy_arp_ = false;
     729         103 :         flood_ = false;
     730         103 :         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         103 :         if (rt_type_ != Agent::BRIDGE) {
     734          46 :             mac_ = MacAddress::ZeroMac();
     735             :         }
     736         103 :         is_learnt_route_ = false;
     737             :     } else {
     738          23 :         label_ = new_rt->label();
     739          23 :         new_plen = new_rt->prefix_len();
     740          23 :         proxy_arp_ = new_rt->proxy_arp();
     741          23 :         flood_ = new_rt->flood();
     742          23 :         wait_for_traffic_ = new_rt->wait_for_traffic();
     743          23 :         mac_ = new_rt->mac();
     744          23 :         is_learnt_route_ = new_rt->IsLearntRoute();
     745             :     }
     746         126 :     return new_plen;
     747             : }
     748             : 
     749         126 : int RouteKSyncEntry::DeleteInternal(NHKSyncEntry *nexthop,
     750             :                                     RouteKSyncEntry *new_rt,
     751             :                                     char *buf, int buf_len) {
     752         126 :     uint8_t replace_plen = CopyReplacementData(nexthop, new_rt);
     753         126 :     KSyncRouteInfo info;
     754         126 :     FillObjectLog(sandesh_op::DEL, info);
     755         126 :     KSYNC_TRACE(Route, GetObject(), info);
     756             : 
     757         252 :     return Encode(sandesh_op::DEL, replace_plen, buf, buf_len);
     758         126 : }
     759             : 
     760         346 : KSyncEntry *RouteKSyncEntry::UnresolvedReference() {
     761         346 :     NHKSyncEntry *nexthop = nh();
     762         346 :     if (!nexthop->IsResolvedAndInSync()) {
     763         151 :         return nexthop;
     764             :     }
     765             : 
     766         195 :     if ((rt_type_ == Agent::INET4_UNICAST) ||
     767         109 :         (rt_type_ == Agent::INET6_UNICAST)) {
     768         112 :         if (!mac_.IsZero()) {
     769             :             //Get Vrf and bridge ksync object
     770          10 :             VrfKSyncObject *vrf_obj = ksync_obj_->ksync()->vrf_ksync_obj();
     771             :             VrfEntry* vrf =
     772          10 :                 ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
     773          10 :             if (vrf) {
     774             :                 VrfKSyncObject::VrfState *state =
     775             :                     static_cast<VrfKSyncObject::VrfState *>
     776          10 :                     (vrf->GetState(vrf->get_table(),
     777             :                                    vrf_obj->vrf_listener_id()));
     778          10 :                 RouteKSyncObject* bridge_ksync_obj = state->bridge_route_table_;
     779          10 :                 BridgeRouteEntry tmp_l2_rt(vrf, mac_, Peer::EVPN_PEER, false);
     780          10 :                 RouteKSyncEntry key(bridge_ksync_obj, &tmp_l2_rt);
     781             :                 RouteKSyncEntry *mac_route_reference =
     782             :                     static_cast<RouteKSyncEntry *>(bridge_ksync_obj->
     783          10 :                                                    GetReference(&key));
     784             :                 //Get the ksync entry for stitched mac
     785             :                 //else mark dependancy on same.
     786          10 :                 if (!mac_route_reference->IsResolved())
     787           5 :                     return mac_route_reference;
     788          15 :             } else {
     789             :                 // clear the mac_ to avoid failure in programming vrouter
     790           0 :                 mac_ = MacAddress::ZeroMac();
     791             :             }
     792             :         }
     793             :     }
     794             : 
     795         190 :     return NULL;
     796             : }
     797             : 
     798          36 : RouteKSyncObject::RouteKSyncObject(KSync *ksync, AgentRouteTable *rt_table):
     799          36 :     KSyncDBObject("KSync Route"), ksync_(ksync), marked_delete_(false),
     800          36 :     table_delete_ref_(this, rt_table->deleter()) {
     801          36 :     rt_table_ = rt_table;
     802          36 :     RegisterDb(rt_table);
     803          36 : }
     804             : 
     805          72 : RouteKSyncObject::~RouteKSyncObject() {
     806          36 :     UnregisterDb(GetDBTable());
     807          36 :     table_delete_ref_.Reset(NULL);
     808          72 : }
     809             : 
     810             : KSyncDBObject::DBFilterResp
     811         376 : RouteKSyncObject::DBEntryFilter(const DBEntry *entry,
     812             :                                 const KSyncDBEntry *ksync) {
     813         376 :     const AgentRoute *route = static_cast<const AgentRoute *>(entry);
     814             :     // Ignore Add/Change notifications when VRF is deleted
     815         376 :     if (route->vrf()->IsDeleted() == true) {
     816           0 :         return DBFilterIgnore;
     817             :     }
     818             : 
     819         376 :     if (route->GetActivePath()->inactive())
     820           0 :         return DBFilterIgnore;
     821         376 :     return DBFilterAccept;
     822             : }
     823             : 
     824         126 : KSyncEntry *RouteKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
     825         126 :     const RouteKSyncEntry *route = static_cast<const RouteKSyncEntry *>(entry);
     826         126 :     RouteKSyncEntry *ksync = new RouteKSyncEntry(this, route, index);
     827         126 :     return static_cast<KSyncEntry *>(ksync);
     828             : }
     829             : 
     830         126 : KSyncEntry *RouteKSyncObject::DBToKSyncEntry(const DBEntry *e) {
     831         126 :     const AgentRoute *route = static_cast<const AgentRoute *>(e);
     832         126 :     RouteKSyncEntry *key = new RouteKSyncEntry(this, route);
     833         126 :     return static_cast<KSyncEntry *>(key);
     834             : }
     835             : 
     836          49 : void RouteKSyncObject::Unregister() {
     837          49 :     if (IsEmpty() == true && marked_delete_ == true) {
     838          36 :         KSYNC_TRACE(Trace, this, "Destroying ksync object: "\
     839             :                     + rt_table_->name());
     840          36 :         KSyncObjectManager::Unregister(this);
     841             :     }
     842          49 : }
     843             : 
     844          36 : void RouteKSyncObject::ManagedDelete() {
     845          36 :     marked_delete_ = true;
     846          36 :     Unregister();
     847          36 : }
     848             : 
     849          24 : void RouteKSyncObject::EmptyTable() {
     850          24 :     if (marked_delete_ == true) {
     851          13 :         Unregister();
     852             :     }
     853          24 : }
     854             : 
     855           9 : VrfKSyncEntry::VrfKSyncEntry(VrfKSyncObject *obj, const VrfEntry *entry) :
     856           9 :     KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
     857           9 :     vrf_id_(entry->vrf_id()), hbf_rintf_(entry->hbf_rintf()),
     858          18 :     hbf_lintf_(entry->hbf_lintf()) {
     859           9 : }
     860             : 
     861           9 : VrfKSyncEntry::VrfKSyncEntry(VrfKSyncObject *obj,
     862             :                              const VrfKSyncEntry *entry,
     863           9 :                              uint32_t index) :
     864             :     KSyncNetlinkDBEntry(index),
     865           9 :     vrf_id_(entry->vrf_id()), hbf_rintf_(entry->hbf_rintf()),
     866          18 :     hbf_lintf_(entry->hbf_lintf()) {
     867           9 :         ksync_obj_ = static_cast<VrfKSyncObject*>(entry->GetObject());
     868           9 : }
     869             : 
     870          36 : VrfKSyncEntry::~VrfKSyncEntry() {
     871          36 : }
     872             : 
     873          54 : KSyncDBObject *VrfKSyncEntry::GetObject() const {
     874          54 :         return ksync_obj_;
     875             : }
     876             : 
     877          58 : bool VrfKSyncEntry::IsLess(const KSyncEntry &rhs) const {
     878          58 :     const VrfKSyncEntry &entry = static_cast<const VrfKSyncEntry &> (rhs);
     879             : 
     880          58 :     if (vrf_id_ == entry.vrf_id()) {
     881          18 :         if (hbf_rintf_ == entry.hbf_rintf()) {
     882          18 :             return (hbf_lintf_ < entry.hbf_lintf());
     883             :         } else {
     884           0 :             return (hbf_rintf_ < entry.hbf_rintf());
     885             :         }
     886             :     } else {
     887          40 :         return (vrf_id_ < entry.vrf_id());
     888             :     }
     889             : }
     890             : 
     891          36 : std::string VrfKSyncEntry::ToString() const {
     892          36 :     std::stringstream s;
     893          36 :     s << "Vrf id: " << vrf_id() << " hbf lintf: " << hbf_lintf() <<
     894          36 :         " hbf rintf: " << hbf_rintf();
     895          72 :     return s.str();
     896          36 : }
     897             : 
     898           6 : bool VrfKSyncEntry::Sync(DBEntry* e) {
     899           6 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
     900             : 
     901          12 :     if ((vrf->hbf_rintf() != hbf_rintf_) ||
     902           6 :         (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           6 :     return false;
     909             : }
     910             : 
     911          18 : int VrfKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen,
     912             :                             char *buf, int buf_len) {
     913          18 :     vr_vrf_req encoder;
     914             :     int encode_len;
     915             : 
     916          18 :     encoder.set_h_op(op);
     917          18 :     encoder.set_vrf_idx(vrf_id_);
     918          18 :     encoder.set_vrf_hbfr_vif_idx(hbf_rintf_);
     919          18 :     encoder.set_vrf_hbfl_vif_idx(hbf_lintf_);
     920          18 :     encoder.set_vrf_flags(VRF_FLAG_HBF_L_VALID|VRF_FLAG_HBF_R_VALID);
     921             : 
     922          18 :     std::stringstream ss;
     923          18 :     ss << "Encoding VrfKSyncEntry, vrf_id_ " << vrf_id_ <<
     924          18 :          " hbf_rintf_ " << hbf_rintf_ << " hbf_lintf_ " << hbf_lintf_;
     925          18 :     HBFTRACE(Trace, ss.str());
     926             : 
     927          18 :     int error = 0;
     928          18 :     encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
     929          18 :     assert(error == 0);
     930          18 :     assert(encode_len <= buf_len);
     931          18 :     return encode_len;
     932          18 : }
     933             : 
     934          18 : void VrfKSyncEntry::FillObjectLog(sandesh_op::type type,
     935             :                                     KSyncVrfInfo &info) const {
     936          18 :     if (type == sandesh_op::ADD) {
     937           9 :         info.set_operation("ADD/CHANGE");
     938             :     } else {
     939           9 :         info.set_operation("DELETE");
     940             :     }
     941             : 
     942          18 :     info.set_vrf_id(vrf_id_);
     943          18 :     info.set_hbf_rintf(hbf_rintf_);
     944          18 :     info.set_hbf_lintf(hbf_lintf_);
     945          18 : }
     946             : 
     947           9 : int VrfKSyncEntry::AddMsg(char *buf, int buf_len) {
     948           9 :     KSyncVrfInfo info;
     949           9 :     FillObjectLog(sandesh_op::ADD, info);
     950           9 :     KSYNC_TRACE(Vrf, GetObject(), info);
     951          18 :     return Encode(sandesh_op::ADD, 0, buf, buf_len);
     952           9 : }
     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           9 : int VrfKSyncEntry::DeleteMsg(char *buf, int buf_len) {
     963           9 :     KSyncVrfInfo info;
     964           9 :     FillObjectLog(sandesh_op::DEL, info);
     965           9 :     KSYNC_TRACE(Vrf, GetObject(), info);
     966             : 
     967          18 :     return Encode(sandesh_op::DEL, 0, buf, buf_len);
     968           9 : }
     969             : 
     970           9 : KSyncEntry *VrfKSyncEntry::UnresolvedReference() {
     971           9 :     return NULL; // TODO: check this
     972             : }
     973             : 
     974           9 : VrfKSyncObject::VrfState::VrfState(Agent *agent) :
     975           9 :     DBState(), seen_(false),
     976           9 :     evpn_rt_table_listener_id_(DBTableBase::kInvalidId) {
     977           9 :     ksync_route_walker_.reset(new KSyncRouteWalker(agent, this));
     978             :     agent->oper_db()->agent_route_walk_manager()->
     979           9 :         RegisterWalker(static_cast<AgentRouteWalker *>
     980             :                        (ksync_route_walker_.get()));
     981           9 : }
     982             : 
     983           9 : KSyncEntry *VrfKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
     984           9 :     const VrfKSyncEntry *vrf = static_cast<const VrfKSyncEntry *>(entry);
     985           9 :     VrfKSyncEntry *ksync = new VrfKSyncEntry(this, vrf, index);
     986           9 :     return static_cast<KSyncEntry *>(ksync);
     987             : }
     988             : 
     989           9 : KSyncEntry *VrfKSyncObject::DBToKSyncEntry(const DBEntry* e) {
     990           9 :     const VrfEntry *vrf = static_cast<const VrfEntry *>(e);
     991           9 :     VrfKSyncEntry *key = new VrfKSyncEntry(this, vrf);
     992           9 :     return static_cast<KSyncEntry *>(key);
     993             : }
     994             : 
     995          83 : void VrfKSyncObject::VrfNotify(DBTablePartBase *partition, DBEntryBase *e) {
     996          83 :     VrfEntry *vrf = static_cast<VrfEntry *>(e);
     997             :     VrfState *state = static_cast<VrfState *>
     998          83 :         (vrf->GetState(partition->parent(), vrf_listener_id_));
     999          83 :     if (vrf->IsDeleted()) {
    1000          68 :         if (state) {
    1001           9 :             UnRegisterEvpnRouteTableListener(vrf, state);
    1002           9 :             vrf->ClearState(partition->parent(), vrf_listener_id_);
    1003           9 :             (static_cast<KSyncRouteWalker *>(state->ksync_route_walker_.get()))->EnqueueDelete();
    1004             : 
    1005           9 :             if (state->ksync_->IsDeleted() == false) {
    1006           9 :                 if (state->ksync_->GetDBEntry() != NULL) {
    1007           9 :                     state->ksync_->SetDBEntry(NULL);
    1008             :                 }
    1009           9 :                 NotifyEvent(state->ksync_, KSyncEntry::DEL_REQ);
    1010             :             }
    1011             : 
    1012           9 :             delete state;
    1013             :         }
    1014          68 :         return;
    1015             :     }
    1016             : 
    1017          15 :     if (state == NULL) {
    1018           9 :         state = new VrfState(ksync_->agent());
    1019           9 :         state->seen_ = true;
    1020             : 
    1021             :         // Create ksync entry for VRF
    1022             :         KSyncEntry *key;
    1023           9 :         key = DBToKSyncEntry(vrf);
    1024           9 :         state->ksync_ = static_cast<VrfKSyncEntry *>(CreateImpl(key));
    1025           9 :         delete key;
    1026           9 :         vrf->SetState(partition->parent(), vrf_listener_id_, state);
    1027           9 :         state->ksync_->SetDBEntry(vrf);
    1028           9 :         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           9 :                           GetInet4UnicastRouteTable());
    1033           9 :         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           9 :                           GetInet6UnicastRouteTable());
    1038           9 :         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           9 :                           GetBridgeRouteTable());
    1043           9 :         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           9 :                           GetInet4MulticastRouteTable());
    1051           9 :         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           9 :                                                   GetEvpnRouteTable());
    1056           9 :         KSYNC_TRACE(Trace, state->inet4_uc_route_table_,
    1057             :                     "Subscribing to route table "\
    1058             :                     + vrf->GetName());
    1059           9 :         if (state->evpn_rt_table_listener_id_ == DBTableBase::kInvalidId) {
    1060           9 :             state->evpn_rt_table_listener_id_ =
    1061           9 :                 rt_table->Register(boost::bind(&VrfKSyncObject::EvpnRouteTableNotify,
    1062             :                                            this, _1, _2));
    1063             :         }
    1064           9 :         (static_cast<KSyncRouteWalker *>(state->ksync_route_walker_.get()))->
    1065           9 :             NotifyRoutes(vrf);
    1066             :     } else {
    1067           6 :         VrfKSyncEntry* ksync = state->ksync_;
    1068           6 :         if (ksync->Sync(vrf) || ksync->IsDeleted()) {
    1069           0 :             NotifyEvent(ksync, KSyncEntry::ADD_CHANGE_REQ);
    1070             :         }
    1071             :     }
    1072             : }
    1073             : 
    1074         106 : void VrfKSyncObject::EvpnRouteTableNotify(DBTablePartBase *partition,
    1075             :                                           DBEntryBase *e) {
    1076         106 :     const EvpnRouteEntry *evpn_rt = static_cast<const EvpnRouteEntry *>(e);
    1077             : 
    1078         106 :     if (evpn_rt->IsType5())
    1079           0 :         return;
    1080             : 
    1081         106 :     if (evpn_rt->IsDeleted()) {
    1082          31 :         DelIpMacBinding(evpn_rt->vrf(), evpn_rt->prefix_address(),
    1083             :                         evpn_rt->mac(), evpn_rt->ethernet_tag());
    1084             :     } else {
    1085          75 :         AddIpMacBinding(evpn_rt->vrf(), evpn_rt->prefix_address(),
    1086             :                         evpn_rt->mac(),
    1087             :                         evpn_rt->ethernet_tag(),
    1088          75 :                         evpn_rt->GetActivePath()->path_preference().preference(),
    1089          75 :                         evpn_rt->WaitForTraffic());
    1090             :     }
    1091         106 :     return;
    1092             : }
    1093             : 
    1094           9 : void VrfKSyncObject::UnRegisterEvpnRouteTableListener(const VrfEntry *vrf,
    1095             :                                                       VrfState *state) {
    1096           9 :     if (state->evpn_rt_table_listener_id_ == DBTableBase::kInvalidId)
    1097           0 :         return;
    1098             : 
    1099             :     AgentRouteTable *rt_table = static_cast<AgentRouteTable *>(vrf->
    1100           9 :                                             GetEvpnRouteTable());
    1101           9 :     rt_table->Unregister(state->evpn_rt_table_listener_id_);
    1102           9 :     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         316 : void vr_route_req::Process(SandeshContext *context) {
    1124         316 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    1125         316 :     ioc->RouteMsgHandler(this);
    1126         316 : }
    1127             : 
    1128          18 : void vr_vrf_req::Process(SandeshContext *context) {
    1129          18 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    1130          18 :     ioc->VrfMsgHandler(this);
    1131          18 : }
    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         211 : bool VrfKSyncObject::RouteNeedsMacBinding(const InetUnicastRouteEntry *rt) {
    1151         211 :     if (rt->prefix_address().is_v4() && rt->prefix_length() != 32)
    1152          39 :         return false;
    1153             : 
    1154         172 :     if (rt->prefix_address().is_v6() && rt->prefix_length() != 128)
    1155           3 :         return false;
    1156             : 
    1157         169 :     VnEntry *vn = NULL;
    1158         169 :     if (rt->vrf() != ksync_->agent()->fabric_vrf()) {
    1159             :         //Check if VN is enabled for bridging, if not then skip mac binding.
    1160         133 :         VnEntry *vn= rt->vrf()->vn();
    1161         133 :         if (vn == NULL || (vn->bridging() == false))
    1162          78 :             return false;
    1163             :     }
    1164             : 
    1165             :     // If the route crosses a VN, we want packet to be routed. So, override
    1166          91 :     const NextHop *nh = rt->GetActiveNextHop();
    1167          91 :     if (nh == NULL)
    1168           0 :         return false;
    1169             : 
    1170         102 :     if (nh->GetType() != NextHop::INTERFACE &&
    1171          21 :         nh->GetType() != NextHop::TUNNEL &&
    1172          20 :         nh->GetType() != NextHop::VLAN &&
    1173         112 :         nh->GetType() != NextHop::VRF &&
    1174          10 :         nh->GetType() != NextHop::ARP)
    1175           5 :         return false;
    1176             : 
    1177          86 :     if (IsGatewayOrServiceInterface(nh) == true)
    1178          29 :         return false;
    1179             : 
    1180          61 :     if (nh->GetType() == NextHop::ARP &&
    1181          61 :         rt->GetActivePath()->gw_ip() == Ip4Address(0)) {
    1182           4 :         return false;
    1183             :     }
    1184             : 
    1185          53 :     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          53 :     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          53 :     return true;
    1206             : }
    1207             : 
    1208             : // Notify change to KSync entry of InetUnicast Route
    1209         106 : void VrfKSyncObject::NotifyUcRoute(VrfEntry *vrf, VrfState *state,
    1210             :                                    const IpAddress &ip) {
    1211         106 :     InetUnicastAgentRouteTable *table = NULL;
    1212         106 :     if (ip.is_v4()) {
    1213         106 :         table = vrf->GetInet4UnicastRouteTable();
    1214             :     } else {
    1215           0 :         table = vrf->GetInet6UnicastRouteTable();
    1216             :     }
    1217             : 
    1218         106 :     InetUnicastRouteEntry *rt = table->FindLPM(ip);
    1219         106 :     if (rt == NULL || rt->IsDeleted())
    1220          65 :         return;
    1221             : 
    1222          41 :     if (rt->GetTableType() == Agent::INET4_UNICAST) {
    1223          41 :         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          75 : 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          75 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1236          75 :     if (state == NULL)
    1237           0 :         return;
    1238             : 
    1239             :     IpToMacBinding::iterator it =
    1240          75 :         state->ip_mac_binding_.find(std::make_pair(ip, ethernet_tag));
    1241             : 
    1242          75 :     PathPreference path_pref(0, pref, wait_for_traffic, false);
    1243          75 :     if (it == state->ip_mac_binding_.end()) {
    1244          20 :         MacBinding mac_binding(mac, path_pref);
    1245          20 :         state->ip_mac_binding_.insert(std::pair<IpToMacBindingKey, MacBinding>
    1246          20 :                 (std::make_pair(ip, ethernet_tag), mac_binding));
    1247          20 :     } else {
    1248          55 :         it->second.set_mac(path_pref, mac);
    1249             :     }
    1250             : 
    1251          75 :     NotifyUcRoute(vrf, state, ip);
    1252          75 : }
    1253             : 
    1254          31 : void VrfKSyncObject::DelIpMacBinding(VrfEntry *vrf, const IpAddress &ip,
    1255             :                                      const MacAddress &mac,
    1256             :                                      uint32_t ethernet_tag) {
    1257             :     VrfState *state = static_cast<VrfState *>
    1258          31 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1259          31 :     if (state == NULL)
    1260           0 :         return;
    1261             : 
    1262             :     IpToMacBinding::iterator it =
    1263          31 :         state->ip_mac_binding_.find(std::make_pair(ip, ethernet_tag));
    1264          31 :     if (it != state->ip_mac_binding_.end()) {
    1265          31 :         it->second.reset_mac(mac);
    1266          31 :         if (it->second.can_erase()) {
    1267          19 :             state->ip_mac_binding_.erase(std::make_pair(ip, ethernet_tag));
    1268             :         }
    1269             :     }
    1270          31 :     NotifyUcRoute(vrf, state, ip);
    1271             : }
    1272             : 
    1273          53 : bool VrfKSyncObject::GetIpMacWaitForTraffic(VrfEntry *vrf,
    1274             :                                             const IpAddress &ip) const {
    1275             :     VrfState *state = static_cast<VrfState *>
    1276          53 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1277          53 :     if (state == NULL) {
    1278           0 :         return false;
    1279             :     }
    1280             : 
    1281             :     IpToMacBinding::const_iterator it =
    1282          53 :         state->ip_mac_binding_.lower_bound(std::make_pair(ip, 0));
    1283          79 :     if (it == state->ip_mac_binding_.end() ||
    1284          26 :         (it->first.first != ip)) {
    1285          27 :         return false;
    1286             :     }
    1287             : 
    1288          26 :     return  it->second.WaitForTraffic();
    1289             : }
    1290             : 
    1291          53 : MacAddress VrfKSyncObject::GetIpMacBinding(VrfEntry *vrf,
    1292             :                                            const IpAddress &ip,
    1293             :                                            const InetUnicastRouteEntry *rt)
    1294             :                                            const {
    1295             :     VrfState *state = static_cast<VrfState *>
    1296          53 :         (vrf->GetState(vrf->get_table(), vrf_listener_id_));
    1297          53 :     if (state == NULL)
    1298           0 :         return MacAddress::ZeroMac();
    1299             : 
    1300          53 :     if (vrf->GetName() == ksync_->agent()->fabric_vrf_name()) {
    1301          26 :         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          53 :         state->ip_mac_binding_.lower_bound(std::make_pair(ip, 0));
    1312          79 :     if (it == state->ip_mac_binding_.end() ||
    1313          26 :         (it->first.first != ip)) {
    1314          27 :         return MacAddress::ZeroMac();
    1315             :     }
    1316             : 
    1317          26 :     return it->second.get_mac();
    1318             : }
    1319             : 
    1320           9 : KSyncRouteWalker::KSyncRouteWalker(Agent *agent, VrfKSyncObject::VrfState *state) :
    1321           9 :     AgentRouteWalker("ksyncroutewalker", agent), state_(state),
    1322           9 :     marked_for_deletion_(false) {
    1323           9 : }
    1324             : 
    1325          18 : KSyncRouteWalker::~KSyncRouteWalker() {
    1326          18 : }
    1327             : 
    1328          44 : bool IsStatePresent(AgentRoute *route, DBTableBase::ListenerId id,
    1329             :                     DBTablePartBase *partition) {
    1330          44 :     DBState *state = route->GetState(partition->parent(), id);
    1331          44 :     return (state != NULL);
    1332             : }
    1333             : 
    1334           9 : void KSyncRouteWalker::EnqueueDelete() {
    1335           9 :     marked_for_deletion_ = true;
    1336           9 :     mgr()->ReleaseWalker(static_cast<AgentRouteWalker *>(this));
    1337           9 : }
    1338             : 
    1339          46 : bool KSyncRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
    1340             :                                       DBEntryBase *e) {
    1341          46 :     if (marked_for_deletion_)
    1342           0 :         return true;
    1343             : 
    1344          46 :     AgentRoute *route = static_cast<AgentRoute *>(e);
    1345             : 
    1346          46 :     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           4 :     case Agent::INET6_UNICAST: {
    1355           4 :         if (IsStatePresent(route, state_->inet6_uc_route_table_->id(),
    1356           4 :                            partition) == false) {
    1357           0 :             state_->inet6_uc_route_table_->Notify(partition, route);
    1358             :         }
    1359           4 :         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          33 :     case Agent::BRIDGE: {
    1369          33 :         if (IsStatePresent(route, state_->bridge_route_table_->id(),
    1370          33 :                            partition) == false) {
    1371           0 :             state_->bridge_route_table_->Notify(partition, route);
    1372             :         }
    1373          33 :         break;
    1374             :     }
    1375           2 :     default: {
    1376           2 :         break;
    1377             :     }
    1378             :     }
    1379          46 :     return true;
    1380             : }
    1381             : 
    1382           9 : void KSyncRouteWalker::NotifyRoutes(VrfEntry *vrf) {
    1383           9 :     if (marked_for_deletion_ == false)
    1384           9 :         StartRouteWalk(vrf);
    1385           9 : }

Generated by: LCOV version 1.14