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

Generated by: LCOV version 1.14