libnl  3.2.24-rc1
bridge.c
1 /*
2  * lib/route/link/bridge.c AF_BRIDGE link support
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup link
14  * @defgroup bridge Bridging
15  *
16  * @details
17  * @{
18  */
19 
20 #include <netlink-private/netlink.h>
21 #include <netlink/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/route/rtnl.h>
24 #include <netlink/route/link/bridge.h>
25 #include <netlink-private/route/link/api.h>
26 #include <linux/if_bridge.h>
27 
28 /** @cond SKIP */
29 #define BRIDGE_ATTR_PORT_STATE (1 << 0)
30 #define BRIDGE_ATTR_PRIORITY (1 << 1)
31 #define BRIDGE_ATTR_COST (1 << 2)
32 #define BRIDGE_ATTR_FLAGS (1 << 3)
33 
34 #define PRIV_FLAG_NEW_ATTRS (1 << 0)
35 
36 struct bridge_data
37 {
38  uint8_t b_port_state;
39  uint8_t b_priv_flags; /* internal flags */
40  uint16_t b_priority;
41  uint32_t b_cost;
42  uint32_t b_flags;
43  uint32_t b_flags_mask;
44  uint32_t ce_mask; /* HACK to support attr macros */
45 };
46 
47 static struct rtnl_link_af_ops bridge_ops;
48 
49 #define IS_BRIDGE_LINK_ASSERT(link) \
50  if (!rtnl_link_is_bridge(link)) { \
51  APPBUG("A function was expecting a link object of type bridge."); \
52  return -NLE_OPNOTSUPP; \
53  }
54 
55 static inline struct bridge_data *bridge_data(struct rtnl_link *link)
56 {
57  return rtnl_link_af_data(link, &bridge_ops);
58 }
59 
60 static void *bridge_alloc(struct rtnl_link *link)
61 {
62  return calloc(1, sizeof(struct bridge_data));
63 }
64 
65 static void *bridge_clone(struct rtnl_link *link, void *data)
66 {
67  struct bridge_data *bd;
68 
69  if ((bd = bridge_alloc(link)))
70  memcpy(bd, data, sizeof(*bd));
71 
72  return bd;
73 }
74 
75 static void bridge_free(struct rtnl_link *link, void *data)
76 {
77  free(data);
78 }
79 
80 static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
81  [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
82  [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
83  [IFLA_BRPORT_COST] = { .type = NLA_U32 },
84  [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
85  [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
86  [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
87  [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 },
88 };
89 
90 static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
91  int type, int flag)
92 {
93  if (attrs[type] && nla_get_u8(attrs[type]))
94  rtnl_link_bridge_set_flags(link, flag);
95 }
96 
97 static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
98  void *data)
99 {
100  struct bridge_data *bd = data;
101  struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
102  int err;
103 
104  /* Backwards compatibility */
105  if (!nla_is_nested(attr)) {
106  if (nla_len(attr) < 1)
107  return -NLE_RANGE;
108 
109  bd->b_port_state = nla_get_u8(attr);
110  bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
111 
112  return 0;
113  }
114 
115  if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
116  br_attrs_policy)) < 0)
117  return err;
118 
119  bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
120 
121  if (br_attrs[IFLA_BRPORT_STATE]) {
122  bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
123  bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
124  }
125 
126  if (br_attrs[IFLA_BRPORT_PRIORITY]) {
127  bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
128  bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
129  }
130 
131  if (br_attrs[IFLA_BRPORT_COST]) {
132  bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
133  bd->ce_mask |= BRIDGE_ATTR_COST;
134  }
135 
136  check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
137  check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
138  check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
139  check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
140 
141  return 0;
142 }
143 
144 static void bridge_dump_details(struct rtnl_link *link,
145  struct nl_dump_params *p, void *data)
146 {
147  struct bridge_data *bd = data;
148 
149  nl_dump_line(p, " bridge: ");
150 
151  if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
152  nl_dump(p, "port-state %u ", bd->b_port_state);
153 
154  if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
155  nl_dump(p, "prio %u ", bd->b_priority);
156 
157  if (bd->ce_mask & BRIDGE_ATTR_COST)
158  nl_dump(p, "cost %u ", bd->b_cost);
159 
160  nl_dump(p, "\n");
161 }
162 
163 static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
164  int family, uint32_t attrs, int flags)
165 {
166  struct bridge_data *a = bridge_data(_a);
167  struct bridge_data *b = bridge_data(_b);
168  int diff = 0;
169 
170 #define BRIDGE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, BRIDGE_ATTR_##ATTR, a, b, EXPR)
171  diff |= BRIDGE_DIFF(PORT_STATE, a->b_port_state != b->b_port_state);
172  diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority);
173  diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost);
174 
175  if (flags & LOOSE_COMPARISON)
176  diff |= BRIDGE_DIFF(FLAGS,
177  (a->b_flags ^ b->b_flags) & b->b_flags_mask);
178  else
179  diff |= BRIDGE_DIFF(FLAGS, a->b_flags != b->b_flags);
180 #undef BRIDGE_DIFF
181 
182  return diff;
183 }
184 /** @endcond */
185 
186 /**
187  * Allocate link object of type bridge
188  *
189  * @return Allocated link object or NULL.
190  */
192 {
193  struct rtnl_link *link;
194  int err;
195 
196  if (!(link = rtnl_link_alloc()))
197  return NULL;
198 
199  if ((err = rtnl_link_set_type(link, "bridge")) < 0) {
200  rtnl_link_put(link);
201  return NULL;
202  }
203 
204  return link;
205 }
206 
207 /**
208  * Create a new kernel bridge device
209  * @arg sock netlink socket
210  * @arg name name of the bridge device or NULL
211  *
212  * Creates a new bridge device in the kernel. If no name is
213  * provided, the kernel will automatically pick a name of the
214  * form "type%d" (e.g. bridge0, vlan1, etc.)
215  *
216  * @return 0 on success or a negative error code
217 */
218 int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
219 {
220  int err;
221  struct rtnl_link *link;
222 
223  if (!(link = rtnl_link_bridge_alloc()))
224  return -NLE_NOMEM;
225 
226  if(name)
227  rtnl_link_set_name(link, name);
228 
229  err = rtnl_link_add(sk, link, NLM_F_CREATE);
230  rtnl_link_put(link);
231 
232  return err;
233 }
234 
235 /**
236  * Check if a link is a bridge
237  * @arg link Link object
238  *
239  * @return 1 if the link is a bridge, 0 otherwise.
240  */
242 {
243  return link->l_family == AF_BRIDGE &&
244  link->l_af_ops == &bridge_ops;
245 }
246 
247 /**
248  * Check if bridge has extended information
249  * @arg link Link object of type bridge
250  *
251  * Checks if the bridge object has been constructed based on
252  * information that is only available in newer kernels. This
253  * affectes the following functions:
254  * - rtnl_link_bridge_get_cost()
255  * - rtnl_link_bridge_get_priority()
256  * - rtnl_link_bridge_get_flags()
257  *
258  * @return 1 if extended information is available, otherwise 0 is returned.
259  */
261 {
262  struct bridge_data *bd;
263 
264  if (!rtnl_link_is_bridge(link))
265  return 0;
266 
267  bd = bridge_data(link);
268  return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
269 }
270 
271 /**
272  * Set Spanning Tree Protocol (STP) port state
273  * @arg link Link object of type bridge
274  * @arg state New STP port state
275  *
276  * The value of state must be one of the following:
277  * - BR_STATE_DISABLED
278  * - BR_STATE_LISTENING
279  * - BR_STATE_LEARNING
280  * - BR_STATE_FORWARDING
281  * - BR_STATE_BLOCKING
282  *
283  * @see rtnl_link_bridge_get_port_state()
284  *
285  * @return 0 on success or a negative error code.
286  * @retval -NLE_OPNOTSUPP Link is not a bridge
287  * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
288  */
289 int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
290 {
291  struct bridge_data *bd = bridge_data(link);
292 
293  IS_BRIDGE_LINK_ASSERT(link);
294 
295  if (state > BR_STATE_BLOCKING)
296  return -NLE_INVAL;
297 
298  bd->b_port_state = state;
299  bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
300 
301  return 0;
302 }
303 
304 /**
305  * Get Spanning Tree Protocol (STP) port state
306  * @arg link Link object of type bridge
307  *
308  * @see rtnl_link_bridge_set_port_state()
309  *
310  * @return The STP port state or a negative error code.
311  * @retval -NLE_OPNOTSUPP Link is not a bridge
312  */
314 {
315  struct bridge_data *bd = bridge_data(link);
316 
317  IS_BRIDGE_LINK_ASSERT(link);
318 
319  return bd->b_port_state;
320 }
321 
322 /**
323  * Set priority
324  * @arg link Link object of type bridge
325  * @arg prio Bridge priority
326  *
327  * @see rtnl_link_bridge_get_priority()
328  *
329  * @return 0 on success or a negative error code.
330  * @retval -NLE_OPNOTSUPP Link is not a bridge
331  */
332 int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
333 {
334  struct bridge_data *bd = bridge_data(link);
335 
336  IS_BRIDGE_LINK_ASSERT(link);
337 
338  bd->b_priority = prio;
339  bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
340 
341  return 0;
342 }
343 
344 /**
345  * Get priority
346  * @arg link Link object of type bridge
347  *
348  * @see rtnl_link_bridge_set_priority()
349  *
350  * @return 0 on success or a negative error code.
351  * @retval -NLE_OPNOTSUPP Link is not a bridge
352  */
354 {
355  struct bridge_data *bd = bridge_data(link);
356 
357  IS_BRIDGE_LINK_ASSERT(link);
358 
359  return bd->b_priority;
360 }
361 
362 /**
363  * Set Spanning Tree Protocol (STP) path cost
364  * @arg link Link object of type bridge
365  * @arg cost New STP path cost value
366  *
367  * @see rtnl_link_bridge_get_cost()
368  *
369  * @return The bridge priority or a negative error code.
370  * @retval -NLE_OPNOTSUPP Link is not a bridge
371  */
372 int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
373 {
374  struct bridge_data *bd = bridge_data(link);
375 
376  IS_BRIDGE_LINK_ASSERT(link);
377 
378  bd->b_cost = cost;
379  bd->ce_mask |= BRIDGE_ATTR_COST;
380 
381  return 0;
382 }
383 
384 /**
385  * Get Spanning Tree Protocol (STP) path cost
386  * @arg link Link object of type bridge
387  * @arg cost Pointer to store STP cost value
388  *
389  * @see rtnl_link_bridge_set_cost()
390  *
391  * @return 0 on success or a negative error code.
392  * @retval -NLE_OPNOTSUPP Link is not a bridge
393  * @retval -NLE_INVAL `cost` is not a valid pointer
394  */
395 int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
396 {
397  struct bridge_data *bd = bridge_data(link);
398 
399  IS_BRIDGE_LINK_ASSERT(link);
400 
401  if (!cost)
402  return -NLE_INVAL;
403 
404  *cost = bd->b_cost;
405 
406  return 0;
407 }
408 
409 /**
410  * Unset flags
411  * @arg link Link object of type bridge
412  * @arg flags Bridging flags to unset
413  *
414  * @see rtnl_link_bridge_set_flags()
415  * @see rtnl_link_bridge_get_flags()
416  *
417  * @return 0 on success or a negative error code.
418  * @retval -NLE_OPNOTSUPP Link is not a bridge
419  */
420 int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
421 {
422  struct bridge_data *bd = bridge_data(link);
423 
424  IS_BRIDGE_LINK_ASSERT(link);
425 
426  bd->b_flags_mask |= flags;
427  bd->b_flags &= ~flags;
428  bd->ce_mask |= BRIDGE_ATTR_FLAGS;
429 
430  return 0;
431 }
432 
433 /**
434  * Set flags
435  * @arg link Link object of type bridge
436  * @arg flags Bridging flags to set
437  *
438  * Valid flags are:
439  * - RTNL_BRIDGE_HAIRPIN_MODE
440  * - RTNL_BRIDGE_BPDU_GUARD
441  * - RTNL_BRIDGE_ROOT_BLOCK
442  * - RTNL_BRIDGE_FAST_LEAVE
443  *
444  * @see rtnl_link_bridge_unset_flags()
445  * @see rtnl_link_bridge_get_flags()
446  *
447  * @return 0 on success or a negative error code.
448  * @retval -NLE_OPNOTSUPP Link is not a bridge
449  */
450 int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
451 {
452  struct bridge_data *bd = bridge_data(link);
453 
454  IS_BRIDGE_LINK_ASSERT(link);
455 
456  bd->b_flags_mask |= flags;
457  bd->b_flags |= flags;
458  bd->ce_mask |= BRIDGE_ATTR_FLAGS;
459 
460  return 0;
461 }
462 
463 /**
464  * Get flags
465  * @arg link Link object of type bridge
466  *
467  * @see rtnl_link_bridge_set_flags()
468  * @see rtnl_link_bridge_unset_flags()
469  *
470  * @return Flags or a negative error code.
471  * @retval -NLE_OPNOTSUPP Link is not a bridge
472  */
474 {
475  struct bridge_data *bd = bridge_data(link);
476 
477  IS_BRIDGE_LINK_ASSERT(link);
478 
479  return bd->b_flags;
480 }
481 
482 static const struct trans_tbl bridge_flags[] = {
483  __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode)
484  __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard)
485  __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block)
486  __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave)
487 };
488 
489 /**
490  * @name Flag Translation
491  * @{
492  */
493 
494 char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
495 {
496  return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
497 }
498 
499 int rtnl_link_bridge_str2flags(const char *name)
500 {
501  return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
502 }
503 
504 /** @} */
505 
506 static struct rtnl_link_af_ops bridge_ops = {
507  .ao_family = AF_BRIDGE,
508  .ao_alloc = &bridge_alloc,
509  .ao_clone = &bridge_clone,
510  .ao_free = &bridge_free,
511  .ao_parse_protinfo = &bridge_parse_protinfo,
512  .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
513  .ao_compare = &bridge_compare,
514 };
515 
516 static void __init bridge_init(void)
517 {
518  rtnl_link_af_register(&bridge_ops);
519 }
520 
521 static void __exit bridge_exit(void)
522 {
523  rtnl_link_af_unregister(&bridge_ops);
524 }
525 
526 /** @} */