iproute2/bridge/vlan.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#include <stdio.h>
   3#include <stdlib.h>
   4#include <unistd.h>
   5#include <fcntl.h>
   6#include <sys/socket.h>
   7#include <sys/time.h>
   8#include <net/if.h>
   9#include <netinet/in.h>
  10#include <linux/if_bridge.h>
  11#include <linux/if_ether.h>
  12#include <string.h>
  13#include <errno.h>
  14
  15#include "json_print.h"
  16#include "libnetlink.h"
  17#include "br_common.h"
  18#include "utils.h"
  19
  20static unsigned int filter_index, filter_vlan;
  21static int vlan_rtm_cur_ifidx = -1;
  22static void print_vlan_info(struct rtattr *tb, int ifindex);
  23
  24enum vlan_show_subject {
  25        VLAN_SHOW_VLAN,
  26        VLAN_SHOW_TUNNELINFO,
  27};
  28
  29#define VLAN_ID_LEN 9
  30
  31static void usage(void)
  32{
  33        fprintf(stderr,
  34                "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ tunnel_info id TUNNEL_ID ]\n"
  35                "                                                     [ pvid ] [ untagged ]\n"
  36                "                                                     [ self ] [ master ]\n"
  37                "       bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
  38                "                                               [ mcast_router MULTICAST_ROUTER ]\n"
  39                "                                               [ mcast_max_groups MAX_GROUPS ]\n"
  40                "                                               [ neigh_suppress {on | off} ]\n"
  41                "       bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
  42                "       bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n"
  43                "       bridge vlan global { set } vid VLAN_ID dev DEV\n"
  44                "                      [ mcast_snooping MULTICAST_SNOOPING ]\n"
  45                "                      [ mcast_querier MULTICAST_QUERIER ]\n"
  46                "                      [ mcast_igmp_version IGMP_VERSION ]\n"
  47                "                      [ mcast_mld_version MLD_VERSION ]\n"
  48                "                      [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
  49                "                      [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
  50                "                      [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
  51                "                      [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
  52                "                      [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
  53                "                      [ mcast_querier_interval QUERIER_INTERVAL ]\n"
  54                "                      [ mcast_query_interval QUERY_INTERVAL ]\n"
  55                "                      [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
  56                "                      [ msti MSTI ]\n"
  57                "       bridge vlan global { show } [ dev DEV ] [ vid VLAN_ID ]\n");
  58        exit(-1);
  59}
  60
  61static int parse_tunnel_info(int *argcp, char ***argvp, __u32 *tun_id_start,
  62                             __u32 *tun_id_end)
  63{
  64        char **argv = *argvp;
  65        int argc = *argcp;
  66        char *t;
  67
  68        NEXT_ARG();
  69        if (!matches(*argv, "id")) {
  70                NEXT_ARG();
  71                t = strchr(*argv, '-');
  72                if (t) {
  73                        *t = '\0';
  74                        if (get_u32(tun_id_start, *argv, 0) ||
  75                                    *tun_id_start >= 1u << 24)
  76                                invarg("invalid tun id", *argv);
  77                        if (get_u32(tun_id_end, t + 1, 0) ||
  78                                    *tun_id_end >= 1u << 24)
  79                                invarg("invalid tun id", *argv);
  80
  81                } else {
  82                        if (get_u32(tun_id_start, *argv, 0) ||
  83                                    *tun_id_start >= 1u << 24)
  84                                invarg("invalid tun id", *argv);
  85                }
  86        } else {
  87                invarg("tunnel id expected", *argv);
  88        }
  89
  90        *argcp = argc;
  91        *argvp = argv;
  92
  93        return 0;
  94}
  95
  96static int add_tunnel_info(struct nlmsghdr *n, int reqsize,
  97                           __u16 vid, __u32 tun_id, __u16 flags)
  98{
  99        struct rtattr *tinfo;
 100
 101        tinfo = addattr_nest(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
 102        addattr32(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_ID, tun_id);
 103        addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_VID, vid);
 104        addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, flags);
 105
 106        addattr_nest_end(n, tinfo);
 107
 108        return 0;
 109}
 110
 111static int add_tunnel_info_range(struct nlmsghdr *n, int reqsize,
 112                                 __u16 vid_start, int16_t vid_end,
 113                                 __u32 tun_id_start, __u32 tun_id_end)
 114{
 115        if (vid_end != -1 && (vid_end - vid_start) > 0) {
 116                add_tunnel_info(n, reqsize, vid_start, tun_id_start,
 117                                BRIDGE_VLAN_INFO_RANGE_BEGIN);
 118
 119                add_tunnel_info(n, reqsize, vid_end, tun_id_end,
 120                                BRIDGE_VLAN_INFO_RANGE_END);
 121        } else {
 122                add_tunnel_info(n, reqsize, vid_start, tun_id_start, 0);
 123        }
 124
 125        return 0;
 126}
 127
 128static int add_vlan_info_range(struct nlmsghdr *n, int reqsize, __u16 vid_start,
 129                               int16_t vid_end, __u16 flags)
 130{
 131        struct bridge_vlan_info vinfo = {};
 132
 133        vinfo.flags = flags;
 134        vinfo.vid = vid_start;
 135        if (vid_end != -1) {
 136                /* send vlan range start */
 137                addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
 138                          sizeof(vinfo));
 139                vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
 140
 141                /* Now send the vlan range end */
 142                vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
 143                vinfo.vid = vid_end;
 144                addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
 145                          sizeof(vinfo));
 146        } else {
 147                addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
 148                          sizeof(vinfo));
 149        }
 150
 151        return 0;
 152}
 153
 154static int vlan_modify(int cmd, int argc, char **argv)
 155{
 156        struct {
 157                struct nlmsghdr n;
 158                struct ifinfomsg        ifm;
 159                char                    buf[1024];
 160        } req = {
 161                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 162                .n.nlmsg_flags = NLM_F_REQUEST,
 163                .n.nlmsg_type = cmd,
 164                .ifm.ifi_family = PF_BRIDGE,
 165        };
 166        char *d = NULL;
 167        short vid = -1;
 168        short vid_end = -1;
 169        struct rtattr *afspec;
 170        struct bridge_vlan_info vinfo = {};
 171        bool tunnel_info_set = false;
 172        unsigned short flags = 0;
 173        __u32 tun_id_start = 0;
 174        __u32 tun_id_end = 0;
 175
 176        while (argc > 0) {
 177                if (strcmp(*argv, "dev") == 0) {
 178                        NEXT_ARG();
 179                        d = *argv;
 180                } else if (strcmp(*argv, "vid") == 0) {
 181                        char *p;
 182
 183                        NEXT_ARG();
 184                        p = strchr(*argv, '-');
 185                        if (p) {
 186                                *p = '\0';
 187                                p++;
 188                                vid = atoi(*argv);
 189                                vid_end = atoi(p);
 190                                vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
 191                        } else {
 192                                vid = atoi(*argv);
 193                        }
 194                } else if (strcmp(*argv, "self") == 0) {
 195                        flags |= BRIDGE_FLAGS_SELF;
 196                } else if (strcmp(*argv, "master") == 0) {
 197                        flags |= BRIDGE_FLAGS_MASTER;
 198                } else if (strcmp(*argv, "pvid") == 0) {
 199                        vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
 200                } else if (strcmp(*argv, "untagged") == 0) {
 201                        vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
 202                } else if (strcmp(*argv, "tunnel_info") == 0) {
 203                                if (parse_tunnel_info(&argc, &argv,
 204                                                      &tun_id_start,
 205                                                      &tun_id_end))
 206                                        return -1;
 207                                tunnel_info_set = true;
 208                } else {
 209                        if (matches(*argv, "help") == 0)
 210                                NEXT_ARG();
 211                }
 212                argc--; argv++;
 213        }
 214
 215        if (d == NULL || vid == -1) {
 216                fprintf(stderr, "Device and VLAN ID are required arguments.\n");
 217                return -1;
 218        }
 219
 220        req.ifm.ifi_index = ll_name_to_index(d);
 221        if (req.ifm.ifi_index == 0) {
 222                fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
 223                return -1;
 224        }
 225
 226        if (vid >= 4096) {
 227                fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
 228                return -1;
 229        }
 230
 231        if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
 232                if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
 233                        fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
 234                                vid, vid_end);
 235                        return -1;
 236                }
 237                if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
 238                        fprintf(stderr,
 239                                "pvid cannot be configured for a vlan range\n");
 240                        return -1;
 241                }
 242        }
 243
 244        afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
 245
 246        if (flags)
 247                addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
 248
 249        if (tunnel_info_set)
 250                add_tunnel_info_range(&req.n, sizeof(req), vid, vid_end,
 251                                      tun_id_start, tun_id_end);
 252        else
 253                add_vlan_info_range(&req.n, sizeof(req), vid, vid_end,
 254                                    vinfo.flags);
 255
 256        addattr_nest_end(&req.n, afspec);
 257
 258        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 259                return -1;
 260
 261        return 0;
 262}
 263
 264static int vlan_option_set(int argc, char **argv)
 265{
 266        struct {
 267                struct nlmsghdr n;
 268                struct br_vlan_msg      bvm;
 269                char                    buf[1024];
 270        } req = {
 271                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
 272                .n.nlmsg_flags = NLM_F_REQUEST,
 273                .n.nlmsg_type = RTM_NEWVLAN,
 274                .bvm.family = PF_BRIDGE,
 275        };
 276        struct bridge_vlan_info vinfo = {};
 277        struct rtattr *afspec;
 278        char *d = NULL;
 279        short vid = -1;
 280
 281        afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
 282        afspec->rta_type |= NLA_F_NESTED;
 283        while (argc > 0) {
 284                if (strcmp(*argv, "dev") == 0) {
 285                        NEXT_ARG();
 286                        d = *argv;
 287                        req.bvm.ifindex = ll_name_to_index(d);
 288                        if (req.bvm.ifindex == 0) {
 289                                fprintf(stderr,
 290                                        "Cannot find network device \"%s\"\n",
 291                                        d);
 292                                return -1;
 293                        }
 294                } else if (strcmp(*argv, "vid") == 0) {
 295                        short vid_end = -1;
 296                        char *p;
 297
 298                        NEXT_ARG();
 299                        p = strchr(*argv, '-');
 300                        if (p) {
 301                                *p = '\0';
 302                                p++;
 303                                vid = atoi(*argv);
 304                                vid_end = atoi(p);
 305                                if (vid >= vid_end || vid_end >= 4096) {
 306                                        fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
 307                                                vid, vid_end);
 308                                        return -1;
 309                                }
 310                        } else {
 311                                vid = atoi(*argv);
 312                        }
 313                        if (vid >= 4096) {
 314                                fprintf(stderr, "Invalid VLAN ID \"%hu\"\n",
 315                                        vid);
 316                                return -1;
 317                        }
 318
 319                        vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
 320                        vinfo.vid = vid;
 321                        addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO,
 322                                  &vinfo, sizeof(vinfo));
 323                        if (vid_end != -1)
 324                                addattr16(&req.n, sizeof(req),
 325                                          BRIDGE_VLANDB_ENTRY_RANGE, vid_end);
 326                } else if (strcmp(*argv, "state") == 0) {
 327                        char *endptr;
 328                        int state;
 329
 330                        NEXT_ARG();
 331                        state = strtol(*argv, &endptr, 10);
 332                        if (!(**argv != '\0' && *endptr == '\0'))
 333                                state = parse_stp_state(*argv);
 334                        if (state == -1) {
 335                                fprintf(stderr, "Error: invalid STP state\n");
 336                                return -1;
 337                        }
 338                        addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE,
 339                                 state);
 340                } else if (strcmp(*argv, "mcast_router") == 0) {
 341                        __u8 mcast_router;
 342
 343                        NEXT_ARG();
 344                        if (get_u8(&mcast_router, *argv, 0))
 345                                invarg("invalid mcast_router", *argv);
 346                        addattr8(&req.n, sizeof(req),
 347                                 BRIDGE_VLANDB_ENTRY_MCAST_ROUTER,
 348                                 mcast_router);
 349                } else if (strcmp(*argv, "mcast_max_groups") == 0) {
 350                        __u32 max_groups;
 351
 352                        NEXT_ARG();
 353                        if (get_u32(&max_groups, *argv, 0))
 354                                invarg("invalid mcast_max_groups", *argv);
 355                        addattr32(&req.n, sizeof(req),
 356                                  BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS,
 357                                  max_groups);
 358                } else if (strcmp(*argv, "neigh_suppress") == 0) {
 359                        bool neigh_suppress;
 360                        int ret;
 361
 362                        NEXT_ARG();
 363                        neigh_suppress = parse_on_off("neigh_suppress", *argv,
 364                                                      &ret);
 365                        if (ret)
 366                                return ret;
 367                        addattr8(&req.n, sizeof(req),
 368                                 BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS,
 369                                 neigh_suppress);
 370                } else {
 371                        if (matches(*argv, "help") == 0)
 372                                NEXT_ARG();
 373                }
 374                argc--; argv++;
 375        }
 376        addattr_nest_end(&req.n, afspec);
 377
 378        if (d == NULL || vid == -1) {
 379                fprintf(stderr, "Device and VLAN ID are required arguments.\n");
 380                return -1;
 381        }
 382
 383        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 384                return -1;
 385
 386        return 0;
 387}
 388
 389static int vlan_global_option_set(int argc, char **argv)
 390{
 391        struct {
 392                struct nlmsghdr n;
 393                struct br_vlan_msg      bvm;
 394                char                    buf[1024];
 395        } req = {
 396                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
 397                .n.nlmsg_flags = NLM_F_REQUEST,
 398                .n.nlmsg_type = RTM_NEWVLAN,
 399                .bvm.family = PF_BRIDGE,
 400        };
 401        struct rtattr *afspec;
 402        short vid_end = -1;
 403        char *d = NULL;
 404        short vid = -1;
 405        __u64 val64;
 406        __u32 val32;
 407        __u16 val16;
 408        __u8 val8;
 409
 410        afspec = addattr_nest(&req.n, sizeof(req),
 411                              BRIDGE_VLANDB_GLOBAL_OPTIONS);
 412        afspec->rta_type |= NLA_F_NESTED;
 413        while (argc > 0) {
 414                if (strcmp(*argv, "dev") == 0) {
 415                        NEXT_ARG();
 416                        d = *argv;
 417                        req.bvm.ifindex = ll_name_to_index(d);
 418                        if (req.bvm.ifindex == 0) {
 419                                fprintf(stderr, "Cannot find network device \"%s\"\n",
 420                                        d);
 421                                return -1;
 422                        }
 423                } else if (strcmp(*argv, "vid") == 0) {
 424                        char *p;
 425
 426                        NEXT_ARG();
 427                        p = strchr(*argv, '-');
 428                        if (p) {
 429                                *p = '\0';
 430                                p++;
 431                                vid = atoi(*argv);
 432                                vid_end = atoi(p);
 433                                if (vid >= vid_end || vid_end >= 4096) {
 434                                        fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
 435                                                vid, vid_end);
 436                                        return -1;
 437                                }
 438                        } else {
 439                                vid = atoi(*argv);
 440                        }
 441                        if (vid >= 4096) {
 442                                fprintf(stderr, "Invalid VLAN ID \"%hu\"\n",
 443                                        vid);
 444                                return -1;
 445                        }
 446                        addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_GOPTS_ID,
 447                                  vid);
 448                        if (vid_end != -1)
 449                                addattr16(&req.n, sizeof(req),
 450                                          BRIDGE_VLANDB_GOPTS_RANGE, vid_end);
 451                } else if (strcmp(*argv, "mcast_snooping") == 0) {
 452                        NEXT_ARG();
 453                        if (get_u8(&val8, *argv, 0))
 454                                invarg("invalid mcast_snooping", *argv);
 455                        addattr8(&req.n, 1024,
 456                                 BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING, val8);
 457                } else if (strcmp(*argv, "mcast_querier") == 0) {
 458                        NEXT_ARG();
 459                        if (get_u8(&val8, *argv, 0))
 460                                invarg("invalid mcast_querier", *argv);
 461                        addattr8(&req.n, 1024,
 462                                 BRIDGE_VLANDB_GOPTS_MCAST_QUERIER, val8);
 463                } else if (strcmp(*argv, "mcast_igmp_version") == 0) {
 464                        NEXT_ARG();
 465                        if (get_u8(&val8, *argv, 0))
 466                                invarg("invalid mcast_igmp_version", *argv);
 467                        addattr8(&req.n, 1024,
 468                                 BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION, val8);
 469                } else if (strcmp(*argv, "mcast_mld_version") == 0) {
 470                        NEXT_ARG();
 471                        if (get_u8(&val8, *argv, 0))
 472                                invarg("invalid mcast_mld_version", *argv);
 473                        addattr8(&req.n, 1024,
 474                                 BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION, val8);
 475                } else if (strcmp(*argv, "mcast_last_member_count") == 0) {
 476                        NEXT_ARG();
 477                        if (get_u32(&val32, *argv, 0))
 478                                invarg("invalid mcast_last_member_count", *argv);
 479                        addattr32(&req.n, 1024,
 480                                  BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT,
 481                                  val32);
 482                } else if (strcmp(*argv, "mcast_startup_query_count") == 0) {
 483                        NEXT_ARG();
 484                        if (get_u32(&val32, *argv, 0))
 485                                invarg("invalid mcast_startup_query_count",
 486                                       *argv);
 487                        addattr32(&req.n, 1024,
 488                                  BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT,
 489                                  val32);
 490                } else if (strcmp(*argv, "mcast_last_member_interval") == 0) {
 491                        NEXT_ARG();
 492                        if (get_u64(&val64, *argv, 0))
 493                                invarg("invalid mcast_last_member_interval",
 494                                       *argv);
 495                        addattr64(&req.n, 1024,
 496                                  BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL,
 497                                  val64);
 498                } else if (strcmp(*argv, "mcast_membership_interval") == 0) {
 499                        NEXT_ARG();
 500                        if (get_u64(&val64, *argv, 0))
 501                                invarg("invalid mcast_membership_interval",
 502                                       *argv);
 503                        addattr64(&req.n, 1024,
 504                                  BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL,
 505                                  val64);
 506                } else if (strcmp(*argv, "mcast_querier_interval") == 0) {
 507                        NEXT_ARG();
 508                        if (get_u64(&val64, *argv, 0))
 509                                invarg("invalid mcast_querier_interval",
 510                                       *argv);
 511                        addattr64(&req.n, 1024,
 512                                  BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL,
 513                                  val64);
 514                } else if (strcmp(*argv, "mcast_query_interval") == 0) {
 515                        NEXT_ARG();
 516                        if (get_u64(&val64, *argv, 0))
 517                                invarg("invalid mcast_query_interval",
 518                                       *argv);
 519                        addattr64(&req.n, 1024,
 520                                  BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL,
 521                                  val64);
 522                } else if (strcmp(*argv, "mcast_query_response_interval") == 0) {
 523                        NEXT_ARG();
 524                        if (get_u64(&val64, *argv, 0))
 525                                invarg("invalid mcast_query_response_interval",
 526                                       *argv);
 527                        addattr64(&req.n, 1024,
 528                                  BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL,
 529                                  val64);
 530                } else if (strcmp(*argv, "mcast_startup_query_interval") == 0) {
 531                        NEXT_ARG();
 532                        if (get_u64(&val64, *argv, 0))
 533                                invarg("invalid mcast_startup_query_interval",
 534                                       *argv);
 535                        addattr64(&req.n, 1024,
 536                                  BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
 537                                  val64);
 538                } else if (strcmp(*argv, "msti") == 0) {
 539                        NEXT_ARG();
 540                        if (get_u16(&val16, *argv, 0))
 541                                invarg("invalid msti", *argv);
 542                        addattr16(&req.n, 1024,
 543                                 BRIDGE_VLANDB_GOPTS_MSTI, val16);
 544                } else {
 545                        if (strcmp(*argv, "help") == 0)
 546                                NEXT_ARG();
 547                }
 548                argc--; argv++;
 549        }
 550        addattr_nest_end(&req.n, afspec);
 551
 552        if (d == NULL || vid == -1) {
 553                fprintf(stderr, "Device and VLAN ID are required arguments.\n");
 554                return -1;
 555        }
 556
 557        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 558                return -1;
 559
 560        return 0;
 561}
 562
 563/* In order to use this function for both filtering and non-filtering cases
 564 * we need to make it a tristate:
 565 * return -1 - if filtering we've gone over so don't continue
 566 * return  0 - skip entry and continue (applies to range start or to entries
 567 *             which are less than filter_vlan)
 568 * return  1 - print the entry and continue
 569 */
 570static int filter_vlan_check(__u16 vid, __u16 flags)
 571{
 572        /* if we're filtering we should stop on the first greater entry */
 573        if (filter_vlan && vid > filter_vlan &&
 574            !(flags & BRIDGE_VLAN_INFO_RANGE_END))
 575                return -1;
 576        if ((flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) ||
 577            vid < filter_vlan)
 578                return 0;
 579
 580        return 1;
 581}
 582
 583static void open_vlan_port(int ifi_index, enum vlan_show_subject subject)
 584{
 585        open_json_object(NULL);
 586        print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
 587                           "%-" textify(IFNAMSIZ) "s  ",
 588                           ll_index_to_name(ifi_index));
 589        open_json_array(PRINT_JSON,
 590                        subject == VLAN_SHOW_VLAN ? "vlans": "tunnels");
 591}
 592
 593static void close_vlan_port(void)
 594{
 595        close_json_array(PRINT_JSON, NULL);
 596        close_json_object();
 597}
 598
 599static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex)
 600{
 601        struct rtattr *i, *list = tb;
 602        int rem = RTA_PAYLOAD(list);
 603        __u16 last_vid_start = 0;
 604        __u32 last_tunid_start = 0;
 605        bool opened = false;
 606
 607        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 608                struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
 609                __u32 tunnel_id = 0;
 610                __u16 tunnel_vid = 0;
 611                __u16 tunnel_flags = 0;
 612                unsigned int width;
 613                int vcheck_ret;
 614
 615                if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO)
 616                        continue;
 617
 618                parse_rtattr(ttb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
 619                             RTA_DATA(i), RTA_PAYLOAD(i));
 620
 621                if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
 622                        tunnel_vid =
 623                                rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
 624                else
 625                        continue;
 626
 627                if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_ID])
 628                        tunnel_id =
 629                                rta_getattr_u32(ttb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
 630
 631                if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
 632                        tunnel_flags =
 633                                rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
 634
 635                if (!(tunnel_flags & BRIDGE_VLAN_INFO_RANGE_END)) {
 636                        last_vid_start = tunnel_vid;
 637                        last_tunid_start = tunnel_id;
 638                }
 639
 640                vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags);
 641                if (vcheck_ret == -1)
 642                        break;
 643                else if (vcheck_ret == 0)
 644                        continue;
 645
 646                if (!opened) {
 647                        open_vlan_port(ifindex, VLAN_SHOW_TUNNELINFO);
 648                        opened = true;
 649                } else {
 650                        print_string(PRINT_FP, NULL,
 651                                     "%-" textify(IFNAMSIZ) "s  ", "");
 652                }
 653
 654                open_json_object(NULL);
 655                width = print_range("vlan", last_vid_start, tunnel_vid);
 656                if (!is_json_context())
 657                        printf("%-*s  ", VLAN_ID_LEN - width, "");
 658                print_range("tunid", last_tunid_start, tunnel_id);
 659                close_json_object();
 660                print_nl();
 661        }
 662
 663        if (opened)
 664                close_vlan_port();
 665}
 666
 667static int print_vlan(struct nlmsghdr *n, void *arg)
 668{
 669        enum vlan_show_subject *subject = arg;
 670        struct ifinfomsg *ifm = NLMSG_DATA(n);
 671        int len = n->nlmsg_len;
 672        struct rtattr *tb[IFLA_MAX+1];
 673
 674        if (n->nlmsg_type != RTM_NEWLINK) {
 675                fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
 676                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
 677                return 0;
 678        }
 679
 680        len -= NLMSG_LENGTH(sizeof(*ifm));
 681        if (len < 0) {
 682                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 683                return -1;
 684        }
 685
 686        if (ifm->ifi_family != AF_BRIDGE)
 687                return 0;
 688
 689        if (filter_index && filter_index != ifm->ifi_index)
 690                return 0;
 691
 692        parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
 693        if (!tb[IFLA_AF_SPEC])
 694                return 0;
 695
 696        switch (*subject) {
 697        case VLAN_SHOW_VLAN:
 698                print_vlan_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
 699                break;
 700        case VLAN_SHOW_TUNNELINFO:
 701                print_vlan_tunnel_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
 702                break;
 703        }
 704
 705        return 0;
 706}
 707
 708static void print_vlan_flags(__u16 flags)
 709{
 710        if (flags == 0)
 711                return;
 712
 713        open_json_array(PRINT_JSON, "flags");
 714        if (flags & BRIDGE_VLAN_INFO_PVID)
 715                print_string(PRINT_ANY, NULL, " %s", "PVID");
 716
 717        if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
 718                print_string(PRINT_ANY, NULL, " %s", "Egress Untagged");
 719        close_json_array(PRINT_JSON, NULL);
 720}
 721
 722static void __print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
 723{
 724        print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s    ", "");
 725        print_lluint(PRINT_ANY, "rx_bytes", "RX: %llu bytes",
 726                     vstats->rx_bytes);
 727        print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n",
 728                     vstats->rx_packets);
 729
 730        print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s    ", "");
 731        print_lluint(PRINT_ANY, "tx_bytes", "TX: %llu bytes",
 732                     vstats->tx_bytes);
 733        print_lluint(PRINT_ANY, "tx_packets", " %llu packets\n",
 734                     vstats->tx_packets);
 735}
 736
 737static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
 738{
 739        open_json_object(NULL);
 740
 741        print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
 742        print_vlan_flags(vstats->flags);
 743        print_nl();
 744        __print_one_vlan_stats(vstats);
 745
 746        close_json_object();
 747}
 748
 749static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
 750{
 751        struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
 752        struct rtattr *i, *list;
 753        bool found_vlan = false;
 754        int rem;
 755
 756        parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
 757                     RTA_PAYLOAD(attr));
 758        if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
 759                return;
 760
 761        list = brtb[LINK_XSTATS_TYPE_BRIDGE];
 762        rem = RTA_PAYLOAD(list);
 763
 764        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 765                const struct bridge_vlan_xstats *vstats = RTA_DATA(i);
 766
 767                if (i->rta_type != BRIDGE_XSTATS_VLAN)
 768                        continue;
 769
 770                if (filter_vlan && filter_vlan != vstats->vid)
 771                        continue;
 772
 773                /* skip pure port entries, they'll be dumped via the slave stats call */
 774                if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
 775                    !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
 776                        continue;
 777
 778                /* found vlan stats, first time print the interface name */
 779                if (!found_vlan) {
 780                        open_vlan_port(ifindex, VLAN_SHOW_VLAN);
 781                        found_vlan = true;
 782                } else {
 783                        print_string(PRINT_FP, NULL,
 784                                     "%-" textify(IFNAMSIZ) "s  ", "");
 785                }
 786                print_one_vlan_stats(vstats);
 787        }
 788
 789        /* vlan_port is opened only if there are any vlan stats */
 790        if (found_vlan)
 791                close_vlan_port();
 792}
 793
 794static int print_vlan_stats(struct nlmsghdr *n, void *arg)
 795{
 796        struct if_stats_msg *ifsm = NLMSG_DATA(n);
 797        struct rtattr *tb[IFLA_STATS_MAX+1];
 798        int len = n->nlmsg_len;
 799        FILE *fp = arg;
 800
 801        len -= NLMSG_LENGTH(sizeof(*ifsm));
 802        if (len < 0) {
 803                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 804                return -1;
 805        }
 806
 807        if (filter_index && filter_index != ifsm->ifindex)
 808                return 0;
 809
 810        parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
 811
 812        /* We have to check if any of the two attrs are usable */
 813        if (tb[IFLA_STATS_LINK_XSTATS])
 814                print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
 815                                      ifsm->ifindex);
 816
 817        if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
 818                print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
 819                                      ifsm->ifindex);
 820
 821        fflush(fp);
 822        return 0;
 823}
 824
 825static void print_vlan_router_ports(struct rtattr *rattr)
 826{
 827        int rem = RTA_PAYLOAD(rattr);
 828        struct rtattr *i;
 829
 830        print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s    ", "");
 831        open_json_array(PRINT_ANY, is_json_context() ? "router_ports" :
 832                                                       "router ports: ");
 833        for (i = RTA_DATA(rattr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 834                uint32_t *port_ifindex = RTA_DATA(i);
 835                const char *port_ifname = ll_index_to_name(*port_ifindex);
 836
 837                open_json_object(NULL);
 838                if (show_stats && i != RTA_DATA(rattr)) {
 839                        print_nl();
 840                        /* start: IFNAMSIZ + 4 + strlen("router ports: ") */
 841                        print_string(PRINT_FP, NULL,
 842                                     "%-" textify(IFNAMSIZ) "s    "
 843                                     "              ",
 844                                     "");
 845                }
 846                print_string(PRINT_ANY, "port", "%s ", port_ifname);
 847                if (show_stats)
 848                        br_print_router_port_stats(i);
 849                close_json_object();
 850        }
 851        close_json_array(PRINT_JSON, NULL);
 852        print_nl();
 853}
 854
 855static void print_vlan_global_opts(struct rtattr *a, int ifindex)
 856{
 857        struct rtattr *vtb[BRIDGE_VLANDB_GOPTS_MAX + 1], *vattr;
 858        __u16 vid, vrange = 0;
 859
 860        if (rta_type(a) != BRIDGE_VLANDB_GLOBAL_OPTIONS)
 861                return;
 862
 863        parse_rtattr_flags(vtb, BRIDGE_VLANDB_GOPTS_MAX, RTA_DATA(a),
 864                           RTA_PAYLOAD(a), NLA_F_NESTED);
 865        vid = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_ID]);
 866        if (vtb[BRIDGE_VLANDB_GOPTS_RANGE])
 867                vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_RANGE]);
 868        else
 869                vrange = vid;
 870
 871        if (filter_vlan && (filter_vlan < vid || filter_vlan > vrange))
 872                return;
 873
 874        if (vlan_rtm_cur_ifidx != ifindex) {
 875                open_vlan_port(ifindex, VLAN_SHOW_VLAN);
 876                open_json_object(NULL);
 877                vlan_rtm_cur_ifidx = ifindex;
 878        } else {
 879                open_json_object(NULL);
 880                print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s  ", "");
 881        }
 882        print_range("vlan", vid, vrange);
 883        print_nl();
 884        print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s    ", "");
 885        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING]) {
 886                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING];
 887                print_uint(PRINT_ANY, "mcast_snooping", "mcast_snooping %u ",
 888                           rta_getattr_u8(vattr));
 889        }
 890        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) {
 891                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER];
 892                print_uint(PRINT_ANY, "mcast_querier", "mcast_querier %u ",
 893                           rta_getattr_u8(vattr));
 894        }
 895        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION]) {
 896                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION];
 897                print_uint(PRINT_ANY, "mcast_igmp_version",
 898                           "mcast_igmp_version %u ", rta_getattr_u8(vattr));
 899        }
 900        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION]) {
 901                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION];
 902                print_uint(PRINT_ANY, "mcast_mld_version",
 903                           "mcast_mld_version %u ", rta_getattr_u8(vattr));
 904        }
 905        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION]) {
 906                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT];
 907                print_uint(PRINT_ANY, "mcast_last_member_count",
 908                           "mcast_last_member_count %u ",
 909                           rta_getattr_u32(vattr));
 910        }
 911        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL]) {
 912                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL];
 913                print_lluint(PRINT_ANY, "mcast_last_member_interval",
 914                             "mcast_last_member_interval %llu ",
 915                             rta_getattr_u64(vattr));
 916        }
 917        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT]) {
 918                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT];
 919                print_uint(PRINT_ANY, "mcast_startup_query_count",
 920                           "mcast_startup_query_count %u ",
 921                           rta_getattr_u32(vattr));
 922        }
 923        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]) {
 924                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL];
 925                print_lluint(PRINT_ANY, "mcast_startup_query_interval",
 926                             "mcast_startup_query_interval %llu ",
 927                             rta_getattr_u64(vattr));
 928        }
 929        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL]) {
 930                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL];
 931                print_lluint(PRINT_ANY, "mcast_membership_interval",
 932                             "mcast_membership_interval %llu ",
 933                             rta_getattr_u64(vattr));
 934        }
 935        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL]) {
 936                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL];
 937                print_lluint(PRINT_ANY, "mcast_querier_interval",
 938                             "mcast_querier_interval %llu ",
 939                             rta_getattr_u64(vattr));
 940        }
 941        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]) {
 942                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL];
 943                print_lluint(PRINT_ANY, "mcast_query_interval",
 944                             "mcast_query_interval %llu ",
 945                             rta_getattr_u64(vattr));
 946        }
 947        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) {
 948                vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL];
 949                print_lluint(PRINT_ANY, "mcast_query_response_interval",
 950                             "mcast_query_response_interval %llu ",
 951                             rta_getattr_u64(vattr));
 952        }
 953        if (vtb[BRIDGE_VLANDB_GOPTS_MSTI]) {
 954                vattr = vtb[BRIDGE_VLANDB_GOPTS_MSTI];
 955                print_uint(PRINT_ANY, "msti", "msti %u ",
 956                           rta_getattr_u16(vattr));
 957        }
 958        print_nl();
 959        if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]) {
 960                vattr = RTA_DATA(vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]);
 961                print_vlan_router_ports(vattr);
 962        }
 963        close_json_object();
 964}
 965
 966static void print_vlan_opts(struct rtattr *a, int ifindex)
 967{
 968        struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *vattr;
 969        struct bridge_vlan_xstats vstats;
 970        struct bridge_vlan_info *vinfo;
 971        __u16 vrange = 0;
 972        __u8 state = 0;
 973
 974        if (rta_type(a) != BRIDGE_VLANDB_ENTRY)
 975                return;
 976
 977        parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
 978                           RTA_PAYLOAD(a), NLA_F_NESTED);
 979        vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
 980
 981        memset(&vstats, 0, sizeof(vstats));
 982        if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
 983                vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
 984        else
 985                vrange = vinfo->vid;
 986
 987        if (filter_vlan && (filter_vlan < vinfo->vid || filter_vlan > vrange))
 988                return;
 989
 990        if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
 991                state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
 992
 993        if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
 994                struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
 995                struct rtattr *attr;
 996
 997                attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
 998                parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
 999                             RTA_PAYLOAD(attr));
