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