1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* |
3 | * include/net/switchdev.h - Switch device API |
4 | * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us> |
5 | * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com> |
6 | */ |
7 | #ifndef _LINUX_SWITCHDEV_H_ |
8 | #define _LINUX_SWITCHDEV_H_ |
9 | |
10 | #include <linux/netdevice.h> |
11 | #include <linux/notifier.h> |
12 | #include <linux/list.h> |
13 | #include <net/ip_fib.h> |
14 | |
15 | #define SWITCHDEV_F_NO_RECURSE BIT(0) |
16 | #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) |
17 | #define SWITCHDEV_F_DEFER BIT(2) |
18 | |
19 | enum switchdev_attr_id { |
20 | SWITCHDEV_ATTR_ID_UNDEFINED, |
21 | SWITCHDEV_ATTR_ID_PORT_STP_STATE, |
22 | SWITCHDEV_ATTR_ID_PORT_MST_STATE, |
23 | SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, |
24 | SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, |
25 | SWITCHDEV_ATTR_ID_PORT_MROUTER, |
26 | SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME, |
27 | SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, |
28 | SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL, |
29 | SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, |
30 | SWITCHDEV_ATTR_ID_BRIDGE_MROUTER, |
31 | SWITCHDEV_ATTR_ID_BRIDGE_MST, |
32 | SWITCHDEV_ATTR_ID_MRP_PORT_ROLE, |
33 | SWITCHDEV_ATTR_ID_VLAN_MSTI, |
34 | }; |
35 | |
36 | struct switchdev_mst_state { |
37 | u16 msti; |
38 | u8 state; |
39 | }; |
40 | |
41 | struct switchdev_brport_flags { |
42 | unsigned long val; |
43 | unsigned long mask; |
44 | }; |
45 | |
46 | struct switchdev_vlan_msti { |
47 | u16 vid; |
48 | u16 msti; |
49 | }; |
50 | |
51 | struct switchdev_attr { |
52 | struct net_device *orig_dev; |
53 | enum switchdev_attr_id id; |
54 | u32 flags; |
55 | void *complete_priv; |
56 | void (*complete)(struct net_device *dev, int err, void *priv); |
57 | union { |
58 | u8 stp_state; /* PORT_STP_STATE */ |
59 | struct switchdev_mst_state mst_state; /* PORT_MST_STATE */ |
60 | struct switchdev_brport_flags brport_flags; /* PORT_BRIDGE_FLAGS */ |
61 | bool mrouter; /* PORT_MROUTER */ |
62 | clock_t ageing_time; /* BRIDGE_AGEING_TIME */ |
63 | bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ |
64 | u16 vlan_protocol; /* BRIDGE_VLAN_PROTOCOL */ |
65 | bool mst; /* BRIDGE_MST */ |
66 | bool mc_disabled; /* MC_DISABLED */ |
67 | u8 mrp_port_role; /* MRP_PORT_ROLE */ |
68 | struct switchdev_vlan_msti vlan_msti; /* VLAN_MSTI */ |
69 | } u; |
70 | }; |
71 | |
72 | enum switchdev_obj_id { |
73 | SWITCHDEV_OBJ_ID_UNDEFINED, |
74 | SWITCHDEV_OBJ_ID_PORT_VLAN, |
75 | SWITCHDEV_OBJ_ID_PORT_MDB, |
76 | SWITCHDEV_OBJ_ID_HOST_MDB, |
77 | SWITCHDEV_OBJ_ID_MRP, |
78 | SWITCHDEV_OBJ_ID_RING_TEST_MRP, |
79 | SWITCHDEV_OBJ_ID_RING_ROLE_MRP, |
80 | SWITCHDEV_OBJ_ID_RING_STATE_MRP, |
81 | SWITCHDEV_OBJ_ID_IN_TEST_MRP, |
82 | SWITCHDEV_OBJ_ID_IN_ROLE_MRP, |
83 | SWITCHDEV_OBJ_ID_IN_STATE_MRP, |
84 | }; |
85 | |
86 | struct switchdev_obj { |
87 | struct list_head list; |
88 | struct net_device *orig_dev; |
89 | enum switchdev_obj_id id; |
90 | u32 flags; |
91 | void *complete_priv; |
92 | void (*complete)(struct net_device *dev, int err, void *priv); |
93 | }; |
94 | |
95 | /* SWITCHDEV_OBJ_ID_PORT_VLAN */ |
96 | struct switchdev_obj_port_vlan { |
97 | struct switchdev_obj obj; |
98 | u16 flags; |
99 | u16 vid; |
100 | /* If set, the notifier signifies a change of one of the following |
101 | * flags for a VLAN that already exists: |
102 | * - BRIDGE_VLAN_INFO_PVID |
103 | * - BRIDGE_VLAN_INFO_UNTAGGED |
104 | * Entries with BRIDGE_VLAN_INFO_BRENTRY unset are not notified at all. |
105 | */ |
106 | bool changed; |
107 | }; |
108 | |
109 | #define SWITCHDEV_OBJ_PORT_VLAN(OBJ) \ |
110 | container_of((OBJ), struct switchdev_obj_port_vlan, obj) |
111 | |
112 | /* SWITCHDEV_OBJ_ID_PORT_MDB */ |
113 | struct switchdev_obj_port_mdb { |
114 | struct switchdev_obj obj; |
115 | unsigned char addr[ETH_ALEN]; |
116 | u16 vid; |
117 | }; |
118 | |
119 | #define SWITCHDEV_OBJ_PORT_MDB(OBJ) \ |
120 | container_of((OBJ), struct switchdev_obj_port_mdb, obj) |
121 | |
122 | |
123 | /* SWITCHDEV_OBJ_ID_MRP */ |
124 | struct switchdev_obj_mrp { |
125 | struct switchdev_obj obj; |
126 | struct net_device *p_port; |
127 | struct net_device *s_port; |
128 | u32 ring_id; |
129 | u16 prio; |
130 | }; |
131 | |
132 | #define SWITCHDEV_OBJ_MRP(OBJ) \ |
133 | container_of((OBJ), struct switchdev_obj_mrp, obj) |
134 | |
135 | /* SWITCHDEV_OBJ_ID_RING_TEST_MRP */ |
136 | struct switchdev_obj_ring_test_mrp { |
137 | struct switchdev_obj obj; |
138 | /* The value is in us and a value of 0 represents to stop */ |
139 | u32 interval; |
140 | u8 max_miss; |
141 | u32 ring_id; |
142 | u32 period; |
143 | bool monitor; |
144 | }; |
145 | |
146 | #define SWITCHDEV_OBJ_RING_TEST_MRP(OBJ) \ |
147 | container_of((OBJ), struct switchdev_obj_ring_test_mrp, obj) |
148 | |
149 | /* SWICHDEV_OBJ_ID_RING_ROLE_MRP */ |
150 | struct switchdev_obj_ring_role_mrp { |
151 | struct switchdev_obj obj; |
152 | u8 ring_role; |
153 | u32 ring_id; |
154 | u8 sw_backup; |
155 | }; |
156 | |
157 | #define SWITCHDEV_OBJ_RING_ROLE_MRP(OBJ) \ |
158 | container_of((OBJ), struct switchdev_obj_ring_role_mrp, obj) |
159 | |
160 | struct switchdev_obj_ring_state_mrp { |
161 | struct switchdev_obj obj; |
162 | u8 ring_state; |
163 | u32 ring_id; |
164 | }; |
165 | |
166 | #define SWITCHDEV_OBJ_RING_STATE_MRP(OBJ) \ |
167 | container_of((OBJ), struct switchdev_obj_ring_state_mrp, obj) |
168 | |
169 | /* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ |
170 | struct switchdev_obj_in_test_mrp { |
171 | struct switchdev_obj obj; |
172 | /* The value is in us and a value of 0 represents to stop */ |
173 | u32 interval; |
174 | u32 in_id; |
175 | u32 period; |
176 | u8 max_miss; |
177 | }; |
178 | |
179 | #define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ |
180 | container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) |
181 | |
182 | /* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ |
183 | struct switchdev_obj_in_role_mrp { |
184 | struct switchdev_obj obj; |
185 | struct net_device *i_port; |
186 | u32 ring_id; |
187 | u16 in_id; |
188 | u8 in_role; |
189 | u8 sw_backup; |
190 | }; |
191 | |
192 | #define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ |
193 | container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) |
194 | |
195 | struct switchdev_obj_in_state_mrp { |
196 | struct switchdev_obj obj; |
197 | u32 in_id; |
198 | u8 in_state; |
199 | }; |
200 | |
201 | #define SWITCHDEV_OBJ_IN_STATE_MRP(OBJ) \ |
202 | container_of((OBJ), struct switchdev_obj_in_state_mrp, obj) |
203 | |
204 | struct switchdev_brport { |
205 | struct net_device *dev; |
206 | const void *ctx; |
207 | struct notifier_block *atomic_nb; |
208 | struct notifier_block *blocking_nb; |
209 | bool tx_fwd_offload; |
210 | }; |
211 | |
212 | enum switchdev_notifier_type { |
213 | SWITCHDEV_FDB_ADD_TO_BRIDGE = 1, |
214 | SWITCHDEV_FDB_DEL_TO_BRIDGE, |
215 | SWITCHDEV_FDB_ADD_TO_DEVICE, |
216 | SWITCHDEV_FDB_DEL_TO_DEVICE, |
217 | SWITCHDEV_FDB_OFFLOADED, |
218 | SWITCHDEV_FDB_FLUSH_TO_BRIDGE, |
219 | |
220 | SWITCHDEV_PORT_OBJ_ADD, /* Blocking. */ |
221 | SWITCHDEV_PORT_OBJ_DEL, /* Blocking. */ |
222 | SWITCHDEV_PORT_ATTR_SET, /* May be blocking . */ |
223 | |
224 | SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE, |
225 | SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE, |
226 | SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, |
227 | SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE, |
228 | SWITCHDEV_VXLAN_FDB_OFFLOADED, |
229 | |
230 | SWITCHDEV_BRPORT_OFFLOADED, |
231 | SWITCHDEV_BRPORT_UNOFFLOADED, |
232 | SWITCHDEV_BRPORT_REPLAY, |
233 | }; |
234 | |
235 | struct switchdev_notifier_info { |
236 | struct net_device *dev; |
237 | struct netlink_ext_ack *extack; |
238 | const void *ctx; |
239 | }; |
240 | |
241 | /* Remember to update br_switchdev_fdb_populate() when adding |
242 | * new members to this structure |
243 | */ |
244 | struct switchdev_notifier_fdb_info { |
245 | struct switchdev_notifier_info info; /* must be first */ |
246 | const unsigned char *addr; |
247 | u16 vid; |
248 | u8 added_by_user:1, |
249 | is_local:1, |
250 | locked:1, |
251 | offloaded:1; |
252 | }; |
253 | |
254 | struct switchdev_notifier_port_obj_info { |
255 | struct switchdev_notifier_info info; /* must be first */ |
256 | const struct switchdev_obj *obj; |
257 | bool handled; |
258 | }; |
259 | |
260 | struct switchdev_notifier_port_attr_info { |
261 | struct switchdev_notifier_info info; /* must be first */ |
262 | const struct switchdev_attr *attr; |
263 | bool handled; |
264 | }; |
265 | |
266 | struct switchdev_notifier_brport_info { |
267 | struct switchdev_notifier_info info; /* must be first */ |
268 | const struct switchdev_brport brport; |
269 | }; |
270 | |
271 | static inline struct net_device * |
272 | switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) |
273 | { |
274 | return info->dev; |
275 | } |
276 | |
277 | static inline struct netlink_ext_ack * |
278 | switchdev_notifier_info_to_extack(const struct switchdev_notifier_info *info) |
279 | { |
280 | return info->extack; |
281 | } |
282 | |
283 | static inline bool |
284 | switchdev_fdb_is_dynamically_learned(const struct switchdev_notifier_fdb_info *fdb_info) |
285 | { |
286 | return !fdb_info->added_by_user && !fdb_info->is_local; |
287 | } |
288 | |
289 | #ifdef CONFIG_NET_SWITCHDEV |
290 | |
291 | int switchdev_bridge_port_offload(struct net_device *brport_dev, |
292 | struct net_device *dev, const void *ctx, |
293 | struct notifier_block *atomic_nb, |
294 | struct notifier_block *blocking_nb, |
295 | bool tx_fwd_offload, |
296 | struct netlink_ext_ack *extack); |
297 | void switchdev_bridge_port_unoffload(struct net_device *brport_dev, |
298 | const void *ctx, |
299 | struct notifier_block *atomic_nb, |
300 | struct notifier_block *blocking_nb); |
301 | int switchdev_bridge_port_replay(struct net_device *brport_dev, |
302 | struct net_device *dev, const void *ctx, |
303 | struct notifier_block *atomic_nb, |
304 | struct notifier_block *blocking_nb, |
305 | struct netlink_ext_ack *extack); |
306 | |
307 | void switchdev_deferred_process(void); |
308 | int switchdev_port_attr_set(struct net_device *dev, |
309 | const struct switchdev_attr *attr, |
310 | struct netlink_ext_ack *extack); |
311 | bool switchdev_port_obj_act_is_deferred(struct net_device *dev, |
312 | enum switchdev_notifier_type nt, |
313 | const struct switchdev_obj *obj); |
314 | int switchdev_port_obj_add(struct net_device *dev, |
315 | const struct switchdev_obj *obj, |
316 | struct netlink_ext_ack *extack); |
317 | int switchdev_port_obj_del(struct net_device *dev, |
318 | const struct switchdev_obj *obj); |
319 | |
320 | int register_switchdev_notifier(struct notifier_block *nb); |
321 | int unregister_switchdev_notifier(struct notifier_block *nb); |
322 | int call_switchdev_notifiers(unsigned long val, struct net_device *dev, |
323 | struct switchdev_notifier_info *info, |
324 | struct netlink_ext_ack *extack); |
325 | |
326 | int register_switchdev_blocking_notifier(struct notifier_block *nb); |
327 | int unregister_switchdev_blocking_notifier(struct notifier_block *nb); |
328 | int call_switchdev_blocking_notifiers(unsigned long val, struct net_device *dev, |
329 | struct switchdev_notifier_info *info, |
330 | struct netlink_ext_ack *extack); |
331 | |
332 | int switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event, |
333 | const struct switchdev_notifier_fdb_info *fdb_info, |
334 | bool (*check_cb)(const struct net_device *dev), |
335 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
336 | const struct net_device *foreign_dev), |
337 | int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev, |
338 | unsigned long event, const void *ctx, |
339 | const struct switchdev_notifier_fdb_info *fdb_info)); |
340 | |
341 | int switchdev_handle_port_obj_add(struct net_device *dev, |
342 | struct switchdev_notifier_port_obj_info *port_obj_info, |
343 | bool (*check_cb)(const struct net_device *dev), |
344 | int (*add_cb)(struct net_device *dev, const void *ctx, |
345 | const struct switchdev_obj *obj, |
346 | struct netlink_ext_ack *extack)); |
347 | int switchdev_handle_port_obj_add_foreign(struct net_device *dev, |
348 | struct switchdev_notifier_port_obj_info *port_obj_info, |
349 | bool (*check_cb)(const struct net_device *dev), |
350 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
351 | const struct net_device *foreign_dev), |
352 | int (*add_cb)(struct net_device *dev, const void *ctx, |
353 | const struct switchdev_obj *obj, |
354 | struct netlink_ext_ack *extack)); |
355 | int switchdev_handle_port_obj_del(struct net_device *dev, |
356 | struct switchdev_notifier_port_obj_info *port_obj_info, |
357 | bool (*check_cb)(const struct net_device *dev), |
358 | int (*del_cb)(struct net_device *dev, const void *ctx, |
359 | const struct switchdev_obj *obj)); |
360 | int switchdev_handle_port_obj_del_foreign(struct net_device *dev, |
361 | struct switchdev_notifier_port_obj_info *port_obj_info, |
362 | bool (*check_cb)(const struct net_device *dev), |
363 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
364 | const struct net_device *foreign_dev), |
365 | int (*del_cb)(struct net_device *dev, const void *ctx, |
366 | const struct switchdev_obj *obj)); |
367 | |
368 | int switchdev_handle_port_attr_set(struct net_device *dev, |
369 | struct switchdev_notifier_port_attr_info *port_attr_info, |
370 | bool (*check_cb)(const struct net_device *dev), |
371 | int (*set_cb)(struct net_device *dev, const void *ctx, |
372 | const struct switchdev_attr *attr, |
373 | struct netlink_ext_ack *extack)); |
374 | #else |
375 | |
376 | static inline int |
377 | switchdev_bridge_port_offload(struct net_device *brport_dev, |
378 | struct net_device *dev, const void *ctx, |
379 | struct notifier_block *atomic_nb, |
380 | struct notifier_block *blocking_nb, |
381 | bool tx_fwd_offload, |
382 | struct netlink_ext_ack *extack) |
383 | { |
384 | return -EOPNOTSUPP; |
385 | } |
386 | |
387 | static inline void |
388 | switchdev_bridge_port_unoffload(struct net_device *brport_dev, |
389 | const void *ctx, |
390 | struct notifier_block *atomic_nb, |
391 | struct notifier_block *blocking_nb) |
392 | { |
393 | } |
394 | |
395 | static inline void switchdev_deferred_process(void) |
396 | { |
397 | } |
398 | |
399 | static inline int switchdev_port_attr_set(struct net_device *dev, |
400 | const struct switchdev_attr *attr, |
401 | struct netlink_ext_ack *extack) |
402 | { |
403 | return -EOPNOTSUPP; |
404 | } |
405 | |
406 | static inline int switchdev_port_obj_add(struct net_device *dev, |
407 | const struct switchdev_obj *obj, |
408 | struct netlink_ext_ack *extack) |
409 | { |
410 | return -EOPNOTSUPP; |
411 | } |
412 | |
413 | static inline int switchdev_port_obj_del(struct net_device *dev, |
414 | const struct switchdev_obj *obj) |
415 | { |
416 | return -EOPNOTSUPP; |
417 | } |
418 | |
419 | static inline int register_switchdev_notifier(struct notifier_block *nb) |
420 | { |
421 | return 0; |
422 | } |
423 | |
424 | static inline int unregister_switchdev_notifier(struct notifier_block *nb) |
425 | { |
426 | return 0; |
427 | } |
428 | |
429 | static inline int call_switchdev_notifiers(unsigned long val, |
430 | struct net_device *dev, |
431 | struct switchdev_notifier_info *info, |
432 | struct netlink_ext_ack *extack) |
433 | { |
434 | return NOTIFY_DONE; |
435 | } |
436 | |
437 | static inline int |
438 | register_switchdev_blocking_notifier(struct notifier_block *nb) |
439 | { |
440 | return 0; |
441 | } |
442 | |
443 | static inline int |
444 | unregister_switchdev_blocking_notifier(struct notifier_block *nb) |
445 | { |
446 | return 0; |
447 | } |
448 | |
449 | static inline int |
450 | call_switchdev_blocking_notifiers(unsigned long val, |
451 | struct net_device *dev, |
452 | struct switchdev_notifier_info *info, |
453 | struct netlink_ext_ack *extack) |
454 | { |
455 | return NOTIFY_DONE; |
456 | } |
457 | |
458 | static inline int |
459 | switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event, |
460 | const struct switchdev_notifier_fdb_info *fdb_info, |
461 | bool (*check_cb)(const struct net_device *dev), |
462 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
463 | const struct net_device *foreign_dev), |
464 | int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev, |
465 | unsigned long event, const void *ctx, |
466 | const struct switchdev_notifier_fdb_info *fdb_info)) |
467 | { |
468 | return 0; |
469 | } |
470 | |
471 | static inline int |
472 | switchdev_handle_port_obj_add(struct net_device *dev, |
473 | struct switchdev_notifier_port_obj_info *port_obj_info, |
474 | bool (*check_cb)(const struct net_device *dev), |
475 | int (*add_cb)(struct net_device *dev, const void *ctx, |
476 | const struct switchdev_obj *obj, |
477 | struct netlink_ext_ack *extack)) |
478 | { |
479 | return 0; |
480 | } |
481 | |
482 | static inline int switchdev_handle_port_obj_add_foreign(struct net_device *dev, |
483 | struct switchdev_notifier_port_obj_info *port_obj_info, |
484 | bool (*check_cb)(const struct net_device *dev), |
485 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
486 | const struct net_device *foreign_dev), |
487 | int (*add_cb)(struct net_device *dev, const void *ctx, |
488 | const struct switchdev_obj *obj, |
489 | struct netlink_ext_ack *extack)) |
490 | { |
491 | return 0; |
492 | } |
493 | |
494 | static inline int |
495 | switchdev_handle_port_obj_del(struct net_device *dev, |
496 | struct switchdev_notifier_port_obj_info *port_obj_info, |
497 | bool (*check_cb)(const struct net_device *dev), |
498 | int (*del_cb)(struct net_device *dev, const void *ctx, |
499 | const struct switchdev_obj *obj)) |
500 | { |
501 | return 0; |
502 | } |
503 | |
504 | static inline int |
505 | switchdev_handle_port_obj_del_foreign(struct net_device *dev, |
506 | struct switchdev_notifier_port_obj_info *port_obj_info, |
507 | bool (*check_cb)(const struct net_device *dev), |
508 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
509 | const struct net_device *foreign_dev), |
510 | int (*del_cb)(struct net_device *dev, const void *ctx, |
511 | const struct switchdev_obj *obj)) |
512 | { |
513 | return 0; |
514 | } |
515 | |
516 | static inline int |
517 | switchdev_handle_port_attr_set(struct net_device *dev, |
518 | struct switchdev_notifier_port_attr_info *port_attr_info, |
519 | bool (*check_cb)(const struct net_device *dev), |
520 | int (*set_cb)(struct net_device *dev, const void *ctx, |
521 | const struct switchdev_attr *attr, |
522 | struct netlink_ext_ack *extack)) |
523 | { |
524 | return 0; |
525 | } |
526 | #endif |
527 | |
528 | #endif /* _LINUX_SWITCHDEV_H_ */ |
529 | |