dpdk/drivers/net/mlx5/linux/mlx5_socket.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright 2019 Mellanox Technologies, Ltd
   3 */
   4
   5#ifndef _GNU_SOURCE
   6#define _GNU_SOURCE
   7#endif
   8
   9#include <sys/types.h>
  10#include <sys/socket.h>
  11#include <sys/un.h>
  12#include <fcntl.h>
  13#include <stdio.h>
  14#include <unistd.h>
  15#include <sys/stat.h>
  16
  17#include "rte_eal.h"
  18#include "mlx5_utils.h"
  19#include "mlx5.h"
  20
  21/* PMD socket service for tools. */
  22
  23#define MLX5_SOCKET_PATH "/var/tmp/dpdk_net_mlx5_%d"
  24
  25int server_socket; /* Unix socket for primary process. */
  26struct rte_intr_handle server_intr_handle; /* Interrupt handler. */
  27
  28/**
  29 * Handle server pmd socket interrupts.
  30 */
  31static void
  32mlx5_pmd_socket_handle(void *cb __rte_unused)
  33{
  34        int conn_sock;
  35        int ret;
  36        struct cmsghdr *cmsg = NULL;
  37        int data;
  38        char buf[CMSG_SPACE(sizeof(int))] = { 0 };
  39        struct iovec io = {
  40                .iov_base = &data,
  41                .iov_len = sizeof(data),
  42        };
  43        struct msghdr msg = {
  44                .msg_iov = &io,
  45                .msg_iovlen = 1,
  46                .msg_control = buf,
  47                .msg_controllen = sizeof(buf),
  48        };
  49        uint16_t port_id;
  50        int fd;
  51        FILE *file = NULL;
  52        struct rte_eth_dev *dev;
  53
  54        /* Accept the connection from the client. */
  55        conn_sock = accept(server_socket, NULL, NULL);
  56        if (conn_sock < 0) {
  57                DRV_LOG(WARNING, "connection failed: %s", strerror(errno));
  58                return;
  59        }
  60        ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
  61        if (ret < 0) {
  62                DRV_LOG(WARNING, "wrong message received: %s",
  63                        strerror(errno));
  64                goto error;
  65        }
  66        /* Receive file descriptor. */
  67        cmsg = CMSG_FIRSTHDR(&msg);
  68        if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS ||
  69            cmsg->cmsg_len < sizeof(int)) {
  70                DRV_LOG(WARNING, "invalid file descriptor message");
  71                goto error;
  72        }
  73        memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
  74        file = fdopen(fd, "w");
  75        if (!file) {
  76                DRV_LOG(WARNING, "Failed to open file");
  77                goto error;
  78        }
  79        /* Receive port number. */
  80        if (msg.msg_iovlen != 1 || msg.msg_iov->iov_len < sizeof(uint16_t)) {
  81                DRV_LOG(WARNING, "wrong port number message");
  82                goto error;
  83        }
  84        memcpy(&port_id, msg.msg_iov->iov_base, sizeof(port_id));
  85        if (!rte_eth_dev_is_valid_port(port_id)) {
  86                DRV_LOG(WARNING, "Invalid port %u", port_id);
  87                goto error;
  88        }
  89        /* Dump flow. */
  90        dev = &rte_eth_devices[port_id];
  91        ret = mlx5_flow_dev_dump(dev, file, NULL);
  92        /* Set-up the ancillary data and reply. */
  93        msg.msg_controllen = 0;
  94        msg.msg_control = NULL;
  95        msg.msg_iovlen = 1;
  96        msg.msg_iov = &io;
  97        data = -ret;
  98        io.iov_len = sizeof(data);
  99        io.iov_base = &data;
 100        do {
 101                ret = sendmsg(conn_sock, &msg, 0);
 102        } while (ret < 0 && errno == EINTR);
 103        if (ret < 0)
 104                DRV_LOG(WARNING, "failed to send response %s",
 105                        strerror(errno));
 106error:
 107        if (conn_sock >= 0)
 108                close(conn_sock);
 109        if (file)
 110                fclose(file);
 111}
 112
 113/**
 114 * Install interrupt handler.
 115 *
 116 * @param dev
 117 *   Pointer to Ethernet device.
 118 * @return
 119 *   0 on success, a negative errno value otherwise.
 120 */
 121static int
 122mlx5_pmd_interrupt_handler_install(void)
 123{
 124        MLX5_ASSERT(server_socket);
 125        server_intr_handle.fd = server_socket;
 126        server_intr_handle.type = RTE_INTR_HANDLE_EXT;
 127        return rte_intr_callback_register(&server_intr_handle,
 128                                          mlx5_pmd_socket_handle, NULL);
 129}
 130
 131/**
 132 * Uninstall interrupt handler.
 133 */
 134static void
 135mlx5_pmd_interrupt_handler_uninstall(void)
 136{
 137        if (server_socket) {
 138                mlx5_intr_callback_unregister(&server_intr_handle,
 139                                              mlx5_pmd_socket_handle,
 140                                              NULL);
 141        }
 142        server_intr_handle.fd = 0;
 143        server_intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
 144}
 145
 146/**
 147 * Initialise the socket to communicate with the secondary process
 148 *
 149 * @param[in] dev
 150 *   Pointer to Ethernet device.
 151 *
 152 * @return
 153 *   0 on success, a negative value otherwise.
 154 */
 155int
 156mlx5_pmd_socket_init(void)
 157{
 158        struct sockaddr_un sun = {
 159                .sun_family = AF_UNIX,
 160        };
 161        int ret;
 162        int flags;
 163
 164        MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
 165        if (server_socket)
 166                return 0;
 167        /*
 168         * Initialize the socket to communicate with the secondary
 169         * process.
 170         */
 171        ret = socket(AF_UNIX, SOCK_STREAM, 0);
 172        if (ret < 0) {
 173                DRV_LOG(WARNING, "Failed to open mlx5 socket: %s",
 174                        strerror(errno));
 175                goto error;
 176        }
 177        server_socket = ret;
 178        flags = fcntl(server_socket, F_GETFL, 0);
 179        if (flags == -1)
 180                goto error;
 181        ret = fcntl(server_socket, F_SETFL, flags | O_NONBLOCK);
 182        if (ret < 0)
 183                goto error;
 184        snprintf(sun.sun_path, sizeof(sun.sun_path), MLX5_SOCKET_PATH,
 185                 getpid());
 186        remove(sun.sun_path);
 187        ret = bind(server_socket, (const struct sockaddr *)&sun, sizeof(sun));
 188        if (ret < 0) {
 189                DRV_LOG(WARNING,
 190                        "cannot bind mlx5 socket: %s", strerror(errno));
 191                goto close;
 192        }
 193        ret = listen(server_socket, 0);
 194        if (ret < 0) {
 195                DRV_LOG(WARNING, "cannot listen on mlx5 socket: %s",
 196                        strerror(errno));
 197                goto close;
 198        }
 199        if (mlx5_pmd_interrupt_handler_install()) {
 200                DRV_LOG(WARNING, "cannot register interrupt handler for mlx5 socket: %s",
 201                        strerror(errno));
 202                goto close;
 203        }
 204        return 0;
 205close:
 206        remove(sun.sun_path);
 207error:
 208        claim_zero(close(server_socket));
 209        server_socket = 0;
 210        DRV_LOG(ERR, "Cannot initialize socket: %s", strerror(errno));
 211        return -errno;
 212}
 213
 214/**
 215 * Un-Initialize the pmd socket
 216 */
 217RTE_FINI(mlx5_pmd_socket_uninit)
 218{
 219        if (!server_socket)
 220                return;
 221        mlx5_pmd_interrupt_handler_uninstall();
 222        claim_zero(close(server_socket));
 223        server_socket = 0;
 224        MKSTR(path, MLX5_SOCKET_PATH, getpid());
 225        claim_zero(remove(path));
 226}
 227