From patchwork Sat Jan 4 02:45:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: sfeldma@cumulusnetworks.com X-Patchwork-Id: 306764 X-Patchwork-Delegate: shemminger@vyatta.com Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 6F7112C007E for ; Sat, 4 Jan 2014 13:45:49 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755044AbaADCpp (ORCPT ); Fri, 3 Jan 2014 21:45:45 -0500 Received: from ext3.cumulusnetworks.com ([198.211.106.187]:56282 "EHLO ext3.cumulusnetworks.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755037AbaADCpn (ORCPT ); Fri, 3 Jan 2014 21:45:43 -0500 Received: from localhost (localhost [127.0.0.1]) by ext3.cumulusnetworks.com (Postfix) with ESMTP id AC8CD14DBEA7; Fri, 3 Jan 2014 18:45:42 -0800 (PST) Received: from ext3.cumulusnetworks.com ([127.0.0.1]) by localhost (ext3.cumulusnetworks.com [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id KFeuvEwsMBDj; Fri, 3 Jan 2014 18:45:41 -0800 (PST) Received: from localhost (localhost [127.0.0.1]) by ext3.cumulusnetworks.com (Postfix) with ESMTP id B5D5214DBEA4; Fri, 3 Jan 2014 18:45:41 -0800 (PST) X-Virus-Scanned: amavisd-new at cumulusnetworks.com Received: from ext3.cumulusnetworks.com ([127.0.0.1]) by localhost (ext3.cumulusnetworks.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id cCkyJrDPpgXi; Fri, 3 Jan 2014 18:45:41 -0800 (PST) Received: from [127.0.1.1] (unknown [216.129.126.126]) by ext3.cumulusnetworks.com (Postfix) with ESMTPSA id 18DD414DBEA3; Fri, 3 Jan 2014 18:45:41 -0800 (PST) Subject: [PATCH iproute2] iproute2: finish support for bonding attributes To: stephen@networkplumber.org From: Scott Feldman Cc: netdev@vger.kernel.org, roopa@cumulusnetworks.com, shm@cumulusnetworks.com, jiri@resnulli.us Date: Fri, 03 Jan 2014 18:45:38 -0800 Message-ID: <20140104024538.3123.21977.stgit@debian> User-Agent: StGit/0.15 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add support for bonding attributes just added to net-next. On set, allow string or number value for enumerated attributes. On show, use always use string value for attribute. Signed-off-by: Scott Feldman --- include/linux/if_link.h | 32 +++ ip/iplink_bond.c | 458 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 483 insertions(+), 7 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 4b727a5..098be3d 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -329,11 +329,43 @@ enum { IFLA_BOND_UNSPEC, IFLA_BOND_MODE, IFLA_BOND_ACTIVE_SLAVE, + IFLA_BOND_MIIMON, + IFLA_BOND_UPDELAY, + IFLA_BOND_DOWNDELAY, + IFLA_BOND_USE_CARRIER, + IFLA_BOND_ARP_INTERVAL, + IFLA_BOND_ARP_IP_TARGET, + IFLA_BOND_ARP_VALIDATE, + IFLA_BOND_ARP_ALL_TARGETS, + IFLA_BOND_PRIMARY, + IFLA_BOND_PRIMARY_RESELECT, + IFLA_BOND_FAIL_OVER_MAC, + IFLA_BOND_XMIT_HASH_POLICY, + IFLA_BOND_RESEND_IGMP, + IFLA_BOND_NUM_PEER_NOTIF, + IFLA_BOND_ALL_SLAVES_ACTIVE, + IFLA_BOND_MIN_LINKS, + IFLA_BOND_LP_INTERVAL, + IFLA_BOND_PACKETS_PER_SLAVE, + IFLA_BOND_AD_LACP_RATE, + IFLA_BOND_AD_SELECT, + IFLA_BOND_AD_INFO, __IFLA_BOND_MAX, }; #define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) +enum { + IFLA_BOND_AD_INFO_AGGREGATOR, + IFLA_BOND_AD_INFO_NUM_PORTS, + IFLA_BOND_AD_INFO_ACTOR_KEY, + IFLA_BOND_AD_INFO_PARTNER_KEY, + IFLA_BOND_AD_INFO_PARTNER_MAC, + __IFLA_BOND_AD_INFO_MAX, +}; + +#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1) + /* SR-IOV virtual function management section */ enum { diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c index 3fb7f4f..f0e5ab1 100644 --- a/ip/iplink_bond.c +++ b/ip/iplink_bond.c @@ -7,41 +7,165 @@ * 2 of the License, or (at your option) any later version. * * Authors: Jiri Pirko + * Scott Feldman */ #include #include #include #include +#include #include #include "rt_names.h" #include "utils.h" #include "ip_common.h" +#define BOND_MAX_ARP_TARGETS 16 + +static const char *mode_tbl[] = { + "balance-rr", + "active-backup", + "balance-xor", + "broadcast", + "802.3ad", + "balance-tlb", + "balance-alb", + NULL, +}; + +static const char *arp_validate_tbl[] = { + "none", + "active", + "backup", + "all", + NULL, +}; + +static const char *arp_all_targets_tbl[] = { + "any", + "all", + NULL, +}; + +static const char *primary_reselect_tbl[] = { + "always", + "better", + "failure", + NULL, +}; + +static const char *fail_over_mac_tbl[] = { + "none", + "active", + "follow", + NULL, +}; + +static const char *xmit_hash_policy_tbl[] = { + "layer2", + "layer3+4", + "layer2+3", + "encap2+3", + "encap3+4", + NULL, +}; + +static const char *lacp_rate_tbl[] = { + "slow", + "fast", + NULL, +}; + +static const char *ad_select_tbl[] = { + "stable", + "bandwidth", + "count", + NULL, +}; + +static const char *get_name(const char **tbl, int index) +{ + int i; + + for (i = 0; tbl[i]; i++) + if (i == index) + return tbl[i]; + + return "UNKNOWN"; +} + +static int get_index(const char **tbl, char *name) +{ + int i, index; + + /* check for integer index passed in instead of name */ + if (get_integer(&index, name, 10) == 0) + for (i = 0; tbl[i]; i++) + if (i == index) + return i; + + for (i = 0; tbl[i]; i++) + if (strncmp(tbl[i], name, strlen(tbl[i])) == 0) + return i; + + return -1; +} + static void explain(void) { fprintf(stderr, "Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n" - " [ clear_active_slave ]\n" + " [ clear_active_slave ] [ miimon MIIMON ]\n" + " [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n" + " [ use_carrier USE_CARRIER ]\n" + " [ arp_interval ARP_INTERVAL ]\n" + " [ arp_validate ARP_VALIDATE ]\n" + " [ arp_all_targets ARP_ALL_TARGETS ]\n" + " [ arp_ip_target [ ARP_IP_TARGET, ... ] ]\n" + " [ primary SLAVE_DEV ]\n" + " [ primary_reselect PRIMARY_RESELECT ]\n" + " [ fail_over_mac FAIL_OVER_MAC ]\n" + " [ xmit_hash_policy XMIT_HASH_POLICY ]\n" + " [ resend_igmp RESEND_IGMP ]\n" + " [ num_grat_arp|num_unsol_na NUM_GRAT_ARP|NUM_UNSOL_NA ]\n" + " [ all_slaves_active ALL_SLAVES_ACTIVE ]\n" + " [ min_links MIN_LINKS ]\n" + " [ lp_interval LP_INTERVAL ]\n" + " [ packets_per_slave PACKETS_PER_SLAVE ]\n" + " [ lacp_rate LACP_RATE ]\n" + " [ ad_select AD_SELECT ]\n" "\n" - "BONDMODE := 0-6\n" + "BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n" + "ARP_VALIDATE := none|active|backup|all\n" + "ARP_ALL_TARGETS := any|all\n" + "PRIMARY_RESELECT := always|better|failure\n" + "FAIL_OVER_MAC := none|active|follow\n" + "XMIT_HASH_POLICY := layer2|layer2+3|layer3+4\n" + "LACP_RATE := slow|fast\n" + "AD_SELECT := stable|bandwidth|count\n" ); } static int bond_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { - __u8 mode; + __u8 mode, use_carrier, primary_reselect, fail_over_mac; + __u8 xmit_hash_policy, num_peer_notif, all_slaves_active; + __u8 lacp_rate, ad_select; + __u32 miimon, updelay, downdelay, arp_interval, arp_validate; + __u32 arp_all_targets, resend_igmp, min_links, lp_interval; + __u32 packets_per_slave; unsigned ifindex; while (argc > 0) { if (matches(*argv, "mode") == 0) { NEXT_ARG(); - if (get_u8(&mode, *argv, 0)) { - invarg("mode %s is invalid", *argv); + if (get_index(mode_tbl, *argv) < 0) { + invarg("invalid mode", *argv); return -1; } + mode = get_index(mode_tbl, *argv); addattr8(n, 1024, IFLA_BOND_MODE, mode); } else if (matches(*argv, "active_slave") == 0) { NEXT_ARG(); @@ -51,6 +175,170 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex); } else if (matches(*argv, "clear_active_slave") == 0) { addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0); + } else if (matches(*argv, "miimon") == 0) { + NEXT_ARG(); + if (get_u32(&miimon, *argv, 0)) { + invarg("invalid miimon", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_MIIMON, miimon); + } else if (matches(*argv, "updelay") == 0) { + NEXT_ARG(); + if (get_u32(&updelay, *argv, 0)) { + invarg("invalid updelay", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_UPDELAY, updelay); + } else if (matches(*argv, "downdelay") == 0) { + NEXT_ARG(); + if (get_u32(&downdelay, *argv, 0)) { + invarg("invalid downdelay", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay); + } else if (matches(*argv, "use_carrier") == 0) { + NEXT_ARG(); + if (get_u8(&use_carrier, *argv, 0)) { + invarg("invalid use_carrier", *argv); + return -1; + } + addattr8(n, 1024, IFLA_BOND_USE_CARRIER, use_carrier); + } else if (matches(*argv, "arp_interval") == 0) { + NEXT_ARG(); + if (get_u32(&arp_interval, *argv, 0)) { + invarg("invalid arp_interval", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval); + } else if (matches(*argv, "arp_ip_target") == 0) { + struct rtattr * nest = addattr_nest(n, 1024, + IFLA_BOND_ARP_IP_TARGET); + if (NEXT_ARG_OK()) { + NEXT_ARG(); + char *targets = strdupa(*argv); + char *target = strtok(targets, ","); + int i; + + for(i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) { + __u32 addr = get_addr32(target); + addattr32(n, 1024, i, addr); + target = strtok(NULL, ","); + } + addattr_nest_end(n, nest); + } + addattr_nest_end(n, nest); + } else if (matches(*argv, "arp_validate") == 0) { + NEXT_ARG(); + if (get_index(arp_validate_tbl, *argv) < 0) { + invarg("invalid arp_validate", *argv); + return -1; + } + arp_validate = get_index(arp_validate_tbl, *argv); + addattr32(n, 1024, IFLA_BOND_ARP_VALIDATE, arp_validate); + } else if (matches(*argv, "arp_all_targets") == 0) { + NEXT_ARG(); + if (get_index(arp_all_targets_tbl, *argv) < 0) { + invarg("invalid arp_all_targets", *argv); + return -1; + } + arp_all_targets = get_index(arp_all_targets_tbl, *argv); + addattr32(n, 1024, IFLA_BOND_ARP_ALL_TARGETS, arp_all_targets); + } else if (matches(*argv, "primary") == 0) { + NEXT_ARG(); + ifindex = if_nametoindex(*argv); + if (!ifindex) + return -1; + addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex); + } else if (matches(*argv, "primary_reselect") == 0) { + NEXT_ARG(); + if (get_index(primary_reselect_tbl, *argv) < 0) { + invarg("invalid primary_reselect", *argv); + return -1; + } + primary_reselect = get_index(primary_reselect_tbl, *argv); + addattr8(n, 1024, IFLA_BOND_PRIMARY_RESELECT, + primary_reselect); + } else if (matches(*argv, "fail_over_mac") == 0) { + NEXT_ARG(); + if (get_index(fail_over_mac_tbl, *argv) < 0) { + invarg("invalid fail_over_mac", *argv); + return -1; + } + fail_over_mac = get_index(fail_over_mac_tbl, *argv); + addattr8(n, 1024, IFLA_BOND_FAIL_OVER_MAC, + fail_over_mac); + } else if (matches(*argv, "xmit_hash_policy") == 0) { + NEXT_ARG(); + if (get_index(xmit_hash_policy_tbl, *argv) < 0) { + invarg("invalid xmit_hash_policy", *argv); + return -1; + } + xmit_hash_policy = get_index(xmit_hash_policy_tbl, *argv); + addattr8(n, 1024, IFLA_BOND_XMIT_HASH_POLICY, + xmit_hash_policy); + } else if (matches(*argv, "resend_igmp") == 0) { + NEXT_ARG(); + if (get_u32(&resend_igmp, *argv, 0)) { + invarg("invalid resend_igmp", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_RESEND_IGMP, resend_igmp); + } else if (matches(*argv, "num_grat_arp") == 0 || + matches(*argv, "num_unsol_na") == 0) { + NEXT_ARG(); + if (get_u8(&num_peer_notif, *argv, 0)) { + invarg("invalid num_grat_arp|num_unsol_na", + *argv); + return -1; + } + addattr8(n, 1024, IFLA_BOND_NUM_PEER_NOTIF, + num_peer_notif); + } else if (matches(*argv, "all_slaves_active") == 0) { + NEXT_ARG(); + if (get_u8(&all_slaves_active, *argv, 0)) { + invarg("invalid all_slaves_active", *argv); + return -1; + } + addattr8(n, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE, + all_slaves_active); + } else if (matches(*argv, "min_links") == 0) { + NEXT_ARG(); + if (get_u32(&min_links, *argv, 0)) { + invarg("invalid min_links", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_MIN_LINKS, min_links); + } else if (matches(*argv, "lp_interval") == 0) { + NEXT_ARG(); + if (get_u32(&lp_interval, *argv, 0)) { + invarg("invalid lp_interval", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_LP_INTERVAL, lp_interval); + } else if (matches(*argv, "packets_per_slave") == 0) { + NEXT_ARG(); + if (get_u32(&packets_per_slave, *argv, 0)) { + invarg("invalid packets_per_slave", *argv); + return -1; + } + addattr32(n, 1024, IFLA_BOND_PACKETS_PER_SLAVE, + packets_per_slave); + } else if (matches(*argv, "lacp_rate") == 0) { + NEXT_ARG(); + if (get_index(lacp_rate_tbl, *argv) < 0) { + invarg("invalid lacp_rate", *argv); + return -1; + } + lacp_rate = get_index(lacp_rate_tbl, *argv); + addattr8(n, 1024, IFLA_BOND_AD_LACP_RATE, lacp_rate); + } else if (matches(*argv, "ad_select") == 0) { + NEXT_ARG(); + if (get_index(ad_select_tbl, *argv) < 0) { + invarg("invalid ad_select", *argv); + return -1; + } + ad_select = get_index(ad_select_tbl, *argv); + addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select); } else { fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv); explain(); @@ -69,8 +357,11 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (!tb) return; - if (tb[IFLA_BOND_MODE]) - fprintf(f, "mode %u ", rta_getattr_u8(tb[IFLA_BOND_MODE])); + if (tb[IFLA_BOND_MODE]) { + const char *mode = get_name(mode_tbl, + rta_getattr_u8(tb[IFLA_BOND_MODE])); + fprintf(f, "mode %s ", mode); + } if (tb[IFLA_BOND_ACTIVE_SLAVE] && (ifindex = rta_getattr_u32(tb[IFLA_BOND_ACTIVE_SLAVE]))) { @@ -82,6 +373,159 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) else fprintf(f, "active_slave %u ", ifindex); } + + if (tb[IFLA_BOND_MIIMON]) + fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON])); + + if (tb[IFLA_BOND_UPDELAY]) + fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY])); + + if (tb[IFLA_BOND_DOWNDELAY]) + fprintf(f, "downdelay %u ", + rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY])); + + if (tb[IFLA_BOND_USE_CARRIER]) + fprintf(f, "use_carrier %u ", + rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER])); + + if (tb[IFLA_BOND_ARP_INTERVAL]) + fprintf(f, "arp_interval %u ", + rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL])); + + if (tb[IFLA_BOND_ARP_IP_TARGET]) { + struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1]; + char buf[INET_ADDRSTRLEN]; + int i; + + parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS, + tb[IFLA_BOND_ARP_IP_TARGET]); + + if (iptb[0]) + fprintf(f, "arp_ip_target "); + + for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { + if (iptb[i]) + fprintf(f, "%s", + rt_addr_n2a(AF_INET, + RTA_PAYLOAD(iptb[i]), + RTA_DATA(iptb[i]), + buf, + INET_ADDRSTRLEN)); + if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1]) + fprintf(f, ","); + } + + if (iptb[0]) + fprintf(f, " "); + } + + if (tb[IFLA_BOND_ARP_VALIDATE]) { + const char *arp_validate = get_name(arp_validate_tbl, + rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE])); + fprintf(f, "arp_validate %s ", arp_validate); + } + + if (tb[IFLA_BOND_ARP_ALL_TARGETS]) { + const char *arp_all_targets = get_name(arp_all_targets_tbl, + rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS])); + fprintf(f, "arp_all_target %s ", arp_all_targets); + } + + if (tb[IFLA_BOND_PRIMARY] && + (ifindex = rta_getattr_u32(tb[IFLA_BOND_PRIMARY]))) { + char buf[IFNAMSIZ]; + const char *n = if_indextoname(ifindex, buf); + + if (n) + fprintf(f, "primary %s ", n); + else + fprintf(f, "primary %u ", ifindex); + } + + if (tb[IFLA_BOND_PRIMARY_RESELECT]) { + const char *primary_reselect = get_name(primary_reselect_tbl, + rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT])); + fprintf(f, "primary_reselect %s ", primary_reselect); + } + + if (tb[IFLA_BOND_FAIL_OVER_MAC]) { + const char *fail_over_mac = get_name(fail_over_mac_tbl, + rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC])); + fprintf(f, "fail_over_mac %s ", fail_over_mac); + } + + if (tb[IFLA_BOND_XMIT_HASH_POLICY]) { + const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl, + rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY])); + fprintf(f, "xmit_hash_policy %s ", xmit_hash_policy); + } + + if (tb[IFLA_BOND_RESEND_IGMP]) + fprintf(f, "resend_igmp %u ", + rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP])); + + if (tb[IFLA_BOND_NUM_PEER_NOTIF]) + fprintf(f, "num_grat_arp %u ", + rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF])); + + if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE]) + fprintf(f, "all_slaves_active %u ", + rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE])); + + if (tb[IFLA_BOND_MIN_LINKS]) + fprintf(f, "min_links %u ", + rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS])); + + if (tb[IFLA_BOND_LP_INTERVAL]) + fprintf(f, "lp_interval %u ", + rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL])); + + if (tb[IFLA_BOND_PACKETS_PER_SLAVE]) + fprintf(f, "packets_per_slave %u ", + rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE])); + + if (tb[IFLA_BOND_AD_LACP_RATE]) { + const char *lacp_rate = get_name(lacp_rate_tbl, + rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE])); + fprintf(f, "lacp_rate %s ", lacp_rate); + } + + if (tb[IFLA_BOND_AD_SELECT]) { + const char *ad_select = get_name(ad_select_tbl, + rta_getattr_u8(tb[IFLA_BOND_AD_SELECT])); + fprintf(f, "ad_select %s ", ad_select); + } + + if (tb[IFLA_BOND_AD_INFO]) { + struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1]; + + parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX, + tb[IFLA_BOND_AD_INFO]); + + if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR]) + fprintf(f, "ad_aggregator %d ", + rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR])); + + if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS]) + fprintf(f, "ad_num_ports %d ", + rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS])); + + if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]) + fprintf(f, "ad_actor_key %d ", + rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])); + + if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]) + fprintf(f, "ad_partner_key %d ", + rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])); + + if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) { + unsigned char *p = + RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]); + SPRINT_BUF(b); + fprintf(f, "ad_partner_mac %s ", + ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b))); + } + } } struct link_util bond_link_util = {