iproute2/bridge/link.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2
   3#include <stdio.h>
   4#include <stdlib.h>
   5#include <unistd.h>
   6#include <time.h>
   7#include <sys/socket.h>
   8#include <sys/time.h>
   9#include <netinet/in.h>
  10#include <linux/if.h>
  11#include <linux/if_bridge.h>
  12#include <string.h>
  13#include <stdbool.h>
  14
  15#include "json_print.h"
  16#include "libnetlink.h"
  17#include "utils.h"
  18#include "br_common.h"
  19
  20static unsigned int filter_index;
  21
  22static const char *port_states[] = {
  23        [BR_STATE_DISABLED] = "disabled",
  24        [BR_STATE_LISTENING] = "listening",
  25        [BR_STATE_LEARNING] = "learning",
  26        [BR_STATE_FORWARDING] = "forwarding",
  27        [BR_STATE_BLOCKING] = "blocking",
  28};
  29
  30static const char *hw_mode[] = {
  31        "VEB", "VEPA"
  32};
  33
  34static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
  35{
  36        open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
  37        if (flags & IFF_UP && !(flags & IFF_RUNNING))
  38                print_string(PRINT_ANY, NULL,
  39                             flags ? "%s," : "%s", "NO-CARRIER");
  40        flags &= ~IFF_RUNNING;
  41
  42#define _PF(f) if (flags&IFF_##f) {                                     \
  43                flags &= ~IFF_##f ;                                     \
  44                print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
  45        _PF(LOOPBACK);
  46        _PF(BROADCAST);
  47        _PF(POINTOPOINT);
  48        _PF(MULTICAST);
  49        _PF(NOARP);
  50        _PF(ALLMULTI);
  51        _PF(PROMISC);
  52        _PF(MASTER);
  53        _PF(SLAVE);
  54        _PF(DEBUG);
  55        _PF(DYNAMIC);
  56        _PF(AUTOMEDIA);
  57        _PF(PORTSEL);
  58        _PF(NOTRAILERS);
  59        _PF(UP);
  60        _PF(LOWER_UP);
  61        _PF(DORMANT);
  62        _PF(ECHO);
  63#undef _PF
  64        if (flags)
  65                print_hex(PRINT_ANY, NULL, "%x", flags);
  66        if (mdown)
  67                print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
  68        close_json_array(PRINT_ANY, "> ");
  69}
  70
  71static void print_portstate(__u8 state)
  72{
  73        if (state <= BR_STATE_BLOCKING)
  74                print_string(PRINT_ANY, "state",
  75                             "state %s ", port_states[state]);
  76        else
  77                print_uint(PRINT_ANY, "state",
  78                             "state (%d) ", state);
  79}
  80
  81static void print_hwmode(__u16 mode)
  82{
  83        if (mode >= ARRAY_SIZE(hw_mode))
  84                print_0xhex(PRINT_ANY, "hwmode",
  85                            "hwmode %#llx ", mode);
  86        else
  87                print_string(PRINT_ANY, "hwmode",
  88                             "hwmode %s ", hw_mode[mode]);
  89}
  90
  91static void print_protinfo(FILE *fp, struct rtattr *attr)
  92{
  93        if (attr->rta_type & NLA_F_NESTED) {
  94                struct rtattr *prtb[IFLA_BRPORT_MAX + 1];
  95
  96                parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
  97
  98                if (prtb[IFLA_BRPORT_STATE])
  99                        print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
 100
 101                if (prtb[IFLA_BRPORT_PRIORITY])
 102                        print_uint(PRINT_ANY, "priority",
 103                                   "priority %u ",
 104                                   rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
 105
 106                if (prtb[IFLA_BRPORT_COST])
 107                        print_uint(PRINT_ANY, "cost",
 108                                   "cost %u ",
 109                                   rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
 110
 111                if (!show_details)
 112                        return;
 113
 114                if (!is_json_context())
 115                        fprintf(fp, "%s    ", _SL_);
 116
 117                if (prtb[IFLA_BRPORT_MODE])
 118                        print_on_off(PRINT_ANY, "hairpin", "hairpin %s ",
 119                                     rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
 120                if (prtb[IFLA_BRPORT_GUARD])
 121                        print_on_off(PRINT_ANY, "guard", "guard %s ",
 122                                     rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
 123                if (prtb[IFLA_BRPORT_PROTECT])
 124                        print_on_off(PRINT_ANY, "root_block", "root_block %s ",
 125                                     rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
 126                if (prtb[IFLA_BRPORT_FAST_LEAVE])
 127                        print_on_off(PRINT_ANY, "fastleave", "fastleave %s ",
 128                                     rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
 129                if (prtb[IFLA_BRPORT_LEARNING])
 130                        print_on_off(PRINT_ANY, "learning", "learning %s ",
 131                                     rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
 132                if (prtb[IFLA_BRPORT_LEARNING_SYNC])
 133                        print_on_off(PRINT_ANY, "learning_sync", "learning_sync %s ",
 134                                     rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
 135                if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
 136                        print_on_off(PRINT_ANY, "flood", "flood %s ",
 137                                     rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
 138                if (prtb[IFLA_BRPORT_MCAST_FLOOD])
 139                        print_on_off(PRINT_ANY, "mcast_flood", "mcast_flood %s ",
 140                                     rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
 141                if (prtb[IFLA_BRPORT_MCAST_TO_UCAST])
 142                        print_on_off(PRINT_ANY, "mcast_to_unicast", "mcast_to_unicast %s ",
 143                                     rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_TO_UCAST]));
 144                if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
 145                        print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
 146                                     rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
 147                if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
 148                        print_on_off(PRINT_ANY, "vlan_tunnel", "vlan_tunnel %s ",
 149                                     rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
 150
 151                if (prtb[IFLA_BRPORT_BACKUP_PORT]) {
 152                        int ifidx;
 153
 154                        ifidx = rta_getattr_u32(prtb[IFLA_BRPORT_BACKUP_PORT]);
 155                        print_string(PRINT_ANY,
 156                                     "backup_port", "backup_port %s ",
 157                                     ll_index_to_name(ifidx));
 158                }
 159
 160                if (prtb[IFLA_BRPORT_ISOLATED])
 161                        print_on_off(PRINT_ANY, "isolated", "isolated %s ",
 162                                     rta_getattr_u8(prtb[IFLA_BRPORT_ISOLATED]));
 163        } else
 164                print_portstate(rta_getattr_u8(attr));
 165}
 166
 167
 168/*
 169 * This is reported by HW devices that have some bridging
 170 * capabilities.
 171 */
 172static void print_af_spec(struct rtattr *attr, int ifindex)
 173{
 174        struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
 175
 176        parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, attr);
 177
 178        if (aftb[IFLA_BRIDGE_MODE])
 179                print_hwmode(rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
 180
 181        if (!show_details)
 182                return;
 183
 184        if (aftb[IFLA_BRIDGE_VLAN_INFO])
 185                print_vlan_info(aftb[IFLA_BRIDGE_VLAN_INFO], ifindex);
 186}
 187
 188int print_linkinfo(struct nlmsghdr *n, void *arg)
 189{
 190        FILE *fp = arg;
 191        struct ifinfomsg *ifi = NLMSG_DATA(n);
 192        struct rtattr *tb[IFLA_MAX+1];
 193        unsigned int m_flag = 0;
 194        int len = n->nlmsg_len;
 195        const char *name;
 196
 197        len -= NLMSG_LENGTH(sizeof(*ifi));
 198        if (len < 0) {
 199                fprintf(stderr, "Message too short!\n");
 200                return -1;
 201        }
 202
 203        if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC))
 204                return 0;
 205
 206        if (filter_index && filter_index != ifi->ifi_index)
 207                return 0;
 208
 209        parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
 210
 211        name = get_ifname_rta(ifi->ifi_index, tb[IFLA_IFNAME]);
 212        if (!name)
 213                return -1;
 214
 215        open_json_object(NULL);
 216        if (n->nlmsg_type == RTM_DELLINK)
 217                print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 218
 219        print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
 220        m_flag = print_name_and_link("%s: ", name, tb);
 221        print_link_flags(fp, ifi->ifi_flags, m_flag);
 222
 223        if (tb[IFLA_MTU])
 224                print_int(PRINT_ANY,
 225                          "mtu", "mtu %u ",
 226                          rta_getattr_u32(tb[IFLA_MTU]));
 227
 228        if (tb[IFLA_MASTER]) {
 229                int master = rta_getattr_u32(tb[IFLA_MASTER]);
 230
 231                print_string(PRINT_ANY, "master", "master %s ",
 232                             ll_index_to_name(master));
 233        }
 234
 235        if (tb[IFLA_PROTINFO])
 236                print_protinfo(fp, tb[IFLA_PROTINFO]);
 237
 238        if (tb[IFLA_AF_SPEC])
 239                print_af_spec(tb[IFLA_AF_SPEC], ifi->ifi_index);
 240
 241        print_string(PRINT_FP, NULL, "%s", "\n");
 242        close_json_object();
 243        fflush(fp);
 244        return 0;
 245}
 246
 247static void usage(void)
 248{
 249        fprintf(stderr,
 250                "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n"
 251                "                               [ guard {on | off} ]\n"
 252                "                               [ hairpin {on | off} ]\n"
 253                "                               [ fastleave {on | off} ]\n"
 254                "                               [ root_block {on | off} ]\n"
 255                "                               [ learning {on | off} ]\n"
 256                "                               [ learning_sync {on | off} ]\n"
 257                "                               [ flood {on | off} ]\n"
 258                "                               [ mcast_flood {on | off} ]\n"
 259                "                               [ mcast_to_unicast {on | off} ]\n"
 260                "                               [ neigh_suppress {on | off} ]\n"
 261                "                               [ vlan_tunnel {on | off} ]\n"
 262                "                               [ isolated {on | off} ]\n"
 263                "                               [ hwmode {vepa | veb} ]\n"
 264                "                               [ backup_port DEVICE ] [ nobackup_port ]\n"
 265                "                               [ self ] [ master ]\n"
 266                "       bridge link show [dev DEV]\n");
 267        exit(-1);
 268}
 269
 270static int brlink_modify(int argc, char **argv)
 271{
 272        struct {
 273                struct nlmsghdr  n;
 274                struct ifinfomsg ifm;
 275                char             buf[512];
 276        } req = {
 277                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 278                .n.nlmsg_flags = NLM_F_REQUEST,
 279                .n.nlmsg_type = RTM_SETLINK,
 280                .ifm.ifi_family = PF_BRIDGE,
 281        };
 282        char *d = NULL;
 283        int backup_port_idx = -1;
 284        __s8 neigh_suppress = -1;
 285        __s8 learning = -1;
 286        __s8 learning_sync = -1;
 287        __s8 flood = -1;
 288        __s8 vlan_tunnel = -1;
 289        __s8 mcast_flood = -1;
 290        __s8 mcast_to_unicast = -1;
 291        __s8 isolated = -1;
 292        __s8 hairpin = -1;
 293        __s8 bpdu_guard = -1;
 294        __s8 fast_leave = -1;
 295        __s8 root_block = -1;
 296        __u32 cost = 0;
 297        __s16 priority = -1;
 298        __s8 state = -1;
 299        __s16 mode = -1;
 300        __u16 flags = 0;
 301        struct rtattr *nest;
 302        int ret;
 303
 304        while (argc > 0) {
 305                if (strcmp(*argv, "dev") == 0) {
 306                        NEXT_ARG();
 307                        d = *argv;
 308                } else if (strcmp(*argv, "guard") == 0) {
 309                        NEXT_ARG();
 310                        bpdu_guard = parse_on_off("guard", *argv, &ret);
 311                        if (ret)
 312                                return ret;
 313                } else if (strcmp(*argv, "hairpin") == 0) {
 314                        NEXT_ARG();
 315                        hairpin = parse_on_off("hairpin", *argv, &ret);
 316                        if (ret)
 317                                return ret;
 318                } else if (strcmp(*argv, "fastleave") == 0) {
 319                        NEXT_ARG();
 320                        fast_leave = parse_on_off("fastleave", *argv, &ret);
 321                        if (ret)
 322                                return ret;
 323                } else if (strcmp(*argv, "root_block") == 0) {
 324                        NEXT_ARG();
 325                        root_block = parse_on_off("root_block", *argv, &ret);
 326                        if (ret)
 327                                return ret;
 328                } else if (strcmp(*argv, "learning") == 0) {
 329                        NEXT_ARG();
 330                        learning = parse_on_off("learning", *argv, &ret);
 331                        if (ret)
 332                                return ret;
 333                } else if (strcmp(*argv, "learning_sync") == 0) {
 334                        NEXT_ARG();
 335                        learning_sync = parse_on_off("learning_sync", *argv, &ret);
 336                        if (ret)
 337                                return ret;
 338                } else if (strcmp(*argv, "flood") == 0) {
 339                        NEXT_ARG();
 340                        flood = parse_on_off("flood", *argv, &ret);
 341                        if (ret)
 342                                return ret;
 343                } else if (strcmp(*argv, "mcast_flood") == 0) {
 344                        NEXT_ARG();
 345                        mcast_flood = parse_on_off("mcast_flood", *argv, &ret);
 346                        if (ret)
 347                                return ret;
 348                } else if (strcmp(*argv, "mcast_to_unicast") == 0) {
 349                        NEXT_ARG();
 350                        mcast_to_unicast = parse_on_off("mcast_to_unicast", *argv, &ret);
 351                        if (ret)
 352                                return ret;
 353                } else if (strcmp(*argv, "cost") == 0) {
 354                        NEXT_ARG();
 355                        cost = atoi(*argv);
 356                } else if (strcmp(*argv, "priority") == 0) {
 357                        NEXT_ARG();
 358                        priority = atoi(*argv);
 359                } else if (strcmp(*argv, "state") == 0) {
 360                        NEXT_ARG();
 361                        char *endptr;
 362                        size_t nstates = ARRAY_SIZE(port_states);
 363
 364                        state = strtol(*argv, &endptr, 10);
 365                        if (!(**argv != '\0' && *endptr == '\0')) {
 366                                for (state = 0; state < nstates; state++)
 367                                        if (strcasecmp(port_states[state], *argv) == 0)
 368                                                break;
 369                                if (state == nstates) {
 370                                        fprintf(stderr,
 371                                                "Error: invalid STP port state\n");
 372                                        return -1;
 373                                }
 374                        }
 375                } else if (strcmp(*argv, "hwmode") == 0) {
 376                        NEXT_ARG();
 377                        flags = BRIDGE_FLAGS_SELF;
 378                        if (strcmp(*argv, "vepa") == 0)
 379                                mode = BRIDGE_MODE_VEPA;
 380                        else if (strcmp(*argv, "veb") == 0)
 381                                mode = BRIDGE_MODE_VEB;
 382                        else {
 383                                fprintf(stderr,
 384                                        "Mode argument must be \"vepa\" or \"veb\".\n");
 385                                return -1;
 386                        }
 387                } else if (strcmp(*argv, "self") == 0) {
 388                        flags |= BRIDGE_FLAGS_SELF;
 389                } else if (strcmp(*argv, "master") == 0) {
 390                        flags |= BRIDGE_FLAGS_MASTER;
 391                } else if (strcmp(*argv, "neigh_suppress") == 0) {
 392                        NEXT_ARG();
 393                        neigh_suppress = parse_on_off("neigh_suppress", *argv, &ret);
 394                        if (ret)
 395                                return ret;
 396                } else if (strcmp(*argv, "vlan_tunnel") == 0) {
 397                        NEXT_ARG();
 398                        vlan_tunnel = parse_on_off("vlan_tunnel", *argv, &ret);
 399                        if (ret)
 400                                return ret;
 401                } else if (strcmp(*argv, "isolated") == 0) {
 402                        NEXT_ARG();
 403                        isolated = parse_on_off("isolated", *argv, &ret);
 404                        if (ret)
 405                                return ret;
 406                } else if (strcmp(*argv, "backup_port") == 0) {
 407                        NEXT_ARG();
 408                        backup_port_idx = ll_name_to_index(*argv);
 409                        if (!backup_port_idx) {
 410                                fprintf(stderr, "Error: device %s does not exist\n",
 411                                        *argv);
 412                                return -1;
 413                        }
 414                } else if (strcmp(*argv, "nobackup_port") == 0) {
 415                        backup_port_idx = 0;
 416                } else {
 417                        usage();
 418                }
 419                argc--; argv++;
 420        }
 421        if (d == NULL) {
 422                fprintf(stderr, "Device is a required argument.\n");
 423                return -1;
 424        }
 425
 426
 427        req.ifm.ifi_index = ll_name_to_index(d);
 428        if (req.ifm.ifi_index == 0) {
 429                fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
 430                return -1;
 431        }
 432
 433        /* Nested PROTINFO attribute.  Contains: port flags, cost, priority and
 434         * state.
 435         */
 436        nest = addattr_nest(&req.n, sizeof(req),
 437                            IFLA_PROTINFO | NLA_F_NESTED);
 438        /* Flags first */
 439        if (bpdu_guard >= 0)
 440                addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard);
 441        if (hairpin >= 0)
 442                addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin);
 443        if (fast_leave >= 0)
 444                addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE,
 445                         fast_leave);
 446        if (root_block >= 0)
 447                addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block);
 448        if (flood >= 0)
 449                addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood);
 450        if (mcast_flood >= 0)
 451                addattr8(&req.n, sizeof(req), IFLA_BRPORT_MCAST_FLOOD,
 452                         mcast_flood);
 453        if (mcast_to_unicast >= 0)
 454                addattr8(&req.n, sizeof(req), IFLA_BRPORT_MCAST_TO_UCAST,
 455                         mcast_to_unicast);
 456        if (learning >= 0)
 457                addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning);
 458        if (learning_sync >= 0)
 459                addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC,
 460                         learning_sync);
 461
 462        if (cost > 0)
 463                addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost);
 464
 465        if (priority >= 0)
 466                addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority);
 467
 468        if (state >= 0)
 469                addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state);
 470
 471        if (neigh_suppress != -1)
 472                addattr8(&req.n, sizeof(req), IFLA_BRPORT_NEIGH_SUPPRESS,
 473                         neigh_suppress);
 474        if (vlan_tunnel != -1)
 475                addattr8(&req.n, sizeof(req), IFLA_BRPORT_VLAN_TUNNEL,
 476                         vlan_tunnel);
 477        if (isolated != -1)
 478                addattr8(&req.n, sizeof(req), IFLA_BRPORT_ISOLATED, isolated);
 479
 480        if (backup_port_idx != -1)
 481                addattr32(&req.n, sizeof(req), IFLA_BRPORT_BACKUP_PORT,
 482                          backup_port_idx);
 483
 484        addattr_nest_end(&req.n, nest);
 485
 486        /* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that
 487         * designates master or self operation and IFLA_BRIDGE_MODE
 488         * for hw 'vepa' or 'veb' operation modes. The hwmodes are
 489         * only valid in 'self' mode on some devices so far.
 490         */
 491        if (mode >= 0 || flags > 0) {
 492                nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
 493
 494                if (flags > 0)
 495                        addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
 496
 497                if (mode >= 0)
 498                        addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);
 499
 500                addattr_nest_end(&req.n, nest);
 501        }
 502
 503        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 504                return -1;
 505
 506        return 0;
 507}
 508
 509static int brlink_show(int argc, char **argv)
 510{
 511        char *filter_dev = NULL;
 512
 513        while (argc > 0) {
 514                if (strcmp(*argv, "dev") == 0) {
 515                        NEXT_ARG();
 516                        if (filter_dev)
 517                                duparg("dev", *argv);
 518                        filter_dev = *argv;
 519                }
 520                argc--; argv++;
 521        }
 522
 523        if (filter_dev) {
 524                filter_index = ll_name_to_index(filter_dev);
 525                if (!filter_index)
 526                        return nodev(filter_dev);
 527        }
 528
 529        if (show_details) {
 530                if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
 531                                             (compress_vlans ?
 532                                              RTEXT_FILTER_BRVLAN_COMPRESSED :
 533                                              RTEXT_FILTER_BRVLAN)) < 0) {
 534                        perror("Cannon send dump request");
 535                        exit(1);
 536                }
 537        } else {
 538                if (rtnl_linkdump_req(&rth, PF_BRIDGE) < 0) {
 539                        perror("Cannon send dump request");
 540                        exit(1);
 541                }
 542        }
 543
 544        new_json_obj(json);
 545        if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
 546                fprintf(stderr, "Dump terminated\n");
 547                exit(1);
 548        }
 549
 550        delete_json_obj();
 551        fflush(stdout);
 552        return 0;
 553}
 554
 555int do_link(int argc, char **argv)
 556{
 557        ll_init_map(&rth);
 558        if (argc > 0) {
 559                if (matches(*argv, "set") == 0 ||
 560                    matches(*argv, "change") == 0)
 561                        return brlink_modify(argc-1, argv+1);
 562                if (matches(*argv, "show") == 0 ||
 563                    matches(*argv, "lst") == 0 ||
 564                    matches(*argv, "list") == 0)
 565                        return brlink_show(argc-1, argv+1);
 566                if (matches(*argv, "help") == 0)
 567                        usage();
 568        } else
 569                return brlink_show(0, NULL);
 570
 571        fprintf(stderr, "Command \"%s\" is unknown, try \"bridge link help\".\n", *argv);
 572        exit(-1);
 573}
 574