LCOV - code coverage report
Current view: top level - vnsw/agent/services - metadata_proxy_ip6.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 93 175 53.1 %
Date: 2026-08-03 02:19:58 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2023 Matvey Kraposhin 
       3             :  */
       4             : extern "C" {
       5             :     #include <errno.h>
       6             :     #include <net/if.h>
       7             :     #include <sys/socket.h>
       8             :     #include <unistd.h>
       9             :     #include <linux/netlink.h>
      10             :     #include <linux/rtnetlink.h>
      11             :     #include <linux/neighbour.h>
      12             :     #include <linux/if_addr.h>
      13             :     #include <arpa/inet.h>
      14             : }
      15             : #include <cstring>
      16             : #include <cmn/agent_cmn.h>
      17             : #include <oper/interface_common.h>
      18             : #include <oper/route_common.h>
      19             : #include <oper/inet_unicast_route.h>
      20             : #include <oper/global_vrouter.h>
      21             : #include <oper/vxlan_routing_manager.h>
      22             : #include "services/metadata_proxy.h"
      23             : #include "services/metadata_server.h"
      24             : #include "services/services_init.h"
      25             : 
      26          25 : int MetadataProxy::VhostIndex(const std::string& vhost_name) {
      27          25 :     if (vhost_name != std::string("")) {
      28          25 :         int intf_idx = if_nametoindex(vhost_name.c_str());
      29          25 :         if (intf_idx > 0)
      30           0 :             return intf_idx;
      31             :     }
      32          25 :     return 0;
      33             : }
      34             : 
      35           0 : void MetadataProxy::AdvertiseMetaDataLinkLocalRoutes(const VmInterface* vm_intf,
      36             :     const Ip6Address& ll_ip, const VrfEntry* intf_vrf) {
      37           0 :     if (vm_intf == NULL || intf_vrf == NULL) {
      38           0 :         return;
      39             :     }
      40             : 
      41           0 :     std::scoped_lock lock(ll_ipv6_addr_mutex_);
      42             :     {
      43             :         InetUnicastAgentRouteTable *intf_inet_table =
      44           0 :             intf_vrf->GetInet6UnicastRouteTable();
      45           0 :         if (intf_inet_table == NULL)
      46           0 :             return;
      47             :         InetUnicastRouteEntry* rt_entry =
      48           0 :             intf_inet_table->FindRoute(ll_ip);
      49             :         // explicitly forbid advertisement of LL IPv6 route
      50             :         // if another with the given prefix exists
      51           0 :         if (rt_entry != NULL &&
      52           0 :             rt_entry->prefix_address().to_v6() == ll_ip &&
      53           0 :             rt_entry->prefix_length() == 128) {
      54           0 :              return;
      55             :         }
      56           0 :         VnListType vn_list;
      57           0 :         if (vm_intf->vn())
      58           0 :             vn_list.insert(vm_intf->vn()->GetName());
      59             : 
      60           0 :         InetInterfaceKey intf_key(vm_intf->name());
      61             :         InetInterfaceRoute *data = new InetInterfaceRoute
      62           0 :             (intf_key, vm_intf->label(), TunnelType::MplsType(),
      63           0 :             vn_list, vm_intf->peer()->sequence_number());
      64             : 
      65           0 :         DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
      66           0 :         req.key.reset(new InetUnicastRouteKey(vm_intf->peer(),
      67           0 :             intf_vrf->GetName(), ll_ip, 128));
      68           0 :         req.data.reset(data);
      69             : 
      70           0 :         intf_inet_table->Process(req);
      71           0 :     }
      72             : 
      73           0 :     ll_ipv6_addresses_.insert(std::make_pair(vm_intf->name(), ll_ip));
      74           0 : }
      75             : 
      76          14 : void MetadataProxy::DeleteMetaDataLinkLocalRoute(const VmInterface* vm_intf) {
      77          14 :     if (vm_intf == NULL)
      78          14 :         return;
      79             : 
      80          14 :     std::scoped_lock lock(ll_ipv6_addr_mutex_);
      81             : 
      82          14 :     Ip6Address ll_ip = Ip6Address::from_string(std::string("::"));
      83          14 :     if (!ll_ipv6_addresses_.count(vm_intf->name()))
      84          14 :         return;
      85             : 
      86           0 :     ll_ip = ll_ipv6_addresses_.at(vm_intf->name());
      87           0 :     const VrfEntry *vrf_entry = services_->agent()->
      88           0 :         vrf_table()->FindVrfFromName(vm_intf->vrf_name());
      89           0 :     if (!vrf_entry)
      90           0 :         return;
      91             : 
      92           0 :     DBEntryBase::KeyPtr tintf_key_ptr;
      93           0 :     InetUnicastRouteEntry *c_entry = NULL;
      94             : 
      95           0 :     tintf_key_ptr = vm_intf->GetDBRequestKey();
      96             :     const VmInterfaceKey* intf_key_ptr =
      97           0 :         dynamic_cast<const VmInterfaceKey *>(tintf_key_ptr.get());
      98           0 :     if (!intf_key_ptr)
      99           0 :         return;
     100             : 
     101           0 :     c_entry = vrf_entry->GetUcRoute(ll_ip);
     102           0 :     if (!c_entry)
     103           0 :         return;
     104             : 
     105             :     {
     106             :         InetUnicastAgentRouteTable *fabric_inet =
     107           0 :             services_->agent()->fabric_vrf()->
     108           0 :                 GetInet6UnicastRouteTable();
     109           0 :             fabric_inet->Delete(services_->agent()->evpn_routing_peer(),
     110           0 :                 services_->agent()->fabric_vrf_name(), ll_ip, 128);
     111             :     }
     112             :     {
     113           0 :         VnListType vn_list;
     114           0 :         if (vm_intf->vn())
     115           0 :             vn_list.insert(vm_intf->vn()->GetName());
     116           0 :         InetInterfaceKey intf_key(vm_intf->name());
     117             :         // InetInterfaceRoute *data = new InetInterfaceRoute
     118             :         //     (intf_key, vm_intf->label(), local_path->GetTunnelType(),
     119             :         //     local_path->dest_vn_list(), local_path->sequence());
     120             :         InetInterfaceRoute *data = new InetInterfaceRoute
     121           0 :             (intf_key, vm_intf->label(), TunnelType::MplsType(),
     122           0 :             vn_list, vm_intf->peer()->sequence_number());
     123             : 
     124             :         InetUnicastAgentRouteTable *table =
     125           0 :             vrf_entry->GetInet6UnicastRouteTable();
     126           0 :         if (table) {
     127           0 :             table->Delete(
     128             :                 vm_intf->peer(),
     129             :                 vrf_entry->GetName(),
     130           0 :                 ll_ip, c_entry->prefix_length(),
     131             :                 data);
     132             :         }
     133           0 :     }
     134             : 
     135           0 :     if (ll_ipv6_addresses_.count(vm_intf->name())) {
     136           0 :         ll_ipv6_addresses_.erase(vm_intf->name());
     137             :     }
     138          14 : }
     139             : 
     140           1 : const Ip6Address& MetadataProxy::Ipv6ServiceAddress() const {
     141           1 :     return ipv6_service_address_;
     142             : }
     143             : 
     144           1 : void MetadataProxy::InitializeHttp6Server(const VmInterface *vhost0) {
     145           2 :     if (vhost0 == NULL ||
     146           1 :         !ipv6_service_address_.is_unspecified()) {
     147           0 :         return;
     148             :     }
     149           1 :     if (!NetlinkGetVhostIp(ipv6_service_address_)) {
     150           1 :         LOG(ERROR, "An error has occured during retrieving IPv6 ll"
     151             :         " address from vhost0 in"
     152             :         " MetadataProxy::InitializeHttp6Server");
     153           1 :         return;
     154             :     }
     155           0 :     const int vhost_idx =  VhostIndex(
     156           0 :         this->services_->agent()->vhost_interface_name());
     157           0 :     http_server6_->RegisterHandler(HTTP_WILDCARD_ENTRY,
     158             :         boost::bind(&MetadataProxy::HandleMetadataRequest, this, _1, _2));
     159           0 :     http_server6_->Initialize(
     160           0 :         services_->agent()->metadata_server_port(),
     161           0 :         ipv6_service_address_, vhost_idx);
     162           0 :     AdvertiseVhostRoute();
     163             : }
     164             : 
     165           0 : void MetadataProxy::AdvertiseVhostRoute() {
     166           0 :     PathPreference path_preference;
     167           0 :     EcmpLoadBalance ecmp_load_balance;
     168             : 
     169           0 :     Agent *agent = services_->agent();
     170             : 
     171             :     const VmInterface *vhost_intf =
     172           0 :         dynamic_cast<const VmInterface*>(agent->vhost_interface());
     173             : 
     174           0 :     VnListType vn_list;
     175           0 :     vn_list.insert(agent->fabric_vn_name());
     176             : 
     177             :     InetUnicastAgentRouteTable *table =
     178             :         static_cast<InetUnicastAgentRouteTable*>
     179           0 :         (agent->vrf_table()->GetInet6UnicastRouteTable(
     180             :                                         agent->fabric_vrf_name()));
     181             : 
     182           0 :     table->AddLocalVmRouteReq(
     183             :         agent->link_local_peer(), agent->fabric_vrf_name(),
     184           0 :         Ipv6ServiceAddress(), 128, vhost_intf->GetUuid(),
     185           0 :         vn_list, vhost_intf->label(), SecurityGroupList(),
     186           0 :         TagList(), CommunityList(), true, path_preference,
     187           0 :         Ip6Address(), ecmp_load_balance, false, false, false,
     188             :         vhost_intf->name());
     189           0 : }
     190             : 
     191           1 : void MetadataProxy::DeleteVhostRoute() {
     192           1 :     Agent *agent = services_->agent();
     193             : 
     194           1 :     InetUnicastAgentRouteTable::Delete(agent->link_local_peer(),
     195             :         agent->fabric_vrf_name(),
     196           1 :         Ipv6ServiceAddress(), 128);
     197           1 : }
     198             : 
     199          78 : void MetadataProxy::OnAVrfChange(DBTablePartBase *, DBEntryBase * entry) {
     200             : 
     201          78 :     VrfEntry *vrf_entry = dynamic_cast<VrfEntry*>(entry);
     202             : 
     203         156 :     if (vrf_entry == nullptr ||
     204          78 :         vrf_entry != services_->agent()->fabric_vrf()) {
     205          69 :         return;
     206             :     }
     207             : 
     208             :     InetUnicastAgentRouteTable *fabric_inet6_table =
     209           9 :         vrf_entry->GetInet6UnicastRouteTable();
     210           9 :     if (fabric_inet6_table == nullptr) {
     211           3 :         return;
     212             :     }
     213             : 
     214          11 :     if (vrf_entry->IsDeleted() &&
     215           5 :         fabric_notify_id_ >= 0) {
     216           1 :             fabric_inet6_table->Unregister(fabric_notify_id_);
     217           1 :             fabric_notify_id_ = -1;
     218             :     }
     219             : 
     220           7 :     if (!vrf_entry->IsDeleted() &&
     221           1 :         fabric_notify_id_ < 0) {
     222           1 :         fabric_notify_id_ =
     223           1 :             fabric_inet6_table->Register(
     224             :                 boost::bind(&MetadataProxy::OnAFabricRouteChange,
     225             :                             this, _1, _2));
     226             :     }
     227             : }
     228             : 
     229          28 : void MetadataProxy::OnAFabricRouteChange
     230             :     (DBTablePartBase *, DBEntryBase *entry) {
     231             : 
     232             :     InetUnicastAgentRouteTable *inet_table =
     233          28 :        dynamic_cast<InetUnicastAgentRouteTable*>(entry->get_table());
     234          28 :     if (!inet_table)
     235          16 :         return;
     236             : 
     237             :     InetUnicastRouteEntry *route_entry =
     238          28 :         dynamic_cast<InetUnicastRouteEntry*>(entry);
     239          28 :     if (!route_entry)
     240           0 :         return;
     241             : 
     242          28 :     const AgentPath *active_path = route_entry->GetActivePath();
     243          28 :     const NextHop *active_nh = active_path ? active_path->nexthop() : NULL;
     244             :     const InterfaceNH *interface_nh =
     245          28 :         dynamic_cast<const InterfaceNH*>(active_nh);
     246          28 :     if (interface_nh == NULL) {
     247          16 :         return;
     248             :     }
     249             : 
     250          12 :     const VmInterface *interface = dynamic_cast<const VmInterface*>(
     251          12 :         interface_nh->GetInterface());
     252          12 :     if (interface == NULL) {
     253           0 :         return;
     254             :     }
     255             : 
     256          12 :     const Ip6Address mip6 = interface->mdata_ip6_addr();
     257             : 
     258          12 :     if (mip6 == route_entry->prefix_address().to_v6()) {
     259          12 :         if (entry->IsDeleted()) {
     260             :         } else {
     261             :             // Create a neighbour record (ip neigh add ...)
     262          12 :             this->NetlinkAddVhostNb(mip6, interface->vm_mac());
     263             : 
     264             :             // Create a routing record (ip route add)
     265          12 :             this->NetlinkAddInterfaceRoute(mip6);
     266             :         }
     267             :     }
     268             : }
     269             : 
     270          82 : void MetadataProxy::OnAnInterfaceChange(DBTablePartBase *, DBEntryBase *entry) {
     271          82 :     VmInterface *vmi = dynamic_cast<VmInterface *>(entry);
     272          82 :     if (!vmi)
     273          15 :         return;
     274             : 
     275          67 :     if (vmi->IsDeleted() && vmi != services_->agent()->vhost_interface()) {
     276          14 :         DeleteMetaDataLinkLocalRoute(vmi);
     277          14 :         return;
     278             :     }
     279             : 
     280          53 :     if (!vmi->IsDeleted() && vmi == services_->agent()->vhost_interface()) {
     281           1 :         InitializeHttp6Server(vmi);
     282             :     }
     283             : 
     284          53 :     if (vmi->IsDeleted() && vmi == services_->agent()->vhost_interface()) {
     285           1 :         this->DeleteVhostRoute();
     286             :     }
     287             : }
     288             : 
     289           1 : void MetadataProxy::RegisterListeners() {
     290           1 :     vrf_table_notify_id_     = -1;
     291           1 :     intf_table_notify_id_    = -1;
     292           1 :     fabric_notify_id_        = -1;  // Will be registered later,
     293             :                                     // since the table isn't present now
     294           1 :     if (services_->agent()->vrf_table()) {
     295           1 :         vrf_table_notify_id_ =
     296           1 :             services_->agent()->vrf_table()->Register(
     297             :                 boost::bind(&MetadataProxy::OnAVrfChange, this, _1, _2));
     298             :     }
     299           1 :     if (services_->agent()->interface_table()) {
     300           1 :         intf_table_notify_id_ =
     301           1 :             services_->agent()->interface_table()->Register(
     302             :                 boost::bind(&MetadataProxy::OnAnInterfaceChange, this, _1, _2));
     303             :     }
     304           1 : }
     305             : 
     306           1 : void MetadataProxy::UnregisterListeners() {
     307           1 :     if (vrf_table_notify_id_ > -1) {
     308           1 :         services_->agent()->vrf_table()->
     309           1 :             Unregister(vrf_table_notify_id_);
     310           1 :         vrf_table_notify_id_ = -1;
     311             :     }
     312           1 :     if (intf_table_notify_id_ > -1) {
     313           1 :         services_->agent()->interface_table()->
     314           1 :             Unregister(intf_table_notify_id_);
     315           1 :         intf_table_notify_id_ = -1;
     316             :     }
     317           1 : }
     318             : 
     319             : //
     320             : // END-OF-FILE
     321             : //

Generated by: LCOV version 1.14