1/* 2 * swlib.c: Switch configuration API (user space part) 3 * 4 * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public License 8 * version 2.1 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16#include <stdio.h> 17#include <string.h> 18#include <stdlib.h> 19#include <inttypes.h> 20#include <errno.h> 21#include <stdint.h> 22#include <getopt.h> 23#include <sys/types.h> 24#include <sys/socket.h> 25#include <linux/switch.h> 26#include "swlib.h" 27#include <netlink/netlink.h> 28#include <netlink/genl/genl.h> 29#include <netlink/genl/family.h> 30 31//#define DEBUG 1 32#ifdef DEBUG 33#define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) 34#else 35#define DPRINTF(fmt, ...) do {} while (0) 36#endif 37 38static struct nl_sock *handle; 39static struct nl_cache *cache; 40static struct genl_family *family; 41static struct nlattr *tb[SWITCH_ATTR_MAX + 1]; 42static int refcount = 0; 43 44static struct nla_policy port_policy[SWITCH_ATTR_MAX] = { 45 [SWITCH_PORT_ID] = { .type = NLA_U32 }, 46 [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, 47}; 48 49static struct nla_policy portmap_policy[SWITCH_PORTMAP_MAX] = { 50 [SWITCH_PORTMAP_SEGMENT] = { .type = NLA_STRING }, 51 [SWITCH_PORTMAP_VIRT] = { .type = NLA_U32 }, 52}; 53 54static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = { 55 [SWITCH_LINK_FLAG_LINK] = { .type = NLA_FLAG }, 56 [SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG }, 57 [SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG }, 58 [SWITCH_LINK_SPEED] = { .type = NLA_U32 }, 59 [SWITCH_LINK_FLAG_EEE_100BASET] = { .type = NLA_FLAG }, 60 [SWITCH_LINK_FLAG_EEE_1000BASET] = { .type = NLA_FLAG }, 61}; 62 63static inline void * 64swlib_alloc(size_t size) 65{ 66 void *ptr; 67 68 ptr = malloc(size); 69 if (!ptr) 70 goto done; 71 memset(ptr, 0, size); 72 73done: 74 return ptr; 75} 76 77static int 78wait_handler(struct nl_msg *msg, void *arg) 79{ 80 int *finished = arg; 81 82 *finished = 1; 83 return NL_STOP; 84} 85 86/* helper function for performing netlink requests */ 87static int 88swlib_call(int cmd, int (*call)(struct nl_msg *, void *), 89 int (*data)(struct nl_msg *, void *), void *arg) 90{ 91 struct nl_msg *msg; 92 struct nl_cb *cb = NULL; 93 int finished; 94 int flags = 0; 95 int err; 96 97 msg = nlmsg_alloc(); 98 if (!msg) { 99 fprintf(stderr, "Out of memory!\n"); 100 exit(1); 101 } 102 103 if (!data) 104 flags |= NLM_F_DUMP; 105 106 genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family), 0, flags, cmd, 0); 107 if (data) { 108 if (data(msg, arg) < 0) 109 goto nla_put_failure; 110 } 111 112 cb = nl_cb_alloc(NL_CB_CUSTOM); 113 if (!cb) { 114 fprintf(stderr, "nl_cb_alloc failed.\n"); 115 exit(1); 116 } 117 118 err = nl_send_auto_complete(handle, msg); 119 if (err < 0) { 120 fprintf(stderr, "nl_send_auto_complete failed: %d\n", err); 121 goto out; 122 } 123 124 finished = 0; 125 126 if (call) 127 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, call, arg); 128 129 if (data) 130 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished); 131 else 132 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished); 133 134 err = nl_recvmsgs(handle, cb); 135 if (err < 0) { 136 goto out; 137 } 138 139 if (!finished) 140 err = nl_wait_for_ack(handle); 141 142out: 143 if (cb) 144 nl_cb_put(cb); 145nla_put_failure: 146 nlmsg_free(msg); 147 return err; 148} 149 150static int 151send_attr(struct nl_msg *msg, void *arg) 152{ 153 struct switch_val *val = arg; 154 struct switch_attr *attr = val->attr; 155 156 NLA_PUT_U32(msg, SWITCH_ATTR_ID, attr->dev->id); 157 NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, attr->id); 158 switch(attr->atype) { 159 case SWLIB_ATTR_GROUP_PORT: 160 NLA_PUT_U32(msg, SWITCH_ATTR_OP_PORT, val->port_vlan); 161 break; 162 case SWLIB_ATTR_GROUP_VLAN: 163 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VLAN, val->port_vlan); 164 break; 165 default: 166 break; 167 } 168 169 return 0; 170 171nla_put_failure: 172 return -1; 173} 174 175static int 176store_port_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val) 177{ 178 struct nlattr *p; 179 int ports = val->attr->dev->ports; 180 int err = 0; 181 int remaining; 182 183 if (!val->value.ports) 184 val->value.ports = malloc(sizeof(struct switch_port) * ports); 185 186 nla_for_each_nested(p, nla, remaining) { 187 struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; 188 struct switch_port *port; 189 190 if (val->len >= ports) 191 break; 192 193 err = nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, p, port_policy); 194 if (err < 0) 195 goto out; 196 197 if (!tb[SWITCH_PORT_ID]) 198 continue; 199 200 port = &val->value.ports[val->len]; 201 port->id = nla_get_u32(tb[SWITCH_PORT_ID]); 202 port->flags = 0; 203 if (tb[SWITCH_PORT_FLAG_TAGGED]) 204 port->flags |= SWLIB_PORT_FLAG_TAGGED; 205 206 val->len++; 207 } 208 209out: 210 return err; 211} 212 213static int 214store_link_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val) 215{ 216 struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1]; 217 struct switch_port_link *link; 218 int err = 0; 219 220 if (!val->value.link) 221 val->value.link = malloc(sizeof(struct switch_port_link)); 222 223 err = nla_parse_nested(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy); 224 if (err < 0) 225 goto out; 226 227 link = val->value.link; 228 link->link = !!tb[SWITCH_LINK_FLAG_LINK]; 229 link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX]; 230 link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG]; 231 link->tx_flow = !!tb[SWITCH_LINK_FLAG_TX_FLOW]; 232 link->rx_flow = !!tb[SWITCH_LINK_FLAG_RX_FLOW]; 233 link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]); 234 link->eee = 0; 235 if (tb[SWITCH_LINK_FLAG_EEE_100BASET]) 236 link->eee |= SWLIB_LINK_FLAG_EEE_100BASET; 237 if (tb[SWITCH_LINK_FLAG_EEE_1000BASET]) 238 link->eee |= SWLIB_LINK_FLAG_EEE_1000BASET; 239 240out: 241 return err; 242} 243 244static int 245store_val(struct nl_msg *msg, void *arg) 246{ 247 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 248 struct switch_val *val = arg; 249 250 if (!val) 251 goto error; 252 253 if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0), 254 genlmsg_attrlen(gnlh, 0), NULL) < 0) { 255 goto error; 256 } 257 258 if (tb[SWITCH_ATTR_OP_VALUE_INT]) 259 val->value.i = nla_get_u32(tb[SWITCH_ATTR_OP_VALUE_INT]); 260 else if (tb[SWITCH_ATTR_OP_VALUE_STR]) 261 val->value.s = strdup(nla_get_string(tb[SWITCH_ATTR_OP_VALUE_STR])); 262 else if (tb[SWITCH_ATTR_OP_VALUE_PORTS]) 263 val->err = store_port_val(msg, tb[SWITCH_ATTR_OP_VALUE_PORTS], val); 264 else if (tb[SWITCH_ATTR_OP_VALUE_LINK]) 265 val->err = store_link_val(msg, tb[SWITCH_ATTR_OP_VALUE_LINK], val); 266 267 val->err = 0; 268 return 0; 269 270error: 271 return NL_SKIP; 272} 273 274int 275swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) 276{ 277 int cmd; 278 int err; 279 280 switch(attr->atype) { 281 case SWLIB_ATTR_GROUP_GLOBAL: 282 cmd = SWITCH_CMD_GET_GLOBAL; 283 break; 284 case SWLIB_ATTR_GROUP_PORT: 285 cmd = SWITCH_CMD_GET_PORT; 286 break; 287 case SWLIB_ATTR_GROUP_VLAN: 288 cmd = SWITCH_CMD_GET_VLAN; 289 break; 290 default: 291 return -EINVAL; 292 } 293 294 memset(&val->value, 0, sizeof(val->value)); 295 val->len = 0; 296 val->attr = attr; 297 val->err = -EINVAL; 298 err = swlib_call(cmd, store_val, send_attr, val); 299 if (!err) 300 err = val->err; 301 302 return err; 303} 304 305static int 306send_attr_ports(struct nl_msg *msg, struct switch_val *val) 307{ 308 struct nlattr *n; 309 int i; 310 311 /* TODO implement multipart? */ 312 if (val->len == 0) 313 goto done; 314 n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_PORTS); 315 if (!n) 316 goto nla_put_failure; 317 for (i = 0; i < val->len; i++) { 318 struct switch_port *port = &val->value.ports[i]; 319 struct nlattr *np; 320 321 np = nla_nest_start(msg, SWITCH_ATTR_PORT); 322 if (!np) 323 goto nla_put_failure; 324 325 NLA_PUT_U32(msg, SWITCH_PORT_ID, port->id); 326 if (port->flags & SWLIB_PORT_FLAG_TAGGED) 327 NLA_PUT_FLAG(msg, SWITCH_PORT_FLAG_TAGGED); 328 329 nla_nest_end(msg, np); 330 } 331 nla_nest_end(msg, n); 332done: 333 return 0; 334 335nla_put_failure: 336 return -1; 337} 338 339static int 340send_attr_link(struct nl_msg *msg, struct switch_val *val) 341{ 342 struct switch_port_link *link = val->value.link; 343 struct nlattr *n; 344 345 n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_LINK); 346 if (!n) 347 goto nla_put_failure; 348 349 if (link->duplex) 350 NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_DUPLEX); 351 if (link->aneg) 352 NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_ANEG); 353 NLA_PUT_U32(msg, SWITCH_LINK_SPEED, link->speed); 354 355 nla_nest_end(msg, n); 356 357 return 0; 358 359nla_put_failure: 360 return -1; 361} 362 363static int 364send_attr_val(struct nl_msg *msg, void *arg) 365{ 366 struct switch_val *val = arg; 367 struct switch_attr *attr = val->attr; 368 369 if (send_attr(msg, arg)) 370 goto nla_put_failure; 371 372 switch(attr->type) { 373 case SWITCH_TYPE_NOVAL: 374 break; 375 case SWITCH_TYPE_INT: 376 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val->value.i); 377 break; 378 case SWITCH_TYPE_STRING: 379 if (!val->value.s) 380 goto nla_put_failure; 381 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val->value.s); 382 break; 383 case SWITCH_TYPE_PORTS: 384 if (send_attr_ports(msg, val) < 0) 385 goto nla_put_failure; 386 break; 387 case SWITCH_TYPE_LINK: 388 if (send_attr_link(msg, val)) 389 goto nla_put_failure; 390 break; 391 default: 392 goto nla_put_failure; 393 } 394 return 0; 395 396nla_put_failure: 397 return -1; 398} 399 400int 401swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) 402{ 403 int cmd; 404 405 switch(attr->atype) { 406 case SWLIB_ATTR_GROUP_GLOBAL: 407 cmd = SWITCH_CMD_SET_GLOBAL; 408 break; 409 case SWLIB_ATTR_GROUP_PORT: 410 cmd = SWITCH_CMD_SET_PORT; 411 break; 412 case SWLIB_ATTR_GROUP_VLAN: 413 cmd = SWITCH_CMD_SET_VLAN; 414 break; 415 default: 416 return -EINVAL; 417 } 418 419 val->attr = attr; 420 return swlib_call(cmd, NULL, send_attr_val, val); 421} 422 423enum { 424 CMD_NONE, 425 CMD_DUPLEX, 426 CMD_ANEG, 427 CMD_SPEED, 428}; 429 430int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *a, int port_vlan, const char *str) 431{ 432 struct switch_port *ports; 433 struct switch_port_link *link; 434 struct switch_val val; 435 char *ptr; 436 int cmd = CMD_NONE; 437 438 memset(&val, 0, sizeof(val)); 439 val.port_vlan = port_vlan; 440 switch(a->type) { 441 case SWITCH_TYPE_INT: 442 val.value.i = atoi(str); 443 break; 444 case SWITCH_TYPE_STRING: 445 val.value.s = (char *)str; 446 break; 447 case SWITCH_TYPE_PORTS: 448 ports = alloca(sizeof(struct switch_port) * dev->ports); 449 memset(ports, 0, sizeof(struct switch_port) * dev->ports); 450 val.len = 0; 451 ptr = (char *)str; 452 while(ptr && *ptr) 453 { 454 while(*ptr && isspace(*ptr)) 455 ptr++; 456 457 if (!*ptr) 458 break; 459 460 if (!isdigit(*ptr)) 461 return -1; 462 463 if (val.len >= dev->ports) 464 return -1; 465 466 ports[val.len].flags = 0; 467 ports[val.len].id = strtoul(ptr, &ptr, 10); 468 while(*ptr && !isspace(*ptr)) { 469 if (*ptr == 't') 470 ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED; 471 else 472 return -1; 473 474 ptr++; 475 } 476 if (*ptr) 477 ptr++; 478 val.len++; 479 } 480 val.value.ports = ports; 481 break; 482 case SWITCH_TYPE_LINK: 483 link = malloc(sizeof(struct switch_port_link)); 484 memset(link, 0, sizeof(struct switch_port_link)); 485 ptr = (char *)str; 486 for (ptr = strtok(ptr," "); ptr; ptr = strtok(NULL, " ")) { 487 switch (cmd) { 488 case CMD_NONE: 489 if (!strcmp(ptr, "duplex")) 490 cmd = CMD_DUPLEX; 491 else if (!strcmp(ptr, "autoneg")) 492 cmd = CMD_ANEG; 493 else if (!strcmp(ptr, "speed")) 494 cmd = CMD_SPEED; 495 else 496 fprintf(stderr, "Unsupported option %s\n", ptr); 497 break; 498 case CMD_DUPLEX: 499 if (!strcmp(ptr, "half")) 500 link->duplex = 0; 501 else if (!strcmp(ptr, "full")) 502 link->duplex = 1; 503 else 504 fprintf(stderr, "Unsupported value %s\n", ptr); 505 cmd = CMD_NONE; 506 break; 507 case CMD_ANEG: 508 if (!strcmp(ptr, "on")) 509 link->aneg = 1; 510 else if (!strcmp(ptr, "off")) 511 link->aneg = 0; 512 else 513 fprintf(stderr, "Unsupported value %s\n", ptr); 514 cmd = CMD_NONE; 515 break; 516 case CMD_SPEED: 517 link->speed = atoi(ptr); 518 cmd = CMD_NONE; 519 break; 520 } 521 } 522 val.value.link = link; 523 break; 524 case SWITCH_TYPE_NOVAL: 525 if (str && !strcmp(str, "0")) 526 return 0; 527 528 break; 529 default: 530 return -1; 531 } 532 return swlib_set_attr(dev, a, &val); 533} 534 535 536struct attrlist_arg { 537 int id; 538 int atype; 539 struct switch_dev *dev; 540 struct switch_attr *prev; 541 struct switch_attr **head; 542}; 543 544static int 545add_id(struct nl_msg *msg, void *arg) 546{ 547 struct attrlist_arg *l = arg; 548 549 NLA_PUT_U32(msg, SWITCH_ATTR_ID, l->id); 550 551 return 0; 552nla_put_failure: 553 return -1; 554} 555 556static int 557add_attr(struct nl_msg *msg, void *ptr) 558{ 559 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 560 struct attrlist_arg *arg = ptr; 561 struct switch_attr *new; 562 563 if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0), 564 genlmsg_attrlen(gnlh, 0), NULL) < 0) 565 goto done; 566 567 new = swlib_alloc(sizeof(struct switch_attr)); 568 if (!new) 569 goto done; 570 571 new->dev = arg->dev; 572 new->atype = arg->atype; 573 if (arg->prev) { 574 arg->prev->next = new; 575 } else { 576 arg->prev = *arg->head; 577 } 578 *arg->head = new; 579 arg->head = &new->next; 580 581 if (tb[SWITCH_ATTR_OP_ID]) 582 new->id = nla_get_u32(tb[SWITCH_ATTR_OP_ID]); 583 if (tb[SWITCH_ATTR_OP_TYPE]) 584 new->type = nla_get_u32(tb[SWITCH_ATTR_OP_TYPE]); 585 if (tb[SWITCH_ATTR_OP_NAME]) 586 new->name = strdup(nla_get_string(tb[SWITCH_ATTR_OP_NAME])); 587 if (tb[SWITCH_ATTR_OP_DESCRIPTION]) 588 new->description = strdup(nla_get_string(tb[SWITCH_ATTR_OP_DESCRIPTION])); 589 590done: 591 return NL_SKIP; 592} 593 594int 595swlib_scan(struct switch_dev *dev) 596{ 597 struct attrlist_arg arg; 598 599 if (dev->ops || dev->port_ops || dev->vlan_ops) 600 return 0; 601 602 arg.atype = SWLIB_ATTR_GROUP_GLOBAL; 603 arg.dev = dev; 604 arg.id = dev->id; 605 arg.prev = NULL; 606 arg.head = &dev->ops; 607 swlib_call(SWITCH_CMD_LIST_GLOBAL, add_attr, add_id, &arg); 608 609 arg.atype = SWLIB_ATTR_GROUP_PORT; 610 arg.prev = NULL; 611 arg.head = &dev->port_ops; 612 swlib_call(SWITCH_CMD_LIST_PORT, add_attr, add_id, &arg); 613 614 arg.atype = SWLIB_ATTR_GROUP_VLAN; 615 arg.prev = NULL; 616 arg.head = &dev->vlan_ops; 617 swlib_call(SWITCH_CMD_LIST_VLAN, add_attr, add_id, &arg); 618 619 return 0; 620} 621 622struct switch_attr *swlib_lookup_attr(struct switch_dev *dev, 623 enum swlib_attr_group atype, const char *name) 624{ 625 struct switch_attr *head; 626 627 if (!name || !dev) 628 return NULL; 629 630 switch(atype) { 631 case SWLIB_ATTR_GROUP_GLOBAL: 632 head = dev->ops; 633 break; 634 case SWLIB_ATTR_GROUP_PORT: 635 head = dev->port_ops; 636 break; 637 case SWLIB_ATTR_GROUP_VLAN: 638 head = dev->vlan_ops; 639 break; 640 } 641 while(head) { 642 if (!strcmp(name, head->name)) 643 return head; 644 head = head->next; 645 } 646 647 return NULL; 648} 649 650static void 651swlib_priv_free(void) 652{ 653 if (family) 654 nl_object_put((struct nl_object*)family); 655 if (cache) 656 nl_cache_free(cache); 657 if (handle) 658 nl_socket_free(handle); 659 family = NULL; 660 handle = NULL; 661 cache = NULL; 662} 663 664static int 665swlib_priv_init(void) 666{ 667 int ret; 668 669 handle = nl_socket_alloc(); 670 if (!handle) { 671 DPRINTF("Failed to create handle\n"); 672 goto err; 673 } 674 675 if (genl_connect(handle)) { 676 DPRINTF("Failed to connect to generic netlink\n"); 677 goto err; 678 } 679 680 ret = genl_ctrl_alloc_cache(handle, &cache); 681 if (ret < 0) { 682 DPRINTF("Failed to allocate netlink cache\n"); 683 goto err; 684 } 685 686 family = genl_ctrl_search_by_name(cache, "switch"); 687 if (!family) { 688 DPRINTF("Switch API not present\n"); 689 goto err; 690 } 691 return 0; 692 693err: 694 swlib_priv_free(); 695 return -EINVAL; 696} 697 698struct swlib_scan_arg { 699 const char *name; 700 struct switch_dev *head; 701 struct switch_dev *ptr; 702}; 703 704static int 705add_port_map(struct switch_dev *dev, struct nlattr *nla) 706{ 707 struct nlattr *p; 708 int err = 0, idx = 0; 709 int remaining; 710 711 dev->maps = malloc(sizeof(struct switch_portmap) * dev->ports); 712 if (!dev->maps) 713 return -1; 714 memset(dev->maps, 0, sizeof(struct switch_portmap) * dev->ports); 715 716 nla_for_each_nested(p, nla, remaining) { 717 struct nlattr *tb[SWITCH_PORTMAP_MAX+1]; 718 719 if (idx >= dev->ports) 720 continue; 721 722 err = nla_parse_nested(tb, SWITCH_PORTMAP_MAX, p, portmap_policy); 723 if (err < 0) 724 continue; 725 726 727 if (tb[SWITCH_PORTMAP_SEGMENT] && tb[SWITCH_PORTMAP_VIRT]) { 728 dev->maps[idx].segment = strdup(nla_get_string(tb[SWITCH_PORTMAP_SEGMENT])); 729 dev->maps[idx].virt = nla_get_u32(tb[SWITCH_PORTMAP_VIRT]); 730 } 731 idx++; 732 } 733 734out: 735 return err; 736} 737 738 739static int 740add_switch(struct nl_msg *msg, void *arg) 741{ 742 struct swlib_scan_arg *sa = arg; 743 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 744 struct switch_dev *dev; 745 const char *name; 746 const char *alias; 747 748 if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0) 749 goto done; 750 751 if (!tb[SWITCH_ATTR_DEV_NAME]) 752 goto done; 753 754 name = nla_get_string(tb[SWITCH_ATTR_DEV_NAME]); 755 alias = nla_get_string(tb[SWITCH_ATTR_ALIAS]); 756 757 if (sa->name && (strcmp(name, sa->name) != 0) && (strcmp(alias, sa->name) != 0)) 758 goto done; 759 760 dev = swlib_alloc(sizeof(struct switch_dev)); 761 if (!dev) 762 goto done; 763 764 strncpy(dev->dev_name, name, IFNAMSIZ - 1); 765 dev->alias = strdup(alias); 766 if (tb[SWITCH_ATTR_ID]) 767 dev->id = nla_get_u32(tb[SWITCH_ATTR_ID]); 768 if (tb[SWITCH_ATTR_NAME]) 769 dev->name = strdup(nla_get_string(tb[SWITCH_ATTR_NAME])); 770 if (tb[SWITCH_ATTR_PORTS]) 771 dev->ports = nla_get_u32(tb[SWITCH_ATTR_PORTS]); 772 if (tb[SWITCH_ATTR_VLANS]) 773 dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]); 774 if (tb[SWITCH_ATTR_CPU_PORT]) 775 dev->cpu_port = nla_get_u32(tb[SWITCH_ATTR_CPU_PORT]); 776 if (tb[SWITCH_ATTR_PORTMAP]) 777 add_port_map(dev, tb[SWITCH_ATTR_PORTMAP]); 778 779 if (!sa->head) { 780 sa->head = dev; 781 sa->ptr = dev; 782 } else { 783 sa->ptr->next = dev; 784 sa->ptr = dev; 785 } 786 787 refcount++; 788done: 789 return NL_SKIP; 790} 791 792static int 793list_switch(struct nl_msg *msg, void *arg) 794{ 795 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 796 797 if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0) 798 goto done; 799 800 if (!tb[SWITCH_ATTR_DEV_NAME] || !tb[SWITCH_ATTR_NAME]) 801 goto done; 802 803 printf("Found: %s - %s\n", nla_get_string(tb[SWITCH_ATTR_DEV_NAME]), 804 nla_get_string(tb[SWITCH_ATTR_ALIAS])); 805 806done: 807 return NL_SKIP; 808} 809 810void 811swlib_list(void) 812{ 813 if (swlib_priv_init() < 0) 814 return; 815 swlib_call(SWITCH_CMD_GET_SWITCH, list_switch, NULL, NULL); 816 swlib_priv_free(); 817} 818 819void 820swlib_print_portmap(struct switch_dev *dev, char *segment) 821{ 822 int i; 823 824 if (segment) { 825 if (!strcmp(segment, "cpu")) { 826 printf("%d ", dev->cpu_port); 827 } else if (!strcmp(segment, "disabled")) { 828 for (i = 0; i < dev->ports; i++) 829 if (!dev->maps[i].segment) 830 printf("%d ", i); 831 } else for (i = 0; i < dev->ports; i++) { 832 if (dev->maps[i].segment && !strcmp(dev->maps[i].segment, segment)) 833 printf("%d ", i); 834 } 835 } else { 836 printf("%s - %s\n", dev->dev_name, dev->name); 837 for (i = 0; i < dev->ports; i++) 838 if (i == dev->cpu_port) 839 printf("port%d:\tcpu\n", i); 840 else if (dev->maps[i].segment) 841 printf("port%d:\t%s.%d\n", i, dev->maps[i].segment, dev->maps[i].virt); 842 else 843 printf("port%d:\tdisabled\n", i); 844 } 845} 846 847struct switch_dev * 848swlib_connect(const char *name) 849{ 850 struct swlib_scan_arg arg; 851 852 if (!refcount) { 853 if (swlib_priv_init() < 0) 854 return NULL; 855 }; 856 857 arg.head = NULL; 858 arg.ptr = NULL; 859 arg.name = name; 860 swlib_call(SWITCH_CMD_GET_SWITCH, add_switch, NULL, &arg); 861 862 if (!refcount) 863 swlib_priv_free(); 864 865 return arg.head; 866} 867 868static void 869swlib_free_attributes(struct switch_attr **head) 870{ 871 struct switch_attr *a = *head; 872 struct switch_attr *next; 873 874 while (a) { 875 next = a->next; 876 free(a->name); 877 free(a->description); 878 free(a); 879 a = next; 880 } 881 *head = NULL; 882} 883 884static void 885swlib_free_port_map(struct switch_dev *dev) 886{ 887 int i; 888 889 if (!dev || !dev->maps) 890 return; 891 892 for (i = 0; i < dev->ports; i++) 893 free(dev->maps[i].segment); 894 free(dev->maps); 895} 896 897void 898swlib_free(struct switch_dev *dev) 899{ 900 swlib_free_attributes(&dev->ops); 901 swlib_free_attributes(&dev->port_ops); 902 swlib_free_attributes(&dev->vlan_ops); 903 swlib_free_port_map(dev); 904 free(dev->name); 905 free(dev->alias); 906 free(dev); 907 908 if (--refcount == 0) 909 swlib_priv_free(); 910} 911 912void 913swlib_free_all(struct switch_dev *dev) 914{ 915 struct switch_dev *p; 916 917 while (dev) { 918 p = dev->next; 919 swlib_free(dev); 920 dev = p; 921 } 922} 923