linux/net/bridge/br_mrp_netlink.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2
   3#include <net/genetlink.h>
   4
   5#include <uapi/linux/mrp_bridge.h>
   6#include "br_private.h"
   7#include "br_private_mrp.h"
   8
   9static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = {
  10        [IFLA_BRIDGE_MRP_UNSPEC]        = { .type = NLA_REJECT },
  11        [IFLA_BRIDGE_MRP_INSTANCE]      = { .type = NLA_NESTED },
  12        [IFLA_BRIDGE_MRP_PORT_STATE]    = { .type = NLA_NESTED },
  13        [IFLA_BRIDGE_MRP_PORT_ROLE]     = { .type = NLA_NESTED },
  14        [IFLA_BRIDGE_MRP_RING_STATE]    = { .type = NLA_NESTED },
  15        [IFLA_BRIDGE_MRP_RING_ROLE]     = { .type = NLA_NESTED },
  16        [IFLA_BRIDGE_MRP_START_TEST]    = { .type = NLA_NESTED },
  17};
  18
  19static const struct nla_policy
  20br_mrp_instance_policy[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1] = {
  21        [IFLA_BRIDGE_MRP_INSTANCE_UNSPEC]       = { .type = NLA_REJECT },
  22        [IFLA_BRIDGE_MRP_INSTANCE_RING_ID]      = { .type = NLA_U32 },
  23        [IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX]    = { .type = NLA_U32 },
  24        [IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]    = { .type = NLA_U32 },
  25        [IFLA_BRIDGE_MRP_INSTANCE_PRIO]         = { .type = NLA_U16 },
  26};
  27
  28static int br_mrp_instance_parse(struct net_bridge *br, struct nlattr *attr,
  29                                 int cmd, struct netlink_ext_ack *extack)
  30{
  31        struct nlattr *tb[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1];
  32        struct br_mrp_instance inst;
  33        int err;
  34
  35        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_INSTANCE_MAX, attr,
  36                               br_mrp_instance_policy, extack);
  37        if (err)
  38                return err;
  39
  40        if (!tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID] ||
  41            !tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX] ||
  42            !tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]) {
  43                NL_SET_ERR_MSG_MOD(extack,
  44                                   "Missing attribute: RING_ID or P_IFINDEX or S_IFINDEX");
  45                return -EINVAL;
  46        }
  47
  48        memset(&inst, 0, sizeof(inst));
  49
  50        inst.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID]);
  51        inst.p_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX]);
  52        inst.s_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]);
  53        inst.prio = MRP_DEFAULT_PRIO;
  54
  55        if (tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO])
  56                inst.prio = nla_get_u16(tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO]);
  57
  58        if (cmd == RTM_SETLINK)
  59                return br_mrp_add(br, &inst);
  60        else
  61                return br_mrp_del(br, &inst);
  62
  63        return 0;
  64}
  65
  66static const struct nla_policy
  67br_mrp_port_state_policy[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1] = {
  68        [IFLA_BRIDGE_MRP_PORT_STATE_UNSPEC]     = { .type = NLA_REJECT },
  69        [IFLA_BRIDGE_MRP_PORT_STATE_STATE]      = { .type = NLA_U32 },
  70};
  71
  72static int br_mrp_port_state_parse(struct net_bridge_port *p,
  73                                   struct nlattr *attr,
  74                                   struct netlink_ext_ack *extack)
  75{
  76        struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1];
  77        enum br_mrp_port_state_type state;
  78        int err;
  79
  80        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_STATE_MAX, attr,
  81                               br_mrp_port_state_policy, extack);
  82        if (err)
  83                return err;
  84
  85        if (!tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]) {
  86                NL_SET_ERR_MSG_MOD(extack, "Missing attribute: STATE");
  87                return -EINVAL;
  88        }
  89
  90        state = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]);
  91
  92        return br_mrp_set_port_state(p, state);
  93}
  94
  95static const struct nla_policy
  96br_mrp_port_role_policy[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1] = {
  97        [IFLA_BRIDGE_MRP_PORT_ROLE_UNSPEC]      = { .type = NLA_REJECT },
  98        [IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]        = { .type = NLA_U32 },
  99};
 100
 101static int br_mrp_port_role_parse(struct net_bridge_port *p,
 102                                  struct nlattr *attr,
 103                                  struct netlink_ext_ack *extack)
 104{
 105        struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1];
 106        enum br_mrp_port_role_type role;
 107        int err;
 108
 109        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_ROLE_MAX, attr,
 110                               br_mrp_port_role_policy, extack);
 111        if (err)
 112                return err;
 113
 114        if (!tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]) {
 115                NL_SET_ERR_MSG_MOD(extack, "Missing attribute: ROLE");
 116                return -EINVAL;
 117        }
 118
 119        role = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]);
 120
 121        return br_mrp_set_port_role(p, role);
 122}
 123
 124static const struct nla_policy
 125br_mrp_ring_state_policy[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1] = {
 126        [IFLA_BRIDGE_MRP_RING_STATE_UNSPEC]     = { .type = NLA_REJECT },
 127        [IFLA_BRIDGE_MRP_RING_STATE_RING_ID]    = { .type = NLA_U32 },
 128        [IFLA_BRIDGE_MRP_RING_STATE_STATE]      = { .type = NLA_U32 },
 129};
 130
 131static int br_mrp_ring_state_parse(struct net_bridge *br, struct nlattr *attr,
 132                                   struct netlink_ext_ack *extack)
 133{
 134        struct nlattr *tb[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1];
 135        struct br_mrp_ring_state state;
 136        int err;
 137
 138        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_STATE_MAX, attr,
 139                               br_mrp_ring_state_policy, extack);
 140        if (err)
 141                return err;
 142
 143        if (!tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID] ||
 144            !tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]) {
 145                NL_SET_ERR_MSG_MOD(extack,
 146                                   "Missing attribute: RING_ID or STATE");
 147                return -EINVAL;
 148        }
 149
 150        memset(&state, 0x0, sizeof(state));
 151
 152        state.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID]);
 153        state.ring_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]);
 154
 155        return br_mrp_set_ring_state(br, &state);
 156}
 157
 158static const struct nla_policy
 159br_mrp_ring_role_policy[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1] = {
 160        [IFLA_BRIDGE_MRP_RING_ROLE_UNSPEC]      = { .type = NLA_REJECT },
 161        [IFLA_BRIDGE_MRP_RING_ROLE_RING_ID]     = { .type = NLA_U32 },
 162        [IFLA_BRIDGE_MRP_RING_ROLE_ROLE]        = { .type = NLA_U32 },
 163};
 164
 165static int br_mrp_ring_role_parse(struct net_bridge *br, struct nlattr *attr,
 166                                  struct netlink_ext_ack *extack)
 167{
 168        struct nlattr *tb[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1];
 169        struct br_mrp_ring_role role;
 170        int err;
 171
 172        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_ROLE_MAX, attr,
 173                               br_mrp_ring_role_policy, extack);
 174        if (err)
 175                return err;
 176
 177        if (!tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID] ||
 178            !tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]) {
 179                NL_SET_ERR_MSG_MOD(extack,
 180                                   "Missing attribute: RING_ID or ROLE");
 181                return -EINVAL;
 182        }
 183
 184        memset(&role, 0x0, sizeof(role));
 185
 186        role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID]);
 187        role.ring_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]);
 188
 189        return br_mrp_set_ring_role(br, &role);
 190}
 191
 192static const struct nla_policy
 193br_mrp_start_test_policy[IFLA_BRIDGE_MRP_START_TEST_MAX + 1] = {
 194        [IFLA_BRIDGE_MRP_START_TEST_UNSPEC]     = { .type = NLA_REJECT },
 195        [IFLA_BRIDGE_MRP_START_TEST_RING_ID]    = { .type = NLA_U32 },
 196        [IFLA_BRIDGE_MRP_START_TEST_INTERVAL]   = { .type = NLA_U32 },
 197        [IFLA_BRIDGE_MRP_START_TEST_MAX_MISS]   = { .type = NLA_U32 },
 198        [IFLA_BRIDGE_MRP_START_TEST_PERIOD]     = { .type = NLA_U32 },
 199        [IFLA_BRIDGE_MRP_START_TEST_MONITOR]    = { .type = NLA_U32 },
 200};
 201
 202static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr,
 203                                   struct netlink_ext_ack *extack)
 204{
 205        struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1];
 206        struct br_mrp_start_test test;
 207        int err;
 208
 209        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_TEST_MAX, attr,
 210                               br_mrp_start_test_policy, extack);
 211        if (err)
 212                return err;
 213
 214        if (!tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID] ||
 215            !tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL] ||
 216            !tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] ||
 217            !tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]) {
 218                NL_SET_ERR_MSG_MOD(extack,
 219                                   "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD");
 220                return -EINVAL;
 221        }
 222
 223        memset(&test, 0x0, sizeof(test));
 224
 225        test.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID]);
 226        test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL]);
 227        test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS]);
 228        test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]);
 229        test.monitor = false;
 230
 231        if (tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR])
 232                test.monitor =
 233                        nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR]);
 234
 235        return br_mrp_start_test(br, &test);
 236}
 237
 238int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
 239                 struct nlattr *attr, int cmd, struct netlink_ext_ack *extack)
 240{
 241        struct nlattr *tb[IFLA_BRIDGE_MRP_MAX + 1];
 242        int err;
 243
 244        /* When this function is called for a port then the br pointer is
 245         * invalid, therefor set the br to point correctly
 246         */
 247        if (p)
 248                br = p->br;
 249
 250        if (br->stp_enabled != BR_NO_STP) {
 251                NL_SET_ERR_MSG_MOD(extack, "MRP can't be enabled if STP is already enabled");
 252                return -EINVAL;
 253        }
 254
 255        err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_MAX, attr,
 256                               br_mrp_policy, extack);
 257        if (err)
 258                return err;
 259
 260        if (tb[IFLA_BRIDGE_MRP_INSTANCE]) {
 261                err = br_mrp_instance_parse(br, tb[IFLA_BRIDGE_MRP_INSTANCE],
 262                                            cmd, extack);
 263                if (err)
 264                        return err;
 265        }
 266
 267        if (tb[IFLA_BRIDGE_MRP_PORT_STATE]) {
 268                err = br_mrp_port_state_parse(p, tb[IFLA_BRIDGE_MRP_PORT_STATE],
 269                                              extack);
 270                if (err)
 271                        return err;
 272        }
 273
 274        if (tb[IFLA_BRIDGE_MRP_PORT_ROLE]) {
 275                err = br_mrp_port_role_parse(p, tb[IFLA_BRIDGE_MRP_PORT_ROLE],
 276                                             extack);
 277                if (err)
 278                        return err;
 279        }
 280
 281        if (tb[IFLA_BRIDGE_MRP_RING_STATE]) {
 282                err = br_mrp_ring_state_parse(br,
 283                                              tb[IFLA_BRIDGE_MRP_RING_STATE],
 284                                              extack);
 285                if (err)
 286                        return err;
 287        }
 288
 289        if (tb[IFLA_BRIDGE_MRP_RING_ROLE]) {
 290                err = br_mrp_ring_role_parse(br, tb[IFLA_BRIDGE_MRP_RING_ROLE],
 291                                             extack);
 292                if (err)
 293                        return err;
 294        }
 295
 296        if (tb[IFLA_BRIDGE_MRP_START_TEST]) {
 297                err = br_mrp_start_test_parse(br,
 298                                              tb[IFLA_BRIDGE_MRP_START_TEST],
 299                                              extack);
 300                if (err)
 301                        return err;
 302        }
 303
 304        return 0;
 305}
 306
 307int br_mrp_port_open(struct net_device *dev, u8 loc)
 308{
 309        struct net_bridge_port *p;
 310        int err = 0;
 311
 312        p = br_port_get_rcu(dev);
 313        if (!p) {
 314                err = -EINVAL;
 315                goto out;
 316        }
 317
 318        if (loc)
 319                p->flags |= BR_MRP_LOST_CONT;
 320        else
 321                p->flags &= ~BR_MRP_LOST_CONT;
 322
 323        br_ifinfo_notify(RTM_NEWLINK, NULL, p);
 324
 325out:
 326        return err;
 327}
 328