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