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