1 /*
2 * iplink_bridge.c Bridge 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 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <netinet/in.h>
16 #include <netinet/ether.h>
17 #include <linux/if_link.h>
18 #include <linux/if_bridge.h>
19 #include <net/if.h>
20
21 #include "rt_names.h"
22 #include "utils.h"
23 #include "ip_common.h"
24
25 static unsigned int xstats_print_attr;
26 static int filter_index;
27
print_explain(FILE * f)28 static void print_explain(FILE *f)
29 {
30 fprintf(f,
31 "Usage: ... bridge [ fdb_flush ]\n"
32 " [ forward_delay FORWARD_DELAY ]\n"
33 " [ hello_time HELLO_TIME ]\n"
34 " [ max_age MAX_AGE ]\n"
35 " [ ageing_time AGEING_TIME ]\n"
36 " [ stp_state STP_STATE ]\n"
37 " [ priority PRIORITY ]\n"
38 " [ group_fwd_mask MASK ]\n"
39 " [ group_address ADDRESS ]\n"
40 " [ vlan_filtering VLAN_FILTERING ]\n"
41 " [ vlan_protocol VLAN_PROTOCOL ]\n"
42 " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n"
43 " [ vlan_stats_enabled VLAN_STATS_ENABLED ]\n"
44 " [ mcast_snooping MULTICAST_SNOOPING ]\n"
45 " [ mcast_router MULTICAST_ROUTER ]\n"
46 " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
47 " [ mcast_querier MULTICAST_QUERIER ]\n"
48 " [ mcast_hash_elasticity HASH_ELASTICITY ]\n"
49 " [ mcast_hash_max HASH_MAX ]\n"
50 " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
51 " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
52 " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
53 " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
54 " [ mcast_querier_interval QUERIER_INTERVAL ]\n"
55 " [ mcast_query_interval QUERY_INTERVAL ]\n"
56 " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
57 " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
58 " [ mcast_stats_enabled MCAST_STATS_ENABLED ]\n"
59 " [ mcast_igmp_version IGMP_VERSION ]\n"
60 " [ mcast_mld_version MLD_VERSION ]\n"
61 " [ nf_call_iptables NF_CALL_IPTABLES ]\n"
62 " [ nf_call_ip6tables NF_CALL_IP6TABLES ]\n"
63 " [ nf_call_arptables NF_CALL_ARPTABLES ]\n"
64 "\n"
65 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
66 );
67 }
68
explain(void)69 static void explain(void)
70 {
71 print_explain(stderr);
72 }
73
br_dump_bridge_id(const struct ifla_bridge_id * id,char * buf,size_t len)74 void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len)
75 {
76 char eaddr[32];
77
78 ether_ntoa_r((const struct ether_addr *)id->addr, eaddr);
79 snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr);
80 }
81
bridge_parse_opt(struct link_util * lu,int argc,char ** argv,struct nlmsghdr * n)82 static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
83 struct nlmsghdr *n)
84 {
85 __u32 val;
86
87 while (argc > 0) {
88 if (matches(*argv, "forward_delay") == 0) {
89 NEXT_ARG();
90 if (get_u32(&val, *argv, 0))
91 invarg("invalid forward_delay", *argv);
92
93 addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
94 } else if (matches(*argv, "hello_time") == 0) {
95 NEXT_ARG();
96 if (get_u32(&val, *argv, 0))
97 invarg("invalid hello_time", *argv);
98
99 addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
100 } else if (matches(*argv, "max_age") == 0) {
101 NEXT_ARG();
102 if (get_u32(&val, *argv, 0))
103 invarg("invalid max_age", *argv);
104
105 addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
106 } else if (matches(*argv, "ageing_time") == 0) {
107 NEXT_ARG();
108 if (get_u32(&val, *argv, 0))
109 invarg("invalid ageing_time", *argv);
110
111 addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
112 } else if (matches(*argv, "stp_state") == 0) {
113 NEXT_ARG();
114 if (get_u32(&val, *argv, 0))
115 invarg("invalid stp_state", *argv);
116
117 addattr32(n, 1024, IFLA_BR_STP_STATE, val);
118 } else if (matches(*argv, "priority") == 0) {
119 __u16 prio;
120
121 NEXT_ARG();
122 if (get_u16(&prio, *argv, 0))
123 invarg("invalid priority", *argv);
124
125 addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
126 } else if (matches(*argv, "vlan_filtering") == 0) {
127 __u8 vlan_filter;
128
129 NEXT_ARG();
130 if (get_u8(&vlan_filter, *argv, 0))
131 invarg("invalid vlan_filtering", *argv);
132
133 addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
134 } else if (matches(*argv, "vlan_protocol") == 0) {
135 __u16 vlan_proto;
136
137 NEXT_ARG();
138 if (ll_proto_a2n(&vlan_proto, *argv))
139 invarg("invalid vlan_protocol", *argv);
140
141 addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
142 } else if (matches(*argv, "group_fwd_mask") == 0) {
143 __u16 fwd_mask;
144
145 NEXT_ARG();
146 if (get_u16(&fwd_mask, *argv, 0))
147 invarg("invalid group_fwd_mask", *argv);
148
149 addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
150 } else if (matches(*argv, "group_address") == 0) {
151 char llabuf[32];
152 int len;
153
154 NEXT_ARG();
155 len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv);
156 if (len < 0)
157 return -1;
158 addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len);
159 } else if (matches(*argv, "fdb_flush") == 0) {
160 addattr(n, 1024, IFLA_BR_FDB_FLUSH);
161 } else if (matches(*argv, "vlan_default_pvid") == 0) {
162 __u16 default_pvid;
163
164 NEXT_ARG();
165 if (get_u16(&default_pvid, *argv, 0))
166 invarg("invalid vlan_default_pvid", *argv);
167
168 addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID,
169 default_pvid);
170 } else if (matches(*argv, "vlan_stats_enabled") == 0) {
171 __u8 vlan_stats_enabled;
172
173 NEXT_ARG();
174 if (get_u8(&vlan_stats_enabled, *argv, 0))
175 invarg("invalid vlan_stats_enabled", *argv);
176 addattr8(n, 1024, IFLA_BR_VLAN_STATS_ENABLED,
177 vlan_stats_enabled);
178 } else if (matches(*argv, "mcast_router") == 0) {
179 __u8 mcast_router;
180
181 NEXT_ARG();
182 if (get_u8(&mcast_router, *argv, 0))
183 invarg("invalid mcast_router", *argv);
184
185 addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router);
186 } else if (matches(*argv, "mcast_snooping") == 0) {
187 __u8 mcast_snoop;
188
189 NEXT_ARG();
190 if (get_u8(&mcast_snoop, *argv, 0))
191 invarg("invalid mcast_snooping", *argv);
192
193 addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop);
194 } else if (matches(*argv, "mcast_query_use_ifaddr") == 0) {
195 __u8 mcast_qui;
196
197 NEXT_ARG();
198 if (get_u8(&mcast_qui, *argv, 0))
199 invarg("invalid mcast_query_use_ifaddr",
200 *argv);
201
202 addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR,
203 mcast_qui);
204 } else if (matches(*argv, "mcast_querier") == 0) {
205 __u8 mcast_querier;
206
207 NEXT_ARG();
208 if (get_u8(&mcast_querier, *argv, 0))
209 invarg("invalid mcast_querier", *argv);
210
211 addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier);
212 } else if (matches(*argv, "mcast_hash_elasticity") == 0) {
213 __u32 mcast_hash_el;
214
215 NEXT_ARG();
216 if (get_u32(&mcast_hash_el, *argv, 0))
217 invarg("invalid mcast_hash_elasticity",
218 *argv);
219
220 addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY,
221 mcast_hash_el);
222 } else if (matches(*argv, "mcast_hash_max") == 0) {
223 __u32 mcast_hash_max;
224
225 NEXT_ARG();
226 if (get_u32(&mcast_hash_max, *argv, 0))
227 invarg("invalid mcast_hash_max", *argv);
228
229 addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX,
230 mcast_hash_max);
231 } else if (matches(*argv, "mcast_last_member_count") == 0) {
232 __u32 mcast_lmc;
233
234 NEXT_ARG();
235 if (get_u32(&mcast_lmc, *argv, 0))
236 invarg("invalid mcast_last_member_count",
237 *argv);
238
239 addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT,
240 mcast_lmc);
241 } else if (matches(*argv, "mcast_startup_query_count") == 0) {
242 __u32 mcast_sqc;
243
244 NEXT_ARG();
245 if (get_u32(&mcast_sqc, *argv, 0))
246 invarg("invalid mcast_startup_query_count",
247 *argv);
248
249 addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT,
250 mcast_sqc);
251 } else if (matches(*argv, "mcast_last_member_interval") == 0) {
252 __u64 mcast_last_member_intvl;
253
254 NEXT_ARG();
255 if (get_u64(&mcast_last_member_intvl, *argv, 0))
256 invarg("invalid mcast_last_member_interval",
257 *argv);
258
259 addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL,
260 mcast_last_member_intvl);
261 } else if (matches(*argv, "mcast_membership_interval") == 0) {
262 __u64 mcast_membership_intvl;
263
264 NEXT_ARG();
265 if (get_u64(&mcast_membership_intvl, *argv, 0))
266 invarg("invalid mcast_membership_interval",
267 *argv);
268
269 addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL,
270 mcast_membership_intvl);
271 } else if (matches(*argv, "mcast_querier_interval") == 0) {
272 __u64 mcast_querier_intvl;
273
274 NEXT_ARG();
275 if (get_u64(&mcast_querier_intvl, *argv, 0))
276 invarg("invalid mcast_querier_interval",
277 *argv);
278
279 addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL,
280 mcast_querier_intvl);
281 } else if (matches(*argv, "mcast_query_interval") == 0) {
282 __u64 mcast_query_intvl;
283
284 NEXT_ARG();
285 if (get_u64(&mcast_query_intvl, *argv, 0))
286 invarg("invalid mcast_query_interval",
287 *argv);
288
289 addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL,
290 mcast_query_intvl);
291 } else if (!matches(*argv, "mcast_query_response_interval")) {
292 __u64 mcast_query_resp_intvl;
293
294 NEXT_ARG();
295 if (get_u64(&mcast_query_resp_intvl, *argv, 0))
296 invarg("invalid mcast_query_response_interval",
297 *argv);
298
299 addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
300 mcast_query_resp_intvl);
301 } else if (!matches(*argv, "mcast_startup_query_interval")) {
302 __u64 mcast_startup_query_intvl;
303
304 NEXT_ARG();
305 if (get_u64(&mcast_startup_query_intvl, *argv, 0))
306 invarg("invalid mcast_startup_query_interval",
307 *argv);
308
309 addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
310 mcast_startup_query_intvl);
311 } else if (matches(*argv, "mcast_stats_enabled") == 0) {
312 __u8 mcast_stats_enabled;
313
314 NEXT_ARG();
315 if (get_u8(&mcast_stats_enabled, *argv, 0))
316 invarg("invalid mcast_stats_enabled", *argv);
317 addattr8(n, 1024, IFLA_BR_MCAST_STATS_ENABLED,
318 mcast_stats_enabled);
319 } else if (matches(*argv, "mcast_igmp_version") == 0) {
320 __u8 igmp_version;
321
322 NEXT_ARG();
323 if (get_u8(&igmp_version, *argv, 0))
324 invarg("invalid mcast_igmp_version", *argv);
325 addattr8(n, 1024, IFLA_BR_MCAST_IGMP_VERSION,
326 igmp_version);
327 } else if (matches(*argv, "mcast_mld_version") == 0) {
328 __u8 mld_version;
329
330 NEXT_ARG();
331 if (get_u8(&mld_version, *argv, 0))
332 invarg("invalid mcast_mld_version", *argv);
333 addattr8(n, 1024, IFLA_BR_MCAST_MLD_VERSION,
334 mld_version);
335 } else if (matches(*argv, "nf_call_iptables") == 0) {
336 __u8 nf_call_ipt;
337
338 NEXT_ARG();
339 if (get_u8(&nf_call_ipt, *argv, 0))
340 invarg("invalid nf_call_iptables", *argv);
341
342 addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES,
343 nf_call_ipt);
344 } else if (matches(*argv, "nf_call_ip6tables") == 0) {
345 __u8 nf_call_ip6t;
346
347 NEXT_ARG();
348 if (get_u8(&nf_call_ip6t, *argv, 0))
349 invarg("invalid nf_call_ip6tables", *argv);
350
351 addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES,
352 nf_call_ip6t);
353 } else if (matches(*argv, "nf_call_arptables") == 0) {
354 __u8 nf_call_arpt;
355
356 NEXT_ARG();
357 if (get_u8(&nf_call_arpt, *argv, 0))
358 invarg("invalid nf_call_arptables", *argv);
359
360 addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES,
361 nf_call_arpt);
362 } else if (matches(*argv, "help") == 0) {
363 explain();
364 return -1;
365 } else {
366 fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
367 explain();
368 return -1;
369 }
370 argc--, argv++;
371 }
372
373 return 0;
374 }
375
_bridge_print_timer(FILE * f,const char * attr,struct rtattr * timer)376 static void _bridge_print_timer(FILE *f,
377 const char *attr,
378 struct rtattr *timer)
379 {
380 struct timeval tv;
381
382 __jiffies_to_tv(&tv, rta_getattr_u64(timer));
383 if (is_json_context()) {
384 json_writer_t *jw = get_json_writer();
385
386 jsonw_name(jw, attr);
387 jsonw_printf(jw, "%i.%.2i",
388 (int)tv.tv_sec,
389 (int)tv.tv_usec / 10000);
390 } else {
391 fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
392 (int)tv.tv_usec / 10000);
393 }
394 }
395
bridge_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])396 static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
397 {
398 if (!tb)
399 return;
400
401 if (tb[IFLA_BR_FORWARD_DELAY])
402 print_uint(PRINT_ANY,
403 "forward_delay",
404 "forward_delay %u ",
405 rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
406
407 if (tb[IFLA_BR_HELLO_TIME])
408 print_uint(PRINT_ANY,
409 "hello_time",
410 "hello_time %u ",
411 rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
412
413 if (tb[IFLA_BR_MAX_AGE])
414 print_uint(PRINT_ANY,
415 "max_age",
416 "max_age %u ",
417 rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
418
419 if (tb[IFLA_BR_AGEING_TIME])
420 print_uint(PRINT_ANY,
421 "ageing_time",
422 "ageing_time %u ",
423 rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
424
425 if (tb[IFLA_BR_STP_STATE])
426 print_uint(PRINT_ANY,
427 "stp_state",
428 "stp_state %u ",
429 rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
430
431 if (tb[IFLA_BR_PRIORITY])
432 print_uint(PRINT_ANY,
433 "priority",
434 "priority %u ",
435 rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
436
437 if (tb[IFLA_BR_VLAN_FILTERING])
438 print_uint(PRINT_ANY,
439 "vlan_filtering",
440 "vlan_filtering %u ",
441 rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
442
443 if (tb[IFLA_BR_VLAN_PROTOCOL]) {
444 SPRINT_BUF(b1);
445
446 print_string(PRINT_ANY,
447 "vlan_protocol",
448 "vlan_protocol %s ",
449 ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
450 b1, sizeof(b1)));
451 }
452
453 if (tb[IFLA_BR_BRIDGE_ID]) {
454 char bridge_id[32];
455
456 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
457 sizeof(bridge_id));
458 print_string(PRINT_ANY,
459 "bridge_id",
460 "bridge_id %s ",
461 bridge_id);
462 }
463
464 if (tb[IFLA_BR_ROOT_ID]) {
465 char root_id[32];
466
467 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
468 sizeof(root_id));
469 print_string(PRINT_ANY,
470 "root_id",
471 "designated_root %s ",
472 root_id);
473 }
474
475 if (tb[IFLA_BR_ROOT_PORT])
476 print_uint(PRINT_ANY,
477 "root_port",
478 "root_port %u ",
479 rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
480
481 if (tb[IFLA_BR_ROOT_PATH_COST])
482 print_uint(PRINT_ANY,
483 "root_path_cost",
484 "root_path_cost %u ",
485 rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
486
487 if (tb[IFLA_BR_TOPOLOGY_CHANGE])
488 print_uint(PRINT_ANY,
489 "topology_change",
490 "topology_change %u ",
491 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
492
493 if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
494 print_uint(PRINT_ANY,
495 "topology_change_detected",
496 "topology_change_detected %u ",
497 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
498
499 if (tb[IFLA_BR_HELLO_TIMER])
500 _bridge_print_timer(f, "hello_timer", tb[IFLA_BR_HELLO_TIMER]);
501
502 if (tb[IFLA_BR_TCN_TIMER])
503 _bridge_print_timer(f, "tcn_timer", tb[IFLA_BR_TCN_TIMER]);
504
505 if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER])
506 _bridge_print_timer(f, "topology_change_timer",
507 tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
508
509 if (tb[IFLA_BR_GC_TIMER])
510 _bridge_print_timer(f, "gc_timer", tb[IFLA_BR_GC_TIMER]);
511
512 if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
513 print_uint(PRINT_ANY,
514 "vlan_default_pvid",
515 "vlan_default_pvid %u ",
516 rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
517
518 if (tb[IFLA_BR_VLAN_STATS_ENABLED])
519 print_uint(PRINT_ANY,
520 "vlan_stats_enabled",
521 "vlan_stats_enabled %u ",
522 rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
523
524 if (tb[IFLA_BR_GROUP_FWD_MASK])
525 print_0xhex(PRINT_ANY,
526 "group_fwd_mask",
527 "group_fwd_mask %#x ",
528 rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
529
530 if (tb[IFLA_BR_GROUP_ADDR]) {
531 SPRINT_BUF(mac);
532
533 print_string(PRINT_ANY,
534 "group_addr",
535 "group_address %s ",
536 ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
537 RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
538 1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
539 }
540
541 if (tb[IFLA_BR_MCAST_SNOOPING])
542 print_uint(PRINT_ANY,
543 "mcast_snooping",
544 "mcast_snooping %u ",
545 rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
546
547 if (tb[IFLA_BR_MCAST_ROUTER])
548 print_uint(PRINT_ANY,
549 "mcast_router",
550 "mcast_router %u ",
551 rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
552
553 if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
554 print_uint(PRINT_ANY,
555 "mcast_query_use_ifaddr",
556 "mcast_query_use_ifaddr %u ",
557 rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
558
559 if (tb[IFLA_BR_MCAST_QUERIER])
560 print_uint(PRINT_ANY,
561 "mcast_querier",
562 "mcast_querier %u ",
563 rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
564
565 if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
566 print_uint(PRINT_ANY,
567 "mcast_hash_elasticity",
568 "mcast_hash_elasticity %u ",
569 rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
570
571 if (tb[IFLA_BR_MCAST_HASH_MAX])
572 print_uint(PRINT_ANY,
573 "mcast_hash_max",
574 "mcast_hash_max %u ",
575 rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
576
577 if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
578 print_uint(PRINT_ANY,
579 "mcast_last_member_cnt",
580 "mcast_last_member_count %u ",
581 rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
582
583 if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])
584 print_uint(PRINT_ANY,
585 "mcast_startup_query_cnt",
586 "mcast_startup_query_count %u ",
587 rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
588
589 if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])
590 print_lluint(PRINT_ANY,
591 "mcast_last_member_intvl",
592 "mcast_last_member_interval %llu ",
593 rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
594
595 if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])
596 print_lluint(PRINT_ANY,
597 "mcast_membership_intvl",
598 "mcast_membership_interval %llu ",
599 rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
600
601 if (tb[IFLA_BR_MCAST_QUERIER_INTVL])
602 print_lluint(PRINT_ANY,
603 "mcast_querier_intvl",
604 "mcast_querier_interval %llu ",
605 rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
606
607 if (tb[IFLA_BR_MCAST_QUERY_INTVL])
608 print_lluint(PRINT_ANY,
609 "mcast_query_intvl",
610 "mcast_query_interval %llu ",
611 rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
612
613 if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])
614 print_lluint(PRINT_ANY,
615 "mcast_query_response_intvl",
616 "mcast_query_response_interval %llu ",
617 rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
618
619 if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])
620 print_lluint(PRINT_ANY,
621 "mcast_startup_query_intvl",
622 "mcast_startup_query_interval %llu ",
623 rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
624
625 if (tb[IFLA_BR_MCAST_STATS_ENABLED])
626 print_uint(PRINT_ANY,
627 "mcast_stats_enabled",
628 "mcast_stats_enabled %u ",
629 rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
630
631 if (tb[IFLA_BR_MCAST_IGMP_VERSION])
632 print_uint(PRINT_ANY,
633 "mcast_igmp_version",
634 "mcast_igmp_version %u ",
635 rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
636
637 if (tb[IFLA_BR_MCAST_MLD_VERSION])
638 print_uint(PRINT_ANY,
639 "mcast_mld_version",
640 "mcast_mld_version %u ",
641 rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
642
643 if (tb[IFLA_BR_NF_CALL_IPTABLES])
644 print_uint(PRINT_ANY,
645 "nf_call_iptables",
646 "nf_call_iptables %u ",
647 rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
648
649 if (tb[IFLA_BR_NF_CALL_IP6TABLES])
650 print_uint(PRINT_ANY,
651 "nf_call_ip6tables",
652 "nf_call_ip6tables %u ",
653 rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
654
655 if (tb[IFLA_BR_NF_CALL_ARPTABLES])
656 print_uint(PRINT_ANY,
657 "nf_call_arptables",
658 "nf_call_arptables %u ",
659 rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
660 }
661
bridge_print_help(struct link_util * lu,int argc,char ** argv,FILE * f)662 static void bridge_print_help(struct link_util *lu, int argc, char **argv,
663 FILE *f)
664 {
665 print_explain(f);
666 }
667
bridge_print_xstats_help(struct link_util * lu,FILE * f)668 static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
669 {
670 fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
671 }
672
bridge_print_stats_attr(FILE * f,struct rtattr * attr,int ifindex)673 static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex)
674 {
675 struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
676 struct br_mcast_stats *mstats;
677 struct rtattr *i, *list;
678 const char *ifname = "";
679 int rem;
680
681 parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
682 RTA_PAYLOAD(attr));
683 if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
684 return;
685
686 list = brtb[LINK_XSTATS_TYPE_BRIDGE];
687 rem = RTA_PAYLOAD(list);
688 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
689 if (xstats_print_attr && i->rta_type != xstats_print_attr)
690 continue;
691 switch (i->rta_type) {
692 case BRIDGE_XSTATS_MCAST:
693 mstats = RTA_DATA(i);
694 ifname = ll_index_to_name(ifindex);
695 fprintf(f, "%-16s\n", ifname);
696 fprintf(f, "%-16s IGMP queries:\n", "");
697 fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n",
698 "",
699 mstats->igmp_v1queries[BR_MCAST_DIR_RX],
700 mstats->igmp_v2queries[BR_MCAST_DIR_RX],
701 mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
702 fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n",
703 "",
704 mstats->igmp_v1queries[BR_MCAST_DIR_TX],
705 mstats->igmp_v2queries[BR_MCAST_DIR_TX],
706 mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
707
708 fprintf(f, "%-16s IGMP reports:\n", "");
709 fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n",
710 "",
711 mstats->igmp_v1reports[BR_MCAST_DIR_RX],
712 mstats->igmp_v2reports[BR_MCAST_DIR_RX],
713 mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
714 fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n",
715 "",
716 mstats->igmp_v1reports[BR_MCAST_DIR_TX],
717 mstats->igmp_v2reports[BR_MCAST_DIR_TX],
718 mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
719
720 fprintf(f, "%-16s IGMP leaves: RX: %llu TX: %llu\n",
721 "",
722 mstats->igmp_leaves[BR_MCAST_DIR_RX],
723 mstats->igmp_leaves[BR_MCAST_DIR_TX]);
724
725 fprintf(f, "%-16s IGMP parse errors: %llu\n",
726 "", mstats->igmp_parse_errors);
727
728 fprintf(f, "%-16s MLD queries:\n", "");
729 fprintf(f, "%-16s RX: v1 %llu v2 %llu\n",
730 "",
731 mstats->mld_v1queries[BR_MCAST_DIR_RX],
732 mstats->mld_v2queries[BR_MCAST_DIR_RX]);
733 fprintf(f, "%-16s TX: v1 %llu v2 %llu\n",
734 "",
735 mstats->mld_v1queries[BR_MCAST_DIR_TX],
736 mstats->mld_v2queries[BR_MCAST_DIR_TX]);
737
738 fprintf(f, "%-16s MLD reports:\n", "");
739 fprintf(f, "%-16s RX: v1 %llu v2 %llu\n",
740 "",
741 mstats->mld_v1reports[BR_MCAST_DIR_RX],
742 mstats->mld_v2reports[BR_MCAST_DIR_RX]);
743 fprintf(f, "%-16s TX: v1 %llu v2 %llu\n",
744 "",
745 mstats->mld_v1reports[BR_MCAST_DIR_TX],
746 mstats->mld_v2reports[BR_MCAST_DIR_TX]);
747
748 fprintf(f, "%-16s MLD leaves: RX: %llu TX: %llu\n",
749 "",
750 mstats->mld_leaves[BR_MCAST_DIR_RX],
751 mstats->mld_leaves[BR_MCAST_DIR_TX]);
752
753 fprintf(f, "%-16s MLD parse errors: %llu\n",
754 "", mstats->mld_parse_errors);
755 break;
756 }
757 }
758 }
759
bridge_print_xstats(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)760 int bridge_print_xstats(const struct sockaddr_nl *who,
761 struct nlmsghdr *n, void *arg)
762 {
763 struct if_stats_msg *ifsm = NLMSG_DATA(n);
764 struct rtattr *tb[IFLA_STATS_MAX+1];
765 int len = n->nlmsg_len;
766 FILE *fp = arg;
767
768 len -= NLMSG_LENGTH(sizeof(*ifsm));
769 if (len < 0) {
770 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
771 return -1;
772 }
773 if (filter_index && filter_index != ifsm->ifindex)
774 return 0;
775
776 parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
777 if (tb[IFLA_STATS_LINK_XSTATS])
778 bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
779 ifsm->ifindex);
780
781 if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
782 bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
783 ifsm->ifindex);
784
785 return 0;
786 }
787
bridge_parse_xstats(struct link_util * lu,int argc,char ** argv)788 int bridge_parse_xstats(struct link_util *lu, int argc, char **argv)
789 {
790 while (argc > 0) {
791 if (strcmp(*argv, "igmp") == 0 || strcmp(*argv, "mcast") == 0) {
792 xstats_print_attr = BRIDGE_XSTATS_MCAST;
793 } else if (strcmp(*argv, "dev") == 0) {
794 NEXT_ARG();
795 filter_index = if_nametoindex(*argv);
796 if (filter_index == 0) {
797 fprintf(stderr, "Cannot find device \"%s\"\n",
798 *argv);
799 return -1;
800 }
801 } else if (strcmp(*argv, "help") == 0) {
802 bridge_print_xstats_help(lu, stdout);
803 exit(0);
804 } else {
805 invarg("unknown attribute", *argv);
806 }
807 argc--; argv++;
808 }
809
810 return 0;
811 }
812
813 struct link_util bridge_link_util = {
814 .id = "bridge",
815 .maxattr = IFLA_BR_MAX,
816 .parse_opt = bridge_parse_opt,
817 .print_opt = bridge_print_opt,
818 .print_help = bridge_print_help,
819 .parse_ifla_xstats = bridge_parse_xstats,
820 .print_ifla_xstats = bridge_print_xstats,
821 };
822