1 /* $NetBSD: lagg.c,v 1.3 2022/03/31 01:53:22 yamaguchi Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Internet Initiative Japan Inc. 5 * All rights reserved. 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #if !defined(lint) 31 __RCSID("$NetBSD: lagg.c,v 1.3 2022/03/31 01:53:22 yamaguchi Exp $"); 32 #endif /* !defined(lint) */ 33 34 #include <sys/param.h> 35 36 #include <sys/ioctl.h> 37 38 #include <net/if.h> 39 #include <net/if_ether.h> 40 #include <net/if_lagg.h> 41 42 #include <ctype.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <string.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <util.h> 49 50 #include "env.h" 51 #include "extern.h" 52 #include "util.h" 53 54 static status_func_t status; 55 static usage_func_t usage; 56 static cmdloop_branch_t branch; 57 58 static void lagg_constructor(void) __attribute__((constructor)); 59 static void lagg_status(prop_dictionary_t, prop_dictionary_t); 60 static void lagg_usage(prop_dictionary_t); 61 62 static int setlaggproto(prop_dictionary_t, prop_dictionary_t); 63 static int setlaggport(prop_dictionary_t, prop_dictionary_t); 64 static int setlagglacp(prop_dictionary_t, prop_dictionary_t); 65 static int setlagglacpmaxports(prop_dictionary_t, prop_dictionary_t); 66 static int setlaggfail(prop_dictionary_t, prop_dictionary_t); 67 static void lagg_status_proto(lagg_proto, struct laggreqproto *); 68 static void lagg_status_port(lagg_proto, struct laggreqport *); 69 70 #ifdef LAGG_DEBUG 71 static const bool lagg_debug = true; 72 #else 73 static const bool lagg_debug = false; 74 #endif 75 76 #define LAGG_RETRY_MAX 10 77 78 static const char *laggprotostr[LAGG_PROTO_MAX] = { 79 [LAGG_PROTO_NONE] = "none", 80 [LAGG_PROTO_LACP] = "lacp", 81 [LAGG_PROTO_FAILOVER] = "failover", 82 [LAGG_PROTO_LOADBALANCE] = "loadbalance", 83 }; 84 85 enum laggportcmd { 86 LAGGPORT_NOCMD = 1, 87 LAGGPORT_ADD, 88 LAGGPORT_DEL, 89 }; 90 91 enum lagglacpcmd { 92 LAGGLACP_ADD = 1, 93 LAGGLACP_DEL, 94 }; 95 96 enum lagglacpopt { 97 LAGGLACPOPT_DUMPDU = 1, 98 LAGGLACPOPT_STOPDU, 99 LAGGLACPOPT_OPTIMISTIC, 100 LAGGLACPOPT_MULTILS, 101 }; 102 103 enum laggfailopt { 104 LAGGFAILOPT_RXALL = 1, 105 }; 106 107 struct pbranch laggport_root; 108 struct pbranch lagglacp_root; 109 struct pbranch laggfail_root; 110 111 struct pstr laggproto = PSTR_INITIALIZER(&laggproto, "lagg-protocol", 112 setlaggproto, "laggproto", &command_root.pb_parser); 113 struct piface laggaddport = PIFACE_INITIALIZER(&laggaddport, 114 "lagg-port-interface", setlaggport, "laggport", 115 &laggport_root.pb_parser); 116 struct piface laggdelport = PIFACE_INITIALIZER(&laggdelport, 117 "lagg-port-interface", setlaggport, "laggport", 118 &command_root.pb_parser); 119 struct pinteger laggportoptpri = PINTEGER_INITIALIZER1(&laggportoptpri, 120 "lagg-port-priority", 0, UINT16_MAX, 10, 121 setlaggport, "laggportpri", &laggport_root.pb_parser); 122 struct pinteger lagglacpmaxports = PINTEGER_INITIALIZER1(&lagglacpmaxports, 123 "lagg-lacp-maxports", 1, UINT32_MAX, 10, 124 setlagglacpmaxports, "lacpmaxports", 125 &lagglacp_root.pb_parser); 126 struct pinteger laggportpri_num = PINTEGER_INITIALIZER1(&laggportpri_num, 127 "lagg-port-priority", 0, UINT16_MAX, 10, 128 setlaggport, "laggportpri", &command_root.pb_parser); 129 struct piface laggportpri_if = PIFACE_INITIALIZER(&laggportpri_if, 130 "lagg-port-interface", NULL, "laggport", 131 &laggportpri_num.pi_parser); 132 133 static const struct kwinst lagglacpkw[] = { 134 {.k_word = "dumpdu", .k_key = "lacpdumpdu", 135 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_DUMPDU} 136 , {.k_word = "-dumpdu", .k_key = "lacpdumpdu", 137 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_DUMPDU} 138 , {.k_word = "stopdu", .k_key = "lacpstopdu", 139 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_STOPDU} 140 , {.k_word = "-stopdu", .k_key = "lacpstopdu", 141 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_STOPDU} 142 , {.k_word = "optimistic", .k_key = "lacpoptimistic", 143 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_OPTIMISTIC} 144 , {.k_word = "-optimistic", .k_key = "lacpoptimistic", 145 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_OPTIMISTIC} 146 , {.k_word = "maxports", .k_nextparser = &lagglacpmaxports.pi_parser} 147 , {.k_word = "-maxports", .k_key = "lacpmaxports", 148 .k_type = KW_T_INT, .k_int = 0} 149 , {.k_word = "multi-linkspeed", .k_key = "lacpmultils", 150 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_MULTILS} 151 , {.k_word = "-multi-linkspeed", .k_key = "lacpmultils", 152 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_MULTILS} 153 }; 154 struct pkw lagglacp = PKW_INITIALIZER(&lagglacp, "lagg-lacp-option", 155 setlagglacp, NULL, lagglacpkw, __arraycount(lagglacpkw), 156 &lagglacp_root.pb_parser); 157 158 static const struct kwinst laggfailkw[] = { 159 {.k_word = "rx-all", .k_key = "failrxall", 160 .k_type = KW_T_INT, .k_int = LAGGFAILOPT_RXALL} 161 , {.k_word = "-rx-all", .k_key = "failrxall", 162 .k_type = KW_T_INT, .k_int = -LAGGFAILOPT_RXALL} 163 }; 164 struct pkw laggfail = PKW_INITIALIZER(&laggfail, "lagg-failover-option", 165 setlaggfail, NULL, laggfailkw, __arraycount(laggfailkw), 166 &laggfail_root.pb_parser); 167 168 static const struct kwinst laggkw[] = { 169 {.k_word = "laggproto", .k_nextparser = &laggproto.ps_parser} 170 , {.k_word = "-laggproto", .k_key = "laggproto", .k_type = KW_T_STR, 171 .k_str = "none", .k_exec = setlaggproto} 172 , {.k_word = "laggport", .k_key = "laggportcmd", .k_type = KW_T_INT, 173 .k_int = LAGGPORT_ADD, .k_nextparser = &laggaddport.pif_parser} 174 , {.k_word = "-laggport", .k_key = "laggportcmd", .k_type = KW_T_INT, 175 .k_int = LAGGPORT_DEL, .k_nextparser = &laggdelport.pif_parser} 176 , {.k_word = "lagglacp", .k_nextparser = &lagglacp.pk_parser} 177 , {.k_word = "laggportpri", .k_nextparser = &laggportpri_if.pif_parser} 178 , {.k_word = "laggfailover", .k_nextparser = &laggfail.pk_parser} 179 }; 180 struct pkw lagg = PKW_INITIALIZER(&lagg, "lagg", NULL, NULL, 181 laggkw, __arraycount(laggkw), NULL); 182 183 static const struct kwinst laggportkw[] = { 184 {.k_word = "pri", .k_nextparser = &laggportoptpri.pi_parser} 185 }; 186 struct pkw laggportopt = PKW_INITIALIZER(&laggportopt, "lagg-port-option", 187 NULL, NULL, laggportkw, __arraycount(laggportkw), NULL); 188 189 struct branch laggport_brs[] = { 190 {.b_nextparser = &laggportopt.pk_parser} 191 , {.b_nextparser = &command_root.pb_parser} 192 }; 193 struct branch lagglacp_brs[] = { 194 {.b_nextparser = &lagglacp.pk_parser} 195 , {.b_nextparser = &command_root.pb_parser} 196 }; 197 struct branch laggfail_brs[] = { 198 {.b_nextparser = &laggfail.pk_parser} 199 , {.b_nextparser = &command_root.pb_parser} 200 }; 201 202 static void 203 lagg_constructor(void) 204 { 205 struct pbranch _laggport_root = PBRANCH_INITIALIZER(&laggport_root, 206 "laggport-root", laggport_brs, __arraycount(laggport_brs), true); 207 struct pbranch _lagglacp_root = PBRANCH_INITIALIZER(&lagglacp_root, 208 "lagglacp-root", lagglacp_brs, __arraycount(lagglacp_brs), true); 209 struct pbranch _laggfail_root = PBRANCH_INITIALIZER(&laggfail_root, 210 "laggfail-root", laggfail_brs, __arraycount(laggfail_brs), true); 211 212 laggport_root = _laggport_root; 213 lagglacp_root = _lagglacp_root; 214 laggfail_root = _laggfail_root; 215 216 cmdloop_branch_init(&branch, &lagg.pk_parser); 217 status_func_init(&status, lagg_status); 218 usage_func_init(&usage, lagg_usage); 219 220 register_cmdloop_branch(&branch); 221 register_status(&status); 222 register_usage(&usage); 223 } 224 225 static int 226 is_laggif(prop_dictionary_t env) 227 { 228 const char *ifname; 229 size_t i, len; 230 231 if ((ifname = getifname(env)) == NULL) 232 return 0; 233 234 if (strncmp(ifname, "lagg", 4) != 0) 235 return 0; 236 237 len = strlen(ifname); 238 for (i = 4; i < len; i++) { 239 if (!isdigit((unsigned char)ifname[i])) 240 return 0; 241 } 242 243 return 1; 244 } 245 246 static struct lagg_req * 247 getlagg(prop_dictionary_t env) 248 { 249 struct lagg_req *req = NULL, *p; 250 size_t nports, bufsiz; 251 int i; 252 253 if (!is_laggif(env)) { 254 if (lagg_debug) 255 warnx("valid only with lagg(4) interfaces"); 256 goto done; 257 } 258 259 for (i = 0, nports = 0; i < LAGG_RETRY_MAX; i++) { 260 bufsiz = sizeof(*req); 261 bufsiz += sizeof(req->lrq_reqports[0]) * nports; 262 p = realloc(req, bufsiz); 263 if (p == NULL) 264 break; 265 266 req = p; 267 memset(req, 0, bufsiz); 268 req->lrq_nports = nports; 269 if (indirect_ioctl(env, SIOCGLAGG, req) == 0) 270 goto done; 271 272 if (errno != ENOBUFS) 273 break; 274 nports = req->lrq_nports + 3; /* 3: additional space */ 275 } 276 277 if (req != NULL) { 278 free(req); 279 req = NULL; 280 } 281 282 done: 283 return req; 284 } 285 286 static void 287 freelagg(struct lagg_req *req) 288 { 289 290 free(req); 291 } 292 293 static void 294 lagg_status(prop_dictionary_t env, prop_dictionary_t oenv) 295 { 296 struct lagg_req *req; 297 struct laggreqport *port; 298 const char *proto; 299 char str[256]; 300 size_t i; 301 302 req = getlagg(env); 303 if (req == NULL) 304 return; 305 306 if (req->lrq_proto >= LAGG_PROTO_MAX || 307 (proto = laggprotostr[req->lrq_proto]) == NULL) { 308 proto = "unknown"; 309 } 310 311 printf("\tlaggproto %s", proto); 312 if (vflag) 313 lagg_status_proto(req->lrq_proto, &req->lrq_reqproto); 314 putchar('\n'); 315 316 if (req->lrq_nports > 0) { 317 printf("\tlaggport:\n"); 318 for (i = 0; i < req->lrq_nports; i++) { 319 port = &req->lrq_reqports[i]; 320 snprintb(str, sizeof(str), 321 LAGG_PORT_BITS, port->rp_flags); 322 323 printf("\t\t%.*s pri=%u flags=%s", 324 IFNAMSIZ, port->rp_portname, 325 (unsigned int)port->rp_prio, 326 str); 327 if (vflag) 328 lagg_status_port(req->lrq_proto, port); 329 putchar('\n'); 330 } 331 } 332 333 freelagg(req); 334 } 335 336 static int 337 setlaggproto(prop_dictionary_t env, prop_dictionary_t oenv) 338 { 339 prop_object_t obj; 340 struct lagg_req req; 341 const char *proto; 342 size_t i, proto_len; 343 344 memset(&req, 0, sizeof(req)); 345 346 obj = prop_dictionary_get(env, "laggproto"); 347 if (obj == NULL) { 348 errno = ENOENT; 349 return -1; 350 } 351 352 switch (prop_object_type(obj)) { 353 case PROP_TYPE_DATA: 354 proto = prop_data_value(obj); 355 proto_len = prop_data_size(obj); 356 break; 357 case PROP_TYPE_STRING: 358 proto = prop_string_value(obj); 359 proto_len = prop_string_size(obj); 360 break; 361 default: 362 errno = EFAULT; 363 return -1; 364 } 365 366 for (i = 0; i < LAGG_PROTO_MAX; i++) { 367 if (strncmp(proto, laggprotostr[i], proto_len) == 0) 368 break; 369 } 370 371 if (i >= LAGG_PROTO_MAX) { 372 errno = EPROTONOSUPPORT; 373 return -1; 374 } 375 376 req.lrq_ioctl = LAGGIOC_SETPROTO; 377 req.lrq_proto = i; 378 379 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) 380 return -1; 381 382 return 0; 383 } 384 385 static int 386 setlaggport(prop_dictionary_t env, prop_dictionary_t oenv __unused) 387 { 388 struct lagg_req req; 389 struct laggreqport *rp; 390 const char *ifname; 391 enum lagg_ioctl ioc; 392 int64_t lpcmd, pri; 393 394 if (!prop_dictionary_get_string(env, "laggport", &ifname)) { 395 if (lagg_debug) 396 warnx("%s.%d", __func__, __LINE__); 397 errno = ENOENT; 398 return -1; 399 } 400 401 memset(&req, 0, sizeof(req)); 402 req.lrq_nports = 1; 403 rp = &req.lrq_reqports[0]; 404 strlcpy(rp->rp_portname, ifname, sizeof(rp->rp_portname)); 405 ioc = LAGGIOC_NOCMD; 406 407 if (prop_dictionary_get_int64(env, "laggportcmd", &lpcmd)) { 408 if (lpcmd == LAGGPORT_ADD) { 409 ioc = LAGGIOC_ADDPORT; 410 } else { 411 ioc = LAGGIOC_DELPORT; 412 } 413 } 414 415 if (prop_dictionary_get_int64(env, "laggportpri", &pri)) { 416 ioc = LAGGIOC_SETPORTPRI; 417 rp->rp_prio = (uint32_t)pri; 418 } 419 420 if (ioc != LAGGIOC_NOCMD) { 421 req.lrq_ioctl = ioc; 422 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) { 423 if (lagg_debug) { 424 warn("cmd=%d", ioc); 425 } 426 return -1; 427 } 428 } 429 430 return 0; 431 } 432 433 static int 434 setlagglacp(prop_dictionary_t env, prop_dictionary_t oenv __unused) 435 { 436 struct lagg_req req_add, req_del; 437 struct laggreq_lacp *add_lacp, *del_lacp; 438 int64_t v; 439 440 memset(&req_add, 0, sizeof(req_add)); 441 memset(&req_del, 0, sizeof(req_del)); 442 443 req_add.lrq_proto = req_del.lrq_proto = LAGG_PROTO_LACP; 444 req_add.lrq_ioctl = req_del.lrq_ioctl = LAGGIOC_SETPROTOOPT; 445 add_lacp = &req_add.lrq_reqproto.rp_lacp; 446 del_lacp = &req_del.lrq_reqproto.rp_lacp; 447 448 add_lacp->command = LAGGIOC_LACPSETFLAGS; 449 del_lacp->command = LAGGIOC_LACPCLRFLAGS; 450 451 if (prop_dictionary_get_int64(env, "lacpdumpdu", &v)) { 452 if (v == LAGGLACPOPT_DUMPDU) { 453 add_lacp->flags |= LAGGREQLACP_DUMPDU; 454 } else { 455 del_lacp->flags |= LAGGREQLACP_DUMPDU; 456 } 457 } 458 459 if (prop_dictionary_get_int64(env, "lacpstopdu", &v)) { 460 if (v == LAGGLACPOPT_STOPDU) { 461 add_lacp->flags |= LAGGREQLACP_STOPDU; 462 } else { 463 del_lacp->flags |= LAGGREQLACP_STOPDU; 464 } 465 } 466 467 if (prop_dictionary_get_int64(env, "lacpoptimistic", &v)) { 468 if (v == LAGGLACPOPT_OPTIMISTIC) { 469 add_lacp->flags |= LAGGREQLACP_OPTIMISTIC; 470 } else { 471 del_lacp->flags |= LAGGREQLACP_OPTIMISTIC; 472 } 473 } 474 475 if (prop_dictionary_get_int64(env, "lacpmultils", &v)) { 476 if (v == LAGGLACPOPT_MULTILS) { 477 add_lacp->flags |= LAGGREQLACP_MULTILS; 478 } else { 479 del_lacp->flags |= LAGGREQLACP_MULTILS; 480 } 481 } 482 483 if (del_lacp->flags != 0) { 484 if (indirect_ioctl(env, SIOCSLAGG, &req_del) == -1) { 485 if (lagg_debug) { 486 warn("cmd=%d, pcmd=%d", 487 req_del.lrq_ioctl, 488 del_lacp->command); 489 } 490 return -1; 491 } 492 } 493 494 if (add_lacp->flags != 0) { 495 if (indirect_ioctl(env, SIOCSLAGG, &req_add) == -1) { 496 if (lagg_debug) { 497 warn("cmd=%d, pcmd=%d", 498 req_add.lrq_ioctl, 499 add_lacp->command); 500 } 501 return -1; 502 } 503 } 504 505 return 0; 506 } 507 508 static int 509 setlagglacpmaxports(prop_dictionary_t env, 510 prop_dictionary_t oenv __unused) 511 { 512 struct lagg_req req; 513 struct laggreq_lacp *lrq_lacp; 514 int64_t v; 515 516 memset(&req, 0, sizeof(req)); 517 req.lrq_proto = LAGG_PROTO_LACP; 518 req.lrq_ioctl = LAGGIOC_SETPROTOOPT; 519 lrq_lacp = &req.lrq_reqproto.rp_lacp; 520 521 if (!prop_dictionary_get_int64(env, "lacpmaxports", &v)) { 522 if (lagg_debug) 523 warnx("%s.%d", __func__, __LINE__); 524 errno = ENOENT; 525 return -1; 526 } 527 528 if (v <= 0) { 529 lrq_lacp->command = LAGGIOC_LACPCLRMAXPORTS; 530 } else if (v > 0){ 531 lrq_lacp->command = LAGGIOC_LACPSETMAXPORTS; 532 lrq_lacp->maxports = (size_t)v; 533 } 534 535 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) { 536 err(EXIT_FAILURE, "SIOCSLAGGPROTO"); 537 } 538 539 return 0; 540 } 541 542 static int 543 setlaggfail(prop_dictionary_t env, 544 prop_dictionary_t oenv __unused) 545 { 546 struct lagg_req req_add, req_del; 547 struct laggreq_fail *add_fail, *del_fail; 548 int64_t v; 549 550 memset(&req_add, 0, sizeof(req_add)); 551 memset(&req_del, 0, sizeof(req_del)); 552 553 req_add.lrq_proto = req_del.lrq_proto = LAGG_PROTO_FAILOVER; 554 req_add.lrq_ioctl = req_del.lrq_ioctl = LAGGIOC_SETPROTOOPT; 555 add_fail = &req_add.lrq_reqproto.rp_fail; 556 del_fail = &req_del.lrq_reqproto.rp_fail; 557 558 add_fail->command = LAGGIOC_FAILSETFLAGS; 559 del_fail->command = LAGGIOC_FAILCLRFLAGS; 560 561 if (prop_dictionary_get_int64(env, "failrxall", &v)) { 562 if (v == LAGGFAILOPT_RXALL) { 563 add_fail->flags |= LAGGREQFAIL_RXALL; 564 } else { 565 del_fail->flags |= LAGGREQFAIL_RXALL; 566 } 567 } 568 569 if (del_fail->flags != 0) { 570 if (indirect_ioctl(env, SIOCSLAGG, &req_del) == -1) { 571 if (lagg_debug) { 572 warn("cmd=%d, pcmd=%d", 573 req_del.lrq_ioctl, 574 del_fail->command); 575 } 576 return -1; 577 } 578 } 579 580 if (add_fail->flags != 0) { 581 if (indirect_ioctl(env, SIOCSLAGG, &req_add) == -1) { 582 if (lagg_debug) { 583 warn("cmd=%d, pcmd=%d", 584 req_add.lrq_ioctl, 585 add_fail->command); 586 } 587 return -1; 588 } 589 } 590 591 return 0; 592 } 593 594 static void 595 lagg_usage(prop_dictionary_t env __unused) 596 { 597 598 fprintf(stderr, "\t[ laggproto p ]\n"); 599 fprintf(stderr, "\t[ laggport i [ pri n ] ] " 600 "[ -laggport i ]\n"); 601 fprintf(stderr, "\t[ laggportpri i [ pri n]]\n"); 602 fprintf(stderr, "\t[ lagglacp [ dumpdu | -dumpdu ] " 603 "[ stopdu | -stopdu ]\n" 604 "\t\t[ maxports n | -maxports ] [ optimistic | -optimistic ] ]\n"); 605 fprintf(stderr, "\t[ laggfailover] [ rx-all | -rx-all ]\n"); 606 } 607 static void 608 lacp_format_id(char *buf, size_t len, 609 uint16_t system_prio, uint8_t *system_mac, uint16_t system_key) 610 { 611 612 snprintf(buf, len, "[%04X,%02X-%02X-%02X-%02X-%02X-%02X," 613 "%04X]", 614 system_prio, 615 (unsigned int)system_mac[0],(unsigned int)system_mac[1], 616 (unsigned int)system_mac[2],(unsigned int)system_mac[3], 617 (unsigned int)system_mac[4],(unsigned int)system_mac[5], 618 system_key); 619 } 620 621 static void 622 lagg_status_proto(lagg_proto pr, struct laggreqproto *req) 623 { 624 struct laggreq_lacp *lacp; 625 char str[256]; 626 627 switch (pr) { 628 case LAGG_PROTO_LACP: 629 lacp = &req->rp_lacp; 630 631 printf("\n"); 632 snprintb(str, sizeof(str), LAGGREQLACP_BITS, 633 lacp->flags); 634 printf("\t\tmax ports=%zu, flags=%s\n", 635 lacp->maxports, str); 636 637 lacp_format_id(str, sizeof(str), lacp->actor_prio, 638 lacp->actor_mac, lacp->actor_key); 639 printf("\t\tactor=%s\n", str); 640 641 lacp_format_id(str, sizeof(str), lacp->partner_prio, 642 lacp->partner_mac, lacp->partner_key); 643 printf("\t\tpartner=%s", str); 644 break; 645 default: 646 break; 647 } 648 } 649 650 static void 651 lagg_status_port(lagg_proto pr, struct laggreqport *req) 652 { 653 struct laggreq_lacpport *lacp; 654 char str[256]; 655 656 switch (pr) { 657 case LAGG_PROTO_LACP: 658 lacp = &req->rp_lacpport; 659 660 putchar('\n'); 661 662 snprintb(str, sizeof(str), LACP_STATE_BITS, lacp->actor_state); 663 printf("\t\t\tactor: state=%s\n",str); 664 665 lacp_format_id(str, sizeof(str), lacp->partner_prio, 666 lacp->partner_mac, lacp->partner_key); 667 printf("\t\t\tpartner=%s\n", str); 668 snprintb(str, sizeof(str), LACP_STATE_BITS, 669 lacp->partner_state); 670 printf("\t\t\tpartner: port=%04X prio=%04X state=%s", 671 lacp->partner_portno, lacp->partner_portprio, str); 672 break; 673 default: 674 break; 675 } 676 } 677