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 
35 struct 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 
49 static 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 
55 static 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 
71 static 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 
79 static inline struct bridge_data *bridge_data(struct rtnl_link *link)
80 {
81  return rtnl_link_af_data(link, &bridge_ops);
82 }
83 
84 static void *bridge_alloc(struct rtnl_link *link)
85 {
86  return calloc(1, sizeof(struct bridge_data));
87 }
88 
89 static 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 
99 static void bridge_free(struct rtnl_link *link, void *data)
100 {
101  free(data);
102 }
103 
104 static 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 
117 static 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 
124 static 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 
176 static 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 
236 static 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 
249 nla_put_failure:
250  return -NLE_MSGSIZE;
251 }
252 
253 static 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 
300 nla_put_failure:
301  return -NLE_MSGSIZE;
302 }
303 
304 static 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 
318 static 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 
324 static 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;
367 next:
368  i = j;
369  }
370  }
371  if (!found)
372  nl_dump(p, " <none>");
373 
374  return;
375 }
376 
377 static 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 
389 static 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 
426 static 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 */
484 int 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  */
555 int 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  */
598 int 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  */
638 int 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  */
661 int 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  */
686 int 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  */
719 int 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  */
785 int 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  */
818 int 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 
836 static 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 
851 char *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 
856 int rtnl_link_bridge_str2flags(const char *name)
857 {
858  return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
859 }
860 
861 /** @} */
862 
863 static 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 
876 char *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 
881 int rtnl_link_bridge_str2portstate(const char *name)
882 {
883  return __str2type(name, port_states, ARRAY_SIZE(port_states));
884 }
885 
886 /** @} */
887 
888 static 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 
899 char *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 
903 uint16_t rtnl_link_bridge_str2hwmode(const char *name)
904 {
905  return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
906 }
907 
908 /** @} */
909 
910 int 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 
923 int 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 
944 struct 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 
958 static 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 
975 static void __init bridge_init(void)
976 {
977  rtnl_link_af_register(&bridge_ops);
978 }
979 
980 static 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:699
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:649
#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
int nla_is_nested(const struct nlattr *attr)
Return true if attribute has NLA_F_NESTED flag set.
Definition: attr.c:1025
#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:599
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:1013
#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
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
@ 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