1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2022 MaxLinear, Inc.
4 */
5
6 /**
7 * @ingroup link
8 * @defgroup bridge Bridging
9 *
10 * @details
11 * @{
12 */
13
14 #include "nl-default.h"
15
16 #include <netlink/route/link/bridge_info.h>
17
18 #include "nl-route.h"
19 #include "link-api.h"
20
21 #define BRIDGE_ATTR_VLAN_FILTERING (1 << 0)
22 #define BRIDGE_ATTR_VLAN_PROTOCOL (1 << 1)
23 #define BRIDGE_ATTR_VLAN_STATS_ENABLED (1 << 2)
24 #define BRIDGE_ATTR_AGEING_TIME (1 << 3)
25 #define BRIDGE_ATTR_VLAN_DEFAULT_PVID (1 << 4)
26 #define BRIDGE_ATTR_NF_CALL_IPTABLES (1 << 5)
27 #define BRIDGE_ATTR_NF_CALL_IP6TABLES (1 << 6)
28 #define BRIDGE_ATTR_NF_CALL_ARPTABLES (1 << 7)
29
30 struct bridge_info {
31 uint32_t ce_mask; /* to support attr macros */
32 uint32_t b_ageing_time;
33 uint16_t b_vlan_protocol;
34 uint16_t b_vlan_default_pvid;
35 uint8_t b_vlan_filtering;
36 uint8_t b_vlan_stats_enabled;
37 uint8_t b_nf_call_iptables;
38 uint8_t b_nf_call_ip6tables;
39 uint8_t b_nf_call_arptables;
40 };
41
42 static const struct nla_policy bi_attrs_policy[IFLA_BR_MAX + 1] = {
43 [IFLA_BR_AGEING_TIME] = { .type = NLA_U32 },
44 [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NLA_U16 },
45 [IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 },
46 [IFLA_BR_VLAN_PROTOCOL] = { .type = NLA_U16 },
47 [IFLA_BR_VLAN_STATS_ENABLED] = { .type = NLA_U8 },
48 [IFLA_BR_NF_CALL_IPTABLES] = { .type = NLA_U8 },
49 [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NLA_U8 },
50 [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NLA_U8 },
51 };
52
bridge_info(struct rtnl_link * link)53 static inline struct bridge_info *bridge_info(struct rtnl_link *link)
54 {
55 return link->l_info;
56 }
57
bridge_info_alloc(struct rtnl_link * link)58 static int bridge_info_alloc(struct rtnl_link *link)
59 {
60 struct bridge_info *bi;
61
62 if (link->l_info)
63 memset(link->l_info, 0, sizeof(*bi));
64 else {
65 bi = calloc(1, sizeof(*bi));
66 if (!bi)
67 return -NLE_NOMEM;
68
69 link->l_info = bi;
70 }
71
72 return 0;
73 }
74
bridge_info_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)75 static int bridge_info_parse(struct rtnl_link *link, struct nlattr *data,
76 struct nlattr *xstats)
77 {
78 struct nlattr *tb[IFLA_BR_MAX + 1];
79 struct bridge_info *bi;
80 int err;
81
82 NL_DBG(3, "Parsing Bridge link info\n");
83
84 if ((err = nla_parse_nested(tb, IFLA_BR_MAX, data, bi_attrs_policy)) <
85 0)
86 return err;
87
88 if ((err = bridge_info_alloc(link)) < 0)
89 return err;
90
91 bi = link->l_info;
92
93 if (tb[IFLA_BR_AGEING_TIME]) {
94 bi->b_ageing_time = nla_get_u32(tb[IFLA_BR_AGEING_TIME]);
95 bi->ce_mask |= BRIDGE_ATTR_AGEING_TIME;
96 }
97
98 if (tb[IFLA_BR_VLAN_DEFAULT_PVID]) {
99 bi->b_vlan_default_pvid =
100 nla_get_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]);
101 bi->ce_mask |= BRIDGE_ATTR_VLAN_DEFAULT_PVID;
102 }
103
104 if (tb[IFLA_BR_VLAN_FILTERING]) {
105 bi->b_vlan_filtering = nla_get_u8(tb[IFLA_BR_VLAN_FILTERING]);
106 bi->ce_mask |= BRIDGE_ATTR_VLAN_FILTERING;
107 }
108
109 if (tb[IFLA_BR_VLAN_PROTOCOL]) {
110 bi->b_vlan_protocol =
111 ntohs(nla_get_u16(tb[IFLA_BR_VLAN_PROTOCOL]));
112 bi->ce_mask |= BRIDGE_ATTR_VLAN_PROTOCOL;
113 }
114
115 if (tb[IFLA_BR_VLAN_STATS_ENABLED]) {
116 bi->b_vlan_stats_enabled =
117 nla_get_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]);
118 bi->ce_mask |= BRIDGE_ATTR_VLAN_STATS_ENABLED;
119 }
120
121 if (tb[IFLA_BR_NF_CALL_IPTABLES]) {
122 bi->b_nf_call_iptables =
123 nla_get_u8(tb[IFLA_BR_NF_CALL_IPTABLES]);
124 bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IPTABLES;
125 }
126
127 if (tb[IFLA_BR_NF_CALL_IP6TABLES]) {
128 bi->b_nf_call_ip6tables =
129 nla_get_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]);
130 bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IP6TABLES;
131 }
132
133 if (tb[IFLA_BR_NF_CALL_ARPTABLES]) {
134 bi->b_nf_call_arptables =
135 nla_get_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]);
136 bi->ce_mask |= BRIDGE_ATTR_NF_CALL_ARPTABLES;
137 }
138
139 return 0;
140 }
141
bridge_info_put_attrs(struct nl_msg * msg,struct rtnl_link * link)142 static int bridge_info_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
143 {
144 struct bridge_info *bi = link->l_info;
145 struct nlattr *data;
146
147 data = nla_nest_start(msg, IFLA_INFO_DATA);
148 if (!data)
149 return -NLE_MSGSIZE;
150
151 if (bi->ce_mask & BRIDGE_ATTR_AGEING_TIME)
152 NLA_PUT_U32(msg, IFLA_BR_AGEING_TIME, bi->b_ageing_time);
153
154 if (bi->ce_mask & BRIDGE_ATTR_VLAN_FILTERING)
155 NLA_PUT_U8(msg, IFLA_BR_VLAN_FILTERING, bi->b_vlan_filtering);
156
157 if (bi->ce_mask & BRIDGE_ATTR_VLAN_DEFAULT_PVID)
158 NLA_PUT_U16(msg, IFLA_BR_VLAN_DEFAULT_PVID,
159 bi->b_vlan_default_pvid);
160
161 if (bi->ce_mask & BRIDGE_ATTR_VLAN_PROTOCOL)
162 NLA_PUT_U16(msg, IFLA_BR_VLAN_PROTOCOL,
163 htons(bi->b_vlan_protocol));
164
165 if (bi->ce_mask & BRIDGE_ATTR_VLAN_STATS_ENABLED)
166 NLA_PUT_U8(msg, IFLA_BR_VLAN_STATS_ENABLED,
167 bi->b_vlan_stats_enabled);
168
169 if (bi->ce_mask & BRIDGE_ATTR_NF_CALL_IPTABLES)
170 NLA_PUT_U8(msg, IFLA_BR_NF_CALL_IPTABLES,
171 bi->b_nf_call_iptables);
172
173 if (bi->ce_mask & BRIDGE_ATTR_NF_CALL_IP6TABLES)
174 NLA_PUT_U8(msg, IFLA_BR_NF_CALL_IP6TABLES,
175 bi->b_nf_call_ip6tables);
176
177 if (bi->ce_mask & BRIDGE_ATTR_NF_CALL_ARPTABLES)
178 NLA_PUT_U8(msg, IFLA_BR_NF_CALL_ARPTABLES,
179 bi->b_nf_call_arptables);
180
181 nla_nest_end(msg, data);
182 return 0;
183
184 nla_put_failure:
185 nla_nest_cancel(msg, data);
186 return -NLE_MSGSIZE;
187 }
188
bridge_info_free(struct rtnl_link * link)189 static void bridge_info_free(struct rtnl_link *link)
190 {
191 _nl_clear_free(&link->l_info);
192 }
193
194 static struct rtnl_link_info_ops bridge_info_ops = {
195 .io_name = "bridge",
196 .io_alloc = bridge_info_alloc,
197 .io_parse = bridge_info_parse,
198 .io_put_attrs = bridge_info_put_attrs,
199 .io_free = bridge_info_free,
200 };
201
202 #define IS_BRIDGE_INFO_ASSERT(link) \
203 do { \
204 if ((link)->l_info_ops != &bridge_info_ops) { \
205 APPBUG("Link is not a bridge link. Set type \"bridge\" first."); \
206 } \
207 } while (0)
208
209 /**
210 * Set ageing time for dynamic forwarding entries
211 * @arg link Link object of type bridge
212 * @arg ageing_time Interval to set.
213 *
214 * @return void
215 */
rtnl_link_bridge_set_ageing_time(struct rtnl_link * link,uint32_t ageing_time)216 void rtnl_link_bridge_set_ageing_time(struct rtnl_link *link,
217 uint32_t ageing_time)
218 {
219 struct bridge_info *bi = bridge_info(link);
220
221 IS_BRIDGE_INFO_ASSERT(link);
222
223 bi->b_ageing_time = ageing_time;
224
225 bi->ce_mask |= BRIDGE_ATTR_AGEING_TIME;
226 }
227
228 /**
229 * Get ageing time for dynamic forwarding entries
230 * @arg link Link object of type bridge
231 * @arg ageing_time Output argument.
232 *
233 * @see rtnl_link_bridge_set_ageing_time()
234 * @return Zero on success, otherwise a negative error code.
235 * @retval -NLE_NOATTR
236 * @retval -NLE_INVAL
237 */
rtnl_link_bridge_get_ageing_time(struct rtnl_link * link,uint32_t * ageing_time)238 int rtnl_link_bridge_get_ageing_time(struct rtnl_link *link,
239 uint32_t *ageing_time)
240 {
241 struct bridge_info *bi = bridge_info(link);
242
243 IS_BRIDGE_INFO_ASSERT(link);
244
245 if (!(bi->ce_mask & BRIDGE_ATTR_AGEING_TIME))
246 return -NLE_NOATTR;
247
248 if (!ageing_time)
249 return -NLE_INVAL;
250
251 *ageing_time = bi->b_ageing_time;
252
253 return 0;
254 }
255
256 /**
257 * Set VLAN filtering flag
258 * @arg link Link object of type bridge
259 * @arg vlan_filtering VLAN_filtering boolean flag to set.
260 *
261 * @see rtnl_link_bridge_get_vlan_filtering()
262 *
263 * @return void
264 */
rtnl_link_bridge_set_vlan_filtering(struct rtnl_link * link,uint8_t vlan_filtering)265 void rtnl_link_bridge_set_vlan_filtering(struct rtnl_link *link,
266 uint8_t vlan_filtering)
267 {
268 struct bridge_info *bi = bridge_info(link);
269
270 IS_BRIDGE_INFO_ASSERT(link);
271
272 bi->b_vlan_filtering = vlan_filtering;
273
274 bi->ce_mask |= BRIDGE_ATTR_VLAN_FILTERING;
275 }
276
277 /**
278 * Get VLAN filtering flag
279 * @arg link Link object of type bridge
280 * @arg vlan_filtering Output argument.
281 *
282 * @see rtnl_link_bridge_set_vlan_filtering()
283 *
284 * @return Zero on success, otherwise a negative error code.
285 * @retval -NLE_NOATTR
286 * @retval -NLE_INVAL
287 */
rtnl_link_bridge_get_vlan_filtering(struct rtnl_link * link,uint8_t * vlan_filtering)288 int rtnl_link_bridge_get_vlan_filtering(struct rtnl_link *link,
289 uint8_t *vlan_filtering)
290 {
291 struct bridge_info *bi = bridge_info(link);
292
293 IS_BRIDGE_INFO_ASSERT(link);
294
295 if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_FILTERING))
296 return -NLE_NOATTR;
297
298 if (!vlan_filtering)
299 return -NLE_INVAL;
300
301 *vlan_filtering = bi->b_vlan_filtering;
302 return 0;
303 }
304
305 /**
306 * Set VLAN protocol
307 * @arg link Link object of type bridge
308 * @arg vlan_protocol VLAN protocol to set. The protocol
309 * numbers is in host byte order.
310 *
311 * @see rtnl_link_bridge_get_vlan_protocol()
312 *
313 * @return void
314 */
rtnl_link_bridge_set_vlan_protocol(struct rtnl_link * link,uint16_t vlan_protocol)315 void rtnl_link_bridge_set_vlan_protocol(struct rtnl_link *link,
316 uint16_t vlan_protocol)
317 {
318 struct bridge_info *bi = bridge_info(link);
319
320 IS_BRIDGE_INFO_ASSERT(link);
321
322 bi->b_vlan_protocol = vlan_protocol;
323
324 bi->ce_mask |= BRIDGE_ATTR_VLAN_PROTOCOL;
325 }
326
327 /**
328 * Get VLAN protocol
329 * @arg link Link object of type bridge
330 * @arg vlan_protocol Output argument. The protocol number is in host byte order.
331 *
332 * @see rtnl_link_bridge_set_vlan_protocol()
333 *
334 * @return Zero on success, otherwise a negative error code.
335 * @retval -NLE_NOATTR
336 * @retval -NLE_INVAL
337 */
rtnl_link_bridge_get_vlan_protocol(struct rtnl_link * link,uint16_t * vlan_protocol)338 int rtnl_link_bridge_get_vlan_protocol(struct rtnl_link *link,
339 uint16_t *vlan_protocol)
340 {
341 struct bridge_info *bi = bridge_info(link);
342
343 IS_BRIDGE_INFO_ASSERT(link);
344
345 if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_PROTOCOL))
346 return -NLE_NOATTR;
347
348 if (!vlan_protocol)
349 return -NLE_INVAL;
350
351 *vlan_protocol = bi->b_vlan_protocol;
352
353 return 0;
354 }
355
356 /**
357 * Set VLAN default pvid
358 * @arg link Link object of type bridge
359 * @arg default pvid VLAN default pvid to set.
360 *
361 * @see rtnl_link_bridge_get_vlan_default_pvid()
362 *
363 * @return void
364 */
rtnl_link_bridge_set_vlan_default_pvid(struct rtnl_link * link,uint16_t default_pvid)365 void rtnl_link_bridge_set_vlan_default_pvid(struct rtnl_link *link,
366 uint16_t default_pvid)
367 {
368 struct bridge_info *bi = bridge_info(link);
369
370 IS_BRIDGE_INFO_ASSERT(link);
371
372 bi->b_vlan_default_pvid = default_pvid;
373
374 bi->ce_mask |= BRIDGE_ATTR_VLAN_DEFAULT_PVID;
375 }
376
377 /**
378 * Get VLAN default pvid
379 * @arg link Link object of type bridge
380 * @arg default_pvid Output argument.
381 *
382 * @see rtnl_link_bridge_set_vlan_default_pvid()
383 *
384 * @return Zero on success, otherwise a negative error code.
385 * @retval -NLE_NOATTR
386 * @retval -NLE_INVAL
387 */
rtnl_link_bridge_get_vlan_default_pvid(struct rtnl_link * link,uint16_t * default_pvid)388 int rtnl_link_bridge_get_vlan_default_pvid(struct rtnl_link *link,
389 uint16_t *default_pvid)
390 {
391 struct bridge_info *bi = bridge_info(link);
392
393 IS_BRIDGE_INFO_ASSERT(link);
394
395 if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_DEFAULT_PVID))
396 return -NLE_NOATTR;
397
398 if (!default_pvid)
399 return -NLE_INVAL;
400
401 *default_pvid = bi->b_vlan_default_pvid;
402
403 return 0;
404 }
405
406 /**
407 * Set VLAN stats enabled flag
408 * @arg link Link object of type bridge
409 * @arg vlan_stats_enabled VLAN stats enabled flag to set
410 *
411 * @see rtnl_link_bridge_get_vlan_stats_enabled()
412 *
413 * @return void
414 */
rtnl_link_bridge_set_vlan_stats_enabled(struct rtnl_link * link,uint8_t vlan_stats_enabled)415 void rtnl_link_bridge_set_vlan_stats_enabled(struct rtnl_link *link,
416 uint8_t vlan_stats_enabled)
417 {
418 struct bridge_info *bi = bridge_info(link);
419
420 IS_BRIDGE_INFO_ASSERT(link);
421
422 bi->b_vlan_stats_enabled = vlan_stats_enabled;
423
424 bi->ce_mask |= BRIDGE_ATTR_VLAN_STATS_ENABLED;
425 }
426
427 /**
428 * Get VLAN stats enabled flag
429 * @arg link Link object of type bridge
430 * @arg vlan_stats_enabled Output argument.
431 *
432 * @see rtnl_link_bridge_set_vlan_stats_enabled()
433 *
434 * @return Zero on success, otherwise a negative error code.
435 * @retval -NLE_NOATTR
436 * @retval -NLE_INVAL
437 */
rtnl_link_bridge_get_vlan_stats_enabled(struct rtnl_link * link,uint8_t * vlan_stats_enabled)438 int rtnl_link_bridge_get_vlan_stats_enabled(struct rtnl_link *link,
439 uint8_t *vlan_stats_enabled)
440 {
441 struct bridge_info *bi = bridge_info(link);
442
443 IS_BRIDGE_INFO_ASSERT(link);
444
445 if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_STATS_ENABLED))
446 return -NLE_NOATTR;
447
448 if (!vlan_stats_enabled)
449 return -NLE_INVAL;
450
451 *vlan_stats_enabled = bi->b_vlan_stats_enabled;
452
453 return 0;
454 }
455
456 /**
457 * Set call enabled flag for passing IPv4 traffic to iptables
458 * @arg link Link object of type bridge
459 * @arg call_enabled call enabled boolean flag to set.
460 *
461 * @return void
462 */
rtnl_link_bridge_set_nf_call_iptables(struct rtnl_link * link,uint8_t call_enabled)463 void rtnl_link_bridge_set_nf_call_iptables(struct rtnl_link *link,
464 uint8_t call_enabled)
465 {
466 struct bridge_info *bi = bridge_info(link);
467
468 IS_BRIDGE_INFO_ASSERT(link);
469
470 bi->b_nf_call_iptables = call_enabled;
471
472 bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IPTABLES;
473 }
474
475 /**
476 * Set call enabled flag for passing IPv6 traffic to ip6tables
477 * @arg link Link object of type bridge
478 * @arg call_enabled call enabled boolean flag to set.
479 *
480 * @return void
481 */
rtnl_link_bridge_set_nf_call_ip6tables(struct rtnl_link * link,uint8_t call_enabled)482 void rtnl_link_bridge_set_nf_call_ip6tables(struct rtnl_link *link,
483 uint8_t call_enabled)
484 {
485 struct bridge_info *bi = bridge_info(link);
486
487 IS_BRIDGE_INFO_ASSERT(link);
488
489 bi->b_nf_call_ip6tables = call_enabled;
490
491 bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IP6TABLES;
492 }
493
494 /**
495 * Set call enabled flag for passing ARP traffic to arptables
496 * @arg link Link object of type bridge
497 * @arg call_enabled call enabled boolean flag to set.
498 *
499 * @return void
500 */
rtnl_link_bridge_set_nf_call_arptables(struct rtnl_link * link,uint8_t call_enabled)501 void rtnl_link_bridge_set_nf_call_arptables(struct rtnl_link *link,
502 uint8_t call_enabled)
503 {
504 struct bridge_info *bi = bridge_info(link);
505
506 IS_BRIDGE_INFO_ASSERT(link);
507
508 bi->b_nf_call_arptables = call_enabled;
509
510 bi->ce_mask |= BRIDGE_ATTR_NF_CALL_ARPTABLES;
511 }
512
bridge_info_init(void)513 static void _nl_init bridge_info_init(void)
514 {
515 rtnl_link_register_info(&bridge_info_ops);
516 }
517
bridge_info_exit(void)518 static void _nl_exit bridge_info_exit(void)
519 {
520 rtnl_link_unregister_info(&bridge_info_ops);
521 }
522
523 /** @} */
524