]>
Commit | Line | Data |
---|---|---|
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 |
25 | static unsigned int xstats_print_attr; |
26 | static int filter_index; | |
27 | ||
63d127b0 | 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 | NULL, | |
74 | }; | |
75 | ||
76 | static const char *lacp_rate_tbl[] = { | |
77 | "slow", | |
78 | "fast", | |
79 | NULL, | |
80 | }; | |
81 | ||
82 | static const char *ad_select_tbl[] = { | |
83 | "stable", | |
84 | "bandwidth", | |
85 | "count", | |
86 | NULL, | |
87 | }; | |
88 | ||
89 | static 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 | ||
100 | static 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 | 117 | static 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 | 157 | static void explain(void) |
158 | { | |
159 | print_explain(stderr); | |
160 | } | |
161 | ||
cc26a890 JP |
162 | static 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 | ||
378 | static 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 | 660 | static 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 |
666 | static 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 | ||
671 | static 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 | ||
742 | static 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 | ||
773 | int 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 | ||
799 | int 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 |
823 | struct 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 | }; |