1000
1001                if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
1002                        attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
1003                        vstats.rx_bytes = rta_getattr_u64(attr);
1004                }
1005                if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
1006                        attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
1007                        vstats.rx_packets = rta_getattr_u64(attr);
1008                }
1009                if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
1010                        attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
1011                        vstats.tx_packets = rta_getattr_u64(attr);
1012                }
1013                if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
1014                        attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
1015                        vstats.tx_bytes = rta_getattr_u64(attr);
1016                }
1017        }
1018
1019        if (vlan_rtm_cur_ifidx != ifindex) {
1020                open_vlan_port(ifindex, VLAN_SHOW_VLAN);
1021                open_json_object(NULL);
1022                vlan_rtm_cur_ifidx = ifindex;
1023        } else {
1024                open_json_object(NULL);
1025                print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s  ", "");
1026        }
1027        print_range("vlan", vinfo->vid, vrange);
1028        print_vlan_flags(vinfo->flags);
1029        print_nl();
1030        print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s    ", "");
1031        print_stp_state(state);
1032        if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER]) {
1033                vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER];
1034                print_uint(PRINT_ANY, "mcast_router", "mcast_router %u ",
1035                           rta_getattr_u8(vattr));
1036        }
1037        if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS]) {
1038                vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS];
1039                print_uint(PRINT_ANY, "mcast_n_groups", "mcast_n_groups %u ",
1040                           rta_getattr_u32(vattr));
1041        }
1042        if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS]) {
1043                vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS];
1044                print_uint(PRINT_ANY, "mcast_max_groups", "mcast_max_groups %u ",
1045                           rta_getattr_u32(vattr));
1046        }
1047        if (vtb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]) {
1048                vattr = vtb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS];
1049                print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
1050                             rta_getattr_u8(vattr));
1051        }
1052        print_nl();
1053        if (show_stats)
1054                __print_one_vlan_stats(&vstats);
1055        close_json_object();
1056}
1057
1058int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor, bool global_only)
1059{
1060        struct br_vlan_msg *bvm = NLMSG_DATA(n);
1061        int len = n->nlmsg_len;
1062        struct rtattr *a;
1063        FILE *fp = arg;
1064        int rem;
1065
1066        if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
1067            n->nlmsg_type != RTM_GETVLAN) {
1068                fprintf(stderr, "Unknown vlan rtm message: %08x %08x %08x\n",
1069                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
1070                return 0;
1071        }
1072
1073        len -= NLMSG_LENGTH(sizeof(*bvm));
1074        if (len < 0) {
1075                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
1076                return -1;
1077        }
1078
1079        if (bvm->family != AF_BRIDGE)
1080                return 0;
1081
1082        if (filter_index && filter_index != bvm->ifindex)
1083                return 0;
1084
1085        print_headers(fp, "[VLAN]");
1086
1087        if (n->nlmsg_type == RTM_DELVLAN)
1088                print_bool(PRINT_ANY, "deleted", "Deleted ", true);
1089
1090        if (monitor)
1091                vlan_rtm_cur_ifidx = -1;
1092
1093        if (vlan_rtm_cur_ifidx != -1 && vlan_rtm_cur_ifidx != bvm->ifindex) {
1094                close_vlan_port();
1095                vlan_rtm_cur_ifidx = -1;
1096        }
1097
1098        rem = len;
1099        for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
1100                unsigned short attr_type = rta_type(a);
1101
1102                /* skip unknown attributes */
1103                if (attr_type > BRIDGE_VLANDB_MAX ||
1104                    (global_only && attr_type != BRIDGE_VLANDB_GLOBAL_OPTIONS))
1105                        continue;
1106
1107                switch (attr_type) {
1108                case BRIDGE_VLANDB_ENTRY:
1109                        print_vlan_opts(a, bvm->ifindex);
1110                        break;
1111                case BRIDGE_VLANDB_GLOBAL_OPTIONS:
1112                        print_vlan_global_opts(a, bvm->ifindex);
1113                        break;
1114                }
1115        }
1116
1117        return 0;
1118}
1119
1120static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
1121{
1122        return print_vlan_rtm(n, arg, false, false);
1123}
1124
1125static int print_vlan_rtm_global_filter(struct nlmsghdr *n, void *arg)
1126{
1127        return print_vlan_rtm(n, arg, false, true);
1128}
1129
1130static int vlan_show(int argc, char **argv, int subject)
1131{
1132        char *filter_dev = NULL;
1133        int ret = 0;
1134
1135        while (argc > 0) {
1136                if (strcmp(*argv, "dev") == 0) {
1137                        NEXT_ARG();
1138                        if (filter_dev)
1139                                duparg("dev", *argv);
1140                        filter_dev = *argv;
1141                } else if (strcmp(*argv, "vid") == 0) {
1142                        NEXT_ARG();
1143                        if (filter_vlan)
1144                                duparg("vid", *argv);
1145                        filter_vlan = atoi(*argv);
1146                }
1147                argc--; argv++;
1148        }
1149
1150        if (filter_dev) {
1151                filter_index = ll_name_to_index(filter_dev);
1152                if (!filter_index)
1153                        return nodev(filter_dev);
1154        }
1155
1156        new_json_obj(json);
1157
1158        /* if show_details is true then use the new bridge vlan dump format */
1159        if (show_details && subject == VLAN_SHOW_VLAN) {
1160                __u32 dump_flags = show_stats ? BRIDGE_VLANDB_DUMPF_STATS : 0;
1161
1162                if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
1163                        perror("Cannot send dump request");
1164                        exit(1);
1165                }
1166
1167                if (!is_json_context()) {
1168                        printf("%-" textify(IFNAMSIZ) "s  %-"
1169                               textify(VLAN_ID_LEN) "s", "port",
1170                               "vlan-id");
1171                        printf("\n");
1172                }
1173
1174                ret = rtnl_dump_filter(&rth, print_vlan_rtm_filter, &subject);
1175                if (ret < 0) {
1176                        fprintf(stderr, "Dump terminated\n");
1177                        exit(1);
1178                }
1179
1180                if (vlan_rtm_cur_ifidx != -1)
1181                        close_vlan_port();
1182
1183                goto out;
1184        }
1185
1186        if (!show_stats) {
1187                if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
1188                                             (compress_vlans ?
1189                                              RTEXT_FILTER_BRVLAN_COMPRESSED :
1190                                              RTEXT_FILTER_BRVLAN)) < 0) {
1191                        perror("Cannot send dump request");
1192                        exit(1);
1193                }
1194
1195                if (!is_json_context()) {
1196                        printf("%-" textify(IFNAMSIZ) "s  %-"
1197                               textify(VLAN_ID_LEN) "s", "port",
1198                               "vlan-id");
1199                        if (subject == VLAN_SHOW_TUNNELINFO)
1200                                printf("  tunnel-id");
1201                        printf("\n");
1202                }
1203
1204                ret = rtnl_dump_filter(&rth, print_vlan, &subject);
1205                if (ret < 0) {
1206                        fprintf(stderr, "Dump terminated\n");
1207                        exit(1);
1208                }
1209        } else {
1210                __u32 filt_mask;
1211
1212                filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
1213                if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
1214                                              NULL, NULL) < 0) {
1215                        perror("Cannot send dump request");
1216                        exit(1);
1217                }
1218
1219                if (!is_json_context())
1220                        printf("%-" textify(IFNAMSIZ) "s  vlan-id\n",
1221                               "port");
1222
1223                if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
1224                        fprintf(stderr, "Dump terminated\n");
1225                        exit(1);
1226                }
1227
1228                filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
1229                if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
1230                                              NULL, NULL) < 0) {
1231                        perror("Cannot send slave dump request");
1232                        exit(1);
1233                }
1234
1235                if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
1236                        fprintf(stderr, "Dump terminated\n");
1237                        exit(1);
1238                }
1239        }
1240
1241out:
1242        delete_json_obj();
1243        fflush(stdout);
1244        return 0;
1245}
1246
1247static int vlan_global_show(int argc, char **argv)
1248{
1249        __u32 dump_flags = BRIDGE_VLANDB_DUMPF_GLOBAL;
1250        int ret = 0, subject = VLAN_SHOW_VLAN;
1251        char *filter_dev = NULL;
1252
1253        while (argc > 0) {
1254                if (strcmp(*argv, "dev") == 0) {
1255                        NEXT_ARG();
1256                        if (filter_dev)
1257                                duparg("dev", *argv);
1258                        filter_dev = *argv;
1259                } else if (strcmp(*argv, "vid") == 0) {
1260                        NEXT_ARG();
1261                        if (filter_vlan)
1262                                duparg("vid", *argv);
1263                        filter_vlan = atoi(*argv);
1264                }
1265                argc--; argv++;
1266        }
1267
1268        if (filter_dev) {
1269                filter_index = ll_name_to_index(filter_dev);
1270                if (!filter_index)
1271                        return nodev(filter_dev);
1272        }
1273
1274        new_json_obj(json);
1275
1276        if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
1277                perror("Cannot send dump request");
1278                exit(1);
1279        }
1280
1281        if (!is_json_context()) {
1282                printf("%-" textify(IFNAMSIZ) "s  %-"
1283                       textify(VLAN_ID_LEN) "s", "port",
1284                       "vlan-id");
1285                printf("\n");
1286        }
1287
1288        ret = rtnl_dump_filter(&rth, print_vlan_rtm_global_filter, &subject);
1289        if (ret < 0) {
1290                fprintf(stderr, "Dump terminated\n");
1291                exit(1);
1292        }
1293
1294        if (vlan_rtm_cur_ifidx != -1)
1295                close_vlan_port();
1296
1297        delete_json_obj();
1298        fflush(stdout);
1299        return 0;
1300}
1301
1302static void print_vlan_info(struct rtattr *tb, int ifindex)
1303{
1304        struct rtattr *i, *list = tb;
1305        int rem = RTA_PAYLOAD(list);
1306        __u16 last_vid_start = 0;
1307        bool opened = false;
1308
1309        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
1310                struct bridge_vlan_info *vinfo;
1311                int vcheck_ret;
1312
1313                if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
1314                        continue;
1315
1316                vinfo = RTA_DATA(i);
1317
1318                if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
1319                        last_vid_start = vinfo->vid;
1320                vcheck_ret = filter_vlan_check(vinfo->vid, vinfo->flags);
1321                if (vcheck_ret == -1)
1322                        break;
1323                else if (vcheck_ret == 0)
1324                        continue;
1325
1326                if (!opened) {
1327                        open_vlan_port(ifindex, VLAN_SHOW_VLAN);
1328                        opened = true;
1329                } else {
1330                        print_string(PRINT_FP, NULL, "%-"
1331                                     textify(IFNAMSIZ) "s  ", "");
1332                }
1333
1334                open_json_object(NULL);
1335                print_range("vlan", last_vid_start, vinfo->vid);
1336
1337                print_vlan_flags(vinfo->flags);
1338                close_json_object();
1339                print_nl();
1340        }
1341
1342        if (opened)
1343                close_vlan_port();
1344}
1345
1346static int vlan_global(int argc, char **argv)
1347{
1348        if (argc > 0) {
1349                if (strcmp(*argv, "show") == 0 ||
1350                    strcmp(*argv, "lst") == 0 ||
1351                    strcmp(*argv, "list") == 0)
1352                        return vlan_global_show(argc-1, argv+1);
1353                else if (strcmp(*argv, "set") == 0)
1354                        return vlan_global_option_set(argc-1, argv+1);
1355                else
1356                        usage();
1357        } else {
1358                return vlan_global_show(0, NULL);
1359        }
1360
1361        return 0;
1362}
1363
1364int do_vlan(int argc, char **argv)
1365{
1366        ll_init_map(&rth);
1367        timestamp = 0;
1368
1369        if (argc > 0) {
1370                if (matches(*argv, "add") == 0)
1371                        return vlan_modify(RTM_SETLINK, argc-1, argv+1);
1372                if (matches(*argv, "delete") == 0)
1373                        return vlan_modify(RTM_DELLINK, argc-1, argv+1);
1374                if (matches(*argv, "show") == 0 ||
1375                    matches(*argv, "lst") == 0 ||
1376                    matches(*argv, "list") == 0)
1377                        return vlan_show(argc-1, argv+1, VLAN_SHOW_VLAN);
1378                if (matches(*argv, "tunnelshow") == 0) {
1379                        return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO);
1380                }
1381                if (matches(*argv, "set") == 0)
1382                        return vlan_option_set(argc-1, argv+1);
1383                if (strcmp(*argv, "global") == 0)
1384                        return vlan_global(argc-1, argv+1);
1385                if (matches(*argv, "help") == 0)
1386                        usage();
1387        } else {
1388                return vlan_show(0, NULL, VLAN_SHOW_VLAN);
1389        }
1390
1391        fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv);
1392        exit(-1);
1393}
1394