Home | History | Annotate | Download | only in ip
      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 (at) resnulli.us>
     10  *              Scott Feldman <sfeldma (at) cumulusnetworks.com>
     11  */
     12 
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <linux/if_link.h>
     17 #include <linux/if_ether.h>
     18 #include <net/if.h>
     19 
     20 #include "rt_names.h"
     21 #include "utils.h"
     22 #include "ip_common.h"
     23 
     24 #define BOND_MAX_ARP_TARGETS    16
     25 
     26 static const char *mode_tbl[] = {
     27 	"balance-rr",
     28 	"active-backup",
     29 	"balance-xor",
     30 	"broadcast",
     31 	"802.3ad",
     32 	"balance-tlb",
     33 	"balance-alb",
     34 	NULL,
     35 };
     36 
     37 static const char *arp_validate_tbl[] = {
     38 	"none",
     39 	"active",
     40 	"backup",
     41 	"all",
     42 	NULL,
     43 };
     44 
     45 static const char *arp_all_targets_tbl[] = {
     46 	"any",
     47 	"all",
     48 	NULL,
     49 };
     50 
     51 static const char *primary_reselect_tbl[] = {
     52 	"always",
     53 	"better",
     54 	"failure",
     55 	NULL,
     56 };
     57 
     58 static const char *fail_over_mac_tbl[] = {
     59 	"none",
     60 	"active",
     61 	"follow",
     62 	NULL,
     63 };
     64 
     65 static const char *xmit_hash_policy_tbl[] = {
     66 	"layer2",
     67 	"layer3+4",
     68 	"layer2+3",
     69 	"encap2+3",
     70 	"encap3+4",
     71 	NULL,
     72 };
     73 
     74 static const char *lacp_rate_tbl[] = {
     75 	"slow",
     76 	"fast",
     77 	NULL,
     78 };
     79 
     80 static const char *ad_select_tbl[] = {
     81 	"stable",
     82 	"bandwidth",
     83 	"count",
     84 	NULL,
     85 };
     86 
     87 static const char *get_name(const char **tbl, int index)
     88 {
     89 	int i;
     90 
     91 	for (i = 0; tbl[i]; i++)
     92 		if (i == index)
     93 			return tbl[i];
     94 
     95 	return "UNKNOWN";
     96 }
     97 
     98 static int get_index(const char **tbl, char *name)
     99 {
    100 	int i, index;
    101 
    102 	/* check for integer index passed in instead of name */
    103 	if (get_integer(&index, name, 10) == 0)
    104 		for (i = 0; tbl[i]; i++)
    105 			if (i == index)
    106 				return i;
    107 
    108 	for (i = 0; tbl[i]; i++)
    109 		if (strcmp(tbl[i], name) == 0)
    110 			return i;
    111 
    112 	return -1;
    113 }
    114 
    115 static void print_explain(FILE *f)
    116 {
    117 	fprintf(f,
    118 		"Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n"
    119 		"                [ clear_active_slave ] [ miimon MIIMON ]\n"
    120 		"                [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n"
    121 		"                [ use_carrier USE_CARRIER ]\n"
    122 		"                [ arp_interval ARP_INTERVAL ]\n"
    123 		"                [ arp_validate ARP_VALIDATE ]\n"
    124 		"                [ arp_all_targets ARP_ALL_TARGETS ]\n"
    125 		"                [ arp_ip_target [ ARP_IP_TARGET, ... ] ]\n"
    126 		"                [ primary SLAVE_DEV ]\n"
    127 		"                [ primary_reselect PRIMARY_RESELECT ]\n"
    128 		"                [ fail_over_mac FAIL_OVER_MAC ]\n"
    129 		"                [ xmit_hash_policy XMIT_HASH_POLICY ]\n"
    130 		"                [ resend_igmp RESEND_IGMP ]\n"
    131 		"                [ num_grat_arp|num_unsol_na NUM_GRAT_ARP|NUM_UNSOL_NA ]\n"
    132 		"                [ all_slaves_active ALL_SLAVES_ACTIVE ]\n"
    133 		"                [ min_links MIN_LINKS ]\n"
    134 		"                [ lp_interval LP_INTERVAL ]\n"
    135 		"                [ packets_per_slave PACKETS_PER_SLAVE ]\n"
    136 		"		 [ tlb_dynamic_lb TLB_DYNAMIC_LB ]\n"
    137 		"                [ lacp_rate LACP_RATE ]\n"
    138 		"                [ ad_select AD_SELECT ]\n"
    139 		"                [ ad_user_port_key PORTKEY ]\n"
    140 		"                [ ad_actor_sys_prio SYSPRIO ]\n"
    141 		"                [ ad_actor_system LLADDR ]\n"
    142 		"\n"
    143 		"BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n"
    144 		"ARP_VALIDATE := none|active|backup|all\n"
    145 		"ARP_ALL_TARGETS := any|all\n"
    146 		"PRIMARY_RESELECT := always|better|failure\n"
    147 		"FAIL_OVER_MAC := none|active|follow\n"
    148 		"XMIT_HASH_POLICY := layer2|layer2+3|layer3+4|encap2+3|encap3+4\n"
    149 		"LACP_RATE := slow|fast\n"
    150 		"AD_SELECT := stable|bandwidth|count\n"
    151 	);
    152 }
    153 
    154 static void explain(void)
    155 {
    156 	print_explain(stderr);
    157 }
    158 
    159 static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
    160 			  struct nlmsghdr *n)
    161 {
    162 	__u8 mode, use_carrier, primary_reselect, fail_over_mac;
    163 	__u8 xmit_hash_policy, num_peer_notif, all_slaves_active;
    164 	__u8 lacp_rate, ad_select, tlb_dynamic_lb;
    165 	__u16 ad_user_port_key, ad_actor_sys_prio;
    166 	__u32 miimon, updelay, downdelay, arp_interval, arp_validate;
    167 	__u32 arp_all_targets, resend_igmp, min_links, lp_interval;
    168 	__u32 packets_per_slave;
    169 	unsigned ifindex;
    170 
    171 	while (argc > 0) {
    172 		if (matches(*argv, "mode") == 0) {
    173 			NEXT_ARG();
    174 			if (get_index(mode_tbl, *argv) < 0)
    175 				invarg("invalid mode", *argv);
    176 			mode = get_index(mode_tbl, *argv);
    177 			addattr8(n, 1024, IFLA_BOND_MODE, mode);
    178 		} else if (matches(*argv, "active_slave") == 0) {
    179 			NEXT_ARG();
    180 			ifindex = if_nametoindex(*argv);
    181 			if (!ifindex)
    182 				return -1;
    183 			addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex);
    184 		} else if (matches(*argv, "clear_active_slave") == 0) {
    185 			addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0);
    186 		} else if (matches(*argv, "miimon") == 0) {
    187 			NEXT_ARG();
    188 			if (get_u32(&miimon, *argv, 0))
    189 				invarg("invalid miimon", *argv);
    190 			addattr32(n, 1024, IFLA_BOND_MIIMON, miimon);
    191 		} else if (matches(*argv, "updelay") == 0) {
    192 			NEXT_ARG();
    193 			if (get_u32(&updelay, *argv, 0))
    194 				invarg("invalid updelay", *argv);
    195 			addattr32(n, 1024, IFLA_BOND_UPDELAY, updelay);
    196 		} else if (matches(*argv, "downdelay") == 0) {
    197 			NEXT_ARG();
    198 			if (get_u32(&downdelay, *argv, 0))
    199 				invarg("invalid downdelay", *argv);
    200 			addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay);
    201 		} else if (matches(*argv, "use_carrier") == 0) {
    202 			NEXT_ARG();
    203 			if (get_u8(&use_carrier, *argv, 0))
    204 				invarg("invalid use_carrier", *argv);
    205 			addattr8(n, 1024, IFLA_BOND_USE_CARRIER, use_carrier);
    206 		} else if (matches(*argv, "arp_interval") == 0) {
    207 			NEXT_ARG();
    208 			if (get_u32(&arp_interval, *argv, 0))
    209 				invarg("invalid arp_interval", *argv);
    210 			addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval);
    211 		} else if (matches(*argv, "arp_ip_target") == 0) {
    212 			struct rtattr * nest = addattr_nest(n, 1024,
    213 				IFLA_BOND_ARP_IP_TARGET);
    214 			if (NEXT_ARG_OK()) {
    215 				NEXT_ARG();
    216 				char *targets = strdupa(*argv);
    217 				char *target = strtok(targets, ",");
    218 				int i;
    219 
    220 				for(i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) {
    221 					__u32 addr = get_addr32(target);
    222 					addattr32(n, 1024, i, addr);
    223 					target = strtok(NULL, ",");
    224 				}
    225 				addattr_nest_end(n, nest);
    226 			}
    227 			addattr_nest_end(n, nest);
    228 		} else if (matches(*argv, "arp_validate") == 0) {
    229 			NEXT_ARG();
    230 			if (get_index(arp_validate_tbl, *argv) < 0)
    231 				invarg("invalid arp_validate", *argv);
    232 			arp_validate = get_index(arp_validate_tbl, *argv);
    233 			addattr32(n, 1024, IFLA_BOND_ARP_VALIDATE, arp_validate);
    234 		} else if (matches(*argv, "arp_all_targets") == 0) {
    235 			NEXT_ARG();
    236 			if (get_index(arp_all_targets_tbl, *argv) < 0)
    237 				invarg("invalid arp_all_targets", *argv);
    238 			arp_all_targets = get_index(arp_all_targets_tbl, *argv);
    239 			addattr32(n, 1024, IFLA_BOND_ARP_ALL_TARGETS, arp_all_targets);
    240 		} else if (matches(*argv, "primary") == 0) {
    241 			NEXT_ARG();
    242 			ifindex = if_nametoindex(*argv);
    243 			if (!ifindex)
    244 				return -1;
    245 			addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex);
    246 		} else if (matches(*argv, "primary_reselect") == 0) {
    247 			NEXT_ARG();
    248 			if (get_index(primary_reselect_tbl, *argv) < 0)
    249 				invarg("invalid primary_reselect", *argv);
    250 			primary_reselect = get_index(primary_reselect_tbl, *argv);
    251 			addattr8(n, 1024, IFLA_BOND_PRIMARY_RESELECT,
    252 				 primary_reselect);
    253 		} else if (matches(*argv, "fail_over_mac") == 0) {
    254 			NEXT_ARG();
    255 			if (get_index(fail_over_mac_tbl, *argv) < 0)
    256 				invarg("invalid fail_over_mac", *argv);
    257 			fail_over_mac = get_index(fail_over_mac_tbl, *argv);
    258 			addattr8(n, 1024, IFLA_BOND_FAIL_OVER_MAC,
    259 				 fail_over_mac);
    260 		} else if (matches(*argv, "xmit_hash_policy") == 0) {
    261 			NEXT_ARG();
    262 			if (get_index(xmit_hash_policy_tbl, *argv) < 0)
    263 				invarg("invalid xmit_hash_policy", *argv);
    264 
    265 			xmit_hash_policy = get_index(xmit_hash_policy_tbl, *argv);
    266 			addattr8(n, 1024, IFLA_BOND_XMIT_HASH_POLICY,
    267 				 xmit_hash_policy);
    268 		} else if (matches(*argv, "resend_igmp") == 0) {
    269 			NEXT_ARG();
    270 			if (get_u32(&resend_igmp, *argv, 0))
    271 				invarg("invalid resend_igmp", *argv);
    272 
    273 			addattr32(n, 1024, IFLA_BOND_RESEND_IGMP, resend_igmp);
    274 		} else if (matches(*argv, "num_grat_arp") == 0 ||
    275 			   matches(*argv, "num_unsol_na") == 0) {
    276 			NEXT_ARG();
    277 			if (get_u8(&num_peer_notif, *argv, 0))
    278 				invarg("invalid num_grat_arp|num_unsol_na",
    279 				       *argv);
    280 
    281 			addattr8(n, 1024, IFLA_BOND_NUM_PEER_NOTIF,
    282 				 num_peer_notif);
    283 		} else if (matches(*argv, "all_slaves_active") == 0) {
    284 			NEXT_ARG();
    285 			if (get_u8(&all_slaves_active, *argv, 0))
    286 				invarg("invalid all_slaves_active", *argv);
    287 
    288 			addattr8(n, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE,
    289 				 all_slaves_active);
    290 		} else if (matches(*argv, "min_links") == 0) {
    291 			NEXT_ARG();
    292 			if (get_u32(&min_links, *argv, 0))
    293 				invarg("invalid min_links", *argv);
    294 
    295 			addattr32(n, 1024, IFLA_BOND_MIN_LINKS, min_links);
    296 		} else if (matches(*argv, "lp_interval") == 0) {
    297 			NEXT_ARG();
    298 			if (get_u32(&lp_interval, *argv, 0))
    299 				invarg("invalid lp_interval", *argv);
    300 
    301 			addattr32(n, 1024, IFLA_BOND_LP_INTERVAL, lp_interval);
    302 		} else if (matches(*argv, "packets_per_slave") == 0) {
    303 			NEXT_ARG();
    304 			if (get_u32(&packets_per_slave, *argv, 0))
    305 				invarg("invalid packets_per_slave", *argv);
    306 
    307 			addattr32(n, 1024, IFLA_BOND_PACKETS_PER_SLAVE,
    308 				  packets_per_slave);
    309 		} else if (matches(*argv, "lacp_rate") == 0) {
    310 			NEXT_ARG();
    311 			if (get_index(lacp_rate_tbl, *argv) < 0)
    312 				invarg("invalid lacp_rate", *argv);
    313 
    314 			lacp_rate = get_index(lacp_rate_tbl, *argv);
    315 			addattr8(n, 1024, IFLA_BOND_AD_LACP_RATE, lacp_rate);
    316 		} else if (matches(*argv, "ad_select") == 0) {
    317 			NEXT_ARG();
    318 			if (get_index(ad_select_tbl, *argv) < 0)
    319 				invarg("invalid ad_select", *argv);
    320 
    321 			ad_select = get_index(ad_select_tbl, *argv);
    322 			addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select);
    323 		} else if (matches(*argv, "ad_user_port_key") == 0) {
    324 			NEXT_ARG();
    325 			if (get_u16(&ad_user_port_key, *argv, 0))
    326 				invarg("invalid ad_user_port_key", *argv);
    327 
    328 			addattr16(n, 1024, IFLA_BOND_AD_USER_PORT_KEY,
    329 				  ad_user_port_key);
    330 		} else if (matches(*argv, "ad_actor_sys_prio") == 0) {
    331 			NEXT_ARG();
    332 			if (get_u16(&ad_actor_sys_prio, *argv, 0))
    333 				invarg("invalid ad_actor_sys_prio", *argv);
    334 
    335 			addattr16(n, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO,
    336 				  ad_actor_sys_prio);
    337 		} else if (matches(*argv, "ad_actor_system") == 0) {
    338 			int len;
    339 			char abuf[32];
    340 
    341 			NEXT_ARG();
    342 			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
    343 			if (len < 0)
    344 				return -1;
    345 			addattr_l(n, 1024, IFLA_BOND_AD_ACTOR_SYSTEM,
    346 				  abuf, len);
    347 		} else if (matches(*argv, "tlb_dynamic_lb") == 0) {
    348 			NEXT_ARG();
    349 			if (get_u8(&tlb_dynamic_lb, *argv, 0)) {
    350 				invarg("invalid tlb_dynamic_lb", *argv);
    351 				return -1;
    352 			}
    353 			addattr8(n, 1024, IFLA_BOND_TLB_DYNAMIC_LB,
    354 				 tlb_dynamic_lb);
    355 		} else if (matches(*argv, "help") == 0) {
    356 			explain();
    357 			return -1;
    358 		} else {
    359 			fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv);
    360 			explain();
    361 			return -1;
    362 		}
    363 		argc--, argv++;
    364 	}
    365 
    366 	return 0;
    367 }
    368 
    369 static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
    370 {
    371 	unsigned ifindex;
    372 
    373 	if (!tb)
    374 		return;
    375 
    376 	if (tb[IFLA_BOND_MODE]) {
    377 		const char *mode = get_name(mode_tbl,
    378 			rta_getattr_u8(tb[IFLA_BOND_MODE]));
    379 		fprintf(f, "mode %s ", mode);
    380 	}
    381 
    382 	if (tb[IFLA_BOND_ACTIVE_SLAVE] &&
    383 	    (ifindex = rta_getattr_u32(tb[IFLA_BOND_ACTIVE_SLAVE]))) {
    384 		char buf[IFNAMSIZ];
    385 		const char *n = if_indextoname(ifindex, buf);
    386 
    387 		if (n)
    388 			fprintf(f, "active_slave %s ", n);
    389 		else
    390 			fprintf(f, "active_slave %u ", ifindex);
    391 	}
    392 
    393 	if (tb[IFLA_BOND_MIIMON])
    394 		fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
    395 
    396 	if (tb[IFLA_BOND_UPDELAY])
    397 		fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
    398 
    399 	if (tb[IFLA_BOND_DOWNDELAY])
    400 		fprintf(f, "downdelay %u ",
    401 			rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
    402 
    403 	if (tb[IFLA_BOND_USE_CARRIER])
    404 		fprintf(f, "use_carrier %u ",
    405 			rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
    406 
    407 	if (tb[IFLA_BOND_ARP_INTERVAL])
    408 		fprintf(f, "arp_interval %u ",
    409 			rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
    410 
    411 	if (tb[IFLA_BOND_ARP_IP_TARGET]) {
    412 		struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1];
    413 		char buf[INET_ADDRSTRLEN];
    414 		int i;
    415 
    416 		parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
    417 			tb[IFLA_BOND_ARP_IP_TARGET]);
    418 
    419 		if (iptb[0])
    420 			fprintf(f, "arp_ip_target ");
    421 
    422 		for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
    423 			if (iptb[i])
    424 				fprintf(f, "%s",
    425 					rt_addr_n2a(AF_INET,
    426 						    RTA_PAYLOAD(iptb[i]),
    427 						    RTA_DATA(iptb[i]),
    428 						    buf,
    429 						    INET_ADDRSTRLEN));
    430 			if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1])
    431 				fprintf(f, ",");
    432 		}
    433 
    434 		if (iptb[0])
    435 			fprintf(f, " ");
    436 	}
    437 
    438 	if (tb[IFLA_BOND_ARP_VALIDATE]) {
    439 		const char *arp_validate = get_name(arp_validate_tbl,
    440 			rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]));
    441 		fprintf(f, "arp_validate %s ", arp_validate);
    442 	}
    443 
    444 	if (tb[IFLA_BOND_ARP_ALL_TARGETS]) {
    445 		const char *arp_all_targets = get_name(arp_all_targets_tbl,
    446 			rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
    447 		fprintf(f, "arp_all_targets %s ", arp_all_targets);
    448 	}
    449 
    450 	if (tb[IFLA_BOND_PRIMARY] &&
    451 	    (ifindex = rta_getattr_u32(tb[IFLA_BOND_PRIMARY]))) {
    452 		char buf[IFNAMSIZ];
    453 		const char *n = if_indextoname(ifindex, buf);
    454 
    455 		if (n)
    456 			fprintf(f, "primary %s ", n);
    457 		else
    458 			fprintf(f, "primary %u ", ifindex);
    459 	}
    460 
    461 	if (tb[IFLA_BOND_PRIMARY_RESELECT]) {
    462 		const char *primary_reselect = get_name(primary_reselect_tbl,
    463 			rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
    464 		fprintf(f, "primary_reselect %s ", primary_reselect);
    465 	}
    466 
    467 	if (tb[IFLA_BOND_FAIL_OVER_MAC]) {
    468 		const char *fail_over_mac = get_name(fail_over_mac_tbl,
    469 			rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
    470 		fprintf(f, "fail_over_mac %s ", fail_over_mac);
    471 	}
    472 
    473 	if (tb[IFLA_BOND_XMIT_HASH_POLICY]) {
    474 		const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl,
    475 			rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
    476 		fprintf(f, "xmit_hash_policy %s ", xmit_hash_policy);
    477 	}
    478 
    479 	if (tb[IFLA_BOND_RESEND_IGMP])
    480 		fprintf(f, "resend_igmp %u ",
    481 			rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
    482 
    483 	if (tb[IFLA_BOND_NUM_PEER_NOTIF])
    484 		fprintf(f, "num_grat_arp %u ",
    485 			rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
    486 
    487 	if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
    488 		fprintf(f, "all_slaves_active %u ",
    489 			rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
    490 
    491 	if (tb[IFLA_BOND_MIN_LINKS])
    492 		fprintf(f, "min_links %u ",
    493 			rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
    494 
    495 	if (tb[IFLA_BOND_LP_INTERVAL])
    496 		fprintf(f, "lp_interval %u ",
    497 			rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
    498 
    499 	if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
    500 		fprintf(f, "packets_per_slave %u ",
    501 			rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
    502 
    503 	if (tb[IFLA_BOND_AD_LACP_RATE]) {
    504 		const char *lacp_rate = get_name(lacp_rate_tbl,
    505 			rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
    506 		fprintf(f, "lacp_rate %s ", lacp_rate);
    507 	}
    508 
    509 	if (tb[IFLA_BOND_AD_SELECT]) {
    510 		const char *ad_select = get_name(ad_select_tbl,
    511 			rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
    512 		fprintf(f, "ad_select %s ", ad_select);
    513 	}
    514 
    515 	if (tb[IFLA_BOND_AD_INFO]) {
    516 		struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1];
    517 
    518 		parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX,
    519 			tb[IFLA_BOND_AD_INFO]);
    520 
    521 		if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR])
    522 			fprintf(f, "ad_aggregator %d ",
    523 			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
    524 
    525 		if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS])
    526 			fprintf(f, "ad_num_ports %d ",
    527 			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
    528 
    529 		if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])
    530 			fprintf(f, "ad_actor_key %d ",
    531 			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
    532 
    533 		if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])
    534 			fprintf(f, "ad_partner_key %d ",
    535 			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
    536 
    537 		if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) {
    538 			unsigned char *p =
    539 				RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]);
    540 			SPRINT_BUF(b);
    541 			fprintf(f, "ad_partner_mac %s ",
    542 				ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
    543 		}
    544 	}
    545 
    546 	if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
    547 		fprintf(f, "ad_actor_sys_prio %u ",
    548 			rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
    549 	}
    550 
    551 	if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
    552 		fprintf(f, "ad_user_port_key %u ",
    553 			rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
    554 	}
    555 
    556 	if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
    557 		/* We assume the l2 address is an Ethernet MAC address */
    558 		SPRINT_BUF(b1);
    559 		fprintf(f, "ad_actor_system %s ",
    560 			ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
    561 				    RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
    562 				    1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
    563 	}
    564 
    565 	if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) {
    566 		fprintf(f, "tlb_dynamic_lb %u ",
    567 			rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
    568 	}
    569 }
    570 
    571 static void bond_print_help(struct link_util *lu, int argc, char **argv,
    572 	FILE *f)
    573 {
    574 	print_explain(f);
    575 }
    576 
    577 struct link_util bond_link_util = {
    578 	.id		= "bond",
    579 	.maxattr	= IFLA_BOND_MAX,
    580 	.parse_opt	= bond_parse_opt,
    581 	.print_opt	= bond_print_opt,
    582 	.print_help	= bond_print_help,
    583 };
    584