LCOV - code coverage report
Current view: top level - vnsw/agent/services/nix/linux - metadata_ipv6_netlink.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 129 240 53.8 %
Date: 2026-08-03 02:19:58 Functions: 20 29 69.0 %
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             : 
      16             : #ifndef  NLM_F_DUMP_FILTERED
      17             : #define  NLM_F_DUMP_FILTERED 0x20
      18             : #endif
      19             : 
      20             : #include <cstring>
      21             : #include <cmn/agent_cmn.h>
      22             : #include <oper/interface_common.h>
      23             : #include "services/metadata_proxy.h"
      24             : #include "services/services_init.h"
      25             : 
      26             : namespace aux {
      27             : 
      28             : /// @brief A wrapper function to insert an attribute
      29             : /// into a netlink message
      30          48 : void insert_attr(nlmsghdr* nl_msg,
      31             :     unsigned short attr_type, int attr_len, const void* attr_data)  // T-L-V
      32             : {
      33          48 :     if (nl_msg == NULL) {
      34           0 :         LOG(ERROR, "NULL pointer in nl_msg in"  // INFO | DEBUG
      35             :         " void insert_attr, metadata_ipv6_netlink.cc");
      36           0 :         return;
      37             :     }
      38          48 :     if (attr_data == NULL) {
      39           0 :         LOG(ERROR, "NULL pointer in attr_data in"
      40             :         " void insert_attr, metadata_ipv6_netlink.cc");
      41           0 :         return;
      42             :     }
      43             : 
      44          48 :     struct rtattr *payload = 
      45          48 :         (struct rtattr*)(((char*)nl_msg) + NLMSG_ALIGN(nl_msg->nlmsg_len));
      46          48 :     payload->rta_type = attr_type;
      47          48 :     payload->rta_len =  RTA_LENGTH(attr_len);
      48             :     std::memcpy
      49          48 :     (
      50             :         RTA_DATA(payload),
      51             :         attr_data, attr_len);
      52          48 :     nl_msg->nlmsg_len = NLMSG_ALIGN(nl_msg->nlmsg_len) + payload->rta_len;
      53             : }
      54             : 
      55             : 
      56             : /// @brief A class template to store Netlink request data
      57             : template <class T>
      58             : struct NetlinkRequest
      59             : {
      60             :     /// @brief A structure carrying the main netlink header
      61             :     nlmsghdr nl_message_hdr;
      62             : 
      63             :     /// @brief A structure carrying the request-specific header
      64             :     T nl_req_hdr;
      65             : 
      66             :     /// @brief A block of memory of memory carrying attributes
      67             :     /// of this request
      68             :     char payload[16384];
      69             : 
      70             :     /// @brief A reference to the total length of this Netlink request
      71             :     unsigned int& msg_len;
      72             : 
      73             :     /// @brief Returns a pointer to the Netlink message, generated
      74             :     /// using this class
      75          48 :     msghdr* message (sockaddr_nl& s_nl) {
      76          48 :         if (this->msg_len < NLMSG_LENGTH(sizeof(T))) {
      77           0 :             LOG(ERROR, " too short msg_len, "
      78             :             "NetlinkRequest::message, metadata_ipv6_netlink.cc, "<<
      79             :             "this->msg_len = " << this->msg_len <<
      80             :             ", NLMSG_LENGTH(sizeof(T)) = " << NLMSG_LENGTH(sizeof(T)));
      81           0 :             return NULL;
      82             :         }
      83             : 
      84          48 :         iov_.iov_len = this->msg_len;
      85          48 :         msg_ptr_.reset(new msghdr);
      86          48 :         std::memset(msg_ptr_.get(), 0, sizeof(msghdr));
      87          48 :         msg_ptr_->msg_name    = &s_nl;
      88          48 :         msg_ptr_->msg_namelen = sizeof(s_nl);
      89          48 :         msg_ptr_->msg_iov     = &iov_;
      90          48 :         msg_ptr_->msg_iovlen  = 1;  // 1 iov entry
      91             : 
      92          48 :         return msg_ptr_.get();
      93             :     }
      94             : 
      95             :     /// @brief Inserts an attribute stored in attr_data into this
      96             :     /// Netlink reequest
      97          48 :     void insert_attr(unsigned short attr_type,
      98             :         int attr_len, const void* attr_data) {
      99          48 :         aux::insert_attr(&nl_message_hdr, attr_type, attr_len, attr_data);
     100          48 :     }
     101             : 
     102             :     /// @brief Creates new blank request
     103          48 :     NetlinkRequest() : msg_len(nl_message_hdr.nlmsg_len) {
     104          48 :         std::memset(&nl_message_hdr, 0, sizeof(nl_message_hdr));
     105          48 :         std::memset(&nl_req_hdr, 0, sizeof(nl_req_hdr));
     106          48 :         std::memset(&payload, 0, sizeof(payload));
     107             : 
     108          48 :         iov_.iov_base = &nl_message_hdr;
     109          48 :     }
     110             : 
     111             :     /// @brief NetlinkRequest dtor
     112          48 :     ~NetlinkRequest() {}
     113             : 
     114             : private:
     115             : 
     116             :     /// @brief Disallow copy ctor
     117             :     NetlinkRequest(const NetlinkRequest<T>&);
     118             : 
     119             :     /// @brief Disallow assignment operator
     120             :     const NetlinkRequest& operator = (const NetlinkRequest<T>&);
     121             : 
     122             :     /// @brief An iovec struct to keep headers with data
     123             :     iovec iov_;
     124             : 
     125             :     /// @brief A pointer to the Netlink message header
     126             :     std::unique_ptr<msghdr> msg_ptr_;
     127             : };
     128             : 
     129             : 
     130             : /// @brief A storage for the Netlink socket descriptor
     131             : /// @brief and for the Netlink socket sockaddr structure
     132             : class NetlinkSocket {
     133             : 
     134             : private:
     135             : 
     136             :     /// @brief Forbid the copy ctor
     137             :     NetlinkSocket(const NetlinkSocket& nl);
     138             : 
     139             :     /// @brief Forbid the copy assignment
     140             :     const NetlinkSocket& operator = (const NetlinkSocket& nl);
     141             : 
     142             : private:
     143             : 
     144             :     /// @brief A Netlink socket ID (descriptor)
     145             :     int socket_fd;
     146             : 
     147             :     /// @brief A Netlink socket sockaddr structure
     148             :     sockaddr_nl local_sock_addr;
     149             : 
     150             : public:
     151             : 
     152             :     /// @brief Creates a socket and binds it with AF_NETLINK family
     153             :     /// @brief and the kernel process
     154          24 :     NetlinkSocket() {
     155          24 :         socket_fd = -1;
     156             :         // open a socket
     157          24 :         socket_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     158          24 :         if (socket_fd < 0) {
     159           0 :             LOG(ERROR, "An error has occured during opening the socket"
     160             :             "NetlinkSocket::NetlinkSocket, metadata_ipv6_netlink.cc, "
     161             :             "errno = " << errno << std::endl);
     162           0 :             return;
     163             :         }
     164             : 
     165             :         // bind the socket to an address
     166          24 :         local_sock_addr.nl_family = AF_NETLINK;
     167          24 :         local_sock_addr.nl_groups = 0;  // no multicast
     168          24 :         local_sock_addr.nl_pad    = 0;  // not used here
     169          24 :         local_sock_addr.nl_pid    = 0;
     170          48 :         if (bind(socket_fd, 
     171          24 :             (sockaddr*)(&local_sock_addr), sizeof(local_sock_addr)) < 0) {
     172           0 :             LOG(ERROR, "An error has occured during binding the socket"
     173             :             "NetlinkSocket::NetlinkSocket, metadata_ipv6_netlink.cc, "
     174             :             "errno = " << errno << std::endl);
     175           0 :             close(socket_fd);
     176             :         }
     177             :     }
     178             : 
     179             :     /// @brief Closes the Netlink connection
     180          24 :     ~NetlinkSocket() {
     181          24 :         int close_res = close(socket_fd);
     182          24 :         if (close_res) {
     183           0 :             LOG(ERROR, "An error has occured during closing the socket"
     184             :             "NetlinkSocket::NetlinkSocket, metadata_ipv6_netlink.cc, "
     185             :             "errno = " << errno << std::endl);
     186             :         }
     187          24 :     }
     188             : 
     189             :     /// @brief Returns a reference to the Netlink socket descriptor
     190          48 :     const int& fd() const {
     191          48 :         return socket_fd;
     192             :     }
     193             : 
     194             :     /// @brief Returns a reference to the Netlink socket sockaddr struct
     195          48 :     sockaddr_nl& netlink_socket() {
     196          48 :         return local_sock_addr;
     197             :     }
     198             : };
     199             : 
     200             : struct NetlinkResponse {
     201             : 
     202             :     /// @brief A pointer to the begin of the response
     203             :     struct nlmsghdr *resp_nh_;
     204             : 
     205             :     /// @brief The number of received bytes in the response
     206             :     int n_recv_;
     207             : 
     208             :     /// @brief contains message with response
     209             :     struct msghdr msg_;
     210             : 
     211             :     /// @brief Contains response data
     212             :     struct iovec iov_;
     213             : 
     214             :     /// @brief A buffer for response data
     215             :     char buffer_[16384];
     216             : 
     217             : private:
     218             : 
     219             :     /// @brief Forbid default ctor for NetlinkResponse
     220             :     NetlinkResponse();
     221             : 
     222             : public:
     223             : 
     224             :     /// @brief Construct a NetlinkResponse object from the request
     225             :     /// message and the Netlink socket
     226           0 :     NetlinkResponse(msghdr* req_msg, NetlinkSocket& nl_sock) {
     227           0 :         resp_nh_ = NULL;
     228           0 :         memset(buffer_, 0, sizeof(buffer_));
     229           0 :         memset(&iov_, 0, sizeof(iov_));
     230             : 
     231           0 :         msg_.msg_name = req_msg->msg_name;
     232           0 :         msg_.msg_namelen = req_msg->msg_namelen;
     233           0 :         msg_.msg_iov = &iov_;
     234           0 :         msg_.msg_iovlen = 1;
     235           0 :         iov_.iov_base = buffer_;
     236           0 :         iov_.iov_len = sizeof(buffer_);
     237           0 :         n_recv_ = recvmsg(nl_sock.fd(), &msg_, 0);
     238           0 :         if (n_recv_ < 0) {
     239           0 :             LOG(ERROR, "Error receiving message from netlink: "
     240             :                 << strerror(errno) << std::endl);
     241             :         } else {
     242           0 :             resp_nh_ = reinterpret_cast<struct nlmsghdr *>(&buffer_[0]);
     243             :         }
     244           0 :     }
     245             : 
     246             :     /// @brief NetlinkResponse dtor
     247           0 :     ~NetlinkResponse() {}
     248             : 
     249             :     /// @brief Iterates over all response parts
     250             :     template <class T>
     251           0 :     int response_iterate(const T& handler_func) {
     252           0 :         for (;
     253           0 :             NLMSG_OK(resp_nh_, n_recv_);
     254           0 :             resp_nh_ = NLMSG_NEXT(resp_nh_, n_recv_)) {
     255           0 :                 int handle_res = handler_func(resp_nh_);
     256           0 :                 if (handle_res >= 0) {
     257           0 :                     return handle_res;
     258             :                 }
     259             :         }
     260           0 :         return -1;
     261             :     }
     262             : };
     263             : 
     264             : struct IPv6Reader {
     265             : 
     266           0 :     explicit IPv6Reader(const unsigned int itf_idx)
     267           0 :     :
     268           0 :         vhost_idx_(itf_idx) {
     269           0 :     }
     270             : 
     271             :     unsigned int vhost_idx_;
     272             : 
     273             :     mutable Ip6Address vhost_addr_;
     274             : 
     275           0 :     int read_ipv6_address(const struct nlmsghdr *resp_nh) const {
     276           0 :         struct rtattr *resp_attr = NULL;
     277           0 :         struct ifaddrmsg *ifa_resp = NULL;
     278           0 :         int attr_len = 0;
     279           0 :         if (resp_nh->nlmsg_type != RTM_NEWADDR) {
     280           0 :             return -1;
     281             :         }
     282           0 :         ifa_resp = static_cast<struct ifaddrmsg *>(NLMSG_DATA(resp_nh));
     283           0 :         if (ifa_resp == NULL) {
     284           0 :             return -1;
     285             :         }
     286           0 :         if (ifa_resp->ifa_index != vhost_idx_) {
     287           0 :             return -1;
     288             :         }
     289           0 :         attr_len = resp_nh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa_resp));
     290           0 :         for (resp_attr = IFA_RTA(ifa_resp);
     291           0 :             RTA_OK(resp_attr, attr_len);
     292           0 :             resp_attr = RTA_NEXT(resp_attr, attr_len)) {
     293           0 :             if (resp_attr->rta_type == IFA_ADDRESS) {
     294             :                 char addr_str[256];
     295           0 :                 memset(addr_str, 0, 256);
     296           0 :                 inet_ntop(AF_INET6,
     297             :                     RTA_DATA(resp_attr), addr_str, 256);
     298           0 :                 if (addr_str[0] != 0) {
     299           0 :                     vhost_addr_ = Ip6Address::from_string(addr_str);
     300           0 :                     if (!vhost_addr_.is_unspecified() &&
     301           0 :                         vhost_addr_.is_link_local()) {
     302           0 :                         return 1;
     303             :                     }
     304             :                 }
     305             :             }
     306             :         }
     307           0 :         return -1;
     308             :     }
     309             : 
     310           0 :     int operator() (const struct nlmsghdr *resp_nh) const {
     311           0 :         return read_ipv6_address(resp_nh);
     312             :     }
     313             : 
     314             : private:
     315             : 
     316             :     IPv6Reader();
     317             : 
     318             :     IPv6Reader(const IPv6Reader&);
     319             : 
     320             : };
     321             : 
     322             : /// @brief Reads a response (ack/nock) after a Netlink request
     323          24 : static bool read_ack_response(
     324             :     const msghdr *msg,
     325             :     int send_n,
     326             :     NetlinkSocket& nl_sock,
     327             :     const char* func_name) {
     328             : 
     329          24 :     aux::NetlinkRequest<nlmsgerr> nl_ack;
     330          24 :     nl_ack.msg_len = NLMSG_LENGTH(sizeof(nl_ack.nl_req_hdr));
     331          24 :     msghdr *ack = nl_ack.message(nl_sock.netlink_socket());
     332          24 :     int recv_n = -1;
     333          24 :     if (msg && send_n > 0 && ack) {
     334          24 :         recv_n = recvmsg(nl_sock.fd(), ack, MSG_WAITALL);
     335          24 :         if (recv_n <= 0) {
     336           0 :             LOG(ERROR, "Recvmsg failed,"<<
     337             :             func_name << ", metadata_ipv6_netlink.cc, "
     338             :             "errno = " << errno << std::endl);
     339           0 :             return false;
     340             :         }
     341          24 :         if (nl_ack.nl_message_hdr.nlmsg_type == NLMSG_ERROR) {
     342          24 :             const int ack_err = -nl_ack.nl_req_hdr.error;
     343          24 :             if (ack_err == 0
     344          24 :                 || ack_err == EEXIST || ack_err == EADDRNOTAVAIL) {
     345             :                 // EEXIST -- address is already present, not an error
     346             :                 // EADDRNOTAVAIL -- address is not present, not an error
     347           0 :                 return true;
     348             :             }
     349          24 :             LOG(ERROR, "Error in the Netlink message, "<<
     350             :             func_name << ", metadata_ipv6_netlink.cc, "
     351             :             "error code = " << ack_err);
     352             :         }
     353             :     }
     354          24 :     return false;
     355          24 : }
     356             : 
     357             : } //namespace aux
     358             : 
     359           1 : bool MetadataProxy::NetlinkGetVhostIp(Ip6Address& vhost_ll_ip) {
     360             :     // set ip address
     361             :     //
     362             :     // set device index
     363             :     const int dev_idx =
     364           1 :         VhostIndex(services_->agent()->vhost_interface_name().c_str());
     365           1 :     if (dev_idx == 0) {
     366           1 :         std::cout<< "Device " << services_->agent()->vhost_interface_name()
     367           2 :                  << " has not been found "
     368           1 :                  << std::endl;
     369           1 :         return false;
     370             :     } else {
     371             : 
     372           0 :         std::cout<< "dev_idx = " << dev_idx
     373           0 :                  << ", dev_name = " << services_->agent()->vhost_interface_name()
     374           0 :                  << std::endl;
     375             :     }
     376             : 
     377             :     // open a socket
     378           0 :     aux::NetlinkSocket nl_sock;
     379           0 :     int send_n = -1;
     380             :     {
     381           0 :         aux::NetlinkRequest<ifaddrmsg> addr_nl_req;
     382           0 :         ifaddrmsg &nl_req_param    = addr_nl_req.nl_req_hdr;
     383           0 :         nl_req_param.ifa_family    = AF_INET6;
     384           0 :         nl_req_param.ifa_prefixlen = 128;
     385           0 :         nl_req_param.ifa_index     = dev_idx;
     386             : 
     387           0 :         nlmsghdr &msg_hdr          = addr_nl_req.nl_message_hdr;
     388           0 :         msg_hdr.nlmsg_type         = RTM_GETADDR;
     389           0 :         msg_hdr.nlmsg_flags        = NLM_F_REQUEST | NLM_F_DUMP; // | NLM_F_DUMP_FILTERED;
     390           0 :         addr_nl_req.msg_len = NLMSG_LENGTH(sizeof(nl_req_param));
     391             : 
     392           0 :         msghdr *msg = addr_nl_req.message(nl_sock.netlink_socket());
     393           0 :         send_n = -1;
     394           0 :         if (msg == NULL) {
     395           0 :             return false;
     396             :         }
     397             : 
     398             :         // send a request to the kernel
     399           0 :         send_n = sendmsg(nl_sock.fd(), msg, 0);
     400           0 :         if (send_n <= 0) {
     401           0 :             LOG(ERROR, "sendmsg failed (address request), "
     402             :             "MetadataProxy::NetlinkAddVhostIp, metadata_ipv6_netlink.cc, "
     403             :             "errno = " << errno << std::endl);
     404           0 :             return false;
     405             :         }
     406             : 
     407             :         // read the response
     408           0 :         aux::NetlinkResponse addr_resp(msg, nl_sock);
     409           0 :         aux::IPv6Reader ipv6_reader(dev_idx);
     410           0 :         int ret_value = addr_resp.response_iterate(ipv6_reader);
     411           0 :         if (ret_value > 0) {
     412           0 :             vhost_ll_ip = ipv6_reader.vhost_addr_;
     413           0 :             return true;
     414             :         }
     415           0 :     }
     416             : 
     417           0 :     return false;
     418           0 : }
     419             : 
     420          12 : void MetadataProxy::
     421             : NetlinkAddVhostNb(const IpAddress& nb_ip, const MacAddress& via_mac) {
     422          12 :     if (!nb_ip.is_v6()) {
     423           0 :         return;
     424             :     }
     425             : 
     426             :     // set ip address
     427             :     in6_addr addr6;
     428          12 :     int addr_res = inet_pton(AF_INET6, nb_ip.to_string().c_str(), &addr6);
     429          12 :     if (addr_res < 0) {
     430           0 :         LOG(ERROR, "An error has occured during address initialization,"
     431             :         "MetadataProxy::NetlinkAddVhostNb, metadata_ipv6_netlink.cc, "
     432             :         "errno = " << errno << std::endl);
     433           0 :         return;
     434             :     }
     435          12 :     if (addr_res == 0) {
     436           0 :         LOG(ERROR, "A wrong address has been specified,"
     437             :         "MetadataProxy::NetlinkAddVhostNb, metadata_ipv6_netlink.cc, "
     438             :         "address = " << nb_ip.to_string().c_str() << std::endl);
     439           0 :         return;
     440             :     }
     441             : 
     442             :     // set mac address
     443          12 :     unsigned char nb_mac_addr[] = {0,0,0,0,0,0};
     444          12 :     via_mac.ToArray(nb_mac_addr, sizeof(nb_mac_addr));
     445             : 
     446             :     // set device index
     447             :     const int dev_idx =
     448          12 :         VhostIndex(services_->agent()->vhost_interface_name());
     449          12 :     if (dev_idx <= 0) {
     450          12 :         LOG(ERROR, "Error while retreiving device index,"
     451             :         "MetadataProxy::NetlinkAddVhostNb, metadata_ipv6_netlink.cc, "
     452             :         "dev_idx = " << dev_idx << std::endl);
     453             :     }
     454             : 
     455             :     // open a socket
     456          12 :     aux::NetlinkSocket nl_sock;
     457             : 
     458          12 :     aux::NetlinkRequest<ndmsg> nd_req;
     459             : 
     460          12 :     ndmsg &nd_message_hdr = nd_req.nl_req_hdr;
     461          12 :     nd_message_hdr.ndm_family   = AF_INET6;  // AF_INET/AF_INET6/AF_UNSPEC
     462          12 :     nd_message_hdr.ndm_ifindex  = dev_idx;
     463          12 :     nd_message_hdr.ndm_state    = NUD_PERMANENT;
     464             : 
     465          12 :     nlmsghdr &nl_message_hdr = nd_req.nl_message_hdr;
     466          12 :     nl_message_hdr.nlmsg_type = RTM_NEWNEIGH;
     467          12 :     nl_message_hdr.nlmsg_flags =  // NLM_F_REPLACE is neccessary, since a
     468             :         NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE  // route might be already
     469             :         | NLM_F_ACK;                                  // in the table
     470             : 
     471          12 :     nd_req.msg_len = NLMSG_LENGTH(sizeof(nd_message_hdr));
     472             : 
     473             :     // insert lladdr (MAC)
     474          12 :     nd_req.insert_attr(NDA_LLADDR, sizeof(nb_mac_addr), &nb_mac_addr[0]);
     475             :     // insert IP (IPv6)
     476          12 :     nd_req.insert_attr(NDA_DST, sizeof(addr6), &addr6);
     477             : 
     478          12 :     msghdr* msg = nd_req.message(nl_sock.netlink_socket());
     479          12 :     int send_n = -1;
     480          12 :     if (msg) {
     481             :         // sending of a request to the kernel
     482          12 :         send_n = sendmsg(nl_sock.fd(), msg, 0);
     483          12 :         if (send_n <= 0) {
     484           0 :             LOG(ERROR, "Sendmsg failed,"
     485             :             "MetadataProxy::NetlinkAddVhostNb, metadata_ipv6_netlink.cc, "
     486             :             "errno = " << errno << std::endl);
     487             :         }
     488             :     }
     489             : 
     490          12 :     aux::read_ack_response(msg, send_n, nl_sock, "NetlinkAddVhostNb");
     491          12 : }
     492             : 
     493          12 : void MetadataProxy::NetlinkAddInterfaceRoute(const IpAddress& intf_addr) {
     494          12 :     if (!intf_addr.is_v6()) {
     495           0 :         return;
     496             :     }
     497             : 
     498             :     // set ip address
     499             :     in6_addr addr6;
     500          12 :     int addr_res = inet_pton(AF_INET6, intf_addr.to_string().c_str(), &addr6);
     501          12 :     if (addr_res < 0) {
     502           0 :         LOG(ERROR, "An error has occured during address initialization,"
     503             :         "MetadataProxy::NetlinkAddInterfaceRoute, metadata_ipv6_netlink.cc, "
     504             :         "errno = " << errno << std::endl);
     505           0 :         return;
     506             :     }
     507          12 :     if (addr_res == 0) {
     508           0 :         LOG(ERROR, "A wrong address has been specified,"
     509             :         "MetadataProxy::NetlinkAddInterfaceRoute, metadata_ipv6_netlink.cc, "
     510             :         "address = " << intf_addr.to_string().c_str() << std::endl);
     511           0 :         return;
     512             :     }
     513             : 
     514             :     // set device index
     515             :     const int dev_idx =
     516          12 :         VhostIndex(services_->agent()->vhost_interface_name());
     517          12 :     if (dev_idx <= 0) {
     518          12 :         LOG(ERROR, "Error while retreiving device index,"
     519             :         "MetadataProxy::NetlinkAddInterfaceRoute, metadata_ipv6_netlink.cc, "
     520             :         "dev_idx = " << dev_idx << std::endl);
     521             :     }
     522             : 
     523             :     // open a socket
     524          12 :     aux::NetlinkSocket nl_sock;
     525             : 
     526          12 :     aux::NetlinkRequest<rtmsg> rt_req;
     527             : 
     528          12 :     rtmsg &rt_message_hdr = rt_req.nl_req_hdr;
     529          12 :     std::memset(&rt_message_hdr, 0, sizeof(rt_message_hdr));
     530          12 :     rt_message_hdr.rtm_family   = AF_INET6;  // AF_INET/AF_INET6/AF_UNSPEC
     531          12 :     rt_message_hdr.rtm_table    = RT_TABLE_MAIN;
     532          12 :     rt_message_hdr.rtm_protocol = RTPROT_STATIC;
     533          12 :     rt_message_hdr.rtm_scope    = RT_SCOPE_UNIVERSE;
     534          12 :     rt_message_hdr.rtm_type     = RTN_UNICAST;
     535          12 :     rt_message_hdr.rtm_dst_len = 128;
     536             : 
     537             : 
     538          12 :     nlmsghdr &nl_message_hdr = rt_req.nl_message_hdr;
     539          12 :     nl_message_hdr.nlmsg_type = RTM_NEWROUTE;
     540          12 :     nl_message_hdr.nlmsg_flags =  // NLM_F_REPLACE is neccessary, since a
     541             :         NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE  // route might be already
     542             :         | NLM_F_ACK;                                  // in the table
     543             : 
     544          12 :     rt_req.msg_len = NLMSG_LENGTH(sizeof(rt_message_hdr));
     545             : 
     546          12 :     rt_req.insert_attr(RTA_DST, sizeof(addr6), &addr6);
     547          12 :     rt_req.insert_attr(RTA_OIF, sizeof(dev_idx), &dev_idx);
     548             : 
     549          12 :     msghdr* msg = rt_req.message(nl_sock.netlink_socket());
     550          12 :     int send_n = -1;
     551          12 :     if (msg) {
     552             :         // sending of a request to the kernel
     553          12 :         send_n = sendmsg(nl_sock.fd(), msg, 0);
     554          12 :         if (send_n <= 0) {
     555           0 :             LOG(ERROR, "Sendmsg failed,"
     556             :             "MetadataProxy::NetlinkAddInterfaceRoute,"
     557             :             " metadata_ipv6_netlink.cc, "
     558             :             "errno = " << errno << std::endl);
     559             :         }
     560             :     }
     561             : 
     562          12 :     aux::read_ack_response(msg, send_n, nl_sock, "NetlinkAddVhostNb");
     563          12 : }
     564             : 
     565             : //
     566             : // END-OF-FILE
     567             : //
     568             : 

Generated by: LCOV version 1.14