1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2010-2013 Thomas Graf <[email protected]>
4 */
5
6 /**
7 * @ingroup link
8 * @defgroup bridge Bridging
9 *
10 * @details
11 * @{
12 */
13
14 #include "nl-default.h"
15
16 #include <linux/if_bridge.h>
17
18 #include <netlink/netlink.h>
19 #include <netlink/attr.h>
20 #include <netlink/route/rtnl.h>
21 #include <netlink/route/link/bridge.h>
22
23 #include "nl-route.h"
24 #include "link-api.h"
25 #include "nl-priv-dynamic-core/nl-core.h"
26 #include "nl-priv-static-route/nl-priv-static-route.h"
27
28 #define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
29
30 /** @cond SKIP */
31 #define BRIDGE_ATTR_PORT_STATE (1 << 0)
32 #define BRIDGE_ATTR_PRIORITY (1 << 1)
33 #define BRIDGE_ATTR_COST (1 << 2)
34 #define BRIDGE_ATTR_FLAGS (1 << 3)
35 #define BRIDGE_ATTR_PORT_VLAN (1 << 4)
36 #define BRIDGE_ATTR_HWMODE (1 << 5)
37 #define BRIDGE_ATTR_CONFIG_MODE (1 << 6)
38
39 #define PRIV_FLAG_NEW_ATTRS (1 << 0)
40
41 struct bridge_data
42 {
43 uint8_t b_port_state;
44 uint8_t b_priv_flags; /* internal flags */
45 uint16_t b_hwmode;
46 uint16_t b_priority;
47 uint16_t b_config_mode;
48 uint32_t b_cost;
49 uint32_t b_flags;
50 uint32_t b_flags_mask;
51 uint32_t ce_mask; /* HACK to support attr macros */
52 struct rtnl_link_bridge_vlan vlan_info;
53 };
54
set_bit(unsigned nr,uint32_t * addr)55 static void set_bit(unsigned nr, uint32_t *addr)
56 {
57 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
58 addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
59 }
60
unset_bit(unsigned nr,uint32_t * addr)61 static void unset_bit(unsigned nr, uint32_t *addr)
62 {
63 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
64 addr[nr / 32] &= ~(((uint32_t) 1) << (nr % 32));
65 }
66
vlan_id_untagged(struct rtnl_link_bridge_vlan * vlan_info,uint16_t vid)67 static bool vlan_id_untagged(struct rtnl_link_bridge_vlan *vlan_info, uint16_t vid)
68 {
69 uint32_t mask, bit;
70
71 _nl_assert(vid / 32u < ARRAY_SIZE(vlan_info->untagged_bitmap));
72
73 mask = vlan_info->untagged_bitmap[vid / 32];
74 bit = (((uint32_t) 1) << vid % 32);
75
76 return mask & bit;
77 }
78
find_next_bit(int i,uint32_t x)79 static int find_next_bit(int i, uint32_t x)
80 {
81 int j;
82
83 if (i >= 32)
84 return -1;
85
86 /* find first bit */
87 if (i < 0)
88 return __builtin_ffs(x);
89
90 /* mask off prior finds to get next */
91 j = __builtin_ffs(x >> i);
92 return j ? j + i : 0;
93 }
94
95 static struct rtnl_link_af_ops bridge_ops;
96
97 #define IS_BRIDGE_LINK_ASSERT(link) \
98 if (!rtnl_link_is_bridge(link)) { \
99 APPBUG("A function was expecting a link object of type bridge."); \
100 return -NLE_OPNOTSUPP; \
101 }
102
bridge_data(struct rtnl_link * link)103 static inline struct bridge_data *bridge_data(struct rtnl_link *link)
104 {
105 return rtnl_link_af_data(link, &bridge_ops);
106 }
107
bridge_alloc(struct rtnl_link * link)108 static void *bridge_alloc(struct rtnl_link *link)
109 {
110 return calloc(1, sizeof(struct bridge_data));
111 }
112
bridge_clone(struct rtnl_link * link,void * data)113 static void *bridge_clone(struct rtnl_link *link, void *data)
114 {
115 struct bridge_data *bd;
116
117 if ((bd = bridge_alloc(link)))
118 memcpy(bd, data, sizeof(*bd));
119
120 return bd;
121 }
122
bridge_free(struct rtnl_link * link,void * data)123 static void bridge_free(struct rtnl_link *link, void *data)
124 {
125 free(data);
126 }
127
128 static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
129 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
130 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
131 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
132 [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
133 [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
134 [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
135 [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 },
136 [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
137 [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 },
138 [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
139 };
140
check_flag(struct rtnl_link * link,struct nlattr * attrs[],int type,int flag)141 static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
142 int type, int flag)
143 {
144 if (attrs[type] && nla_get_u8(attrs[type]))
145 rtnl_link_bridge_set_flags(link, flag);
146 }
147
bridge_parse_protinfo(struct rtnl_link * link,struct nlattr * attr,void * data)148 static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
149 void *data)
150 {
151 struct bridge_data *bd = data;
152 struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
153 int err;
154
155 /* Backwards compatibility */
156 if (!nla_is_nested(attr)) {
157 if (nla_len(attr) < 1)
158 return -NLE_RANGE;
159
160 bd->b_port_state = nla_get_u8(attr);
161 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
162
163 return 0;
164 }
165
166 if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
167 br_attrs_policy)) < 0)
168 return err;
169
170 bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
171
172 if (br_attrs[IFLA_BRPORT_STATE]) {
173 bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
174 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
175 }
176
177 if (br_attrs[IFLA_BRPORT_PRIORITY]) {
178 bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
179 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
180 }
181
182 if (br_attrs[IFLA_BRPORT_COST]) {
183 bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
184 bd->ce_mask |= BRIDGE_ATTR_COST;
185 }
186
187 check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
188 check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
189 check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
190 check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
191 check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
192 RTNL_BRIDGE_UNICAST_FLOOD);
193 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
194 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
195 RTNL_BRIDGE_LEARNING_SYNC);
196
197 return 0;
198 }
199
bridge_parse_af_full(struct rtnl_link * link,struct nlattr * attr_full,void * data)200 static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
201 void *data)
202 {
203 struct bridge_data *bd = data;
204 struct bridge_vlan_info *vinfo = NULL;
205 uint16_t vid_range_start = 0;
206 uint16_t vid_range_flags = -1;
207
208 struct nlattr *attr;
209 int remaining;
210
211 nla_for_each_nested(attr, attr_full, remaining) {
212
213 if (nla_type(attr) == IFLA_BRIDGE_MODE) {
214 bd->b_hwmode = nla_get_u16(attr);
215 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
216 continue;
217 } else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
218 continue;
219
220 if (nla_len(attr) != sizeof(struct bridge_vlan_info))
221 return -EINVAL;
222
223 vinfo = nla_data(attr);
224 if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
225 return -EINVAL;
226
227
228 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
229 vid_range_start = vinfo->vid;
230 vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
231 continue;
232 }
233
234 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
235 /* sanity check the range flags */
236 if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
237 NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
238 return -EINVAL;
239 }
240 } else {
241 vid_range_start = vinfo->vid;
242 }
243
244 for (; vid_range_start <= vinfo->vid; vid_range_start++) {
245 if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
246 bd->vlan_info.pvid = vinfo->vid;
247
248 if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
249 set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
250
251 set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
252 bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
253 }
254
255 vid_range_flags = -1;
256 }
257
258 return 0;
259 }
260
_nl_bridge_fill_vlan_info(struct nl_msg * msg,struct rtnl_link_bridge_vlan * vlan_info)261 int _nl_bridge_fill_vlan_info(struct nl_msg *msg, struct rtnl_link_bridge_vlan * vlan_info)
262 {
263 struct bridge_vlan_info vinfo;
264 int i = -1, j, k;
265 int start = -1, prev = -1;
266 int done;
267 bool untagged = false;
268
269 for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++)
270 {
271 int base_bit;
272 uint32_t a = vlan_info->vlan_bitmap[k];
273
274 base_bit = k * 32;
275 i = -1;
276 done = 0;
277 while (!done)
278 {
279 j = find_next_bit(i, a);
280 if (j > 0)
281 {
282 /* Skip if id equal to pvid */
283 if (vlan_info->pvid != 0 && j - 1 + base_bit == vlan_info->pvid)
284 goto nxt;
285 /* first hit of any bit */
286 if (start < 0 && prev < 0)
287 {
288 start = prev = j - 1 + base_bit;
289 /* Start range attribute */
290 untagged = vlan_id_untagged(vlan_info,start);
291 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
292 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
293 vinfo.vid = start;
294 goto nxt;
295 }
296 /* this bit is a continuation of prior bits */
297 if (j - 2 + base_bit == prev)
298 {
299 prev++;
300 /* Hit end of untagged/tagged range */
301 if (untagged != vlan_id_untagged(vlan_info,prev))
302 {
303 /* put vlan into attributes */
304 if (start == prev-1)
305 {
306 /* only 1 vid in range */
307 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
308 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
309 }
310 else
311 {
312 /* end of untagged/tagged range */
313 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
314
315 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
316 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
317 vinfo.vid = prev-1;
318 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
319 }
320 /* start of new range */
321 untagged = !untagged;
322 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
323 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
324 vinfo.vid = prev;
325 }
326 goto nxt;
327 }
328 }
329 else
330 done = 1;
331
332 if (start >= 0)
333 {
334 if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
335 break;
336
337 if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN && start != prev)
338 {
339 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
340
341 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
342 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
343 vinfo.vid = prev;
344 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
345 }
346 else if (start == prev)
347 {
348 vinfo.flags = untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
349 vinfo.vid = start;
350 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
351 }
352
353 if (done)
354 break;
355 }
356 if (j > 0)
357 {
358 start = prev = j - 1 + base_bit;
359 untagged = vlan_id_untagged(vlan_info,start);
360 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
361 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
362 vinfo.vid = start;
363 }
364 nxt:
365 i = j;
366 }
367 }
368
369 if (vlan_info->pvid != 0)
370 {
371 untagged = vlan_id_untagged(vlan_info,vlan_info->pvid);
372 vinfo.flags = BRIDGE_VLAN_INFO_PVID;
373 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
374 vinfo.vid = vlan_info->pvid;
375 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
376 }
377
378 return 0;
379
380 nla_put_failure:
381 return -NLE_MSGSIZE;
382 }
383
bridge_fill_af(struct rtnl_link * link,struct nl_msg * msg,void * data)384 static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
385 void *data)
386 {
387 struct bridge_data *bd = data;
388
389 if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
390 {
391 NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
392 bd->b_config_mode = BRIDGE_FLAGS_SELF;
393 bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
394 }
395
396 if (bd->ce_mask & BRIDGE_ATTR_CONFIG_MODE)
397 NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, bd->b_config_mode);
398
399 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
400 if (_nl_bridge_fill_vlan_info(msg, &bd->vlan_info)) {
401 goto nla_put_failure;
402 }
403 }
404
405 return 0;
406
407 nla_put_failure:
408 return -NLE_MSGSIZE;
409 }
410
bridge_fill_pi(struct rtnl_link * link,struct nl_msg * msg,void * data)411 static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
412 void *data)
413 {
414 struct bridge_data *bd = data;
415
416 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
417 if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
418 NLA_PUT_U8(msg, IFLA_BRPORT_GUARD,
419 bd->b_flags & RTNL_BRIDGE_BPDU_GUARD);
420 }
421 if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
422 NLA_PUT_U8(msg, IFLA_BRPORT_MODE,
423 bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE);
424 }
425 if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
426 NLA_PUT_U8(msg, IFLA_BRPORT_FAST_LEAVE,
427 bd->b_flags & RTNL_BRIDGE_FAST_LEAVE);
428 }
429 if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
430 NLA_PUT_U8(msg, IFLA_BRPORT_PROTECT,
431 bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK);
432 }
433 if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
434 NLA_PUT_U8(msg, IFLA_BRPORT_UNICAST_FLOOD,
435 bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD);
436 }
437 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
438 NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING,
439 bd->b_flags & RTNL_BRIDGE_LEARNING);
440 }
441 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
442 NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING_SYNC,
443 bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC);
444 }
445 }
446
447 if (bd->ce_mask & BRIDGE_ATTR_COST)
448 NLA_PUT_U32(msg, IFLA_BRPORT_COST, bd->b_cost);
449
450 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
451 NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
452
453 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
454 NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
455
456 return 0;
457
458 nla_put_failure:
459 return -NLE_MSGSIZE;
460 }
461
bridge_override_rtm(struct rtnl_link * link)462 static int bridge_override_rtm(struct rtnl_link *link) {
463 struct bridge_data *bd;
464
465 if (!rtnl_link_is_bridge(link))
466 return 0;
467
468 bd = bridge_data(link);
469
470 if (bd->ce_mask & BRIDGE_ATTR_FLAGS)
471 return 1;
472
473 return 0;
474 }
475
bridge_get_af(struct nl_msg * msg,uint32_t * ext_filter_mask)476 static int bridge_get_af(struct nl_msg *msg, uint32_t *ext_filter_mask)
477 {
478 *ext_filter_mask |= RTEXT_FILTER_BRVLAN;
479 return 0;
480 }
481
dump_bitmap(struct nl_dump_params * p,const uint32_t * b)482 static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b)
483 {
484 int i = -1, j, k;
485 int start = -1, prev = -1;
486 int done, found = 0;
487
488 for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
489 int base_bit;
490 uint32_t a = b[k];
491
492 base_bit = k * 32;
493 i = -1;
494 done = 0;
495 while (!done) {
496 j = find_next_bit(i, a);
497 if (j > 0) {
498 /* first hit of any bit */
499 if (start < 0 && prev < 0) {
500 start = prev = j - 1 + base_bit;
501 goto next;
502 }
503 /* this bit is a continuation of prior bits */
504 if (j - 2 + base_bit == prev) {
505 prev++;
506 goto next;
507 }
508 } else
509 done = 1;
510
511 if (start >= 0) {
512 found++;
513 if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
514 break;
515
516 nl_dump(p, " %d", start);
517 if (start != prev)
518 nl_dump(p, "-%d", prev);
519
520 if (done)
521 break;
522 }
523 if (j > 0)
524 start = prev = j - 1 + base_bit;
525 next:
526 i = j;
527 }
528 }
529 if (!found)
530 nl_dump(p, " <none>");
531
532 return;
533 }
534
rtnl_link_bridge_dump_vlans(struct nl_dump_params * p,struct bridge_data * bd)535 static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p,
536 struct bridge_data *bd)
537 {
538 nl_dump(p, "pvid %u", bd->vlan_info.pvid);
539
540 nl_dump(p, " all vlans:");
541 dump_bitmap(p, bd->vlan_info.vlan_bitmap);
542
543 nl_dump(p, " untagged vlans:");
544 dump_bitmap(p, bd->vlan_info.untagged_bitmap);
545 }
546
bridge_dump_details(struct rtnl_link * link,struct nl_dump_params * p,void * data)547 static void bridge_dump_details(struct rtnl_link *link,
548 struct nl_dump_params *p, void *data)
549 {
550 struct bridge_data *bd = data;
551
552 nl_dump_line(p, " bridge: ");
553
554 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
555 nl_dump(p, "port-state %u ", bd->b_port_state);
556
557 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
558 nl_dump(p, "prio %u ", bd->b_priority);
559
560 if (bd->ce_mask & BRIDGE_ATTR_COST)
561 nl_dump(p, "cost %u ", bd->b_cost);
562
563 if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
564 char hbuf[32];
565
566 rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
567 nl_dump(p, "hwmode %s", hbuf);
568 }
569
570 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
571 rtnl_link_bridge_dump_vlans(p, bd);
572
573 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
574 char buf[256];
575
576 rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
577 buf, sizeof(buf));
578 nl_dump(p, "%s", buf);
579 }
580
581 nl_dump(p, "\n");
582 }
583
bridge_compare(struct rtnl_link * _a,struct rtnl_link * _b,int family,uint32_t attrs,int flags)584 static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
585 int family, uint32_t attrs, int flags)
586 {
587 struct bridge_data *a = bridge_data(_a);
588 struct bridge_data *b = bridge_data(_b);
589 int diff = 0;
590
591 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
592 diff |= _DIFF(BRIDGE_ATTR_PORT_STATE,
593 a->b_port_state != b->b_port_state);
594 diff |= _DIFF(BRIDGE_ATTR_PRIORITY, a->b_priority != b->b_priority);
595 diff |= _DIFF(BRIDGE_ATTR_COST, a->b_cost != b->b_cost);
596 diff |= _DIFF(BRIDGE_ATTR_PORT_VLAN,
597 memcmp(&a->vlan_info, &b->vlan_info,
598 sizeof(struct rtnl_link_bridge_vlan)));
599 diff |= _DIFF(BRIDGE_ATTR_HWMODE, a->b_hwmode != b->b_hwmode);
600 diff |= _DIFF(BRIDGE_ATTR_CONFIG_MODE, a->b_config_mode != b->b_config_mode);
601
602 if (flags & LOOSE_COMPARISON)
603 diff |= _DIFF(BRIDGE_ATTR_FLAGS,
604 (a->b_flags ^ b->b_flags) & b->b_flags_mask);
605 else
606 diff |= _DIFF(BRIDGE_ATTR_FLAGS, a->b_flags != b->b_flags);
607 #undef _DIFF
608
609 return diff;
610 }
611 /** @endcond */
612
613 /**
614 * Allocate link object of type bridge
615 *
616 * @return Allocated link object or NULL.
617 */
rtnl_link_bridge_alloc(void)618 struct rtnl_link *rtnl_link_bridge_alloc(void)
619 {
620 struct rtnl_link *link;
621
622 if (!(link = rtnl_link_alloc()))
623 return NULL;
624
625 if (rtnl_link_set_type(link, "bridge") < 0) {
626 rtnl_link_put(link);
627 return NULL;
628 }
629
630 return link;
631 }
632
633 /**
634 * Create a new kernel bridge device
635 * @arg sk netlink socket
636 * @arg name name of the bridge device or NULL
637 *
638 * Creates a new bridge device in the kernel. If no name is
639 * provided, the kernel will automatically pick a name of the
640 * form "type%d" (e.g. bridge0, vlan1, etc.)
641 *
642 * @return 0 on success or a negative error code
643 */
rtnl_link_bridge_add(struct nl_sock * sk,const char * name)644 int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
645 {
646 int err;
647 struct rtnl_link *link;
648
649 if (!(link = rtnl_link_bridge_alloc()))
650 return -NLE_NOMEM;
651
652 if(name)
653 rtnl_link_set_name(link, name);
654
655 err = rtnl_link_add(sk, link, NLM_F_CREATE);
656 rtnl_link_put(link);
657
658 return err;
659 }
660
661 /**
662 * Check if a link is a bridge
663 * @arg link Link object
664 *
665 * @return 1 if the link is a bridge, 0 otherwise.
666 */
rtnl_link_is_bridge(struct rtnl_link * link)667 int rtnl_link_is_bridge(struct rtnl_link *link)
668 {
669 return link->l_family == AF_BRIDGE &&
670 link->l_af_ops == &bridge_ops;
671 }
672
673 /**
674 * Check if bridge has extended information
675 * @arg link Link object of type bridge
676 *
677 * Checks if the bridge object has been constructed based on
678 * information that is only available in newer kernels. This
679 * affectes the following functions:
680 * - rtnl_link_bridge_get_cost()
681 * - rtnl_link_bridge_get_priority()
682 * - rtnl_link_bridge_get_flags()
683 *
684 * @return 1 if extended information is available, otherwise 0 is returned.
685 */
rtnl_link_bridge_has_ext_info(struct rtnl_link * link)686 int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
687 {
688 struct bridge_data *bd;
689
690 if (!rtnl_link_is_bridge(link))
691 return 0;
692
693 bd = bridge_data(link);
694 return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
695 }
696
697 /**
698 * Set Spanning Tree Protocol (STP) port state
699 * @arg link Link object of type bridge
700 * @arg state New STP port state
701 *
702 * The value of state must be one of the following:
703 * - BR_STATE_DISABLED
704 * - BR_STATE_LISTENING
705 * - BR_STATE_LEARNING
706 * - BR_STATE_FORWARDING
707 * - BR_STATE_BLOCKING
708 *
709 * @see rtnl_link_bridge_get_port_state()
710 *
711 * @return 0 on success or a negative error code.
712 * @retval -NLE_OPNOTSUPP Link is not a bridge
713 * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
714 */
rtnl_link_bridge_set_port_state(struct rtnl_link * link,uint8_t state)715 int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
716 {
717 struct bridge_data *bd = bridge_data(link);
718
719 IS_BRIDGE_LINK_ASSERT(link);
720
721 if (state > BR_STATE_BLOCKING)
722 return -NLE_INVAL;
723
724 bd->b_port_state = state;
725 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
726
727 return 0;
728 }
729
730 /**
731 * Get Spanning Tree Protocol (STP) port state
732 * @arg link Link object of type bridge
733 *
734 * @see rtnl_link_bridge_set_port_state()
735 *
736 * @return The STP port state or a negative error code.
737 * @retval -NLE_OPNOTSUPP Link is not a bridge
738 */
rtnl_link_bridge_get_port_state(struct rtnl_link * link)739 int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
740 {
741 struct bridge_data *bd = bridge_data(link);
742
743 IS_BRIDGE_LINK_ASSERT(link);
744
745 return bd->b_port_state;
746 }
747
748 /**
749 * Set priority
750 * @arg link Link object of type bridge
751 * @arg prio Bridge priority
752 *
753 * @see rtnl_link_bridge_get_priority()
754 *
755 * @return 0 on success or a negative error code.
756 * @retval -NLE_OPNOTSUPP Link is not a bridge
757 */
rtnl_link_bridge_set_priority(struct rtnl_link * link,uint16_t prio)758 int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
759 {
760 struct bridge_data *bd = bridge_data(link);
761
762 IS_BRIDGE_LINK_ASSERT(link);
763
764 bd->b_priority = prio;
765 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
766
767 return 0;
768 }
769
770 /**
771 * Get priority
772 * @arg link Link object of type bridge
773 *
774 * @see rtnl_link_bridge_set_priority()
775 *
776 * @return 0 on success or a negative error code.
777 * @retval -NLE_OPNOTSUPP Link is not a bridge
778 */
rtnl_link_bridge_get_priority(struct rtnl_link * link)779 int rtnl_link_bridge_get_priority(struct rtnl_link *link)
780 {
781 struct bridge_data *bd = bridge_data(link);
782
783 IS_BRIDGE_LINK_ASSERT(link);
784
785 return bd->b_priority;
786 }
787
788 /**
789 * Set Spanning Tree Protocol (STP) path cost
790 * @arg link Link object of type bridge
791 * @arg cost New STP path cost value
792 *
793 * @see rtnl_link_bridge_get_cost()
794 *
795 * @return The bridge priority or a negative error code.
796 * @retval -NLE_OPNOTSUPP Link is not a bridge
797 */
rtnl_link_bridge_set_cost(struct rtnl_link * link,uint32_t cost)798 int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
799 {
800 struct bridge_data *bd = bridge_data(link);
801
802 IS_BRIDGE_LINK_ASSERT(link);
803
804 bd->b_cost = cost;
805 bd->ce_mask |= BRIDGE_ATTR_COST;
806
807 return 0;
808 }
809
810 /**
811 * Get Spanning Tree Protocol (STP) path cost
812 * @arg link Link object of type bridge
813 * @arg cost Pointer to store STP cost value
814 *
815 * @see rtnl_link_bridge_set_cost()
816 *
817 * @return 0 on success or a negative error code.
818 * @retval -NLE_OPNOTSUPP Link is not a bridge
819 * @retval -NLE_INVAL `cost` is not a valid pointer
820 */
rtnl_link_bridge_get_cost(struct rtnl_link * link,uint32_t * cost)821 int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
822 {
823 struct bridge_data *bd = bridge_data(link);
824
825 IS_BRIDGE_LINK_ASSERT(link);
826
827 if (!cost)
828 return -NLE_INVAL;
829
830 *cost = bd->b_cost;
831
832 return 0;
833 }
834
835 /**
836 * Unset flags
837 * @arg link Link object of type bridge
838 * @arg flags Bridging flags to unset
839 *
840 * @see rtnl_link_bridge_set_flags()
841 * @see rtnl_link_bridge_get_flags()
842 *
843 * @return 0 on success or a negative error code.
844 * @retval -NLE_OPNOTSUPP Link is not a bridge
845 */
rtnl_link_bridge_unset_flags(struct rtnl_link * link,unsigned int flags)846 int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
847 {
848 struct bridge_data *bd = bridge_data(link);
849
850 IS_BRIDGE_LINK_ASSERT(link);
851
852 bd->b_flags_mask |= flags;
853 bd->b_flags &= ~flags;
854 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
855
856 return 0;
857 }
858
859 /**
860 * Set flags
861 * @arg link Link object of type bridge
862 * @arg flags Bridging flags to set
863 *
864 * Valid flags are:
865 * - RTNL_BRIDGE_HAIRPIN_MODE
866 * - RTNL_BRIDGE_BPDU_GUARD
867 * - RTNL_BRIDGE_ROOT_BLOCK
868 * - RTNL_BRIDGE_FAST_LEAVE
869 * - RTNL_BRIDGE_UNICAST_FLOOD
870 * - RTNL_BRIDGE_LEARNING
871 * - RTNL_BRIDGE_LEARNING_SYNC
872 *
873 * @see rtnl_link_bridge_unset_flags()
874 * @see rtnl_link_bridge_get_flags()
875 *
876 * @return 0 on success or a negative error code.
877 * @retval -NLE_OPNOTSUPP Link is not a bridge
878 */
rtnl_link_bridge_set_flags(struct rtnl_link * link,unsigned int flags)879 int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
880 {
881 struct bridge_data *bd = bridge_data(link);
882
883 IS_BRIDGE_LINK_ASSERT(link);
884
885 bd->b_flags_mask |= flags;
886 bd->b_flags |= flags;
887 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
888
889 return 0;
890 }
891
892 /**
893 * Get flags
894 * @arg link Link object of type bridge
895 *
896 * @see rtnl_link_bridge_set_flags()
897 * @see rtnl_link_bridge_unset_flags()
898 *
899 * @return Flags or a negative error code.
900 * @retval -NLE_OPNOTSUPP Link is not a bridge
901 */
rtnl_link_bridge_get_flags(struct rtnl_link * link)902 int rtnl_link_bridge_get_flags(struct rtnl_link *link)
903 {
904 struct bridge_data *bd = bridge_data(link);
905
906 IS_BRIDGE_LINK_ASSERT(link);
907
908 return bd->b_flags;
909 }
910
911 /**
912 * Set link change type to self
913 * @arg link Link Object of type bridge
914 *
915 * This will set the bridge change flag to self, meaning that changes to
916 * be applied with this link object will be applied directly to the physical
917 * device in a bridge instead of the virtual device.
918 *
919 * @return 0 on success or negative error code
920 * @return -NLE_OPNOTSUP Link is not a bridge
921 */
rtnl_link_bridge_set_self(struct rtnl_link * link)922 int rtnl_link_bridge_set_self(struct rtnl_link *link)
923 {
924 struct bridge_data *bd = bridge_data(link);
925
926 IS_BRIDGE_LINK_ASSERT(link);
927
928 bd->b_config_mode = BRIDGE_FLAGS_SELF;
929 bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
930
931 return 0;
932 }
933
934 /**
935 * Set link change type to master
936 * @arg link Link Object of type bridge
937 *
938 * This will set the bridge change flag to master, meaning that changes to
939 * be applied with this link object will be applied directly to the virtual
940 * device in a bridge instead of the physical device.
941 *
942 * @return 0 on success or negative error code
943 * @return -NLE_OPNOTSUP Link is not a bridge
944 */
rtnl_link_bridge_set_master(struct rtnl_link * link)945 int rtnl_link_bridge_set_master(struct rtnl_link *link)
946 {
947 struct bridge_data *bd = bridge_data(link);
948
949 IS_BRIDGE_LINK_ASSERT(link);
950
951 bd->b_config_mode = BRIDGE_FLAGS_MASTER;
952 bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
953
954 return 0;
955 }
956
957 /**
958 * Get hardware mode
959 * @arg link Link object of type bridge
960 * @arg hwmode Output argument.
961 *
962 * @see rtnl_link_bridge_set_hwmode()
963 *
964 * @return 0 if hardware mode is present and returned in hwmode
965 * @return -NLE_NOATTR if hardware mode is not present
966 * @return -NLE_OPNOTSUP Link is not a bridge
967 */
rtnl_link_bridge_get_hwmode(struct rtnl_link * link,uint16_t * hwmode)968 int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
969 {
970 struct bridge_data *bd = bridge_data(link);
971
972 IS_BRIDGE_LINK_ASSERT(link);
973
974 if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
975 return -NLE_NOATTR;
976
977 *hwmode = bd->b_hwmode;
978 return 0;
979 }
980
981 /**
982 * Set hardware mode
983 * @arg link Link object of type bridge
984 * @arg hwmode Hardware mode to set on link
985 *
986 * This will set the hardware mode of a link when it supports hardware
987 * offloads for bridging.
988 * @see rtnl_link_bridge_get_hwmode()
989 *
990 * Valid modes are:
991 * - RTNL_BRIDGE_HWMODE_VEB
992 * - RTNL_BRIDGE_HWMODE_VEPA
993 *
994 * When setting hardware mode, the change type will be set to self.
995 * @see rtnl_link_bridge_set_self()
996 *
997 * @return 0 on success or negative error code
998 * @return -NLE_OPNOTSUP Link is not a bridge
999 * @return -NLE_INVAL when specified hwmode is unsupported.
1000 */
rtnl_link_bridge_set_hwmode(struct rtnl_link * link,uint16_t hwmode)1001 int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
1002 {
1003 int err;
1004 struct bridge_data *bd = bridge_data(link);
1005
1006 if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
1007 return -NLE_INVAL;
1008
1009 if ((err = rtnl_link_bridge_set_self(link)) < 0)
1010 return err;
1011
1012 bd->b_hwmode = hwmode;
1013 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
1014
1015 return 0;
1016 }
1017
1018
1019 static const struct trans_tbl bridge_flags[] = {
1020 __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
1021 __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
1022 __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block),
1023 __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave),
1024 __ADD(RTNL_BRIDGE_UNICAST_FLOOD, flood),
1025 __ADD(RTNL_BRIDGE_LEARNING, learning),
1026 __ADD(RTNL_BRIDGE_LEARNING_SYNC, learning_sync),
1027 };
1028
1029 /**
1030 * @name Flag Translation
1031 * @{
1032 */
1033
rtnl_link_bridge_flags2str(int flags,char * buf,size_t len)1034 char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
1035 {
1036 return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
1037 }
1038
rtnl_link_bridge_str2flags(const char * name)1039 int rtnl_link_bridge_str2flags(const char *name)
1040 {
1041 return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
1042 }
1043
1044 /** @} */
1045
1046 static const struct trans_tbl port_states[] = {
1047 __ADD(BR_STATE_DISABLED, disabled),
1048 __ADD(BR_STATE_LISTENING, listening),
1049 __ADD(BR_STATE_LEARNING, learning),
1050 __ADD(BR_STATE_FORWARDING, forwarding),
1051 __ADD(BR_STATE_BLOCKING, blocking),
1052 };
1053
1054 /**
1055 * @name Port State Translation
1056 * @{
1057 */
1058
rtnl_link_bridge_portstate2str(int st,char * buf,size_t len)1059 char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
1060 {
1061 return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
1062 }
1063
rtnl_link_bridge_str2portstate(const char * name)1064 int rtnl_link_bridge_str2portstate(const char *name)
1065 {
1066 return __str2type(name, port_states, ARRAY_SIZE(port_states));
1067 }
1068
1069 /** @} */
1070
1071 static const struct trans_tbl hw_modes[] = {
1072 __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
1073 __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
1074 __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
1075 };
1076
1077 /**
1078 * @name Hardware Mode Translation
1079 * @{
1080 */
1081
rtnl_link_bridge_hwmode2str(uint16_t st,char * buf,size_t len)1082 char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
1083 return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
1084 }
1085
rtnl_link_bridge_str2hwmode(const char * name)1086 uint16_t rtnl_link_bridge_str2hwmode(const char *name)
1087 {
1088 return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
1089 }
1090
1091 /** @} */
1092
1093 /**
1094 * Enable the ability to set vlan info
1095 * @arg link Link object of type bridge
1096 *
1097 * @return 0 on success or negative error code
1098 * @return -NLE_OPNOTSUP Link is not a bridge
1099 */
rtnl_link_bridge_enable_vlan(struct rtnl_link * link)1100 int rtnl_link_bridge_enable_vlan(struct rtnl_link *link)
1101 {
1102 struct bridge_data *bd = bridge_data(link);
1103
1104 IS_BRIDGE_LINK_ASSERT(link);
1105
1106 bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
1107
1108 return 0;
1109 }
1110
1111 /**
1112 * @name Quality of Service
1113 * @{
1114 */
1115
1116 /**
1117 * Set port vlan membership range
1118 * @arg link Link object of type bridge
1119 * @arg start Start of membership range.
1120 * @arg end End of membership range.
1121 * @arg untagged Set membership range to be untagged.
1122 *
1123 * This will set the vlan membership range for a bridge port.
1124 * This will unset the untagged membership if untagged is false.
1125 * Supported range is 1-4094
1126 *
1127 * @return 0 on success or negative error code
1128 * @return -NLE_NOATTR if port vlan attribute not present
1129 * @return -NLE_OPNOTSUP Link is not a bridge
1130 * @return -NLE_INVAL range is not in supported range.
1131 */
rtnl_link_bridge_set_port_vlan_map_range(struct rtnl_link * link,uint16_t start,uint16_t end,int untagged)1132 int rtnl_link_bridge_set_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end, int untagged)
1133 {
1134 struct rtnl_link_bridge_vlan * vinfo;
1135
1136 IS_BRIDGE_LINK_ASSERT(link);
1137
1138 vinfo = rtnl_link_bridge_get_port_vlan(link);
1139
1140 if (!vinfo)
1141 return -NLE_NOATTR;
1142
1143 if (start == 0 || start > end || end >= VLAN_VID_MASK)
1144 return -NLE_INVAL;
1145
1146 for (uint16_t i = start; i <= end; i++)
1147 {
1148 set_bit(i,vinfo->vlan_bitmap);
1149 if (untagged) {
1150 set_bit(i,vinfo->untagged_bitmap);
1151 } else {
1152 unset_bit(i,vinfo->untagged_bitmap);
1153 }
1154 }
1155 return 0;
1156 }
1157
1158 /**
1159 * Unset port vlan membership range
1160 * @arg link Link object of type bridge
1161 * @arg start Start of membership range.
1162 * @arg end End of membership range.
1163 *
1164 * This will unset the vlan membership range for a bridge port
1165 * for both tagged and untagged membership.
1166 * Supported range is 1-4094
1167 *
1168 * @return 0 on success or negative error code
1169 * @return -NLE_NOATTR if port vlan attribute not present
1170 * @return -NLE_OPNOTSUP Link is not a bridge
1171 * @return -NLE_INVAL range is not in supported range.
1172 */
rtnl_link_bridge_unset_port_vlan_map_range(struct rtnl_link * link,uint16_t start,uint16_t end)1173 int rtnl_link_bridge_unset_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end)
1174 {
1175 struct rtnl_link_bridge_vlan * vinfo;
1176
1177 IS_BRIDGE_LINK_ASSERT(link);
1178
1179 vinfo = rtnl_link_bridge_get_port_vlan(link);
1180
1181 if (!vinfo)
1182 return -NLE_NOATTR;
1183
1184 if (start == 0 || start > end || end >= VLAN_VID_MASK)
1185 return -NLE_INVAL;
1186
1187 for (uint16_t i = start; i <= end; i++)
1188 {
1189 unset_bit(i,vinfo->vlan_bitmap);
1190 unset_bit(i,vinfo->untagged_bitmap);
1191 }
1192 return 0;
1193 }
1194
1195 /**
1196 * Set port primary vlan id
1197 * @arg link Link object of type bridge
1198 * @arg pvid PVID to set.
1199 * @arg untagged Set vlan id to be untagged.
1200 *
1201 * This will set the primary vlan id for a bridge port.
1202 * Supported range is 0-4094, Setting pvid to 0 will unset it.
1203 * You will most likely want to set/unset pvid in the vlan map.
1204 * @see rtnl_link_bridge_set_port_vlan_map_range()
1205 * @see rtnl_link_bridge_unset_port_vlan_map_range()
1206 *
1207 * @return 0 on success or negative error code
1208 * @return -NLE_NOATTR if port vlan attribute not present
1209 * @return -NLE_OPNOTSUP Link is not a bridge
1210 * @return -NLE_INVAL PVID is above supported range.
1211 */
rtnl_link_bridge_set_port_vlan_pvid(struct rtnl_link * link,uint16_t pvid)1212 int rtnl_link_bridge_set_port_vlan_pvid (struct rtnl_link *link, uint16_t pvid)
1213 {
1214 struct rtnl_link_bridge_vlan * vinfo;
1215
1216 IS_BRIDGE_LINK_ASSERT(link);
1217
1218 vinfo = rtnl_link_bridge_get_port_vlan(link);
1219
1220 if (!vinfo)
1221 return -NLE_NOATTR;
1222
1223 if (pvid >= VLAN_VID_MASK)
1224 return -NLE_INVAL;
1225
1226 vinfo->pvid = pvid;
1227
1228 return 0;
1229 }
1230
1231 /** @} */
1232
rtnl_link_bridge_pvid(struct rtnl_link * link)1233 int rtnl_link_bridge_pvid(struct rtnl_link *link)
1234 {
1235 struct bridge_data *bd;
1236
1237 IS_BRIDGE_LINK_ASSERT(link);
1238
1239 bd = link->l_af_data[AF_BRIDGE];
1240 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
1241 return (int) bd->vlan_info.pvid;
1242
1243 return -EINVAL;
1244 }
1245
rtnl_link_bridge_has_vlan(struct rtnl_link * link)1246 int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
1247 {
1248 struct bridge_data *bd;
1249 int i;
1250
1251 IS_BRIDGE_LINK_ASSERT(link);
1252
1253 bd = link->l_af_data[AF_BRIDGE];
1254 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
1255 if (bd->vlan_info.pvid)
1256 return 1;
1257
1258 for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
1259 if (bd->vlan_info.vlan_bitmap[i] ||
1260 bd->vlan_info.untagged_bitmap[i])
1261 return 1;
1262 }
1263 }
1264 return 0;
1265 }
1266
rtnl_link_bridge_get_port_vlan(struct rtnl_link * link)1267 struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
1268 {
1269 struct bridge_data *data;
1270
1271 if (!rtnl_link_is_bridge(link))
1272 return NULL;
1273
1274 data = link->l_af_data[AF_BRIDGE];
1275 if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
1276 return &data->vlan_info;
1277
1278 return NULL;
1279 }
1280
1281 static struct rtnl_link_af_ops bridge_ops = {
1282 .ao_family = AF_BRIDGE,
1283 .ao_alloc = &bridge_alloc,
1284 .ao_clone = &bridge_clone,
1285 .ao_free = &bridge_free,
1286 .ao_parse_protinfo = &bridge_parse_protinfo,
1287 .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
1288 .ao_compare = &bridge_compare,
1289 .ao_parse_af_full = &bridge_parse_af_full,
1290 .ao_get_af = &bridge_get_af,
1291 .ao_fill_af = &bridge_fill_af,
1292 .ao_fill_pi = &bridge_fill_pi,
1293 .ao_fill_pi_flags = NLA_F_NESTED,
1294 .ao_override_rtm = &bridge_override_rtm,
1295 .ao_fill_af_no_nest = 1,
1296 };
1297
bridge_init(void)1298 static void _nl_init bridge_init(void)
1299 {
1300 rtnl_link_af_register(&bridge_ops);
1301 }
1302
bridge_exit(void)1303 static void _nl_exit bridge_exit(void)
1304 {
1305 rtnl_link_af_unregister(&bridge_ops);
1306 }
1307
1308 /** @} */
1309