]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_bond.c
devlink: Introduce PCI SF port flavour and attribute
[mirror_iproute2.git] / ip / iplink_bond.c
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@resnulli.us>
10 * Scott Feldman <sfeldma@cumulusnetworks.com>
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
25 static unsigned int xstats_print_attr;
26 static int filter_index;
27
28 static 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
39 static const char *arp_validate_tbl[] = {
40 "none",
41 "active",
42 "backup",
43 "all",
44 NULL,
45 };
46
47 static const char *arp_all_targets_tbl[] = {
48 "any",
49 "all",
50 NULL,
51 };
52
53 static const char *primary_reselect_tbl[] = {
54 "always",
55 "better",
56 "failure",
57 NULL,
58 };
59
60 static const char *fail_over_mac_tbl[] = {
61 "none",
62 "active",
63 "follow",
64 NULL,
65 };
66
67 static const char *xmit_hash_policy_tbl[] = {
68 "layer2",
69 "layer3+4",
70 "layer2+3",
71 "encap2+3",
72 "encap3+4",
73 "vlan+srcmac",
74 NULL,
75 };
76
77 static const char *lacp_rate_tbl[] = {
78 "slow",
79 "fast",
80 NULL,
81 };
82
83 static const char *ad_select_tbl[] = {
84 "stable",
85 "bandwidth",
86 "count",
87 NULL,
88 };
89
90 static const char *get_name(const char **tbl, int index)
91 {
92 int i;
93
94 for (i = 0; tbl[i]; i++)
95 if (i == index)
96 return tbl[i];
97
98 return "UNKNOWN";
99 }
100
101 static int get_index(const char **tbl, char *name)
102 {
103 int i, index;
104
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++)
108 if (i == index)
109 return i;
110
111 for (i = 0; tbl[i]; i++)
112 if (strcmp(tbl[i], name) == 0)
113 return i;
114
115 return -1;
116 }
117
118 static void print_explain(FILE *f)
119 {
120 fprintf(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"
146 "\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"
155 );
156 }
157
158 static void explain(void)
159 {
160 print_explain(stderr);
161 }
162
163 static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
164 struct nlmsghdr *n)
165 {
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;
174
175 while (argc > 0) {
176 if (matches(*argv, "mode") == 0) {
177 NEXT_ARG();
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) {
183 NEXT_ARG();
184 ifindex = ll_name_to_index(*argv);
185 if (!ifindex)
186 return nodev(*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) {
191 NEXT_ARG();
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) {
196 NEXT_ARG();
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) {
201 NEXT_ARG();
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) {
206 NEXT_ARG();
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) {
211 NEXT_ARG();
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) {
216 NEXT_ARG();
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);
223 if (NEXT_ARG_OK()) {
224 NEXT_ARG();
225 char *targets = strdupa(*argv);
226 char *target = strtok(targets, ",");
227 int i;
228
229 for (i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) {
230 __u32 addr = get_addr32(target);
231
232 addattr32(n, 1024, i, addr);
233 target = strtok(NULL, ",");
234 }
235 addattr_nest_end(n, nest);
236 }
237 addattr_nest_end(n, nest);
238 } else if (matches(*argv, "arp_validate") == 0) {
239 NEXT_ARG();
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) {
245 NEXT_ARG();
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) {
251 NEXT_ARG();
252 ifindex = ll_name_to_index(*argv);
253 if (!ifindex)
254 return nodev(*argv);
255 addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex);
256 } else if (matches(*argv, "primary_reselect") == 0) {
257 NEXT_ARG();
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,
262 primary_reselect);
263 } else if (matches(*argv, "fail_over_mac") == 0) {
264 NEXT_ARG();
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,
269 fail_over_mac);
270 } else if (matches(*argv, "xmit_hash_policy") == 0) {
271 NEXT_ARG();
272 if (get_index(xmit_hash_policy_tbl, *argv) < 0)
273 invarg("invalid xmit_hash_policy", *argv);
274
275 xmit_hash_policy = get_index(xmit_hash_policy_tbl, *argv);
276 addattr8(n, 1024, IFLA_BOND_XMIT_HASH_POLICY,
277 xmit_hash_policy);
278 } else if (matches(*argv, "resend_igmp") == 0) {
279 NEXT_ARG();
280 if (get_u32(&resend_igmp, *argv, 0))
281 invarg("invalid resend_igmp", *argv);
282
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) {
286 NEXT_ARG();
287 if (get_u8(&num_peer_notif, *argv, 0))
288 invarg("invalid num_grat_arp|num_unsol_na",
289 *argv);
290
291 addattr8(n, 1024, IFLA_BOND_NUM_PEER_NOTIF,
292 num_peer_notif);
293 } else if (matches(*argv, "all_slaves_active") == 0) {
294 NEXT_ARG();
295 if (get_u8(&all_slaves_active, *argv, 0))
296 invarg("invalid all_slaves_active", *argv);
297
298 addattr8(n, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE,
299 all_slaves_active);
300 } else if (matches(*argv, "min_links") == 0) {
301 NEXT_ARG();
302 if (get_u32(&min_links, *argv, 0))
303 invarg("invalid min_links", *argv);
304
305 addattr32(n, 1024, IFLA_BOND_MIN_LINKS, min_links);
306 } else if (matches(*argv, "lp_interval") == 0) {
307 NEXT_ARG();
308 if (get_u32(&lp_interval, *argv, 0))
309 invarg("invalid lp_interval", *argv);
310
311 addattr32(n, 1024, IFLA_BOND_LP_INTERVAL, lp_interval);
312 } else if (matches(*argv, "packets_per_slave") == 0) {
313 NEXT_ARG();
314 if (get_u32(&packets_per_slave, *argv, 0))
315 invarg("invalid packets_per_slave", *argv);
316
317 addattr32(n, 1024, IFLA_BOND_PACKETS_PER_SLAVE,
318 packets_per_slave);
319 } else if (matches(*argv, "lacp_rate") == 0) {
320 NEXT_ARG();
321 if (get_index(lacp_rate_tbl, *argv) < 0)
322 invarg("invalid lacp_rate", *argv);
323
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) {
327 NEXT_ARG();
328 if (get_index(ad_select_tbl, *argv) < 0)
329 invarg("invalid ad_select", *argv);
330
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) {
334 NEXT_ARG();
335 if (get_u16(&ad_user_port_key, *argv, 0))
336 invarg("invalid ad_user_port_key", *argv);
337
338 addattr16(n, 1024, IFLA_BOND_AD_USER_PORT_KEY,
339 ad_user_port_key);
340 } else if (matches(*argv, "ad_actor_sys_prio") == 0) {
341 NEXT_ARG();
342 if (get_u16(&ad_actor_sys_prio, *argv, 0))
343 invarg("invalid ad_actor_sys_prio", *argv);
344
345 addattr16(n, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO,
346 ad_actor_sys_prio);
347 } else if (matches(*argv, "ad_actor_system") == 0) {
348 int len;
349 char abuf[32];
350
351 NEXT_ARG();
352 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
353 if (len < 0)
354 return -1;
355 addattr_l(n, 1024, IFLA_BOND_AD_ACTOR_SYSTEM,
356 abuf, len);
357 } else if (matches(*argv, "tlb_dynamic_lb") == 0) {
358 NEXT_ARG();
359 if (get_u8(&tlb_dynamic_lb, *argv, 0)) {
360 invarg("invalid tlb_dynamic_lb", *argv);
361 return -1;
362 }
363 addattr8(n, 1024, IFLA_BOND_TLB_DYNAMIC_LB,
364 tlb_dynamic_lb);
365 } else if (matches(*argv, "help") == 0) {
366 explain();
367 return -1;
368 } else {
369 fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv);
370 explain();
371 return -1;
372 }
373 argc--, argv++;
374 }
375
376 return 0;
377 }
378
379 static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
380 {
381 if (!tb)
382 return;
383
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);
388 }
389
390 if (tb[IFLA_BOND_ACTIVE_SLAVE]) {
391 unsigned int ifindex =
392 rta_getattr_u32(tb[IFLA_BOND_ACTIVE_SLAVE]);
393
394 if (ifindex) {
395 print_string(PRINT_ANY,
396 "active_slave",
397 "active_slave %s ",
398 ll_index_to_name(ifindex));
399 }
400 }
401
402 if (tb[IFLA_BOND_MIIMON])
403 print_uint(PRINT_ANY,
404 "miimon",
405 "miimon %u ",
406 rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
407
408 if (tb[IFLA_BOND_UPDELAY])
409 print_uint(PRINT_ANY,
410 "updelay",
411 "updelay %u ",
412 rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
413
414 if (tb[IFLA_BOND_DOWNDELAY])
415 print_uint(PRINT_ANY,
416 "downdelay",
417 "downdelay %u ",
418 rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
419
420 if (tb[IFLA_BOND_PEER_NOTIF_DELAY])
421 print_uint(PRINT_ANY,
422 "peer_notify_delay",
423 "peer_notify_delay %u ",
424 rta_getattr_u32(tb[IFLA_BOND_PEER_NOTIF_DELAY]));
425
426 if (tb[IFLA_BOND_USE_CARRIER])
427 print_uint(PRINT_ANY,
428 "use_carrier",
429 "use_carrier %u ",
430 rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
431
432 if (tb[IFLA_BOND_ARP_INTERVAL])
433 print_uint(PRINT_ANY,
434 "arp_interval",
435 "arp_interval %u ",
436 rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
437
438 if (tb[IFLA_BOND_ARP_IP_TARGET]) {
439 struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1];
440 int i;
441
442 parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
443 tb[IFLA_BOND_ARP_IP_TARGET]);
444
445 if (iptb[0]) {
446 open_json_array(PRINT_JSON, "arp_ip_target");
447 print_string(PRINT_FP, NULL, "arp_ip_target ", NULL);
448 }
449
450 for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
451 if (iptb[i])
452 print_string(PRINT_ANY,
453 NULL,
454 "%s",
455 rt_addr_n2a_rta(AF_INET, iptb[i]));
456 if (!is_json_context()
457 && i < BOND_MAX_ARP_TARGETS-1
458 && iptb[i+1])
459 fprintf(f, ",");
460 }
461
462 if (iptb[0]) {
463 print_string(PRINT_FP, NULL, " ", NULL);
464 close_json_array(PRINT_JSON, NULL);
465 }
466 }
467
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);
471
472 if (!arp_v && is_json_context())
473 print_null(PRINT_JSON, "arp_validate", NULL, NULL);
474 else
475 print_string(PRINT_ANY,
476 "arp_validate",
477 "arp_validate %s ",
478 arp_validate);
479 }
480
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,
485 "arp_all_targets",
486 "arp_all_targets %s ",
487 arp_all_targets);
488 }
489
490 if (tb[IFLA_BOND_PRIMARY]) {
491 unsigned int ifindex = rta_getattr_u32(tb[IFLA_BOND_PRIMARY]);
492
493 if (ifindex) {
494 print_string(PRINT_ANY,
495 "primary",
496 "primary %s ",
497 ll_index_to_name(ifindex));
498 }
499 }
500
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,
505 "primary_reselect",
506 "primary_reselect %s ",
507 primary_reselect);
508 }
509
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,
514 "fail_over_mac",
515 "fail_over_mac %s ",
516 fail_over_mac);
517 }
518
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,
523 "xmit_hash_policy",
524 "xmit_hash_policy %s ",
525 xmit_hash_policy);
526 }
527
528 if (tb[IFLA_BOND_RESEND_IGMP])
529 print_uint(PRINT_ANY,
530 "resend_igmp",
531 "resend_igmp %u ",
532 rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
533
534 if (tb[IFLA_BOND_NUM_PEER_NOTIF])
535 print_uint(PRINT_ANY,
536 "num_peer_notif",
537 "num_grat_arp %u ",
538 rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
539
540 if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
541 print_uint(PRINT_ANY,
542 "all_slaves_active",
543 "all_slaves_active %u ",
544 rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
545
546 if (tb[IFLA_BOND_MIN_LINKS])
547 print_uint(PRINT_ANY,
548 "min_links",
549 "min_links %u ",
550 rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
551
552 if (tb[IFLA_BOND_LP_INTERVAL])
553 print_uint(PRINT_ANY,
554 "lp_interval",
555 "lp_interval %u ",
556 rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
557
558 if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
559 print_uint(PRINT_ANY,
560 "packets_per_slave",
561 "packets_per_slave %u ",
562 rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
563
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,
568 "ad_lacp_rate",
569 "lacp_rate %s ",
570 lacp_rate);
571 }
572
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,
577 "ad_select",
578 "ad_select %s ",
579 ad_select);
580 }
581
582 if (tb[IFLA_BOND_AD_INFO]) {
583 struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1];
584
585 parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX,
586 tb[IFLA_BOND_AD_INFO]);
587
588 open_json_object("ad_info");
589
590 if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR])
591 print_int(PRINT_ANY,
592 "aggregator",
593 "ad_aggregator %d ",
594 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
595
596 if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS])
597 print_int(PRINT_ANY,
598 "num_ports",
599 "ad_num_ports %d ",
600 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
601
602 if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])
603 print_int(PRINT_ANY,
604 "actor_key",
605 "ad_actor_key %d ",
606 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
607
608 if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])
609 print_int(PRINT_ANY,
610 "partner_key",
611 "ad_partner_key %d ",
612 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
613
614 if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) {
615 unsigned char *p =
616 RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]);
617 SPRINT_BUF(b);
618 print_string(PRINT_ANY,
619 "partner_mac",
620 "ad_partner_mac %s ",
621 ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
622 }
623
624 close_json_object();
625 }
626
627 if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
628 print_uint(PRINT_ANY,
629 "ad_actor_sys_prio",
630 "ad_actor_sys_prio %u ",
631 rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
632 }
633
634 if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
635 print_uint(PRINT_ANY,
636 "ad_user_port_key",
637 "ad_user_port_key %u ",
638 rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
639 }
640
641 if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
642 /* We assume the l2 address is an Ethernet MAC address */
643 SPRINT_BUF(b1);
644
645 print_string(PRINT_ANY,
646 "ad_actor_system",
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)));
651 }
652
653 if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) {
654 print_uint(PRINT_ANY,
655 "tlb_dynamic_lb",
656 "tlb_dynamic_lb %u ",
657 rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
658 }
659 }
660
661 static void bond_print_help(struct link_util *lu, int argc, char **argv,
662 FILE *f)
663 {
664 print_explain(f);
665 }
666
667 static void bond_print_xstats_help(struct link_util *lu, FILE *f)
668 {
669 fprintf(f, "Usage: ... %s [ 802.3ad ] [ dev DEVICE ]\n", lu->id);
670 }
671
672 static void bond_print_3ad_stats(struct rtattr *lacpattr)
673 {
674 struct rtattr *lacptb[BOND_3AD_STAT_MAX+1];
675 __u64 val;
676
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]));
684 }
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]));
689 }
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]);
693 print_u64(PRINT_ANY,
694 "lacpdu_unknown_rx",
695 "LACPDU Unknown type Rx %llu\n",
696 val);
697 }
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]);
701 print_u64(PRINT_ANY,
702 "lacpdu_illegal_rx",
703 "LACPDU Illegal Rx %llu\n",
704 val);
705 }
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]));
710 }
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]));
715 }
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]);
719 print_u64(PRINT_ANY,
720 "marker_response_rx",
721 "Marker response Rx %llu\n",
722 val);
723 }
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]);
727 print_u64(PRINT_ANY,
728 "marker_response_tx",
729 "Marker response Tx %llu\n",
730 val);
731 }
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]);
735 print_u64(PRINT_ANY,
736 "marker_unknown_rx",
737 "Marker unknown type Rx %llu\n",
738 val);
739 }
740 close_json_object();
741 }
742
743 static void bond_print_stats_attr(struct rtattr *attr, int ifindex)
744 {
745 struct rtattr *bondtb[LINK_XSTATS_TYPE_MAX+1];
746 struct rtattr *i, *list;
747 const char *ifname = "";
748 int rem;
749
750 parse_rtattr(bondtb, LINK_XSTATS_TYPE_MAX+1, RTA_DATA(attr),
751 RTA_PAYLOAD(attr));
752 if (!bondtb[LINK_XSTATS_TYPE_BOND])
753 return;
754
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)
762 continue;
763
764 switch (i->rta_type) {
765 case BOND_XSTATS_3AD:
766 bond_print_3ad_stats(i);
767 break;
768 }
769 break;
770 }
771 close_json_object();
772 }
773
774 int bond_print_xstats(struct nlmsghdr *n, void *arg)
775 {
776 struct if_stats_msg *ifsm = NLMSG_DATA(n);
777 struct rtattr *tb[IFLA_STATS_MAX+1];
778 int len = n->nlmsg_len;
779
780 len -= NLMSG_LENGTH(sizeof(*ifsm));
781 if (len < 0) {
782 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
783 return -1;
784 }
785 if (filter_index && filter_index != ifsm->ifindex)
786 return 0;
787
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],
791 ifsm->ifindex);
792
793 if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
794 bond_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
795 ifsm->ifindex);
796
797 return 0;
798 }
799
800 int bond_parse_xstats(struct link_util *lu, int argc, char **argv)
801 {
802 while (argc > 0) {
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) {
807 NEXT_ARG();
808 filter_index = ll_name_to_index(*argv);
809 if (!filter_index)
810 return nodev(*argv);
811 } else if (strcmp(*argv, "help") == 0) {
812 bond_print_xstats_help(lu, stdout);
813 exit(0);
814 } else {
815 invarg("unknown attribute", *argv);
816 }
817 argc--; argv++;
818 }
819
820 return 0;
821 }
822
823
824 struct link_util bond_link_util = {
825 .id = "bond",
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,
832 };