LCOV - code coverage report
Current view: top level - spdk/lib/env_dpdk - pci_event.c (source / functions) Hit Total Coverage
Test: Combined Lines: 81 117 69.2 %
Date: 2024-07-15 22:46:19 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 50 70 71.4 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2020 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/string.h"
       8                 :            : 
       9                 :            : #include "spdk/log.h"
      10                 :            : #include "spdk/env.h"
      11                 :            : 
      12                 :            : #ifdef __linux__
      13                 :            : 
      14                 :            : #include <linux/netlink.h>
      15                 :            : 
      16                 :            : #define SPDK_UEVENT_MSG_LEN 4096
      17                 :            : #define SPDK_UEVENT_RECVBUF_SIZE 1024 * 1024
      18                 :            : 
      19                 :            : int
      20                 :        794 : spdk_pci_event_listen(void)
      21                 :            : {
      22                 :        244 :         struct sockaddr_nl addr;
      23                 :            :         int netlink_fd;
      24                 :        794 :         int size = SPDK_UEVENT_RECVBUF_SIZE;
      25                 :        244 :         int buf_size;
      26                 :        244 :         socklen_t opt_size;
      27                 :            :         int flag, rc;
      28                 :            : 
      29                 :        794 :         memset(&addr, 0, sizeof(addr));
      30                 :        794 :         addr.nl_family = AF_NETLINK;
      31                 :        794 :         addr.nl_pid = 0;
      32                 :        794 :         addr.nl_groups = 0xffffffff;
      33                 :            : 
      34                 :        794 :         netlink_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
      35         [ -  + ]:        794 :         if (netlink_fd < 0) {
      36                 :          0 :                 SPDK_ERRLOG("Failed to create netlink socket\n");
      37                 :          0 :                 return netlink_fd;
      38                 :            :         }
      39                 :            : 
      40         [ -  + ]:        794 :         if (setsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0) {
      41         [ #  # ]:          0 :                 if (setsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) {
      42                 :          0 :                         rc = errno;
      43                 :          0 :                         SPDK_ERRLOG("Failed to set socket option SO_RCVBUF\n");
      44                 :          0 :                         goto error;
      45                 :            :                 }
      46                 :          0 :                 opt_size = sizeof(buf_size);
      47         [ #  # ]:          0 :                 if (getsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUF, &buf_size, &opt_size) < 0) {
      48                 :          0 :                         rc = errno;
      49                 :          0 :                         SPDK_ERRLOG("Failed to get socket option SO_RCVBUF\n");
      50                 :          0 :                         goto error;
      51                 :            :                 }
      52         [ #  # ]:          0 :                 if (buf_size < SPDK_UEVENT_RECVBUF_SIZE) {
      53                 :          0 :                         SPDK_ERRLOG("Socket recv buffer is too small (< %d), see SO_RCVBUF "
      54                 :            :                                     "section in socket(7) man page for specifics on how to "
      55                 :            :                                     "adjust the system setting.", SPDK_UEVENT_RECVBUF_SIZE);
      56                 :          0 :                         rc = ENOSPC;
      57                 :          0 :                         goto error;
      58                 :            :                 }
      59                 :            :         }
      60                 :            : 
      61                 :        794 :         flag = fcntl(netlink_fd, F_GETFL);
      62         [ -  + ]:        794 :         if (flag < 0) {
      63                 :          0 :                 rc = errno;
      64                 :          0 :                 SPDK_ERRLOG("Failed to get socket flag, fd: %d\n", netlink_fd);
      65                 :          0 :                 goto error;
      66                 :            :         }
      67                 :            : 
      68         [ -  + ]:        794 :         if (fcntl(netlink_fd, F_SETFL, flag | O_NONBLOCK) < 0) {
      69                 :          0 :                 rc = errno;
      70                 :          0 :                 SPDK_ERRLOG("Fcntl can't set nonblocking mode for socket, fd: %d\n", netlink_fd);
      71                 :          0 :                 goto error;
      72                 :            :         }
      73                 :            : 
      74         [ -  + ]:        794 :         if (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
      75                 :          0 :                 rc = errno;
      76                 :          0 :                 SPDK_ERRLOG("Failed to bind the netlink\n");
      77                 :          0 :                 goto error;
      78                 :            :         }
      79                 :            : 
      80                 :        794 :         return netlink_fd;
      81                 :          0 : error:
      82                 :          0 :         close(netlink_fd);
      83                 :          0 :         return -rc;
      84                 :            : }
      85                 :            : 
      86                 :            : /* Note: We parse the event from uio and vfio subsystem and will ignore
      87                 :            :  *       all the event from other subsystem. the event from uio subsystem
      88                 :            :  *       as below:
      89                 :            :  *       action: "add" or "remove"
      90                 :            :  *       subsystem: "uio"
      91                 :            :  *       dev_path: "/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0"
      92                 :            :  *       VFIO subsystem add event:
      93                 :            :  *       ACTION=bind
      94                 :            :  *       DRIVER=vfio-pci
      95                 :            :  *       PCI_SLOT_NAME=0000:d8:00.0
      96                 :            :  */
      97                 :            : static int
      98                 :       4669 : parse_subsystem_event(const char *buf, struct spdk_pci_event *event)
      99                 :            : {
     100                 :       3030 :         char subsystem[SPDK_UEVENT_MSG_LEN];
     101                 :       3030 :         char action[SPDK_UEVENT_MSG_LEN];
     102                 :       3030 :         char dev_path[SPDK_UEVENT_MSG_LEN];
     103                 :       3030 :         char driver[SPDK_UEVENT_MSG_LEN];
     104                 :       3030 :         char vfio_pci_addr[SPDK_UEVENT_MSG_LEN];
     105                 :            :         char *pci_address, *tmp;
     106                 :            :         int rc;
     107                 :            : 
     108                 :       4669 :         memset(subsystem, 0, SPDK_UEVENT_MSG_LEN);
     109                 :       4669 :         memset(action, 0, SPDK_UEVENT_MSG_LEN);
     110                 :       4669 :         memset(dev_path, 0, SPDK_UEVENT_MSG_LEN);
     111                 :       4669 :         memset(driver, 0, SPDK_UEVENT_MSG_LEN);
     112                 :       4669 :         memset(vfio_pci_addr, 0, SPDK_UEVENT_MSG_LEN);
     113                 :            : 
     114         [ +  + ]:      25328 :         while (*buf) {
     115   [ +  +  +  + ]:      20659 :                 if (!strncmp(buf, "SUBSYSTEM=", 10)) {
     116                 :       2356 :                         buf += 10;
     117                 :       2356 :                         snprintf(subsystem, sizeof(subsystem), "%s", buf);
     118   [ +  +  +  + ]:      18303 :                 } else if (!strncmp(buf, "ACTION=", 7)) {
     119                 :       2356 :                         buf += 7;
     120                 :       2356 :                         snprintf(action, sizeof(action), "%s", buf);
     121   [ +  +  +  + ]:      15947 :                 } else if (!strncmp(buf, "DEVPATH=", 8)) {
     122                 :       2356 :                         buf += 8;
     123                 :       2356 :                         snprintf(dev_path, sizeof(dev_path), "%s", buf);
     124   [ +  +  +  + ]:      13591 :                 } else if (!strncmp(buf, "DRIVER=", 7)) {
     125                 :        168 :                         buf += 7;
     126                 :        168 :                         snprintf(driver, sizeof(driver), "%s", buf);
     127   [ +  +  +  + ]:      13423 :                 } else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
     128                 :        453 :                         buf += 14;
     129                 :        453 :                         snprintf(vfio_pci_addr, sizeof(vfio_pci_addr), "%s", buf);
     130                 :            :                 }
     131                 :            : 
     132         [ +  + ]:     439195 :                 while (*buf++)
     133                 :            :                         ;
     134                 :            :         }
     135                 :            : 
     136         [ +  + ]:       4669 :         if (!strncmp(subsystem, "uio", 3)) {
     137         [ +  + ]:        134 :                 if (!strncmp(action, "remove", 6)) {
     138                 :         66 :                         event->action = SPDK_UEVENT_REMOVE;
     139         [ +  - ]:         68 :                 } else if (!strncmp(action, "add", 3)) {
     140                 :            :                         /* Support the ADD UEVENT for the device allow */
     141                 :         68 :                         event->action = SPDK_UEVENT_ADD;
     142                 :            :                 } else {
     143                 :          0 :                         return 0;
     144                 :            :                 }
     145                 :            : 
     146                 :        134 :                 tmp = strstr(dev_path, "/uio/");
     147         [ -  + ]:        134 :                 if (!tmp) {
     148                 :          0 :                         SPDK_ERRLOG("Invalid format of uevent: %s\n", dev_path);
     149                 :          0 :                         return -EBADMSG;
     150                 :            :                 }
     151         [ -  + ]:        134 :                 memset(tmp, 0, SPDK_UEVENT_MSG_LEN - (tmp - dev_path));
     152                 :            : 
     153                 :        134 :                 pci_address = strrchr(dev_path, '/');
     154         [ -  + ]:        134 :                 if (!pci_address) {
     155                 :          0 :                         SPDK_ERRLOG("Not found PCI device BDF in uevent: %s\n", dev_path);
     156                 :          0 :                         return -EBADMSG;
     157                 :            :                 }
     158                 :        134 :                 pci_address++;
     159                 :            : 
     160                 :        134 :                 rc = spdk_pci_addr_parse(&event->traddr, pci_address);
     161         [ +  + ]:        134 :                 if (rc != 0) {
     162                 :          3 :                         SPDK_ERRLOG("Invalid format for PCI device BDF: %s\n", pci_address);
     163                 :          3 :                         return rc;
     164                 :            :                 }
     165                 :            : 
     166                 :        131 :                 return 1;
     167                 :            :         }
     168                 :            : 
     169         [ +  + ]:       4535 :         if (!strncmp(driver, "vfio-pci", 8)) {
     170         [ +  + ]:         17 :                 if (!strncmp(action, "bind", 4)) {
     171                 :            :                         /* Support the ADD UEVENT for the device allow */
     172                 :         14 :                         event->action = SPDK_UEVENT_ADD;
     173                 :            :                 } else {
     174                 :            :                         /* Only need to support add event.
     175                 :            :                          * VFIO hotplug interface is "pci.c:pci_device_rte_dev_event".
     176                 :            :                          * VFIO informs the userspace hotplug through vfio req notifier interrupt.
     177                 :            :                          * The app needs to free the device userspace driver resource first then
     178                 :            :                          * the OS remove the device VFIO driver and broadcast the VFIO uevent.
     179                 :            :                          */
     180                 :          3 :                         return 0;
     181                 :            :                 }
     182                 :            : 
     183                 :         14 :                 rc = spdk_pci_addr_parse(&event->traddr, vfio_pci_addr);
     184         [ +  + ]:         14 :                 if (rc != 0) {
     185                 :          3 :                         SPDK_ERRLOG("Invalid format for PCI device BDF: %s\n", vfio_pci_addr);
     186                 :          3 :                         return rc;
     187                 :            :                 }
     188                 :            : 
     189                 :         11 :                 return 1;
     190                 :            :         }
     191                 :            : 
     192                 :       4518 :         return 0;
     193                 :            : }
     194                 :            : 
     195                 :            : int
     196                 :      84314 : spdk_pci_get_event(int fd, struct spdk_pci_event *event)
     197                 :            : {
     198                 :            :         int ret;
     199                 :      39459 :         char buf[SPDK_UEVENT_MSG_LEN];
     200                 :            : 
     201                 :      84314 :         memset(buf, 0, SPDK_UEVENT_MSG_LEN);
     202         [ -  + ]:      84314 :         memset(event, 0, sizeof(*event));
     203                 :            : 
     204                 :      84314 :         ret = recv(fd, buf, SPDK_UEVENT_MSG_LEN - 1, MSG_DONTWAIT);
     205         [ +  + ]:      84314 :         if (ret > 0) {
     206                 :       4642 :                 return parse_subsystem_event(buf, event);
     207         [ +  - ]:      79672 :         } else if (ret < 0) {
     208   [ -  +  -  - ]:      79672 :                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
     209                 :      79672 :                         return 0;
     210                 :            :                 } else {
     211                 :          0 :                         ret = errno;
     212                 :          0 :                         SPDK_ERRLOG("Socket read error %d\n", errno);
     213                 :          0 :                         return -ret;
     214                 :            :                 }
     215                 :            :         } else {
     216                 :            :                 /* connection closed */
     217                 :          0 :                 return -ENOTCONN;
     218                 :            :         }
     219                 :            : 
     220                 :            :         return 0;
     221                 :            : }
     222                 :            : 
     223                 :            : #else /* Not Linux */
     224                 :            : 
     225                 :            : int
     226                 :            : spdk_pci_event_listen(void)
     227                 :            : {
     228                 :            :         SPDK_ERRLOG("Non-Linux does not support this operation\n");
     229                 :            :         return -ENOTSUP;
     230                 :            : }
     231                 :            : 
     232                 :            : int
     233                 :            : spdk_pci_get_event(int fd, struct spdk_pci_event *event)
     234                 :            : {
     235                 :            :         SPDK_ERRLOG("Non-Linux does not support this operation\n");
     236                 :            :         return -ENOTSUP;
     237                 :            : }
     238                 :            : #endif

Generated by: LCOV version 1.14