xref: /openbmc/linux/net/bridge/br_mrp_netlink.c (revision 7419995a)
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 	[IFLA_BRIDGE_MRP_IN_ROLE]	= { .type = NLA_NESTED },
18 	[IFLA_BRIDGE_MRP_IN_STATE]	= { .type = NLA_NESTED },
19 	[IFLA_BRIDGE_MRP_START_IN_TEST]	= { .type = NLA_NESTED },
20 };
21 
22 static const struct nla_policy
23 br_mrp_instance_policy[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1] = {
24 	[IFLA_BRIDGE_MRP_INSTANCE_UNSPEC]	= { .type = NLA_REJECT },
25 	[IFLA_BRIDGE_MRP_INSTANCE_RING_ID]	= { .type = NLA_U32 },
26 	[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX]	= { .type = NLA_U32 },
27 	[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]	= { .type = NLA_U32 },
28 	[IFLA_BRIDGE_MRP_INSTANCE_PRIO]		= { .type = NLA_U16 },
29 };
30 
31 static int br_mrp_instance_parse(struct net_bridge *br, struct nlattr *attr,
32 				 int cmd, struct netlink_ext_ack *extack)
33 {
34 	struct nlattr *tb[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1];
35 	struct br_mrp_instance inst;
36 	int err;
37 
38 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_INSTANCE_MAX, attr,
39 			       br_mrp_instance_policy, extack);
40 	if (err)
41 		return err;
42 
43 	if (!tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID] ||
44 	    !tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX] ||
45 	    !tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]) {
46 		NL_SET_ERR_MSG_MOD(extack,
47 				   "Missing attribute: RING_ID or P_IFINDEX or S_IFINDEX");
48 		return -EINVAL;
49 	}
50 
51 	memset(&inst, 0, sizeof(inst));
52 
53 	inst.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID]);
54 	inst.p_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX]);
55 	inst.s_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]);
56 	inst.prio = MRP_DEFAULT_PRIO;
57 
58 	if (tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO])
59 		inst.prio = nla_get_u16(tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO]);
60 
61 	if (cmd == RTM_SETLINK)
62 		return br_mrp_add(br, &inst);
63 	else
64 		return br_mrp_del(br, &inst);
65 
66 	return 0;
67 }
68 
69 static const struct nla_policy
70 br_mrp_port_state_policy[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1] = {
71 	[IFLA_BRIDGE_MRP_PORT_STATE_UNSPEC]	= { .type = NLA_REJECT },
72 	[IFLA_BRIDGE_MRP_PORT_STATE_STATE]	= { .type = NLA_U32 },
73 };
74 
75 static int br_mrp_port_state_parse(struct net_bridge_port *p,
76 				   struct nlattr *attr,
77 				   struct netlink_ext_ack *extack)
78 {
79 	struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1];
80 	enum br_mrp_port_state_type state;
81 	int err;
82 
83 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_STATE_MAX, attr,
84 			       br_mrp_port_state_policy, extack);
85 	if (err)
86 		return err;
87 
88 	if (!tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]) {
89 		NL_SET_ERR_MSG_MOD(extack, "Missing attribute: STATE");
90 		return -EINVAL;
91 	}
92 
93 	state = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]);
94 
95 	return br_mrp_set_port_state(p, state);
96 }
97 
98 static const struct nla_policy
99 br_mrp_port_role_policy[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1] = {
100 	[IFLA_BRIDGE_MRP_PORT_ROLE_UNSPEC]	= { .type = NLA_REJECT },
101 	[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]	= { .type = NLA_U32 },
102 };
103 
104 static int br_mrp_port_role_parse(struct net_bridge_port *p,
105 				  struct nlattr *attr,
106 				  struct netlink_ext_ack *extack)
107 {
108 	struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1];
109 	enum br_mrp_port_role_type role;
110 	int err;
111 
112 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_ROLE_MAX, attr,
113 			       br_mrp_port_role_policy, extack);
114 	if (err)
115 		return err;
116 
117 	if (!tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]) {
118 		NL_SET_ERR_MSG_MOD(extack, "Missing attribute: ROLE");
119 		return -EINVAL;
120 	}
121 
122 	role = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]);
123 
124 	return br_mrp_set_port_role(p, role);
125 }
126 
127 static const struct nla_policy
128 br_mrp_ring_state_policy[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1] = {
129 	[IFLA_BRIDGE_MRP_RING_STATE_UNSPEC]	= { .type = NLA_REJECT },
130 	[IFLA_BRIDGE_MRP_RING_STATE_RING_ID]	= { .type = NLA_U32 },
131 	[IFLA_BRIDGE_MRP_RING_STATE_STATE]	= { .type = NLA_U32 },
132 };
133 
134 static int br_mrp_ring_state_parse(struct net_bridge *br, struct nlattr *attr,
135 				   struct netlink_ext_ack *extack)
136 {
137 	struct nlattr *tb[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1];
138 	struct br_mrp_ring_state state;
139 	int err;
140 
141 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_STATE_MAX, attr,
142 			       br_mrp_ring_state_policy, extack);
143 	if (err)
144 		return err;
145 
146 	if (!tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID] ||
147 	    !tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]) {
148 		NL_SET_ERR_MSG_MOD(extack,
149 				   "Missing attribute: RING_ID or STATE");
150 		return -EINVAL;
151 	}
152 
153 	memset(&state, 0x0, sizeof(state));
154 
155 	state.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID]);
156 	state.ring_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]);
157 
158 	return br_mrp_set_ring_state(br, &state);
159 }
160 
161 static const struct nla_policy
162 br_mrp_ring_role_policy[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1] = {
163 	[IFLA_BRIDGE_MRP_RING_ROLE_UNSPEC]	= { .type = NLA_REJECT },
164 	[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID]	= { .type = NLA_U32 },
165 	[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]	= { .type = NLA_U32 },
166 };
167 
168 static int br_mrp_ring_role_parse(struct net_bridge *br, struct nlattr *attr,
169 				  struct netlink_ext_ack *extack)
170 {
171 	struct nlattr *tb[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1];
172 	struct br_mrp_ring_role role;
173 	int err;
174 
175 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_ROLE_MAX, attr,
176 			       br_mrp_ring_role_policy, extack);
177 	if (err)
178 		return err;
179 
180 	if (!tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID] ||
181 	    !tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]) {
182 		NL_SET_ERR_MSG_MOD(extack,
183 				   "Missing attribute: RING_ID or ROLE");
184 		return -EINVAL;
185 	}
186 
187 	memset(&role, 0x0, sizeof(role));
188 
189 	role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID]);
190 	role.ring_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]);
191 
192 	return br_mrp_set_ring_role(br, &role);
193 }
194 
195 static const struct nla_policy
196 br_mrp_start_test_policy[IFLA_BRIDGE_MRP_START_TEST_MAX + 1] = {
197 	[IFLA_BRIDGE_MRP_START_TEST_UNSPEC]	= { .type = NLA_REJECT },
198 	[IFLA_BRIDGE_MRP_START_TEST_RING_ID]	= { .type = NLA_U32 },
199 	[IFLA_BRIDGE_MRP_START_TEST_INTERVAL]	= { .type = NLA_U32 },
200 	[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS]	= { .type = NLA_U32 },
201 	[IFLA_BRIDGE_MRP_START_TEST_PERIOD]	= { .type = NLA_U32 },
202 	[IFLA_BRIDGE_MRP_START_TEST_MONITOR]	= { .type = NLA_U32 },
203 };
204 
205 static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr,
206 				   struct netlink_ext_ack *extack)
207 {
208 	struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1];
209 	struct br_mrp_start_test test;
210 	int err;
211 
212 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_TEST_MAX, attr,
213 			       br_mrp_start_test_policy, extack);
214 	if (err)
215 		return err;
216 
217 	if (!tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID] ||
218 	    !tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL] ||
219 	    !tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] ||
220 	    !tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]) {
221 		NL_SET_ERR_MSG_MOD(extack,
222 				   "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD");
223 		return -EINVAL;
224 	}
225 
226 	memset(&test, 0x0, sizeof(test));
227 
228 	test.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID]);
229 	test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL]);
230 	test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS]);
231 	test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]);
232 	test.monitor = false;
233 
234 	if (tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR])
235 		test.monitor =
236 			nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR]);
237 
238 	return br_mrp_start_test(br, &test);
239 }
240 
241 static const struct nla_policy
242 br_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = {
243 	[IFLA_BRIDGE_MRP_IN_STATE_UNSPEC]	= { .type = NLA_REJECT },
244 	[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]	= { .type = NLA_U32 },
245 	[IFLA_BRIDGE_MRP_IN_STATE_STATE]	= { .type = NLA_U32 },
246 };
247 
248 static int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr,
249 				 struct netlink_ext_ack *extack)
250 {
251 	struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1];
252 	struct br_mrp_in_state state;
253 	int err;
254 
255 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr,
256 			       br_mrp_in_state_policy, extack);
257 	if (err)
258 		return err;
259 
260 	if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] ||
261 	    !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) {
262 		NL_SET_ERR_MSG_MOD(extack,
263 				   "Missing attribute: IN_ID or STATE");
264 		return -EINVAL;
265 	}
266 
267 	memset(&state, 0x0, sizeof(state));
268 
269 	state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]);
270 	state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]);
271 
272 	return br_mrp_set_in_state(br, &state);
273 }
274 
275 static const struct nla_policy
276 br_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = {
277 	[IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC]	= { .type = NLA_REJECT },
278 	[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]	= { .type = NLA_U32 },
279 	[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]		= { .type = NLA_U16 },
280 	[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]		= { .type = NLA_U32 },
281 	[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]	= { .type = NLA_U32 },
282 };
283 
284 static int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr,
285 				struct netlink_ext_ack *extack)
286 {
287 	struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1];
288 	struct br_mrp_in_role role;
289 	int err;
290 
291 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr,
292 			       br_mrp_in_role_policy, extack);
293 	if (err)
294 		return err;
295 
296 	if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] ||
297 	    !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] ||
298 	    !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] ||
299 	    !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) {
300 		NL_SET_ERR_MSG_MOD(extack,
301 				   "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX");
302 		return -EINVAL;
303 	}
304 
305 	memset(&role, 0x0, sizeof(role));
306 
307 	role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]);
308 	role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]);
309 	role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]);
310 	role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]);
311 
312 	return br_mrp_set_in_role(br, &role);
313 }
314 
315 static const struct nla_policy
316 br_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = {
317 	[IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC]	= { .type = NLA_REJECT },
318 	[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID]	= { .type = NLA_U32 },
319 	[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]	= { .type = NLA_U32 },
320 	[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]	= { .type = NLA_U32 },
321 	[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]	= { .type = NLA_U32 },
322 };
323 
324 static int br_mrp_start_in_test_parse(struct net_bridge *br,
325 				      struct nlattr *attr,
326 				      struct netlink_ext_ack *extack)
327 {
328 	struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1];
329 	struct br_mrp_start_in_test test;
330 	int err;
331 
332 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_IN_TEST_MAX, attr,
333 			       br_mrp_start_in_test_policy, extack);
334 	if (err)
335 		return err;
336 
337 	if (!tb[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] ||
338 	    !tb[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] ||
339 	    !tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS] ||
340 	    !tb[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]) {
341 		NL_SET_ERR_MSG_MOD(extack,
342 				   "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD");
343 		return -EINVAL;
344 	}
345 
346 	memset(&test, 0x0, sizeof(test));
347 
348 	test.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID]);
349 	test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]);
350 	test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]);
351 	test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]);
352 
353 	return br_mrp_start_in_test(br, &test);
354 }
355 
356 int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
357 		 struct nlattr *attr, int cmd, struct netlink_ext_ack *extack)
358 {
359 	struct nlattr *tb[IFLA_BRIDGE_MRP_MAX + 1];
360 	int err;
361 
362 	/* When this function is called for a port then the br pointer is
363 	 * invalid, therefor set the br to point correctly
364 	 */
365 	if (p)
366 		br = p->br;
367 
368 	if (br->stp_enabled != BR_NO_STP) {
369 		NL_SET_ERR_MSG_MOD(extack, "MRP can't be enabled if STP is already enabled");
370 		return -EINVAL;
371 	}
372 
373 	err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_MAX, attr,
374 			       br_mrp_policy, extack);
375 	if (err)
376 		return err;
377 
378 	if (tb[IFLA_BRIDGE_MRP_INSTANCE]) {
379 		err = br_mrp_instance_parse(br, tb[IFLA_BRIDGE_MRP_INSTANCE],
380 					    cmd, extack);
381 		if (err)
382 			return err;
383 	}
384 
385 	if (tb[IFLA_BRIDGE_MRP_PORT_STATE]) {
386 		err = br_mrp_port_state_parse(p, tb[IFLA_BRIDGE_MRP_PORT_STATE],
387 					      extack);
388 		if (err)
389 			return err;
390 	}
391 
392 	if (tb[IFLA_BRIDGE_MRP_PORT_ROLE]) {
393 		err = br_mrp_port_role_parse(p, tb[IFLA_BRIDGE_MRP_PORT_ROLE],
394 					     extack);
395 		if (err)
396 			return err;
397 	}
398 
399 	if (tb[IFLA_BRIDGE_MRP_RING_STATE]) {
400 		err = br_mrp_ring_state_parse(br,
401 					      tb[IFLA_BRIDGE_MRP_RING_STATE],
402 					      extack);
403 		if (err)
404 			return err;
405 	}
406 
407 	if (tb[IFLA_BRIDGE_MRP_RING_ROLE]) {
408 		err = br_mrp_ring_role_parse(br, tb[IFLA_BRIDGE_MRP_RING_ROLE],
409 					     extack);
410 		if (err)
411 			return err;
412 	}
413 
414 	if (tb[IFLA_BRIDGE_MRP_START_TEST]) {
415 		err = br_mrp_start_test_parse(br,
416 					      tb[IFLA_BRIDGE_MRP_START_TEST],
417 					      extack);
418 		if (err)
419 			return err;
420 	}
421 
422 	if (tb[IFLA_BRIDGE_MRP_IN_STATE]) {
423 		err = br_mrp_in_state_parse(br, tb[IFLA_BRIDGE_MRP_IN_STATE],
424 					    extack);
425 		if (err)
426 			return err;
427 	}
428 
429 	if (tb[IFLA_BRIDGE_MRP_IN_ROLE]) {
430 		err = br_mrp_in_role_parse(br, tb[IFLA_BRIDGE_MRP_IN_ROLE],
431 					   extack);
432 		if (err)
433 			return err;
434 	}
435 
436 	if (tb[IFLA_BRIDGE_MRP_START_IN_TEST]) {
437 		err = br_mrp_start_in_test_parse(br,
438 						 tb[IFLA_BRIDGE_MRP_START_IN_TEST],
439 						 extack);
440 		if (err)
441 			return err;
442 	}
443 
444 	return 0;
445 }
446 
447 int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br)
448 {
449 	struct nlattr *tb, *mrp_tb;
450 	struct br_mrp *mrp;
451 
452 	mrp_tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP);
453 	if (!mrp_tb)
454 		return -EMSGSIZE;
455 
456 	hlist_for_each_entry_rcu(mrp, &br->mrp_list, list) {
457 		struct net_bridge_port *p;
458 
459 		tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO);
460 		if (!tb)
461 			goto nla_info_failure;
462 
463 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ID,
464 				mrp->ring_id))
465 			goto nla_put_failure;
466 
467 		p = rcu_dereference(mrp->p_port);
468 		if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_P_IFINDEX,
469 				     p->dev->ifindex))
470 			goto nla_put_failure;
471 
472 		p = rcu_dereference(mrp->s_port);
473 		if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_S_IFINDEX,
474 				     p->dev->ifindex))
475 			goto nla_put_failure;
476 
477 		p = rcu_dereference(mrp->i_port);
478 		if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX,
479 				     p->dev->ifindex))
480 			goto nla_put_failure;
481 
482 		if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO,
483 				mrp->prio))
484 			goto nla_put_failure;
485 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_STATE,
486 				mrp->ring_state))
487 			goto nla_put_failure;
488 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ROLE,
489 				mrp->ring_role))
490 			goto nla_put_failure;
491 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL,
492 				mrp->test_interval))
493 			goto nla_put_failure;
494 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS,
495 				mrp->test_max_miss))
496 			goto nla_put_failure;
497 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR,
498 				mrp->test_monitor))
499 			goto nla_put_failure;
500 
501 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE,
502 				mrp->in_state))
503 			goto nla_put_failure;
504 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE,
505 				mrp->in_role))
506 			goto nla_put_failure;
507 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL,
508 				mrp->in_test_interval))
509 			goto nla_put_failure;
510 		if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS,
511 				mrp->in_test_max_miss))
512 			goto nla_put_failure;
513 
514 		nla_nest_end(skb, tb);
515 	}
516 	nla_nest_end(skb, mrp_tb);
517 
518 	return 0;
519 
520 nla_put_failure:
521 	nla_nest_cancel(skb, tb);
522 
523 nla_info_failure:
524 	nla_nest_cancel(skb, mrp_tb);
525 
526 	return -EMSGSIZE;
527 }
528 
529 int br_mrp_ring_port_open(struct net_device *dev, u8 loc)
530 {
531 	struct net_bridge_port *p;
532 	int err = 0;
533 
534 	p = br_port_get_rcu(dev);
535 	if (!p) {
536 		err = -EINVAL;
537 		goto out;
538 	}
539 
540 	if (loc)
541 		p->flags |= BR_MRP_LOST_CONT;
542 	else
543 		p->flags &= ~BR_MRP_LOST_CONT;
544 
545 	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
546 
547 out:
548 	return err;
549 }
550 
551 int br_mrp_in_port_open(struct net_device *dev, u8 loc)
552 {
553 	struct net_bridge_port *p;
554 	int err = 0;
555 
556 	p = br_port_get_rcu(dev);
557 	if (!p) {
558 		err = -EINVAL;
559 		goto out;
560 	}
561 
562 	if (loc)
563 		p->flags |= BR_MRP_LOST_IN_CONT;
564 	else
565 		p->flags &= ~BR_MRP_LOST_IN_CONT;
566 
567 	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
568 
569 out:
570 	return err;
571 }
572