Home | History | Annotate | Download | only in ip
      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 (at) 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 
     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 
     69 static void explain(void)
     70 {
     71 	print_explain(stderr);
     72 }
     73 
     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 
     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 
    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 
    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 
    662 static void bridge_print_help(struct link_util *lu, int argc, char **argv,
    663 			      FILE *f)
    664 {
    665 	print_explain(f);
    666 }
    667 
    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 
    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 
    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 
    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