iproute2/ip/iplink_bond.c
<<
>>
Prefs
   1/*
   2 * iplink_bond.c        Bonding device support
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Jiri Pirko <jiri@resnulli.us>
  10 *              Scott Feldman <sfeldma@cumulusnetworks.com>
  11 */
  12
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <string.h>
  16#include <linux/if_bonding.h>
  17
  18#include "rt_names.h"
  19#include "utils.h"
  20#include "ip_common.h"
  21#include "json_print.h"
  22
  23#define BOND_MAX_ARP_TARGETS    16
  24
  25static unsigned int xstats_print_attr;
  26static int filter_index;
  27
  28static const char *mode_tbl[] = {
  29        "balance-rr",
  30        "active-backup",
  31        "balance-xor",
  32        "broadcast",
  33        "802.3ad",
  34        "balance-tlb",
  35        "balance-alb",
  36        NULL,
  37};
  38
  39static const char *arp_validate_tbl[] = {
  40        "none",
  41        "active",
  42        "backup",
  43        "all",
  44        "filter",
  45        "filter_active",
  46        "filter_backup",
  47        NULL,
  48};
  49
  50static const char *arp_all_targets_tbl[] = {
  51        "any",
  52        "all",
  53        NULL,
  54};
  55
  56static const char *primary_reselect_tbl[] = {
  57        "always",
  58        "better",
  59        "failure",
  60        NULL,
  61};
  62
  63static const char *fail_over_mac_tbl[] = {
  64        "none",
  65        "active",
  66        "follow",
  67        NULL,
  68};
  69
  70static const char *xmit_hash_policy_tbl[] = {
  71        "layer2",
  72        "layer3+4",
  73        "layer2+3",
  74        "encap2+3",
  75        "encap3+4",
  76        "vlan+srcmac",
  77        NULL,
  78};
  79
  80static const char *lacp_rate_tbl[] = {
  81        "slow",
  82        "fast",
  83        NULL,
  84};
  85
  86static const char *ad_select_tbl[] = {
  87        "stable",
  88        "bandwidth",
  89        "count",
  90        NULL,
  91};
  92
  93static const char *get_name(const char **tbl, int index)
  94{
  95        int i;
  96
  97        for (i = 0; tbl[i]; i++)
  98                if (i == index)
  99                        return tbl[i];
 100
 101        return "UNKNOWN";
 102}
 103
 104static int get_index(const char **tbl, char *name)
 105{
 106        int i, index;
 107
 108        /* check for integer index passed in instead of name */
 109        if (get_integer(&index, name, 10) == 0)
 110                for (i = 0; tbl[i]; i++)
 111                        if (i == index)
 112                                return i;
 113
 114        for (i = 0; tbl[i]; i++)
 115                if (strcmp(tbl[i], name) == 0)
 116                        return i;
 117
 118        return -1;
 119}
 120
 121static void print_explain(FILE *f)
 122{
 123        fprintf(f,
 124                "Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n"
 125                "                [ clear_active_slave ] [ miimon MIIMON ]\n"
 126                "                [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n"
 127                "                [ peer_notify_delay DELAY ]\n"
 128                "                [ use_carrier USE_CARRIER ]\n"
 129                "                [ arp_interval ARP_INTERVAL ]\n"
 130                "                [ arp_validate ARP_VALIDATE ]\n"
 131                "                [ arp_all_targets ARP_ALL_TARGETS ]\n"
 132                "                [ arp_ip_target [ ARP_IP_TARGET, ... ] ]\n"
 133                "                [ primary SLAVE_DEV ]\n"
 134                "                [ primary_reselect PRIMARY_RESELECT ]\n"
 135                "                [ fail_over_mac FAIL_OVER_MAC ]\n"
 136                "                [ xmit_hash_policy XMIT_HASH_POLICY ]\n"
 137                "                [ resend_igmp RESEND_IGMP ]\n"
 138                "                [ num_grat_arp|num_unsol_na NUM_GRAT_ARP|NUM_UNSOL_NA ]\n"
 139                "                [ all_slaves_active ALL_SLAVES_ACTIVE ]\n"
 140                "                [ min_links MIN_LINKS ]\n"
 141                "                [ lp_interval LP_INTERVAL ]\n"
 142                "                [ packets_per_slave PACKETS_PER_SLAVE ]\n"
 143                "                [ tlb_dynamic_lb TLB_DYNAMIC_LB ]\n"
 144                "                [ lacp_rate LACP_RATE ]\n"
 145                "                [ ad_select AD_SELECT ]\n"
 146                "                [ ad_user_port_key PORTKEY ]\n"
 147                "                [ ad_actor_sys_prio SYSPRIO ]\n"
 148                "                [ ad_actor_system LLADDR ]\n"
 149                "\n"
 150                "BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n"
 151                "ARP_VALIDATE := none|active|backup|all|filter|filter_active|filter_backup\n"
 152                "ARP_ALL_TARGETS := any|all\n"
 153                "PRIMARY_RESELECT := always|better|failure\n"
 154                "FAIL_OVER_MAC := none|active|follow\n"
 155                "XMIT_HASH_POLICY := layer2|layer2+3|layer3+4|encap2+3|encap3+4|vlan+srcmac\n"
 156                "LACP_RATE := slow|fast\n"
 157                "AD_SELECT := stable|bandwidth|count\n"
 158        );
 159}
 160
 161static void explain(void)
 162{
 163        print_explain(stderr);
 164}
 165
 166static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
 167                          struct nlmsghdr *n)
 168{
 169        __u8 mode, use_carrier, primary_reselect, fail_over_mac;
 170        __u8 xmit_hash_policy, num_peer_notif, all_slaves_active;
 171        __u8 lacp_rate, ad_select, tlb_dynamic_lb;
 172        __u16 ad_user_port_key, ad_actor_sys_prio;
 173        __u32 miimon, updelay, downdelay, peer_notify_delay, arp_interval, arp_validate;
 174        __u32 arp_all_targets, resend_igmp, min_links, lp_interval;
 175        __u32 packets_per_slave;
 176        unsigned int ifindex;
 177
 178        while (argc > 0) {
 179                if (matches(*argv, "mode") == 0) {
 180                        NEXT_ARG();
 181                        if (get_index(mode_tbl, *argv) < 0)
 182                                invarg("invalid mode", *argv);
 183                        mode = get_index(mode_tbl, *argv);
 184                        addattr8(n, 1024, IFLA_BOND_MODE, mode);
 185                } else if (matches(*argv, "active_slave") == 0) {
 186                        NEXT_ARG();
 187                        ifindex = ll_name_to_index(*argv);
 188                        if (!ifindex)
 189                                return nodev(*argv);
 190                        addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex);
 191                } else if (matches(*argv, "clear_active_slave") == 0) {
 192                        addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0);
 193                } else if (matches(*argv, "miimon") == 0) {
 194                        NEXT_ARG();
 195                        if (get_u32(&miimon, *argv, 0))
 196                                invarg("invalid miimon", *argv);
 197                        addattr32(n, 1024, IFLA_BOND_MIIMON, miimon);
 198                } else if (matches(*argv, "updelay") == 0) {
 199                        NEXT_ARG();
 200                        if (get_u32(&updelay, *argv, 0))
 201                                invarg("invalid updelay", *argv);
 202                        addattr32(n, 1024, IFLA_BOND_UPDELAY, updelay);
 203                } else if (matches(*argv, "downdelay") == 0) {
 204                        NEXT_ARG();
 205                        if (get_u32(&downdelay, *argv, 0))
 206                                invarg("invalid downdelay", *argv);
 207                        addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay);
 208                } else if (matches(*argv, "peer_notify_delay") == 0) {
 209                        NEXT_ARG();
 210                        if (get_u32(&peer_notify_delay, *argv, 0))
 211                                invarg("invalid peer_notify_delay", *argv);
 212                        addattr32(n, 1024, IFLA_BOND_PEER_NOTIF_DELAY, peer_notify_delay);
 213                } else if (matches(*argv, "use_carrier") == 0) {
 214                        NEXT_ARG();
 215                        if (get_u8(&use_carrier, *argv, 0))
 216                                invarg("invalid use_carrier", *argv);
 217                        addattr8(n, 1024, IFLA_BOND_USE_CARRIER, use_carrier);
 218                } else if (matches(*argv, "arp_interval") == 0) {
 219                        NEXT_ARG();
 220                        if (get_u32(&arp_interval, *argv, 0))
 221                                invarg("invalid arp_interval", *argv);
 222                        addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval);
 223                } else if (matches(*argv, "arp_ip_target") == 0) {
 224                        struct rtattr *nest = addattr_nest(n, 1024,
 225                                IFLA_BOND_ARP_IP_TARGET);
 226                        if (NEXT_ARG_OK()) {
 227                                NEXT_ARG();
 228                                char *targets = strdupa(*argv);
 229                                char *target = strtok(targets, ",");
 230                                int i;
 231
 232                                for (i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) {
 233                                        __u32 addr = get_addr32(target);
 234
 235                                        addattr32(n, 1024, i, addr);
 236                                        target = strtok(NULL, ",");
 237                                }
 238                                addattr_nest_end(n, nest);
 239                        }
 240                        addattr_nest_end(n, nest);
 241                } else if (matches(*argv, "arp_validate") == 0) {
 242                        NEXT_ARG();
 243                        if (get_index(arp_validate_tbl, *argv) < 0)
 244                                invarg("invalid arp_validate", *argv);
 245                        arp_validate = get_index(arp_validate_tbl, *argv);
 246                        addattr32(n, 1024, IFLA_BOND_ARP_VALIDATE, arp_validate);
 247                } else if (matches(*argv, "arp_all_targets") == 0) {
 248                        NEXT_ARG();
 249                        if (get_index(arp_all_targets_tbl, *argv) < 0)
 250                                invarg("invalid arp_all_targets", *argv);
 251                        arp_all_targets = get_index(arp_all_targets_tbl, *argv);
 252                        addattr32(n, 1024, IFLA_BOND_ARP_ALL_TARGETS, arp_all_targets);
 253                } else if (matches(*argv, "primary") == 0) {
 254                        NEXT_ARG();
 255                        ifindex = ll_name_to_index(*argv);
 256                        if (!ifindex)
 257                                return nodev(*argv);
 258                        addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex);
 259                } else if (matches(*argv, "primary_reselect") == 0) {
 260                        NEXT_ARG();
 261                        if (get_index(primary_reselect_tbl, *argv) < 0)
 262                                invarg("invalid primary_reselect", *argv);
 263                        primary_reselect = get_index(primary_reselect_tbl, *argv);
 264                        addattr8(n, 1024, IFLA_BOND_PRIMARY_RESELECT,
 265                                 primary_reselect);
 266                } else if (matches(*argv, "fail_over_mac") == 0) {
 267                        NEXT_ARG();
 268                        if (get_index(fail_over_mac_tbl, *argv) < 0)
 269                                invarg("invalid fail_over_mac", *argv);
 270                        fail_over_mac = get_index(fail_over_mac_tbl, *argv);
 271                        addattr8(n, 1024, IFLA_BOND_FAIL_OVER_MAC,
 272                                 fail_over_mac);
 273                } else if (matches(*argv, "xmit_hash_policy") == 0) {
 274                        NEXT_ARG();
 275                        if (get_index(xmit_hash_policy_tbl, *argv) < 0)
 276                                invarg("invalid xmit_hash_policy", *argv);
 277
 278                        xmit_hash_policy = get_index(xmit_hash_policy_tbl, *argv);
 279                        addattr8(n, 1024, IFLA_BOND_XMIT_HASH_POLICY,
 280                                 xmit_hash_policy);
 281                } else if (matches(*argv, "resend_igmp") == 0) {
 282                        NEXT_ARG();
 283                        if (get_u32(&resend_igmp, *argv, 0))
 284                                invarg("invalid resend_igmp", *argv);
 285
 286                        addattr32(n, 1024, IFLA_BOND_RESEND_IGMP, resend_igmp);
 287                } else if (matches(*argv, "num_grat_arp") == 0 ||
 288                           matches(*argv, "num_unsol_na") == 0) {
 289                        NEXT_ARG();
 290                        if (get_u8(&num_peer_notif, *argv, 0))
 291                                invarg("invalid num_grat_arp|num_unsol_na",
 292                                       *argv);
 293
 294                        addattr8(n, 1024, IFLA_BOND_NUM_PEER_NOTIF,
 295                                 num_peer_notif);
 296                } else if (matches(*argv, "all_slaves_active") == 0) {
 297                        NEXT_ARG();
 298                        if (get_u8(&all_slaves_active, *argv, 0))
 299                                invarg("invalid all_slaves_active", *argv);
 300
 301                        addattr8(n, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE,
 302                                 all_slaves_active);
 303                } else if (matches(*argv, "min_links") == 0) {
 304                        NEXT_ARG();
 305                        if (get_u32(&min_links, *argv, 0))
 306                                invarg("invalid min_links", *argv);
 307
 308                        addattr32(n, 1024, IFLA_BOND_MIN_LINKS, min_links);
 309                } else if (matches(*argv, "lp_interval") == 0) {
 310                        NEXT_ARG();
 311                        if (get_u32(&lp_interval, *argv, 0))
 312                                invarg("invalid lp_interval", *argv);
 313
 314                        addattr32(n, 1024, IFLA_BOND_LP_INTERVAL, lp_interval);
 315                } else if (matches(*argv, "packets_per_slave") == 0) {
 316                        NEXT_ARG();
 317                        if (get_u32(&packets_per_slave, *argv, 0))
 318                                invarg("invalid packets_per_slave", *argv);
 319
 320                        addattr32(n, 1024, IFLA_BOND_PACKETS_PER_SLAVE,
 321                                  packets_per_slave);
 322                } else if (matches(*argv, "lacp_rate") == 0) {
 323                        NEXT_ARG();
 324                        if (get_index(lacp_rate_tbl, *argv) < 0)
 325                                invarg("invalid lacp_rate", *argv);
 326
 327                        lacp_rate = get_index(lacp_rate_tbl, *argv);
 328                        addattr8(n, 1024, IFLA_BOND_AD_LACP_RATE, lacp_rate);
 329                } else if (matches(*argv, "ad_select") == 0) {
 330                        NEXT_ARG();
 331                        if (get_index(ad_select_tbl, *argv) < 0)
 332                                invarg("invalid ad_select", *argv);
 333
 334                        ad_select = get_index(ad_select_tbl, *argv);
 335                        addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select);
 336                } else if (matches(*argv, "ad_user_port_key") == 0) {
 337                        NEXT_ARG();
 338                        if (get_u16(&ad_user_port_key, *argv, 0))
 339                                invarg("invalid ad_user_port_key", *argv);
 340
 341                        addattr16(n, 1024, IFLA_BOND_AD_USER_PORT_KEY,
 342                                  ad_user_port_key);
 343                } else if (matches(*argv, "ad_actor_sys_prio") == 0) {
 344                        NEXT_ARG();
 345                        if (get_u16(&ad_actor_sys_prio, *argv, 0))
 346                                invarg("invalid ad_actor_sys_prio", *argv);
 347
 348                        addattr16(n, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO,
 349                                  ad_actor_sys_prio);
 350                } else if (matches(*argv, "ad_actor_system") == 0) {
 351                        int len;
 352                        char abuf[32];
 353
 354                        NEXT_ARG();
 355                        len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
 356                        if (len < 0)
 357                                return -1;
 358                        addattr_l(n, 1024, IFLA_BOND_AD_ACTOR_SYSTEM,
 359                                  abuf, len);
 360                } else if (matches(*argv, "tlb_dynamic_lb") == 0) {
 361                        NEXT_ARG();
 362                        if (get_u8(&tlb_dynamic_lb, *argv, 0)) {
 363                                invarg("invalid tlb_dynamic_lb", *argv);
 364                                return -1;
 365                        }
 366                        addattr8(n, 1024, IFLA_BOND_TLB_DYNAMIC_LB,
 367                                 tlb_dynamic_lb);
 368                } else if (matches(*argv, "help") == 0) {
 369                        explain();
 370                        return -1;
 371                } else {
 372                        fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv);
 373                        explain();
 374                        return -1;
 375                }
 376                argc--, argv++;
 377        }
 378
 379        return 0;
 380}
 381
 382static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 383{
 384        if (!tb)
 385                return;
 386
 387        if (tb[IFLA_BOND_MODE]) {
 388                const char *mode = get_name(mode_tbl,
 389                                            rta_getattr_u8(tb[IFLA_BOND_MODE]));
 390                print_string(PRINT_ANY, "mode", "mode %s ", mode);
 391        }
 392
 393        if (tb[IFLA_BOND_ACTIVE_SLAVE]) {
 394                unsigned int ifindex =
 395                        rta_getattr_u32(tb[IFLA_BOND_ACTIVE_SLAVE]);
 396
 397                if (ifindex) {
 398                        print_string(PRINT_ANY,
 399                                     "active_slave",
 400                                     "active_slave %s ",
 401                                     ll_index_to_name(ifindex));
 402                }
 403        }
 404
 405        if (tb[IFLA_BOND_MIIMON])
 406                print_uint(PRINT_ANY,
 407                           "miimon",
 408                           "miimon %u ",
 409                           rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
 410
 411        if (tb[IFLA_BOND_UPDELAY])
 412                print_uint(PRINT_ANY,
 413                           "updelay",
 414                           "updelay %u ",
 415                           rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
 416
 417        if (tb[IFLA_BOND_DOWNDELAY])
 418                print_uint(PRINT_ANY,
 419                           "downdelay",
 420                           "downdelay %u ",
 421                           rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
 422
 423        if (tb[IFLA_BOND_PEER_NOTIF_DELAY])
 424                print_uint(PRINT_ANY,
 425                           "peer_notify_delay",
 426                           "peer_notify_delay %u ",
 427                           rta_getattr_u32(tb[IFLA_BOND_PEER_NOTIF_DELAY]));
 428
 429        if (tb[IFLA_BOND_USE_CARRIER])
 430                print_uint(PRINT_ANY,
 431                           "use_carrier",
 432                           "use_carrier %u ",
 433                           rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
 434
 435        if (tb[IFLA_BOND_ARP_INTERVAL])
 436                print_uint(PRINT_ANY,
 437                           "arp_interval",
 438                           "arp_interval %u ",
 439                           rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
 440
 441        if (tb[IFLA_BOND_ARP_IP_TARGET]) {
 442                struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1];
 443                int i;
 444
 445                parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
 446                                    tb[IFLA_BOND_ARP_IP_TARGET]);
 447
 448                if (iptb[0]) {
 449                        open_json_array(PRINT_JSON, "arp_ip_target");
 450                        print_string(PRINT_FP, NULL, "arp_ip_target ", NULL);
 451                }
 452
 453                for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
 454                        if (iptb[i])
 455                                print_string(PRINT_ANY,
 456                                             NULL,
 457                                             "%s",
 458                                             rt_addr_n2a_rta(AF_INET, iptb[i]));
 459                        if (!is_json_context()
 460                            && i < BOND_MAX_ARP_TARGETS-1
 461                            && iptb[i+1])
 462                                fprintf(f, ",");
 463                }
 464
 465                if (iptb[0]) {
 466                        print_string(PRINT_FP, NULL, " ", NULL);
 467                        close_json_array(PRINT_JSON, NULL);
 468                }
 469        }
 470
 471        if (tb[IFLA_BOND_ARP_VALIDATE]) {
 472                __u32 arp_v = rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]);
 473                const char *arp_validate = get_name(arp_validate_tbl, arp_v);
 474
 475                if (!arp_v && is_json_context())
 476                        print_null(PRINT_JSON, "arp_validate", NULL, NULL);
 477                else
 478                        print_string(PRINT_ANY,
 479                                     "arp_validate",
 480                                     "arp_validate %s ",
 481                                     arp_validate);
 482        }
 483
 484        if (tb[IFLA_BOND_ARP_ALL_TARGETS]) {
 485                const char *arp_all_targets = get_name(arp_all_targets_tbl,
 486                                                       rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
 487                print_string(PRINT_ANY,
 488                             "arp_all_targets",
 489                             "arp_all_targets %s ",
 490                             arp_all_targets);
 491        }
 492
 493        if (tb[IFLA_BOND_PRIMARY]) {
 494                unsigned int ifindex = rta_getattr_u32(tb[IFLA_BOND_PRIMARY]);
 495
 496                if (ifindex) {
 497                        print_string(PRINT_ANY,
 498                                     "primary",
 499                                     "primary %s ",
 500                                     ll_index_to_name(ifindex));
 501                }
 502        }
 503
 504        if (tb[IFLA_BOND_PRIMARY_RESELECT]) {
 505                const char *primary_reselect = get_name(primary_reselect_tbl,
 506                                                        rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
 507                print_string(PRINT_ANY,
 508                             "primary_reselect",
 509                             "primary_reselect %s ",
 510                             primary_reselect);
 511        }
 512
 513        if (tb[IFLA_BOND_FAIL_OVER_MAC]) {
 514                const char *fail_over_mac = get_name(fail_over_mac_tbl,
 515                                                     rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
 516                print_string(PRINT_ANY,
 517                             "fail_over_mac",
 518                             "fail_over_mac %s ",
 519                             fail_over_mac);
 520        }
 521
 522        if (tb[IFLA_BOND_XMIT_HASH_POLICY]) {
 523                const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl,
 524                                                        rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
 525                print_string(PRINT_ANY,
 526                             "xmit_hash_policy",
 527                             "xmit_hash_policy %s ",
 528                             xmit_hash_policy);
 529        }
 530
 531        if (tb[IFLA_BOND_RESEND_IGMP])
 532                print_uint(PRINT_ANY,
 533                           "resend_igmp",
 534                           "resend_igmp %u ",
 535                           rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
 536
 537        if (tb[IFLA_BOND_NUM_PEER_NOTIF])
 538                print_uint(PRINT_ANY,
 539                           "num_peer_notif",
 540                           "num_grat_arp %u ",
 541                           rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
 542
 543        if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
 544                print_uint(PRINT_ANY,
 545                           "all_slaves_active",
 546                           "all_slaves_active %u ",
 547                           rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
 548
 549        if (tb[IFLA_BOND_MIN_LINKS])
 550                print_uint(PRINT_ANY,
 551                           "min_links",
 552                           "min_links %u ",
 553                           rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
 554
 555        if (tb[IFLA_BOND_LP_INTERVAL])
 556                print_uint(PRINT_ANY,
 557                           "lp_interval",
 558                           "lp_interval %u ",
 559                           rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
 560
 561        if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
 562                print_uint(PRINT_ANY,
 563                           "packets_per_slave",
 564                           "packets_per_slave %u ",
 565                           rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
 566
 567        if (tb[IFLA_BOND_AD_LACP_RATE]) {
 568                const char *lacp_rate = get_name(lacp_rate_tbl,
 569                                                 rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
 570                print_string(PRINT_ANY,
 571                             "ad_lacp_rate",
 572                             "lacp_rate %s ",
 573                             lacp_rate);
 574        }
 575
 576        if (tb[IFLA_BOND_AD_SELECT]) {
 577                const char *ad_select = get_name(ad_select_tbl,
 578                                                 rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
 579                print_string(PRINT_ANY,
 580                             "ad_select",
 581                             "ad_select %s ",
 582                             ad_select);
 583        }
 584
 585        if (tb[IFLA_BOND_AD_INFO]) {
 586                struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1];
 587
 588                parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX,
 589                                    tb[IFLA_BOND_AD_INFO]);
 590
 591                open_json_object("ad_info");
 592
 593                if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR])
 594                        print_int(PRINT_ANY,
 595                                  "aggregator",
 596                                  "ad_aggregator %d ",
 597                                  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
 598
 599                if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS])
 600                        print_int(PRINT_ANY,
 601                                  "num_ports",
 602                                  "ad_num_ports %d ",
 603                                  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
 604
 605                if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])
 606                        print_int(PRINT_ANY,
 607                                  "actor_key",
 608                                  "ad_actor_key %d ",
 609                                  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
 610
 611                if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])
 612                        print_int(PRINT_ANY,
 613                                  "partner_key",
 614                                  "ad_partner_key %d ",
 615                                  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
 616
 617                if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) {
 618                        unsigned char *p =
 619                                RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]);
 620                        SPRINT_BUF(b);
 621                        print_string(PRINT_ANY,
 622                                     "partner_mac",
 623                                     "ad_partner_mac %s ",
 624                                     ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
 625                }
 626
 627                close_json_object();
 628        }
 629
 630        if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
 631                print_uint(PRINT_ANY,
 632                           "ad_actor_sys_prio",
 633                           "ad_actor_sys_prio %u ",
 634                           rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
 635        }
 636
 637        if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
 638                print_uint(PRINT_ANY,
 639                           "ad_user_port_key",
 640                           "ad_user_port_key %u ",
 641                           rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
 642        }
 643
 644        if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
 645                /* We assume the l2 address is an Ethernet MAC address */
 646                SPRINT_BUF(b1);
 647
 648                print_string(PRINT_ANY,
 649                             "ad_actor_system",
 650                             "ad_actor_system %s ",
 651                             ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
 652                                         RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
 653                                         1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
 654        }
 655
 656        if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) {
 657                print_uint(PRINT_ANY,
 658                           "tlb_dynamic_lb",
 659                           "tlb_dynamic_lb %u ",
 660                           rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
 661        }
 662}
 663
 664static void bond_print_help(struct link_util *lu, int argc, char **argv,
 665                            FILE *f)
 666{
 667        print_explain(f);
 668}
 669
 670static void bond_print_xstats_help(struct link_util *lu, FILE *f)
 671{
 672        fprintf(f, "Usage: ... %s [ 802.3ad ] [ dev DEVICE ]\n", lu->id);
 673}
 674
 675static void bond_print_3ad_stats(struct rtattr *lacpattr)
 676{
 677        struct rtattr *lacptb[BOND_3AD_STAT_MAX+1];
 678        __u64 val;
 679
 680        parse_rtattr(lacptb, BOND_3AD_STAT_MAX, RTA_DATA(lacpattr),
 681                     RTA_PAYLOAD(lacpattr));
 682        open_json_object("802.3ad");
 683        if (lacptb[BOND_3AD_STAT_LACPDU_RX]) {
 684                print_string(PRINT_FP, NULL, "%-16s    ", "");
 685                print_u64(PRINT_ANY, "lacpdu_rx", "LACPDU Rx %llu\n",
 686                          rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_RX]));
 687        }
 688        if (lacptb[BOND_3AD_STAT_LACPDU_TX]) {
 689                print_string(PRINT_FP, NULL, "%-16s    ", "");
 690                print_u64(PRINT_ANY, "lacpdu_tx", "LACPDU Tx %llu\n",
 691                          rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_TX]));
 692        }
 693        if (lacptb[BOND_3AD_STAT_LACPDU_UNKNOWN_RX]) {
 694                print_string(PRINT_FP, NULL, "%-16s    ", "");
 695                val = rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_UNKNOWN_RX]);
 696                print_u64(PRINT_ANY,
 697                          "lacpdu_unknown_rx",
 698                          "LACPDU Unknown type Rx %llu\n",
 699                          val);
 700        }
 701        if (lacptb[BOND_3AD_STAT_LACPDU_ILLEGAL_RX]) {
 702                print_string(PRINT_FP, NULL, "%-16s    ", "");
 703                val = rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_ILLEGAL_RX]);
 704                print_u64(PRINT_ANY,
 705                          "lacpdu_illegal_rx",
 706                          "LACPDU Illegal Rx %llu\n",
 707                          val);
 708        }
 709        if (lacptb[BOND_3AD_STAT_MARKER_RX]) {
 710                print_string(PRINT_FP, NULL, "%-16s    ", "");
 711                print_u64(PRINT_ANY, "marker_rx", "Marker Rx %llu\n",
 712                          rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_RX]));
 713        }
 714        if (lacptb[BOND_3AD_STAT_MARKER_TX]) {
 715                print_string(PRINT_FP, NULL, "%-16s    ", "");
 716                print_u64(PRINT_ANY, "marker_tx", "Marker Tx %llu\n",
 717                          rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_TX]));
 718        }
 719        if (lacptb[BOND_3AD_STAT_MARKER_RESP_RX]) {
 720                print_string(PRINT_FP, NULL, "%-16s    ", "");
 721                val = rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_RESP_RX]);
 722                print_u64(PRINT_ANY,
 723                          "marker_response_rx",
 724                          "Marker response Rx %llu\n",
 725                          val);
 726        }
 727        if (lacptb[BOND_3AD_STAT_MARKER_RESP_TX]) {
 728                print_string(PRINT_FP, NULL, "%-16s    ", "");
 729                val = rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_RESP_TX]);
 730                print_u64(PRINT_ANY,
 731                          "marker_response_tx",
 732                          "Marker response Tx %llu\n",
 733                          val);
 734        }
 735        if (lacptb[BOND_3AD_STAT_MARKER_UNKNOWN_RX]) {
 736                print_string(PRINT_FP, NULL, "%-16s    ", "");
 737                val = rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_UNKNOWN_RX]);
 738                print_u64(PRINT_ANY,
 739                          "marker_unknown_rx",
 740                          "Marker unknown type Rx %llu\n",
 741                          val);
 742        }
 743        close_json_object();
 744}
 745
 746static void bond_print_stats_attr(struct rtattr *attr, int ifindex)
 747{
 748        struct rtattr *bondtb[LINK_XSTATS_TYPE_MAX+1];
 749        struct rtattr *i, *list;
 750        const char *ifname = "";
 751        int rem;
 752
 753        parse_rtattr(bondtb, LINK_XSTATS_TYPE_MAX+1, RTA_DATA(attr),
 754        RTA_PAYLOAD(attr));
 755        if (!bondtb[LINK_XSTATS_TYPE_BOND])
 756                return;
 757
 758        list = bondtb[LINK_XSTATS_TYPE_BOND];
 759        rem = RTA_PAYLOAD(list);
 760        open_json_object(NULL);
 761        ifname = ll_index_to_name(ifindex);
 762        print_string(PRINT_ANY, "ifname", "%-16s\n", ifname);
 763        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 764                if (xstats_print_attr && i->rta_type != xstats_print_attr)
 765                        continue;
 766
 767                switch (i->rta_type) {
 768                case BOND_XSTATS_3AD:
 769                        bond_print_3ad_stats(i);
 770                        break;
 771                }
 772                break;
 773        }
 774        close_json_object();
 775}
 776
 777int bond_print_xstats(struct nlmsghdr *n, void *arg)
 778{
 779        struct if_stats_msg *ifsm = NLMSG_DATA(n);
 780        struct rtattr *tb[IFLA_STATS_MAX+1];
 781        int len = n->nlmsg_len;
 782
 783        len -= NLMSG_LENGTH(sizeof(*ifsm));
 784        if (len < 0) {
 785                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 786                return -1;
 787        }
 788        if (filter_index && filter_index != ifsm->ifindex)
 789                return 0;
 790
 791        parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
 792        if (tb[IFLA_STATS_LINK_XSTATS])
 793                bond_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
 794                                      ifsm->ifindex);
 795
 796        if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
 797                bond_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
 798                                      ifsm->ifindex);
 799
 800        return 0;
 801}
 802
 803int bond_parse_xstats(struct link_util *lu, int argc, char **argv)
 804{
 805        while (argc > 0) {
 806                if (strcmp(*argv, "lacp") == 0 ||
 807                    strcmp(*argv, "802.3ad") == 0) {
 808                        xstats_print_attr = BOND_XSTATS_3AD;
 809                } else if (strcmp(*argv, "dev") == 0) {
 810                        NEXT_ARG();
 811                        filter_index = ll_name_to_index(*argv);
 812                        if (!filter_index)
 813                                return nodev(*argv);
 814                } else if (strcmp(*argv, "help") == 0) {
 815                        bond_print_xstats_help(lu, stdout);
 816                        exit(0);
 817                } else {
 818                        invarg("unknown attribute", *argv);
 819                }
 820                argc--; argv++;
 821        }
 822
 823        return 0;
 824}
 825
 826
 827struct link_util bond_link_util = {
 828        .id             = "bond",
 829        .maxattr        = IFLA_BOND_MAX,
 830        .parse_opt      = bond_parse_opt,
 831        .print_opt      = bond_print_opt,
 832        .print_help     = bond_print_help,
 833        .parse_ifla_xstats = bond_parse_xstats,
 834        .print_ifla_xstats = bond_print_xstats,
 835};
 836