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