linux/net/dsa/switch.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Handling of a single switch chip, part of a switch fabric
   4 *
   5 * Copyright (c) 2017 Savoir-faire Linux Inc.
   6 *      Vivien Didelot <vivien.didelot@savoirfairelinux.com>
   7 */
   8
   9#include <linux/if_bridge.h>
  10#include <linux/netdevice.h>
  11#include <linux/notifier.h>
  12#include <linux/if_vlan.h>
  13#include <net/switchdev.h>
  14
  15#include "dsa_priv.h"
  16
  17static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
  18                                                   unsigned int ageing_time)
  19{
  20        int i;
  21
  22        for (i = 0; i < ds->num_ports; ++i) {
  23                struct dsa_port *dp = dsa_to_port(ds, i);
  24
  25                if (dp->ageing_time && dp->ageing_time < ageing_time)
  26                        ageing_time = dp->ageing_time;
  27        }
  28
  29        return ageing_time;
  30}
  31
  32static int dsa_switch_ageing_time(struct dsa_switch *ds,
  33                                  struct dsa_notifier_ageing_time_info *info)
  34{
  35        unsigned int ageing_time = info->ageing_time;
  36
  37        if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
  38                return -ERANGE;
  39
  40        if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
  41                return -ERANGE;
  42
  43        /* Program the fastest ageing time in case of multiple bridges */
  44        ageing_time = dsa_switch_fastest_ageing_time(ds, ageing_time);
  45
  46        if (ds->ops->set_ageing_time)
  47                return ds->ops->set_ageing_time(ds, ageing_time);
  48
  49        return 0;
  50}
  51
  52static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
  53                                 struct dsa_notifier_mtu_info *info)
  54{
  55        if (ds->index == info->sw_index)
  56                return (port == info->port) || dsa_is_dsa_port(ds, port);
  57
  58        if (!info->propagate_upstream)
  59                return false;
  60
  61        if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
  62                return true;
  63
  64        return false;
  65}
  66
  67static int dsa_switch_mtu(struct dsa_switch *ds,
  68                          struct dsa_notifier_mtu_info *info)
  69{
  70        int port, ret;
  71
  72        if (!ds->ops->port_change_mtu)
  73                return -EOPNOTSUPP;
  74
  75        for (port = 0; port < ds->num_ports; port++) {
  76                if (dsa_switch_mtu_match(ds, port, info)) {
  77                        ret = ds->ops->port_change_mtu(ds, port, info->mtu);
  78                        if (ret)
  79                                return ret;
  80                }
  81        }
  82
  83        return 0;
  84}
  85
  86static int dsa_switch_bridge_join(struct dsa_switch *ds,
  87                                  struct dsa_notifier_bridge_info *info)
  88{
  89        struct dsa_switch_tree *dst = ds->dst;
  90
  91        if (dst->index == info->tree_index && ds->index == info->sw_index &&
  92            ds->ops->port_bridge_join)
  93                return ds->ops->port_bridge_join(ds, info->port, info->br);
  94
  95        if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
  96            ds->ops->crosschip_bridge_join)
  97                return ds->ops->crosschip_bridge_join(ds, info->tree_index,
  98                                                      info->sw_index,
  99                                                      info->port, info->br);
 100
 101        return 0;
 102}
 103
 104static int dsa_switch_bridge_leave(struct dsa_switch *ds,
 105                                   struct dsa_notifier_bridge_info *info)
 106{
 107        bool unset_vlan_filtering = br_vlan_enabled(info->br);
 108        struct dsa_switch_tree *dst = ds->dst;
 109        struct netlink_ext_ack extack = {0};
 110        int err, port;
 111
 112        if (dst->index == info->tree_index && ds->index == info->sw_index &&
 113            ds->ops->port_bridge_leave)
 114                ds->ops->port_bridge_leave(ds, info->port, info->br);
 115
 116        if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
 117            ds->ops->crosschip_bridge_leave)
 118                ds->ops->crosschip_bridge_leave(ds, info->tree_index,
 119                                                info->sw_index, info->port,
 120                                                info->br);
 121
 122        /* If the bridge was vlan_filtering, the bridge core doesn't trigger an
 123         * event for changing vlan_filtering setting upon slave ports leaving
 124         * it. That is a good thing, because that lets us handle it and also
 125         * handle the case where the switch's vlan_filtering setting is global
 126         * (not per port). When that happens, the correct moment to trigger the
 127         * vlan_filtering callback is only when the last port leaves the last
 128         * VLAN-aware bridge.
 129         */
 130        if (unset_vlan_filtering && ds->vlan_filtering_is_global) {
 131                for (port = 0; port < ds->num_ports; port++) {
 132                        struct net_device *bridge_dev;
 133
 134                        bridge_dev = dsa_to_port(ds, port)->bridge_dev;
 135
 136                        if (bridge_dev && br_vlan_enabled(bridge_dev)) {
 137                                unset_vlan_filtering = false;
 138                                break;
 139                        }
 140                }
 141        }
 142        if (unset_vlan_filtering) {
 143                err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
 144                                              false, &extack);
 145                if (extack._msg)
 146                        dev_err(ds->dev, "port %d: %s\n", info->port,
 147                                extack._msg);
 148                if (err && err != EOPNOTSUPP)
 149                        return err;
 150        }
 151        return 0;
 152}
 153
 154static int dsa_switch_fdb_add(struct dsa_switch *ds,
 155                              struct dsa_notifier_fdb_info *info)
 156{
 157        int port = dsa_towards_port(ds, info->sw_index, info->port);
 158
 159        if (!ds->ops->port_fdb_add)
 160                return -EOPNOTSUPP;
 161
 162        return ds->ops->port_fdb_add(ds, port, info->addr, info->vid);
 163}
 164
 165static int dsa_switch_fdb_del(struct dsa_switch *ds,
 166                              struct dsa_notifier_fdb_info *info)
 167{
 168        int port = dsa_towards_port(ds, info->sw_index, info->port);
 169
 170        if (!ds->ops->port_fdb_del)
 171                return -EOPNOTSUPP;
 172
 173        return ds->ops->port_fdb_del(ds, port, info->addr, info->vid);
 174}
 175
 176static int dsa_switch_hsr_join(struct dsa_switch *ds,
 177                               struct dsa_notifier_hsr_info *info)
 178{
 179        if (ds->index == info->sw_index && ds->ops->port_hsr_join)
 180                return ds->ops->port_hsr_join(ds, info->port, info->hsr);
 181
 182        return -EOPNOTSUPP;
 183}
 184
 185static int dsa_switch_hsr_leave(struct dsa_switch *ds,
 186                                struct dsa_notifier_hsr_info *info)
 187{
 188        if (ds->index == info->sw_index && ds->ops->port_hsr_leave)
 189                return ds->ops->port_hsr_leave(ds, info->port, info->hsr);
 190
 191        return -EOPNOTSUPP;
 192}
 193
 194static int dsa_switch_lag_change(struct dsa_switch *ds,
 195                                 struct dsa_notifier_lag_info *info)
 196{
 197        if (ds->index == info->sw_index && ds->ops->port_lag_change)
 198                return ds->ops->port_lag_change(ds, info->port);
 199
 200        if (ds->index != info->sw_index && ds->ops->crosschip_lag_change)
 201                return ds->ops->crosschip_lag_change(ds, info->sw_index,
 202                                                     info->port);
 203
 204        return 0;
 205}
 206
 207static int dsa_switch_lag_join(struct dsa_switch *ds,
 208                               struct dsa_notifier_lag_info *info)
 209{
 210        if (ds->index == info->sw_index && ds->ops->port_lag_join)
 211                return ds->ops->port_lag_join(ds, info->port, info->lag,
 212                                              info->info);
 213
 214        if (ds->index != info->sw_index && ds->ops->crosschip_lag_join)
 215                return ds->ops->crosschip_lag_join(ds, info->sw_index,
 216                                                   info->port, info->lag,
 217                                                   info->info);
 218
 219        return 0;
 220}
 221
 222static int dsa_switch_lag_leave(struct dsa_switch *ds,
 223                                struct dsa_notifier_lag_info *info)
 224{
 225        if (ds->index == info->sw_index && ds->ops->port_lag_leave)
 226                return ds->ops->port_lag_leave(ds, info->port, info->lag);
 227
 228        if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave)
 229                return ds->ops->crosschip_lag_leave(ds, info->sw_index,
 230                                                    info->port, info->lag);
 231
 232        return 0;
 233}
 234
 235static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port,
 236                                 struct dsa_notifier_mdb_info *info)
 237{
 238        if (ds->index == info->sw_index && port == info->port)
 239                return true;
 240
 241        if (dsa_is_dsa_port(ds, port))
 242                return true;
 243
 244        return false;
 245}
 246
 247static int dsa_switch_mdb_add(struct dsa_switch *ds,
 248                              struct dsa_notifier_mdb_info *info)
 249{
 250        int err = 0;
 251        int port;
 252
 253        if (!ds->ops->port_mdb_add)
 254                return -EOPNOTSUPP;
 255
 256        for (port = 0; port < ds->num_ports; port++) {
 257                if (dsa_switch_mdb_match(ds, port, info)) {
 258                        err = ds->ops->port_mdb_add(ds, port, info->mdb);
 259                        if (err)
 260                                break;
 261                }
 262        }
 263
 264        return err;
 265}
 266
 267static int dsa_switch_mdb_del(struct dsa_switch *ds,
 268                              struct dsa_notifier_mdb_info *info)
 269{
 270        if (!ds->ops->port_mdb_del)
 271                return -EOPNOTSUPP;
 272
 273        if (ds->index == info->sw_index)
 274                return ds->ops->port_mdb_del(ds, info->port, info->mdb);
 275
 276        return 0;
 277}
 278
 279static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
 280                                  struct dsa_notifier_vlan_info *info)
 281{
 282        if (ds->index == info->sw_index && port == info->port)
 283                return true;
 284
 285        if (dsa_is_dsa_port(ds, port))
 286                return true;
 287
 288        return false;
 289}
 290
 291static int dsa_switch_vlan_add(struct dsa_switch *ds,
 292                               struct dsa_notifier_vlan_info *info)
 293{
 294        int port, err;
 295
 296        if (!ds->ops->port_vlan_add)
 297                return -EOPNOTSUPP;
 298
 299        for (port = 0; port < ds->num_ports; port++) {
 300                if (dsa_switch_vlan_match(ds, port, info)) {
 301                        err = ds->ops->port_vlan_add(ds, port, info->vlan,
 302                                                     info->extack);
 303                        if (err)
 304                                return err;
 305                }
 306        }
 307
 308        return 0;
 309}
 310
 311static int dsa_switch_vlan_del(struct dsa_switch *ds,
 312                               struct dsa_notifier_vlan_info *info)
 313{
 314        if (!ds->ops->port_vlan_del)
 315                return -EOPNOTSUPP;
 316
 317        if (ds->index == info->sw_index)
 318                return ds->ops->port_vlan_del(ds, info->port, info->vlan);
 319
 320        /* Do not deprogram the DSA links as they may be used as conduit
 321         * for other VLAN members in the fabric.
 322         */
 323        return 0;
 324}
 325
 326static int dsa_switch_change_tag_proto(struct dsa_switch *ds,
 327                                       struct dsa_notifier_tag_proto_info *info)
 328{
 329        const struct dsa_device_ops *tag_ops = info->tag_ops;
 330        int port, err;
 331
 332        if (!ds->ops->change_tag_protocol)
 333                return -EOPNOTSUPP;
 334
 335        ASSERT_RTNL();
 336
 337        for (port = 0; port < ds->num_ports; port++) {
 338                if (!dsa_is_cpu_port(ds, port))
 339                        continue;
 340
 341                err = ds->ops->change_tag_protocol(ds, port, tag_ops->proto);
 342                if (err)
 343                        return err;
 344
 345                dsa_port_set_tag_protocol(dsa_to_port(ds, port), tag_ops);
 346        }
 347
 348        /* Now that changing the tag protocol can no longer fail, let's update
 349         * the remaining bits which are "duplicated for faster access", and the
 350         * bits that depend on the tagger, such as the MTU.
 351         */
 352        for (port = 0; port < ds->num_ports; port++) {
 353                if (dsa_is_user_port(ds, port)) {
 354                        struct net_device *slave;
 355
 356                        slave = dsa_to_port(ds, port)->slave;
 357                        dsa_slave_setup_tagger(slave);
 358
 359                        /* rtnl_mutex is held in dsa_tree_change_tag_proto */
 360                        dsa_slave_change_mtu(slave, slave->mtu);
 361                }
 362        }
 363
 364        return 0;
 365}
 366
 367static bool dsa_switch_mrp_match(struct dsa_switch *ds, int port,
 368                                 struct dsa_notifier_mrp_info *info)
 369{
 370        if (ds->index == info->sw_index && port == info->port)
 371                return true;
 372
 373        if (dsa_is_dsa_port(ds, port))
 374                return true;
 375
 376        return false;
 377}
 378
 379static int dsa_switch_mrp_add(struct dsa_switch *ds,
 380                              struct dsa_notifier_mrp_info *info)
 381{
 382        int err = 0;
 383        int port;
 384
 385        if (!ds->ops->port_mrp_add)
 386                return -EOPNOTSUPP;
 387
 388        for (port = 0; port < ds->num_ports; port++) {
 389                if (dsa_switch_mrp_match(ds, port, info)) {
 390                        err = ds->ops->port_mrp_add(ds, port, info->mrp);
 391                        if (err)
 392                                break;
 393                }
 394        }
 395
 396        return err;
 397}
 398
 399static int dsa_switch_mrp_del(struct dsa_switch *ds,
 400                              struct dsa_notifier_mrp_info *info)
 401{
 402        if (!ds->ops->port_mrp_del)
 403                return -EOPNOTSUPP;
 404
 405        if (ds->index == info->sw_index)
 406                return ds->ops->port_mrp_del(ds, info->port, info->mrp);
 407
 408        return 0;
 409}
 410
 411static bool
 412dsa_switch_mrp_ring_role_match(struct dsa_switch *ds, int port,
 413                               struct dsa_notifier_mrp_ring_role_info *info)
 414{
 415        if (ds->index == info->sw_index && port == info->port)
 416                return true;
 417
 418        if (dsa_is_dsa_port(ds, port))
 419                return true;
 420
 421        return false;
 422}
 423
 424static int
 425dsa_switch_mrp_add_ring_role(struct dsa_switch *ds,
 426                             struct dsa_notifier_mrp_ring_role_info *info)
 427{
 428        int err = 0;
 429        int port;
 430
 431        if (!ds->ops->port_mrp_add)
 432                return -EOPNOTSUPP;
 433
 434        for (port = 0; port < ds->num_ports; port++) {
 435                if (dsa_switch_mrp_ring_role_match(ds, port, info)) {
 436                        err = ds->ops->port_mrp_add_ring_role(ds, port,
 437                                                              info->mrp);
 438                        if (err)
 439                                break;
 440                }
 441        }
 442
 443        return err;
 444}
 445
 446static int
 447dsa_switch_mrp_del_ring_role(struct dsa_switch *ds,
 448                             struct dsa_notifier_mrp_ring_role_info *info)
 449{
 450        if (!ds->ops->port_mrp_del)
 451                return -EOPNOTSUPP;
 452
 453        if (ds->index == info->sw_index)
 454                return ds->ops->port_mrp_del_ring_role(ds, info->port,
 455                                                       info->mrp);
 456
 457        return 0;
 458}
 459
 460static int dsa_switch_event(struct notifier_block *nb,
 461                            unsigned long event, void *info)
 462{
 463        struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb);
 464        int err;
 465
 466        switch (event) {
 467        case DSA_NOTIFIER_AGEING_TIME:
 468                err = dsa_switch_ageing_time(ds, info);
 469                break;
 470        case DSA_NOTIFIER_BRIDGE_JOIN:
 471                err = dsa_switch_bridge_join(ds, info);
 472                break;
 473        case DSA_NOTIFIER_BRIDGE_LEAVE:
 474                err = dsa_switch_bridge_leave(ds, info);
 475                break;
 476        case DSA_NOTIFIER_FDB_ADD:
 477                err = dsa_switch_fdb_add(ds, info);
 478                break;
 479        case DSA_NOTIFIER_FDB_DEL:
 480                err = dsa_switch_fdb_del(ds, info);
 481                break;
 482        case DSA_NOTIFIER_HSR_JOIN:
 483                err = dsa_switch_hsr_join(ds, info);
 484                break;
 485        case DSA_NOTIFIER_HSR_LEAVE:
 486                err = dsa_switch_hsr_leave(ds, info);
 487                break;
 488        case DSA_NOTIFIER_LAG_CHANGE:
 489                err = dsa_switch_lag_change(ds, info);
 490                break;
 491        case DSA_NOTIFIER_LAG_JOIN:
 492                err = dsa_switch_lag_join(ds, info);
 493                break;
 494        case DSA_NOTIFIER_LAG_LEAVE:
 495                err = dsa_switch_lag_leave(ds, info);
 496                break;
 497        case DSA_NOTIFIER_MDB_ADD:
 498                err = dsa_switch_mdb_add(ds, info);
 499                break;
 500        case DSA_NOTIFIER_MDB_DEL:
 501                err = dsa_switch_mdb_del(ds, info);
 502                break;
 503        case DSA_NOTIFIER_VLAN_ADD:
 504                err = dsa_switch_vlan_add(ds, info);
 505                break;
 506        case DSA_NOTIFIER_VLAN_DEL:
 507                err = dsa_switch_vlan_del(ds, info);
 508                break;
 509        case DSA_NOTIFIER_MTU:
 510                err = dsa_switch_mtu(ds, info);
 511                break;
 512        case DSA_NOTIFIER_TAG_PROTO:
 513                err = dsa_switch_change_tag_proto(ds, info);
 514                break;
 515        case DSA_NOTIFIER_MRP_ADD:
 516                err = dsa_switch_mrp_add(ds, info);
 517                break;
 518        case DSA_NOTIFIER_MRP_DEL:
 519                err = dsa_switch_mrp_del(ds, info);
 520                break;
 521        case DSA_NOTIFIER_MRP_ADD_RING_ROLE:
 522                err = dsa_switch_mrp_add_ring_role(ds, info);
 523                break;
 524        case DSA_NOTIFIER_MRP_DEL_RING_ROLE:
 525                err = dsa_switch_mrp_del_ring_role(ds, info);
 526                break;
 527        default:
 528                err = -EOPNOTSUPP;
 529                break;
 530        }
 531
 532        if (err)
 533                dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n",
 534                        event, err);
 535
 536        return notifier_from_errno(err);
 537}
 538
 539int dsa_switch_register_notifier(struct dsa_switch *ds)
 540{
 541        ds->nb.notifier_call = dsa_switch_event;
 542
 543        return raw_notifier_chain_register(&ds->dst->nh, &ds->nb);
 544}
 545
 546void dsa_switch_unregister_notifier(struct dsa_switch *ds)
 547{
 548        int err;
 549
 550        err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb);
 551        if (err)
 552                dev_err(ds->dev, "failed to unregister notifier (%d)\n", err);
 553}
 554