iproute2/ip/iplink_bridge_slave.c
<<
>>
Prefs
   1/*
   2 * iplink_bridge_slave.c        Bridge slave 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 <sys/socket.h>
  14#include <netinet/in.h>
  15#include <linux/if_link.h>
  16#include <linux/if_bridge.h>
  17
  18#include "rt_names.h"
  19#include "utils.h"
  20#include "ip_common.h"
  21
  22static void print_explain(FILE *f)
  23{
  24        fprintf(f,
  25                "Usage: ... bridge_slave [ fdb_flush ]\n"
  26                "                       [ state STATE ]\n"
  27                "                       [ priority PRIO ]\n"
  28                "                       [ cost COST ]\n"
  29                "                       [ guard {on | off} ]\n"
  30                "                       [ hairpin {on | off} ]\n"
  31                "                       [ fastleave {on | off} ]\n"
  32                "                       [ root_block {on | off} ]\n"
  33                "                       [ learning {on | off} ]\n"
  34                "                       [ flood {on | off} ]\n"
  35                "                       [ proxy_arp {on | off} ]\n"
  36                "                       [ proxy_arp_wifi {on | off} ]\n"
  37                "                       [ mcast_router MULTICAST_ROUTER ]\n"
  38                "                       [ mcast_fast_leave {on | off} ]\n"
  39                "                       [ mcast_flood {on | off} ]\n"
  40                "                       [ mcast_to_unicast {on | off} ]\n"
  41                "                       [ group_fwd_mask MASK ]\n"
  42                "                       [ neigh_suppress {on | off} ]\n"
  43                "                       [ vlan_tunnel {on | off} ]\n"
  44                "                       [ isolated {on | off} ]\n"
  45                "                       [ backup_port DEVICE ] [ nobackup_port ]\n"
  46        );
  47}
  48
  49static void explain(void)
  50{
  51        print_explain(stderr);
  52}
  53
  54static const char *port_states[] = {
  55        [BR_STATE_DISABLED] = "disabled",
  56        [BR_STATE_LISTENING] = "listening",
  57        [BR_STATE_LEARNING] = "learning",
  58        [BR_STATE_FORWARDING] = "forwarding",
  59        [BR_STATE_BLOCKING] = "blocking",
  60};
  61
  62static const char *fwd_mask_tbl[16] = {
  63        [0]     = "stp",
  64        [2]     = "lacp",
  65        [14]    = "lldp"
  66};
  67
  68static void print_portstate(FILE *f, __u8 state)
  69{
  70        if (state <= BR_STATE_BLOCKING)
  71                print_string(PRINT_ANY,
  72                             "state",
  73                             "state %s ",
  74                             port_states[state]);
  75        else
  76                print_int(PRINT_ANY, "state_index", "state (%d) ", state);
  77}
  78
  79static void _print_timer(FILE *f, const char *attr, struct rtattr *timer)
  80{
  81        struct timeval tv;
  82
  83        __jiffies_to_tv(&tv, rta_getattr_u64(timer));
  84        if (is_json_context()) {
  85                json_writer_t *jw = get_json_writer();
  86
  87                jsonw_name(jw, attr);
  88                jsonw_printf(jw, "%i.%.2i",
  89                             (int)tv.tv_sec, (int)tv.tv_usec / 10000);
  90        } else {
  91                fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
  92                        (int)tv.tv_usec / 10000);
  93        }
  94}
  95
  96static void _bitmask2str(__u16 bitmask, char *dst, size_t dst_size,
  97                         const char **tbl)
  98{
  99        int len, i;
 100
 101        for (i = 0, len = 0; bitmask; i++, bitmask >>= 1) {
 102                if (bitmask & 0x1) {
 103                        if (tbl[i])
 104                                len += snprintf(dst + len, dst_size - len, "%s,",
 105                                                tbl[i]);
 106                        else
 107                                len += snprintf(dst + len, dst_size - len, "0x%x,",
 108                                                (1 << i));
 109                }
 110        }
 111
 112        if (!len)
 113                snprintf(dst, dst_size, "0x0");
 114        else
 115                dst[len - 1] = 0;
 116}
 117
 118static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
 119                                   struct rtattr *tb[])
 120{
 121        if (!tb)
 122                return;
 123
 124        if (tb[IFLA_BRPORT_STATE])
 125                print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE]));
 126
 127        if (tb[IFLA_BRPORT_PRIORITY])
 128                print_int(PRINT_ANY,
 129                          "priority",
 130                          "priority %d ",
 131                          rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
 132
 133        if (tb[IFLA_BRPORT_COST])
 134                print_int(PRINT_ANY,
 135                          "cost",
 136                          "cost %d ",
 137                          rta_getattr_u32(tb[IFLA_BRPORT_COST]));
 138
 139        if (tb[IFLA_BRPORT_MODE])
 140                print_on_off(PRINT_ANY, "hairpin", "hairpin %s ",
 141                             rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
 142
 143        if (tb[IFLA_BRPORT_GUARD])
 144                print_on_off(PRINT_ANY, "guard", "guard %s ",
 145                             rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
 146
 147        if (tb[IFLA_BRPORT_PROTECT])
 148                print_on_off(PRINT_ANY, "root_block", "root_block %s ",
 149                             rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
 150
 151        if (tb[IFLA_BRPORT_FAST_LEAVE])
 152                print_on_off(PRINT_ANY, "fastleave", "fastleave %s ",
 153                             rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
 154
 155        if (tb[IFLA_BRPORT_LEARNING])
 156                print_on_off(PRINT_ANY, "learning", "learning %s ",
 157                             rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
 158
 159        if (tb[IFLA_BRPORT_UNICAST_FLOOD])
 160                print_on_off(PRINT_ANY, "flood", "flood %s ",
 161                             rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
 162
 163        if (tb[IFLA_BRPORT_ID])
 164                print_0xhex(PRINT_ANY, "id", "port_id %#llx ",
 165                            rta_getattr_u16(tb[IFLA_BRPORT_ID]));
 166
 167        if (tb[IFLA_BRPORT_NO])
 168                print_0xhex(PRINT_ANY, "no", "port_no %#llx ",
 169                           rta_getattr_u16(tb[IFLA_BRPORT_NO]));
 170
 171        if (tb[IFLA_BRPORT_DESIGNATED_PORT])
 172                print_uint(PRINT_ANY,
 173                           "designated_port",
 174                           "designated_port %u ",
 175                           rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
 176
 177        if (tb[IFLA_BRPORT_DESIGNATED_COST])
 178                print_uint(PRINT_ANY,
 179                           "designated_cost",
 180                           "designated_cost %u ",
 181                           rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
 182
 183        if (tb[IFLA_BRPORT_BRIDGE_ID]) {
 184                char bridge_id[32];
 185
 186                br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_BRIDGE_ID]),
 187                                  bridge_id, sizeof(bridge_id));
 188                print_string(PRINT_ANY,
 189                             "bridge_id",
 190                             "designated_bridge %s ",
 191                             bridge_id);
 192        }
 193
 194        if (tb[IFLA_BRPORT_ROOT_ID]) {
 195                char root_id[32];
 196
 197                br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_ROOT_ID]),
 198                                  root_id, sizeof(root_id));
 199                print_string(PRINT_ANY,
 200                             "root_id",
 201                             "designated_root %s ", root_id);
 202        }
 203
 204        if (tb[IFLA_BRPORT_HOLD_TIMER])
 205                _print_timer(f, "hold_timer", tb[IFLA_BRPORT_HOLD_TIMER]);
 206
 207        if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER])
 208                _print_timer(f, "message_age_timer",
 209                             tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
 210
 211        if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER])
 212                _print_timer(f, "forward_delay_timer",
 213                             tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
 214
 215        if (tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK])
 216                print_uint(PRINT_ANY,
 217                           "topology_change_ack",
 218                           "topology_change_ack %u ",
 219                           rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
 220
 221        if (tb[IFLA_BRPORT_CONFIG_PENDING])
 222                print_uint(PRINT_ANY,
 223                           "config_pending",
 224                           "config_pending %u ",
 225                           rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
 226
 227        if (tb[IFLA_BRPORT_PROXYARP])
 228                print_on_off(PRINT_ANY, "proxy_arp", "proxy_arp %s ",
 229                             rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
 230
 231        if (tb[IFLA_BRPORT_PROXYARP_WIFI])
 232                print_on_off(PRINT_ANY, "proxy_arp_wifi", "proxy_arp_wifi %s ",
 233                             rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
 234
 235        if (tb[IFLA_BRPORT_MULTICAST_ROUTER])
 236                print_uint(PRINT_ANY,
 237                           "multicast_router",
 238                           "mcast_router %u ",
 239                           rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
 240
 241        if (tb[IFLA_BRPORT_FAST_LEAVE])
 242                // not printing any json here because
 243                // we already printed fast_leave before
 244                print_string(PRINT_FP,
 245                             NULL,
 246                             "mcast_fast_leave %s ",
 247                             rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]) ? "on" : "off");
 248
 249        if (tb[IFLA_BRPORT_MCAST_FLOOD])
 250                print_on_off(PRINT_ANY, "mcast_flood", "mcast_flood %s ",
 251                             rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
 252
 253        if (tb[IFLA_BRPORT_MCAST_TO_UCAST])
 254                print_on_off(PRINT_ANY, "mcast_to_unicast", "mcast_to_unicast %s ",
 255                             rta_getattr_u8(tb[IFLA_BRPORT_MCAST_TO_UCAST]));
 256
 257        if (tb[IFLA_BRPORT_NEIGH_SUPPRESS])
 258                print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
 259                             rta_getattr_u8(tb[IFLA_BRPORT_NEIGH_SUPPRESS]));
 260
 261        if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
 262                char convbuf[256];
 263                __u16 fwd_mask;
 264
 265                fwd_mask = rta_getattr_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
 266                print_0xhex(PRINT_ANY, "group_fwd_mask",
 267                            "group_fwd_mask %#llx ", fwd_mask);
 268                _bitmask2str(fwd_mask, convbuf, sizeof(convbuf), fwd_mask_tbl);
 269                print_string(PRINT_ANY, "group_fwd_mask_str",
 270                             "group_fwd_mask_str %s ", convbuf);
 271        }
 272
 273        if (tb[IFLA_BRPORT_VLAN_TUNNEL])
 274                print_on_off(PRINT_ANY, "vlan_tunnel", "vlan_tunnel %s ",
 275                             rta_getattr_u8(tb[IFLA_BRPORT_VLAN_TUNNEL]));
 276
 277        if (tb[IFLA_BRPORT_ISOLATED])
 278                print_on_off(PRINT_ANY, "isolated", "isolated %s ",
 279                             rta_getattr_u8(tb[IFLA_BRPORT_ISOLATED]));
 280
 281        if (tb[IFLA_BRPORT_BACKUP_PORT]) {
 282                int backup_p = rta_getattr_u32(tb[IFLA_BRPORT_BACKUP_PORT]);
 283
 284                print_string(PRINT_ANY, "backup_port", "backup_port %s ",
 285                             ll_index_to_name(backup_p));
 286        }
 287}
 288
 289static void bridge_slave_parse_on_off(char *arg_name, char *arg_val,
 290                                      struct nlmsghdr *n, int type)
 291{
 292        int ret;
 293        __u8 val = parse_on_off(arg_name, arg_val, &ret);
 294
 295        if (ret)
 296                exit(1);
 297        addattr8(n, 1024, type, val);
 298}
 299
 300static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv,
 301                                  struct nlmsghdr *n)
 302{
 303        __u8 state;
 304        __u16 priority;
 305        __u32 cost;
 306
 307        while (argc > 0) {
 308                if (matches(*argv, "fdb_flush") == 0) {
 309                        addattr(n, 1024, IFLA_BRPORT_FLUSH);
 310                } else if (matches(*argv, "state") == 0) {
 311                        NEXT_ARG();
 312                        if (get_u8(&state, *argv, 0))
 313                                invarg("state is invalid", *argv);
 314                        addattr8(n, 1024, IFLA_BRPORT_STATE, state);
 315                } else if (matches(*argv, "priority") == 0) {
 316                        NEXT_ARG();
 317                        if (get_u16(&priority, *argv, 0))
 318                                invarg("priority is invalid", *argv);
 319                        addattr16(n, 1024, IFLA_BRPORT_PRIORITY, priority);
 320                } else if (matches(*argv, "cost") == 0) {
 321                        NEXT_ARG();
 322                        if (get_u32(&cost, *argv, 0))
 323                                invarg("cost is invalid", *argv);
 324                        addattr32(n, 1024, IFLA_BRPORT_COST, cost);
 325                } else if (matches(*argv, "hairpin") == 0) {
 326                        NEXT_ARG();
 327                        bridge_slave_parse_on_off("hairpin", *argv, n,
 328                                                  IFLA_BRPORT_MODE);
 329                } else if (matches(*argv, "guard") == 0) {
 330                        NEXT_ARG();
 331                        bridge_slave_parse_on_off("guard", *argv, n,
 332                                                  IFLA_BRPORT_GUARD);
 333                } else if (matches(*argv, "root_block") == 0) {
 334                        NEXT_ARG();
 335                        bridge_slave_parse_on_off("root_block", *argv, n,
 336                                                  IFLA_BRPORT_PROTECT);
 337                } else if (matches(*argv, "fastleave") == 0) {
 338                        NEXT_ARG();
 339                        bridge_slave_parse_on_off("fastleave", *argv, n,
 340                                                  IFLA_BRPORT_FAST_LEAVE);
 341                } else if (matches(*argv, "learning") == 0) {
 342                        NEXT_ARG();
 343                        bridge_slave_parse_on_off("learning", *argv, n,
 344                                                  IFLA_BRPORT_LEARNING);
 345                } else if (matches(*argv, "flood") == 0) {
 346                        NEXT_ARG();
 347                        bridge_slave_parse_on_off("flood", *argv, n,
 348                                                  IFLA_BRPORT_UNICAST_FLOOD);
 349                } else if (matches(*argv, "mcast_flood") == 0) {
 350                        NEXT_ARG();
 351                        bridge_slave_parse_on_off("mcast_flood", *argv, n,
 352                                                  IFLA_BRPORT_MCAST_FLOOD);
 353                } else if (matches(*argv, "mcast_to_unicast") == 0) {
 354                        NEXT_ARG();
 355                        bridge_slave_parse_on_off("mcast_to_unicast", *argv, n,
 356                                                  IFLA_BRPORT_MCAST_TO_UCAST);
 357                } else if (matches(*argv, "proxy_arp") == 0) {
 358                        NEXT_ARG();
 359                        bridge_slave_parse_on_off("proxy_arp", *argv, n,
 360                                                  IFLA_BRPORT_PROXYARP);
 361                } else if (matches(*argv, "proxy_arp_wifi") == 0) {
 362                        NEXT_ARG();
 363                        bridge_slave_parse_on_off("proxy_arp_wifi", *argv, n,
 364                                                  IFLA_BRPORT_PROXYARP_WIFI);
 365                } else if (matches(*argv, "mcast_router") == 0) {
 366                        __u8 mcast_router;
 367
 368                        NEXT_ARG();
 369                        if (get_u8(&mcast_router, *argv, 0))
 370                                invarg("invalid mcast_router", *argv);
 371                        addattr8(n, 1024, IFLA_BRPORT_MULTICAST_ROUTER,
 372                                 mcast_router);
 373                } else if (matches(*argv, "mcast_fast_leave") == 0) {
 374                        NEXT_ARG();
 375                        bridge_slave_parse_on_off("mcast_fast_leave", *argv, n,
 376                                                  IFLA_BRPORT_FAST_LEAVE);
 377                } else if (matches(*argv, "neigh_suppress") == 0) {
 378                        NEXT_ARG();
 379                        bridge_slave_parse_on_off("neigh_suppress", *argv, n,
 380                                                  IFLA_BRPORT_NEIGH_SUPPRESS);
 381                } else if (matches(*argv, "group_fwd_mask") == 0) {
 382                        __u16 mask;
 383
 384                        NEXT_ARG();
 385                        if (get_u16(&mask, *argv, 0))
 386                                invarg("invalid group_fwd_mask", *argv);
 387                        addattr16(n, 1024, IFLA_BRPORT_GROUP_FWD_MASK, mask);
 388                } else if (matches(*argv, "vlan_tunnel") == 0) {
 389                        NEXT_ARG();
 390                        bridge_slave_parse_on_off("vlan_tunnel", *argv, n,
 391                                                  IFLA_BRPORT_VLAN_TUNNEL);
 392                } else if (matches(*argv, "isolated") == 0) {
 393                        NEXT_ARG();
 394                        bridge_slave_parse_on_off("isolated", *argv, n,
 395                                                  IFLA_BRPORT_ISOLATED);
 396                } else if (matches(*argv, "backup_port") == 0) {
 397                        int ifindex;
 398
 399                        NEXT_ARG();
 400                        ifindex = ll_name_to_index(*argv);
 401                        if (!ifindex)
 402                                invarg("Device does not exist\n", *argv);
 403                        addattr32(n, 1024, IFLA_BRPORT_BACKUP_PORT, ifindex);
 404                } else if (matches(*argv, "nobackup_port") == 0) {
 405                        addattr32(n, 1024, IFLA_BRPORT_BACKUP_PORT, 0);
 406                } else if (matches(*argv, "help") == 0) {
 407                        explain();
 408                        return -1;
 409                } else {
 410                        fprintf(stderr, "bridge_slave: unknown option \"%s\"?\n",
 411                                *argv);
 412                        explain();
 413                        return -1;
 414                }
 415                argc--, argv++;
 416        }
 417
 418        return 0;
 419}
 420
 421static void bridge_slave_print_help(struct link_util *lu, int argc, char **argv,
 422                FILE *f)
 423{
 424        print_explain(f);
 425}
 426
 427struct link_util bridge_slave_link_util = {
 428        .id             = "bridge_slave",
 429        .maxattr        = IFLA_BRPORT_MAX,
 430        .print_opt      = bridge_slave_print_opt,
 431        .parse_opt      = bridge_slave_parse_opt,
 432        .print_help     = bridge_slave_print_help,
 433        .parse_ifla_xstats = bridge_parse_xstats,
 434        .print_ifla_xstats = bridge_print_xstats,
 435};
 436