• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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