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