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

Generated by: LCOV version 1.14