linux/drivers/net/ethernet/intel/ice/ice_lag.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (C) 2018-2021, Intel Corporation. */
   3
   4/* Link Aggregation code */
   5
   6#include "ice.h"
   7#include "ice_lag.h"
   8
   9/**
  10 * ice_lag_nop_handler - no-op Rx handler to disable LAG
  11 * @pskb: pointer to skb pointer
  12 */
  13rx_handler_result_t ice_lag_nop_handler(struct sk_buff __always_unused **pskb)
  14{
  15        return RX_HANDLER_PASS;
  16}
  17
  18/**
  19 * ice_lag_set_primary - set PF LAG state as Primary
  20 * @lag: LAG info struct
  21 */
  22static void ice_lag_set_primary(struct ice_lag *lag)
  23{
  24        struct ice_pf *pf = lag->pf;
  25
  26        if (!pf)
  27                return;
  28
  29        if (lag->role != ICE_LAG_UNSET && lag->role != ICE_LAG_BACKUP) {
  30                dev_warn(ice_pf_to_dev(pf), "%s: Attempt to be Primary, but incompatible state.\n",
  31                         netdev_name(lag->netdev));
  32                return;
  33        }
  34
  35        lag->role = ICE_LAG_PRIMARY;
  36}
  37
  38/**
  39 * ice_lag_set_backup - set PF LAG state to Backup
  40 * @lag: LAG info struct
  41 */
  42static void ice_lag_set_backup(struct ice_lag *lag)
  43{
  44        struct ice_pf *pf = lag->pf;
  45
  46        if (!pf)
  47                return;
  48
  49        if (lag->role != ICE_LAG_UNSET && lag->role != ICE_LAG_PRIMARY) {
  50                dev_dbg(ice_pf_to_dev(pf), "%s: Attempt to be Backup, but incompatible state\n",
  51                        netdev_name(lag->netdev));
  52                return;
  53        }
  54
  55        lag->role = ICE_LAG_BACKUP;
  56}
  57
  58/**
  59 * ice_display_lag_info - print LAG info
  60 * @lag: LAG info struct
  61 */
  62static void ice_display_lag_info(struct ice_lag *lag)
  63{
  64        const char *name, *peer, *upper, *role, *bonded, *master;
  65        struct device *dev = &lag->pf->pdev->dev;
  66
  67        name = lag->netdev ? netdev_name(lag->netdev) : "unset";
  68        peer = lag->peer_netdev ? netdev_name(lag->peer_netdev) : "unset";
  69        upper = lag->upper_netdev ? netdev_name(lag->upper_netdev) : "unset";
  70        master = lag->master ? "TRUE" : "FALSE";
  71        bonded = lag->bonded ? "BONDED" : "UNBONDED";
  72
  73        switch (lag->role) {
  74        case ICE_LAG_NONE:
  75                role = "NONE";
  76                break;
  77        case ICE_LAG_PRIMARY:
  78                role = "PRIMARY";
  79                break;
  80        case ICE_LAG_BACKUP:
  81                role = "BACKUP";
  82                break;
  83        case ICE_LAG_UNSET:
  84                role = "UNSET";
  85                break;
  86        default:
  87                role = "ERROR";
  88        }
  89
  90        dev_dbg(dev, "%s %s, peer:%s, upper:%s, role:%s, master:%s\n", name,
  91                bonded, peer, upper, role, master);
  92}
  93
  94/**
  95 * ice_lag_info_event - handle NETDEV_BONDING_INFO event
  96 * @lag: LAG info struct
  97 * @ptr: opaque data pointer
  98 *
  99 * ptr is to be cast to (netdev_notifier_bonding_info *)
 100 */
 101static void ice_lag_info_event(struct ice_lag *lag, void *ptr)
 102{
 103        struct netdev_notifier_bonding_info *info;
 104        struct netdev_bonding_info *bonding_info;
 105        struct net_device *event_netdev;
 106        const char *lag_netdev_name;
 107
 108        event_netdev = netdev_notifier_info_to_dev(ptr);
 109        info = ptr;
 110        lag_netdev_name = netdev_name(lag->netdev);
 111        bonding_info = &info->bonding_info;
 112
 113        if (event_netdev != lag->netdev || !lag->bonded || !lag->upper_netdev)
 114                return;
 115
 116        if (bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) {
 117                netdev_dbg(lag->netdev, "Bonding event recv, but mode not active/backup\n");
 118                goto lag_out;
 119        }
 120
 121        if (strcmp(bonding_info->slave.slave_name, lag_netdev_name)) {
 122                netdev_dbg(lag->netdev, "Bonding event recv, but slave info not for us\n");
 123                goto lag_out;
 124        }
 125
 126        if (bonding_info->slave.state)
 127                ice_lag_set_backup(lag);
 128        else
 129                ice_lag_set_primary(lag);
 130
 131lag_out:
 132        ice_display_lag_info(lag);
 133}
 134
 135/**
 136 * ice_lag_link - handle LAG link event
 137 * @lag: LAG info struct
 138 * @info: info from the netdev notifier
 139 */
 140static void
 141ice_lag_link(struct ice_lag *lag, struct netdev_notifier_changeupper_info *info)
 142{
 143        struct net_device *netdev_tmp, *upper = info->upper_dev;
 144        struct ice_pf *pf = lag->pf;
 145        int peers = 0;
 146
 147        if (lag->bonded)
 148                dev_warn(ice_pf_to_dev(pf), "%s Already part of a bond\n",
 149                         netdev_name(lag->netdev));
 150
 151        rcu_read_lock();
 152        for_each_netdev_in_bond_rcu(upper, netdev_tmp)
 153                peers++;
 154        rcu_read_unlock();
 155
 156        if (lag->upper_netdev != upper) {
 157                dev_hold(upper);
 158                lag->upper_netdev = upper;
 159        }
 160
 161        ice_clear_sriov_cap(pf);
 162        ice_clear_rdma_cap(pf);
 163
 164        lag->bonded = true;
 165        lag->role = ICE_LAG_UNSET;
 166
 167        /* if this is the first element in an LAG mark as master */
 168        lag->master = !!(peers == 1);
 169}
 170
 171/**
 172 * ice_lag_unlink - handle unlink event
 173 * @lag: LAG info struct
 174 * @info: info from netdev notification
 175 */
 176static void
 177ice_lag_unlink(struct ice_lag *lag,
 178               struct netdev_notifier_changeupper_info *info)
 179{
 180        struct net_device *netdev_tmp, *upper = info->upper_dev;
 181        struct ice_pf *pf = lag->pf;
 182        bool found = false;
 183
 184        if (!lag->bonded) {
 185                netdev_dbg(lag->netdev, "bonding unlink event on non-LAG netdev\n");
 186                return;
 187        }
 188
 189        /* determine if we are in the new LAG config or not */
 190        rcu_read_lock();
 191        for_each_netdev_in_bond_rcu(upper, netdev_tmp) {
 192                if (netdev_tmp == lag->netdev) {
 193                        found = true;
 194                        break;
 195                }
 196        }
 197        rcu_read_unlock();
 198
 199        if (found)
 200                return;
 201
 202        if (lag->upper_netdev) {
 203                dev_put(lag->upper_netdev);
 204                lag->upper_netdev = NULL;
 205        }
 206
 207        if (lag->peer_netdev) {
 208                dev_put(lag->peer_netdev);
 209                lag->peer_netdev = NULL;
 210        }
 211
 212        ice_set_sriov_cap(pf);
 213        ice_set_rdma_cap(pf);
 214        lag->bonded = false;
 215        lag->role = ICE_LAG_NONE;
 216}
 217
 218/**
 219 * ice_lag_changeupper_event - handle LAG changeupper event
 220 * @lag: LAG info struct
 221 * @ptr: opaque pointer data
 222 *
 223 * ptr is to be cast into netdev_notifier_changeupper_info
 224 */
 225static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr)
 226{
 227        struct netdev_notifier_changeupper_info *info;
 228        struct net_device *netdev;
 229
 230        info = ptr;
 231        netdev = netdev_notifier_info_to_dev(ptr);
 232
 233        /* not for this netdev */
 234        if (netdev != lag->netdev)
 235                return;
 236
 237        if (!info->upper_dev) {
 238                netdev_dbg(netdev, "changeupper rcvd, but no upper defined\n");
 239                return;
 240        }
 241
 242        netdev_dbg(netdev, "bonding %s\n", info->linking ? "LINK" : "UNLINK");
 243
 244        if (!netif_is_lag_master(info->upper_dev)) {
 245                netdev_dbg(netdev, "changeupper rcvd, but not master. bail\n");
 246                return;
 247        }
 248
 249        if (info->linking)
 250                ice_lag_link(lag, info);
 251        else
 252                ice_lag_unlink(lag, info);
 253
 254        ice_display_lag_info(lag);
 255}
 256
 257/**
 258 * ice_lag_changelower_event - handle LAG changelower event
 259 * @lag: LAG info struct
 260 * @ptr: opaque data pointer
 261 *
 262 * ptr to be cast to netdev_notifier_changelowerstate_info
 263 */
 264static void ice_lag_changelower_event(struct ice_lag *lag, void *ptr)
 265{
 266        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
 267
 268        if (netdev != lag->netdev)
 269                return;
 270
 271        netdev_dbg(netdev, "bonding info\n");
 272
 273        if (!netif_is_lag_port(netdev))
 274                netdev_dbg(netdev, "CHANGELOWER rcvd, but netdev not in LAG. Bail\n");
 275}
 276
 277/**
 278 * ice_lag_event_handler - handle LAG events from netdev
 279 * @notif_blk: notifier block registered by this netdev
 280 * @event: event type
 281 * @ptr: opaque data containing notifier event
 282 */
 283static int
 284ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
 285                      void *ptr)
 286{
 287        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
 288        struct ice_lag *lag;
 289
 290        lag = container_of(notif_blk, struct ice_lag, notif_block);
 291
 292        if (!lag->netdev)
 293                return NOTIFY_DONE;
 294
 295        /* Check that the netdev is in the working namespace */
 296        if (!net_eq(dev_net(netdev), &init_net))
 297                return NOTIFY_DONE;
 298
 299        switch (event) {
 300        case NETDEV_CHANGEUPPER:
 301                ice_lag_changeupper_event(lag, ptr);
 302                break;
 303        case NETDEV_CHANGELOWERSTATE:
 304                ice_lag_changelower_event(lag, ptr);
 305                break;
 306        case NETDEV_BONDING_INFO:
 307                ice_lag_info_event(lag, ptr);
 308                break;
 309        case NETDEV_UNREGISTER:
 310                ice_lag_unlink(lag, ptr);
 311                break;
 312        default:
 313                break;
 314        }
 315
 316        return NOTIFY_DONE;
 317}
 318
 319/**
 320 * ice_register_lag_handler - register LAG handler on netdev
 321 * @lag: LAG struct
 322 */
 323static int ice_register_lag_handler(struct ice_lag *lag)
 324{
 325        struct device *dev = ice_pf_to_dev(lag->pf);
 326        struct notifier_block *notif_blk;
 327
 328        notif_blk = &lag->notif_block;
 329
 330        if (!notif_blk->notifier_call) {
 331                notif_blk->notifier_call = ice_lag_event_handler;
 332                if (register_netdevice_notifier(notif_blk)) {
 333                        notif_blk->notifier_call = NULL;
 334                        dev_err(dev, "FAIL register LAG event handler!\n");
 335                        return -EINVAL;
 336                }
 337                dev_dbg(dev, "LAG event handler registered\n");
 338        }
 339        return 0;
 340}
 341
 342/**
 343 * ice_unregister_lag_handler - unregister LAG handler on netdev
 344 * @lag: LAG struct
 345 */
 346static void ice_unregister_lag_handler(struct ice_lag *lag)
 347{
 348        struct device *dev = ice_pf_to_dev(lag->pf);
 349        struct notifier_block *notif_blk;
 350
 351        notif_blk = &lag->notif_block;
 352        if (notif_blk->notifier_call) {
 353                unregister_netdevice_notifier(notif_blk);
 354                dev_dbg(dev, "LAG event handler unregistered\n");
 355        }
 356}
 357
 358/**
 359 * ice_init_lag - initialize support for LAG
 360 * @pf: PF struct
 361 *
 362 * Alloc memory for LAG structs and initialize the elements.
 363 * Memory will be freed in ice_deinit_lag
 364 */
 365int ice_init_lag(struct ice_pf *pf)
 366{
 367        struct device *dev = ice_pf_to_dev(pf);
 368        struct ice_lag *lag;
 369        struct ice_vsi *vsi;
 370        int err;
 371
 372        pf->lag = kzalloc(sizeof(*lag), GFP_KERNEL);
 373        if (!pf->lag)
 374                return -ENOMEM;
 375        lag = pf->lag;
 376
 377        vsi = ice_get_main_vsi(pf);
 378        if (!vsi) {
 379                dev_err(dev, "couldn't get main vsi, link aggregation init fail\n");
 380                err = -EIO;
 381                goto lag_error;
 382        }
 383
 384        lag->pf = pf;
 385        lag->netdev = vsi->netdev;
 386        lag->role = ICE_LAG_NONE;
 387        lag->bonded = false;
 388        lag->peer_netdev = NULL;
 389        lag->upper_netdev = NULL;
 390        lag->notif_block.notifier_call = NULL;
 391
 392        err = ice_register_lag_handler(lag);
 393        if (err) {
 394                dev_warn(dev, "INIT LAG: Failed to register event handler\n");
 395                goto lag_error;
 396        }
 397
 398        ice_display_lag_info(lag);
 399
 400        dev_dbg(dev, "INIT LAG complete\n");
 401        return 0;
 402
 403lag_error:
 404        kfree(lag);
 405        pf->lag = NULL;
 406        return err;
 407}
 408
 409/**
 410 * ice_deinit_lag - Clean up LAG
 411 * @pf: PF struct
 412 *
 413 * Clean up kernel LAG info and free memory
 414 * This function is meant to only be called on driver remove/shutdown
 415 */
 416void ice_deinit_lag(struct ice_pf *pf)
 417{
 418        struct ice_lag *lag;
 419
 420        lag = pf->lag;
 421
 422        if (!lag)
 423                return;
 424
 425        if (lag->pf)
 426                ice_unregister_lag_handler(lag);
 427
 428        if (lag->upper_netdev)
 429                dev_put(lag->upper_netdev);
 430
 431        if (lag->peer_netdev)
 432                dev_put(lag->peer_netdev);
 433
 434        kfree(lag);
 435
 436        pf->lag = NULL;
 437}
 438