2 * iplink_bond.c Bonding device support
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.
9 * Authors: Jiri Pirko <jiri@resnulli.us>
10 * Scott Feldman <sfeldma@cumulusnetworks.com>
16 #include <linux/if_link.h>
17 #include <linux/if_ether.h>
22 #include "ip_common.h"
24 #define BOND_MAX_ARP_TARGETS 16
26 static const char *mode_tbl
[] = {
37 static const char *arp_validate_tbl
[] = {
45 static const char *arp_all_targets_tbl
[] = {
51 static const char *primary_reselect_tbl
[] = {
58 static const char *fail_over_mac_tbl
[] = {
65 static const char *xmit_hash_policy_tbl
[] = {
74 static const char *lacp_rate_tbl
[] = {
80 static const char *ad_select_tbl
[] = {
87 static const char *get_name(const char **tbl
, int index
)
91 for (i
= 0; tbl
[i
]; i
++)
98 static int get_index(const char **tbl
, char *name
)
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
++)
108 for (i
= 0; tbl
[i
]; i
++)
109 if (strcmp(tbl
[i
], name
) == 0)
115 static void print_explain(FILE *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"
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"
154 static void explain(void)
156 print_explain(stderr
);
159 static int bond_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
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 int ifindex
;
172 if (matches(*argv
, "mode") == 0) {
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) {
180 ifindex
= ll_name_to_index(*argv
);
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) {
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) {
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) {
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) {
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) {
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
);
216 char *targets
= strdupa(*argv
);
217 char *target
= strtok(targets
, ",");
220 for (i
= 0; target
&& i
< BOND_MAX_ARP_TARGETS
; i
++) {
221 __u32 addr
= get_addr32(target
);
223 addattr32(n
, 1024, i
, addr
);
224 target
= strtok(NULL
, ",");
226 addattr_nest_end(n
, nest
);
228 addattr_nest_end(n
, nest
);
229 } else if (matches(*argv
, "arp_validate") == 0) {
231 if (get_index(arp_validate_tbl
, *argv
) < 0)
232 invarg("invalid arp_validate", *argv
);
233 arp_validate
= get_index(arp_validate_tbl
, *argv
);
234 addattr32(n
, 1024, IFLA_BOND_ARP_VALIDATE
, arp_validate
);
235 } else if (matches(*argv
, "arp_all_targets") == 0) {
237 if (get_index(arp_all_targets_tbl
, *argv
) < 0)
238 invarg("invalid arp_all_targets", *argv
);
239 arp_all_targets
= get_index(arp_all_targets_tbl
, *argv
);
240 addattr32(n
, 1024, IFLA_BOND_ARP_ALL_TARGETS
, arp_all_targets
);
241 } else if (matches(*argv
, "primary") == 0) {
243 ifindex
= ll_name_to_index(*argv
);
246 addattr32(n
, 1024, IFLA_BOND_PRIMARY
, ifindex
);
247 } else if (matches(*argv
, "primary_reselect") == 0) {
249 if (get_index(primary_reselect_tbl
, *argv
) < 0)
250 invarg("invalid primary_reselect", *argv
);
251 primary_reselect
= get_index(primary_reselect_tbl
, *argv
);
252 addattr8(n
, 1024, IFLA_BOND_PRIMARY_RESELECT
,
254 } else if (matches(*argv
, "fail_over_mac") == 0) {
256 if (get_index(fail_over_mac_tbl
, *argv
) < 0)
257 invarg("invalid fail_over_mac", *argv
);
258 fail_over_mac
= get_index(fail_over_mac_tbl
, *argv
);
259 addattr8(n
, 1024, IFLA_BOND_FAIL_OVER_MAC
,
261 } else if (matches(*argv
, "xmit_hash_policy") == 0) {
263 if (get_index(xmit_hash_policy_tbl
, *argv
) < 0)
264 invarg("invalid xmit_hash_policy", *argv
);
266 xmit_hash_policy
= get_index(xmit_hash_policy_tbl
, *argv
);
267 addattr8(n
, 1024, IFLA_BOND_XMIT_HASH_POLICY
,
269 } else if (matches(*argv
, "resend_igmp") == 0) {
271 if (get_u32(&resend_igmp
, *argv
, 0))
272 invarg("invalid resend_igmp", *argv
);
274 addattr32(n
, 1024, IFLA_BOND_RESEND_IGMP
, resend_igmp
);
275 } else if (matches(*argv
, "num_grat_arp") == 0 ||
276 matches(*argv
, "num_unsol_na") == 0) {
278 if (get_u8(&num_peer_notif
, *argv
, 0))
279 invarg("invalid num_grat_arp|num_unsol_na",
282 addattr8(n
, 1024, IFLA_BOND_NUM_PEER_NOTIF
,
284 } else if (matches(*argv
, "all_slaves_active") == 0) {
286 if (get_u8(&all_slaves_active
, *argv
, 0))
287 invarg("invalid all_slaves_active", *argv
);
289 addattr8(n
, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE
,
291 } else if (matches(*argv
, "min_links") == 0) {
293 if (get_u32(&min_links
, *argv
, 0))
294 invarg("invalid min_links", *argv
);
296 addattr32(n
, 1024, IFLA_BOND_MIN_LINKS
, min_links
);
297 } else if (matches(*argv
, "lp_interval") == 0) {
299 if (get_u32(&lp_interval
, *argv
, 0))
300 invarg("invalid lp_interval", *argv
);
302 addattr32(n
, 1024, IFLA_BOND_LP_INTERVAL
, lp_interval
);
303 } else if (matches(*argv
, "packets_per_slave") == 0) {
305 if (get_u32(&packets_per_slave
, *argv
, 0))
306 invarg("invalid packets_per_slave", *argv
);
308 addattr32(n
, 1024, IFLA_BOND_PACKETS_PER_SLAVE
,
310 } else if (matches(*argv
, "lacp_rate") == 0) {
312 if (get_index(lacp_rate_tbl
, *argv
) < 0)
313 invarg("invalid lacp_rate", *argv
);
315 lacp_rate
= get_index(lacp_rate_tbl
, *argv
);
316 addattr8(n
, 1024, IFLA_BOND_AD_LACP_RATE
, lacp_rate
);
317 } else if (matches(*argv
, "ad_select") == 0) {
319 if (get_index(ad_select_tbl
, *argv
) < 0)
320 invarg("invalid ad_select", *argv
);
322 ad_select
= get_index(ad_select_tbl
, *argv
);
323 addattr8(n
, 1024, IFLA_BOND_AD_SELECT
, ad_select
);
324 } else if (matches(*argv
, "ad_user_port_key") == 0) {
326 if (get_u16(&ad_user_port_key
, *argv
, 0))
327 invarg("invalid ad_user_port_key", *argv
);
329 addattr16(n
, 1024, IFLA_BOND_AD_USER_PORT_KEY
,
331 } else if (matches(*argv
, "ad_actor_sys_prio") == 0) {
333 if (get_u16(&ad_actor_sys_prio
, *argv
, 0))
334 invarg("invalid ad_actor_sys_prio", *argv
);
336 addattr16(n
, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO
,
338 } else if (matches(*argv
, "ad_actor_system") == 0) {
343 len
= ll_addr_a2n(abuf
, sizeof(abuf
), *argv
);
346 addattr_l(n
, 1024, IFLA_BOND_AD_ACTOR_SYSTEM
,
348 } else if (matches(*argv
, "tlb_dynamic_lb") == 0) {
350 if (get_u8(&tlb_dynamic_lb
, *argv
, 0)) {
351 invarg("invalid tlb_dynamic_lb", *argv
);
354 addattr8(n
, 1024, IFLA_BOND_TLB_DYNAMIC_LB
,
356 } else if (matches(*argv
, "help") == 0) {
360 fprintf(stderr
, "bond: unknown command \"%s\"?\n", *argv
);
370 static void bond_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
375 if (tb
[IFLA_BOND_MODE
]) {
376 const char *mode
= get_name(mode_tbl
,
377 rta_getattr_u8(tb
[IFLA_BOND_MODE
]));
378 print_string(PRINT_ANY
, "mode", "mode %s ", mode
);
381 if (tb
[IFLA_BOND_ACTIVE_SLAVE
]) {
382 unsigned int ifindex
=
383 rta_getattr_u32(tb
[IFLA_BOND_ACTIVE_SLAVE
]);
386 print_string(PRINT_ANY
,
389 ll_index_to_name(ifindex
));
393 if (tb
[IFLA_BOND_MIIMON
])
394 print_uint(PRINT_ANY
,
397 rta_getattr_u32(tb
[IFLA_BOND_MIIMON
]));
399 if (tb
[IFLA_BOND_UPDELAY
])
400 print_uint(PRINT_ANY
,
403 rta_getattr_u32(tb
[IFLA_BOND_UPDELAY
]));
405 if (tb
[IFLA_BOND_DOWNDELAY
])
406 print_uint(PRINT_ANY
,
409 rta_getattr_u32(tb
[IFLA_BOND_DOWNDELAY
]));
411 if (tb
[IFLA_BOND_USE_CARRIER
])
412 print_uint(PRINT_ANY
,
415 rta_getattr_u8(tb
[IFLA_BOND_USE_CARRIER
]));
417 if (tb
[IFLA_BOND_ARP_INTERVAL
])
418 print_uint(PRINT_ANY
,
421 rta_getattr_u32(tb
[IFLA_BOND_ARP_INTERVAL
]));
423 if (tb
[IFLA_BOND_ARP_IP_TARGET
]) {
424 struct rtattr
*iptb
[BOND_MAX_ARP_TARGETS
+ 1];
427 parse_rtattr_nested(iptb
, BOND_MAX_ARP_TARGETS
,
428 tb
[IFLA_BOND_ARP_IP_TARGET
]);
431 open_json_array(PRINT_JSON
, "arp_ip_target");
432 print_string(PRINT_FP
, NULL
, "arp_ip_target ", NULL
);
435 for (i
= 0; i
< BOND_MAX_ARP_TARGETS
; i
++) {
437 print_string(PRINT_ANY
,
440 rt_addr_n2a_rta(AF_INET
, iptb
[i
]));
441 if (!is_json_context()
442 && i
< BOND_MAX_ARP_TARGETS
-1
448 print_string(PRINT_FP
, NULL
, " ", NULL
);
449 close_json_array(PRINT_JSON
, NULL
);
453 if (tb
[IFLA_BOND_ARP_VALIDATE
]) {
454 __u32 arp_v
= rta_getattr_u32(tb
[IFLA_BOND_ARP_VALIDATE
]);
455 const char *arp_validate
= get_name(arp_validate_tbl
, arp_v
);
457 if (!arp_v
&& is_json_context())
458 print_null(PRINT_JSON
, "arp_validate", NULL
, NULL
);
460 print_string(PRINT_ANY
,
466 if (tb
[IFLA_BOND_ARP_ALL_TARGETS
]) {
467 const char *arp_all_targets
= get_name(arp_all_targets_tbl
,
468 rta_getattr_u32(tb
[IFLA_BOND_ARP_ALL_TARGETS
]));
469 print_string(PRINT_ANY
,
471 "arp_all_targets %s ",
475 if (tb
[IFLA_BOND_PRIMARY
]) {
476 unsigned int ifindex
= rta_getattr_u32(tb
[IFLA_BOND_PRIMARY
]);
479 print_string(PRINT_ANY
,
482 ll_index_to_name(ifindex
));
486 if (tb
[IFLA_BOND_PRIMARY_RESELECT
]) {
487 const char *primary_reselect
= get_name(primary_reselect_tbl
,
488 rta_getattr_u8(tb
[IFLA_BOND_PRIMARY_RESELECT
]));
489 print_string(PRINT_ANY
,
491 "primary_reselect %s ",
495 if (tb
[IFLA_BOND_FAIL_OVER_MAC
]) {
496 const char *fail_over_mac
= get_name(fail_over_mac_tbl
,
497 rta_getattr_u8(tb
[IFLA_BOND_FAIL_OVER_MAC
]));
498 print_string(PRINT_ANY
,
504 if (tb
[IFLA_BOND_XMIT_HASH_POLICY
]) {
505 const char *xmit_hash_policy
= get_name(xmit_hash_policy_tbl
,
506 rta_getattr_u8(tb
[IFLA_BOND_XMIT_HASH_POLICY
]));
507 print_string(PRINT_ANY
,
509 "xmit_hash_policy %s ",
513 if (tb
[IFLA_BOND_RESEND_IGMP
])
514 print_uint(PRINT_ANY
,
517 rta_getattr_u32(tb
[IFLA_BOND_RESEND_IGMP
]));
519 if (tb
[IFLA_BOND_NUM_PEER_NOTIF
])
520 print_uint(PRINT_ANY
,
523 rta_getattr_u8(tb
[IFLA_BOND_NUM_PEER_NOTIF
]));
525 if (tb
[IFLA_BOND_ALL_SLAVES_ACTIVE
])
526 print_uint(PRINT_ANY
,
528 "all_slaves_active %u ",
529 rta_getattr_u8(tb
[IFLA_BOND_ALL_SLAVES_ACTIVE
]));
531 if (tb
[IFLA_BOND_MIN_LINKS
])
532 print_uint(PRINT_ANY
,
535 rta_getattr_u32(tb
[IFLA_BOND_MIN_LINKS
]));
537 if (tb
[IFLA_BOND_LP_INTERVAL
])
538 print_uint(PRINT_ANY
,
541 rta_getattr_u32(tb
[IFLA_BOND_LP_INTERVAL
]));
543 if (tb
[IFLA_BOND_PACKETS_PER_SLAVE
])
544 print_uint(PRINT_ANY
,
546 "packets_per_slave %u ",
547 rta_getattr_u32(tb
[IFLA_BOND_PACKETS_PER_SLAVE
]));
549 if (tb
[IFLA_BOND_AD_LACP_RATE
]) {
550 const char *lacp_rate
= get_name(lacp_rate_tbl
,
551 rta_getattr_u8(tb
[IFLA_BOND_AD_LACP_RATE
]));
552 print_string(PRINT_ANY
,
558 if (tb
[IFLA_BOND_AD_SELECT
]) {
559 const char *ad_select
= get_name(ad_select_tbl
,
560 rta_getattr_u8(tb
[IFLA_BOND_AD_SELECT
]));
561 print_string(PRINT_ANY
,
567 if (tb
[IFLA_BOND_AD_INFO
]) {
568 struct rtattr
*adtb
[IFLA_BOND_AD_INFO_MAX
+ 1];
570 parse_rtattr_nested(adtb
, IFLA_BOND_AD_INFO_MAX
,
571 tb
[IFLA_BOND_AD_INFO
]);
573 open_json_object("ad_info");
575 if (adtb
[IFLA_BOND_AD_INFO_AGGREGATOR
])
579 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_AGGREGATOR
]));
581 if (adtb
[IFLA_BOND_AD_INFO_NUM_PORTS
])
585 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_NUM_PORTS
]));
587 if (adtb
[IFLA_BOND_AD_INFO_ACTOR_KEY
])
591 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_ACTOR_KEY
]));
593 if (adtb
[IFLA_BOND_AD_INFO_PARTNER_KEY
])
596 "ad_partner_key %d ",
597 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_PARTNER_KEY
]));
599 if (adtb
[IFLA_BOND_AD_INFO_PARTNER_MAC
]) {
601 RTA_DATA(adtb
[IFLA_BOND_AD_INFO_PARTNER_MAC
]);
603 print_string(PRINT_ANY
,
605 "ad_partner_mac %s ",
606 ll_addr_n2a(p
, ETH_ALEN
, 0, b
, sizeof(b
)));
612 if (tb
[IFLA_BOND_AD_ACTOR_SYS_PRIO
]) {
613 print_uint(PRINT_ANY
,
615 "ad_actor_sys_prio %u ",
616 rta_getattr_u16(tb
[IFLA_BOND_AD_ACTOR_SYS_PRIO
]));
619 if (tb
[IFLA_BOND_AD_USER_PORT_KEY
]) {
620 print_uint(PRINT_ANY
,
622 "ad_user_port_key %u ",
623 rta_getattr_u16(tb
[IFLA_BOND_AD_USER_PORT_KEY
]));
626 if (tb
[IFLA_BOND_AD_ACTOR_SYSTEM
]) {
627 /* We assume the l2 address is an Ethernet MAC address */
630 print_string(PRINT_ANY
,
632 "ad_actor_system %s ",
633 ll_addr_n2a(RTA_DATA(tb
[IFLA_BOND_AD_ACTOR_SYSTEM
]),
634 RTA_PAYLOAD(tb
[IFLA_BOND_AD_ACTOR_SYSTEM
]),
635 1 /*ARPHDR_ETHER*/, b1
, sizeof(b1
)));
638 if (tb
[IFLA_BOND_TLB_DYNAMIC_LB
]) {
639 print_uint(PRINT_ANY
,
641 "tlb_dynamic_lb %u ",
642 rta_getattr_u8(tb
[IFLA_BOND_TLB_DYNAMIC_LB
]));
646 static void bond_print_help(struct link_util
*lu
, int argc
, char **argv
,
652 struct link_util bond_link_util
= {
654 .maxattr
= IFLA_BOND_MAX
,
655 .parse_opt
= bond_parse_opt
,
656 .print_opt
= bond_print_opt
,
657 .print_help
= bond_print_help
,