]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_bridge.c
iplink: bridge: add support for displaying xstats
[mirror_iproute2.git] / ip / iplink_bridge.c
CommitLineData
28d84b42
JP
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>
60ec0ecf 15#include <netinet/in.h>
28d84b42 16#include <linux/if_link.h>
60ec0ecf 17#include <linux/if_bridge.h>
70dfb0b8 18#include <netinet/ether.h>
60ec0ecf 19#include <net/if.h>
28d84b42 20
1eea5c46 21#include "rt_names.h"
28d84b42
JP
22#include "utils.h"
23#include "ip_common.h"
24
60ec0ecf
NA
25static unsigned int xstats_print_attr;
26static int filter_index;
27
43367ef7 28static void print_explain(FILE *f)
28d84b42 29{
43367ef7 30 fprintf(f,
f3372d62
HL
31 "Usage: ... bridge [ fdb_flush ]\n"
32 " [ forward_delay FORWARD_DELAY ]\n"
28d84b42
JP
33 " [ hello_time HELLO_TIME ]\n"
34 " [ max_age MAX_AGE ]\n"
6c99fb60 35 " [ ageing_time AGEING_TIME ]\n"
dab04962 36 " [ stp_state STP_STATE ]\n"
b0197a04 37 " [ priority PRIORITY ]\n"
8caaf33b 38 " [ group_fwd_mask MASK ]\n"
0a61aa39 39 " [ group_address ADDRESS ]\n"
e4d456f0 40 " [ vlan_filtering VLAN_FILTERING ]\n"
1eea5c46 41 " [ vlan_protocol VLAN_PROTOCOL ]\n"
719832af 42 " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n"
7d93b567 43 " [ vlan_stats_enabled VLAN_STATS_ENABLED ]\n"
7ddd2d94 44 " [ mcast_snooping MULTICAST_SNOOPING ]\n"
963d137c 45 " [ mcast_router MULTICAST_ROUTER ]\n"
449843d1 46 " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
0778b741 47 " [ mcast_querier MULTICAST_QUERIER ]\n"
92c0ef70 48 " [ mcast_hash_elasticity HASH_ELASTICITY ]\n"
8b9eb7cd 49 " [ mcast_hash_max HASH_MAX ]\n"
fb44cadb 50 " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
ceb64866 51 " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
10082a25 52 " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
7f3d5592 53 " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
1f2244b8 54 " [ mcast_querier_interval QUERIER_INTERVAL ]\n"
5a32388f 55 " [ mcast_query_interval QUERY_INTERVAL ]\n"
483df11c 56 " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
178b1806 57 " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
6ddad009 58 " [ mcast_stats_enabled MCAST_STATS_ENABLED ]\n"
19756950 59 " [ mcast_igmp_version IGMP_VERSION ]\n"
c3f1e3c4 60 " [ mcast_mld_version MLD_VERSION ]\n"
861c5dae
NA
61 " [ nf_call_iptables NF_CALL_IPTABLES ]\n"
62 " [ nf_call_ip6tables NF_CALL_IP6TABLES ]\n"
63 " [ nf_call_arptables NF_CALL_ARPTABLES ]\n"
1eea5c46
TM
64 "\n"
65 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
28d84b42
JP
66 );
67}
68
43367ef7
ZS
69static void explain(void)
70{
71 print_explain(stderr);
72}
73
3069539f 74void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len)
70dfb0b8
NA
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
28d84b42
JP
82static 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();
6a9ce30e 90 if (get_u32(&val, *argv, 0))
28d84b42 91 invarg("invalid forward_delay", *argv);
6a9ce30e 92
28d84b42
JP
93 addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
94 } else if (matches(*argv, "hello_time") == 0) {
95 NEXT_ARG();
6a9ce30e 96 if (get_u32(&val, *argv, 0))
28d84b42 97 invarg("invalid hello_time", *argv);
6a9ce30e 98
28d84b42
JP
99 addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
100 } else if (matches(*argv, "max_age") == 0) {
101 NEXT_ARG();
6a9ce30e 102 if (get_u32(&val, *argv, 0))
28d84b42 103 invarg("invalid max_age", *argv);
6a9ce30e 104
28d84b42 105 addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
6c99fb60
NA
106 } else if (matches(*argv, "ageing_time") == 0) {
107 NEXT_ARG();
6a9ce30e 108 if (get_u32(&val, *argv, 0))
6c99fb60 109 invarg("invalid ageing_time", *argv);
6a9ce30e 110
6c99fb60 111 addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
dab04962
NA
112 } else if (matches(*argv, "stp_state") == 0) {
113 NEXT_ARG();
6a9ce30e 114 if (get_u32(&val, *argv, 0))
dab04962 115 invarg("invalid stp_state", *argv);
6a9ce30e 116
dab04962 117 addattr32(n, 1024, IFLA_BR_STP_STATE, val);
b0197a04
NA
118 } else if (matches(*argv, "priority") == 0) {
119 __u16 prio;
120
121 NEXT_ARG();
6a9ce30e 122 if (get_u16(&prio, *argv, 0))
b0197a04 123 invarg("invalid priority", *argv);
6a9ce30e 124
b0197a04 125 addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
e4d456f0
NA
126 } else if (matches(*argv, "vlan_filtering") == 0) {
127 __u8 vlan_filter;
128
129 NEXT_ARG();
8a4cd394 130 if (get_u8(&vlan_filter, *argv, 0))
e4d456f0 131 invarg("invalid vlan_filtering", *argv);
8a4cd394 132
e4d456f0 133 addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
1eea5c46
TM
134 } else if (matches(*argv, "vlan_protocol") == 0) {
135 __u16 vlan_proto;
136
137 NEXT_ARG();
8a4cd394 138 if (ll_proto_a2n(&vlan_proto, *argv))
1eea5c46 139 invarg("invalid vlan_protocol", *argv);
8a4cd394 140
1eea5c46 141 addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
8caaf33b
NA
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);
0a61aa39
NA
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);
f3372d62
HL
159 } else if (matches(*argv, "fdb_flush") == 0) {
160 addattr(n, 1024, IFLA_BR_FDB_FLUSH);
719832af
NA
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);
7d93b567
HL
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);
963d137c
NA
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);
7ddd2d94
NA
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);
449843d1
NA
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);
0778b741
NA
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);
92c0ef70
NA
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);
8b9eb7cd
NA
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);
fb44cadb
NA
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);
ceb64866
NA
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);
10082a25
NA
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);
7f3d5592
NA
261 } else if (matches(*argv, "mcast_membership_interval") == 0) {
262 __u64 mcast_membership_intvl;
263
264 NEXT_ARG();
8a4cd394 265 if (get_u64(&mcast_membership_intvl, *argv, 0))
7f3d5592
NA
266 invarg("invalid mcast_membership_interval",
267 *argv);
8a4cd394 268
7f3d5592
NA
269 addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL,
270 mcast_membership_intvl);
1f2244b8
NA
271 } else if (matches(*argv, "mcast_querier_interval") == 0) {
272 __u64 mcast_querier_intvl;
273
274 NEXT_ARG();
8a4cd394 275 if (get_u64(&mcast_querier_intvl, *argv, 0))
1f2244b8
NA
276 invarg("invalid mcast_querier_interval",
277 *argv);
8a4cd394 278
1f2244b8
NA
279 addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL,
280 mcast_querier_intvl);
5a32388f
NA
281 } else if (matches(*argv, "mcast_query_interval") == 0) {
282 __u64 mcast_query_intvl;
283
284 NEXT_ARG();
8a4cd394 285 if (get_u64(&mcast_query_intvl, *argv, 0))
5a32388f
NA
286 invarg("invalid mcast_query_interval",
287 *argv);
8a4cd394 288
5a32388f
NA
289 addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL,
290 mcast_query_intvl);
483df11c
NA
291 } else if (!matches(*argv, "mcast_query_response_interval")) {
292 __u64 mcast_query_resp_intvl;
293
294 NEXT_ARG();
8a4cd394 295 if (get_u64(&mcast_query_resp_intvl, *argv, 0))
483df11c
NA
296 invarg("invalid mcast_query_response_interval",
297 *argv);
8a4cd394 298
483df11c
NA
299 addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
300 mcast_query_resp_intvl);
178b1806
NA
301 } else if (!matches(*argv, "mcast_startup_query_interval")) {
302 __u64 mcast_startup_query_intvl;
303
304 NEXT_ARG();
8a4cd394 305 if (get_u64(&mcast_startup_query_intvl, *argv, 0))
178b1806
NA
306 invarg("invalid mcast_startup_query_interval",
307 *argv);
8a4cd394 308
178b1806
NA
309 addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
310 mcast_startup_query_intvl);
6ddad009
HL
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);
19756950
HL
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);
c3f1e3c4
HL
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);
861c5dae
NA
335 } else if (matches(*argv, "nf_call_iptables") == 0) {
336 __u8 nf_call_ipt;
337
338 NEXT_ARG();
8a4cd394 339 if (get_u8(&nf_call_ipt, *argv, 0))
861c5dae 340 invarg("invalid nf_call_iptables", *argv);
8a4cd394 341
861c5dae
NA
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();
8a4cd394 348 if (get_u8(&nf_call_ip6t, *argv, 0))
861c5dae 349 invarg("invalid nf_call_ip6tables", *argv);
8a4cd394 350
861c5dae
NA
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();
8a4cd394 357 if (get_u8(&nf_call_arpt, *argv, 0))
861c5dae 358 invarg("invalid nf_call_arptables", *argv);
8a4cd394 359
861c5dae
NA
360 addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES,
361 nf_call_arpt);
28d84b42
JP
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
376static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
377{
378 if (!tb)
379 return;
380
381 if (tb[IFLA_BR_FORWARD_DELAY])
382 fprintf(f, "forward_delay %u ",
383 rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
384
385 if (tb[IFLA_BR_HELLO_TIME])
386 fprintf(f, "hello_time %u ",
387 rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
388
389 if (tb[IFLA_BR_MAX_AGE])
390 fprintf(f, "max_age %u ",
391 rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
fdba0515
NA
392
393 if (tb[IFLA_BR_AGEING_TIME])
394 fprintf(f, "ageing_time %u ",
395 rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
396
397 if (tb[IFLA_BR_STP_STATE])
398 fprintf(f, "stp_state %u ",
399 rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
400
401 if (tb[IFLA_BR_PRIORITY])
402 fprintf(f, "priority %u ",
403 rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
e4d456f0
NA
404
405 if (tb[IFLA_BR_VLAN_FILTERING])
406 fprintf(f, "vlan_filtering %u ",
407 rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
1eea5c46
TM
408
409 if (tb[IFLA_BR_VLAN_PROTOCOL]) {
410 SPRINT_BUF(b1);
411
412 fprintf(f, "vlan_protocol %s ",
413 ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
414 b1, sizeof(b1)));
415 }
70dfb0b8
NA
416
417 if (tb[IFLA_BR_BRIDGE_ID]) {
418 char bridge_id[32];
419
420 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
421 sizeof(bridge_id));
422 fprintf(f, "bridge_id %s ", bridge_id);
423 }
424
425 if (tb[IFLA_BR_ROOT_ID]) {
426 char root_id[32];
427
428 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
429 sizeof(root_id));
430 fprintf(f, "designated_root %s ", root_id);
431 }
4e3bbc66
NA
432
433 if (tb[IFLA_BR_ROOT_PORT])
434 fprintf(f, "root_port %u ",
435 rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
436
437 if (tb[IFLA_BR_ROOT_PATH_COST])
438 fprintf(f, "root_path_cost %u ",
439 rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
440
441 if (tb[IFLA_BR_TOPOLOGY_CHANGE])
442 fprintf(f, "topology_change %u ",
443 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
444
445 if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
446 fprintf(f, "topology_change_detected %u ",
447 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
8c0f7a16
NA
448
449 if (tb[IFLA_BR_HELLO_TIMER]) {
450 struct timeval tv;
451
452 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
453 fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
454 (int)tv.tv_usec/10000);
455 }
456
457 if (tb[IFLA_BR_TCN_TIMER]) {
458 struct timeval tv;
459
460 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
461 fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
462 (int)tv.tv_usec/10000);
463 }
464
465 if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
466 unsigned long jiffies;
467 struct timeval tv;
468
469 jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
470 __jiffies_to_tv(&tv, jiffies);
471 fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
472 (int)tv.tv_usec/10000);
473 }
474
475 if (tb[IFLA_BR_GC_TIMER]) {
476 struct timeval tv;
477
478 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
479 fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
480 (int)tv.tv_usec/10000);
481 }
8caaf33b 482
719832af
NA
483 if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
484 fprintf(f, "vlan_default_pvid %u ",
485 rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
486
7d93b567
HL
487 if (tb[IFLA_BR_VLAN_STATS_ENABLED])
488 fprintf(f, "vlan_stats_enabled %u ",
489 rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
490
8caaf33b
NA
491 if (tb[IFLA_BR_GROUP_FWD_MASK])
492 fprintf(f, "group_fwd_mask %#x ",
493 rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
0a61aa39
NA
494
495 if (tb[IFLA_BR_GROUP_ADDR]) {
496 SPRINT_BUF(mac);
497
498 fprintf(f, "group_address %s ",
499 ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
500 RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
501 1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
502 }
963d137c 503
7ddd2d94
NA
504 if (tb[IFLA_BR_MCAST_SNOOPING])
505 fprintf(f, "mcast_snooping %u ",
506 rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
507
963d137c
NA
508 if (tb[IFLA_BR_MCAST_ROUTER])
509 fprintf(f, "mcast_router %u ",
510 rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
449843d1
NA
511
512 if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
513 fprintf(f, "mcast_query_use_ifaddr %u ",
514 rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
0778b741
NA
515
516 if (tb[IFLA_BR_MCAST_QUERIER])
517 fprintf(f, "mcast_querier %u ",
518 rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
92c0ef70
NA
519
520 if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
521 fprintf(f, "mcast_hash_elasticity %u ",
522 rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
8b9eb7cd
NA
523
524 if (tb[IFLA_BR_MCAST_HASH_MAX])
525 fprintf(f, "mcast_hash_max %u ",
526 rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
fb44cadb
NA
527
528 if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
529 fprintf(f, "mcast_last_member_count %u ",
530 rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
ceb64866
NA
531
532 if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])
533 fprintf(f, "mcast_startup_query_count %u ",
534 rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
10082a25
NA
535
536 if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])
537 fprintf(f, "mcast_last_member_interval %llu ",
538 rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
7f3d5592
NA
539
540 if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])
541 fprintf(f, "mcast_membership_interval %llu ",
542 rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
1f2244b8
NA
543
544 if (tb[IFLA_BR_MCAST_QUERIER_INTVL])
545 fprintf(f, "mcast_querier_interval %llu ",
546 rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
5a32388f
NA
547
548 if (tb[IFLA_BR_MCAST_QUERY_INTVL])
549 fprintf(f, "mcast_query_interval %llu ",
550 rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
483df11c
NA
551
552 if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])
553 fprintf(f, "mcast_query_response_interval %llu ",
554 rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
178b1806
NA
555
556 if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])
557 fprintf(f, "mcast_startup_query_interval %llu ",
558 rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
861c5dae 559
6ddad009
HL
560 if (tb[IFLA_BR_MCAST_STATS_ENABLED])
561 fprintf(f, "mcast_stats_enabled %u ",
562 rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
563
19756950
HL
564 if (tb[IFLA_BR_MCAST_IGMP_VERSION])
565 fprintf(f, "mcast_igmp_version %u ",
566 rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
567
c3f1e3c4
HL
568 if (tb[IFLA_BR_MCAST_MLD_VERSION])
569 fprintf(f, "mcast_mld_version %u ",
570 rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
571
861c5dae
NA
572 if (tb[IFLA_BR_NF_CALL_IPTABLES])
573 fprintf(f, "nf_call_iptables %u ",
574 rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
575
576 if (tb[IFLA_BR_NF_CALL_IP6TABLES])
577 fprintf(f, "nf_call_ip6tables %u ",
578 rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
579
580 if (tb[IFLA_BR_NF_CALL_ARPTABLES])
581 fprintf(f, "nf_call_arptables %u ",
582 rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
28d84b42
JP
583}
584
43367ef7
ZS
585static void bridge_print_help(struct link_util *lu, int argc, char **argv,
586 FILE *f)
587{
588 print_explain(f);
589}
590
60ec0ecf
NA
591static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
592{
593 fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
594}
595
596static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex)
597{
598 struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
599 struct br_mcast_stats *mstats;
600 struct rtattr *i, *list;
601 const char *ifname = "";
602 int rem;
603
604 parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
605 RTA_PAYLOAD(attr));
606 if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
607 return;
608
609 list = brtb[LINK_XSTATS_TYPE_BRIDGE];
610 rem = RTA_PAYLOAD(list);
611 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
612 if (xstats_print_attr && i->rta_type != xstats_print_attr)
613 continue;
614 switch (i->rta_type) {
615 case BRIDGE_XSTATS_MCAST:
616 mstats = RTA_DATA(i);
617 ifname = ll_index_to_name(ifindex);
618 fprintf(f, "%-16s\n", ifname);
619 fprintf(f, "%-16s IGMP queries:\n", "");
620 fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n",
621 "",
622 mstats->igmp_v1queries[BR_MCAST_DIR_RX],
623 mstats->igmp_v2queries[BR_MCAST_DIR_RX],
624 mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
625 fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n",
626 "",
627 mstats->igmp_v1queries[BR_MCAST_DIR_TX],
628 mstats->igmp_v2queries[BR_MCAST_DIR_TX],
629 mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
630
631 fprintf(f, "%-16s IGMP reports:\n", "");
632 fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n",
633 "",
634 mstats->igmp_v1reports[BR_MCAST_DIR_RX],
635 mstats->igmp_v2reports[BR_MCAST_DIR_RX],
636 mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
637 fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n",
638 "",
639 mstats->igmp_v1reports[BR_MCAST_DIR_TX],
640 mstats->igmp_v2reports[BR_MCAST_DIR_TX],
641 mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
642
643 fprintf(f, "%-16s IGMP leaves: RX: %llu TX: %llu\n",
644 "",
645 mstats->igmp_leaves[BR_MCAST_DIR_RX],
646 mstats->igmp_leaves[BR_MCAST_DIR_TX]);
647
648 fprintf(f, "%-16s IGMP parse errors: %llu\n",
649 "", mstats->igmp_parse_errors);
650
651 fprintf(f, "%-16s MLD queries:\n", "");
652 fprintf(f, "%-16s RX: v1 %llu v2 %llu\n",
653 "",
654 mstats->mld_v1queries[BR_MCAST_DIR_RX],
655 mstats->mld_v2queries[BR_MCAST_DIR_RX]);
656 fprintf(f, "%-16s TX: v1 %llu v2 %llu\n",
657 "",
658 mstats->mld_v1queries[BR_MCAST_DIR_TX],
659 mstats->mld_v2queries[BR_MCAST_DIR_TX]);
660
661 fprintf(f, "%-16s MLD reports:\n", "");
662 fprintf(f, "%-16s RX: v1 %llu v2 %llu\n",
663 "",
664 mstats->mld_v1reports[BR_MCAST_DIR_RX],
665 mstats->mld_v2reports[BR_MCAST_DIR_RX]);
666 fprintf(f, "%-16s TX: v1 %llu v2 %llu\n",
667 "",
668 mstats->mld_v1reports[BR_MCAST_DIR_TX],
669 mstats->mld_v2reports[BR_MCAST_DIR_TX]);
670
671 fprintf(f, "%-16s MLD leaves: RX: %llu TX: %llu\n",
672 "",
673 mstats->mld_leaves[BR_MCAST_DIR_RX],
674 mstats->mld_leaves[BR_MCAST_DIR_TX]);
675
676 fprintf(f, "%-16s MLD parse errors: %llu\n",
677 "", mstats->mld_parse_errors);
678 break;
679 }
680 }
681}
682
683static int bridge_print_xstats(const struct sockaddr_nl *who,
684 struct nlmsghdr *n, void *arg)
685{
686 struct if_stats_msg *ifsm = NLMSG_DATA(n);
687 struct rtattr *tb[IFLA_STATS_MAX+1];
688 int len = n->nlmsg_len;
689 FILE *fp = arg;
690
691 len -= NLMSG_LENGTH(sizeof(*ifsm));
692 if (len < 0) {
693 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
694 return -1;
695 }
696 if (filter_index && filter_index != ifsm->ifindex)
697 return 0;
698
699 parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
700 if (tb[IFLA_STATS_LINK_XSTATS])
701 bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
702 ifsm->ifindex);
703
704 if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
705 bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
706 ifsm->ifindex);
707
708 return 0;
709}
710
711static int bridge_parse_xstats(struct link_util *lu, int argc, char **argv)
712{
713 while (argc > 0) {
714 if (strcmp(*argv, "igmp") == 0 || strcmp(*argv, "mcast") == 0) {
715 xstats_print_attr = BRIDGE_XSTATS_MCAST;
716 } else if (strcmp(*argv, "dev") == 0) {
717 NEXT_ARG();
718 filter_index = if_nametoindex(*argv);
719 if (filter_index == 0) {
720 fprintf(stderr, "Cannot find device \"%s\"\n",
721 *argv);
722 return -1;
723 }
724 } else if (strcmp(*argv, "help") == 0) {
725 bridge_print_xstats_help(lu, stdout);
726 exit(0);
727 } else {
728 invarg("unknown attribute", *argv);
729 }
730 argc--; argv++;
731 }
732
733 return 0;
734}
735
28d84b42
JP
736struct link_util bridge_link_util = {
737 .id = "bridge",
738 .maxattr = IFLA_BR_MAX,
739 .parse_opt = bridge_parse_opt,
740 .print_opt = bridge_print_opt,
43367ef7 741 .print_help = bridge_print_help,
60ec0ecf
NA
742 .parse_ifla_xstats = bridge_parse_xstats,
743 .print_ifla_xstats = bridge_print_xstats,
28d84b42 744};