Merge tag 'nios2-v5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/lftan...
[linux-2.6-microblaze.git] / net / bridge / br_mrp_netlink.c
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 }