ifbridge.c revision 164653
1/*- 2 * Copyright 2001 Wasabi Systems, Inc. 3 * All rights reserved. 4 * 5 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project by 18 * Wasabi Systems, Inc. 19 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 20 * or promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36#ifndef lint 37static const char rcsid[] = 38 "$FreeBSD: head/sbin/ifconfig/ifbridge.c 164653 2006-11-27 00:35:40Z thompsa $"; 39#endif /* not lint */ 40 41#include <sys/param.h> 42#include <sys/ioctl.h> 43#include <sys/socket.h> 44#include <sys/sockio.h> 45 46#include <stdlib.h> 47#include <unistd.h> 48 49#include <net/ethernet.h> 50#include <net/if.h> 51#include <net/if_bridgevar.h> 52#include <net/route.h> 53 54#include <ctype.h> 55#include <stdio.h> 56#include <string.h> 57#include <stdlib.h> 58#include <unistd.h> 59#include <err.h> 60#include <errno.h> 61 62#include "ifconfig.h" 63 64#define PV2ID(pv, epri, eaddr) do { \ 65 epri = pv >> 48; \ 66 eaddr[0] = pv >> 40; \ 67 eaddr[1] = pv >> 32; \ 68 eaddr[2] = pv >> 24; \ 69 eaddr[3] = pv >> 16; \ 70 eaddr[4] = pv >> 8; \ 71 eaddr[5] = pv >> 0; \ 72} while (0) 73 74static const char *stpstates[] = { 75 "disabled", 76 "listening", 77 "learning", 78 "forwarding", 79 "blocking", 80 "discarding" 81}; 82static const char *stpproto[] = { 83 "stp", 84 "-", 85 "rstp" 86}; 87static const char *stproles[] = { 88 "disabled", 89 "root", 90 "designated", 91 "alternate", 92 "backup" 93}; 94 95static int 96get_val(const char *cp, u_long *valp) 97{ 98 char *endptr; 99 u_long val; 100 101 errno = 0; 102 val = strtoul(cp, &endptr, 0); 103 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 104 return (-1); 105 106 *valp = val; 107 return (0); 108} 109 110static int 111do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) 112{ 113 struct ifdrv ifd; 114 115 memset(&ifd, 0, sizeof(ifd)); 116 117 strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); 118 ifd.ifd_cmd = op; 119 ifd.ifd_len = argsize; 120 ifd.ifd_data = arg; 121 122 return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); 123} 124 125static void 126do_bridgeflag(int sock, const char *ifs, int flag, int set) 127{ 128 struct ifbreq req; 129 130 strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); 131 132 if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) 133 err(1, "unable to get bridge flags"); 134 135 if (set) 136 req.ifbr_ifsflags |= flag; 137 else 138 req.ifbr_ifsflags &= ~flag; 139 140 if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) 141 err(1, "unable to set bridge flags"); 142} 143 144static void 145bridge_interfaces(int s, const char *prefix) 146{ 147 struct ifbifconf bifc; 148 struct ifbreq *req; 149 char *inbuf = NULL, *ninbuf; 150 char *p, *pad; 151 int i, len = 8192; 152 153 pad = strdup(prefix); 154 if (pad == NULL) 155 err(1, "strdup"); 156 /* replace the prefix with whitespace */ 157 for (p = pad; *p != '\0'; p++) { 158 if(isprint(*p)) 159 *p = ' '; 160 } 161 162 for (;;) { 163 ninbuf = realloc(inbuf, len); 164 if (ninbuf == NULL) 165 err(1, "unable to allocate interface buffer"); 166 bifc.ifbic_len = len; 167 bifc.ifbic_buf = inbuf = ninbuf; 168 if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0) 169 err(1, "unable to get interface list"); 170 if ((bifc.ifbic_len + sizeof(*req)) < len) 171 break; 172 len *= 2; 173 } 174 175 for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) { 176 req = bifc.ifbic_req + i; 177 printf("%s%s ", prefix, req->ifbr_ifsname); 178 printb("flags", req->ifbr_ifsflags, IFBIFBITS); 179 printf("\n"); 180 181 if (req->ifbr_ifsflags & IFBIF_STP) { 182 printf("%s", pad); 183 printf("port %u priority %u", 184 req->ifbr_portno, req->ifbr_priority); 185 printf(" path cost %u", req->ifbr_path_cost); 186 if (req->ifbr_proto < 187 sizeof(stpproto) / sizeof(stpproto[0])) 188 printf(" proto %s", stpproto[req->ifbr_proto]); 189 else 190 printf(" <unknown proto %d>", 191 req->ifbr_proto); 192 193 printf("\n%s", pad); 194 if (req->ifbr_role < 195 sizeof(stproles) / sizeof(stproles[0])) 196 printf("role %s", stproles[req->ifbr_role]); 197 else 198 printf("<unknown role %d>", 199 req->ifbr_role); 200 if (req->ifbr_state < 201 sizeof(stpstates) / sizeof(stpstates[0])) 202 printf(" state %s", stpstates[req->ifbr_state]); 203 else 204 printf(" <unknown state %d>", 205 req->ifbr_state); 206 printf("\n"); 207 } 208 } 209 210 free(inbuf); 211} 212 213static void 214bridge_addresses(int s, const char *prefix) 215{ 216 struct ifbaconf ifbac; 217 struct ifbareq *ifba; 218 char *inbuf = NULL, *ninbuf; 219 int i, len = 8192; 220 struct ether_addr ea; 221 222 for (;;) { 223 ninbuf = realloc(inbuf, len); 224 if (ninbuf == NULL) 225 err(1, "unable to allocate address buffer"); 226 ifbac.ifbac_len = len; 227 ifbac.ifbac_buf = inbuf = ninbuf; 228 if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0) 229 err(1, "unable to get address cache"); 230 if ((ifbac.ifbac_len + sizeof(*ifba)) < len) 231 break; 232 len *= 2; 233 } 234 235 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 236 ifba = ifbac.ifbac_req + i; 237 memcpy(ea.octet, ifba->ifba_dst, 238 sizeof(ea.octet)); 239 printf("%s%s %s %lu ", prefix, ether_ntoa(&ea), 240 ifba->ifba_ifsname, ifba->ifba_expire); 241 printb("flags", ifba->ifba_flags, IFBAFBITS); 242 printf("\n"); 243 } 244 245 free(inbuf); 246} 247 248static void 249bridge_status(int s) 250{ 251 struct ifbropreq param; 252 u_int16_t pri; 253 u_int8_t ht, fd, ma, hc, pro; 254 u_int8_t lladdr[ETHER_ADDR_LEN]; 255 u_int16_t bprio; 256 257 if (do_cmd(s, BRDGPARAM, ¶m, sizeof(param), 0) < 0) 258 return; 259 pri = param.ifbop_priority; 260 pro = param.ifbop_protocol; 261 ht = param.ifbop_hellotime; 262 fd = param.ifbop_fwddelay; 263 hc = param.ifbop_holdcount; 264 ma = param.ifbop_maxage; 265 266 PV2ID(param.ifbop_bridgeid, bprio, lladdr); 267 printf("\tid %s priority %u hellotime %u fwddelay %u\n", 268 ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd); 269 printf("\tmaxage %u holdcnt %u proto %s\n", 270 ma, hc, stpproto[pro]); 271 272 PV2ID(param.ifbop_designated_root, bprio, lladdr); 273 printf("\troot id %s priority %d ifcost %u port %u\n", 274 ether_ntoa((struct ether_addr *)lladdr), bprio, 275 param.ifbop_root_path_cost, param.ifbop_root_port & 0xfff); 276 277 bridge_interfaces(s, "\tmember: "); 278 279 return; 280 281} 282 283static void 284setbridge_add(const char *val, int d, int s, const struct afswtch *afp) 285{ 286 struct ifbreq req; 287 288 memset(&req, 0, sizeof(req)); 289 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 290 if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0) 291 err(1, "BRDGADD %s", val); 292} 293 294static void 295setbridge_delete(const char *val, int d, int s, const struct afswtch *afp) 296{ 297 struct ifbreq req; 298 299 memset(&req, 0, sizeof(req)); 300 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 301 if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0) 302 err(1, "BRDGDEL %s", val); 303} 304 305static void 306setbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 307{ 308 309 do_bridgeflag(s, val, IFBIF_DISCOVER, 1); 310} 311 312static void 313unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp) 314{ 315 316 do_bridgeflag(s, val, IFBIF_DISCOVER, 0); 317} 318 319static void 320setbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 321{ 322 323 do_bridgeflag(s, val, IFBIF_LEARNING, 1); 324} 325 326static void 327unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp) 328{ 329 330 do_bridgeflag(s, val, IFBIF_LEARNING, 0); 331} 332 333static void 334setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) 335{ 336 337 do_bridgeflag(s, val, IFBIF_STICKY, 1); 338} 339 340static void 341unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) 342{ 343 344 do_bridgeflag(s, val, IFBIF_STICKY, 0); 345} 346 347static void 348setbridge_span(const char *val, int d, int s, const struct afswtch *afp) 349{ 350 struct ifbreq req; 351 352 memset(&req, 0, sizeof(req)); 353 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 354 if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0) 355 err(1, "BRDGADDS %s", val); 356} 357 358static void 359unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp) 360{ 361 struct ifbreq req; 362 363 memset(&req, 0, sizeof(req)); 364 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); 365 if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0) 366 err(1, "BRDGDELS %s", val); 367} 368 369static void 370setbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 371{ 372 373 do_bridgeflag(s, val, IFBIF_STP, 1); 374} 375 376static void 377unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp) 378{ 379 380 do_bridgeflag(s, val, IFBIF_STP, 0); 381} 382 383static void 384setbridge_edge(const char *val, int d, int s, const struct afswtch *afp) 385{ 386 do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1); 387} 388 389static void 390unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp) 391{ 392 do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0); 393} 394 395static void 396setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) 397{ 398 do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1); 399} 400 401static void 402unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) 403{ 404 do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0); 405} 406 407static void 408setbridge_p2p(const char *val, int d, int s, const struct afswtch *afp) 409{ 410 do_bridgeflag(s, val, IFBIF_BSTP_P2P, 1); 411} 412 413static void 414unsetbridge_p2p(const char *val, int d, int s, const struct afswtch *afp) 415{ 416 do_bridgeflag(s, val, IFBIF_BSTP_P2P, 0); 417} 418 419static void 420setbridge_autop2p(const char *val, int d, int s, const struct afswtch *afp) 421{ 422 do_bridgeflag(s, val, IFBIF_BSTP_AUTOP2P, 1); 423} 424 425static void 426unsetbridge_autop2p(const char *val, int d, int s, const struct afswtch *afp) 427{ 428 do_bridgeflag(s, val, IFBIF_BSTP_AUTOP2P, 0); 429} 430 431static void 432setbridge_flush(const char *val, int d, int s, const struct afswtch *afp) 433{ 434 struct ifbreq req; 435 436 memset(&req, 0, sizeof(req)); 437 req.ifbr_ifsflags = IFBF_FLUSHDYN; 438 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 439 err(1, "BRDGFLUSH"); 440} 441 442static void 443setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp) 444{ 445 struct ifbreq req; 446 447 memset(&req, 0, sizeof(req)); 448 req.ifbr_ifsflags = IFBF_FLUSHALL; 449 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) 450 err(1, "BRDGFLUSH"); 451} 452 453static void 454setbridge_static(const char *val, const char *mac, int s, 455 const struct afswtch *afp) 456{ 457 struct ifbareq req; 458 struct ether_addr *ea; 459 460 memset(&req, 0, sizeof(req)); 461 strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); 462 463 ea = ether_aton(mac); 464 if (ea == NULL) 465 errx(1, "%s: invalid address: %s", val, mac); 466 467 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 468 req.ifba_flags = IFBAF_STATIC; 469 470 if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0) 471 err(1, "BRDGSADDR %s", val); 472} 473 474static void 475setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp) 476{ 477 struct ifbareq req; 478 struct ether_addr *ea; 479 480 memset(&req, 0, sizeof(req)); 481 482 ea = ether_aton(val); 483 if (ea == NULL) 484 errx(1, "invalid address: %s", val); 485 486 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); 487 488 if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0) 489 err(1, "BRDGDADDR %s", val); 490} 491 492static void 493setbridge_addr(const char *val, int d, int s, const struct afswtch *afp) 494{ 495 496 bridge_addresses(s, ""); 497} 498 499static void 500setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp) 501{ 502 struct ifbrparam param; 503 u_long val; 504 505 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 506 errx(1, "invalid value: %s", arg); 507 508 param.ifbrp_csize = val & 0xffffffff; 509 510 if (do_cmd(s, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) 511 err(1, "BRDGSCACHE %s", arg); 512} 513 514static void 515setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp) 516{ 517 struct ifbrparam param; 518 u_long val; 519 520 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 521 errx(1, "invalid value: %s", arg); 522 523 param.ifbrp_hellotime = val & 0xff; 524 525 if (do_cmd(s, BRDGSHT, ¶m, sizeof(param), 1) < 0) 526 err(1, "BRDGSHT %s", arg); 527} 528 529static void 530setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp) 531{ 532 struct ifbrparam param; 533 u_long val; 534 535 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 536 errx(1, "invalid value: %s", arg); 537 538 param.ifbrp_fwddelay = val & 0xff; 539 540 if (do_cmd(s, BRDGSFD, ¶m, sizeof(param), 1) < 0) 541 err(1, "BRDGSFD %s", arg); 542} 543 544static void 545setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp) 546{ 547 struct ifbrparam param; 548 u_long val; 549 550 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 551 errx(1, "invalid value: %s", arg); 552 553 param.ifbrp_maxage = val & 0xff; 554 555 if (do_cmd(s, BRDGSMA, ¶m, sizeof(param), 1) < 0) 556 err(1, "BRDGSMA %s", arg); 557} 558 559static void 560setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp) 561{ 562 struct ifbrparam param; 563 u_long val; 564 565 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) 566 errx(1, "invalid value: %s", arg); 567 568 param.ifbrp_prio = val & 0xffff; 569 570 if (do_cmd(s, BRDGSPRI, ¶m, sizeof(param), 1) < 0) 571 err(1, "BRDGSPRI %s", arg); 572} 573 574static void 575setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp) 576{ 577 struct ifbrparam param; 578 579 if (strcasecmp(arg, "stp") == 0) { 580 param.ifbrp_proto = 0; 581 } else if (strcasecmp(arg, "rstp") == 0) { 582 param.ifbrp_proto = 2; 583 } else { 584 errx(1, "unknown stp protocol"); 585 } 586 587 if (do_cmd(s, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) 588 err(1, "BRDGSPROTO %s", arg); 589} 590 591static void 592setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp) 593{ 594 struct ifbrparam param; 595 u_long val; 596 597 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) 598 errx(1, "invalid value: %s", arg); 599 600 param.ifbrp_txhc = val & 0xff; 601 602 if (do_cmd(s, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) 603 err(1, "BRDGSTXHC %s", arg); 604} 605 606static void 607setbridge_ifpriority(const char *ifn, const char *pri, int s, 608 const struct afswtch *afp) 609{ 610 struct ifbreq req; 611 u_long val; 612 613 memset(&req, 0, sizeof(req)); 614 615 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) 616 errx(1, "invalid value: %s", pri); 617 618 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 619 req.ifbr_priority = val & 0xff; 620 621 if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) 622 err(1, "BRDGSIFPRIO %s", pri); 623} 624 625static void 626setbridge_ifpathcost(const char *ifn, const char *cost, int s, 627 const struct afswtch *afp) 628{ 629 struct ifbreq req; 630 u_long val; 631 632 memset(&req, 0, sizeof(req)); 633 634 if (get_val(cost, &val) < 0) 635 errx(1, "invalid value: %s", cost); 636 637 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 638 req.ifbr_path_cost = val; 639 640 if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0) 641 err(1, "BRDGSIFCOST %s", cost); 642} 643 644static void 645setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp) 646{ 647 struct ifbrparam param; 648 u_long val; 649 650 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) 651 errx(1, "invalid value: %s", arg); 652 653 param.ifbrp_ctime = val & 0xffffffff; 654 655 if (do_cmd(s, BRDGSTO, ¶m, sizeof(param), 1) < 0) 656 err(1, "BRDGSTO %s", arg); 657} 658 659static struct cmd bridge_cmds[] = { 660 DEF_CMD_ARG("addm", setbridge_add), 661 DEF_CMD_ARG("deletem", setbridge_delete), 662 DEF_CMD_ARG("discover", setbridge_discover), 663 DEF_CMD_ARG("-discover", unsetbridge_discover), 664 DEF_CMD_ARG("learn", setbridge_learn), 665 DEF_CMD_ARG("-learn", unsetbridge_learn), 666 DEF_CMD_ARG("sticky", setbridge_sticky), 667 DEF_CMD_ARG("-sticky", unsetbridge_sticky), 668 DEF_CMD_ARG("span", setbridge_span), 669 DEF_CMD_ARG("-span", unsetbridge_span), 670 DEF_CMD_ARG("stp", setbridge_stp), 671 DEF_CMD_ARG("-stp", unsetbridge_stp), 672 DEF_CMD_ARG("edge", setbridge_edge), 673 DEF_CMD_ARG("-edge", unsetbridge_edge), 674 DEF_CMD_ARG("autoedge", setbridge_autoedge), 675 DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), 676 DEF_CMD_ARG("p2p", setbridge_p2p), 677 DEF_CMD_ARG("-p2p", unsetbridge_p2p), 678 DEF_CMD_ARG("autop2p", setbridge_autop2p), 679 DEF_CMD_ARG("-autop2p", unsetbridge_autop2p), 680 DEF_CMD("flush", 0, setbridge_flush), 681 DEF_CMD("flushall", 0, setbridge_flushall), 682 DEF_CMD_ARG2("static", setbridge_static), 683 DEF_CMD_ARG("deladdr", setbridge_deladdr), 684 DEF_CMD("addr", 1, setbridge_addr), 685 DEF_CMD_ARG("maxaddr", setbridge_maxaddr), 686 DEF_CMD_ARG("hellotime", setbridge_hellotime), 687 DEF_CMD_ARG("fwddelay", setbridge_fwddelay), 688 DEF_CMD_ARG("maxage", setbridge_maxage), 689 DEF_CMD_ARG("priority", setbridge_priority), 690 DEF_CMD_ARG("proto", setbridge_protocol), 691 DEF_CMD_ARG("holdcount", setbridge_holdcount), 692 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), 693 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), 694 DEF_CMD_ARG("timeout", setbridge_timeout), 695}; 696static struct afswtch af_bridge = { 697 .af_name = "af_bridge", 698 .af_af = AF_UNSPEC, 699 .af_other_status = bridge_status, 700}; 701 702static __constructor void 703bridge_ctor(void) 704{ 705#define N(a) (sizeof(a) / sizeof(a[0])) 706 int i; 707 708 for (i = 0; i < N(bridge_cmds); i++) 709 cmd_register(&bridge_cmds[i]); 710 af_register(&af_bridge); 711#undef N 712} 713