1 /* $NetBSD: lagg.c,v 1.8 2024/04/09 08:53:08 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.8 2024/04/09 08:53:08 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_exec = setlagglacp} 137 , {.k_word = "-dumpdu", .k_key = "lacpdumpdu", 138 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_DUMPDU, 139 .k_exec = setlagglacp} 140 , {.k_word = "stopdu", .k_key = "lacpstopdu", 141 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_STOPDU, 142 .k_exec = setlagglacp} 143 , {.k_word = "-stopdu", .k_key = "lacpstopdu", 144 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_STOPDU, 145 .k_exec = setlagglacp} 146 , {.k_word = "optimistic", .k_key = "lacpoptimistic", 147 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_OPTIMISTIC, 148 .k_exec = setlagglacp} 149 , {.k_word = "-optimistic", .k_key = "lacpoptimistic", 150 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_OPTIMISTIC, 151 .k_exec = setlagglacp} 152 , {.k_word = "maxports", .k_nextparser = &lagglacpmaxports.pi_parser} 153 , {.k_word = "-maxports", .k_key = "lacpmaxports", 154 .k_type = KW_T_INT, .k_int = 0, .k_exec = setlagglacpmaxports} 155 , {.k_word = "multi-linkspeed", .k_key = "lacpmultils", 156 .k_type = KW_T_INT, .k_int = LAGGLACPOPT_MULTILS, 157 .k_exec = setlagglacp} 158 , {.k_word = "-multi-linkspeed", .k_key = "lacpmultils", 159 .k_type = KW_T_INT, .k_int = -LAGGLACPOPT_MULTILS, 160 .k_exec = setlagglacp} 161 }; 162 struct pkw lagglacp = PKW_INITIALIZER(&lagglacp, "lagg-lacp-option", 163 NULL, NULL, lagglacpkw, __arraycount(lagglacpkw), 164 &lagglacp_root.pb_parser); 165 166 static const struct kwinst laggfailkw[] = { 167 {.k_word = "rx-all", .k_key = "failrxall", 168 .k_type = KW_T_INT, .k_int = LAGGFAILOPT_RXALL} 169 , {.k_word = "-rx-all", .k_key = "failrxall", 170 .k_type = KW_T_INT, .k_int = -LAGGFAILOPT_RXALL} 171 }; 172 struct pkw laggfail = PKW_INITIALIZER(&laggfail, "lagg-failover-option", 173 setlaggfail, NULL, laggfailkw, __arraycount(laggfailkw), 174 &laggfail_root.pb_parser); 175 176 static const struct kwinst laggkw[] = { 177 {.k_word = "laggproto", .k_nextparser = &laggproto.ps_parser} 178 , {.k_word = "-laggproto", .k_key = "laggproto", .k_type = KW_T_STR, 179 .k_str = "none", .k_exec = setlaggproto} 180 , {.k_word = "laggport", .k_key = "laggportcmd", .k_type = KW_T_INT, 181 .k_int = LAGGPORT_ADD, .k_nextparser = &laggaddport.pif_parser} 182 , {.k_word = "-laggport", .k_key = "laggportcmd", .k_type = KW_T_INT, 183 .k_int = LAGGPORT_DEL, .k_nextparser = &laggdelport.pif_parser} 184 , {.k_word = "lagglacp", .k_nextparser = &lagglacp.pk_parser} 185 , {.k_word = "laggportpri", .k_nextparser = &laggportpri_if.pif_parser} 186 , {.k_word = "laggfailover", .k_nextparser = &laggfail.pk_parser} 187 }; 188 struct pkw lagg = PKW_INITIALIZER(&lagg, "lagg", NULL, NULL, 189 laggkw, __arraycount(laggkw), NULL); 190 191 static const struct kwinst laggportkw[] = { 192 {.k_word = "pri", .k_nextparser = &laggportoptpri.pi_parser} 193 }; 194 struct pkw laggportopt = PKW_INITIALIZER(&laggportopt, "lagg-port-option", 195 NULL, NULL, laggportkw, __arraycount(laggportkw), NULL); 196 197 struct branch laggport_brs[] = { 198 {.b_nextparser = &laggportopt.pk_parser} 199 , {.b_nextparser = &command_root.pb_parser} 200 }; 201 struct branch lagglacp_brs[] = { 202 {.b_nextparser = &lagglacp.pk_parser} 203 , {.b_nextparser = &command_root.pb_parser} 204 }; 205 struct branch laggfail_brs[] = { 206 {.b_nextparser = &laggfail.pk_parser} 207 , {.b_nextparser = &command_root.pb_parser} 208 }; 209 210 static void 211 lagg_constructor(void) 212 { 213 struct pbranch _laggport_root = PBRANCH_INITIALIZER(&laggport_root, 214 "laggport-root", laggport_brs, __arraycount(laggport_brs), true); 215 struct pbranch _lagglacp_root = PBRANCH_INITIALIZER(&lagglacp_root, 216 "lagglacp-root", lagglacp_brs, __arraycount(lagglacp_brs), true); 217 struct pbranch _laggfail_root = PBRANCH_INITIALIZER(&laggfail_root, 218 "laggfail-root", laggfail_brs, __arraycount(laggfail_brs), true); 219 220 laggport_root = _laggport_root; 221 lagglacp_root = _lagglacp_root; 222 laggfail_root = _laggfail_root; 223 224 cmdloop_branch_init(&branch, &lagg.pk_parser); 225 status_func_init(&status, lagg_status); 226 usage_func_init(&usage, lagg_usage); 227 228 register_cmdloop_branch(&branch); 229 register_status(&status); 230 register_usage(&usage); 231 } 232 233 static int 234 is_laggif(prop_dictionary_t env) 235 { 236 const char *ifname; 237 size_t i, len; 238 239 if ((ifname = getifname(env)) == NULL) 240 return 0; 241 242 if (strncmp(ifname, "lagg", 4) != 0) 243 return 0; 244 245 len = strlen(ifname); 246 for (i = 4; i < len; i++) { 247 if (!isdigit((unsigned char)ifname[i])) 248 return 0; 249 } 250 251 return 1; 252 } 253 254 static struct lagg_req * 255 getlagg(prop_dictionary_t env) 256 { 257 struct lagg_req *req = NULL, *p; 258 size_t nports, bufsiz; 259 int i; 260 261 if (!is_laggif(env)) { 262 if (lagg_debug) 263 warnx("valid only with lagg(4) interfaces"); 264 goto done; 265 } 266 267 for (i = 0, nports = 0; i < LAGG_RETRY_MAX; i++) { 268 bufsiz = sizeof(*req); 269 bufsiz += sizeof(req->lrq_reqports[0]) * nports; 270 p = realloc(req, bufsiz); 271 if (p == NULL) 272 break; 273 274 req = p; 275 memset(req, 0, bufsiz); 276 req->lrq_nports = nports; 277 if (indirect_ioctl(env, SIOCGLAGG, req) == 0) 278 goto done; 279 280 if (errno != ENOBUFS) 281 break; 282 nports = req->lrq_nports; 283 } 284 285 if (req != NULL) { 286 free(req); 287 req = NULL; 288 } 289 290 done: 291 return req; 292 } 293 294 static void 295 freelagg(struct lagg_req *req) 296 { 297 298 free(req); 299 } 300 301 static void 302 lagg_status(prop_dictionary_t env, prop_dictionary_t oenv) 303 { 304 struct lagg_req *req; 305 struct laggreqport *port; 306 const char *proto; 307 char str[256]; 308 size_t i; 309 310 req = getlagg(env); 311 if (req == NULL) 312 return; 313 314 if (req->lrq_proto >= LAGG_PROTO_MAX || 315 (proto = laggprotostr[req->lrq_proto]) == NULL) { 316 proto = "unknown"; 317 } 318 319 printf("\tlaggproto %s", proto); 320 if (vflag) 321 lagg_status_proto(req->lrq_proto, &req->lrq_reqproto); 322 putchar('\n'); 323 324 if (req->lrq_nports > 0) { 325 printf("\tlaggport:\n"); 326 for (i = 0; i < req->lrq_nports; i++) { 327 port = &req->lrq_reqports[i]; 328 snprintb(str, sizeof(str), 329 LAGG_PORT_BITS, port->rp_flags); 330 331 printf("\t\t%.*s pri=%u flags=%s", 332 IFNAMSIZ, port->rp_portname, 333 (unsigned int)port->rp_prio, 334 str); 335 if (vflag) 336 lagg_status_port(req->lrq_proto, port); 337 putchar('\n'); 338 } 339 } 340 341 freelagg(req); 342 } 343 344 static int 345 setlaggproto(prop_dictionary_t env, prop_dictionary_t oenv) 346 { 347 prop_object_t obj; 348 struct lagg_req req; 349 const char *proto; 350 size_t i, proto_len; 351 352 memset(&req, 0, sizeof(req)); 353 354 obj = prop_dictionary_get(env, "laggproto"); 355 if (obj == NULL) { 356 errno = ENOENT; 357 return -1; 358 } 359 360 switch (prop_object_type(obj)) { 361 case PROP_TYPE_DATA: 362 proto = prop_data_value(obj); 363 proto_len = prop_data_size(obj); 364 break; 365 case PROP_TYPE_STRING: 366 proto = prop_string_value(obj); 367 proto_len = prop_string_size(obj); 368 break; 369 default: 370 errno = EFAULT; 371 return -1; 372 } 373 374 for (i = 0; i < LAGG_PROTO_MAX; i++) { 375 if (strncmp(proto, laggprotostr[i], proto_len) == 0) 376 break; 377 } 378 379 if (i >= LAGG_PROTO_MAX) { 380 errno = EPROTONOSUPPORT; 381 return -1; 382 } 383 384 req.lrq_ioctl = LAGGIOC_SETPROTO; 385 req.lrq_proto = i; 386 387 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) 388 return -1; 389 390 return 0; 391 } 392 393 static int 394 setlaggport(prop_dictionary_t env, prop_dictionary_t oenv __unused) 395 { 396 struct lagg_req *req; 397 struct laggreqport *rp; 398 const char *ifname; 399 enum lagg_ioctl ioc; 400 int64_t lpcmd, pri; 401 int rv; 402 size_t sz; 403 404 if (!prop_dictionary_get_string(env, "laggport", &ifname)) { 405 if (lagg_debug) 406 warnx("%s.%d", __func__, __LINE__); 407 errno = ENOENT; 408 return -1; 409 } 410 411 sz = sizeof(*req) + sizeof(req->lrq_reqports[0]) * 1; 412 req = calloc(1, sz); 413 if (req == NULL) { 414 errno = ENOBUFS; 415 return -1; 416 } 417 418 req->lrq_nports = 1; 419 rp = &req->lrq_reqports[0]; 420 strlcpy(rp->rp_portname, ifname, sizeof(rp->rp_portname)); 421 ioc = LAGGIOC_NOCMD; 422 423 if (prop_dictionary_get_int64(env, "laggportcmd", &lpcmd)) { 424 if (lpcmd == LAGGPORT_ADD) { 425 ioc = LAGGIOC_ADDPORT; 426 } else { 427 ioc = LAGGIOC_DELPORT; 428 } 429 } 430 431 if (prop_dictionary_get_int64(env, "laggportpri", &pri)) { 432 ioc = LAGGIOC_SETPORTPRI; 433 rp->rp_prio = (uint32_t)pri; 434 } 435 436 if (ioc != LAGGIOC_NOCMD) { 437 req->lrq_ioctl = ioc; 438 rv = indirect_ioctl(env, SIOCSLAGG, req); 439 if (lagg_debug && rv == -1) 440 warn("cmd=%d", ioc); 441 } else { 442 rv = 0; 443 } 444 445 free(req); 446 447 return rv; 448 } 449 450 static int 451 setlagglacp(prop_dictionary_t env, prop_dictionary_t oenv __unused) 452 { 453 struct lagg_req req_add, req_del; 454 struct laggreq_lacp *add_lacp, *del_lacp; 455 int64_t v; 456 457 memset(&req_add, 0, sizeof(req_add)); 458 memset(&req_del, 0, sizeof(req_del)); 459 460 req_add.lrq_proto = req_del.lrq_proto = LAGG_PROTO_LACP; 461 req_add.lrq_ioctl = req_del.lrq_ioctl = LAGGIOC_SETPROTOOPT; 462 add_lacp = &req_add.lrq_reqproto.rp_lacp; 463 del_lacp = &req_del.lrq_reqproto.rp_lacp; 464 465 add_lacp->command = LAGGIOC_LACPSETFLAGS; 466 del_lacp->command = LAGGIOC_LACPCLRFLAGS; 467 468 if (prop_dictionary_get_int64(env, "lacpdumpdu", &v)) { 469 if (v == LAGGLACPOPT_DUMPDU) { 470 add_lacp->flags |= LAGGREQLACP_DUMPDU; 471 } else { 472 del_lacp->flags |= LAGGREQLACP_DUMPDU; 473 } 474 } 475 476 if (prop_dictionary_get_int64(env, "lacpstopdu", &v)) { 477 if (v == LAGGLACPOPT_STOPDU) { 478 add_lacp->flags |= LAGGREQLACP_STOPDU; 479 } else { 480 del_lacp->flags |= LAGGREQLACP_STOPDU; 481 } 482 } 483 484 if (prop_dictionary_get_int64(env, "lacpoptimistic", &v)) { 485 if (v == LAGGLACPOPT_OPTIMISTIC) { 486 add_lacp->flags |= LAGGREQLACP_OPTIMISTIC; 487 } else { 488 del_lacp->flags |= LAGGREQLACP_OPTIMISTIC; 489 } 490 } 491 492 if (prop_dictionary_get_int64(env, "lacpmultils", &v)) { 493 if (v == LAGGLACPOPT_MULTILS) { 494 add_lacp->flags |= LAGGREQLACP_MULTILS; 495 } else { 496 del_lacp->flags |= LAGGREQLACP_MULTILS; 497 } 498 } 499 500 if (del_lacp->flags != 0) { 501 if (indirect_ioctl(env, SIOCSLAGG, &req_del) == -1) { 502 if (lagg_debug) { 503 warn("cmd=%d, pcmd=%d", 504 req_del.lrq_ioctl, 505 del_lacp->command); 506 } 507 return -1; 508 } 509 } 510 511 if (add_lacp->flags != 0) { 512 if (indirect_ioctl(env, SIOCSLAGG, &req_add) == -1) { 513 if (lagg_debug) { 514 warn("cmd=%d, pcmd=%d", 515 req_add.lrq_ioctl, 516 add_lacp->command); 517 } 518 return -1; 519 } 520 } 521 522 return 0; 523 } 524 525 static int 526 setlagglacpmaxports(prop_dictionary_t env, 527 prop_dictionary_t oenv __unused) 528 { 529 struct lagg_req req; 530 struct laggreq_lacp *lrq_lacp; 531 int64_t v; 532 533 memset(&req, 0, sizeof(req)); 534 req.lrq_proto = LAGG_PROTO_LACP; 535 req.lrq_ioctl = LAGGIOC_SETPROTOOPT; 536 lrq_lacp = &req.lrq_reqproto.rp_lacp; 537 538 if (!prop_dictionary_get_int64(env, "lacpmaxports", &v)) { 539 if (lagg_debug) 540 warnx("%s.%d", __func__, __LINE__); 541 errno = ENOENT; 542 return -1; 543 } 544 545 if (v <= 0) { 546 lrq_lacp->command = LAGGIOC_LACPCLRMAXPORTS; 547 } else if (v > 0){ 548 lrq_lacp->command = LAGGIOC_LACPSETMAXPORTS; 549 lrq_lacp->maxports = (size_t)v; 550 } 551 552 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) { 553 err(EXIT_FAILURE, "SIOCSLAGGPROTO"); 554 } 555 556 return 0; 557 } 558 559 static int 560 setlaggfail(prop_dictionary_t env, 561 prop_dictionary_t oenv __unused) 562 { 563 struct lagg_req req_add, req_del; 564 struct laggreq_fail *add_fail, *del_fail; 565 int64_t v; 566 567 memset(&req_add, 0, sizeof(req_add)); 568 memset(&req_del, 0, sizeof(req_del)); 569 570 req_add.lrq_proto = req_del.lrq_proto = LAGG_PROTO_FAILOVER; 571 req_add.lrq_ioctl = req_del.lrq_ioctl = LAGGIOC_SETPROTOOPT; 572 add_fail = &req_add.lrq_reqproto.rp_fail; 573 del_fail = &req_del.lrq_reqproto.rp_fail; 574 575 add_fail->command = LAGGIOC_FAILSETFLAGS; 576 del_fail->command = LAGGIOC_FAILCLRFLAGS; 577 578 if (prop_dictionary_get_int64(env, "failrxall", &v)) { 579 if (v == LAGGFAILOPT_RXALL) { 580 add_fail->flags |= LAGGREQFAIL_RXALL; 581 } else { 582 del_fail->flags |= LAGGREQFAIL_RXALL; 583 } 584 } 585 586 if (del_fail->flags != 0) { 587 if (indirect_ioctl(env, SIOCSLAGG, &req_del) == -1) { 588 if (lagg_debug) { 589 warn("cmd=%d, pcmd=%d", 590 req_del.lrq_ioctl, 591 del_fail->command); 592 } 593 return -1; 594 } 595 } 596 597 if (add_fail->flags != 0) { 598 if (indirect_ioctl(env, SIOCSLAGG, &req_add) == -1) { 599 if (lagg_debug) { 600 warn("cmd=%d, pcmd=%d", 601 req_add.lrq_ioctl, 602 add_fail->command); 603 } 604 return -1; 605 } 606 } 607 608 return 0; 609 } 610 611 static void 612 lagg_usage(prop_dictionary_t env __unused) 613 { 614 615 fprintf(stderr, "\t[ laggproto p ]\n"); 616 fprintf(stderr, "\t[ laggport i [ pri n ] ] " 617 "[ -laggport i ]\n"); 618 fprintf(stderr, "\t[ laggportpri i [ pri n]]\n"); 619 fprintf(stderr, "\t[ lagglacp [ dumpdu | -dumpdu ] " 620 "[ stopdu | -stopdu ]\n" 621 "\t\t[ maxports n | -maxports ] [ optimistic | -optimistic ] ]\n"); 622 fprintf(stderr, "\t[ laggfailover] [ rx-all | -rx-all ]\n"); 623 } 624 static void 625 lacp_format_id(char *buf, size_t len, 626 uint16_t system_prio, uint8_t *system_mac, uint16_t system_key) 627 { 628 629 snprintf(buf, len, "[%04X,%02X-%02X-%02X-%02X-%02X-%02X," 630 "%04X]", 631 system_prio, 632 (unsigned int)system_mac[0],(unsigned int)system_mac[1], 633 (unsigned int)system_mac[2],(unsigned int)system_mac[3], 634 (unsigned int)system_mac[4],(unsigned int)system_mac[5], 635 system_key); 636 } 637 638 static void 639 lagg_status_proto(lagg_proto pr, struct laggreqproto *req) 640 { 641 struct laggreq_lacp *lacp; 642 char str[256]; 643 644 switch (pr) { 645 case LAGG_PROTO_LACP: 646 lacp = &req->rp_lacp; 647 648 printf("\n"); 649 snprintb(str, sizeof(str), LAGGREQLACP_BITS, 650 lacp->flags); 651 printf("\t\tmax ports=%zu, flags=%s\n", 652 lacp->maxports, str); 653 654 lacp_format_id(str, sizeof(str), lacp->actor_prio, 655 lacp->actor_mac, lacp->actor_key); 656 printf("\t\tactor=%s\n", str); 657 658 lacp_format_id(str, sizeof(str), lacp->partner_prio, 659 lacp->partner_mac, lacp->partner_key); 660 printf("\t\tpartner=%s", str); 661 break; 662 default: 663 break; 664 } 665 } 666 667 static void 668 lagg_status_port(lagg_proto pr, struct laggreqport *req) 669 { 670 struct laggreq_lacpport *lacp; 671 char str[256]; 672 673 switch (pr) { 674 case LAGG_PROTO_LACP: 675 lacp = &req->rp_lacpport; 676 677 putchar('\n'); 678 679 snprintb(str, sizeof(str), LACP_STATE_BITS, lacp->actor_state); 680 printf("\t\t\tactor: state=%s\n",str); 681 682 lacp_format_id(str, sizeof(str), lacp->partner_prio, 683 lacp->partner_mac, lacp->partner_key); 684 printf("\t\t\tpartner=%s\n", str); 685 snprintb(str, sizeof(str), LACP_STATE_BITS, 686 lacp->partner_state); 687 printf("\t\t\tpartner: port=%04X prio=%04X state=%s", 688 lacp->partner_portno, lacp->partner_portprio, str); 689 break; 690 default: 691 break; 692 } 693 } 694