iproute2/bridge/mst.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * Get/set Multiple Spanning Tree (MST) states
   4 */
   5
   6#include <stdio.h>
   7#include <sys/time.h>
   8#include <netinet/in.h>
   9#include <linux/if_bridge.h>
  10#include <net/if.h>
  11
  12#include "libnetlink.h"
  13#include "json_print.h"
  14#include "utils.h"
  15
  16#include "br_common.h"
  17
  18#define MST_ID_LEN 9
  19
  20#define __stringify_1(x...) #x
  21#define __stringify(x...) __stringify_1(x)
  22
  23static unsigned int filter_index;
  24
  25static void usage(void)
  26{
  27        fprintf(stderr,
  28                "Usage: bridge mst set dev DEV msti MSTI state STATE\n"
  29                "       bridge mst {show} [ dev DEV ]\n");
  30        exit(-1);
  31}
  32
  33static void print_mst_entry(struct rtattr *a, FILE *fp)
  34{
  35        struct rtattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
  36        __u16 msti = 0;
  37        __u8 state = 0;
  38
  39        parse_rtattr_flags(tb, IFLA_BRIDGE_MST_ENTRY_MAX, RTA_DATA(a),
  40                           RTA_PAYLOAD(a), NLA_F_NESTED);
  41
  42
  43        if (!(tb[IFLA_BRIDGE_MST_ENTRY_MSTI] &&
  44              tb[IFLA_BRIDGE_MST_ENTRY_STATE])) {
  45                fprintf(stderr, "BUG: broken MST entry");
  46                return;
  47        }
  48
  49        msti = rta_getattr_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
  50        state = rta_getattr_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
  51
  52        open_json_object(NULL);
  53        print_uint(PRINT_ANY, "msti", "%u", msti);
  54        print_nl();
  55        print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s    ", "");
  56        print_stp_state(state);
  57        print_nl();
  58        close_json_object();
  59}
  60
  61static int print_msts(struct nlmsghdr *n, void *arg)
  62{
  63        struct ifinfomsg *ifi = NLMSG_DATA(n);
  64        struct rtattr *af_spec, *mst, *a;
  65        int rem = n->nlmsg_len;
  66        bool opened = false;
  67
  68        rem -= NLMSG_LENGTH(sizeof(*ifi));
  69        if (rem < 0) {
  70                fprintf(stderr, "BUG: wrong nlmsg len %d\n", rem);
  71                return -1;
  72        }
  73
  74        af_spec = parse_rtattr_one(IFLA_AF_SPEC, IFLA_RTA(ifi), rem);
  75        if (!af_spec)
  76                return -1;
  77
  78        if (filter_index && filter_index != ifi->ifi_index)
  79                return 0;
  80
  81        mst = parse_rtattr_one_nested(NLA_F_NESTED | IFLA_BRIDGE_MST, af_spec);
  82        if (!mst)
  83                return 0;
  84
  85        rem = RTA_PAYLOAD(mst);
  86        for (a = RTA_DATA(mst); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
  87                unsigned short rta_type = a->rta_type & NLA_TYPE_MASK;
  88
  89                if (rta_type > IFLA_BRIDGE_MST_MAX)
  90                        continue;
  91
  92                switch (rta_type) {
  93                case IFLA_BRIDGE_MST_ENTRY:
  94                        if (!opened) {
  95                                open_json_object(NULL);
  96                                print_color_string(PRINT_ANY, COLOR_IFNAME,
  97                                                   "ifname",
  98                                                   "%-" __stringify(IFNAMSIZ) "s  ",
  99                                                   ll_index_to_name(ifi->ifi_index));
 100                                open_json_array(PRINT_JSON, "mst");
 101                                opened = true;
 102                        } else {
 103                                print_string(PRINT_FP, NULL, "%-"
 104                                             __stringify(IFNAMSIZ) "s  ", "");
 105                        }
 106
 107                        print_mst_entry(a, arg);
 108                        break;
 109                }
 110        }
 111
 112        if (opened) {
 113                close_json_array(PRINT_JSON, NULL);
 114                close_json_object();
 115        }
 116
 117        return 0;
 118}
 119
 120static int mst_show(int argc, char **argv)
 121{
 122        char *filter_dev = NULL;
 123
 124        while (argc > 0) {
 125                if (strcmp(*argv, "dev") == 0) {
 126                        NEXT_ARG();
 127                        if (filter_dev)
 128                                duparg("dev", *argv);
 129                        filter_dev = *argv;
 130                }
 131                argc--; argv++;
 132        }
 133
 134        if (filter_dev) {
 135                filter_index = ll_name_to_index(filter_dev);
 136                if (!filter_index)
 137                        return nodev(filter_dev);
 138        }
 139
 140        if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE, RTEXT_FILTER_MST) < 0) {
 141                perror("Cannon send dump request");
 142                exit(1);
 143        }
 144
 145        new_json_obj(json);
 146
 147        if (!is_json_context()) {
 148                printf("%-" __stringify(IFNAMSIZ) "s  "
 149                       "%-" __stringify(MST_ID_LEN) "s",
 150                       "port", "msti");
 151                printf("\n");
 152        }
 153
 154        if (rtnl_dump_filter(&rth, print_msts, stdout) < 0) {
 155                fprintf(stderr, "Dump terminated\n");
 156                delete_json_obj();
 157                return -1;
 158        }
 159
 160        delete_json_obj();
 161        fflush(stdout);
 162        return 0;
 163}
 164
 165static int mst_set(int argc, char **argv)
 166{
 167        struct {
 168                struct nlmsghdr         n;
 169                struct ifinfomsg        ifi;
 170                char                    buf[512];
 171        } req = {
 172                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 173                .n.nlmsg_flags = NLM_F_REQUEST,
 174                .n.nlmsg_type = RTM_SETLINK,
 175                .ifi.ifi_family = PF_BRIDGE,
 176        };
 177        char *d = NULL, *m = NULL, *s = NULL, *endptr;
 178        struct rtattr *af_spec, *mst, *entry;
 179        __u16 msti;
 180        int state;
 181
 182        while (argc > 0) {
 183                if (strcmp(*argv, "dev") == 0) {
 184                        NEXT_ARG();
 185                        d = *argv;
 186                } else if (strcmp(*argv, "msti") == 0) {
 187                        NEXT_ARG();
 188                        m = *argv;
 189                } else if (strcmp(*argv, "state") == 0) {
 190                        NEXT_ARG();
 191                        s = *argv;
 192                } else {
 193                        if (matches(*argv, "help") == 0)
 194                                usage();
 195                }
 196                argc--; argv++;
 197        }
 198
 199        if (d == NULL || m == NULL || s == NULL) {
 200                fprintf(stderr, "Device, MSTI and state are required arguments.\n");
 201                return -1;
 202        }
 203
 204        req.ifi.ifi_index = ll_name_to_index(d);
 205        if (!req.ifi.ifi_index)
 206                return nodev(d);
 207
 208        msti = strtol(m, &endptr, 10);
 209        if (!(*s != '\0' && *endptr == '\0')) {
 210                fprintf(stderr,
 211                        "Error: invalid MSTI\n");
 212                return -1;
 213        }
 214
 215        state = strtol(s, &endptr, 10);
 216        if (!(*s != '\0' && *endptr == '\0'))
 217                state = parse_stp_state(s);
 218        
 219        if (state < 0 || state > UINT8_MAX) {
 220                fprintf(stderr, "Error: invalid STP port state\n");
 221                return -1;
 222        }
 223
 224        af_spec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
 225        mst = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST);
 226
 227        entry = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY);
 228        entry->rta_type |= NLA_F_NESTED;
 229
 230        addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_MSTI, msti);
 231        addattr8(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_STATE, state);
 232
 233        addattr_nest_end(&req.n, entry);
 234
 235        addattr_nest_end(&req.n, mst);
 236        addattr_nest_end(&req.n, af_spec);
 237
 238
 239        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 240                return -1;
 241
 242        return 0;
 243}
 244
 245int do_mst(int argc, char **argv)
 246{
 247        ll_init_map(&rth);
 248
 249        if (argc > 0) {
 250                if (matches(*argv, "set") == 0)
 251                        return mst_set(argc-1, argv+1);
 252
 253                if (matches(*argv, "show") == 0 ||
 254                    matches(*argv, "lst") == 0 ||
 255                    matches(*argv, "list") == 0)
 256                        return mst_show(argc-1, argv+1);
 257                if (matches(*argv, "help") == 0)
 258                        usage();
 259        } else
 260                return mst_show(0, NULL);
 261
 262        fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mst help\".\n", *argv);
 263        exit(-1);
 264}
 265