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 (at) 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 */ 191 struct rtnl_link *rtnl_link_bridge_alloc(void) 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 sk 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 */ 241 int rtnl_link_is_bridge(struct rtnl_link *link) 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 */ 260 int rtnl_link_bridge_has_ext_info(struct rtnl_link *link) 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 */ 313 int rtnl_link_bridge_get_port_state(struct rtnl_link *link) 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 */ 353 int rtnl_link_bridge_get_priority(struct rtnl_link *link) 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 */ 473 int rtnl_link_bridge_get_flags(struct rtnl_link *link) 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 /** @} */ 527