2 * iplink_bridge.c Bridge device support
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.
9 * Authors: Jiri Pirko <jiri@resnulli.us>
15 #include <netinet/in.h>
16 #include <netinet/ether.h>
17 #include <linux/if_link.h>
18 #include <linux/if_bridge.h>
23 #include "ip_common.h"
25 static unsigned int xstats_print_attr
;
26 static int filter_index
;
28 static void print_explain(FILE *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 " [ vlan_stats_per_port VLAN_STATS_PER_PORT ]\n"
45 " [ mcast_snooping MULTICAST_SNOOPING ]\n"
46 " [ mcast_router MULTICAST_ROUTER ]\n"
47 " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
48 " [ mcast_querier MULTICAST_QUERIER ]\n"
49 " [ mcast_hash_elasticity HASH_ELASTICITY ]\n"
50 " [ mcast_hash_max HASH_MAX ]\n"
51 " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
52 " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
53 " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
54 " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
55 " [ mcast_querier_interval QUERIER_INTERVAL ]\n"
56 " [ mcast_query_interval QUERY_INTERVAL ]\n"
57 " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
58 " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
59 " [ mcast_stats_enabled MCAST_STATS_ENABLED ]\n"
60 " [ mcast_igmp_version IGMP_VERSION ]\n"
61 " [ mcast_mld_version MLD_VERSION ]\n"
62 " [ nf_call_iptables NF_CALL_IPTABLES ]\n"
63 " [ nf_call_ip6tables NF_CALL_IP6TABLES ]\n"
64 " [ nf_call_arptables NF_CALL_ARPTABLES ]\n"
66 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
70 static void explain(void)
72 print_explain(stderr
);
75 void br_dump_bridge_id(const struct ifla_bridge_id
*id
, char *buf
, size_t len
)
79 ether_ntoa_r((const struct ether_addr
*)id
->addr
, eaddr
);
80 snprintf(buf
, len
, "%.2x%.2x.%s", id
->prio
[0], id
->prio
[1], eaddr
);
83 static int bridge_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
89 if (matches(*argv
, "forward_delay") == 0) {
91 if (get_u32(&val
, *argv
, 0))
92 invarg("invalid forward_delay", *argv
);
94 addattr32(n
, 1024, IFLA_BR_FORWARD_DELAY
, val
);
95 } else if (matches(*argv
, "hello_time") == 0) {
97 if (get_u32(&val
, *argv
, 0))
98 invarg("invalid hello_time", *argv
);
100 addattr32(n
, 1024, IFLA_BR_HELLO_TIME
, val
);
101 } else if (matches(*argv
, "max_age") == 0) {
103 if (get_u32(&val
, *argv
, 0))
104 invarg("invalid max_age", *argv
);
106 addattr32(n
, 1024, IFLA_BR_MAX_AGE
, val
);
107 } else if (matches(*argv
, "ageing_time") == 0) {
109 if (get_u32(&val
, *argv
, 0))
110 invarg("invalid ageing_time", *argv
);
112 addattr32(n
, 1024, IFLA_BR_AGEING_TIME
, val
);
113 } else if (matches(*argv
, "stp_state") == 0) {
115 if (get_u32(&val
, *argv
, 0))
116 invarg("invalid stp_state", *argv
);
118 addattr32(n
, 1024, IFLA_BR_STP_STATE
, val
);
119 } else if (matches(*argv
, "priority") == 0) {
123 if (get_u16(&prio
, *argv
, 0))
124 invarg("invalid priority", *argv
);
126 addattr16(n
, 1024, IFLA_BR_PRIORITY
, prio
);
127 } else if (matches(*argv
, "vlan_filtering") == 0) {
131 if (get_u8(&vlan_filter
, *argv
, 0))
132 invarg("invalid vlan_filtering", *argv
);
134 addattr8(n
, 1024, IFLA_BR_VLAN_FILTERING
, vlan_filter
);
135 } else if (matches(*argv
, "vlan_protocol") == 0) {
139 if (ll_proto_a2n(&vlan_proto
, *argv
))
140 invarg("invalid vlan_protocol", *argv
);
142 addattr16(n
, 1024, IFLA_BR_VLAN_PROTOCOL
, vlan_proto
);
143 } else if (matches(*argv
, "group_fwd_mask") == 0) {
147 if (get_u16(&fwd_mask
, *argv
, 0))
148 invarg("invalid group_fwd_mask", *argv
);
150 addattr16(n
, 1024, IFLA_BR_GROUP_FWD_MASK
, fwd_mask
);
151 } else if (matches(*argv
, "group_address") == 0) {
156 len
= ll_addr_a2n(llabuf
, sizeof(llabuf
), *argv
);
159 addattr_l(n
, 1024, IFLA_BR_GROUP_ADDR
, llabuf
, len
);
160 } else if (matches(*argv
, "fdb_flush") == 0) {
161 addattr(n
, 1024, IFLA_BR_FDB_FLUSH
);
162 } else if (matches(*argv
, "vlan_default_pvid") == 0) {
166 if (get_u16(&default_pvid
, *argv
, 0))
167 invarg("invalid vlan_default_pvid", *argv
);
169 addattr16(n
, 1024, IFLA_BR_VLAN_DEFAULT_PVID
,
171 } else if (matches(*argv
, "vlan_stats_enabled") == 0) {
172 __u8 vlan_stats_enabled
;
175 if (get_u8(&vlan_stats_enabled
, *argv
, 0))
176 invarg("invalid vlan_stats_enabled", *argv
);
177 addattr8(n
, 1024, IFLA_BR_VLAN_STATS_ENABLED
,
179 } else if (matches(*argv
, "vlan_stats_per_port") == 0) {
180 __u8 vlan_stats_per_port
;
183 if (get_u8(&vlan_stats_per_port
, *argv
, 0))
184 invarg("invalid vlan_stats_per_port", *argv
);
185 addattr8(n
, 1024, IFLA_BR_VLAN_STATS_PER_PORT
,
186 vlan_stats_per_port
);
187 } else if (matches(*argv
, "mcast_router") == 0) {
191 if (get_u8(&mcast_router
, *argv
, 0))
192 invarg("invalid mcast_router", *argv
);
194 addattr8(n
, 1024, IFLA_BR_MCAST_ROUTER
, mcast_router
);
195 } else if (matches(*argv
, "mcast_snooping") == 0) {
199 if (get_u8(&mcast_snoop
, *argv
, 0))
200 invarg("invalid mcast_snooping", *argv
);
202 addattr8(n
, 1024, IFLA_BR_MCAST_SNOOPING
, mcast_snoop
);
203 } else if (matches(*argv
, "mcast_query_use_ifaddr") == 0) {
207 if (get_u8(&mcast_qui
, *argv
, 0))
208 invarg("invalid mcast_query_use_ifaddr",
211 addattr8(n
, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR
,
213 } else if (matches(*argv
, "mcast_querier") == 0) {
217 if (get_u8(&mcast_querier
, *argv
, 0))
218 invarg("invalid mcast_querier", *argv
);
220 addattr8(n
, 1024, IFLA_BR_MCAST_QUERIER
, mcast_querier
);
221 } else if (matches(*argv
, "mcast_hash_elasticity") == 0) {
225 if (get_u32(&mcast_hash_el
, *argv
, 0))
226 invarg("invalid mcast_hash_elasticity",
229 addattr32(n
, 1024, IFLA_BR_MCAST_HASH_ELASTICITY
,
231 } else if (matches(*argv
, "mcast_hash_max") == 0) {
232 __u32 mcast_hash_max
;
235 if (get_u32(&mcast_hash_max
, *argv
, 0))
236 invarg("invalid mcast_hash_max", *argv
);
238 addattr32(n
, 1024, IFLA_BR_MCAST_HASH_MAX
,
240 } else if (matches(*argv
, "mcast_last_member_count") == 0) {
244 if (get_u32(&mcast_lmc
, *argv
, 0))
245 invarg("invalid mcast_last_member_count",
248 addattr32(n
, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT
,
250 } else if (matches(*argv
, "mcast_startup_query_count") == 0) {
254 if (get_u32(&mcast_sqc
, *argv
, 0))
255 invarg("invalid mcast_startup_query_count",
258 addattr32(n
, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT
,
260 } else if (matches(*argv
, "mcast_last_member_interval") == 0) {
261 __u64 mcast_last_member_intvl
;
264 if (get_u64(&mcast_last_member_intvl
, *argv
, 0))
265 invarg("invalid mcast_last_member_interval",
268 addattr64(n
, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL
,
269 mcast_last_member_intvl
);
270 } else if (matches(*argv
, "mcast_membership_interval") == 0) {
271 __u64 mcast_membership_intvl
;
274 if (get_u64(&mcast_membership_intvl
, *argv
, 0))
275 invarg("invalid mcast_membership_interval",
278 addattr64(n
, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL
,
279 mcast_membership_intvl
);
280 } else if (matches(*argv
, "mcast_querier_interval") == 0) {
281 __u64 mcast_querier_intvl
;
284 if (get_u64(&mcast_querier_intvl
, *argv
, 0))
285 invarg("invalid mcast_querier_interval",
288 addattr64(n
, 1024, IFLA_BR_MCAST_QUERIER_INTVL
,
289 mcast_querier_intvl
);
290 } else if (matches(*argv
, "mcast_query_interval") == 0) {
291 __u64 mcast_query_intvl
;
294 if (get_u64(&mcast_query_intvl
, *argv
, 0))
295 invarg("invalid mcast_query_interval",
298 addattr64(n
, 1024, IFLA_BR_MCAST_QUERY_INTVL
,
300 } else if (!matches(*argv
, "mcast_query_response_interval")) {
301 __u64 mcast_query_resp_intvl
;
304 if (get_u64(&mcast_query_resp_intvl
, *argv
, 0))
305 invarg("invalid mcast_query_response_interval",
308 addattr64(n
, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
,
309 mcast_query_resp_intvl
);
310 } else if (!matches(*argv
, "mcast_startup_query_interval")) {
311 __u64 mcast_startup_query_intvl
;
314 if (get_u64(&mcast_startup_query_intvl
, *argv
, 0))
315 invarg("invalid mcast_startup_query_interval",
318 addattr64(n
, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL
,
319 mcast_startup_query_intvl
);
320 } else if (matches(*argv
, "mcast_stats_enabled") == 0) {
321 __u8 mcast_stats_enabled
;
324 if (get_u8(&mcast_stats_enabled
, *argv
, 0))
325 invarg("invalid mcast_stats_enabled", *argv
);
326 addattr8(n
, 1024, IFLA_BR_MCAST_STATS_ENABLED
,
327 mcast_stats_enabled
);
328 } else if (matches(*argv
, "mcast_igmp_version") == 0) {
332 if (get_u8(&igmp_version
, *argv
, 0))
333 invarg("invalid mcast_igmp_version", *argv
);
334 addattr8(n
, 1024, IFLA_BR_MCAST_IGMP_VERSION
,
336 } else if (matches(*argv
, "mcast_mld_version") == 0) {
340 if (get_u8(&mld_version
, *argv
, 0))
341 invarg("invalid mcast_mld_version", *argv
);
342 addattr8(n
, 1024, IFLA_BR_MCAST_MLD_VERSION
,
344 } else if (matches(*argv
, "nf_call_iptables") == 0) {
348 if (get_u8(&nf_call_ipt
, *argv
, 0))
349 invarg("invalid nf_call_iptables", *argv
);
351 addattr8(n
, 1024, IFLA_BR_NF_CALL_IPTABLES
,
353 } else if (matches(*argv
, "nf_call_ip6tables") == 0) {
357 if (get_u8(&nf_call_ip6t
, *argv
, 0))
358 invarg("invalid nf_call_ip6tables", *argv
);
360 addattr8(n
, 1024, IFLA_BR_NF_CALL_IP6TABLES
,
362 } else if (matches(*argv
, "nf_call_arptables") == 0) {
366 if (get_u8(&nf_call_arpt
, *argv
, 0))
367 invarg("invalid nf_call_arptables", *argv
);
369 addattr8(n
, 1024, IFLA_BR_NF_CALL_ARPTABLES
,
371 } else if (matches(*argv
, "help") == 0) {
375 fprintf(stderr
, "bridge: unknown command \"%s\"?\n", *argv
);
385 static void _bridge_print_timer(FILE *f
,
387 struct rtattr
*timer
)
391 __jiffies_to_tv(&tv
, rta_getattr_u64(timer
));
392 if (is_json_context()) {
393 json_writer_t
*jw
= get_json_writer();
395 jsonw_name(jw
, attr
);
396 jsonw_printf(jw
, "%i.%.2i",
398 (int)tv
.tv_usec
/ 10000);
400 fprintf(f
, "%s %4i.%.2i ", attr
, (int)tv
.tv_sec
,
401 (int)tv
.tv_usec
/ 10000);
405 static void bridge_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
410 if (tb
[IFLA_BR_FORWARD_DELAY
])
411 print_uint(PRINT_ANY
,
414 rta_getattr_u32(tb
[IFLA_BR_FORWARD_DELAY
]));
416 if (tb
[IFLA_BR_HELLO_TIME
])
417 print_uint(PRINT_ANY
,
420 rta_getattr_u32(tb
[IFLA_BR_HELLO_TIME
]));
422 if (tb
[IFLA_BR_MAX_AGE
])
423 print_uint(PRINT_ANY
,
426 rta_getattr_u32(tb
[IFLA_BR_MAX_AGE
]));
428 if (tb
[IFLA_BR_AGEING_TIME
])
429 print_uint(PRINT_ANY
,
432 rta_getattr_u32(tb
[IFLA_BR_AGEING_TIME
]));
434 if (tb
[IFLA_BR_STP_STATE
])
435 print_uint(PRINT_ANY
,
438 rta_getattr_u32(tb
[IFLA_BR_STP_STATE
]));
440 if (tb
[IFLA_BR_PRIORITY
])
441 print_uint(PRINT_ANY
,
444 rta_getattr_u16(tb
[IFLA_BR_PRIORITY
]));
446 if (tb
[IFLA_BR_VLAN_FILTERING
])
447 print_uint(PRINT_ANY
,
449 "vlan_filtering %u ",
450 rta_getattr_u8(tb
[IFLA_BR_VLAN_FILTERING
]));
452 if (tb
[IFLA_BR_VLAN_PROTOCOL
]) {
455 print_string(PRINT_ANY
,
458 ll_proto_n2a(rta_getattr_u16(tb
[IFLA_BR_VLAN_PROTOCOL
]),
462 if (tb
[IFLA_BR_BRIDGE_ID
]) {
465 br_dump_bridge_id(RTA_DATA(tb
[IFLA_BR_BRIDGE_ID
]), bridge_id
,
467 print_string(PRINT_ANY
,
473 if (tb
[IFLA_BR_ROOT_ID
]) {
476 br_dump_bridge_id(RTA_DATA(tb
[IFLA_BR_BRIDGE_ID
]), root_id
,
478 print_string(PRINT_ANY
,
480 "designated_root %s ",
484 if (tb
[IFLA_BR_ROOT_PORT
])
485 print_uint(PRINT_ANY
,
488 rta_getattr_u16(tb
[IFLA_BR_ROOT_PORT
]));
490 if (tb
[IFLA_BR_ROOT_PATH_COST
])
491 print_uint(PRINT_ANY
,
493 "root_path_cost %u ",
494 rta_getattr_u32(tb
[IFLA_BR_ROOT_PATH_COST
]));
496 if (tb
[IFLA_BR_TOPOLOGY_CHANGE
])
497 print_uint(PRINT_ANY
,
499 "topology_change %u ",
500 rta_getattr_u8(tb
[IFLA_BR_TOPOLOGY_CHANGE
]));
502 if (tb
[IFLA_BR_TOPOLOGY_CHANGE_DETECTED
])
503 print_uint(PRINT_ANY
,
504 "topology_change_detected",
505 "topology_change_detected %u ",
506 rta_getattr_u8(tb
[IFLA_BR_TOPOLOGY_CHANGE_DETECTED
]));
508 if (tb
[IFLA_BR_HELLO_TIMER
])
509 _bridge_print_timer(f
, "hello_timer", tb
[IFLA_BR_HELLO_TIMER
]);
511 if (tb
[IFLA_BR_TCN_TIMER
])
512 _bridge_print_timer(f
, "tcn_timer", tb
[IFLA_BR_TCN_TIMER
]);
514 if (tb
[IFLA_BR_TOPOLOGY_CHANGE_TIMER
])
515 _bridge_print_timer(f
, "topology_change_timer",
516 tb
[IFLA_BR_TOPOLOGY_CHANGE_TIMER
]);
518 if (tb
[IFLA_BR_GC_TIMER
])
519 _bridge_print_timer(f
, "gc_timer", tb
[IFLA_BR_GC_TIMER
]);
521 if (tb
[IFLA_BR_VLAN_DEFAULT_PVID
])
522 print_uint(PRINT_ANY
,
524 "vlan_default_pvid %u ",
525 rta_getattr_u16(tb
[IFLA_BR_VLAN_DEFAULT_PVID
]));
527 if (tb
[IFLA_BR_VLAN_STATS_ENABLED
])
528 print_uint(PRINT_ANY
,
529 "vlan_stats_enabled",
530 "vlan_stats_enabled %u ",
531 rta_getattr_u8(tb
[IFLA_BR_VLAN_STATS_ENABLED
]));
533 if (tb
[IFLA_BR_VLAN_STATS_PER_PORT
])
534 print_uint(PRINT_ANY
,
535 "vlan_stats_per_port",
536 "vlan_stats_per_port %u ",
537 rta_getattr_u8(tb
[IFLA_BR_VLAN_STATS_PER_PORT
]));
539 if (tb
[IFLA_BR_GROUP_FWD_MASK
])
540 print_0xhex(PRINT_ANY
,
542 "group_fwd_mask %#llx ",
543 rta_getattr_u16(tb
[IFLA_BR_GROUP_FWD_MASK
]));
545 if (tb
[IFLA_BR_GROUP_ADDR
]) {
548 print_string(PRINT_ANY
,
551 ll_addr_n2a(RTA_DATA(tb
[IFLA_BR_GROUP_ADDR
]),
552 RTA_PAYLOAD(tb
[IFLA_BR_GROUP_ADDR
]),
553 1 /*ARPHDR_ETHER*/, mac
, sizeof(mac
)));
556 if (tb
[IFLA_BR_MCAST_SNOOPING
])
557 print_uint(PRINT_ANY
,
559 "mcast_snooping %u ",
560 rta_getattr_u8(tb
[IFLA_BR_MCAST_SNOOPING
]));
562 if (tb
[IFLA_BR_MCAST_ROUTER
])
563 print_uint(PRINT_ANY
,
566 rta_getattr_u8(tb
[IFLA_BR_MCAST_ROUTER
]));
568 if (tb
[IFLA_BR_MCAST_QUERY_USE_IFADDR
])
569 print_uint(PRINT_ANY
,
570 "mcast_query_use_ifaddr",
571 "mcast_query_use_ifaddr %u ",
572 rta_getattr_u8(tb
[IFLA_BR_MCAST_QUERY_USE_IFADDR
]));
574 if (tb
[IFLA_BR_MCAST_QUERIER
])
575 print_uint(PRINT_ANY
,
578 rta_getattr_u8(tb
[IFLA_BR_MCAST_QUERIER
]));
580 if (tb
[IFLA_BR_MCAST_HASH_ELASTICITY
])
581 print_uint(PRINT_ANY
,
582 "mcast_hash_elasticity",
583 "mcast_hash_elasticity %u ",
584 rta_getattr_u32(tb
[IFLA_BR_MCAST_HASH_ELASTICITY
]));
586 if (tb
[IFLA_BR_MCAST_HASH_MAX
])
587 print_uint(PRINT_ANY
,
589 "mcast_hash_max %u ",
590 rta_getattr_u32(tb
[IFLA_BR_MCAST_HASH_MAX
]));
592 if (tb
[IFLA_BR_MCAST_LAST_MEMBER_CNT
])
593 print_uint(PRINT_ANY
,
594 "mcast_last_member_cnt",
595 "mcast_last_member_count %u ",
596 rta_getattr_u32(tb
[IFLA_BR_MCAST_LAST_MEMBER_CNT
]));
598 if (tb
[IFLA_BR_MCAST_STARTUP_QUERY_CNT
])
599 print_uint(PRINT_ANY
,
600 "mcast_startup_query_cnt",
601 "mcast_startup_query_count %u ",
602 rta_getattr_u32(tb
[IFLA_BR_MCAST_STARTUP_QUERY_CNT
]));
604 if (tb
[IFLA_BR_MCAST_LAST_MEMBER_INTVL
])
605 print_lluint(PRINT_ANY
,
606 "mcast_last_member_intvl",
607 "mcast_last_member_interval %llu ",
608 rta_getattr_u64(tb
[IFLA_BR_MCAST_LAST_MEMBER_INTVL
]));
610 if (tb
[IFLA_BR_MCAST_MEMBERSHIP_INTVL
])
611 print_lluint(PRINT_ANY
,
612 "mcast_membership_intvl",
613 "mcast_membership_interval %llu ",
614 rta_getattr_u64(tb
[IFLA_BR_MCAST_MEMBERSHIP_INTVL
]));
616 if (tb
[IFLA_BR_MCAST_QUERIER_INTVL
])
617 print_lluint(PRINT_ANY
,
618 "mcast_querier_intvl",
619 "mcast_querier_interval %llu ",
620 rta_getattr_u64(tb
[IFLA_BR_MCAST_QUERIER_INTVL
]));
622 if (tb
[IFLA_BR_MCAST_QUERY_INTVL
])
623 print_lluint(PRINT_ANY
,
625 "mcast_query_interval %llu ",
626 rta_getattr_u64(tb
[IFLA_BR_MCAST_QUERY_INTVL
]));
628 if (tb
[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
])
629 print_lluint(PRINT_ANY
,
630 "mcast_query_response_intvl",
631 "mcast_query_response_interval %llu ",
632 rta_getattr_u64(tb
[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
]));
634 if (tb
[IFLA_BR_MCAST_STARTUP_QUERY_INTVL
])
635 print_lluint(PRINT_ANY
,
636 "mcast_startup_query_intvl",
637 "mcast_startup_query_interval %llu ",
638 rta_getattr_u64(tb
[IFLA_BR_MCAST_STARTUP_QUERY_INTVL
]));
640 if (tb
[IFLA_BR_MCAST_STATS_ENABLED
])
641 print_uint(PRINT_ANY
,
642 "mcast_stats_enabled",
643 "mcast_stats_enabled %u ",
644 rta_getattr_u8(tb
[IFLA_BR_MCAST_STATS_ENABLED
]));
646 if (tb
[IFLA_BR_MCAST_IGMP_VERSION
])
647 print_uint(PRINT_ANY
,
648 "mcast_igmp_version",
649 "mcast_igmp_version %u ",
650 rta_getattr_u8(tb
[IFLA_BR_MCAST_IGMP_VERSION
]));
652 if (tb
[IFLA_BR_MCAST_MLD_VERSION
])
653 print_uint(PRINT_ANY
,
655 "mcast_mld_version %u ",
656 rta_getattr_u8(tb
[IFLA_BR_MCAST_MLD_VERSION
]));
658 if (tb
[IFLA_BR_NF_CALL_IPTABLES
])
659 print_uint(PRINT_ANY
,
661 "nf_call_iptables %u ",
662 rta_getattr_u8(tb
[IFLA_BR_NF_CALL_IPTABLES
]));
664 if (tb
[IFLA_BR_NF_CALL_IP6TABLES
])
665 print_uint(PRINT_ANY
,
667 "nf_call_ip6tables %u ",
668 rta_getattr_u8(tb
[IFLA_BR_NF_CALL_IP6TABLES
]));
670 if (tb
[IFLA_BR_NF_CALL_ARPTABLES
])
671 print_uint(PRINT_ANY
,
673 "nf_call_arptables %u ",
674 rta_getattr_u8(tb
[IFLA_BR_NF_CALL_ARPTABLES
]));
677 static void bridge_print_help(struct link_util
*lu
, int argc
, char **argv
,
683 static void bridge_print_xstats_help(struct link_util
*lu
, FILE *f
)
685 fprintf(f
, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu
->id
);
688 static void bridge_print_stats_attr(struct rtattr
*attr
, int ifindex
)
690 struct rtattr
*brtb
[LINK_XSTATS_TYPE_MAX
+1];
691 struct bridge_stp_xstats
*sstats
;
692 struct br_mcast_stats
*mstats
;
693 struct rtattr
*i
, *list
;
694 const char *ifname
= "";
697 parse_rtattr(brtb
, LINK_XSTATS_TYPE_MAX
, RTA_DATA(attr
),
699 if (!brtb
[LINK_XSTATS_TYPE_BRIDGE
])
702 list
= brtb
[LINK_XSTATS_TYPE_BRIDGE
];
703 rem
= RTA_PAYLOAD(list
);
704 open_json_object(NULL
);
705 ifname
= ll_index_to_name(ifindex
);
706 print_string(PRINT_ANY
, "ifname", "%-16s\n", ifname
);
707 for (i
= RTA_DATA(list
); RTA_OK(i
, rem
); i
= RTA_NEXT(i
, rem
)) {
708 if (xstats_print_attr
&& i
->rta_type
!= xstats_print_attr
)
710 switch (i
->rta_type
) {
711 case BRIDGE_XSTATS_MCAST
:
712 mstats
= RTA_DATA(i
);
713 open_json_object("multicast");
714 open_json_object("igmp_queries");
715 print_string(PRINT_FP
, NULL
,
716 "%-16s IGMP queries:\n", "");
717 print_string(PRINT_FP
, NULL
, "%-16s ", "");
718 print_u64(PRINT_ANY
, "rx_v1", "RX: v1 %llu ",
719 mstats
->igmp_v1queries
[BR_MCAST_DIR_RX
]);
720 print_u64(PRINT_ANY
, "rx_v2", "v2 %llu ",
721 mstats
->igmp_v2queries
[BR_MCAST_DIR_RX
]);
722 print_u64(PRINT_ANY
, "rx_v3", "v3 %llu\n",
723 mstats
->igmp_v3queries
[BR_MCAST_DIR_RX
]);
724 print_string(PRINT_FP
, NULL
, "%-16s ", "");
725 print_u64(PRINT_ANY
, "tx_v1", "TX: v1 %llu ",
726 mstats
->igmp_v1queries
[BR_MCAST_DIR_TX
]);
727 print_u64(PRINT_ANY
, "tx_v2", "v2 %llu ",
728 mstats
->igmp_v2queries
[BR_MCAST_DIR_TX
]);
729 print_u64(PRINT_ANY
, "tx_v3", "v3 %llu\n",
730 mstats
->igmp_v3queries
[BR_MCAST_DIR_TX
]);
733 open_json_object("igmp_reports");
734 print_string(PRINT_FP
, NULL
,
735 "%-16s IGMP reports:\n", "");
736 print_string(PRINT_FP
, NULL
, "%-16s ", "");
737 print_u64(PRINT_ANY
, "rx_v1", "RX: v1 %llu ",
738 mstats
->igmp_v1reports
[BR_MCAST_DIR_RX
]);
739 print_u64(PRINT_ANY
, "rx_v2", "v2 %llu ",
740 mstats
->igmp_v2reports
[BR_MCAST_DIR_RX
]);
741 print_u64(PRINT_ANY
, "rx_v3", "v3 %llu\n",
742 mstats
->igmp_v3reports
[BR_MCAST_DIR_RX
]);
743 print_string(PRINT_FP
, NULL
, "%-16s ", "");
744 print_u64(PRINT_ANY
, "tx_v1", "TX: v1 %llu ",
745 mstats
->igmp_v1reports
[BR_MCAST_DIR_TX
]);
746 print_u64(PRINT_ANY
, "tx_v2", "v2 %llu ",
747 mstats
->igmp_v2reports
[BR_MCAST_DIR_TX
]);
748 print_u64(PRINT_ANY
, "tx_v3", "v3 %llu\n",
749 mstats
->igmp_v3reports
[BR_MCAST_DIR_TX
]);
752 open_json_object("igmp_leaves");
753 print_string(PRINT_FP
, NULL
,
754 "%-16s IGMP leaves: ", "");
755 print_u64(PRINT_ANY
, "rx", "RX: %llu ",
756 mstats
->igmp_leaves
[BR_MCAST_DIR_RX
]);
757 print_u64(PRINT_ANY
, "tx", "TX: %llu\n",
758 mstats
->igmp_leaves
[BR_MCAST_DIR_TX
]);
761 print_string(PRINT_FP
, NULL
,
762 "%-16s IGMP parse errors: ", "");
763 print_u64(PRINT_ANY
, "igmp_parse_errors", "%llu\n",
764 mstats
->igmp_parse_errors
);
766 open_json_object("mld_queries");
767 print_string(PRINT_FP
, NULL
,
768 "%-16s MLD queries:\n", "");
769 print_string(PRINT_FP
, NULL
, "%-16s ", "");
770 print_u64(PRINT_ANY
, "rx_v1", "RX: v1 %llu ",
771 mstats
->mld_v1queries
[BR_MCAST_DIR_RX
]);
772 print_u64(PRINT_ANY
, "rx_v2", "v2 %llu\n",
773 mstats
->mld_v2queries
[BR_MCAST_DIR_RX
]);
774 print_string(PRINT_FP
, NULL
, "%-16s ", "");
775 print_u64(PRINT_ANY
, "tx_v1", "TX: v1 %llu ",
776 mstats
->mld_v1queries
[BR_MCAST_DIR_TX
]);
777 print_u64(PRINT_ANY
, "tx_v2", "v2 %llu\n",
778 mstats
->mld_v2queries
[BR_MCAST_DIR_TX
]);
781 open_json_object("mld_reports");
782 print_string(PRINT_FP
, NULL
,
783 "%-16s MLD reports:\n", "");
784 print_string(PRINT_FP
, NULL
, "%-16s ", "");
785 print_u64(PRINT_ANY
, "rx_v1", "RX: v1 %llu ",
786 mstats
->mld_v1reports
[BR_MCAST_DIR_RX
]);
787 print_u64(PRINT_ANY
, "rx_v2", "v2 %llu\n",
788 mstats
->mld_v2reports
[BR_MCAST_DIR_RX
]);
789 print_string(PRINT_FP
, NULL
, "%-16s ", "");
790 print_u64(PRINT_ANY
, "tx_v1", "TX: v1 %llu ",
791 mstats
->mld_v1reports
[BR_MCAST_DIR_TX
]);
792 print_u64(PRINT_ANY
, "tx_v2", "v2 %llu\n",
793 mstats
->mld_v2reports
[BR_MCAST_DIR_TX
]);
796 open_json_object("mld_leaves");
797 print_string(PRINT_FP
, NULL
,
798 "%-16s MLD leaves: ", "");
799 print_u64(PRINT_ANY
, "rx", "RX: %llu ",
800 mstats
->mld_leaves
[BR_MCAST_DIR_RX
]);
801 print_u64(PRINT_ANY
, "tx", "TX: %llu\n",
802 mstats
->mld_leaves
[BR_MCAST_DIR_TX
]);
805 print_string(PRINT_FP
, NULL
,
806 "%-16s MLD parse errors: ", "");
807 print_u64(PRINT_ANY
, "mld_parse_errors", "%llu\n",
808 mstats
->mld_parse_errors
);
811 case BRIDGE_XSTATS_STP
:
812 sstats
= RTA_DATA(i
);
813 open_json_object("stp");
814 print_string(PRINT_FP
, NULL
,
815 "%-16s STP BPDU: ", "");
816 print_u64(PRINT_ANY
, "rx_bpdu", "RX: %llu ",
818 print_u64(PRINT_ANY
, "tx_bpdu", "TX: %llu\n",
820 print_string(PRINT_FP
, NULL
,
821 "%-16s STP TCN: ", "");
822 print_u64(PRINT_ANY
, "rx_tcn", "RX: %llu ",
824 print_u64(PRINT_ANY
, "tx_tcn", "TX: %llu\n",
826 print_string(PRINT_FP
, NULL
,
827 "%-16s STP Transitions: ", "");
828 print_u64(PRINT_ANY
, "transition_blk", "Blocked: %llu ",
829 sstats
->transition_blk
);
830 print_u64(PRINT_ANY
, "transition_fwd", "Forwarding: %llu\n",
831 sstats
->transition_fwd
);
839 int bridge_print_xstats(struct nlmsghdr
*n
, void *arg
)
841 struct if_stats_msg
*ifsm
= NLMSG_DATA(n
);
842 struct rtattr
*tb
[IFLA_STATS_MAX
+1];
843 int len
= n
->nlmsg_len
;
845 len
-= NLMSG_LENGTH(sizeof(*ifsm
));
847 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
850 if (filter_index
&& filter_index
!= ifsm
->ifindex
)
853 parse_rtattr(tb
, IFLA_STATS_MAX
, IFLA_STATS_RTA(ifsm
), len
);
854 if (tb
[IFLA_STATS_LINK_XSTATS
])
855 bridge_print_stats_attr(tb
[IFLA_STATS_LINK_XSTATS
],
858 if (tb
[IFLA_STATS_LINK_XSTATS_SLAVE
])
859 bridge_print_stats_attr(tb
[IFLA_STATS_LINK_XSTATS_SLAVE
],
865 int bridge_parse_xstats(struct link_util
*lu
, int argc
, char **argv
)
868 if (strcmp(*argv
, "igmp") == 0 || strcmp(*argv
, "mcast") == 0) {
869 xstats_print_attr
= BRIDGE_XSTATS_MCAST
;
870 } else if (strcmp(*argv
, "stp") == 0) {
871 xstats_print_attr
= BRIDGE_XSTATS_STP
;
872 } else if (strcmp(*argv
, "dev") == 0) {
874 filter_index
= ll_name_to_index(*argv
);
877 } else if (strcmp(*argv
, "help") == 0) {
878 bridge_print_xstats_help(lu
, stdout
);
881 invarg("unknown attribute", *argv
);
889 struct link_util bridge_link_util
= {
891 .maxattr
= IFLA_BR_MAX
,
892 .parse_opt
= bridge_parse_opt
,
893 .print_opt
= bridge_print_opt
,
894 .print_help
= bridge_print_help
,
895 .parse_ifla_xstats
= bridge_parse_xstats
,
896 .print_ifla_xstats
= bridge_print_xstats
,