xref: /openbmc/linux/net/bridge/br_mrp_netlink.c (revision 55fd7e02)
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