iproute2/ip/iplink_bridge.c
<<
>>
Prefs
   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
  25static unsigned int xstats_print_attr;
  26static int filter_index;
  27
  28static 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                "                 [ vlan_stats_per_port VLAN_STATS_PER_PORT ]\n"
  45                "                 [ mcast_snooping MULTICAST_SNOOPING ]\n"
  46                "                 [ mcast_router MULTICAST_ROUTER ]\n"
  47                "                 [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
  48                "                 [ mcast_querier MULTICAST_QUERIER ]\n"
  49                "                 [ mcast_hash_elasticity HASH_ELASTICITY ]\n"
  50                "                 [ mcast_hash_max HASH_MAX ]\n"
  51                "                 [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
  52                "                 [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
  53                "                 [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
  54                "                 [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
  55                "                 [ mcast_querier_interval QUERIER_INTERVAL ]\n"
  56                "                 [ mcast_query_interval QUERY_INTERVAL ]\n"
  57                "                 [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
  58                "                 [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
  59                "                 [ mcast_stats_enabled MCAST_STATS_ENABLED ]\n"
  60                "                 [ mcast_igmp_version IGMP_VERSION ]\n"
  61                "                 [ mcast_mld_version MLD_VERSION ]\n"
  62                "                 [ nf_call_iptables NF_CALL_IPTABLES ]\n"
  63                "                 [ nf_call_ip6tables NF_CALL_IP6TABLES ]\n"
  64                "                 [ nf_call_arptables NF_CALL_ARPTABLES ]\n"
  65                "\n"
  66                "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
  67        );
  68}
  69
  70static void explain(void)
  71{
  72        print_explain(stderr);
  73}
  74
  75void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len)
  76{
  77        char eaddr[18];
  78
  79        ether_ntoa_r((const struct ether_addr *)id->addr, eaddr);
  80        snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr);
  81}
  82
  83static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
  84                            struct nlmsghdr *n)
  85{
  86        __u32 val;
  87
  88        while (argc > 0) {
  89                if (matches(*argv, "forward_delay") == 0) {
  90                        NEXT_ARG();
  91                        if (get_u32(&val, *argv, 0))
  92                                invarg("invalid forward_delay", *argv);
  93
  94                        addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
  95                } else if (matches(*argv, "hello_time") == 0) {
  96                        NEXT_ARG();
  97                        if (get_u32(&val, *argv, 0))
  98                                invarg("invalid hello_time", *argv);
  99
 100                        addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
 101                } else if (matches(*argv, "max_age") == 0) {
 102                        NEXT_ARG();
 103                        if (get_u32(&val, *argv, 0))
 104                                invarg("invalid max_age", *argv);
 105
 106                        addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
 107                } else if (matches(*argv, "ageing_time") == 0) {
 108                        NEXT_ARG();
 109                        if (get_u32(&val, *argv, 0))
 110                                invarg("invalid ageing_time", *argv);
 111
 112                        addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
 113                } else if (matches(*argv, "stp_state") == 0) {
 114                        NEXT_ARG();
 115                        if (get_u32(&val, *argv, 0))
 116                                invarg("invalid stp_state", *argv);
 117
 118                        addattr32(n, 1024, IFLA_BR_STP_STATE, val);
 119                } else if (matches(*argv, "priority") == 0) {
 120                        __u16 prio;
 121
 122                        NEXT_ARG();
 123                        if (get_u16(&prio, *argv, 0))
 124                                invarg("invalid priority", *argv);
 125
 126                        addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
 127                } else if (matches(*argv, "vlan_filtering") == 0) {
 128                        __u8 vlan_filter;
 129
 130                        NEXT_ARG();
 131                        if (get_u8(&vlan_filter, *argv, 0))
 132                                invarg("invalid vlan_filtering", *argv);
 133
 134                        addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
 135                } else if (matches(*argv, "vlan_protocol") == 0) {
 136                        __u16 vlan_proto;
 137
 138                        NEXT_ARG();
 139                        if (ll_proto_a2n(&vlan_proto, *argv))
 140                                invarg("invalid vlan_protocol", *argv);
 141
 142                        addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
 143                } else if (matches(*argv, "group_fwd_mask") == 0) {
 144                        __u16 fwd_mask;
 145
 146                        NEXT_ARG();
 147                        if (get_u16(&fwd_mask, *argv, 0))
 148                                invarg("invalid group_fwd_mask", *argv);
 149
 150                        addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
 151                } else if (matches(*argv, "group_address") == 0) {
 152                        char llabuf[32];
 153                        int len;
 154
 155                        NEXT_ARG();
 156                        len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv);
 157                        if (len < 0)
 158                                return -1;
 159                        addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len);
 160                } else if (matches(*argv, "fdb_flush") == 0) {
 161                        addattr(n, 1024, IFLA_BR_FDB_FLUSH);
 162                } else if (matches(*argv, "vlan_default_pvid") == 0) {
 163                        __u16 default_pvid;
 164
 165                        NEXT_ARG();
 166                        if (get_u16(&default_pvid, *argv, 0))
 167                                invarg("invalid vlan_default_pvid", *argv);
 168
 169                        addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID,
 170                                  default_pvid);
 171                } else if (matches(*argv, "vlan_stats_enabled") == 0) {
 172                        __u8 vlan_stats_enabled;
 173
 174                        NEXT_ARG();
 175                        if (get_u8(&vlan_stats_enabled, *argv, 0))
 176                                invarg("invalid vlan_stats_enabled", *argv);
 177                        addattr8(n, 1024, IFLA_BR_VLAN_STATS_ENABLED,
 178                                  vlan_stats_enabled);
 179                } else if (matches(*argv, "vlan_stats_per_port") == 0) {
 180                        __u8 vlan_stats_per_port;
 181
 182                        NEXT_ARG();
 183                        if (get_u8(&vlan_stats_per_port, *argv, 0))
 184                                invarg("invalid vlan_stats_per_port", *argv);
 185                        addattr8(n, 1024, IFLA_BR_VLAN_STATS_PER_PORT,
 186                                 vlan_stats_per_port);
 187                } else if (matches(*argv, "mcast_router") == 0) {
 188                        __u8 mcast_router;
 189
 190                        NEXT_ARG();
 191                        if (get_u8(&mcast_router, *argv, 0))
 192                                invarg("invalid mcast_router", *argv);
 193
 194                        addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router);
 195                } else if (matches(*argv, "mcast_snooping") == 0) {
 196                        __u8 mcast_snoop;
 197
 198                        NEXT_ARG();
 199                        if (get_u8(&mcast_snoop, *argv, 0))
 200                                invarg("invalid mcast_snooping", *argv);
 201
 202                        addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop);
 203                } else if (matches(*argv, "mcast_query_use_ifaddr") == 0) {
 204                        __u8 mcast_qui;
 205
 206                        NEXT_ARG();
 207                        if (get_u8(&mcast_qui, *argv, 0))
 208                                invarg("invalid mcast_query_use_ifaddr",
 209                                       *argv);
 210
 211                        addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR,
 212                                 mcast_qui);
 213                } else if (matches(*argv, "mcast_querier") == 0) {
 214                        __u8 mcast_querier;
 215
 216                        NEXT_ARG();
 217                        if (get_u8(&mcast_querier, *argv, 0))
 218                                invarg("invalid mcast_querier", *argv);
 219
 220                        addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier);
 221                } else if (matches(*argv, "mcast_hash_elasticity") == 0) {
 222                        __u32 mcast_hash_el;
 223
 224                        NEXT_ARG();
 225                        if (get_u32(&mcast_hash_el, *argv, 0))
 226                                invarg("invalid mcast_hash_elasticity",
 227                                       *argv);
 228
 229                        addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY,
 230                                  mcast_hash_el);
 231                } else if (matches(*argv, "mcast_hash_max") == 0) {
 232                        __u32 mcast_hash_max;
 233
 234                        NEXT_ARG();
 235                        if (get_u32(&mcast_hash_max, *argv, 0))
 236                                invarg("invalid mcast_hash_max", *argv);
 237
 238                        addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX,
 239                                  mcast_hash_max);
 240                } else if (matches(*argv, "mcast_last_member_count") == 0) {
 241                        __u32 mcast_lmc;
 242
 243                        NEXT_ARG();
 244                        if (get_u32(&mcast_lmc, *argv, 0))
 245                                invarg("invalid mcast_last_member_count",
 246                                       *argv);
 247
 248                        addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT,
 249                                  mcast_lmc);
 250                } else if (matches(*argv, "mcast_startup_query_count") == 0) {
 251                        __u32 mcast_sqc;
 252
 253                        NEXT_ARG();
 254                        if (get_u32(&mcast_sqc, *argv, 0))
 255                                invarg("invalid mcast_startup_query_count",
 256                                       *argv);
 257
 258                        addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT,
 259                                  mcast_sqc);
 260                } else if (matches(*argv, "mcast_last_member_interval") == 0) {
 261                        __u64 mcast_last_member_intvl;
 262
 263                        NEXT_ARG();
 264                        if (get_u64(&mcast_last_member_intvl, *argv, 0))
 265                                invarg("invalid mcast_last_member_interval",
 266                                       *argv);
 267
 268                        addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL,
 269                                  mcast_last_member_intvl);
 270                } else if (matches(*argv, "mcast_membership_interval") == 0) {
 271                        __u64 mcast_membership_intvl;
 272
 273                        NEXT_ARG();
 274                        if (get_u64(&mcast_membership_intvl, *argv, 0))
 275                                invarg("invalid mcast_membership_interval",
 276                                       *argv);
 277
 278                        addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL,
 279                                  mcast_membership_intvl);
 280                } else if (matches(*argv, "mcast_querier_interval") == 0) {
 281                        __u64 mcast_querier_intvl;
 282
 283                        NEXT_ARG();
 284                        if (get_u64(&mcast_querier_intvl, *argv, 0))
 285                                invarg("invalid mcast_querier_interval",
 286                                       *argv);
 287
 288                        addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL,
 289                                  mcast_querier_intvl);
 290                } else if (matches(*argv, "mcast_query_interval") == 0) {
 291                        __u64 mcast_query_intvl;
 292
 293                        NEXT_ARG();
 294                        if (get_u64(&mcast_query_intvl, *argv, 0))
 295                                invarg("invalid mcast_query_interval",
 296                                       *argv);
 297
 298                        addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL,
 299                                  mcast_query_intvl);
 300                } else if (!matches(*argv, "mcast_query_response_interval")) {
 301                        __u64 mcast_query_resp_intvl;
 302
 303                        NEXT_ARG();
 304                        if (get_u64(&mcast_query_resp_intvl, *argv, 0))
 305                                invarg("invalid mcast_query_response_interval",
 306                                       *argv);
 307
 308                        addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
 309                                  mcast_query_resp_intvl);
 310                } else if (!matches(*argv, "mcast_startup_query_interval")) {
 311                        __u64 mcast_startup_query_intvl;
 312
 313                        NEXT_ARG();
 314                        if (get_u64(&mcast_startup_query_intvl, *argv, 0))
 315                                invarg("invalid mcast_startup_query_interval",
 316                                       *argv);
 317
 318                        addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
 319                                  mcast_startup_query_intvl);
 320                } else if (matches(*argv, "mcast_stats_enabled") == 0) {
 321                        __u8 mcast_stats_enabled;
 322
 323                        NEXT_ARG();
 324                        if (get_u8(&mcast_stats_enabled, *argv, 0))
 325                                invarg("invalid mcast_stats_enabled", *argv);
 326                        addattr8(n, 1024, IFLA_BR_MCAST_STATS_ENABLED,
 327                                  mcast_stats_enabled);
 328                } else if (matches(*argv, "mcast_igmp_version") == 0) {
 329                        __u8 igmp_version;
 330
 331                        NEXT_ARG();
 332                        if (get_u8(&igmp_version, *argv, 0))
 333                                invarg("invalid mcast_igmp_version", *argv);
 334                        addattr8(n, 1024, IFLA_BR_MCAST_IGMP_VERSION,
 335                                  igmp_version);
 336                } else if (matches(*argv, "mcast_mld_version") == 0) {
 337                        __u8 mld_version;
 338
 339                        NEXT_ARG();
 340                        if (get_u8(&mld_version, *argv, 0))
 341                                invarg("invalid mcast_mld_version", *argv);
 342                        addattr8(n, 1024, IFLA_BR_MCAST_MLD_VERSION,
 343                                  mld_version);
 344                } else if (matches(*argv, "nf_call_iptables") == 0) {
 345                        __u8 nf_call_ipt;
 346
 347                        NEXT_ARG();
 348                        if (get_u8(&nf_call_ipt, *argv, 0))
 349                                invarg("invalid nf_call_iptables", *argv);
 350
 351                        addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES,
 352                                 nf_call_ipt);
 353                } else if (matches(*argv, "nf_call_ip6tables") == 0) {
 354                        __u8 nf_call_ip6t;
 355
 356                        NEXT_ARG();
 357                        if (get_u8(&nf_call_ip6t, *argv, 0))
 358                                invarg("invalid nf_call_ip6tables", *argv);
 359
 360                        addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES,
 361                                 nf_call_ip6t);
 362                } else if (matches(*argv, "nf_call_arptables") == 0) {
 363                        __u8 nf_call_arpt;
 364
 365                        NEXT_ARG();
 366                        if (get_u8(&nf_call_arpt, *argv, 0))
 367                                invarg("invalid nf_call_arptables", *argv);
 368
 369                        addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES,
 370                                 nf_call_arpt);
 371                } else if (matches(*argv, "help") == 0) {
 372                        explain();
 373                        return -1;
 374                } else {
 375                        fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
 376                        explain();
 377                        return -1;
 378                }
 379                argc--, argv++;
 380        }
 381
 382        return 0;
 383}
 384
 385static void _bridge_print_timer(FILE *f,
 386                                const char *attr,
 387                                struct rtattr *timer)
 388{
 389        struct timeval tv;
 390
 391        __jiffies_to_tv(&tv, rta_getattr_u64(timer));
 392        if (is_json_context()) {
 393                json_writer_t *jw = get_json_writer();
 394
 395                jsonw_name(jw, attr);
 396                jsonw_printf(jw, "%i.%.2i",
 397                             (int)tv.tv_sec,
 398                             (int)tv.tv_usec / 10000);
 399        } else {
 400                fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
 401                        (int)tv.tv_usec / 10000);
 402        }
 403}
 404
 405static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 406{
 407        if (!tb)
 408                return;
 409
 410        if (tb[IFLA_BR_FORWARD_DELAY])
 411                print_uint(PRINT_ANY,
 412                           "forward_delay",
 413                           "forward_delay %u ",
 414                           rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
 415
 416        if (tb[IFLA_BR_HELLO_TIME])
 417                print_uint(PRINT_ANY,
 418                           "hello_time",
 419                           "hello_time %u ",
 420                           rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
 421
 422        if (tb[IFLA_BR_MAX_AGE])
 423                print_uint(PRINT_ANY,
 424                           "max_age",
 425                           "max_age %u ",
 426                           rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
 427
 428        if (tb[IFLA_BR_AGEING_TIME])
 429                print_uint(PRINT_ANY,
 430                           "ageing_time",
 431                           "ageing_time %u ",
 432                           rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
 433
 434        if (tb[IFLA_BR_STP_STATE])
 435                print_uint(PRINT_ANY,
 436                           "stp_state",
 437                           "stp_state %u ",
 438                           rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
 439
 440        if (tb[IFLA_BR_PRIORITY])
 441                print_uint(PRINT_ANY,
 442                           "priority",
 443                           "priority %u ",
 444                           rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
 445
 446        if (tb[IFLA_BR_VLAN_FILTERING])
 447                print_uint(PRINT_ANY,
 448                           "vlan_filtering",
 449                           "vlan_filtering %u ",
 450                           rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
 451
 452        if (tb[IFLA_BR_VLAN_PROTOCOL]) {
 453                SPRINT_BUF(b1);
 454
 455                print_string(PRINT_ANY,
 456                             "vlan_protocol",
 457                             "vlan_protocol %s ",
 458                             ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
 459                                          b1, sizeof(b1)));
 460        }
 461
 462        if (tb[IFLA_BR_BRIDGE_ID]) {
 463                char bridge_id[32];
 464
 465                br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
 466                                  sizeof(bridge_id));
 467                print_string(PRINT_ANY,
 468                             "bridge_id",
 469                             "bridge_id %s ",
 470                             bridge_id);
 471        }
 472
 473        if (tb[IFLA_BR_ROOT_ID]) {
 474                char root_id[32];
 475
 476                br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
 477                                  sizeof(root_id));
 478                print_string(PRINT_ANY,
 479                             "root_id",
 480                             "designated_root %s ",
 481                             root_id);
 482        }
 483
 484        if (tb[IFLA_BR_ROOT_PORT])
 485                print_uint(PRINT_ANY,
 486                           "root_port",
 487                           "root_port %u ",
 488                           rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
 489
 490        if (tb[IFLA_BR_ROOT_PATH_COST])
 491                print_uint(PRINT_ANY,
 492                           "root_path_cost",
 493                           "root_path_cost %u ",
 494                           rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
 495
 496        if (tb[IFLA_BR_TOPOLOGY_CHANGE])
 497                print_uint(PRINT_ANY,
 498                           "topology_change",
 499                           "topology_change %u ",
 500                           rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
 501
 502        if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
 503                print_uint(PRINT_ANY,
 504                           "topology_change_detected",
 505                           "topology_change_detected %u ",
 506                           rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
 507
 508        if (tb[IFLA_BR_HELLO_TIMER])
 509                _bridge_print_timer(f, "hello_timer", tb[IFLA_BR_HELLO_TIMER]);
 510
 511        if (tb[IFLA_BR_TCN_TIMER])
 512                _bridge_print_timer(f, "tcn_timer", tb[IFLA_BR_TCN_TIMER]);
 513
 514        if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER])
 515                _bridge_print_timer(f, "topology_change_timer",
 516                                    tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
 517
 518        if (tb[IFLA_BR_GC_TIMER])
 519                _bridge_print_timer(f, "gc_timer", tb[IFLA_BR_GC_TIMER]);
 520
 521        if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
 522                print_uint(PRINT_ANY,
 523                           "vlan_default_pvid",
 524                           "vlan_default_pvid %u ",
 525                           rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
 526
 527        if (tb[IFLA_BR_VLAN_STATS_ENABLED])
 528                print_uint(PRINT_ANY,
 529                           "vlan_stats_enabled",
 530                           "vlan_stats_enabled %u ",
 531                           rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
 532
 533        if (tb[IFLA_BR_VLAN_STATS_PER_PORT])
 534                print_uint(PRINT_ANY,
 535                           "vlan_stats_per_port",
 536                           "vlan_stats_per_port %u ",
 537                           rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_PER_PORT]));
 538
 539        if (tb[IFLA_BR_GROUP_FWD_MASK])
 540                print_0xhex(PRINT_ANY,
 541                            "group_fwd_mask",
 542                            "group_fwd_mask %#llx ",
 543                            rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
 544
 545        if (tb[IFLA_BR_GROUP_ADDR]) {
 546                SPRINT_BUF(mac);
 547
 548                print_string(PRINT_ANY,
 549                             "group_addr",
 550                             "group_address %s ",
 551                             ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
 552                                         RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
 553                                         1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
 554        }
 555
 556        if (tb[IFLA_BR_MCAST_SNOOPING])
 557                print_uint(PRINT_ANY,
 558                           "mcast_snooping",
 559                           "mcast_snooping %u ",
 560                           rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
 561
 562        if (tb[IFLA_BR_MCAST_ROUTER])
 563                print_uint(PRINT_ANY,
 564                           "mcast_router",
 565                           "mcast_router %u ",
 566                           rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
 567
 568        if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
 569                print_uint(PRINT_ANY,
 570                           "mcast_query_use_ifaddr",
 571                           "mcast_query_use_ifaddr %u ",
 572                           rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
 573
 574        if (tb[IFLA_BR_MCAST_QUERIER])
 575                print_uint(PRINT_ANY,
 576                           "mcast_querier",
 577                           "mcast_querier %u ",
 578                           rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
 579
 580        if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
 581                print_uint(PRINT_ANY,
 582                           "mcast_hash_elasticity",
 583                           "mcast_hash_elasticity %u ",
 584                           rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
 585
 586        if (tb[IFLA_BR_MCAST_HASH_MAX])
 587                print_uint(PRINT_ANY,
 588                           "mcast_hash_max",
 589                           "mcast_hash_max %u ",
 590                           rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
 591
 592        if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
 593                print_uint(PRINT_ANY,
 594                           "mcast_last_member_cnt",
 595                           "mcast_last_member_count %u ",
 596                           rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
 597
 598        if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])
 599                print_uint(PRINT_ANY,
 600                           "mcast_startup_query_cnt",
 601                           "mcast_startup_query_count %u ",
 602                           rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
 603
 604        if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])
 605                print_lluint(PRINT_ANY,
 606                             "mcast_last_member_intvl",
 607                             "mcast_last_member_interval %llu ",
 608                             rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
 609
 610        if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])
 611                print_lluint(PRINT_ANY,
 612                             "mcast_membership_intvl",
 613                             "mcast_membership_interval %llu ",
 614                             rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
 615
 616        if (tb[IFLA_BR_MCAST_QUERIER_INTVL])
 617                print_lluint(PRINT_ANY,
 618                             "mcast_querier_intvl",
 619                             "mcast_querier_interval %llu ",
 620                             rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
 621
 622        if (tb[IFLA_BR_MCAST_QUERY_INTVL])
 623                print_lluint(PRINT_ANY,
 624                             "mcast_query_intvl",
 625                             "mcast_query_interval %llu ",
 626                             rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
 627
 628        if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])
 629                print_lluint(PRINT_ANY,
 630                             "mcast_query_response_intvl",
 631                             "mcast_query_response_interval %llu ",
 632                             rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
 633
 634        if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])
 635                print_lluint(PRINT_ANY,
 636                             "mcast_startup_query_intvl",
 637                             "mcast_startup_query_interval %llu ",
 638                             rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
 639
 640        if (tb[IFLA_BR_MCAST_STATS_ENABLED])
 641                print_uint(PRINT_ANY,
 642                           "mcast_stats_enabled",
 643                           "mcast_stats_enabled %u ",
 644                           rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
 645
 646        if (tb[IFLA_BR_MCAST_IGMP_VERSION])
 647                print_uint(PRINT_ANY,
 648                           "mcast_igmp_version",
 649                           "mcast_igmp_version %u ",
 650                           rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
 651
 652        if (tb[IFLA_BR_MCAST_MLD_VERSION])
 653                print_uint(PRINT_ANY,
 654                           "mcast_mld_version",
 655                           "mcast_mld_version %u ",
 656                           rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
 657
 658        if (tb[IFLA_BR_NF_CALL_IPTABLES])
 659                print_uint(PRINT_ANY,
 660                           "nf_call_iptables",
 661                           "nf_call_iptables %u ",
 662                           rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
 663
 664        if (tb[IFLA_BR_NF_CALL_IP6TABLES])
 665                print_uint(PRINT_ANY,
 666                           "nf_call_ip6tables",
 667                           "nf_call_ip6tables %u ",
 668                           rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
 669
 670        if (tb[IFLA_BR_NF_CALL_ARPTABLES])
 671                print_uint(PRINT_ANY,
 672                           "nf_call_arptables",
 673                           "nf_call_arptables %u ",
 674                           rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
 675}
 676
 677static void bridge_print_help(struct link_util *lu, int argc, char **argv,
 678                              FILE *f)
 679{
 680        print_explain(f);
 681}
 682
 683static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
 684{
 685        fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
 686}
 687
 688static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
 689{
 690        struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
 691        struct bridge_stp_xstats *sstats;
 692        struct br_mcast_stats *mstats;
 693        struct rtattr *i, *list;
 694        const char *ifname = "";
 695        int rem;
 696
 697        parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
 698        RTA_PAYLOAD(attr));
 699        if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
 700                return;
 701
 702        list = brtb[LINK_XSTATS_TYPE_BRIDGE];
 703        rem = RTA_PAYLOAD(list);
 704        open_json_object(NULL);
 705        ifname = ll_index_to_name(ifindex);
 706        print_string(PRINT_ANY, "ifname", "%-16s\n", ifname);
 707        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 708                if (xstats_print_attr && i->rta_type != xstats_print_attr)
 709                        continue;
 710                switch (i->rta_type) {
 711                case BRIDGE_XSTATS_MCAST:
 712                        mstats = RTA_DATA(i);
 713                        open_json_object("multicast");
 714                        open_json_object("igmp_queries");
 715                        print_string(PRINT_FP, NULL,
 716                                     "%-16s    IGMP queries:\n", "");
 717                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 718                        print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
 719                                  mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
 720                        print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
 721                                  mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
 722                        print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
 723                                  mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
 724                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 725                        print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
 726                                  mstats->igmp_v1queries[BR_MCAST_DIR_TX]);
 727                        print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
 728                                  mstats->igmp_v2queries[BR_MCAST_DIR_TX]);
 729                        print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
 730                                  mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
 731                        close_json_object();
 732
 733                        open_json_object("igmp_reports");
 734                        print_string(PRINT_FP, NULL,
 735                                     "%-16s    IGMP reports:\n", "");
 736                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 737                        print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
 738                                  mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
 739                        print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
 740                                  mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
 741                        print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
 742                                  mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
 743                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 744                        print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
 745                                  mstats->igmp_v1reports[BR_MCAST_DIR_TX]);
 746                        print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
 747                                  mstats->igmp_v2reports[BR_MCAST_DIR_TX]);
 748                        print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
 749                                  mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
 750                        close_json_object();
 751
 752                        open_json_object("igmp_leaves");
 753                        print_string(PRINT_FP, NULL,
 754                                     "%-16s    IGMP leaves: ", "");
 755                        print_u64(PRINT_ANY, "rx", "RX: %llu ",
 756                                  mstats->igmp_leaves[BR_MCAST_DIR_RX]);
 757                        print_u64(PRINT_ANY, "tx", "TX: %llu\n",
 758                                  mstats->igmp_leaves[BR_MCAST_DIR_TX]);
 759                        close_json_object();
 760
 761                        print_string(PRINT_FP, NULL,
 762                                     "%-16s    IGMP parse errors: ", "");
 763                        print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
 764                                  mstats->igmp_parse_errors);
 765
 766                        open_json_object("mld_queries");
 767                        print_string(PRINT_FP, NULL,
 768                                     "%-16s    MLD queries:\n", "");
 769                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 770                        print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
 771                                  mstats->mld_v1queries[BR_MCAST_DIR_RX]);
 772                        print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
 773                                  mstats->mld_v2queries[BR_MCAST_DIR_RX]);
 774                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 775                        print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
 776                                  mstats->mld_v1queries[BR_MCAST_DIR_TX]);
 777                        print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
 778                                  mstats->mld_v2queries[BR_MCAST_DIR_TX]);
 779                        close_json_object();
 780
 781                        open_json_object("mld_reports");
 782                        print_string(PRINT_FP, NULL,
 783                                     "%-16s    MLD reports:\n", "");
 784                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 785                        print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
 786                                  mstats->mld_v1reports[BR_MCAST_DIR_RX]);
 787                        print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
 788                                  mstats->mld_v2reports[BR_MCAST_DIR_RX]);
 789                        print_string(PRINT_FP, NULL, "%-16s      ", "");
 790                        print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
 791                                  mstats->mld_v1reports[BR_MCAST_DIR_TX]);
 792                        print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
 793                                  mstats->mld_v2reports[BR_MCAST_DIR_TX]);
 794                        close_json_object();
 795
 796                        open_json_object("mld_leaves");
 797                        print_string(PRINT_FP, NULL,
 798                                     "%-16s    MLD leaves: ", "");
 799                        print_u64(PRINT_ANY, "rx", "RX: %llu ",
 800                                  mstats->mld_leaves[BR_MCAST_DIR_RX]);
 801                        print_u64(PRINT_ANY, "tx", "TX: %llu\n",
 802                                  mstats->mld_leaves[BR_MCAST_DIR_TX]);
 803                        close_json_object();
 804
 805                        print_string(PRINT_FP, NULL,
 806                                     "%-16s    MLD parse errors: ", "");
 807                        print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
 808                                  mstats->mld_parse_errors);
 809                        close_json_object();
 810                        break;
 811                case BRIDGE_XSTATS_STP:
 812                        sstats = RTA_DATA(i);
 813                        open_json_object("stp");
 814                        print_string(PRINT_FP, NULL,
 815                                     "%-16s    STP BPDU:  ", "");
 816                        print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ",
 817                                  sstats->rx_bpdu);
 818                        print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n",
 819                                  sstats->tx_bpdu);
 820                        print_string(PRINT_FP, NULL,
 821                                     "%-16s    STP TCN:   ", "");
 822                        print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ",
 823                                  sstats->rx_tcn);
 824                        print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n",
 825                                  sstats->tx_tcn);
 826                        print_string(PRINT_FP, NULL,
 827                                     "%-16s    STP Transitions: ", "");
 828                        print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ",
 829                                  sstats->transition_blk);
 830                        print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n",
 831                                  sstats->transition_fwd);
 832                        close_json_object();
 833                        break;
 834                }
 835        }
 836        close_json_object();
 837}
 838
 839int bridge_print_xstats(struct nlmsghdr *n, void *arg)
 840{
 841        struct if_stats_msg *ifsm = NLMSG_DATA(n);
 842        struct rtattr *tb[IFLA_STATS_MAX+1];
 843        int len = n->nlmsg_len;
 844
 845        len -= NLMSG_LENGTH(sizeof(*ifsm));
 846        if (len < 0) {
 847                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 848                return -1;
 849        }
 850        if (filter_index && filter_index != ifsm->ifindex)
 851                return 0;
 852
 853        parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
 854        if (tb[IFLA_STATS_LINK_XSTATS])
 855                bridge_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
 856                                        ifsm->ifindex);
 857
 858        if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
 859                bridge_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
 860                                        ifsm->ifindex);
 861
 862        return 0;
 863}
 864
 865int bridge_parse_xstats(struct link_util *lu, int argc, char **argv)
 866{
 867        while (argc > 0) {
 868                if (strcmp(*argv, "igmp") == 0 || strcmp(*argv, "mcast") == 0) {
 869                        xstats_print_attr = BRIDGE_XSTATS_MCAST;
 870                } else if (strcmp(*argv, "stp") == 0) {
 871                        xstats_print_attr = BRIDGE_XSTATS_STP;
 872                } else if (strcmp(*argv, "dev") == 0) {
 873                        NEXT_ARG();
 874                        filter_index = ll_name_to_index(*argv);
 875                        if (!filter_index)
 876                                return nodev(*argv);
 877                } else if (strcmp(*argv, "help") == 0) {
 878                        bridge_print_xstats_help(lu, stdout);
 879                        exit(0);
 880                } else {
 881                        invarg("unknown attribute", *argv);
 882                }
 883                argc--; argv++;
 884        }
 885
 886        return 0;
 887}
 888
 889struct link_util bridge_link_util = {
 890        .id             = "bridge",
 891        .maxattr        = IFLA_BR_MAX,
 892        .parse_opt      = bridge_parse_opt,
 893        .print_opt      = bridge_print_opt,
 894        .print_help     = bridge_print_help,
 895        .parse_ifla_xstats = bridge_parse_xstats,
 896        .print_ifla_xstats = bridge_print_xstats,
 897};
 898