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

Generated by: LCOV version 1.14