blob: bb155a16d45409afc1f2f83888043c79e1afadcf [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Vivien Didelotf515f192017-02-03 13:20:20 -05002/*
3 * Handling of a single switch chip, part of a switch fabric
4 *
Vivien Didelot4333d612017-03-28 15:10:36 -04005 * Copyright (c) 2017 Savoir-faire Linux Inc.
6 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Vivien Didelotf515f192017-02-03 13:20:20 -05007 */
8
Vladimir Olteand371b7c2019-04-28 21:45:46 +03009#include <linux/if_bridge.h>
Vivien Didelotf515f192017-02-03 13:20:20 -050010#include <linux/netdevice.h>
11#include <linux/notifier.h>
Florian Fainelli061f6a52019-02-20 14:35:39 -080012#include <linux/if_vlan.h>
Vivien Didelot1faabf72017-05-19 17:00:52 -040013#include <net/switchdev.h>
Vivien Didelotea5dd342017-05-17 15:46:03 -040014
15#include "dsa_priv.h"
Vivien Didelotf515f192017-02-03 13:20:20 -050016
Vivien Didelot1faabf72017-05-19 17:00:52 -040017static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
18 unsigned int ageing_time)
19{
Vladimir Olteand0004a02021-10-20 20:49:50 +030020 struct dsa_port *dp;
Vivien Didelot1faabf72017-05-19 17:00:52 -040021
Vladimir Olteand0004a02021-10-20 20:49:50 +030022 dsa_switch_for_each_port(dp, ds)
Vivien Didelot1faabf72017-05-19 17:00:52 -040023 if (dp->ageing_time && dp->ageing_time < ageing_time)
24 ageing_time = dp->ageing_time;
Vivien Didelot1faabf72017-05-19 17:00:52 -040025
26 return ageing_time;
27}
28
29static int dsa_switch_ageing_time(struct dsa_switch *ds,
30 struct dsa_notifier_ageing_time_info *info)
31{
32 unsigned int ageing_time = info->ageing_time;
Vivien Didelot1faabf72017-05-19 17:00:52 -040033
Vladimir Oltean77b61362021-01-09 02:01:51 +020034 if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
35 return -ERANGE;
36
37 if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
38 return -ERANGE;
Vivien Didelot1faabf72017-05-19 17:00:52 -040039
40 /* Program the fastest ageing time in case of multiple bridges */
41 ageing_time = dsa_switch_fastest_ageing_time(ds, ageing_time);
42
43 if (ds->ops->set_ageing_time)
44 return ds->ops->set_ageing_time(ds, ageing_time);
45
46 return 0;
47}
48
Vladimir Olteanfac6abd2021-10-20 20:49:53 +030049static bool dsa_port_mtu_match(struct dsa_port *dp,
50 struct dsa_notifier_mtu_info *info)
Vladimir Olteanbfcb8132020-03-27 21:55:42 +020051{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +030052 if (dp->ds->index == info->sw_index && dp->index == info->port)
Vladimir Oltean88faba22021-06-21 19:42:18 +030053 return true;
Vladimir Olteanbfcb8132020-03-27 21:55:42 +020054
Vladimir Oltean88faba22021-06-21 19:42:18 +030055 /* Do not propagate to other switches in the tree if the notifier was
56 * targeted for a single switch.
57 */
58 if (info->targeted_match)
Vladimir Olteanbfcb8132020-03-27 21:55:42 +020059 return false;
60
Vladimir Olteanfac6abd2021-10-20 20:49:53 +030061 if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
Vladimir Olteanbfcb8132020-03-27 21:55:42 +020062 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{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +030070 struct dsa_port *dp;
71 int ret;
Vladimir Olteanbfcb8132020-03-27 21:55:42 +020072
73 if (!ds->ops->port_change_mtu)
74 return -EOPNOTSUPP;
75
Vladimir Olteanfac6abd2021-10-20 20:49:53 +030076 dsa_switch_for_each_port(dp, ds) {
77 if (dsa_port_mtu_match(dp, info)) {
78 ret = ds->ops->port_change_mtu(ds, dp->index,
79 info->mtu);
Vladimir Olteanbfcb8132020-03-27 21:55:42 +020080 if (ret)
81 return ret;
82 }
83 }
84
85 return 0;
86}
87
Vivien Didelot04d3a4c2017-02-03 13:20:21 -050088static int dsa_switch_bridge_join(struct dsa_switch *ds,
89 struct dsa_notifier_bridge_info *info)
90{
Vladimir Olteanf66a6a62020-05-10 19:37:41 +030091 struct dsa_switch_tree *dst = ds->dst;
Vladimir Olteane19cc132021-07-19 20:14:51 +030092 int err;
Vladimir Olteanf66a6a62020-05-10 19:37:41 +030093
Vladimir Oltean67b5fb52021-08-24 00:22:56 +030094 if (dst->index == info->tree_index && ds->index == info->sw_index) {
95 if (!ds->ops->port_bridge_join)
96 return -EOPNOTSUPP;
97
Vladimir Olteane19cc132021-07-19 20:14:51 +030098 err = ds->ops->port_bridge_join(ds, info->port, info->br);
99 if (err)
100 return err;
101 }
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500102
Vladimir Olteanf66a6a62020-05-10 19:37:41 +0300103 if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
Vladimir Olteane19cc132021-07-19 20:14:51 +0300104 ds->ops->crosschip_bridge_join) {
105 err = ds->ops->crosschip_bridge_join(ds, info->tree_index,
106 info->sw_index,
107 info->port, info->br);
108 if (err)
109 return err;
110 }
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500111
Vladimir Olteane19cc132021-07-19 20:14:51 +0300112 return dsa_tag_8021q_bridge_join(ds, info);
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500113}
114
115static int dsa_switch_bridge_leave(struct dsa_switch *ds,
116 struct dsa_notifier_bridge_info *info)
117{
Vladimir Olteanf66a6a62020-05-10 19:37:41 +0300118 struct dsa_switch_tree *dst = ds->dst;
Vladimir Oltean89153ed2021-02-13 22:43:19 +0200119 struct netlink_ext_ack extack = {0};
Vladimir Oltean58adf9d2021-08-24 00:22:58 +0300120 bool change_vlan_filtering = false;
121 bool vlan_filtering;
Vladimir Olteand0004a02021-10-20 20:49:50 +0300122 struct dsa_port *dp;
123 int err;
Vladimir Olteand371b7c2019-04-28 21:45:46 +0300124
Vladimir Olteanf66a6a62020-05-10 19:37:41 +0300125 if (dst->index == info->tree_index && ds->index == info->sw_index &&
Vladimir Olteanbcb99282021-07-13 12:40:21 +0300126 ds->ops->port_bridge_leave)
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500127 ds->ops->port_bridge_leave(ds, info->port, info->br);
128
Vladimir Olteanf66a6a62020-05-10 19:37:41 +0300129 if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
Vladimir Olteanbcb99282021-07-13 12:40:21 +0300130 ds->ops->crosschip_bridge_leave)
Vladimir Olteanf66a6a62020-05-10 19:37:41 +0300131 ds->ops->crosschip_bridge_leave(ds, info->tree_index,
132 info->sw_index, info->port,
Vivien Didelot40ef2c92017-03-30 17:37:14 -0400133 info->br);
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500134
Vladimir Oltean58adf9d2021-08-24 00:22:58 +0300135 if (ds->needs_standalone_vlan_filtering && !br_vlan_enabled(info->br)) {
136 change_vlan_filtering = true;
137 vlan_filtering = true;
138 } else if (!ds->needs_standalone_vlan_filtering &&
139 br_vlan_enabled(info->br)) {
140 change_vlan_filtering = true;
141 vlan_filtering = false;
142 }
143
Vladimir Olteand371b7c2019-04-28 21:45:46 +0300144 /* If the bridge was vlan_filtering, the bridge core doesn't trigger an
145 * event for changing vlan_filtering setting upon slave ports leaving
146 * it. That is a good thing, because that lets us handle it and also
147 * handle the case where the switch's vlan_filtering setting is global
148 * (not per port). When that happens, the correct moment to trigger the
Vladimir Oltean479dc492021-03-24 11:56:39 +0200149 * vlan_filtering callback is only when the last port leaves the last
150 * VLAN-aware bridge.
Vladimir Olteand371b7c2019-04-28 21:45:46 +0300151 */
Vladimir Oltean58adf9d2021-08-24 00:22:58 +0300152 if (change_vlan_filtering && ds->vlan_filtering_is_global) {
Vladimir Olteand0004a02021-10-20 20:49:50 +0300153 dsa_switch_for_each_port(dp, ds) {
Vladimir Oltean479dc492021-03-24 11:56:39 +0200154 struct net_device *bridge_dev;
155
Vladimir Olteand0004a02021-10-20 20:49:50 +0300156 bridge_dev = dp->bridge_dev;
Vladimir Oltean479dc492021-03-24 11:56:39 +0200157
158 if (bridge_dev && br_vlan_enabled(bridge_dev)) {
Vladimir Oltean58adf9d2021-08-24 00:22:58 +0300159 change_vlan_filtering = false;
Vladimir Olteand371b7c2019-04-28 21:45:46 +0300160 break;
161 }
162 }
163 }
Vladimir Oltean58adf9d2021-08-24 00:22:58 +0300164
165 if (change_vlan_filtering) {
Vladimir Oltean2e554a72020-10-03 01:06:46 +0300166 err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
Vladimir Oltean58adf9d2021-08-24 00:22:58 +0300167 vlan_filtering, &extack);
Vladimir Oltean89153ed2021-02-13 22:43:19 +0200168 if (extack._msg)
169 dev_err(ds->dev, "port %d: %s\n", info->port,
170 extack._msg);
Alvin Å ipraga43a4b4d2021-10-12 13:27:31 +0200171 if (err && err != -EOPNOTSUPP)
Vladimir Olteand371b7c2019-04-28 21:45:46 +0300172 return err;
173 }
Vladimir Olteane19cc132021-07-19 20:14:51 +0300174
175 return dsa_tag_8021q_bridge_leave(ds, info);
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500176}
177
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300178/* Matches for all upstream-facing ports (the CPU port and all upstream-facing
179 * DSA links) that sit between the targeted port on which the notifier was
180 * emitted and its dedicated CPU port.
181 */
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300182static bool dsa_port_host_address_match(struct dsa_port *dp,
183 int info_sw_index, int info_port)
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300184{
185 struct dsa_port *targeted_dp, *cpu_dp;
186 struct dsa_switch *targeted_ds;
187
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300188 targeted_ds = dsa_switch_find(dp->ds->dst->index, info_sw_index);
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300189 targeted_dp = dsa_to_port(targeted_ds, info_port);
190 cpu_dp = targeted_dp->cpu_dp;
191
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300192 if (dsa_switch_is_upstream_of(dp->ds, targeted_ds))
193 return dp->index == dsa_towards_port(dp->ds, cpu_dp->ds->index,
194 cpu_dp->index);
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300195
196 return false;
197}
198
Vladimir Oltean161ca592021-06-29 17:06:50 +0300199static struct dsa_mac_addr *dsa_mac_addr_find(struct list_head *addr_list,
200 const unsigned char *addr,
201 u16 vid)
202{
203 struct dsa_mac_addr *a;
204
205 list_for_each_entry(a, addr_list, list)
206 if (ether_addr_equal(a->addr, addr) && a->vid == vid)
207 return a;
208
209 return NULL;
210}
211
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300212static int dsa_port_do_mdb_add(struct dsa_port *dp,
213 const struct switchdev_obj_port_mdb *mdb)
Vladimir Oltean161ca592021-06-29 17:06:50 +0300214{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300215 struct dsa_switch *ds = dp->ds;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300216 struct dsa_mac_addr *a;
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300217 int port = dp->index;
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300218 int err = 0;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300219
220 /* No need to bother with refcounting for user ports */
221 if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
222 return ds->ops->port_mdb_add(ds, port, mdb);
223
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300224 mutex_lock(&dp->addr_lists_lock);
225
Vladimir Oltean161ca592021-06-29 17:06:50 +0300226 a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid);
227 if (a) {
228 refcount_inc(&a->refcount);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300229 goto out;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300230 }
231
232 a = kzalloc(sizeof(*a), GFP_KERNEL);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300233 if (!a) {
234 err = -ENOMEM;
235 goto out;
236 }
Vladimir Oltean161ca592021-06-29 17:06:50 +0300237
238 err = ds->ops->port_mdb_add(ds, port, mdb);
239 if (err) {
240 kfree(a);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300241 goto out;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300242 }
243
244 ether_addr_copy(a->addr, mdb->addr);
245 a->vid = mdb->vid;
246 refcount_set(&a->refcount, 1);
247 list_add_tail(&a->list, &dp->mdbs);
248
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300249out:
250 mutex_unlock(&dp->addr_lists_lock);
251
252 return err;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300253}
254
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300255static int dsa_port_do_mdb_del(struct dsa_port *dp,
256 const struct switchdev_obj_port_mdb *mdb)
Vladimir Oltean161ca592021-06-29 17:06:50 +0300257{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300258 struct dsa_switch *ds = dp->ds;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300259 struct dsa_mac_addr *a;
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300260 int port = dp->index;
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300261 int err = 0;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300262
263 /* No need to bother with refcounting for user ports */
264 if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
265 return ds->ops->port_mdb_del(ds, port, mdb);
266
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300267 mutex_lock(&dp->addr_lists_lock);
268
Vladimir Oltean161ca592021-06-29 17:06:50 +0300269 a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300270 if (!a) {
271 err = -ENOENT;
272 goto out;
273 }
Vladimir Oltean161ca592021-06-29 17:06:50 +0300274
275 if (!refcount_dec_and_test(&a->refcount))
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300276 goto out;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300277
278 err = ds->ops->port_mdb_del(ds, port, mdb);
279 if (err) {
Vladimir Oltean232deb32021-10-24 20:17:48 +0300280 refcount_set(&a->refcount, 1);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300281 goto out;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300282 }
283
284 list_del(&a->list);
285 kfree(a);
286
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300287out:
288 mutex_unlock(&dp->addr_lists_lock);
289
290 return err;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300291}
292
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300293static int dsa_port_do_fdb_add(struct dsa_port *dp, const unsigned char *addr,
294 u16 vid)
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300295{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300296 struct dsa_switch *ds = dp->ds;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300297 struct dsa_mac_addr *a;
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300298 int port = dp->index;
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300299 int err = 0;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300300
301 /* No need to bother with refcounting for user ports */
302 if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
303 return ds->ops->port_fdb_add(ds, port, addr, vid);
304
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300305 mutex_lock(&dp->addr_lists_lock);
306
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300307 a = dsa_mac_addr_find(&dp->fdbs, addr, vid);
308 if (a) {
309 refcount_inc(&a->refcount);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300310 goto out;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300311 }
312
313 a = kzalloc(sizeof(*a), GFP_KERNEL);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300314 if (!a) {
315 err = -ENOMEM;
316 goto out;
317 }
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300318
319 err = ds->ops->port_fdb_add(ds, port, addr, vid);
320 if (err) {
321 kfree(a);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300322 goto out;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300323 }
324
325 ether_addr_copy(a->addr, addr);
326 a->vid = vid;
327 refcount_set(&a->refcount, 1);
328 list_add_tail(&a->list, &dp->fdbs);
329
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300330out:
331 mutex_unlock(&dp->addr_lists_lock);
332
333 return err;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300334}
335
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300336static int dsa_port_do_fdb_del(struct dsa_port *dp, const unsigned char *addr,
337 u16 vid)
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300338{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300339 struct dsa_switch *ds = dp->ds;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300340 struct dsa_mac_addr *a;
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300341 int port = dp->index;
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300342 int err = 0;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300343
344 /* No need to bother with refcounting for user ports */
345 if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
346 return ds->ops->port_fdb_del(ds, port, addr, vid);
347
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300348 mutex_lock(&dp->addr_lists_lock);
349
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300350 a = dsa_mac_addr_find(&dp->fdbs, addr, vid);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300351 if (!a) {
352 err = -ENOENT;
353 goto out;
354 }
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300355
356 if (!refcount_dec_and_test(&a->refcount))
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300357 goto out;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300358
359 err = ds->ops->port_fdb_del(ds, port, addr, vid);
360 if (err) {
Vladimir Oltean232deb32021-10-24 20:17:48 +0300361 refcount_set(&a->refcount, 1);
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300362 goto out;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300363 }
364
365 list_del(&a->list);
366 kfree(a);
367
Vladimir Oltean338a3a472021-10-24 20:17:54 +0300368out:
369 mutex_unlock(&dp->addr_lists_lock);
370
371 return err;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300372}
373
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300374static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
375 struct dsa_notifier_fdb_info *info)
376{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300377 struct dsa_port *dp;
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300378 int err = 0;
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300379
380 if (!ds->ops->port_fdb_add)
381 return -EOPNOTSUPP;
382
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300383 dsa_switch_for_each_port(dp, ds) {
384 if (dsa_port_host_address_match(dp, info->sw_index,
385 info->port)) {
386 err = dsa_port_do_fdb_add(dp, info->addr, info->vid);
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300387 if (err)
388 break;
389 }
390 }
391
392 return err;
393}
394
395static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
396 struct dsa_notifier_fdb_info *info)
397{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300398 struct dsa_port *dp;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300399 int err = 0;
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300400
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300401 if (!ds->ops->port_fdb_del)
402 return -EOPNOTSUPP;
403
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300404 dsa_switch_for_each_port(dp, ds) {
405 if (dsa_port_host_address_match(dp, info->sw_index,
406 info->port)) {
407 err = dsa_port_do_fdb_del(dp, info->addr, info->vid);
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300408 if (err)
409 break;
410 }
411 }
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300412
Vladimir Oltean3f6e32f2021-06-29 17:06:52 +0300413 return err;
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300414}
415
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400416static int dsa_switch_fdb_add(struct dsa_switch *ds,
417 struct dsa_notifier_fdb_info *info)
418{
Vivien Didelot31692412017-11-30 12:56:43 -0500419 int port = dsa_towards_port(ds, info->sw_index, info->port);
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300420 struct dsa_port *dp = dsa_to_port(ds, port);
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400421
Arkadi Sharshevsky1b6dd552017-08-06 16:15:40 +0300422 if (!ds->ops->port_fdb_add)
423 return -EOPNOTSUPP;
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400424
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300425 return dsa_port_do_fdb_add(dp, info->addr, info->vid);
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400426}
427
428static int dsa_switch_fdb_del(struct dsa_switch *ds,
429 struct dsa_notifier_fdb_info *info)
430{
Vivien Didelot31692412017-11-30 12:56:43 -0500431 int port = dsa_towards_port(ds, info->sw_index, info->port);
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300432 struct dsa_port *dp = dsa_to_port(ds, port);
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400433
434 if (!ds->ops->port_fdb_del)
435 return -EOPNOTSUPP;
436
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300437 return dsa_port_do_fdb_del(dp, info->addr, info->vid);
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400438}
439
George McCollister18596f52021-02-09 19:02:12 -0600440static int dsa_switch_hsr_join(struct dsa_switch *ds,
441 struct dsa_notifier_hsr_info *info)
442{
443 if (ds->index == info->sw_index && ds->ops->port_hsr_join)
444 return ds->ops->port_hsr_join(ds, info->port, info->hsr);
445
446 return -EOPNOTSUPP;
447}
448
449static int dsa_switch_hsr_leave(struct dsa_switch *ds,
450 struct dsa_notifier_hsr_info *info)
451{
452 if (ds->index == info->sw_index && ds->ops->port_hsr_leave)
453 return ds->ops->port_hsr_leave(ds, info->port, info->hsr);
454
455 return -EOPNOTSUPP;
456}
457
Tobias Waldekranz058102a2021-01-13 09:42:53 +0100458static int dsa_switch_lag_change(struct dsa_switch *ds,
459 struct dsa_notifier_lag_info *info)
460{
461 if (ds->index == info->sw_index && ds->ops->port_lag_change)
462 return ds->ops->port_lag_change(ds, info->port);
463
464 if (ds->index != info->sw_index && ds->ops->crosschip_lag_change)
465 return ds->ops->crosschip_lag_change(ds, info->sw_index,
466 info->port);
467
468 return 0;
469}
470
471static int dsa_switch_lag_join(struct dsa_switch *ds,
472 struct dsa_notifier_lag_info *info)
473{
474 if (ds->index == info->sw_index && ds->ops->port_lag_join)
475 return ds->ops->port_lag_join(ds, info->port, info->lag,
476 info->info);
477
478 if (ds->index != info->sw_index && ds->ops->crosschip_lag_join)
479 return ds->ops->crosschip_lag_join(ds, info->sw_index,
480 info->port, info->lag,
481 info->info);
482
Vladimir Olteanb71d0982021-06-29 23:32:15 +0300483 return -EOPNOTSUPP;
Tobias Waldekranz058102a2021-01-13 09:42:53 +0100484}
485
486static int dsa_switch_lag_leave(struct dsa_switch *ds,
487 struct dsa_notifier_lag_info *info)
488{
489 if (ds->index == info->sw_index && ds->ops->port_lag_leave)
490 return ds->ops->port_lag_leave(ds, info->port, info->lag);
491
492 if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave)
493 return ds->ops->crosschip_lag_leave(ds, info->sw_index,
494 info->port, info->lag);
495
Vladimir Olteanb71d0982021-06-29 23:32:15 +0300496 return -EOPNOTSUPP;
Tobias Waldekranz058102a2021-01-13 09:42:53 +0100497}
498
Vladimir Olteanffb68fc2021-01-09 02:01:48 +0200499static int dsa_switch_mdb_add(struct dsa_switch *ds,
500 struct dsa_notifier_mdb_info *info)
Vivien Didelote6db98d2017-11-30 11:24:00 -0500501{
Vladimir Olteanabd49532021-06-21 19:42:16 +0300502 int port = dsa_towards_port(ds, info->sw_index, info->port);
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300503 struct dsa_port *dp = dsa_to_port(ds, port);
Vivien Didelote6db98d2017-11-30 11:24:00 -0500504
Vladimir Olteana52b2da2021-01-09 02:01:52 +0200505 if (!ds->ops->port_mdb_add)
Vivien Didelote6db98d2017-11-30 11:24:00 -0500506 return -EOPNOTSUPP;
507
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300508 return dsa_port_do_mdb_add(dp, info->mdb);
Vivien Didelot8ae5bcd2017-05-19 17:00:54 -0400509}
510
511static int dsa_switch_mdb_del(struct dsa_switch *ds,
512 struct dsa_notifier_mdb_info *info)
513{
Vladimir Oltean161ca592021-06-29 17:06:50 +0300514 int port = dsa_towards_port(ds, info->sw_index, info->port);
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300515 struct dsa_port *dp = dsa_to_port(ds, port);
Vladimir Oltean161ca592021-06-29 17:06:50 +0300516
Vivien Didelot8ae5bcd2017-05-19 17:00:54 -0400517 if (!ds->ops->port_mdb_del)
518 return -EOPNOTSUPP;
519
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300520 return dsa_port_do_mdb_del(dp, info->mdb);
Vivien Didelot8ae5bcd2017-05-19 17:00:54 -0400521}
522
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300523static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
524 struct dsa_notifier_mdb_info *info)
525{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300526 struct dsa_port *dp;
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300527 int err = 0;
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300528
529 if (!ds->ops->port_mdb_add)
530 return -EOPNOTSUPP;
531
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300532 dsa_switch_for_each_port(dp, ds) {
533 if (dsa_port_host_address_match(dp, info->sw_index,
534 info->port)) {
535 err = dsa_port_do_mdb_add(dp, info->mdb);
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300536 if (err)
537 break;
538 }
539 }
540
541 return err;
542}
543
544static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
545 struct dsa_notifier_mdb_info *info)
546{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300547 struct dsa_port *dp;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300548 int err = 0;
Vladimir Oltean161ca592021-06-29 17:06:50 +0300549
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300550 if (!ds->ops->port_mdb_del)
551 return -EOPNOTSUPP;
552
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300553 dsa_switch_for_each_port(dp, ds) {
554 if (dsa_port_host_address_match(dp, info->sw_index,
555 info->port)) {
556 err = dsa_port_do_mdb_del(dp, info->mdb);
Vladimir Oltean161ca592021-06-29 17:06:50 +0300557 if (err)
558 break;
559 }
560 }
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300561
Vladimir Oltean161ca592021-06-29 17:06:50 +0300562 return err;
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300563}
564
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300565static bool dsa_port_vlan_match(struct dsa_port *dp,
566 struct dsa_notifier_vlan_info *info)
Vivien Didelote65d45c2019-08-25 13:25:15 -0400567{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300568 if (dp->ds->index == info->sw_index && dp->index == info->port)
Vivien Didelote65d45c2019-08-25 13:25:15 -0400569 return true;
570
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300571 if (dsa_port_is_dsa(dp))
Vivien Didelote65d45c2019-08-25 13:25:15 -0400572 return true;
573
574 return false;
575}
576
Vladimir Olteanffb68fc2021-01-09 02:01:48 +0200577static int dsa_switch_vlan_add(struct dsa_switch *ds,
578 struct dsa_notifier_vlan_info *info)
Vivien Didelot9c428c52017-11-30 11:23:59 -0500579{
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300580 struct dsa_port *dp;
581 int err;
Vivien Didelot9c428c52017-11-30 11:23:59 -0500582
Vladimir Oltean1958d582021-01-09 02:01:53 +0200583 if (!ds->ops->port_vlan_add)
Vivien Didelot9c428c52017-11-30 11:23:59 -0500584 return -EOPNOTSUPP;
585
Vladimir Olteanfac6abd2021-10-20 20:49:53 +0300586 dsa_switch_for_each_port(dp, ds) {
587 if (dsa_port_vlan_match(dp, info)) {
588 err = ds->ops->port_vlan_add(ds, dp->index, info->vlan,
Vladimir Oltean31046a52021-02-13 22:43:18 +0200589 info->extack);
Vivien Didelote65d45c2019-08-25 13:25:15 -0400590 if (err)
591 return err;
592 }
Vivien Didelot9c428c52017-11-30 11:23:59 -0500593 }
594
Vivien Didelotd0c627b2017-05-19 17:00:55 -0400595 return 0;
596}
597
598static int dsa_switch_vlan_del(struct dsa_switch *ds,
599 struct dsa_notifier_vlan_info *info)
600{
Vivien Didelotd0c627b2017-05-19 17:00:55 -0400601 if (!ds->ops->port_vlan_del)
602 return -EOPNOTSUPP;
603
Vivien Didelot1ca4aa92017-06-07 18:12:14 -0400604 if (ds->index == info->sw_index)
Vivien Didelote65d45c2019-08-25 13:25:15 -0400605 return ds->ops->port_vlan_del(ds, info->port, info->vlan);
Vivien Didelot1ca4aa92017-06-07 18:12:14 -0400606
Vivien Didelot7e1741b2019-08-25 13:25:19 -0400607 /* Do not deprogram the DSA links as they may be used as conduit
608 * for other VLAN members in the fabric.
609 */
Vivien Didelot1ca4aa92017-06-07 18:12:14 -0400610 return 0;
Vivien Didelotd0c627b2017-05-19 17:00:55 -0400611}
612
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200613static int dsa_switch_change_tag_proto(struct dsa_switch *ds,
614 struct dsa_notifier_tag_proto_info *info)
615{
616 const struct dsa_device_ops *tag_ops = info->tag_ops;
Vladimir Olteand0004a02021-10-20 20:49:50 +0300617 struct dsa_port *dp, *cpu_dp;
618 int err;
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200619
620 if (!ds->ops->change_tag_protocol)
621 return -EOPNOTSUPP;
622
623 ASSERT_RTNL();
624
Vladimir Olteand0004a02021-10-20 20:49:50 +0300625 dsa_switch_for_each_cpu_port(cpu_dp, ds) {
626 err = ds->ops->change_tag_protocol(ds, cpu_dp->index,
627 tag_ops->proto);
Tobias Waldekranz21e0b502021-04-20 20:53:09 +0200628 if (err)
629 return err;
630
Vladimir Olteand0004a02021-10-20 20:49:50 +0300631 dsa_port_set_tag_protocol(cpu_dp, tag_ops);
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200632 }
633
634 /* Now that changing the tag protocol can no longer fail, let's update
635 * the remaining bits which are "duplicated for faster access", and the
636 * bits that depend on the tagger, such as the MTU.
637 */
Vladimir Olteand0004a02021-10-20 20:49:50 +0300638 dsa_switch_for_each_user_port(dp, ds) {
639 struct net_device *slave = dp->slave;
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200640
Vladimir Olteand0004a02021-10-20 20:49:50 +0300641 dsa_slave_setup_tagger(slave);
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200642
Vladimir Olteand0004a02021-10-20 20:49:50 +0300643 /* rtnl_mutex is held in dsa_tree_change_tag_proto */
644 dsa_slave_change_mtu(slave, slave->mtu);
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200645 }
646
647 return 0;
648}
649
Horatiu Vulturc595c432021-02-16 22:42:04 +0100650static int dsa_switch_mrp_add(struct dsa_switch *ds,
651 struct dsa_notifier_mrp_info *info)
652{
Horatiu Vulturc595c432021-02-16 22:42:04 +0100653 if (!ds->ops->port_mrp_add)
654 return -EOPNOTSUPP;
655
Vladimir Olteanf9bcdc362021-06-21 19:42:19 +0300656 if (ds->index == info->sw_index)
657 return ds->ops->port_mrp_add(ds, info->port, info->mrp);
Horatiu Vulturc595c432021-02-16 22:42:04 +0100658
Vladimir Olteanf9bcdc362021-06-21 19:42:19 +0300659 return 0;
Horatiu Vulturc595c432021-02-16 22:42:04 +0100660}
661
662static int dsa_switch_mrp_del(struct dsa_switch *ds,
663 struct dsa_notifier_mrp_info *info)
664{
665 if (!ds->ops->port_mrp_del)
666 return -EOPNOTSUPP;
667
668 if (ds->index == info->sw_index)
669 return ds->ops->port_mrp_del(ds, info->port, info->mrp);
670
671 return 0;
672}
673
Horatiu Vulturc595c432021-02-16 22:42:04 +0100674static int
675dsa_switch_mrp_add_ring_role(struct dsa_switch *ds,
676 struct dsa_notifier_mrp_ring_role_info *info)
677{
Horatiu Vulturc595c432021-02-16 22:42:04 +0100678 if (!ds->ops->port_mrp_add)
679 return -EOPNOTSUPP;
680
Vladimir Olteanf9bcdc362021-06-21 19:42:19 +0300681 if (ds->index == info->sw_index)
682 return ds->ops->port_mrp_add_ring_role(ds, info->port,
683 info->mrp);
Horatiu Vulturc595c432021-02-16 22:42:04 +0100684
Vladimir Olteanf9bcdc362021-06-21 19:42:19 +0300685 return 0;
Horatiu Vulturc595c432021-02-16 22:42:04 +0100686}
687
688static int
689dsa_switch_mrp_del_ring_role(struct dsa_switch *ds,
690 struct dsa_notifier_mrp_ring_role_info *info)
691{
692 if (!ds->ops->port_mrp_del)
693 return -EOPNOTSUPP;
694
695 if (ds->index == info->sw_index)
696 return ds->ops->port_mrp_del_ring_role(ds, info->port,
697 info->mrp);
698
699 return 0;
700}
701
Vivien Didelotf515f192017-02-03 13:20:20 -0500702static int dsa_switch_event(struct notifier_block *nb,
703 unsigned long event, void *info)
704{
705 struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb);
706 int err;
707
708 switch (event) {
Vivien Didelot1faabf72017-05-19 17:00:52 -0400709 case DSA_NOTIFIER_AGEING_TIME:
710 err = dsa_switch_ageing_time(ds, info);
711 break;
Vivien Didelot04d3a4c2017-02-03 13:20:21 -0500712 case DSA_NOTIFIER_BRIDGE_JOIN:
713 err = dsa_switch_bridge_join(ds, info);
714 break;
715 case DSA_NOTIFIER_BRIDGE_LEAVE:
716 err = dsa_switch_bridge_leave(ds, info);
717 break;
Vivien Didelot685fb6a2017-05-19 17:00:53 -0400718 case DSA_NOTIFIER_FDB_ADD:
719 err = dsa_switch_fdb_add(ds, info);
720 break;
721 case DSA_NOTIFIER_FDB_DEL:
722 err = dsa_switch_fdb_del(ds, info);
723 break;
Vladimir Oltean3dc80af2021-06-29 17:06:51 +0300724 case DSA_NOTIFIER_HOST_FDB_ADD:
725 err = dsa_switch_host_fdb_add(ds, info);
726 break;
727 case DSA_NOTIFIER_HOST_FDB_DEL:
728 err = dsa_switch_host_fdb_del(ds, info);
729 break;
George McCollister18596f52021-02-09 19:02:12 -0600730 case DSA_NOTIFIER_HSR_JOIN:
731 err = dsa_switch_hsr_join(ds, info);
732 break;
733 case DSA_NOTIFIER_HSR_LEAVE:
734 err = dsa_switch_hsr_leave(ds, info);
735 break;
Tobias Waldekranz058102a2021-01-13 09:42:53 +0100736 case DSA_NOTIFIER_LAG_CHANGE:
737 err = dsa_switch_lag_change(ds, info);
738 break;
739 case DSA_NOTIFIER_LAG_JOIN:
740 err = dsa_switch_lag_join(ds, info);
741 break;
742 case DSA_NOTIFIER_LAG_LEAVE:
743 err = dsa_switch_lag_leave(ds, info);
744 break;
Vivien Didelot8ae5bcd2017-05-19 17:00:54 -0400745 case DSA_NOTIFIER_MDB_ADD:
746 err = dsa_switch_mdb_add(ds, info);
747 break;
748 case DSA_NOTIFIER_MDB_DEL:
749 err = dsa_switch_mdb_del(ds, info);
750 break;
Vladimir Olteanb8e997c2021-06-29 17:06:49 +0300751 case DSA_NOTIFIER_HOST_MDB_ADD:
752 err = dsa_switch_host_mdb_add(ds, info);
753 break;
754 case DSA_NOTIFIER_HOST_MDB_DEL:
755 err = dsa_switch_host_mdb_del(ds, info);
756 break;
Vivien Didelotd0c627b2017-05-19 17:00:55 -0400757 case DSA_NOTIFIER_VLAN_ADD:
758 err = dsa_switch_vlan_add(ds, info);
759 break;
760 case DSA_NOTIFIER_VLAN_DEL:
761 err = dsa_switch_vlan_del(ds, info);
762 break;
Vladimir Olteanbfcb8132020-03-27 21:55:42 +0200763 case DSA_NOTIFIER_MTU:
764 err = dsa_switch_mtu(ds, info);
765 break;
Vladimir Oltean53da0eb2021-01-29 03:00:06 +0200766 case DSA_NOTIFIER_TAG_PROTO:
767 err = dsa_switch_change_tag_proto(ds, info);
768 break;
Horatiu Vulturc595c432021-02-16 22:42:04 +0100769 case DSA_NOTIFIER_MRP_ADD:
770 err = dsa_switch_mrp_add(ds, info);
771 break;
772 case DSA_NOTIFIER_MRP_DEL:
773 err = dsa_switch_mrp_del(ds, info);
774 break;
775 case DSA_NOTIFIER_MRP_ADD_RING_ROLE:
776 err = dsa_switch_mrp_add_ring_role(ds, info);
777 break;
778 case DSA_NOTIFIER_MRP_DEL_RING_ROLE:
779 err = dsa_switch_mrp_del_ring_role(ds, info);
780 break;
Vladimir Olteanc64b9c02021-07-19 20:14:52 +0300781 case DSA_NOTIFIER_TAG_8021Q_VLAN_ADD:
782 err = dsa_switch_tag_8021q_vlan_add(ds, info);
783 break;
784 case DSA_NOTIFIER_TAG_8021Q_VLAN_DEL:
785 err = dsa_switch_tag_8021q_vlan_del(ds, info);
786 break;
Vivien Didelotf515f192017-02-03 13:20:20 -0500787 default:
788 err = -EOPNOTSUPP;
789 break;
790 }
791
Vivien Didelotf515f192017-02-03 13:20:20 -0500792 if (err)
793 dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n",
794 event, err);
795
796 return notifier_from_errno(err);
797}
798
799int dsa_switch_register_notifier(struct dsa_switch *ds)
800{
801 ds->nb.notifier_call = dsa_switch_event;
802
803 return raw_notifier_chain_register(&ds->dst->nh, &ds->nb);
804}
805
806void dsa_switch_unregister_notifier(struct dsa_switch *ds)
807{
808 int err;
809
810 err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb);
811 if (err)
812 dev_err(ds->dev, "failed to unregister notifier (%d)\n", err);
813}