dpdk/drivers/net/failsafe/failsafe.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright 2017 6WIND S.A.
   3 * Copyright 2017 Mellanox Technologies, Ltd
   4 */
   5
   6#include <stdbool.h>
   7
   8#include <rte_alarm.h>
   9#include <rte_malloc.h>
  10#include <ethdev_driver.h>
  11#include <ethdev_vdev.h>
  12#include <rte_devargs.h>
  13#include <rte_kvargs.h>
  14#include <rte_bus_vdev.h>
  15
  16#include "failsafe_private.h"
  17
  18const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
  19static const struct rte_eth_link eth_link = {
  20        .link_speed = RTE_ETH_SPEED_NUM_10G,
  21        .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
  22        .link_status = RTE_ETH_LINK_UP,
  23        .link_autoneg = RTE_ETH_LINK_AUTONEG,
  24};
  25
  26static int
  27fs_sub_device_alloc(struct rte_eth_dev *dev,
  28                const char *params)
  29{
  30        uint8_t nb_subs;
  31        int ret;
  32        int i;
  33        struct sub_device *sdev;
  34        uint8_t sdev_iterator;
  35
  36        ret = failsafe_args_count_subdevice(dev, params);
  37        if (ret)
  38                return ret;
  39        if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
  40                ERROR("Cannot allocate more than %d ports",
  41                        FAILSAFE_MAX_ETHPORTS);
  42                return -ENOSPC;
  43        }
  44        nb_subs = PRIV(dev)->subs_tail;
  45        PRIV(dev)->subs = rte_zmalloc(NULL,
  46                        sizeof(struct sub_device) * nb_subs,
  47                        RTE_CACHE_LINE_SIZE);
  48        if (PRIV(dev)->subs == NULL) {
  49                ERROR("Could not allocate sub_devices");
  50                return -ENOMEM;
  51        }
  52        /* Initiate static sub devices linked list. */
  53        for (i = 1; i < nb_subs; i++)
  54                PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i;
  55        PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs;
  56
  57        FOREACH_SUBDEV(sdev, sdev_iterator, dev) {
  58                sdev->sdev_port_id = RTE_MAX_ETHPORTS;
  59        }
  60        return 0;
  61}
  62
  63static void fs_hotplug_alarm(void *arg);
  64
  65int
  66failsafe_hotplug_alarm_install(struct rte_eth_dev *dev)
  67{
  68        int ret;
  69
  70        if (dev == NULL)
  71                return -EINVAL;
  72        if (PRIV(dev)->pending_alarm)
  73                return 0;
  74        ret = rte_eal_alarm_set(failsafe_hotplug_poll * 1000,
  75                                fs_hotplug_alarm,
  76                                dev);
  77        if (ret) {
  78                ERROR("Could not set up plug-in event detection");
  79                return ret;
  80        }
  81        PRIV(dev)->pending_alarm = 1;
  82        return 0;
  83}
  84
  85int
  86failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev)
  87{
  88        int ret = 0;
  89
  90        rte_errno = 0;
  91        rte_eal_alarm_cancel(fs_hotplug_alarm, dev);
  92        if (rte_errno) {
  93                ERROR("rte_eal_alarm_cancel failed (errno: %s)",
  94                      strerror(rte_errno));
  95                ret = -rte_errno;
  96        } else {
  97                PRIV(dev)->pending_alarm = 0;
  98        }
  99        return ret;
 100}
 101
 102static void
 103fs_hotplug_alarm(void *arg)
 104{
 105        struct rte_eth_dev *dev = arg;
 106        struct sub_device *sdev;
 107        int ret;
 108        uint8_t i;
 109
 110        if (!PRIV(dev)->pending_alarm)
 111                return;
 112        PRIV(dev)->pending_alarm = 0;
 113        FOREACH_SUBDEV(sdev, i, dev)
 114                if (sdev->state != PRIV(dev)->state)
 115                        break;
 116        /* if we have non-probed device */
 117        if (i != PRIV(dev)->subs_tail) {
 118                if (fs_lock(dev, 1) != 0)
 119                        goto reinstall;
 120                ret = failsafe_eth_dev_state_sync(dev);
 121                fs_unlock(dev, 1);
 122                if (ret)
 123                        ERROR("Unable to synchronize sub_device state");
 124        }
 125        failsafe_dev_remove(dev);
 126reinstall:
 127        ret = failsafe_hotplug_alarm_install(dev);
 128        if (ret)
 129                ERROR("Unable to set up next alarm");
 130}
 131
 132static int
 133fs_mutex_init(struct fs_priv *priv)
 134{
 135        int ret;
 136        pthread_mutexattr_t attr;
 137
 138        ret = pthread_mutexattr_init(&attr);
 139        if (ret) {
 140                ERROR("Cannot initiate mutex attributes - %s", strerror(ret));
 141                return ret;
 142        }
 143        /* Allow mutex relocks for the thread holding the mutex. */
 144        ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 145        if (ret) {
 146                ERROR("Cannot set mutex type - %s", strerror(ret));
 147                return ret;
 148        }
 149        ret = pthread_mutex_init(&priv->hotplug_mutex, &attr);
 150        if (ret) {
 151                ERROR("Cannot initiate mutex - %s", strerror(ret));
 152                return ret;
 153        }
 154        return 0;
 155}
 156
 157static int
 158fs_eth_dev_create(struct rte_vdev_device *vdev)
 159{
 160        struct rte_eth_dev *dev;
 161        struct rte_ether_addr *mac;
 162        struct fs_priv *priv;
 163        struct sub_device *sdev;
 164        const char *params;
 165        unsigned int socket_id;
 166        uint8_t i;
 167        int ret;
 168
 169        dev = NULL;
 170        priv = NULL;
 171        socket_id = rte_socket_id();
 172        INFO("Creating fail-safe device on NUMA socket %u", socket_id);
 173        params = rte_vdev_device_args(vdev);
 174        if (params == NULL) {
 175                ERROR("This PMD requires sub-devices, none provided");
 176                return -1;
 177        }
 178        dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
 179        if (dev == NULL) {
 180                ERROR("Unable to allocate rte_eth_dev");
 181                return -1;
 182        }
 183        priv = PRIV(dev);
 184        priv->data = dev->data;
 185        priv->rxp = FS_RX_PROXY_INIT;
 186        dev->dev_ops = &failsafe_ops;
 187        dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
 188        dev->data->dev_link = eth_link;
 189        PRIV(dev)->nb_mac_addr = 1;
 190        TAILQ_INIT(&PRIV(dev)->flow_list);
 191        dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 192        dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 193        ret = fs_sub_device_alloc(dev, params);
 194        if (ret) {
 195                ERROR("Could not allocate sub_devices");
 196                goto free_dev;
 197        }
 198        ret = failsafe_args_parse(dev, params);
 199        if (ret)
 200                goto free_subs;
 201        ret = rte_eth_dev_owner_new(&priv->my_owner.id);
 202        if (ret) {
 203                ERROR("Failed to get unique owner identifier");
 204                goto free_args;
 205        }
 206        snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
 207                 FAILSAFE_OWNER_NAME);
 208        DEBUG("Failsafe port %u owner info: %s_%016"PRIX64, dev->data->port_id,
 209              priv->my_owner.name, priv->my_owner.id);
 210        ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
 211                                            failsafe_eth_new_event_callback,
 212                                            dev);
 213        if (ret) {
 214                ERROR("Failed to register NEW callback");
 215                goto free_args;
 216        }
 217        ret = failsafe_eal_init(dev);
 218        if (ret)
 219                goto unregister_new_callback;
 220        ret = fs_mutex_init(priv);
 221        if (ret)
 222                goto unregister_new_callback;
 223        ret = failsafe_hotplug_alarm_install(dev);
 224        if (ret) {
 225                ERROR("Could not set up plug-in event detection");
 226                goto unregister_new_callback;
 227        }
 228        mac = &dev->data->mac_addrs[0];
 229        if (failsafe_mac_from_arg) {
 230                /*
 231                 * If MAC address was provided as a parameter,
 232                 * apply to all probed subdevices.
 233                 */
 234                FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
 235                        ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
 236                                                               mac);
 237                        if (ret) {
 238                                ERROR("Failed to set default MAC address");
 239                                goto cancel_alarm;
 240                        }
 241                }
 242        } else {
 243                /*
 244                 * Use the ether_addr from first probed
 245                 * device, either preferred or fallback.
 246                 */
 247                FOREACH_SUBDEV(sdev, i, dev)
 248                        if (sdev->state >= DEV_PROBED) {
 249                                rte_ether_addr_copy(
 250                                        &ETH(sdev)->data->mac_addrs[0], mac);
 251                                break;
 252                        }
 253                /*
 254                 * If no device has been probed and no ether_addr
 255                 * has been provided on the command line, use a random
 256                 * valid one.
 257                 * It will be applied during future state syncs to
 258                 * probed subdevices.
 259                 */
 260                if (i == priv->subs_tail)
 261                        rte_eth_random_addr(&mac->addr_bytes[0]);
 262        }
 263        INFO("MAC address is " RTE_ETHER_ADDR_PRT_FMT,
 264                RTE_ETHER_ADDR_BYTES(mac));
 265        dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC |
 266                                RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
 267
 268        /* Allocate interrupt instance */
 269        PRIV(dev)->intr_handle =
 270                rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
 271        if (PRIV(dev)->intr_handle == NULL) {
 272                ERROR("Failed to allocate intr handle");
 273                goto cancel_alarm;
 274        }
 275
 276        if (rte_intr_fd_set(PRIV(dev)->intr_handle, -1))
 277                goto cancel_alarm;
 278
 279        if (rte_intr_type_set(PRIV(dev)->intr_handle, RTE_INTR_HANDLE_EXT))
 280                goto cancel_alarm;
 281
 282        rte_eth_dev_probing_finish(dev);
 283
 284        return 0;
 285cancel_alarm:
 286        failsafe_hotplug_alarm_cancel(dev);
 287unregister_new_callback:
 288        rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
 289                                        failsafe_eth_new_event_callback, dev);
 290free_args:
 291        failsafe_args_free(dev);
 292free_subs:
 293        rte_free(PRIV(dev)->subs);
 294free_dev:
 295        /* mac_addrs must not be freed alone because part of dev_private */
 296        dev->data->mac_addrs = NULL;
 297        rte_eth_dev_release_port(dev);
 298        return -1;
 299}
 300
 301static int
 302fs_rte_eth_free(const char *name)
 303{
 304        struct rte_eth_dev *dev;
 305        int ret;
 306
 307        dev = rte_eth_dev_allocated(name);
 308        if (dev == NULL)
 309                return 0; /* port already released */
 310        ret = failsafe_eth_dev_close(dev);
 311        rte_eth_dev_release_port(dev);
 312        rte_intr_instance_free(PRIV(dev)->intr_handle);
 313        return ret;
 314}
 315
 316static bool
 317devargs_already_listed(struct rte_devargs *devargs)
 318{
 319        struct rte_devargs *list_da;
 320
 321        RTE_EAL_DEVARGS_FOREACH(devargs->bus->name, list_da) {
 322                if (strcmp(list_da->name, devargs->name) == 0)
 323                        /* devargs already in the list */
 324                        return true;
 325        }
 326        return false;
 327}
 328
 329static int
 330rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
 331{
 332        const char *name;
 333        struct rte_eth_dev *eth_dev;
 334        struct sub_device  *sdev;
 335        struct rte_devargs devargs;
 336        uint8_t i;
 337        int ret;
 338
 339        name = rte_vdev_device_name(vdev);
 340        INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
 341                        name);
 342
 343        if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
 344                eth_dev = rte_eth_dev_attach_secondary(name);
 345                if (!eth_dev) {
 346                        ERROR("Failed to probe %s", name);
 347                        return -1;
 348                }
 349                eth_dev->dev_ops = &failsafe_ops;
 350                eth_dev->device = &vdev->device;
 351                eth_dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
 352                eth_dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
 353                /*
 354                 * Failsafe will attempt to probe all of its sub-devices.
 355                 * Any failure in sub-devices is not a fatal error.
 356                 * A sub-device can be plugged later.
 357                 */
 358                FOREACH_SUBDEV(sdev, i, eth_dev) {
 359                        /* skip empty devargs */
 360                        if (sdev->devargs.name[0] == '\0')
 361                                continue;
 362
 363                        /* rebuild devargs to be able to get the bus name. */
 364                        ret = rte_devargs_parse(&devargs,
 365                                                sdev->devargs.name);
 366                        if (ret != 0) {
 367                                ERROR("Failed to parse devargs %s",
 368                                        devargs.name);
 369                                continue;
 370                        }
 371                        if (!devargs_already_listed(&devargs)) {
 372                                ret = rte_dev_probe(devargs.name);
 373                                if (ret < 0) {
 374                                        ERROR("Failed to probe devargs %s",
 375                                              devargs.name);
 376                                        continue;
 377                                }
 378                        }
 379                }
 380                rte_eth_dev_probing_finish(eth_dev);
 381                return 0;
 382        }
 383
 384        return fs_eth_dev_create(vdev);
 385}
 386
 387static int
 388rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
 389{
 390        const char *name;
 391
 392        name = rte_vdev_device_name(vdev);
 393        INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
 394        return fs_rte_eth_free(name);
 395}
 396
 397static struct rte_vdev_driver failsafe_drv = {
 398        .probe = rte_pmd_failsafe_probe,
 399        .remove = rte_pmd_failsafe_remove,
 400};
 401
 402RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
 403RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);
 404RTE_LOG_REGISTER_DEFAULT(failsafe_logtype, NOTICE)
 405