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 | int switchdev_port_obj_add(struct net_device *dev, |
312 | const struct switchdev_obj *obj, |
313 | struct netlink_ext_ack *extack); |
314 | int switchdev_port_obj_del(struct net_device *dev, |
315 | const struct switchdev_obj *obj); |
316 | |
317 | int register_switchdev_notifier(struct notifier_block *nb); |
318 | int unregister_switchdev_notifier(struct notifier_block *nb); |
319 | int call_switchdev_notifiers(unsigned long val, struct net_device *dev, |
320 | struct switchdev_notifier_info *info, |
321 | struct netlink_ext_ack *extack); |
322 | |
323 | int register_switchdev_blocking_notifier(struct notifier_block *nb); |
324 | int unregister_switchdev_blocking_notifier(struct notifier_block *nb); |
325 | int call_switchdev_blocking_notifiers(unsigned long val, struct net_device *dev, |
326 | struct switchdev_notifier_info *info, |
327 | struct netlink_ext_ack *extack); |
328 | |
329 | int switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event, |
330 | const struct switchdev_notifier_fdb_info *fdb_info, |
331 | bool (*check_cb)(const struct net_device *dev), |
332 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
333 | const struct net_device *foreign_dev), |
334 | int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev, |
335 | unsigned long event, const void *ctx, |
336 | const struct switchdev_notifier_fdb_info *fdb_info)); |
337 | |
338 | int switchdev_handle_port_obj_add(struct net_device *dev, |
339 | struct switchdev_notifier_port_obj_info *port_obj_info, |
340 | bool (*check_cb)(const struct net_device *dev), |
341 | int (*add_cb)(struct net_device *dev, const void *ctx, |
342 | const struct switchdev_obj *obj, |
343 | struct netlink_ext_ack *extack)); |
344 | int switchdev_handle_port_obj_add_foreign(struct net_device *dev, |
345 | struct switchdev_notifier_port_obj_info *port_obj_info, |
346 | bool (*check_cb)(const struct net_device *dev), |
347 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
348 | const struct net_device *foreign_dev), |
349 | int (*add_cb)(struct net_device *dev, const void *ctx, |
350 | const struct switchdev_obj *obj, |
351 | struct netlink_ext_ack *extack)); |
352 | int switchdev_handle_port_obj_del(struct net_device *dev, |
353 | struct switchdev_notifier_port_obj_info *port_obj_info, |
354 | bool (*check_cb)(const struct net_device *dev), |
355 | int (*del_cb)(struct net_device *dev, const void *ctx, |
356 | const struct switchdev_obj *obj)); |
357 | int switchdev_handle_port_obj_del_foreign(struct net_device *dev, |
358 | struct switchdev_notifier_port_obj_info *port_obj_info, |
359 | bool (*check_cb)(const struct net_device *dev), |
360 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
361 | const struct net_device *foreign_dev), |
362 | int (*del_cb)(struct net_device *dev, const void *ctx, |
363 | const struct switchdev_obj *obj)); |
364 | |
365 | int switchdev_handle_port_attr_set(struct net_device *dev, |
366 | struct switchdev_notifier_port_attr_info *port_attr_info, |
367 | bool (*check_cb)(const struct net_device *dev), |
368 | int (*set_cb)(struct net_device *dev, const void *ctx, |
369 | const struct switchdev_attr *attr, |
370 | struct netlink_ext_ack *extack)); |
371 | #else |
372 | |
373 | static inline int |
374 | switchdev_bridge_port_offload(struct net_device *brport_dev, |
375 | struct net_device *dev, const void *ctx, |
376 | struct notifier_block *atomic_nb, |
377 | struct notifier_block *blocking_nb, |
378 | bool tx_fwd_offload, |
379 | struct netlink_ext_ack *extack) |
380 | { |
381 | return -EOPNOTSUPP; |
382 | } |
383 | |
384 | static inline void |
385 | switchdev_bridge_port_unoffload(struct net_device *brport_dev, |
386 | const void *ctx, |
387 | struct notifier_block *atomic_nb, |
388 | struct notifier_block *blocking_nb) |
389 | { |
390 | } |
391 | |
392 | static inline void switchdev_deferred_process(void) |
393 | { |
394 | } |
395 | |
396 | static inline int switchdev_port_attr_set(struct net_device *dev, |
397 | const struct switchdev_attr *attr, |
398 | struct netlink_ext_ack *extack) |
399 | { |
400 | return -EOPNOTSUPP; |
401 | } |
402 | |
403 | static inline int switchdev_port_obj_add(struct net_device *dev, |
404 | const struct switchdev_obj *obj, |
405 | struct netlink_ext_ack *extack) |
406 | { |
407 | return -EOPNOTSUPP; |
408 | } |
409 | |
410 | static inline int switchdev_port_obj_del(struct net_device *dev, |
411 | const struct switchdev_obj *obj) |
412 | { |
413 | return -EOPNOTSUPP; |
414 | } |
415 | |
416 | static inline int register_switchdev_notifier(struct notifier_block *nb) |
417 | { |
418 | return 0; |
419 | } |
420 | |
421 | static inline int unregister_switchdev_notifier(struct notifier_block *nb) |
422 | { |
423 | return 0; |
424 | } |
425 | |
426 | static inline int call_switchdev_notifiers(unsigned long val, |
427 | struct net_device *dev, |
428 | struct switchdev_notifier_info *info, |
429 | struct netlink_ext_ack *extack) |
430 | { |
431 | return NOTIFY_DONE; |
432 | } |
433 | |
434 | static inline int |
435 | register_switchdev_blocking_notifier(struct notifier_block *nb) |
436 | { |
437 | return 0; |
438 | } |
439 | |
440 | static inline int |
441 | unregister_switchdev_blocking_notifier(struct notifier_block *nb) |
442 | { |
443 | return 0; |
444 | } |
445 | |
446 | static inline int |
447 | call_switchdev_blocking_notifiers(unsigned long val, |
448 | struct net_device *dev, |
449 | struct switchdev_notifier_info *info, |
450 | struct netlink_ext_ack *extack) |
451 | { |
452 | return NOTIFY_DONE; |
453 | } |
454 | |
455 | static inline int |
456 | switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event, |
457 | const struct switchdev_notifier_fdb_info *fdb_info, |
458 | bool (*check_cb)(const struct net_device *dev), |
459 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
460 | const struct net_device *foreign_dev), |
461 | int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev, |
462 | unsigned long event, const void *ctx, |
463 | const struct switchdev_notifier_fdb_info *fdb_info)) |
464 | { |
465 | return 0; |
466 | } |
467 | |
468 | static inline int |
469 | switchdev_handle_port_obj_add(struct net_device *dev, |
470 | struct switchdev_notifier_port_obj_info *port_obj_info, |
471 | bool (*check_cb)(const struct net_device *dev), |
472 | int (*add_cb)(struct net_device *dev, const void *ctx, |
473 | const struct switchdev_obj *obj, |
474 | struct netlink_ext_ack *extack)) |
475 | { |
476 | return 0; |
477 | } |
478 | |
479 | static inline int switchdev_handle_port_obj_add_foreign(struct net_device *dev, |
480 | struct switchdev_notifier_port_obj_info *port_obj_info, |
481 | bool (*check_cb)(const struct net_device *dev), |
482 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
483 | const struct net_device *foreign_dev), |
484 | int (*add_cb)(struct net_device *dev, const void *ctx, |
485 | const struct switchdev_obj *obj, |
486 | struct netlink_ext_ack *extack)) |
487 | { |
488 | return 0; |
489 | } |
490 | |
491 | static inline int |
492 | switchdev_handle_port_obj_del(struct net_device *dev, |
493 | struct switchdev_notifier_port_obj_info *port_obj_info, |
494 | bool (*check_cb)(const struct net_device *dev), |
495 | int (*del_cb)(struct net_device *dev, const void *ctx, |
496 | const struct switchdev_obj *obj)) |
497 | { |
498 | return 0; |
499 | } |
500 | |
501 | static inline int |
502 | switchdev_handle_port_obj_del_foreign(struct net_device *dev, |
503 | struct switchdev_notifier_port_obj_info *port_obj_info, |
504 | bool (*check_cb)(const struct net_device *dev), |
505 | bool (*foreign_dev_check_cb)(const struct net_device *dev, |
506 | const struct net_device *foreign_dev), |
507 | int (*del_cb)(struct net_device *dev, const void *ctx, |
508 | const struct switchdev_obj *obj)) |
509 | { |
510 | return 0; |
511 | } |
512 | |
513 | static inline int |
514 | switchdev_handle_port_attr_set(struct net_device *dev, |
515 | struct switchdev_notifier_port_attr_info *port_attr_info, |
516 | bool (*check_cb)(const struct net_device *dev), |
517 | int (*set_cb)(struct net_device *dev, const void *ctx, |
518 | const struct switchdev_attr *attr, |
519 | struct netlink_ext_ack *extack)) |
520 | { |
521 | return 0; |
522 | } |
523 | #endif |
524 | |
525 | #endif /* _LINUX_SWITCHDEV_H_ */ |
526 | |