libnl 3.7.0
bridge.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch>
4 */
5
6/**
7 * @ingroup link
8 * @defgroup bridge Bridging
9 *
10 * @details
11 * @{
12 */
13
14#include <netlink-private/netlink.h>
15#include <netlink/netlink.h>
16#include <netlink/attr.h>
17#include <netlink/route/rtnl.h>
18#include <netlink/route/link/bridge.h>
19#include <netlink-private/route/link/api.h>
20#include <linux/if_bridge.h>
21
22#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
23
24/** @cond SKIP */
25#define BRIDGE_ATTR_PORT_STATE (1 << 0)
26#define BRIDGE_ATTR_PRIORITY (1 << 1)
27#define BRIDGE_ATTR_COST (1 << 2)
28#define BRIDGE_ATTR_FLAGS (1 << 3)
29#define BRIDGE_ATTR_PORT_VLAN (1 << 4)
30#define BRIDGE_ATTR_HWMODE (1 << 5)
31#define BRIDGE_ATTR_SELF (1 << 6)
32
33#define PRIV_FLAG_NEW_ATTRS (1 << 0)
34
35struct bridge_data
36{
37 uint8_t b_port_state;
38 uint8_t b_priv_flags; /* internal flags */
39 uint16_t b_hwmode;
40 uint16_t b_priority;
41 uint16_t b_self; /* here for comparison reasons */
42 uint32_t b_cost;
43 uint32_t b_flags;
44 uint32_t b_flags_mask;
45 uint32_t ce_mask; /* HACK to support attr macros */
46 struct rtnl_link_bridge_vlan vlan_info;
47};
48
49static void set_bit(unsigned nr, uint32_t *addr)
50{
51 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
52 addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
53}
54
55static int find_next_bit(int i, uint32_t x)
56{
57 int j;
58
59 if (i >= 32)
60 return -1;
61
62 /* find first bit */
63 if (i < 0)
64 return __builtin_ffs(x);
65
66 /* mask off prior finds to get next */
67 j = __builtin_ffs(x >> i);
68 return j ? j + i : 0;
69}
70
71static struct rtnl_link_af_ops bridge_ops;
72
73#define IS_BRIDGE_LINK_ASSERT(link) \
74 if (!rtnl_link_is_bridge(link)) { \
75 APPBUG("A function was expecting a link object of type bridge."); \
76 return -NLE_OPNOTSUPP; \
77 }
78
79static inline struct bridge_data *bridge_data(struct rtnl_link *link)
80{
81 return rtnl_link_af_data(link, &bridge_ops);
82}
83
84static void *bridge_alloc(struct rtnl_link *link)
85{
86 return calloc(1, sizeof(struct bridge_data));
87}
88
89static void *bridge_clone(struct rtnl_link *link, void *data)
90{
91 struct bridge_data *bd;
92
93 if ((bd = bridge_alloc(link)))
94 memcpy(bd, data, sizeof(*bd));
95
96 return bd;
97}
98
99static void bridge_free(struct rtnl_link *link, void *data)
100{
101 free(data);
102}
103
104static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
105 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
106 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
107 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
108 [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
109 [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
110 [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
111 [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 },
112 [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
113 [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 },
114 [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
115};
116
117static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
118 int type, int flag)
119{
120 if (attrs[type] && nla_get_u8(attrs[type]))
121 rtnl_link_bridge_set_flags(link, flag);
122}
123
124static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
125 void *data)
126{
127 struct bridge_data *bd = data;
128 struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
129 int err;
130
131 /* Backwards compatibility */
132 if (!nla_is_nested(attr)) {
133 if (nla_len(attr) < 1)
134 return -NLE_RANGE;
135
136 bd->b_port_state = nla_get_u8(attr);
137 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
138
139 return 0;
140 }
141
142 if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
143 br_attrs_policy)) < 0)
144 return err;
145
146 bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
147
148 if (br_attrs[IFLA_BRPORT_STATE]) {
149 bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
150 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
151 }
152
153 if (br_attrs[IFLA_BRPORT_PRIORITY]) {
154 bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
155 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
156 }
157
158 if (br_attrs[IFLA_BRPORT_COST]) {
159 bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
160 bd->ce_mask |= BRIDGE_ATTR_COST;
161 }
162
163 check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
164 check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
165 check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
166 check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
167 check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
168 RTNL_BRIDGE_UNICAST_FLOOD);
169 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
170 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
171 RTNL_BRIDGE_LEARNING_SYNC);
172
173 return 0;
174}
175
176static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
177 void *data)
178{
179 struct bridge_data *bd = data;
180 struct bridge_vlan_info *vinfo = NULL;
181 uint16_t vid_range_start = 0;
182 uint16_t vid_range_flags = -1;
183
184 struct nlattr *attr;
185 int remaining;
186
187 nla_for_each_nested(attr, attr_full, remaining) {
188
189 if (nla_type(attr) == IFLA_BRIDGE_MODE) {
190 bd->b_hwmode = nla_get_u16(attr);
191 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
192 } else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
193 continue;
194
195 if (nla_len(attr) != sizeof(struct bridge_vlan_info))
196 return -EINVAL;
197
198 vinfo = nla_data(attr);
199 if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
200 return -EINVAL;
201
202
203 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
204 vid_range_start = vinfo->vid;
205 vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
206 continue;
207 }
208
209 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
210 /* sanity check the range flags */
211 if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
212 NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
213 return -EINVAL;
214 }
215 } else {
216 vid_range_start = vinfo->vid;
217 }
218
219 for (; vid_range_start <= vinfo->vid; vid_range_start++) {
220 if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
221 bd->vlan_info.pvid = vinfo->vid;
222
223 if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
224 set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
225
226 set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
227 bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
228 }
229
230 vid_range_flags = -1;
231 }
232
233 return 0;
234}
235
236static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
237 void *data)
238{
239 struct bridge_data *bd = data;
240
241 if ((bd->ce_mask & BRIDGE_ATTR_SELF)||(bd->ce_mask & BRIDGE_ATTR_HWMODE))
242 NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
243
244 if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
245 NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
246
247 return 0;
248
249nla_put_failure:
250 return -NLE_MSGSIZE;
251}
252
253static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
254 void *data)
255{
256 struct bridge_data *bd = data;
257
258 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
259 if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
260 NLA_PUT_U8(msg, IFLA_BRPORT_GUARD,
261 bd->b_flags & RTNL_BRIDGE_BPDU_GUARD);
262 }
263 if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
264 NLA_PUT_U8(msg, IFLA_BRPORT_MODE,
265 bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE);
266 }
267 if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
268 NLA_PUT_U8(msg, IFLA_BRPORT_FAST_LEAVE,
269 bd->b_flags & RTNL_BRIDGE_FAST_LEAVE);
270 }
271 if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
272 NLA_PUT_U8(msg, IFLA_BRPORT_PROTECT,
273 bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK);
274 }
275 if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
276 NLA_PUT_U8(msg, IFLA_BRPORT_UNICAST_FLOOD,
277 bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD);
278 }
279 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
280 NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING,
281 bd->b_flags & RTNL_BRIDGE_LEARNING);
282 }
283 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
284 NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING_SYNC,
285 bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC);
286 }
287 }
288
289 if (bd->ce_mask & BRIDGE_ATTR_COST)
290 NLA_PUT_U32(msg, IFLA_BRPORT_COST, bd->b_cost);
291
292 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
293 NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
294
295 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
296 NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
297
298 return 0;
299
300nla_put_failure:
301 return -NLE_MSGSIZE;
302}
303
304static int bridge_override_rtm(struct rtnl_link *link) {
305 struct bridge_data *bd;
306
307 if (!rtnl_link_is_bridge(link))
308 return 0;
309
310 bd = bridge_data(link);
311
312 if (bd->ce_mask & BRIDGE_ATTR_FLAGS)
313 return 1;
314
315 return 0;
316}
317
318static int bridge_get_af(struct nl_msg *msg, uint32_t *ext_filter_mask)
319{
320 *ext_filter_mask |= RTEXT_FILTER_BRVLAN;
321 return 0;
322}
323
324static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b)
325{
326 int i = -1, j, k;
327 int start = -1, prev = -1;
328 int done, found = 0;
329
330 for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
331 int base_bit;
332 uint32_t a = b[k];
333
334 base_bit = k * 32;
335 i = -1;
336 done = 0;
337 while (!done) {
338 j = find_next_bit(i, a);
339 if (j > 0) {
340 /* first hit of any bit */
341 if (start < 0 && prev < 0) {
342 start = prev = j - 1 + base_bit;
343 goto next;
344 }
345 /* this bit is a continuation of prior bits */
346 if (j - 2 + base_bit == prev) {
347 prev++;
348 goto next;
349 }
350 } else
351 done = 1;
352
353 if (start >= 0) {
354 found++;
355 if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
356 break;
357
358 nl_dump(p, " %d", start);
359 if (start != prev)
360 nl_dump(p, "-%d", prev);
361
362 if (done)
363 break;
364 }
365 if (j > 0)
366 start = prev = j - 1 + base_bit;
367next:
368 i = j;
369 }
370 }
371 if (!found)
372 nl_dump(p, " <none>");
373
374 return;
375}
376
377static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p,
378 struct bridge_data *bd)
379{
380 nl_dump(p, "pvid %u", bd->vlan_info.pvid);
381
382 nl_dump(p, " all vlans:");
383 dump_bitmap(p, bd->vlan_info.vlan_bitmap);
384
385 nl_dump(p, " untagged vlans:");
386 dump_bitmap(p, bd->vlan_info.untagged_bitmap);
387}
388
389static void bridge_dump_details(struct rtnl_link *link,
390 struct nl_dump_params *p, void *data)
391{
392 struct bridge_data *bd = data;
393
394 nl_dump_line(p, " bridge: ");
395
396 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
397 nl_dump(p, "port-state %u ", bd->b_port_state);
398
399 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
400 nl_dump(p, "prio %u ", bd->b_priority);
401
402 if (bd->ce_mask & BRIDGE_ATTR_COST)
403 nl_dump(p, "cost %u ", bd->b_cost);
404
405 if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
406 char hbuf[32];
407
408 rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
409 nl_dump(p, "hwmode %s", hbuf);
410 }
411
412 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
413 rtnl_link_bridge_dump_vlans(p, bd);
414
415 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
416 char buf[256];
417
418 rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
419 buf, sizeof(buf));
420 nl_dump(p, "%s", buf);
421 }
422
423 nl_dump(p, "\n");
424}
425
426static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
427 int family, uint32_t attrs, int flags)
428{
429 struct bridge_data *a = bridge_data(_a);
430 struct bridge_data *b = bridge_data(_b);
431 int diff = 0;
432
433#define BRIDGE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, BRIDGE_ATTR_##ATTR, a, b, EXPR)
434 diff |= BRIDGE_DIFF(PORT_STATE, a->b_port_state != b->b_port_state);
435 diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority);
436 diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost);
437 diff |= BRIDGE_DIFF(PORT_VLAN, memcmp(&a->vlan_info, &b->vlan_info,
438 sizeof(struct rtnl_link_bridge_vlan)));
439 diff |= BRIDGE_DIFF(HWMODE, a->b_hwmode != b->b_hwmode);
440 diff |= BRIDGE_DIFF(SELF, a->b_self != b->b_self);
441
442 if (flags & LOOSE_COMPARISON)
443 diff |= BRIDGE_DIFF(FLAGS,
444 (a->b_flags ^ b->b_flags) & b->b_flags_mask);
445 else
446 diff |= BRIDGE_DIFF(FLAGS, a->b_flags != b->b_flags);
447#undef BRIDGE_DIFF
448
449 return diff;
450}
451/** @endcond */
452
453/**
454 * Allocate link object of type bridge
455 *
456 * @return Allocated link object or NULL.
457 */
459{
460 struct rtnl_link *link;
461
462 if (!(link = rtnl_link_alloc()))
463 return NULL;
464
465 if (rtnl_link_set_type(link, "bridge") < 0) {
466 rtnl_link_put(link);
467 return NULL;
468 }
469
470 return link;
471}
472
473/**
474 * Create a new kernel bridge device
475 * @arg sk netlink socket
476 * @arg name name of the bridge device or NULL
477 *
478 * Creates a new bridge device in the kernel. If no name is
479 * provided, the kernel will automatically pick a name of the
480 * form "type%d" (e.g. bridge0, vlan1, etc.)
481 *
482 * @return 0 on success or a negative error code
483*/
484int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
485{
486 int err;
487 struct rtnl_link *link;
488
489 if (!(link = rtnl_link_bridge_alloc()))
490 return -NLE_NOMEM;
491
492 if(name)
493 rtnl_link_set_name(link, name);
494
495 err = rtnl_link_add(sk, link, NLM_F_CREATE);
496 rtnl_link_put(link);
497
498 return err;
499}
500
501/**
502 * Check if a link is a bridge
503 * @arg link Link object
504 *
505 * @return 1 if the link is a bridge, 0 otherwise.
506 */
508{
509 return link->l_family == AF_BRIDGE &&
510 link->l_af_ops == &bridge_ops;
511}
512
513/**
514 * Check if bridge has extended information
515 * @arg link Link object of type bridge
516 *
517 * Checks if the bridge object has been constructed based on
518 * information that is only available in newer kernels. This
519 * affectes the following functions:
520 * - rtnl_link_bridge_get_cost()
521 * - rtnl_link_bridge_get_priority()
522 * - rtnl_link_bridge_get_flags()
523 *
524 * @return 1 if extended information is available, otherwise 0 is returned.
525 */
527{
528 struct bridge_data *bd;
529
530 if (!rtnl_link_is_bridge(link))
531 return 0;
532
533 bd = bridge_data(link);
534 return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
535}
536
537/**
538 * Set Spanning Tree Protocol (STP) port state
539 * @arg link Link object of type bridge
540 * @arg state New STP port state
541 *
542 * The value of state must be one of the following:
543 * - BR_STATE_DISABLED
544 * - BR_STATE_LISTENING
545 * - BR_STATE_LEARNING
546 * - BR_STATE_FORWARDING
547 * - BR_STATE_BLOCKING
548 *
549 * @see rtnl_link_bridge_get_port_state()
550 *
551 * @return 0 on success or a negative error code.
552 * @retval -NLE_OPNOTSUPP Link is not a bridge
553 * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
554 */
555int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
556{
557 struct bridge_data *bd = bridge_data(link);
558
559 IS_BRIDGE_LINK_ASSERT(link);
560
561 if (state > BR_STATE_BLOCKING)
562 return -NLE_INVAL;
563
564 bd->b_port_state = state;
565 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
566
567 return 0;
568}
569
570/**
571 * Get Spanning Tree Protocol (STP) port state
572 * @arg link Link object of type bridge
573 *
574 * @see rtnl_link_bridge_set_port_state()
575 *
576 * @return The STP port state or a negative error code.
577 * @retval -NLE_OPNOTSUPP Link is not a bridge
578 */
580{
581 struct bridge_data *bd = bridge_data(link);
582
583 IS_BRIDGE_LINK_ASSERT(link);
584
585 return bd->b_port_state;
586}
587
588/**
589 * Set priority
590 * @arg link Link object of type bridge
591 * @arg prio Bridge priority
592 *
593 * @see rtnl_link_bridge_get_priority()
594 *
595 * @return 0 on success or a negative error code.
596 * @retval -NLE_OPNOTSUPP Link is not a bridge
597 */
598int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
599{
600 struct bridge_data *bd = bridge_data(link);
601
602 IS_BRIDGE_LINK_ASSERT(link);
603
604 bd->b_priority = prio;
605 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
606
607 return 0;
608}
609
610/**
611 * Get priority
612 * @arg link Link object of type bridge
613 *
614 * @see rtnl_link_bridge_set_priority()
615 *
616 * @return 0 on success or a negative error code.
617 * @retval -NLE_OPNOTSUPP Link is not a bridge
618 */
620{
621 struct bridge_data *bd = bridge_data(link);
622
623 IS_BRIDGE_LINK_ASSERT(link);
624
625 return bd->b_priority;
626}
627
628/**
629 * Set Spanning Tree Protocol (STP) path cost
630 * @arg link Link object of type bridge
631 * @arg cost New STP path cost value
632 *
633 * @see rtnl_link_bridge_get_cost()
634 *
635 * @return The bridge priority or a negative error code.
636 * @retval -NLE_OPNOTSUPP Link is not a bridge
637 */
638int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
639{
640 struct bridge_data *bd = bridge_data(link);
641
642 IS_BRIDGE_LINK_ASSERT(link);
643
644 bd->b_cost = cost;
645 bd->ce_mask |= BRIDGE_ATTR_COST;
646
647 return 0;
648}
649
650/**
651 * Get Spanning Tree Protocol (STP) path cost
652 * @arg link Link object of type bridge
653 * @arg cost Pointer to store STP cost value
654 *
655 * @see rtnl_link_bridge_set_cost()
656 *
657 * @return 0 on success or a negative error code.
658 * @retval -NLE_OPNOTSUPP Link is not a bridge
659 * @retval -NLE_INVAL `cost` is not a valid pointer
660 */
661int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
662{
663 struct bridge_data *bd = bridge_data(link);
664
665 IS_BRIDGE_LINK_ASSERT(link);
666
667 if (!cost)
668 return -NLE_INVAL;
669
670 *cost = bd->b_cost;
671
672 return 0;
673}
674
675/**
676 * Unset flags
677 * @arg link Link object of type bridge
678 * @arg flags Bridging flags to unset
679 *
680 * @see rtnl_link_bridge_set_flags()
681 * @see rtnl_link_bridge_get_flags()
682 *
683 * @return 0 on success or a negative error code.
684 * @retval -NLE_OPNOTSUPP Link is not a bridge
685 */
686int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
687{
688 struct bridge_data *bd = bridge_data(link);
689
690 IS_BRIDGE_LINK_ASSERT(link);
691
692 bd->b_flags_mask |= flags;
693 bd->b_flags &= ~flags;
694 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
695
696 return 0;
697}
698
699/**
700 * Set flags
701 * @arg link Link object of type bridge
702 * @arg flags Bridging flags to set
703 *
704 * Valid flags are:
705 * - RTNL_BRIDGE_HAIRPIN_MODE
706 * - RTNL_BRIDGE_BPDU_GUARD
707 * - RTNL_BRIDGE_ROOT_BLOCK
708 * - RTNL_BRIDGE_FAST_LEAVE
709 * - RTNL_BRIDGE_UNICAST_FLOOD
710 * - RTNL_BRIDGE_LEARNING
711 * - RTNL_BRIDGE_LEARNING_SYNC
712 *
713 * @see rtnl_link_bridge_unset_flags()
714 * @see rtnl_link_bridge_get_flags()
715 *
716 * @return 0 on success or a negative error code.
717 * @retval -NLE_OPNOTSUPP Link is not a bridge
718 */
719int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
720{
721 struct bridge_data *bd = bridge_data(link);
722
723 IS_BRIDGE_LINK_ASSERT(link);
724
725 bd->b_flags_mask |= flags;
726 bd->b_flags |= flags;
727 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
728
729 return 0;
730}
731
732/**
733 * Get flags
734 * @arg link Link object of type bridge
735 *
736 * @see rtnl_link_bridge_set_flags()
737 * @see rtnl_link_bridge_unset_flags()
738 *
739 * @return Flags or a negative error code.
740 * @retval -NLE_OPNOTSUPP Link is not a bridge
741 */
743{
744 struct bridge_data *bd = bridge_data(link);
745
746 IS_BRIDGE_LINK_ASSERT(link);
747
748 return bd->b_flags;
749}
750
751/**
752 * Set link change type to self
753 * @arg link Link Object of type bridge
754 *
755 * This will set the bridge change flag to self, meaning that changes to
756 * be applied with this link object will be applied directly to the physical
757 * device in a bridge instead of the virtual device.
758 *
759 * @return 0 on success or negative error code
760 * @return -NLE_OPNOTSUP Link is not a bridge
761 */
763{
764 struct bridge_data *bd = bridge_data(link);
765
766 IS_BRIDGE_LINK_ASSERT(link);
767
768 bd->b_self |= 1;
769 bd->ce_mask |= BRIDGE_ATTR_SELF;
770
771 return 0;
772}
773
774/**
775 * Get hardware mode
776 * @arg link Link object of type bridge
777 * @arg hwmode Output argument.
778 *
779 * @see rtnl_link_bridge_set_hwmode()
780 *
781 * @return 0 if hardware mode is present and returned in hwmode
782 * @return -NLE_NOATTR if hardware mode is not present
783 * @return -NLE_OPNOTSUP Link is not a bridge
784 */
785int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
786{
787 struct bridge_data *bd = bridge_data(link);
788
789 IS_BRIDGE_LINK_ASSERT(link);
790
791 if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
792 return -NLE_NOATTR;
793
794 *hwmode = bd->b_hwmode;
795 return 0;
796}
797
798/**
799 * Set hardware mode
800 * @arg link Link object of type bridge
801 * @arg hwmode Hardware mode to set on link
802 *
803 * This will set the hardware mode of a link when it supports hardware
804 * offloads for bridging.
805 * @see rtnl_link_bridge_get_hwmode()
806 *
807 * Valid modes are:
808 * - RTNL_BRIDGE_HWMODE_VEB
809 * - RTNL_BRIDGE_HWMODE_VEPA
810 *
811 * When setting hardware mode, the change type will be set to self.
812 * @see rtnl_link_bridge_set_self()
813 *
814 * @return 0 on success or negative error code
815 * @return -NLE_OPNOTSUP Link is not a bridge
816 * @return -NLE_INVAL when specified hwmode is unsupported.
817 */
818int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
819{
820 int err;
821 struct bridge_data *bd = bridge_data(link);
822
823 if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
824 return -NLE_INVAL;
825
826 if ((err = rtnl_link_bridge_set_self(link)) < 0)
827 return err;
828
829 bd->b_hwmode = hwmode;
830 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
831
832 return 0;
833}
834
835
836static const struct trans_tbl bridge_flags[] = {
837 __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
838 __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
839 __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block),
840 __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave),
841 __ADD(RTNL_BRIDGE_UNICAST_FLOOD, flood),
842 __ADD(RTNL_BRIDGE_LEARNING, learning),
843 __ADD(RTNL_BRIDGE_LEARNING_SYNC, learning_sync),
844};
845
846/**
847 * @name Flag Translation
848 * @{
849 */
850
851char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
852{
853 return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
854}
855
856int rtnl_link_bridge_str2flags(const char *name)
857{
858 return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
859}
860
861/** @} */
862
863static const struct trans_tbl port_states[] = {
864 __ADD(BR_STATE_DISABLED, disabled),
865 __ADD(BR_STATE_LISTENING, listening),
866 __ADD(BR_STATE_LEARNING, learning),
867 __ADD(BR_STATE_FORWARDING, forwarding),
868 __ADD(BR_STATE_BLOCKING, blocking),
869};
870
871/**
872 * @name Port State Translation
873 * @{
874 */
875
876char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
877{
878 return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
879}
880
881int rtnl_link_bridge_str2portstate(const char *name)
882{
883 return __str2type(name, port_states, ARRAY_SIZE(port_states));
884}
885
886/** @} */
887
888static const struct trans_tbl hw_modes[] = {
889 __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
890 __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
891 __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
892};
893
894/**
895 * @name Hardware Mode Translation
896 * @{
897 */
898
899char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
900 return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
901}
902
903uint16_t rtnl_link_bridge_str2hwmode(const char *name)
904{
905 return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
906}
907
908/** @} */
909
910int rtnl_link_bridge_pvid(struct rtnl_link *link)
911{
912 struct bridge_data *bd;
913
914 IS_BRIDGE_LINK_ASSERT(link);
915
916 bd = link->l_af_data[AF_BRIDGE];
917 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
918 return (int) bd->vlan_info.pvid;
919
920 return -EINVAL;
921}
922
923int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
924{
925 struct bridge_data *bd;
926 int i;
927
928 IS_BRIDGE_LINK_ASSERT(link);
929
930 bd = link->l_af_data[AF_BRIDGE];
931 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
932 if (bd->vlan_info.pvid)
933 return 1;
934
935 for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
936 if (bd->vlan_info.vlan_bitmap[i] ||
937 bd->vlan_info.untagged_bitmap[i])
938 return 1;
939 }
940 }
941 return 0;
942}
943
944struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
945{
946 struct bridge_data *data;
947
948 if (!rtnl_link_is_bridge(link))
949 return NULL;
950
951 data = link->l_af_data[AF_BRIDGE];
952 if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
953 return &data->vlan_info;
954
955 return NULL;
956}
957
958static struct rtnl_link_af_ops bridge_ops = {
959 .ao_family = AF_BRIDGE,
960 .ao_alloc = &bridge_alloc,
961 .ao_clone = &bridge_clone,
962 .ao_free = &bridge_free,
963 .ao_parse_protinfo = &bridge_parse_protinfo,
964 .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
965 .ao_compare = &bridge_compare,
966 .ao_parse_af_full = &bridge_parse_af_full,
967 .ao_get_af = &bridge_get_af,
968 .ao_fill_af = &bridge_fill_af,
969 .ao_fill_pi = &bridge_fill_pi,
970 .ao_fill_pi_flags = NLA_F_NESTED,
971 .ao_override_rtm = &bridge_override_rtm,
972 .ao_fill_af_no_nest = 1,
973};
974
975static void __init bridge_init(void)
976{
977 rtnl_link_af_register(&bridge_ops);
978}
979
980static void __exit bridge_exit(void)
981{
982 rtnl_link_af_unregister(&bridge_ops);
983}
984
985/** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:702
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:652
#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
int nla_type(const struct nlattr *nla)
Return type of the attribute.
Definition: attr.c:103
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
int nla_is_nested(const struct nlattr *attr)
Return true if attribute has NLA_F_NESTED flag set.
Definition: attr.c:1028
#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:602
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:1016
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
Definition: attr.h:324
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:125
@ 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_set_cost(struct rtnl_link *link, uint32_t cost)
Set Spanning Tree Protocol (STP) path cost.
Definition: bridge.c:638
int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
Get Spanning Tree Protocol (STP) port state.
Definition: bridge.c:579
int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
Set hardware mode.
Definition: bridge.c:818
int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
Check if bridge has extended information.
Definition: bridge.c:526
int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
Create a new kernel bridge device.
Definition: bridge.c:484
int rtnl_link_is_bridge(struct rtnl_link *link)
Check if a link is a bridge.
Definition: bridge.c:507
int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
Set Spanning Tree Protocol (STP) port state.
Definition: bridge.c:555
int rtnl_link_bridge_set_self(struct rtnl_link *link)
Set link change type to self.
Definition: bridge.c:762
struct rtnl_link * rtnl_link_bridge_alloc(void)
Allocate link object of type bridge.
Definition: bridge.c:458
int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
Get hardware mode.
Definition: bridge.c:785
int rtnl_link_bridge_get_flags(struct rtnl_link *link)
Get flags.
Definition: bridge.c:742
int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
Get Spanning Tree Protocol (STP) path cost.
Definition: bridge.c:661
int rtnl_link_bridge_get_priority(struct rtnl_link *link)
Get priority.
Definition: bridge.c:619
int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
Unset flags.
Definition: bridge.c:686
int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
Set priority.
Definition: bridge.c:598
int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
Set flags.
Definition: bridge.c:719
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:65