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