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