xref: /aosp_15_r20/external/libnl/lib/route/link/bridge_info.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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