]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
007f790c JP |
2 | /* |
3 | * include/net/switchdev.h - Switch device API | |
7ea6eb3f | 4 | * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us> |
f8f21471 | 5 | * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com> |
007f790c JP |
6 | */ |
7 | #ifndef _LINUX_SWITCHDEV_H_ | |
8 | #define _LINUX_SWITCHDEV_H_ | |
9 | ||
10 | #include <linux/netdevice.h> | |
03bf0c28 | 11 | #include <linux/notifier.h> |
7ea6eb3f | 12 | #include <linux/list.h> |
850d0cbc | 13 | #include <net/ip_fib.h> |
03bf0c28 | 14 | |
3094333d | 15 | #define SWITCHDEV_F_NO_RECURSE BIT(0) |
464314ea | 16 | #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) |
0bc05d58 | 17 | #define SWITCHDEV_F_DEFER BIT(2) |
3094333d | 18 | |
3094333d | 19 | enum switchdev_attr_id { |
1f868398 | 20 | SWITCHDEV_ATTR_ID_UNDEFINED, |
1f868398 JP |
21 | SWITCHDEV_ATTR_ID_PORT_STP_STATE, |
22 | SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, | |
746dc184 | 23 | SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, |
6d549648 | 24 | SWITCHDEV_ATTR_ID_PORT_MROUTER, |
f55ac58a | 25 | SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME, |
81435c33 | 26 | SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, |
22ec19f3 | 27 | SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL, |
147c1e9b | 28 | SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, |
77041420 | 29 | SWITCHDEV_ATTR_ID_BRIDGE_MROUTER, |
c284b545 | 30 | SWITCHDEV_ATTR_ID_MRP_PORT_ROLE, |
3094333d SF |
31 | }; |
32 | ||
e18f4c18 VO |
33 | struct switchdev_brport_flags { |
34 | unsigned long val; | |
35 | unsigned long mask; | |
36 | }; | |
37 | ||
3094333d | 38 | struct switchdev_attr { |
6ff64f6f | 39 | struct net_device *orig_dev; |
3094333d | 40 | enum switchdev_attr_id id; |
3094333d | 41 | u32 flags; |
7ceb2afb ER |
42 | void *complete_priv; |
43 | void (*complete)(struct net_device *dev, int err, void *priv); | |
f8e20a9f | 44 | union { |
35636062 | 45 | u8 stp_state; /* PORT_STP_STATE */ |
e18f4c18 | 46 | struct switchdev_brport_flags brport_flags; /* PORT_BRIDGE_FLAGS */ |
6d549648 | 47 | bool mrouter; /* PORT_MROUTER */ |
eabfdda9 | 48 | clock_t ageing_time; /* BRIDGE_AGEING_TIME */ |
81435c33 | 49 | bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ |
22ec19f3 | 50 | u16 vlan_protocol; /* BRIDGE_VLAN_PROTOCOL */ |
147c1e9b | 51 | bool mc_disabled; /* MC_DISABLED */ |
c284b545 | 52 | u8 mrp_port_role; /* MRP_PORT_ROLE */ |
42275bd8 | 53 | } u; |
3094333d SF |
54 | }; |
55 | ||
491d0f15 | 56 | enum switchdev_obj_id { |
57d80838 JP |
57 | SWITCHDEV_OBJ_ID_UNDEFINED, |
58 | SWITCHDEV_OBJ_ID_PORT_VLAN, | |
4d41e125 | 59 | SWITCHDEV_OBJ_ID_PORT_MDB, |
47d5b6db | 60 | SWITCHDEV_OBJ_ID_HOST_MDB, |
c284b545 HV |
61 | SWITCHDEV_OBJ_ID_MRP, |
62 | SWITCHDEV_OBJ_ID_RING_TEST_MRP, | |
63 | SWITCHDEV_OBJ_ID_RING_ROLE_MRP, | |
64 | SWITCHDEV_OBJ_ID_RING_STATE_MRP, | |
cf7c5274 HV |
65 | SWITCHDEV_OBJ_ID_IN_TEST_MRP, |
66 | SWITCHDEV_OBJ_ID_IN_ROLE_MRP, | |
67 | SWITCHDEV_OBJ_ID_IN_STATE_MRP, | |
491d0f15 SF |
68 | }; |
69 | ||
648b4a99 | 70 | struct switchdev_obj { |
4f2673b3 | 71 | struct list_head list; |
6ff64f6f | 72 | struct net_device *orig_dev; |
9e8f4a54 | 73 | enum switchdev_obj_id id; |
4d429c5d | 74 | u32 flags; |
7ceb2afb ER |
75 | void *complete_priv; |
76 | void (*complete)(struct net_device *dev, int err, void *priv); | |
648b4a99 JP |
77 | }; |
78 | ||
57d80838 | 79 | /* SWITCHDEV_OBJ_ID_PORT_VLAN */ |
8f24f309 | 80 | struct switchdev_obj_port_vlan { |
648b4a99 | 81 | struct switchdev_obj obj; |
44bbcf5c | 82 | u16 flags; |
b7a9e0da | 83 | u16 vid; |
44bbcf5c VD |
84 | }; |
85 | ||
ec394af5 PM |
86 | #define SWITCHDEV_OBJ_PORT_VLAN(OBJ) \ |
87 | container_of((OBJ), struct switchdev_obj_port_vlan, obj) | |
648b4a99 | 88 | |
4d41e125 ER |
89 | /* SWITCHDEV_OBJ_ID_PORT_MDB */ |
90 | struct switchdev_obj_port_mdb { | |
91 | struct switchdev_obj obj; | |
92 | unsigned char addr[ETH_ALEN]; | |
93 | u16 vid; | |
94 | }; | |
95 | ||
ec394af5 PM |
96 | #define SWITCHDEV_OBJ_PORT_MDB(OBJ) \ |
97 | container_of((OBJ), struct switchdev_obj_port_mdb, obj) | |
4d41e125 | 98 | |
c284b545 | 99 | |
c284b545 HV |
100 | /* SWITCHDEV_OBJ_ID_MRP */ |
101 | struct switchdev_obj_mrp { | |
102 | struct switchdev_obj obj; | |
103 | struct net_device *p_port; | |
104 | struct net_device *s_port; | |
105 | u32 ring_id; | |
4b3a61b0 | 106 | u16 prio; |
c284b545 HV |
107 | }; |
108 | ||
109 | #define SWITCHDEV_OBJ_MRP(OBJ) \ | |
110 | container_of((OBJ), struct switchdev_obj_mrp, obj) | |
111 | ||
112 | /* SWITCHDEV_OBJ_ID_RING_TEST_MRP */ | |
113 | struct switchdev_obj_ring_test_mrp { | |
114 | struct switchdev_obj obj; | |
115 | /* The value is in us and a value of 0 represents to stop */ | |
116 | u32 interval; | |
117 | u8 max_miss; | |
118 | u32 ring_id; | |
119 | u32 period; | |
c6676e7d | 120 | bool monitor; |
c284b545 HV |
121 | }; |
122 | ||
123 | #define SWITCHDEV_OBJ_RING_TEST_MRP(OBJ) \ | |
124 | container_of((OBJ), struct switchdev_obj_ring_test_mrp, obj) | |
125 | ||
126 | /* SWICHDEV_OBJ_ID_RING_ROLE_MRP */ | |
127 | struct switchdev_obj_ring_role_mrp { | |
128 | struct switchdev_obj obj; | |
129 | u8 ring_role; | |
130 | u32 ring_id; | |
c513efa2 | 131 | u8 sw_backup; |
c284b545 HV |
132 | }; |
133 | ||
134 | #define SWITCHDEV_OBJ_RING_ROLE_MRP(OBJ) \ | |
135 | container_of((OBJ), struct switchdev_obj_ring_role_mrp, obj) | |
136 | ||
137 | struct switchdev_obj_ring_state_mrp { | |
138 | struct switchdev_obj obj; | |
139 | u8 ring_state; | |
140 | u32 ring_id; | |
141 | }; | |
142 | ||
143 | #define SWITCHDEV_OBJ_RING_STATE_MRP(OBJ) \ | |
144 | container_of((OBJ), struct switchdev_obj_ring_state_mrp, obj) | |
145 | ||
cf7c5274 HV |
146 | /* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ |
147 | struct switchdev_obj_in_test_mrp { | |
148 | struct switchdev_obj obj; | |
149 | /* The value is in us and a value of 0 represents to stop */ | |
150 | u32 interval; | |
151 | u32 in_id; | |
152 | u32 period; | |
153 | u8 max_miss; | |
154 | }; | |
155 | ||
156 | #define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ | |
157 | container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) | |
158 | ||
159 | /* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ | |
160 | struct switchdev_obj_in_role_mrp { | |
161 | struct switchdev_obj obj; | |
162 | struct net_device *i_port; | |
163 | u32 ring_id; | |
164 | u16 in_id; | |
165 | u8 in_role; | |
c513efa2 | 166 | u8 sw_backup; |
cf7c5274 HV |
167 | }; |
168 | ||
169 | #define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ | |
170 | container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) | |
171 | ||
172 | struct switchdev_obj_in_state_mrp { | |
173 | struct switchdev_obj obj; | |
174 | u32 in_id; | |
175 | u8 in_state; | |
176 | }; | |
177 | ||
178 | #define SWITCHDEV_OBJ_IN_STATE_MRP(OBJ) \ | |
179 | container_of((OBJ), struct switchdev_obj_in_state_mrp, obj) | |
180 | ||
648b4a99 JP |
181 | typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); |
182 | ||
ebb9a03a | 183 | enum switchdev_notifier_type { |
6b26b51b AS |
184 | SWITCHDEV_FDB_ADD_TO_BRIDGE = 1, |
185 | SWITCHDEV_FDB_DEL_TO_BRIDGE, | |
186 | SWITCHDEV_FDB_ADD_TO_DEVICE, | |
187 | SWITCHDEV_FDB_DEL_TO_DEVICE, | |
9fe8bcec | 188 | SWITCHDEV_FDB_OFFLOADED, |
d05e8e68 | 189 | SWITCHDEV_FDB_FLUSH_TO_BRIDGE, |
9a997353 | 190 | |
aa4efe21 PM |
191 | SWITCHDEV_PORT_OBJ_ADD, /* Blocking. */ |
192 | SWITCHDEV_PORT_OBJ_DEL, /* Blocking. */ | |
1cb33af1 | 193 | SWITCHDEV_PORT_ATTR_SET, /* May be blocking . */ |
aa4efe21 | 194 | |
5728ae0d PM |
195 | SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE, |
196 | SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE, | |
9a997353 PM |
197 | SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, |
198 | SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE, | |
0efe1173 | 199 | SWITCHDEV_VXLAN_FDB_OFFLOADED, |
3aeb6617 JP |
200 | }; |
201 | ||
ebb9a03a | 202 | struct switchdev_notifier_info { |
03bf0c28 | 203 | struct net_device *dev; |
479c86dc | 204 | struct netlink_ext_ack *extack; |
69bfac96 | 205 | const void *ctx; |
03bf0c28 JP |
206 | }; |
207 | ||
ebb9a03a JP |
208 | struct switchdev_notifier_fdb_info { |
209 | struct switchdev_notifier_info info; /* must be first */ | |
3aeb6617 JP |
210 | const unsigned char *addr; |
211 | u16 vid; | |
e9ba0fbc | 212 | u8 added_by_user:1, |
2c4eca3e | 213 | is_local:1, |
e9ba0fbc | 214 | offloaded:1; |
3aeb6617 JP |
215 | }; |
216 | ||
aa4efe21 PM |
217 | struct switchdev_notifier_port_obj_info { |
218 | struct switchdev_notifier_info info; /* must be first */ | |
219 | const struct switchdev_obj *obj; | |
aa4efe21 PM |
220 | bool handled; |
221 | }; | |
222 | ||
1cb33af1 FF |
223 | struct switchdev_notifier_port_attr_info { |
224 | struct switchdev_notifier_info info; /* must be first */ | |
225 | const struct switchdev_attr *attr; | |
1cb33af1 FF |
226 | bool handled; |
227 | }; | |
228 | ||
03bf0c28 | 229 | static inline struct net_device * |
ebb9a03a | 230 | switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) |
03bf0c28 JP |
231 | { |
232 | return info->dev; | |
233 | } | |
007f790c | 234 | |
479c86dc PM |
235 | static inline struct netlink_ext_ack * |
236 | switchdev_notifier_info_to_extack(const struct switchdev_notifier_info *info) | |
237 | { | |
238 | return info->extack; | |
239 | } | |
240 | ||
007f790c JP |
241 | #ifdef CONFIG_NET_SWITCHDEV |
242 | ||
793f4014 | 243 | void switchdev_deferred_process(void); |
3094333d | 244 | int switchdev_port_attr_set(struct net_device *dev, |
dcbdf135 VO |
245 | const struct switchdev_attr *attr, |
246 | struct netlink_ext_ack *extack); | |
9e8f4a54 | 247 | int switchdev_port_obj_add(struct net_device *dev, |
69b7320e PM |
248 | const struct switchdev_obj *obj, |
249 | struct netlink_ext_ack *extack); | |
9e8f4a54 | 250 | int switchdev_port_obj_del(struct net_device *dev, |
648b4a99 | 251 | const struct switchdev_obj *obj); |
a93e3b17 | 252 | |
ebb9a03a JP |
253 | int register_switchdev_notifier(struct notifier_block *nb); |
254 | int unregister_switchdev_notifier(struct notifier_block *nb); | |
255 | int call_switchdev_notifiers(unsigned long val, struct net_device *dev, | |
6685987c PM |
256 | struct switchdev_notifier_info *info, |
257 | struct netlink_ext_ack *extack); | |
a93e3b17 PM |
258 | |
259 | int register_switchdev_blocking_notifier(struct notifier_block *nb); | |
260 | int unregister_switchdev_blocking_notifier(struct notifier_block *nb); | |
261 | int call_switchdev_blocking_notifiers(unsigned long val, struct net_device *dev, | |
479c86dc PM |
262 | struct switchdev_notifier_info *info, |
263 | struct netlink_ext_ack *extack); | |
a93e3b17 | 264 | |
1a3b2ec9 SF |
265 | void switchdev_port_fwd_mark_set(struct net_device *dev, |
266 | struct net_device *group_dev, | |
267 | bool joining); | |
5e8d9049 | 268 | |
f30f0601 PM |
269 | int switchdev_handle_port_obj_add(struct net_device *dev, |
270 | struct switchdev_notifier_port_obj_info *port_obj_info, | |
271 | bool (*check_cb)(const struct net_device *dev), | |
69bfac96 | 272 | int (*add_cb)(struct net_device *dev, const void *ctx, |
f30f0601 | 273 | const struct switchdev_obj *obj, |
69213513 | 274 | struct netlink_ext_ack *extack)); |
f30f0601 PM |
275 | int switchdev_handle_port_obj_del(struct net_device *dev, |
276 | struct switchdev_notifier_port_obj_info *port_obj_info, | |
277 | bool (*check_cb)(const struct net_device *dev), | |
69bfac96 | 278 | int (*del_cb)(struct net_device *dev, const void *ctx, |
f30f0601 PM |
279 | const struct switchdev_obj *obj)); |
280 | ||
1cb33af1 FF |
281 | int switchdev_handle_port_attr_set(struct net_device *dev, |
282 | struct switchdev_notifier_port_attr_info *port_attr_info, | |
283 | bool (*check_cb)(const struct net_device *dev), | |
69bfac96 | 284 | int (*set_cb)(struct net_device *dev, const void *ctx, |
4c08c586 VO |
285 | const struct switchdev_attr *attr, |
286 | struct netlink_ext_ack *extack)); | |
007f790c JP |
287 | #else |
288 | ||
793f4014 JP |
289 | static inline void switchdev_deferred_process(void) |
290 | { | |
291 | } | |
292 | ||
3094333d | 293 | static inline int switchdev_port_attr_set(struct net_device *dev, |
419dfaed VO |
294 | const struct switchdev_attr *attr, |
295 | struct netlink_ext_ack *extack) | |
3094333d SF |
296 | { |
297 | return -EOPNOTSUPP; | |
298 | } | |
299 | ||
491d0f15 | 300 | static inline int switchdev_port_obj_add(struct net_device *dev, |
69b7320e PM |
301 | const struct switchdev_obj *obj, |
302 | struct netlink_ext_ack *extack) | |
491d0f15 SF |
303 | { |
304 | return -EOPNOTSUPP; | |
305 | } | |
306 | ||
307 | static inline int switchdev_port_obj_del(struct net_device *dev, | |
648b4a99 | 308 | const struct switchdev_obj *obj) |
491d0f15 SF |
309 | { |
310 | return -EOPNOTSUPP; | |
311 | } | |
312 | ||
ebb9a03a | 313 | static inline int register_switchdev_notifier(struct notifier_block *nb) |
03bf0c28 JP |
314 | { |
315 | return 0; | |
316 | } | |
317 | ||
ebb9a03a | 318 | static inline int unregister_switchdev_notifier(struct notifier_block *nb) |
03bf0c28 JP |
319 | { |
320 | return 0; | |
321 | } | |
322 | ||
ebb9a03a JP |
323 | static inline int call_switchdev_notifiers(unsigned long val, |
324 | struct net_device *dev, | |
6685987c PM |
325 | struct switchdev_notifier_info *info, |
326 | struct netlink_ext_ack *extack) | |
03bf0c28 JP |
327 | { |
328 | return NOTIFY_DONE; | |
329 | } | |
330 | ||
a93e3b17 PM |
331 | static inline int |
332 | register_switchdev_blocking_notifier(struct notifier_block *nb) | |
333 | { | |
334 | return 0; | |
335 | } | |
336 | ||
337 | static inline int | |
338 | unregister_switchdev_blocking_notifier(struct notifier_block *nb) | |
339 | { | |
340 | return 0; | |
341 | } | |
342 | ||
343 | static inline int | |
344 | call_switchdev_blocking_notifiers(unsigned long val, | |
345 | struct net_device *dev, | |
479c86dc PM |
346 | struct switchdev_notifier_info *info, |
347 | struct netlink_ext_ack *extack) | |
a93e3b17 PM |
348 | { |
349 | return NOTIFY_DONE; | |
350 | } | |
351 | ||
f30f0601 PM |
352 | static inline int |
353 | switchdev_handle_port_obj_add(struct net_device *dev, | |
354 | struct switchdev_notifier_port_obj_info *port_obj_info, | |
355 | bool (*check_cb)(const struct net_device *dev), | |
69bfac96 | 356 | int (*add_cb)(struct net_device *dev, const void *ctx, |
f30f0601 | 357 | const struct switchdev_obj *obj, |
69213513 | 358 | struct netlink_ext_ack *extack)) |
f30f0601 PM |
359 | { |
360 | return 0; | |
361 | } | |
362 | ||
363 | static inline int | |
364 | switchdev_handle_port_obj_del(struct net_device *dev, | |
365 | struct switchdev_notifier_port_obj_info *port_obj_info, | |
366 | bool (*check_cb)(const struct net_device *dev), | |
69bfac96 | 367 | int (*del_cb)(struct net_device *dev, const void *ctx, |
f30f0601 PM |
368 | const struct switchdev_obj *obj)) |
369 | { | |
370 | return 0; | |
371 | } | |
372 | ||
1cb33af1 FF |
373 | static inline int |
374 | switchdev_handle_port_attr_set(struct net_device *dev, | |
375 | struct switchdev_notifier_port_attr_info *port_attr_info, | |
376 | bool (*check_cb)(const struct net_device *dev), | |
69bfac96 | 377 | int (*set_cb)(struct net_device *dev, const void *ctx, |
4c08c586 VO |
378 | const struct switchdev_attr *attr, |
379 | struct netlink_ext_ack *extack)) | |
1cb33af1 FF |
380 | { |
381 | return 0; | |
382 | } | |
007f790c JP |
383 | #endif |
384 | ||
385 | #endif /* _LINUX_SWITCHDEV_H_ */ |