1 /* 2 * lib/route/link/vlan.c VLAN Link Info 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) 2003-2013 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup link 14 * @defgroup vlan VLAN 15 * Virtual LAN link module 16 * 17 * @details 18 * \b Link Type Name: "vlan" 19 * 20 * @route_doc{link_vlan, VLAN Documentation} 21 * 22 * @{ 23 */ 24 25 #include <netlink-private/netlink.h> 26 #include <netlink/netlink.h> 27 #include <netlink/attr.h> 28 #include <netlink/utils.h> 29 #include <netlink/object.h> 30 #include <netlink/route/rtnl.h> 31 #include <netlink-private/route/link/api.h> 32 #include <netlink/route/link/vlan.h> 33 34 #include <linux/if_vlan.h> 35 36 /** @cond SKIP */ 37 #define VLAN_HAS_ID (1<<0) 38 #define VLAN_HAS_FLAGS (1<<1) 39 #define VLAN_HAS_INGRESS_QOS (1<<2) 40 #define VLAN_HAS_EGRESS_QOS (1<<3) 41 #define VLAN_HAS_PROTOCOL (1<<4) 42 43 struct vlan_info 44 { 45 uint16_t vi_vlan_id; 46 uint16_t vi_protocol; 47 uint32_t vi_flags; 48 uint32_t vi_flags_mask; 49 uint32_t vi_ingress_qos[VLAN_PRIO_MAX+1]; 50 uint32_t vi_negress; 51 uint32_t vi_egress_size; 52 struct vlan_map * vi_egress_qos; 53 uint32_t vi_mask; 54 }; 55 56 /** @endcond */ 57 58 static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = { 59 [IFLA_VLAN_ID] = { .type = NLA_U16 }, 60 [IFLA_VLAN_FLAGS] = { .minlen = sizeof(struct ifla_vlan_flags) }, 61 [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, 62 [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, 63 [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 }, 64 }; 65 66 static int vlan_alloc(struct rtnl_link *link) 67 { 68 struct vlan_info *vi; 69 70 if ((vi = calloc(1, sizeof(*vi))) == NULL) 71 return -NLE_NOMEM; 72 73 link->l_info = vi; 74 75 return 0; 76 } 77 78 static int vlan_parse(struct rtnl_link *link, struct nlattr *data, 79 struct nlattr *xstats) 80 { 81 struct nlattr *tb[IFLA_VLAN_MAX+1]; 82 struct vlan_info *vi; 83 int err; 84 85 NL_DBG(3, "Parsing VLAN link info"); 86 87 if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0) 88 goto errout; 89 90 if ((err = vlan_alloc(link)) < 0) 91 goto errout; 92 93 vi = link->l_info; 94 95 if (tb[IFLA_VLAN_ID]) { 96 vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]); 97 vi->vi_mask |= VLAN_HAS_ID; 98 } 99 100 if (tb[IFLA_VLAN_PROTOCOL]) { 101 vi->vi_protocol = nla_get_u16(tb[IFLA_VLAN_PROTOCOL]); 102 vi->vi_mask |= VLAN_HAS_PROTOCOL; 103 } 104 105 if (tb[IFLA_VLAN_FLAGS]) { 106 struct ifla_vlan_flags flags; 107 nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); 108 109 vi->vi_flags = flags.flags; 110 vi->vi_mask |= VLAN_HAS_FLAGS; 111 } 112 113 if (tb[IFLA_VLAN_INGRESS_QOS]) { 114 struct ifla_vlan_qos_mapping *map; 115 struct nlattr *nla; 116 int remaining; 117 118 memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos)); 119 120 nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) { 121 if (nla_len(nla) < sizeof(*map)) 122 return -NLE_INVAL; 123 124 map = nla_data(nla); 125 if (map->from > VLAN_PRIO_MAX) { 126 return -NLE_INVAL; 127 } 128 129 vi->vi_ingress_qos[map->from] = map->to; 130 } 131 132 vi->vi_mask |= VLAN_HAS_INGRESS_QOS; 133 } 134 135 if (tb[IFLA_VLAN_EGRESS_QOS]) { 136 struct ifla_vlan_qos_mapping *map; 137 struct nlattr *nla; 138 int remaining, i = 0; 139 140 nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) { 141 if (nla_len(nla) < sizeof(*map)) 142 return -NLE_INVAL; 143 i++; 144 } 145 146 /* align to have a little reserve */ 147 vi->vi_egress_size = (i + 32) & ~31; 148 vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*vi->vi_egress_qos)); 149 if (vi->vi_egress_qos == NULL) 150 return -NLE_NOMEM; 151 152 i = 0; 153 nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) { 154 map = nla_data(nla); 155 NL_DBG(4, "Assigning egress qos mapping %d\n", i); 156 vi->vi_egress_qos[i].vm_from = map->from; 157 vi->vi_egress_qos[i++].vm_to = map->to; 158 } 159 160 vi->vi_negress = i; 161 vi->vi_mask |= VLAN_HAS_EGRESS_QOS; 162 } 163 164 err = 0; 165 errout: 166 return err; 167 } 168 169 static void vlan_free(struct rtnl_link *link) 170 { 171 struct vlan_info *vi = link->l_info; 172 173 if (vi) { 174 free(vi->vi_egress_qos); 175 vi->vi_egress_qos = NULL; 176 } 177 178 free(vi); 179 link->l_info = NULL; 180 } 181 182 static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p) 183 { 184 struct vlan_info *vi = link->l_info; 185 186 nl_dump(p, "vlan-id %d", vi->vi_vlan_id); 187 } 188 189 static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p) 190 { 191 struct vlan_info *vi = link->l_info; 192 int printed; 193 uint32_t i; 194 char buf[64]; 195 196 rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf)); 197 nl_dump_line(p, " vlan-info id %d <%s>", vi->vi_vlan_id, buf); 198 199 if (vi->vi_mask & VLAN_HAS_PROTOCOL) 200 nl_dump_line(p, " vlan protocol <%d>", vi->vi_protocol); 201 202 nl_dump(p, "\n"); 203 204 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) { 205 nl_dump_line(p, 206 " ingress vlan prio -> qos/socket prio mapping:\n"); 207 for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) { 208 if (vi->vi_ingress_qos[i]) { 209 if (printed == 0) 210 nl_dump_line(p, " "); 211 nl_dump(p, "%x -> %#08x, ", 212 i, vi->vi_ingress_qos[i]); 213 if (printed++ == 3) { 214 nl_dump(p, "\n"); 215 printed = 0; 216 } 217 } 218 } 219 220 if (printed > 0 && printed != 4) 221 nl_dump(p, "\n"); 222 } 223 224 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { 225 nl_dump_line(p, 226 " egress qos/socket prio -> vlan prio mapping:\n"); 227 for (i = 0, printed = 0; i < vi->vi_negress; i++) { 228 if (printed == 0) 229 nl_dump_line(p, " "); 230 nl_dump(p, "%#08x -> %x, ", 231 vi->vi_egress_qos[i].vm_from, 232 vi->vi_egress_qos[i].vm_to); 233 if (printed++ == 3) { 234 nl_dump(p, "\n"); 235 printed = 0; 236 } 237 } 238 239 if (printed > 0 && printed != 4) 240 nl_dump(p, "\n"); 241 } 242 } 243 244 static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src) 245 { 246 struct vlan_info *vdst, *vsrc = src->l_info; 247 int err; 248 249 dst->l_info = NULL; 250 if ((err = rtnl_link_set_type(dst, "vlan")) < 0) 251 return err; 252 vdst = dst->l_info; 253 254 vdst->vi_egress_qos = calloc(vsrc->vi_egress_size, 255 sizeof(struct vlan_map)); 256 if (!vdst->vi_egress_qos) 257 return -NLE_NOMEM; 258 259 memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos, 260 vsrc->vi_egress_size * sizeof(struct vlan_map)); 261 262 return 0; 263 } 264 265 static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link) 266 { 267 struct vlan_info *vi = link->l_info; 268 struct nlattr *data; 269 270 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) 271 return -NLE_MSGSIZE; 272 273 if (vi->vi_mask & VLAN_HAS_ID) 274 NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id); 275 276 if (vi->vi_mask & VLAN_HAS_FLAGS) { 277 struct ifla_vlan_flags flags = { 278 .flags = vi->vi_flags, 279 .mask = vi->vi_flags_mask, 280 }; 281 282 NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags); 283 } 284 285 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) { 286 struct ifla_vlan_qos_mapping map; 287 struct nlattr *qos; 288 int i; 289 290 if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS))) 291 goto nla_put_failure; 292 293 for (i = 0; i <= VLAN_PRIO_MAX; i++) { 294 if (vi->vi_ingress_qos[i]) { 295 map.from = i; 296 map.to = vi->vi_ingress_qos[i]; 297 298 NLA_PUT(msg, i, sizeof(map), &map); 299 } 300 } 301 302 nla_nest_end(msg, qos); 303 } 304 305 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { 306 struct ifla_vlan_qos_mapping map; 307 struct nlattr *qos; 308 uint32_t i; 309 310 if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) 311 goto nla_put_failure; 312 313 for (i = 0; i < vi->vi_negress; i++) { 314 map.from = vi->vi_egress_qos[i].vm_from; 315 map.to = vi->vi_egress_qos[i].vm_to; 316 317 NLA_PUT(msg, i, sizeof(map), &map); 318 } 319 320 nla_nest_end(msg, qos); 321 } 322 323 nla_nest_end(msg, data); 324 325 nla_put_failure: 326 327 return 0; 328 } 329 330 static struct rtnl_link_info_ops vlan_info_ops = { 331 .io_name = "vlan", 332 .io_alloc = vlan_alloc, 333 .io_parse = vlan_parse, 334 .io_dump = { 335 [NL_DUMP_LINE] = vlan_dump_line, 336 [NL_DUMP_DETAILS] = vlan_dump_details, 337 }, 338 .io_clone = vlan_clone, 339 .io_put_attrs = vlan_put_attrs, 340 .io_free = vlan_free, 341 }; 342 343 /** @cond SKIP */ 344 #define IS_VLAN_LINK_ASSERT(link) \ 345 if ((link)->l_info_ops != &vlan_info_ops) { \ 346 APPBUG("Link is not a vlan link. set type \"vlan\" first."); \ 347 return -NLE_OPNOTSUPP; \ 348 } 349 /** @endcond */ 350 351 /** 352 * @name VLAN Object 353 * @{ 354 */ 355 356 /** 357 * Allocate link object of type VLAN 358 * 359 * @return Allocated link object or NULL. 360 */ 361 struct rtnl_link *rtnl_link_vlan_alloc(void) 362 { 363 struct rtnl_link *link; 364 int err; 365 366 if (!(link = rtnl_link_alloc())) 367 return NULL; 368 369 if ((err = rtnl_link_set_type(link, "vlan")) < 0) { 370 rtnl_link_put(link); 371 return NULL; 372 } 373 374 return link; 375 } 376 377 /** 378 * Check if link is a VLAN link 379 * @arg link Link object 380 * 381 * @return True if link is a VLAN link, otherwise false is returned. 382 */ 383 int rtnl_link_is_vlan(struct rtnl_link *link) 384 { 385 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vlan"); 386 } 387 388 /** 389 * Set VLAN ID 390 * @arg link Link object 391 * @arg id VLAN identifier 392 * 393 * @return 0 on success or a negative error code 394 */ 395 int rtnl_link_vlan_set_id(struct rtnl_link *link, uint16_t id) 396 { 397 struct vlan_info *vi = link->l_info; 398 399 IS_VLAN_LINK_ASSERT(link); 400 401 vi->vi_vlan_id = id; 402 vi->vi_mask |= VLAN_HAS_ID; 403 404 return 0; 405 } 406 407 /** 408 * Get VLAN Id 409 * @arg link Link object 410 * 411 * @return VLAN id, 0 if not set or a negative error code. 412 */ 413 int rtnl_link_vlan_get_id(struct rtnl_link *link) 414 { 415 struct vlan_info *vi = link->l_info; 416 417 IS_VLAN_LINK_ASSERT(link); 418 419 if (vi->vi_mask & VLAN_HAS_ID) 420 return vi->vi_vlan_id; 421 else 422 return 0; 423 } 424 425 /** 426 * Set VLAN protocol 427 * @arg link Link object 428 * @arg protocol VLAN protocol 429 * 430 * @return 0 on success or a negative error code 431 */ 432 int rtnl_link_vlan_set_protocol(struct rtnl_link *link, uint16_t protocol) 433 { 434 struct vlan_info *vi = link->l_info; 435 436 IS_VLAN_LINK_ASSERT(link); 437 438 vi->vi_protocol = protocol; 439 vi->vi_mask |= VLAN_HAS_PROTOCOL; 440 441 return 0; 442 } 443 444 /** 445 * Get VLAN protocol 446 * @arg link Link object 447 * 448 * @return VLAN protocol, 0 if not set or a negative error code. 449 */ 450 int rtnl_link_vlan_get_protocol(struct rtnl_link *link) 451 { 452 struct vlan_info *vi = link->l_info; 453 454 IS_VLAN_LINK_ASSERT(link); 455 456 if (vi->vi_mask & VLAN_HAS_PROTOCOL) 457 return vi->vi_protocol; 458 else 459 return 0; 460 } 461 462 /** 463 * Set VLAN flags 464 * @arg link Link object 465 * @arg flags VLAN flags 466 * 467 * @return 0 on success or a negative error code. 468 */ 469 int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags) 470 { 471 struct vlan_info *vi = link->l_info; 472 473 IS_VLAN_LINK_ASSERT(link); 474 475 vi->vi_flags_mask |= flags; 476 vi->vi_flags |= flags; 477 vi->vi_mask |= VLAN_HAS_FLAGS; 478 479 return 0; 480 } 481 482 /** 483 * Unset VLAN flags 484 * @arg link Link object 485 * @arg flags VLAN flags 486 * 487 * @return 0 on success or a negative error code. 488 */ 489 int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags) 490 { 491 struct vlan_info *vi = link->l_info; 492 493 IS_VLAN_LINK_ASSERT(link); 494 495 vi->vi_flags_mask |= flags; 496 vi->vi_flags &= ~flags; 497 vi->vi_mask |= VLAN_HAS_FLAGS; 498 499 return 0; 500 } 501 502 /** 503 * Get VLAN flags 504 * @arg link Link object 505 * 506 * @return VLAN flags, 0 if none set, or a negative error code. 507 */ 508 int rtnl_link_vlan_get_flags(struct rtnl_link *link) 509 { 510 struct vlan_info *vi = link->l_info; 511 512 IS_VLAN_LINK_ASSERT(link); 513 514 return vi->vi_flags; 515 } 516 517 /** @} */ 518 519 /** 520 * @name Quality of Service 521 * @{ 522 */ 523 524 int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from, 525 uint32_t to) 526 { 527 struct vlan_info *vi = link->l_info; 528 529 IS_VLAN_LINK_ASSERT(link); 530 531 if (from < 0 || from > VLAN_PRIO_MAX) 532 return -NLE_INVAL; 533 534 vi->vi_ingress_qos[from] = to; 535 vi->vi_mask |= VLAN_HAS_INGRESS_QOS; 536 537 return 0; 538 } 539 540 uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link) 541 { 542 struct vlan_info *vi = link->l_info; 543 544 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) 545 return NULL; 546 547 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) 548 return vi->vi_ingress_qos; 549 else 550 return NULL; 551 } 552 553 int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to) 554 { 555 struct vlan_info *vi = link->l_info; 556 557 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) 558 return -NLE_OPNOTSUPP; 559 560 if (to < 0 || to > VLAN_PRIO_MAX) 561 return -NLE_INVAL; 562 563 if (vi->vi_negress >= vi->vi_egress_size) { 564 int new_size = vi->vi_egress_size + 32; 565 void *ptr; 566 567 ptr = realloc(vi->vi_egress_qos, new_size); 568 if (!ptr) 569 return -NLE_NOMEM; 570 571 vi->vi_egress_qos = ptr; 572 vi->vi_egress_size = new_size; 573 } 574 575 vi->vi_egress_qos[vi->vi_negress].vm_from = from; 576 vi->vi_egress_qos[vi->vi_negress].vm_to = to; 577 vi->vi_negress++; 578 vi->vi_mask |= VLAN_HAS_EGRESS_QOS; 579 580 return 0; 581 } 582 583 struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link, 584 int *negress) 585 { 586 struct vlan_info *vi = link->l_info; 587 588 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) 589 return NULL; 590 591 if (negress == NULL) 592 return NULL; 593 594 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { 595 *negress = vi->vi_negress; 596 return vi->vi_egress_qos; 597 } else { 598 *negress = 0; 599 return NULL; 600 } 601 } 602 603 /** @} */ 604 605 static const struct trans_tbl vlan_flags[] = { 606 __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr) 607 }; 608 609 /** 610 * @name Flag Translation 611 * @{ 612 */ 613 614 char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len) 615 { 616 return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags)); 617 } 618 619 int rtnl_link_vlan_str2flags(const char *name) 620 { 621 return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags)); 622 } 623 624 /** @} */ 625 626 627 static void __init vlan_init(void) 628 { 629 rtnl_link_register_info(&vlan_info_ops); 630 } 631 632 static void __exit vlan_exit(void) 633 { 634 rtnl_link_unregister_info(&vlan_info_ops); 635 } 636 637 /** @} */ 638