LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - vr_dpdk_netlink.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 108 145 74.5 %
Date: 2026-11-09 02:10:49 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_dpdk_netlink.c -- message handling from agent
       3             :  *
       4             :  * Copyright (c) 2014, Juniper Networks Private Inc.,
       5             :  * Copyright Contributors to the OpenSDN project
       6             :  * All rights reserved
       7             :  */
       8             : 
       9             : #include <stdint.h>
      10             : #include <sys/stat.h>
      11             : #include <sys/un.h>
      12             : #include <linux/genetlink.h>
      13             : 
      14             : #include <rte_errno.h>
      15             : #include "nl_util.h"
      16             : #include "vr_dpdk.h"
      17             : #include "vr_dpdk_usocket.h"
      18             : #include "vr_message.h"
      19             : #include "vr_genetlink.h"
      20             : #include "vr_uvhost.h"
      21             : #include "vr_uvhost_msg.h"
      22             : 
      23             : #define HDR_LEN (NLMSG_HDRLEN + GENL_HDRLEN + sizeof(struct nlattr))
      24             : 
      25             : struct nlmsghdr *dpdk_nl_message_hdr(struct vr_message *);
      26             : unsigned int dpdk_nl_message_len(struct vr_message *);
      27             : 
      28             : int vr_usocket_message_write(struct vr_usocket *, struct vr_message *);
      29             : int vr_nl_uvh_sock;
      30             : 
      31             : void
      32          53 : vr_dpdk_netlink_wakeup(void)
      33             : {
      34          53 :     if (likely(vr_dpdk.netlink_event_sock != NULL)) {
      35          53 :         if (vr_usocket_eventfd_write(vr_dpdk.netlink_event_sock) < 0) {
      36           0 :             vr_usocket_close(vr_dpdk.netlink_event_sock);
      37           0 :             vr_dpdk.netlink_event_sock = NULL;
      38             :         }
      39             :     }
      40          53 : }
      41             : 
      42             : static void
      43        2862 : dpdk_nl_process_response(void *usockp, struct nlmsghdr *nlh)
      44             : {
      45             :     __u32 seq;
      46        2862 :     unsigned int multi_flag = 0;
      47        2862 :     bool write = true;
      48             : 
      49             :     struct vr_message *resp;
      50             : 
      51             :     struct nlmsghdr *resp_nlh;
      52             :     struct genlmsghdr *genlh, *resp_genlh;
      53             :     struct nlattr *resp_nla;
      54             : 
      55        2862 :     seq = nlh->nlmsg_seq;
      56        2862 :     genlh = (struct genlmsghdr *)((unsigned char *)nlh + NLMSG_HDRLEN);
      57             : 
      58             :     /* Process responses */
      59        5725 :     while ((resp = (struct vr_message *)vr_message_dequeue_response())) {
      60        2863 :         if (!write) {
      61           0 :             vr_message_free(resp);
      62           0 :             continue;
      63             :         }
      64             : 
      65        2863 :         if (!vr_response_queue_empty()) {
      66           1 :             multi_flag = NLM_F_MULTI;
      67             :         } else {
      68        2862 :             multi_flag = 0;
      69             :         }
      70             : 
      71             :         /* Update Netlink headers */
      72        2863 :         resp_nlh = dpdk_nl_message_hdr(resp);
      73        2863 :         resp_nlh->nlmsg_len = dpdk_nl_message_len(resp);
      74        2863 :         resp_nlh->nlmsg_type = nlh->nlmsg_type;
      75        2863 :         resp_nlh->nlmsg_flags = multi_flag;
      76        2863 :         resp_nlh->nlmsg_seq = seq;
      77        2863 :         resp_nlh->nlmsg_pid = 0;
      78             : 
      79        2863 :         resp_genlh = (struct genlmsghdr *)((unsigned char *)resp_nlh +
      80             :                 NLMSG_HDRLEN);
      81        2863 :         memcpy(resp_genlh, genlh, sizeof(*genlh));
      82             : 
      83        2863 :         resp_nla = (struct nlattr *)((unsigned char *)resp_genlh + GENL_HDRLEN);
      84        2863 :         resp_nla->nla_len = resp->vr_message_len;
      85        2863 :         resp_nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL;
      86             : 
      87        2863 :         if (vr_usocket_message_write(usockp, resp) < 0) {
      88           0 :             write = false;
      89           0 :             vr_usocket_close(usockp);
      90             :         }
      91             :     }
      92             : 
      93        2862 :     return;
      94             : }
      95             : 
      96             : int
      97        2862 : dpdk_netlink_receive(void *usockp, char *nl_buf,
      98             :         unsigned int nl_len)
      99             : {
     100             :     int ret;
     101             :     struct vr_message request;
     102             : 
     103        2862 :     memset(&request, 0, sizeof(request));
     104        2862 :     request.vr_message_buf = nl_buf + HDR_LEN;
     105        2862 :     request.vr_message_len = nl_len - HDR_LEN;
     106             : 
     107        2862 :     ret = vr_message_request(&request);
     108        2862 :     if (ret < 0)
     109           0 :         vr_send_response(ret);
     110             : 
     111        2862 :     dpdk_nl_process_response(usockp, (struct nlmsghdr *)nl_buf);
     112             : 
     113        2862 :     return 0;
     114             : }
     115             : 
     116             : unsigned int
     117        5726 : dpdk_nl_message_len(struct vr_message *message)
     118             : {
     119        5726 :     return message->vr_message_len + HDR_LEN;
     120             : }
     121             : 
     122             : struct nlmsghdr *
     123        5726 : dpdk_nl_message_hdr(struct vr_message *message)
     124             : {
     125        5726 :     return (struct nlmsghdr *)(message->vr_message_buf - HDR_LEN);
     126             : }
     127             : 
     128             : static void
     129        2863 : dpdk_nl_trans_free(char *buf)
     130             : {
     131        2863 :     buf -= HDR_LEN;
     132        2863 :     vr_free(buf, VR_MESSAGE_OBJECT);
     133             : 
     134        2863 :     return;
     135             : }
     136             : 
     137             : static char *
     138        2863 : dpdk_nl_trans_alloc(unsigned int size)
     139             : {
     140             :     char *buf;
     141             : 
     142        2863 :     buf = vr_malloc(size + HDR_LEN, VR_MESSAGE_OBJECT);
     143        2863 :     if (!buf)
     144           0 :         return NULL;
     145             : 
     146        2863 :     return buf + HDR_LEN;
     147             : }
     148             : 
     149             : static struct vr_mtransport dpdk_nl_transport = {
     150             :     .mtrans_alloc       =       dpdk_nl_trans_alloc,
     151             :     .mtrans_free        =       dpdk_nl_trans_free,
     152             : };
     153             : 
     154             : /*
     155             :  * vr_netlink_uvhost_vif_del - sends a message to the user space vhost
     156             :  * thread when a vif is deleted. vif_idx is the index of the vif.
     157             :  *
     158             :  * Returns 0 on success, -1 otherwise.
     159             :  */
     160             : int
     161         166 : vr_netlink_uvhost_vif_del(unsigned int vif_idx)
     162             : {
     163             :     vrnu_msg_t msg;
     164             : 
     165         166 :     memset(&msg, 0, sizeof(msg));
     166         166 :     msg.vrnum_type = VRNU_MSG_VIF_DEL;
     167         166 :     msg.vrnum_vif_del.vrnu_vif_idx = vif_idx;
     168             : 
     169             :     /*
     170             :      * This is a blocking send.
     171             :      */
     172         166 :     if (send(vr_nl_uvh_sock, (void *) &msg, sizeof(msg), 0) !=
     173             :              sizeof(msg)) {
     174           0 :         RTE_LOG(ERR, VROUTER, "    error deleting vif %u from user space vhost:"
     175             :             " %s (%d)\n", vif_idx, rte_strerror(errno), errno);
     176           0 :         return -1;
     177             :     }
     178             : 
     179         166 :     return 0;
     180             : }
     181             : 
     182             : /*
     183             :  * vr_netlink_uvhost_vif_add - sends a message to the user space vhost
     184             :  * thread when a new vif is created. The name os the vif is specified in
     185             :  * the vif_name argument.
     186             :  *
     187             :  * Returns 0 on success, -1 otherwise.
     188             :  */
     189             : int
     190         332 : vr_netlink_uvhost_vif_add(char *vif_name, uint32_t vif_idx,
     191             :                           uint32_t vif_gen, uint32_t vif_nrxqs,
     192             :                           uint32_t vif_ntxqs,
     193             :                           unsigned char vif_vhostuser_mode)
     194             : {
     195             :     vrnu_msg_t msg;
     196             : 
     197         332 :     memset(&msg, 0, sizeof(msg));
     198         332 :     msg.vrnum_type = VRNU_MSG_VIF_ADD;
     199         332 :     strncpy(msg.vrnum_vif_add.vrnu_vif_name, vif_name,
     200             :             sizeof(msg.vrnum_vif_add.vrnu_vif_name) - 1);
     201         332 :     msg.vrnum_vif_add.vrnu_vif_idx = vif_idx;
     202         332 :     msg.vrnum_vif_add.vrnu_vif_nrxqs = vif_nrxqs;
     203         332 :     msg.vrnum_vif_add.vrnu_vif_ntxqs = vif_ntxqs;
     204         332 :     msg.vrnum_vif_add.vrnu_vif_gen = vif_gen;
     205         332 :     msg.vrnum_vif_add.vrnu_vif_vhostuser_mode = vif_vhostuser_mode;
     206             : 
     207             :     /*
     208             :      * This is a blocking send.
     209             :      */
     210         332 :     if (send(vr_nl_uvh_sock, (void *) &msg, sizeof(msg), 0) !=
     211             :              sizeof(msg)) {
     212           0 :         RTE_LOG(ERR, VROUTER, "    error adding vif %u to user space vhost:"
     213             :             " %s (%d)\n", vif_idx, rte_strerror(errno), errno);
     214           0 :         return -1;
     215             :     }
     216             : 
     217         332 :     return 0;
     218             : }
     219             : 
     220             : void
     221          53 : dpdk_netlink_exit(void)
     222             : {
     223          53 :     vr_message_transport_unregister(&dpdk_nl_transport);
     224          53 :     vr_usocket_close(vr_dpdk.netlink_sock);
     225          53 :     vr_dpdk.netlink_sock = NULL;
     226          53 :     vr_dpdk.netlink_event_sock = NULL;
     227             : 
     228          53 :     return;
     229             : }
     230             : 
     231             : /*
     232             :  * vr_nl_uvhost_connect - connect to the user space vhost server on a UNIX
     233             :  * domain socket.
     234             :  *
     235             :  * Returns 0 on success, error otherwise.
     236             :  */
     237             : static int
     238          53 : vr_nl_uvhost_connect(void)
     239             : {
     240          53 :     int s = 0, ret = -1, err;
     241             :     struct sockaddr_un nl_sun, uvh_sun;
     242             : 
     243          53 :     s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
     244          53 :     if (s == -1) {
     245           0 :         RTE_LOG(ERR, VROUTER, "    error creating uvhost socket: %s (%d)\n",
     246             :                         rte_strerror(errno), errno);
     247           0 :         goto error;
     248             :     }
     249          53 :     RTE_LOG(INFO, VROUTER, "    uvhost Unix socket FD is %d\n", s);
     250             : 
     251          53 :     memset(&nl_sun, 0, sizeof(nl_sun));
     252          53 :     nl_sun.sun_family = AF_UNIX;
     253          53 :     strncpy(nl_sun.sun_path, vr_socket_dir, sizeof(nl_sun.sun_path) - 1);
     254          53 :     strncat(nl_sun.sun_path, "/"VR_NL_UVH_SOCK_NAME, sizeof(nl_sun.sun_path)
     255          53 :         - strlen(nl_sun.sun_path) - 1);
     256             : 
     257          53 :     mkdir(vr_socket_dir, VR_DEF_SOCKET_DIR_MODE);
     258          53 :     unlink(nl_sun.sun_path);
     259          53 :     ret = bind(s, (struct sockaddr *) &nl_sun, sizeof(nl_sun));
     260          53 :     if (ret == -1) {
     261           0 :         RTE_LOG(ERR, VROUTER, "    error binding uvhost FD %d to %s: %s (%d)\n",
     262             :                         s, nl_sun.sun_path, rte_strerror(errno), errno);
     263           0 :         goto error;
     264             :     }
     265             : 
     266             :     /*
     267             :      * This will block until the user space vhost thread listens on the
     268             :      * socket.
     269             :      */
     270          53 :     memset(&uvh_sun, 0, sizeof(uvh_sun));
     271          53 :     uvh_sun.sun_family = AF_UNIX;
     272          53 :     strncpy(uvh_sun.sun_path, vr_socket_dir, sizeof(uvh_sun.sun_path) - 1);
     273          53 :     strncat(uvh_sun.sun_path, "/"VR_UVH_NL_SOCK_NAME, sizeof(uvh_sun.sun_path)
     274          53 :         - strlen(uvh_sun.sun_path) - 1);
     275             : 
     276          53 :     ret = vr_dpdk_retry_connect(s, (struct sockaddr *) &uvh_sun, sizeof(uvh_sun));
     277          53 :     if (ret == -1) {
     278           0 :         RTE_LOG(ERR, VROUTER, "    error connecting uvhost socket FD %d to %s:"
     279             :             " %s (%d)\n", s, uvh_sun.sun_path, rte_strerror(errno), errno);
     280           0 :         goto error;
     281             :     }
     282             : 
     283          53 :     vr_nl_uvh_sock = s;
     284             : 
     285          53 :     return 0;
     286             : 
     287           0 : error:
     288             : 
     289           0 :     err = errno;
     290           0 :     if (s > 0) {
     291           0 :         close(s);
     292             :     }
     293           0 :     errno = err;
     294             : 
     295           0 :     return ret;
     296             : }
     297             : 
     298             : /* Init NetLink and UVHost sockets */
     299             : int
     300          53 : vr_dpdk_netlink_init(void)
     301             : {
     302          53 :     void *event_sock = NULL;
     303             :     int ret;
     304             : 
     305          53 :     RTE_LOG(INFO, VROUTER, "Starting NetLink...\n");
     306          53 :     ret = vr_message_transport_register(&dpdk_nl_transport);
     307          53 :     if (ret)
     308           0 :         return ret;
     309             : 
     310             : #ifdef AGENT_VROUTER_TCP
     311             :     vr_dpdk.netlink_sock = vr_usocket(NETLINK, TCP);
     312             : #else
     313          53 :     vr_dpdk.netlink_sock = vr_usocket(NETLINK, UNIX);
     314             : #endif
     315          53 :     if (!vr_dpdk.netlink_sock) {
     316           0 :         RTE_LOG(ERR, VROUTER, "    error creating NetLink server socket:"
     317             :             " %s (%d)\n", rte_strerror(errno), errno);
     318           0 :         goto error;
     319             :     }
     320          53 :     RTE_LOG(INFO, VROUTER, "    NetLink TCP socket FD is %d\n",
     321             :             ((struct vr_usocket *)vr_dpdk.netlink_sock)->usock_fd);
     322             : 
     323          53 :     ret = vr_nl_uvhost_connect();
     324          53 :     if (ret != 0) {
     325           0 :         RTE_LOG(ERR, VROUTER, "    error creating uvhost connection\n");
     326           0 :         goto error;
     327             :     }
     328             : 
     329             :     /* create and bind event usock to wake up the NetLink lcore */
     330          53 :     event_sock = (void *)vr_usocket(EVENT, RAW);
     331          53 :     if (!event_sock) {
     332           0 :         RTE_LOG(ERR, VROUTER, "    error creating NetLink event\n");
     333           0 :         goto error;
     334             :     }
     335             : 
     336          53 :     if (vr_usocket_bind_usockets(vr_dpdk.netlink_sock,
     337             :                 event_sock)) {
     338           0 :         RTE_LOG(ERR, VROUTER, "    error binding NetLink event\n");
     339           0 :         goto error;
     340             :     }
     341          53 :     vr_dpdk.netlink_event_sock = event_sock;
     342             : 
     343          53 :     return 0;
     344             : 
     345           0 : error:
     346           0 :     vr_message_transport_unregister(&dpdk_nl_transport);
     347           0 :     vr_usocket_close(vr_dpdk.netlink_sock);
     348             : 
     349           0 :     return -1;
     350             : }

Generated by: LCOV version 1.14