libnl  3.6.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  int err;
462 
463  if (!(link = rtnl_link_alloc()))
464  return NULL;
465 
466  if ((err = rtnl_link_set_type(link, "bridge")) < 0) {
467  rtnl_link_put(link);
468  return NULL;
469  }
470 
471  return link;
472 }
473 
474 /**
475  * Create a new kernel bridge device
476  * @arg sk netlink socket
477  * @arg name name of the bridge device or NULL
478  *
479  * Creates a new bridge device in the kernel. If no name is
480  * provided, the kernel will automatically pick a name of the
481  * form "type%d" (e.g. bridge0, vlan1, etc.)
482  *
483  * @return 0 on success or a negative error code
484 */
485 int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
486 {
487  int err;
488  struct rtnl_link *link;
489 
490  if (!(link = rtnl_link_bridge_alloc()))
491  return -NLE_NOMEM;
492 
493  if(name)
494  rtnl_link_set_name(link, name);
495 
496  err = rtnl_link_add(sk, link, NLM_F_CREATE);
497  rtnl_link_put(link);
498 
499  return err;
500 }
501 
502 /**
503  * Check if a link is a bridge
504  * @arg link Link object
505  *
506  * @return 1 if the link is a bridge, 0 otherwise.
507  */
509 {
510  return link->l_family == AF_BRIDGE &&
511  link->l_af_ops == &bridge_ops;
512 }
513 
514 /**
515  * Check if bridge has extended information
516  * @arg link Link object of type bridge
517  *
518  * Checks if the bridge object has been constructed based on
519  * information that is only available in newer kernels. This
520  * affectes the following functions:
521  * - rtnl_link_bridge_get_cost()
522  * - rtnl_link_bridge_get_priority()
523  * - rtnl_link_bridge_get_flags()
524  *
525  * @return 1 if extended information is available, otherwise 0 is returned.
526  */
528 {
529  struct bridge_data *bd;
530 
531  if (!rtnl_link_is_bridge(link))
532  return 0;
533 
534  bd = bridge_data(link);
535  return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
536 }
537 
538 /**
539  * Set Spanning Tree Protocol (STP) port state
540  * @arg link Link object of type bridge
541  * @arg state New STP port state
542  *
543  * The value of state must be one of the following:
544  * - BR_STATE_DISABLED
545  * - BR_STATE_LISTENING
546  * - BR_STATE_LEARNING
547  * - BR_STATE_FORWARDING
548  * - BR_STATE_BLOCKING
549  *
550  * @see rtnl_link_bridge_get_port_state()
551  *
552  * @return 0 on success or a negative error code.
553  * @retval -NLE_OPNOTSUPP Link is not a bridge
554  * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
555  */
556 int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
557 {
558  struct bridge_data *bd = bridge_data(link);
559 
560  IS_BRIDGE_LINK_ASSERT(link);
561 
562  if (state > BR_STATE_BLOCKING)
563  return -NLE_INVAL;
564 
565  bd->b_port_state = state;
566  bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
567 
568  return 0;
569 }
570 
571 /**
572  * Get Spanning Tree Protocol (STP) port state
573  * @arg link Link object of type bridge
574  *
575  * @see rtnl_link_bridge_set_port_state()
576  *
577  * @return The STP port state or a negative error code.
578  * @retval -NLE_OPNOTSUPP Link is not a bridge
579  */
581 {
582  struct bridge_data *bd = bridge_data(link);
583 
584  IS_BRIDGE_LINK_ASSERT(link);
585 
586  return bd->b_port_state;
587 }
588 
589 /**
590  * Set priority
591  * @arg link Link object of type bridge
592  * @arg prio Bridge priority
593  *
594  * @see rtnl_link_bridge_get_priority()
595  *
596  * @return 0 on success or a negative error code.
597  * @retval -NLE_OPNOTSUPP Link is not a bridge
598  */
599 int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
600 {
601  struct bridge_data *bd = bridge_data(link);
602 
603  IS_BRIDGE_LINK_ASSERT(link);
604 
605  bd->b_priority = prio;
606  bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
607 
608  return 0;
609 }
610 
611 /**
612  * Get priority
613  * @arg link Link object of type bridge
614  *
615  * @see rtnl_link_bridge_set_priority()
616  *
617  * @return 0 on success or a negative error code.
618  * @retval -NLE_OPNOTSUPP Link is not a bridge
619  */
621 {
622  struct bridge_data *bd = bridge_data(link);
623 
624  IS_BRIDGE_LINK_ASSERT(link);
625 
626  return bd->b_priority;
627 }
628 
629 /**
630  * Set Spanning Tree Protocol (STP) path cost
631  * @arg link Link object of type bridge
632  * @arg cost New STP path cost value
633  *
634  * @see rtnl_link_bridge_get_cost()
635  *
636  * @return The bridge priority or a negative error code.
637  * @retval -NLE_OPNOTSUPP Link is not a bridge
638  */
639 int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
640 {
641  struct bridge_data *bd = bridge_data(link);
642 
643  IS_BRIDGE_LINK_ASSERT(link);
644 
645  bd->b_cost = cost;
646  bd->ce_mask |= BRIDGE_ATTR_COST;
647 
648  return 0;
649 }
650 
651 /**
652  * Get Spanning Tree Protocol (STP) path cost
653  * @arg link Link object of type bridge
654  * @arg cost Pointer to store STP cost value
655  *
656  * @see rtnl_link_bridge_set_cost()
657  *
658  * @return 0 on success or a negative error code.
659  * @retval -NLE_OPNOTSUPP Link is not a bridge
660  * @retval -NLE_INVAL `cost` is not a valid pointer
661  */
662 int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
663 {
664  struct bridge_data *bd = bridge_data(link);
665 
666  IS_BRIDGE_LINK_ASSERT(link);
667 
668  if (!cost)
669  return -NLE_INVAL;
670 
671  *cost = bd->b_cost;
672 
673  return 0;
674 }
675 
676 /**
677  * Unset flags
678  * @arg link Link object of type bridge
679  * @arg flags Bridging flags to unset
680  *
681  * @see rtnl_link_bridge_set_flags()
682  * @see rtnl_link_bridge_get_flags()
683  *
684  * @return 0 on success or a negative error code.
685  * @retval -NLE_OPNOTSUPP Link is not a bridge
686  */
687 int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
688 {
689  struct bridge_data *bd = bridge_data(link);
690 
691  IS_BRIDGE_LINK_ASSERT(link);
692 
693  bd->b_flags_mask |= flags;
694  bd->b_flags &= ~flags;
695  bd->ce_mask |= BRIDGE_ATTR_FLAGS;
696 
697  return 0;
698 }
699 
700 /**
701  * Set flags
702  * @arg link Link object of type bridge
703  * @arg flags Bridging flags to set
704  *
705  * Valid flags are:
706  * - RTNL_BRIDGE_HAIRPIN_MODE
707  * - RTNL_BRIDGE_BPDU_GUARD
708  * - RTNL_BRIDGE_ROOT_BLOCK
709  * - RTNL_BRIDGE_FAST_LEAVE
710  * - RTNL_BRIDGE_UNICAST_FLOOD
711  * - RTNL_BRIDGE_LEARNING
712  * - RTNL_BRIDGE_LEARNING_SYNC
713  *
714  * @see rtnl_link_bridge_unset_flags()
715  * @see rtnl_link_bridge_get_flags()
716  *
717  * @return 0 on success or a negative error code.
718  * @retval -NLE_OPNOTSUPP Link is not a bridge
719  */
720 int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
721 {
722  struct bridge_data *bd = bridge_data(link);
723 
724  IS_BRIDGE_LINK_ASSERT(link);
725 
726  bd->b_flags_mask |= flags;
727  bd->b_flags |= flags;
728  bd->ce_mask |= BRIDGE_ATTR_FLAGS;
729 
730  return 0;
731 }
732 
733 /**
734  * Get flags
735  * @arg link Link object of type bridge
736  *
737  * @see rtnl_link_bridge_set_flags()
738  * @see rtnl_link_bridge_unset_flags()
739  *
740  * @return Flags or a negative error code.
741  * @retval -NLE_OPNOTSUPP Link is not a bridge
742  */
744 {
745  struct bridge_data *bd = bridge_data(link);
746 
747  IS_BRIDGE_LINK_ASSERT(link);
748 
749  return bd->b_flags;
750 }
751 
752 /**
753  * Set link change type to self
754  * @arg link Link Object of type bridge
755  *
756  * This will set the bridge change flag to self, meaning that changes to
757  * be applied with this link object will be applied directly to the physical
758  * device in a bridge instead of the virtual device.
759  *
760  * @return 0 on success or negative error code
761  * @return -NLE_OPNOTSUP Link is not a bridge
762  */
764 {
765  struct bridge_data *bd = bridge_data(link);
766 
767  IS_BRIDGE_LINK_ASSERT(link);
768 
769  bd->b_self |= 1;
770  bd->ce_mask |= BRIDGE_ATTR_SELF;
771 
772  return 0;
773 }
774 
775 /**
776  * Get hardware mode
777  * @arg link Link object of type bridge
778  * @arg hwmode Output argument.
779  *
780  * @see rtnl_link_bridge_set_hwmode()
781  *
782  * @return 0 if hardware mode is present and returned in hwmode
783  * @return -NLE_NOATTR if hardware mode is not present
784  * @return -NLE_OPNOTSUP Link is not a bridge
785  */
786 int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
787 {
788  struct bridge_data *bd = bridge_data(link);
789 
790  IS_BRIDGE_LINK_ASSERT(link);
791 
792  if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
793  return -NLE_NOATTR;
794 
795  *hwmode = bd->b_hwmode;
796  return 0;
797 }
798 
799 /**
800  * Set hardware mode
801  * @arg link Link object of type bridge
802  * @arg hwmode Hardware mode to set on link
803  *
804  * This will set the hardware mode of a link when it supports hardware
805  * offloads for bridging.
806  * @see rtnl_link_bridge_get_hwmode()
807  *
808  * Valid modes are:
809  * - RTNL_BRIDGE_HWMODE_VEB
810  * - RTNL_BRIDGE_HWMODE_VEPA
811  *
812  * When setting hardware mode, the change type will be set to self.
813  * @see rtnl_link_bridge_set_self()
814  *
815  * @return 0 on success or negative error code
816  * @return -NLE_OPNOTSUP Link is not a bridge
817  * @return -NLE_INVAL when specified hwmode is unsupported.
818  */
819 int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
820 {
821  int err;
822  struct bridge_data *bd = bridge_data(link);
823 
824  if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
825  return -NLE_INVAL;
826 
827  if ((err = rtnl_link_bridge_set_self(link)) < 0)
828  return err;
829 
830  bd->b_hwmode = hwmode;
831  bd->ce_mask |= BRIDGE_ATTR_HWMODE;
832 
833  return 0;
834 }
835 
836 
837 static const struct trans_tbl bridge_flags[] = {
838  __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
839  __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
840  __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block),
841  __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave),
842  __ADD(RTNL_BRIDGE_UNICAST_FLOOD, flood),
843  __ADD(RTNL_BRIDGE_LEARNING, learning),
844  __ADD(RTNL_BRIDGE_LEARNING_SYNC, learning_sync),
845 };
846 
847 /**
848  * @name Flag Translation
849  * @{
850  */
851 
852 char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
853 {
854  return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
855 }
856 
857 int rtnl_link_bridge_str2flags(const char *name)
858 {
859  return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
860 }
861 
862 /** @} */
863 
864 static const struct trans_tbl port_states[] = {
865  __ADD(BR_STATE_DISABLED, disabled),
866  __ADD(BR_STATE_LISTENING, listening),
867  __ADD(BR_STATE_LEARNING, learning),
868  __ADD(BR_STATE_FORWARDING, forwarding),
869  __ADD(BR_STATE_BLOCKING, blocking),
870 };
871 
872 /**
873  * @name Port State Translation
874  * @{
875  */
876 
877 char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
878 {
879  return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
880 }
881 
882 int rtnl_link_bridge_str2portstate(const char *name)
883 {
884  return __str2type(name, port_states, ARRAY_SIZE(port_states));
885 }
886 
887 /** @} */
888 
889 static const struct trans_tbl hw_modes[] = {
890  __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
891  __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
892  __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
893 };
894 
895 /**
896  * @name Hardware Mode Translation
897  * @{
898  */
899 
900 char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
901  return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
902 }
903 
904 uint16_t rtnl_link_bridge_str2hwmode(const char *name)
905 {
906  return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
907 }
908 
909 /** @} */
910 
911 int rtnl_link_bridge_pvid(struct rtnl_link *link)
912 {
913  struct bridge_data *bd;
914 
915  IS_BRIDGE_LINK_ASSERT(link);
916 
917  bd = link->l_af_data[AF_BRIDGE];
918  if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
919  return (int) bd->vlan_info.pvid;
920 
921  return -EINVAL;
922 }
923 
924 int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
925 {
926  struct bridge_data *bd;
927  int i;
928 
929  IS_BRIDGE_LINK_ASSERT(link);
930 
931  bd = link->l_af_data[AF_BRIDGE];
932  if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
933  if (bd->vlan_info.pvid)
934  return 1;
935 
936  for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
937  if (bd->vlan_info.vlan_bitmap[i] ||
938  bd->vlan_info.untagged_bitmap[i])
939  return 1;
940  }
941  }
942  return 0;
943 }
944 
945 struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
946 {
947  struct bridge_data *data;
948 
949  if (!rtnl_link_is_bridge(link))
950  return NULL;
951 
952  data = link->l_af_data[AF_BRIDGE];
953  if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
954  return &data->vlan_info;
955 
956  return NULL;
957 }
958 
959 static struct rtnl_link_af_ops bridge_ops = {
960  .ao_family = AF_BRIDGE,
961  .ao_alloc = &bridge_alloc,
962  .ao_clone = &bridge_clone,
963  .ao_free = &bridge_free,
964  .ao_parse_protinfo = &bridge_parse_protinfo,
965  .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
966  .ao_compare = &bridge_compare,
967  .ao_parse_af_full = &bridge_parse_af_full,
968  .ao_get_af = &bridge_get_af,
969  .ao_fill_af = &bridge_fill_af,
970  .ao_fill_pi = &bridge_fill_pi,
971  .ao_fill_pi_flags = NLA_F_NESTED,
972  .ao_override_rtm = &bridge_override_rtm,
973  .ao_fill_af_no_nest = 1,
974 };
975 
976 static void __init bridge_init(void)
977 {
978  rtnl_link_af_register(&bridge_ops);
979 }
980 
981 static void __exit bridge_exit(void)
982 {
983  rtnl_link_af_unregister(&bridge_ops);
984 }
985 
986 /** @} */
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:639
int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
Get Spanning Tree Protocol (STP) port state.
Definition: bridge.c:580
int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
Set hardware mode.
Definition: bridge.c:819
int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
Check if bridge has extended information.
Definition: bridge.c:527
int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
Create a new kernel bridge device.
Definition: bridge.c:485
int rtnl_link_is_bridge(struct rtnl_link *link)
Check if a link is a bridge.
Definition: bridge.c:508
int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
Set Spanning Tree Protocol (STP) port state.
Definition: bridge.c:556
int rtnl_link_bridge_set_self(struct rtnl_link *link)
Set link change type to self.
Definition: bridge.c:763
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:786
int rtnl_link_bridge_get_flags(struct rtnl_link *link)
Get flags.
Definition: bridge.c:743
int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
Get Spanning Tree Protocol (STP) path cost.
Definition: bridge.c:662
int rtnl_link_bridge_get_priority(struct rtnl_link *link)
Get priority.
Definition: bridge.c:620
int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
Unset flags.
Definition: bridge.c:687
int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
Set priority.
Definition: bridge.c:599
int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
Set flags.
Definition: bridge.c:720
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