1 /* $NetBSD: lagg.c,v 1.4 2023/12/06 05:57:39 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.4 2023/12/06 05:57:39 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 + 3; /* 3: additional space */ 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 402 if (!prop_dictionary_get_string(env, "laggport", &ifname)) { 403 if (lagg_debug) 404 warnx("%s.%d", __func__, __LINE__); 405 errno = ENOENT; 406 return -1; 407 } 408 409 memset(&req, 0, sizeof(req)); 410 req.lrq_nports = 1; 411 rp = &req.lrq_reqports[0]; 412 strlcpy(rp->rp_portname, ifname, sizeof(rp->rp_portname)); 413 ioc = LAGGIOC_NOCMD; 414 415 if (prop_dictionary_get_int64(env, "laggportcmd", &lpcmd)) { 416 if (lpcmd == LAGGPORT_ADD) { 417 ioc = LAGGIOC_ADDPORT; 418 } else { 419 ioc = LAGGIOC_DELPORT; 420 } 421 } 422 423 if (prop_dictionary_get_int64(env, "laggportpri", &pri)) { 424 ioc = LAGGIOC_SETPORTPRI; 425 rp->rp_prio = (uint32_t)pri; 426 } 427 428 if (ioc != LAGGIOC_NOCMD) { 429 req.lrq_ioctl = ioc; 430 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) { 431 if (lagg_debug) { 432 warn("cmd=%d", ioc); 433 } 434 return -1; 435 } 436 } 437 438 return 0; 439 } 440 441 static int 442 setlagglacp(prop_dictionary_t env, prop_dictionary_t oenv __unused) 443 { 444 struct lagg_req req_add, req_del; 445 struct laggreq_lacp *add_lacp, *del_lacp; 446 int64_t v; 447 448 memset(&req_add, 0, sizeof(req_add)); 449 memset(&req_del, 0, sizeof(req_del)); 450 451 req_add.lrq_proto = req_del.lrq_proto = LAGG_PROTO_LACP; 452 req_add.lrq_ioctl = req_del.lrq_ioctl = LAGGIOC_SETPROTOOPT; 453 add_lacp = &req_add.lrq_reqproto.rp_lacp; 454 del_lacp = &req_del.lrq_reqproto.rp_lacp; 455 456 add_lacp->command = LAGGIOC_LACPSETFLAGS; 457 del_lacp->command = LAGGIOC_LACPCLRFLAGS; 458 459 if (prop_dictionary_get_int64(env, "lacpdumpdu", &v)) { 460 if (v == LAGGLACPOPT_DUMPDU) { 461 add_lacp->flags |= LAGGREQLACP_DUMPDU; 462 } else { 463 del_lacp->flags |= LAGGREQLACP_DUMPDU; 464 } 465 } 466 467 if (prop_dictionary_get_int64(env, "lacpstopdu", &v)) { 468 if (v == LAGGLACPOPT_STOPDU) { 469 add_lacp->flags |= LAGGREQLACP_STOPDU; 470 } else { 471 del_lacp->flags |= LAGGREQLACP_STOPDU; 472 } 473 } 474 475 if (prop_dictionary_get_int64(env, "lacpoptimistic", &v)) { 476 if (v == LAGGLACPOPT_OPTIMISTIC) { 477 add_lacp->flags |= LAGGREQLACP_OPTIMISTIC; 478 } else { 479 del_lacp->flags |= LAGGREQLACP_OPTIMISTIC; 480 } 481 } 482 483 if (prop_dictionary_get_int64(env, "lacpmultils", &v)) { 484 if (v == LAGGLACPOPT_MULTILS) { 485 add_lacp->flags |= LAGGREQLACP_MULTILS; 486 } else { 487 del_lacp->flags |= LAGGREQLACP_MULTILS; 488 } 489 } 490 491 if (del_lacp->flags != 0) { 492 if (indirect_ioctl(env, SIOCSLAGG, &req_del) == -1) { 493 if (lagg_debug) { 494 warn("cmd=%d, pcmd=%d", 495 req_del.lrq_ioctl, 496 del_lacp->command); 497 } 498 return -1; 499 } 500 } 501 502 if (add_lacp->flags != 0) { 503 if (indirect_ioctl(env, SIOCSLAGG, &req_add) == -1) { 504 if (lagg_debug) { 505 warn("cmd=%d, pcmd=%d", 506 req_add.lrq_ioctl, 507 add_lacp->command); 508 } 509 return -1; 510 } 511 } 512 513 return 0; 514 } 515 516 static int 517 setlagglacpmaxports(prop_dictionary_t env, 518 prop_dictionary_t oenv __unused) 519 { 520 struct lagg_req req; 521 struct laggreq_lacp *lrq_lacp; 522 int64_t v; 523 524 memset(&req, 0, sizeof(req)); 525 req.lrq_proto = LAGG_PROTO_LACP; 526 req.lrq_ioctl = LAGGIOC_SETPROTOOPT; 527 lrq_lacp = &req.lrq_reqproto.rp_lacp; 528 529 if (!prop_dictionary_get_int64(env, "lacpmaxports", &v)) { 530 if (lagg_debug) 531 warnx("%s.%d", __func__, __LINE__); 532 errno = ENOENT; 533 return -1; 534 } 535 536 if (v <= 0) { 537 lrq_lacp->command = LAGGIOC_LACPCLRMAXPORTS; 538 } else if (v > 0){ 539 lrq_lacp->command = LAGGIOC_LACPSETMAXPORTS; 540 lrq_lacp->maxports = (size_t)v; 541 } 542 543 if (indirect_ioctl(env, SIOCSLAGG, &req) == -1) { 544 err(EXIT_FAILURE, "SIOCSLAGGPROTO"); 545 } 546 547 return 0; 548 } 549 550 static int 551 setlaggfail(prop_dictionary_t env, 552 prop_dictionary_t oenv __unused) 553 { 554 struct lagg_req req_add, req_del; 555 struct laggreq_fail *add_fail, *del_fail; 556 int64_t v; 557 558 memset(&req_add, 0, sizeof(req_add)); 559 memset(&req_del, 0, sizeof(req_del)); 560 561 req_add.lrq_proto = req_del.lrq_proto = LAGG_PROTO_FAILOVER; 562 req_add.lrq_ioctl = req_del.lrq_ioctl = LAGGIOC_SETPROTOOPT; 563 add_fail = &req_add.lrq_reqproto.rp_fail; 564 del_fail = &req_del.lrq_reqproto.rp_fail; 565 566 add_fail->command = LAGGIOC_FAILSETFLAGS; 567 del_fail->command = LAGGIOC_FAILCLRFLAGS; 568 569 if (prop_dictionary_get_int64(env, "failrxall", &v)) { 570 if (v == LAGGFAILOPT_RXALL) { 571 add_fail->flags |= LAGGREQFAIL_RXALL; 572 } else { 573 del_fail->flags |= LAGGREQFAIL_RXALL; 574 } 575 } 576 577 if (del_fail->flags != 0) { 578 if (indirect_ioctl(env, SIOCSLAGG, &req_del) == -1) { 579 if (lagg_debug) { 580 warn("cmd=%d, pcmd=%d", 581 req_del.lrq_ioctl, 582 del_fail->command); 583 } 584 return -1; 585 } 586 } 587 588 if (add_fail->flags != 0) { 589 if (indirect_ioctl(env, SIOCSLAGG, &req_add) == -1) { 590 if (lagg_debug) { 591 warn("cmd=%d, pcmd=%d", 592 req_add.lrq_ioctl, 593 add_fail->command); 594 } 595 return -1; 596 } 597 } 598 599 return 0; 600 } 601 602 static void 603 lagg_usage(prop_dictionary_t env __unused) 604 { 605 606 fprintf(stderr, "\t[ laggproto p ]\n"); 607 fprintf(stderr, "\t[ laggport i [ pri n ] ] " 608 "[ -laggport i ]\n"); 609 fprintf(stderr, "\t[ laggportpri i [ pri n]]\n"); 610 fprintf(stderr, "\t[ lagglacp [ dumpdu | -dumpdu ] " 611 "[ stopdu | -stopdu ]\n" 612 "\t\t[ maxports n | -maxports ] [ optimistic | -optimistic ] ]\n"); 613 fprintf(stderr, "\t[ laggfailover] [ rx-all | -rx-all ]\n"); 614 } 615 static void 616 lacp_format_id(char *buf, size_t len, 617 uint16_t system_prio, uint8_t *system_mac, uint16_t system_key) 618 { 619 620 snprintf(buf, len, "[%04X,%02X-%02X-%02X-%02X-%02X-%02X," 621 "%04X]", 622 system_prio, 623 (unsigned int)system_mac[0],(unsigned int)system_mac[1], 624 (unsigned int)system_mac[2],(unsigned int)system_mac[3], 625 (unsigned int)system_mac[4],(unsigned int)system_mac[5], 626 system_key); 627 } 628 629 static void 630 lagg_status_proto(lagg_proto pr, struct laggreqproto *req) 631 { 632 struct laggreq_lacp *lacp; 633 char str[256]; 634 635 switch (pr) { 636 case LAGG_PROTO_LACP: 637 lacp = &req->rp_lacp; 638 639 printf("\n"); 640 snprintb(str, sizeof(str), LAGGREQLACP_BITS, 641 lacp->flags); 642 printf("\t\tmax ports=%zu, flags=%s\n", 643 lacp->maxports, str); 644 645 lacp_format_id(str, sizeof(str), lacp->actor_prio, 646 lacp->actor_mac, lacp->actor_key); 647 printf("\t\tactor=%s\n", str); 648 649 lacp_format_id(str, sizeof(str), lacp->partner_prio, 650 lacp->partner_mac, lacp->partner_key); 651 printf("\t\tpartner=%s", str); 652 break; 653 default: 654 break; 655 } 656 } 657 658 static void 659 lagg_status_port(lagg_proto pr, struct laggreqport *req) 660 { 661 struct laggreq_lacpport *lacp; 662 char str[256]; 663 664 switch (pr) { 665 case LAGG_PROTO_LACP: 666 lacp = &req->rp_lacpport; 667 668 putchar('\n'); 669 670 snprintb(str, sizeof(str), LACP_STATE_BITS, lacp->actor_state); 671 printf("\t\t\tactor: state=%s\n",str); 672 673 lacp_format_id(str, sizeof(str), lacp->partner_prio, 674 lacp->partner_mac, lacp->partner_key); 675 printf("\t\t\tpartner=%s\n", str); 676 snprintb(str, sizeof(str), LACP_STATE_BITS, 677 lacp->partner_state); 678 printf("\t\t\tpartner: port=%04X prio=%04X state=%s", 679 lacp->partner_portno, lacp->partner_portprio, str); 680 break; 681 default: 682 break; 683 } 684 } 685