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 9 static 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 19 static const struct nla_policy 20 br_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 28 static 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 66 static const struct nla_policy 67 br_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 72 static 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 95 static const struct nla_policy 96 br_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 101 static 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 124 static const struct nla_policy 125 br_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 131 static 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 158 static const struct nla_policy 159 br_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 165 static 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 192 static const struct nla_policy 193 br_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 202 static 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 238 int 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 307 int 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 325 out: 326 return err; 327 } 328