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_bonding.h>
20 #include "ip_common.h"
21 #include "json_print.h"
23 #define BOND_MAX_ARP_TARGETS 16
25 static unsigned int xstats_print_attr
;
26 static int filter_index
;
28 static const char *mode_tbl
[] = {
39 static const char *arp_validate_tbl
[] = {
47 static const char *arp_all_targets_tbl
[] = {
53 static const char *primary_reselect_tbl
[] = {
60 static const char *fail_over_mac_tbl
[] = {
67 static const char *xmit_hash_policy_tbl
[] = {
77 static const char *lacp_rate_tbl
[] = {
83 static const char *ad_select_tbl
[] = {
90 static const char *get_name(const char **tbl
, int index
)
94 for (i
= 0; tbl
[i
]; i
++)
101 static int get_index(const char **tbl
, char *name
)
105 /* check for integer index passed in instead of name */
106 if (get_integer(&index
, name
, 10) == 0)
107 for (i
= 0; tbl
[i
]; i
++)
111 for (i
= 0; tbl
[i
]; i
++)
112 if (strcmp(tbl
[i
], name
) == 0)
118 static void print_explain(FILE *f
)
121 "Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n"
122 " [ clear_active_slave ] [ miimon MIIMON ]\n"
123 " [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n"
124 " [ peer_notify_delay DELAY ]\n"
125 " [ use_carrier USE_CARRIER ]\n"
126 " [ arp_interval ARP_INTERVAL ]\n"
127 " [ arp_validate ARP_VALIDATE ]\n"
128 " [ arp_all_targets ARP_ALL_TARGETS ]\n"
129 " [ arp_ip_target [ ARP_IP_TARGET, ... ] ]\n"
130 " [ primary SLAVE_DEV ]\n"
131 " [ primary_reselect PRIMARY_RESELECT ]\n"
132 " [ fail_over_mac FAIL_OVER_MAC ]\n"
133 " [ xmit_hash_policy XMIT_HASH_POLICY ]\n"
134 " [ resend_igmp RESEND_IGMP ]\n"
135 " [ num_grat_arp|num_unsol_na NUM_GRAT_ARP|NUM_UNSOL_NA ]\n"
136 " [ all_slaves_active ALL_SLAVES_ACTIVE ]\n"
137 " [ min_links MIN_LINKS ]\n"
138 " [ lp_interval LP_INTERVAL ]\n"
139 " [ packets_per_slave PACKETS_PER_SLAVE ]\n"
140 " [ tlb_dynamic_lb TLB_DYNAMIC_LB ]\n"
141 " [ lacp_rate LACP_RATE ]\n"
142 " [ ad_select AD_SELECT ]\n"
143 " [ ad_user_port_key PORTKEY ]\n"
144 " [ ad_actor_sys_prio SYSPRIO ]\n"
145 " [ ad_actor_system LLADDR ]\n"
147 "BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n"
148 "ARP_VALIDATE := none|active|backup|all\n"
149 "ARP_ALL_TARGETS := any|all\n"
150 "PRIMARY_RESELECT := always|better|failure\n"
151 "FAIL_OVER_MAC := none|active|follow\n"
152 "XMIT_HASH_POLICY := layer2|layer2+3|layer3+4|encap2+3|encap3+4|vlan+srcmac\n"
153 "LACP_RATE := slow|fast\n"
154 "AD_SELECT := stable|bandwidth|count\n"
158 static void explain(void)
160 print_explain(stderr
);
163 static int bond_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
166 __u8 mode
, use_carrier
, primary_reselect
, fail_over_mac
;
167 __u8 xmit_hash_policy
, num_peer_notif
, all_slaves_active
;
168 __u8 lacp_rate
, ad_select
, tlb_dynamic_lb
;
169 __u16 ad_user_port_key
, ad_actor_sys_prio
;
170 __u32 miimon
, updelay
, downdelay
, peer_notify_delay
, arp_interval
, arp_validate
;
171 __u32 arp_all_targets
, resend_igmp
, min_links
, lp_interval
;
172 __u32 packets_per_slave
;
173 unsigned int ifindex
;
176 if (matches(*argv
, "mode") == 0) {
178 if (get_index(mode_tbl
, *argv
) < 0)
179 invarg("invalid mode", *argv
);
180 mode
= get_index(mode_tbl
, *argv
);
181 addattr8(n
, 1024, IFLA_BOND_MODE
, mode
);
182 } else if (matches(*argv
, "active_slave") == 0) {
184 ifindex
= ll_name_to_index(*argv
);
187 addattr32(n
, 1024, IFLA_BOND_ACTIVE_SLAVE
, ifindex
);
188 } else if (matches(*argv
, "clear_active_slave") == 0) {
189 addattr32(n
, 1024, IFLA_BOND_ACTIVE_SLAVE
, 0);
190 } else if (matches(*argv
, "miimon") == 0) {
192 if (get_u32(&miimon
, *argv
, 0))
193 invarg("invalid miimon", *argv
);
194 addattr32(n
, 1024, IFLA_BOND_MIIMON
, miimon
);
195 } else if (matches(*argv
, "updelay") == 0) {
197 if (get_u32(&updelay
, *argv
, 0))
198 invarg("invalid updelay", *argv
);
199 addattr32(n
, 1024, IFLA_BOND_UPDELAY
, updelay
);
200 } else if (matches(*argv
, "downdelay") == 0) {
202 if (get_u32(&downdelay
, *argv
, 0))
203 invarg("invalid downdelay", *argv
);
204 addattr32(n
, 1024, IFLA_BOND_DOWNDELAY
, downdelay
);
205 } else if (matches(*argv
, "peer_notify_delay") == 0) {
207 if (get_u32(&peer_notify_delay
, *argv
, 0))
208 invarg("invalid peer_notify_delay", *argv
);
209 addattr32(n
, 1024, IFLA_BOND_PEER_NOTIF_DELAY
, peer_notify_delay
);
210 } else if (matches(*argv
, "use_carrier") == 0) {
212 if (get_u8(&use_carrier
, *argv
, 0))
213 invarg("invalid use_carrier", *argv
);
214 addattr8(n
, 1024, IFLA_BOND_USE_CARRIER
, use_carrier
);
215 } else if (matches(*argv
, "arp_interval") == 0) {
217 if (get_u32(&arp_interval
, *argv
, 0))
218 invarg("invalid arp_interval", *argv
);
219 addattr32(n
, 1024, IFLA_BOND_ARP_INTERVAL
, arp_interval
);
220 } else if (matches(*argv
, "arp_ip_target") == 0) {
221 struct rtattr
*nest
= addattr_nest(n
, 1024,
222 IFLA_BOND_ARP_IP_TARGET
);
225 char *targets
= strdupa(*argv
);
226 char *target
= strtok(targets
, ",");
229 for (i
= 0; target
&& i
< BOND_MAX_ARP_TARGETS
; i
++) {
230 __u32 addr
= get_addr32(target
);
232 addattr32(n
, 1024, i
, addr
);
233 target
= strtok(NULL
, ",");
235 addattr_nest_end(n
, nest
);
237 addattr_nest_end(n
, nest
);
238 } else if (matches(*argv
, "arp_validate") == 0) {
240 if (get_index(arp_validate_tbl
, *argv
) < 0)
241 invarg("invalid arp_validate", *argv
);
242 arp_validate
= get_index(arp_validate_tbl
, *argv
);
243 addattr32(n
, 1024, IFLA_BOND_ARP_VALIDATE
, arp_validate
);
244 } else if (matches(*argv
, "arp_all_targets") == 0) {
246 if (get_index(arp_all_targets_tbl
, *argv
) < 0)
247 invarg("invalid arp_all_targets", *argv
);
248 arp_all_targets
= get_index(arp_all_targets_tbl
, *argv
);
249 addattr32(n
, 1024, IFLA_BOND_ARP_ALL_TARGETS
, arp_all_targets
);
250 } else if (matches(*argv
, "primary") == 0) {
252 ifindex
= ll_name_to_index(*argv
);
255 addattr32(n
, 1024, IFLA_BOND_PRIMARY
, ifindex
);
256 } else if (matches(*argv
, "primary_reselect") == 0) {
258 if (get_index(primary_reselect_tbl
, *argv
) < 0)
259 invarg("invalid primary_reselect", *argv
);
260 primary_reselect
= get_index(primary_reselect_tbl
, *argv
);
261 addattr8(n
, 1024, IFLA_BOND_PRIMARY_RESELECT
,
263 } else if (matches(*argv
, "fail_over_mac") == 0) {
265 if (get_index(fail_over_mac_tbl
, *argv
) < 0)
266 invarg("invalid fail_over_mac", *argv
);
267 fail_over_mac
= get_index(fail_over_mac_tbl
, *argv
);
268 addattr8(n
, 1024, IFLA_BOND_FAIL_OVER_MAC
,
270 } else if (matches(*argv
, "xmit_hash_policy") == 0) {
272 if (get_index(xmit_hash_policy_tbl
, *argv
) < 0)
273 invarg("invalid xmit_hash_policy", *argv
);
275 xmit_hash_policy
= get_index(xmit_hash_policy_tbl
, *argv
);
276 addattr8(n
, 1024, IFLA_BOND_XMIT_HASH_POLICY
,
278 } else if (matches(*argv
, "resend_igmp") == 0) {
280 if (get_u32(&resend_igmp
, *argv
, 0))
281 invarg("invalid resend_igmp", *argv
);
283 addattr32(n
, 1024, IFLA_BOND_RESEND_IGMP
, resend_igmp
);
284 } else if (matches(*argv
, "num_grat_arp") == 0 ||
285 matches(*argv
, "num_unsol_na") == 0) {
287 if (get_u8(&num_peer_notif
, *argv
, 0))
288 invarg("invalid num_grat_arp|num_unsol_na",
291 addattr8(n
, 1024, IFLA_BOND_NUM_PEER_NOTIF
,
293 } else if (matches(*argv
, "all_slaves_active") == 0) {
295 if (get_u8(&all_slaves_active
, *argv
, 0))
296 invarg("invalid all_slaves_active", *argv
);
298 addattr8(n
, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE
,
300 } else if (matches(*argv
, "min_links") == 0) {
302 if (get_u32(&min_links
, *argv
, 0))
303 invarg("invalid min_links", *argv
);
305 addattr32(n
, 1024, IFLA_BOND_MIN_LINKS
, min_links
);
306 } else if (matches(*argv
, "lp_interval") == 0) {
308 if (get_u32(&lp_interval
, *argv
, 0))
309 invarg("invalid lp_interval", *argv
);
311 addattr32(n
, 1024, IFLA_BOND_LP_INTERVAL
, lp_interval
);
312 } else if (matches(*argv
, "packets_per_slave") == 0) {
314 if (get_u32(&packets_per_slave
, *argv
, 0))
315 invarg("invalid packets_per_slave", *argv
);
317 addattr32(n
, 1024, IFLA_BOND_PACKETS_PER_SLAVE
,
319 } else if (matches(*argv
, "lacp_rate") == 0) {
321 if (get_index(lacp_rate_tbl
, *argv
) < 0)
322 invarg("invalid lacp_rate", *argv
);
324 lacp_rate
= get_index(lacp_rate_tbl
, *argv
);
325 addattr8(n
, 1024, IFLA_BOND_AD_LACP_RATE
, lacp_rate
);
326 } else if (matches(*argv
, "ad_select") == 0) {
328 if (get_index(ad_select_tbl
, *argv
) < 0)
329 invarg("invalid ad_select", *argv
);
331 ad_select
= get_index(ad_select_tbl
, *argv
);
332 addattr8(n
, 1024, IFLA_BOND_AD_SELECT
, ad_select
);
333 } else if (matches(*argv
, "ad_user_port_key") == 0) {
335 if (get_u16(&ad_user_port_key
, *argv
, 0))
336 invarg("invalid ad_user_port_key", *argv
);
338 addattr16(n
, 1024, IFLA_BOND_AD_USER_PORT_KEY
,
340 } else if (matches(*argv
, "ad_actor_sys_prio") == 0) {
342 if (get_u16(&ad_actor_sys_prio
, *argv
, 0))
343 invarg("invalid ad_actor_sys_prio", *argv
);
345 addattr16(n
, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO
,
347 } else if (matches(*argv
, "ad_actor_system") == 0) {
352 len
= ll_addr_a2n(abuf
, sizeof(abuf
), *argv
);
355 addattr_l(n
, 1024, IFLA_BOND_AD_ACTOR_SYSTEM
,
357 } else if (matches(*argv
, "tlb_dynamic_lb") == 0) {
359 if (get_u8(&tlb_dynamic_lb
, *argv
, 0)) {
360 invarg("invalid tlb_dynamic_lb", *argv
);
363 addattr8(n
, 1024, IFLA_BOND_TLB_DYNAMIC_LB
,
365 } else if (matches(*argv
, "help") == 0) {
369 fprintf(stderr
, "bond: unknown command \"%s\"?\n", *argv
);
379 static void bond_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
384 if (tb
[IFLA_BOND_MODE
]) {
385 const char *mode
= get_name(mode_tbl
,
386 rta_getattr_u8(tb
[IFLA_BOND_MODE
]));
387 print_string(PRINT_ANY
, "mode", "mode %s ", mode
);
390 if (tb
[IFLA_BOND_ACTIVE_SLAVE
]) {
391 unsigned int ifindex
=
392 rta_getattr_u32(tb
[IFLA_BOND_ACTIVE_SLAVE
]);
395 print_string(PRINT_ANY
,
398 ll_index_to_name(ifindex
));
402 if (tb
[IFLA_BOND_MIIMON
])
403 print_uint(PRINT_ANY
,
406 rta_getattr_u32(tb
[IFLA_BOND_MIIMON
]));
408 if (tb
[IFLA_BOND_UPDELAY
])
409 print_uint(PRINT_ANY
,
412 rta_getattr_u32(tb
[IFLA_BOND_UPDELAY
]));
414 if (tb
[IFLA_BOND_DOWNDELAY
])
415 print_uint(PRINT_ANY
,
418 rta_getattr_u32(tb
[IFLA_BOND_DOWNDELAY
]));
420 if (tb
[IFLA_BOND_PEER_NOTIF_DELAY
])
421 print_uint(PRINT_ANY
,
423 "peer_notify_delay %u ",
424 rta_getattr_u32(tb
[IFLA_BOND_PEER_NOTIF_DELAY
]));
426 if (tb
[IFLA_BOND_USE_CARRIER
])
427 print_uint(PRINT_ANY
,
430 rta_getattr_u8(tb
[IFLA_BOND_USE_CARRIER
]));
432 if (tb
[IFLA_BOND_ARP_INTERVAL
])
433 print_uint(PRINT_ANY
,
436 rta_getattr_u32(tb
[IFLA_BOND_ARP_INTERVAL
]));
438 if (tb
[IFLA_BOND_ARP_IP_TARGET
]) {
439 struct rtattr
*iptb
[BOND_MAX_ARP_TARGETS
+ 1];
442 parse_rtattr_nested(iptb
, BOND_MAX_ARP_TARGETS
,
443 tb
[IFLA_BOND_ARP_IP_TARGET
]);
446 open_json_array(PRINT_JSON
, "arp_ip_target");
447 print_string(PRINT_FP
, NULL
, "arp_ip_target ", NULL
);
450 for (i
= 0; i
< BOND_MAX_ARP_TARGETS
; i
++) {
452 print_string(PRINT_ANY
,
455 rt_addr_n2a_rta(AF_INET
, iptb
[i
]));
456 if (!is_json_context()
457 && i
< BOND_MAX_ARP_TARGETS
-1
463 print_string(PRINT_FP
, NULL
, " ", NULL
);
464 close_json_array(PRINT_JSON
, NULL
);
468 if (tb
[IFLA_BOND_ARP_VALIDATE
]) {
469 __u32 arp_v
= rta_getattr_u32(tb
[IFLA_BOND_ARP_VALIDATE
]);
470 const char *arp_validate
= get_name(arp_validate_tbl
, arp_v
);
472 if (!arp_v
&& is_json_context())
473 print_null(PRINT_JSON
, "arp_validate", NULL
, NULL
);
475 print_string(PRINT_ANY
,
481 if (tb
[IFLA_BOND_ARP_ALL_TARGETS
]) {
482 const char *arp_all_targets
= get_name(arp_all_targets_tbl
,
483 rta_getattr_u32(tb
[IFLA_BOND_ARP_ALL_TARGETS
]));
484 print_string(PRINT_ANY
,
486 "arp_all_targets %s ",
490 if (tb
[IFLA_BOND_PRIMARY
]) {
491 unsigned int ifindex
= rta_getattr_u32(tb
[IFLA_BOND_PRIMARY
]);
494 print_string(PRINT_ANY
,
497 ll_index_to_name(ifindex
));
501 if (tb
[IFLA_BOND_PRIMARY_RESELECT
]) {
502 const char *primary_reselect
= get_name(primary_reselect_tbl
,
503 rta_getattr_u8(tb
[IFLA_BOND_PRIMARY_RESELECT
]));
504 print_string(PRINT_ANY
,
506 "primary_reselect %s ",
510 if (tb
[IFLA_BOND_FAIL_OVER_MAC
]) {
511 const char *fail_over_mac
= get_name(fail_over_mac_tbl
,
512 rta_getattr_u8(tb
[IFLA_BOND_FAIL_OVER_MAC
]));
513 print_string(PRINT_ANY
,
519 if (tb
[IFLA_BOND_XMIT_HASH_POLICY
]) {
520 const char *xmit_hash_policy
= get_name(xmit_hash_policy_tbl
,
521 rta_getattr_u8(tb
[IFLA_BOND_XMIT_HASH_POLICY
]));
522 print_string(PRINT_ANY
,
524 "xmit_hash_policy %s ",
528 if (tb
[IFLA_BOND_RESEND_IGMP
])
529 print_uint(PRINT_ANY
,
532 rta_getattr_u32(tb
[IFLA_BOND_RESEND_IGMP
]));
534 if (tb
[IFLA_BOND_NUM_PEER_NOTIF
])
535 print_uint(PRINT_ANY
,
538 rta_getattr_u8(tb
[IFLA_BOND_NUM_PEER_NOTIF
]));
540 if (tb
[IFLA_BOND_ALL_SLAVES_ACTIVE
])
541 print_uint(PRINT_ANY
,
543 "all_slaves_active %u ",
544 rta_getattr_u8(tb
[IFLA_BOND_ALL_SLAVES_ACTIVE
]));
546 if (tb
[IFLA_BOND_MIN_LINKS
])
547 print_uint(PRINT_ANY
,
550 rta_getattr_u32(tb
[IFLA_BOND_MIN_LINKS
]));
552 if (tb
[IFLA_BOND_LP_INTERVAL
])
553 print_uint(PRINT_ANY
,
556 rta_getattr_u32(tb
[IFLA_BOND_LP_INTERVAL
]));
558 if (tb
[IFLA_BOND_PACKETS_PER_SLAVE
])
559 print_uint(PRINT_ANY
,
561 "packets_per_slave %u ",
562 rta_getattr_u32(tb
[IFLA_BOND_PACKETS_PER_SLAVE
]));
564 if (tb
[IFLA_BOND_AD_LACP_RATE
]) {
565 const char *lacp_rate
= get_name(lacp_rate_tbl
,
566 rta_getattr_u8(tb
[IFLA_BOND_AD_LACP_RATE
]));
567 print_string(PRINT_ANY
,
573 if (tb
[IFLA_BOND_AD_SELECT
]) {
574 const char *ad_select
= get_name(ad_select_tbl
,
575 rta_getattr_u8(tb
[IFLA_BOND_AD_SELECT
]));
576 print_string(PRINT_ANY
,
582 if (tb
[IFLA_BOND_AD_INFO
]) {
583 struct rtattr
*adtb
[IFLA_BOND_AD_INFO_MAX
+ 1];
585 parse_rtattr_nested(adtb
, IFLA_BOND_AD_INFO_MAX
,
586 tb
[IFLA_BOND_AD_INFO
]);
588 open_json_object("ad_info");
590 if (adtb
[IFLA_BOND_AD_INFO_AGGREGATOR
])
594 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_AGGREGATOR
]));
596 if (adtb
[IFLA_BOND_AD_INFO_NUM_PORTS
])
600 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_NUM_PORTS
]));
602 if (adtb
[IFLA_BOND_AD_INFO_ACTOR_KEY
])
606 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_ACTOR_KEY
]));
608 if (adtb
[IFLA_BOND_AD_INFO_PARTNER_KEY
])
611 "ad_partner_key %d ",
612 rta_getattr_u16(adtb
[IFLA_BOND_AD_INFO_PARTNER_KEY
]));
614 if (adtb
[IFLA_BOND_AD_INFO_PARTNER_MAC
]) {
616 RTA_DATA(adtb
[IFLA_BOND_AD_INFO_PARTNER_MAC
]);
618 print_string(PRINT_ANY
,
620 "ad_partner_mac %s ",
621 ll_addr_n2a(p
, ETH_ALEN
, 0, b
, sizeof(b
)));
627 if (tb
[IFLA_BOND_AD_ACTOR_SYS_PRIO
]) {
628 print_uint(PRINT_ANY
,
630 "ad_actor_sys_prio %u ",
631 rta_getattr_u16(tb
[IFLA_BOND_AD_ACTOR_SYS_PRIO
]));
634 if (tb
[IFLA_BOND_AD_USER_PORT_KEY
]) {
635 print_uint(PRINT_ANY
,
637 "ad_user_port_key %u ",
638 rta_getattr_u16(tb
[IFLA_BOND_AD_USER_PORT_KEY
]));
641 if (tb
[IFLA_BOND_AD_ACTOR_SYSTEM
]) {
642 /* We assume the l2 address is an Ethernet MAC address */
645 print_string(PRINT_ANY
,
647 "ad_actor_system %s ",
648 ll_addr_n2a(RTA_DATA(tb
[IFLA_BOND_AD_ACTOR_SYSTEM
]),
649 RTA_PAYLOAD(tb
[IFLA_BOND_AD_ACTOR_SYSTEM
]),
650 1 /*ARPHDR_ETHER*/, b1
, sizeof(b1
)));
653 if (tb
[IFLA_BOND_TLB_DYNAMIC_LB
]) {
654 print_uint(PRINT_ANY
,
656 "tlb_dynamic_lb %u ",
657 rta_getattr_u8(tb
[IFLA_BOND_TLB_DYNAMIC_LB
]));
661 static void bond_print_help(struct link_util
*lu
, int argc
, char **argv
,
667 static void bond_print_xstats_help(struct link_util
*lu
, FILE *f
)
669 fprintf(f
, "Usage: ... %s [ 802.3ad ] [ dev DEVICE ]\n", lu
->id
);
672 static void bond_print_3ad_stats(struct rtattr
*lacpattr
)
674 struct rtattr
*lacptb
[BOND_3AD_STAT_MAX
+1];
677 parse_rtattr(lacptb
, BOND_3AD_STAT_MAX
, RTA_DATA(lacpattr
),
678 RTA_PAYLOAD(lacpattr
));
679 open_json_object("802.3ad");
680 if (lacptb
[BOND_3AD_STAT_LACPDU_RX
]) {
681 print_string(PRINT_FP
, NULL
, "%-16s ", "");
682 print_u64(PRINT_ANY
, "lacpdu_rx", "LACPDU Rx %llu\n",
683 rta_getattr_u64(lacptb
[BOND_3AD_STAT_LACPDU_RX
]));
685 if (lacptb
[BOND_3AD_STAT_LACPDU_TX
]) {
686 print_string(PRINT_FP
, NULL
, "%-16s ", "");
687 print_u64(PRINT_ANY
, "lacpdu_tx", "LACPDU Tx %llu\n",
688 rta_getattr_u64(lacptb
[BOND_3AD_STAT_LACPDU_TX
]));
690 if (lacptb
[BOND_3AD_STAT_LACPDU_UNKNOWN_RX
]) {
691 print_string(PRINT_FP
, NULL
, "%-16s ", "");
692 val
= rta_getattr_u64(lacptb
[BOND_3AD_STAT_LACPDU_UNKNOWN_RX
]);
695 "LACPDU Unknown type Rx %llu\n",
698 if (lacptb
[BOND_3AD_STAT_LACPDU_ILLEGAL_RX
]) {
699 print_string(PRINT_FP
, NULL
, "%-16s ", "");
700 val
= rta_getattr_u64(lacptb
[BOND_3AD_STAT_LACPDU_ILLEGAL_RX
]);
703 "LACPDU Illegal Rx %llu\n",
706 if (lacptb
[BOND_3AD_STAT_MARKER_RX
]) {
707 print_string(PRINT_FP
, NULL
, "%-16s ", "");
708 print_u64(PRINT_ANY
, "marker_rx", "Marker Rx %llu\n",
709 rta_getattr_u64(lacptb
[BOND_3AD_STAT_MARKER_RX
]));
711 if (lacptb
[BOND_3AD_STAT_MARKER_TX
]) {
712 print_string(PRINT_FP
, NULL
, "%-16s ", "");
713 print_u64(PRINT_ANY
, "marker_tx", "Marker Tx %llu\n",
714 rta_getattr_u64(lacptb
[BOND_3AD_STAT_MARKER_TX
]));
716 if (lacptb
[BOND_3AD_STAT_MARKER_RESP_RX
]) {
717 print_string(PRINT_FP
, NULL
, "%-16s ", "");
718 val
= rta_getattr_u64(lacptb
[BOND_3AD_STAT_MARKER_RESP_RX
]);
720 "marker_response_rx",
721 "Marker response Rx %llu\n",
724 if (lacptb
[BOND_3AD_STAT_MARKER_RESP_TX
]) {
725 print_string(PRINT_FP
, NULL
, "%-16s ", "");
726 val
= rta_getattr_u64(lacptb
[BOND_3AD_STAT_MARKER_RESP_TX
]);
728 "marker_response_tx",
729 "Marker response Tx %llu\n",
732 if (lacptb
[BOND_3AD_STAT_MARKER_UNKNOWN_RX
]) {
733 print_string(PRINT_FP
, NULL
, "%-16s ", "");
734 val
= rta_getattr_u64(lacptb
[BOND_3AD_STAT_MARKER_UNKNOWN_RX
]);
737 "Marker unknown type Rx %llu\n",
743 static void bond_print_stats_attr(struct rtattr
*attr
, int ifindex
)
745 struct rtattr
*bondtb
[LINK_XSTATS_TYPE_MAX
+1];
746 struct rtattr
*i
, *list
;
747 const char *ifname
= "";
750 parse_rtattr(bondtb
, LINK_XSTATS_TYPE_MAX
+1, RTA_DATA(attr
),
752 if (!bondtb
[LINK_XSTATS_TYPE_BOND
])
755 list
= bondtb
[LINK_XSTATS_TYPE_BOND
];
756 rem
= RTA_PAYLOAD(list
);
757 open_json_object(NULL
);
758 ifname
= ll_index_to_name(ifindex
);
759 print_string(PRINT_ANY
, "ifname", "%-16s\n", ifname
);
760 for (i
= RTA_DATA(list
); RTA_OK(i
, rem
); i
= RTA_NEXT(i
, rem
)) {
761 if (xstats_print_attr
&& i
->rta_type
!= xstats_print_attr
)
764 switch (i
->rta_type
) {
765 case BOND_XSTATS_3AD
:
766 bond_print_3ad_stats(i
);
774 int bond_print_xstats(struct nlmsghdr
*n
, void *arg
)
776 struct if_stats_msg
*ifsm
= NLMSG_DATA(n
);
777 struct rtattr
*tb
[IFLA_STATS_MAX
+1];
778 int len
= n
->nlmsg_len
;
780 len
-= NLMSG_LENGTH(sizeof(*ifsm
));
782 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
785 if (filter_index
&& filter_index
!= ifsm
->ifindex
)
788 parse_rtattr(tb
, IFLA_STATS_MAX
, IFLA_STATS_RTA(ifsm
), len
);
789 if (tb
[IFLA_STATS_LINK_XSTATS
])
790 bond_print_stats_attr(tb
[IFLA_STATS_LINK_XSTATS
],
793 if (tb
[IFLA_STATS_LINK_XSTATS_SLAVE
])
794 bond_print_stats_attr(tb
[IFLA_STATS_LINK_XSTATS_SLAVE
],
800 int bond_parse_xstats(struct link_util
*lu
, int argc
, char **argv
)
803 if (strcmp(*argv
, "lacp") == 0 ||
804 strcmp(*argv
, "802.3ad") == 0) {
805 xstats_print_attr
= BOND_XSTATS_3AD
;
806 } else if (strcmp(*argv
, "dev") == 0) {
808 filter_index
= ll_name_to_index(*argv
);
811 } else if (strcmp(*argv
, "help") == 0) {
812 bond_print_xstats_help(lu
, stdout
);
815 invarg("unknown attribute", *argv
);
824 struct link_util bond_link_util
= {
826 .maxattr
= IFLA_BOND_MAX
,
827 .parse_opt
= bond_parse_opt
,
828 .print_opt
= bond_print_opt
,
829 .print_help
= bond_print_help
,
830 .parse_ifla_xstats
= bond_parse_xstats
,
831 .print_ifla_xstats
= bond_print_xstats
,