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