libnl 3.10.0
bridge_info.c
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
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
42static const struct nla_policy bi_attrs_policy[IFLA_BR_MAX + 1] = {
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
53static inline struct bridge_info *bridge_info(struct rtnl_link *link)
54{
55 return link->l_info;
56}
57
58static 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
75static 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
142static 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
184nla_put_failure:
185 nla_nest_cancel(msg, data);
186 return -NLE_MSGSIZE;
187}
188
189static void bridge_info_free(struct rtnl_link *link)
190{
191 _nl_clear_free(&link->l_info);
192}
193
194static 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
513static void _nl_init bridge_info_init(void)
514{
515 rtnl_link_register_info(&bridge_info_ops);
516}
517
518static void _nl_exit bridge_info_exit(void)
519{
520 rtnl_link_unregister_info(&bridge_info_ops);
521}
522
523/** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition attr.c:712
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition attr.c:662
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition attr.h:212
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition attr.h:194
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:230
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition attr.c:612
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition attr.c:908
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition attr.c:1035
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
Definition attr.c:1000
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition attr.c:971
@ NLA_U8
8 bit integer
Definition attr.h:35
@ NLA_U16
16 bit integer
Definition attr.h:36
@ NLA_U32
32 bit integer
Definition attr.h:37
int rtnl_link_bridge_get_vlan_default_pvid(struct rtnl_link *link, uint16_t *default_pvid)
Get VLAN default pvid.
int rtnl_link_bridge_get_vlan_protocol(struct rtnl_link *link, uint16_t *vlan_protocol)
Get VLAN protocol.
void rtnl_link_bridge_set_vlan_stats_enabled(struct rtnl_link *link, uint8_t vlan_stats_enabled)
Set VLAN stats enabled flag.
void rtnl_link_bridge_set_vlan_filtering(struct rtnl_link *link, uint8_t vlan_filtering)
Set VLAN filtering flag.
int rtnl_link_bridge_get_ageing_time(struct rtnl_link *link, uint32_t *ageing_time)
Get ageing time for dynamic forwarding entries.
int rtnl_link_bridge_get_vlan_filtering(struct rtnl_link *link, uint8_t *vlan_filtering)
Get VLAN filtering flag.
void rtnl_link_bridge_set_nf_call_iptables(struct rtnl_link *link, uint8_t call_enabled)
Set call enabled flag for passing IPv4 traffic to iptables.
void rtnl_link_bridge_set_ageing_time(struct rtnl_link *link, uint32_t ageing_time)
Set ageing time for dynamic forwarding entries.
void rtnl_link_bridge_set_nf_call_arptables(struct rtnl_link *link, uint8_t call_enabled)
Set call enabled flag for passing ARP traffic to arptables.
int rtnl_link_bridge_get_vlan_stats_enabled(struct rtnl_link *link, uint8_t *vlan_stats_enabled)
Get VLAN stats enabled flag.
void rtnl_link_bridge_set_vlan_protocol(struct rtnl_link *link, uint16_t vlan_protocol)
Set VLAN protocol.
void rtnl_link_bridge_set_nf_call_ip6tables(struct rtnl_link *link, uint8_t call_enabled)
Set call enabled flag for passing IPv6 traffic to ip6tables.
void rtnl_link_bridge_set_vlan_default_pvid(struct rtnl_link *link, uint16_t default_pvid)
Set VLAN default pvid.
Attribute validation policy.
Definition attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:65