devlink: put netnsid to nested handle
[linux-2.6-microblaze.git] / net / devlink / linecard.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5  */
6
7 #include "devl_internal.h"
8
9 struct devlink_linecard {
10         struct list_head list;
11         struct devlink *devlink;
12         unsigned int index;
13         const struct devlink_linecard_ops *ops;
14         void *priv;
15         enum devlink_linecard_state state;
16         struct mutex state_lock; /* Protects state */
17         const char *type;
18         struct devlink_linecard_type *types;
19         unsigned int types_count;
20         struct devlink *nested_devlink;
21 };
22
23 unsigned int devlink_linecard_index(struct devlink_linecard *linecard)
24 {
25         return linecard->index;
26 }
27
28 static struct devlink_linecard *
29 devlink_linecard_get_by_index(struct devlink *devlink,
30                               unsigned int linecard_index)
31 {
32         struct devlink_linecard *devlink_linecard;
33
34         list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) {
35                 if (devlink_linecard->index == linecard_index)
36                         return devlink_linecard;
37         }
38         return NULL;
39 }
40
41 static bool devlink_linecard_index_exists(struct devlink *devlink,
42                                           unsigned int linecard_index)
43 {
44         return devlink_linecard_get_by_index(devlink, linecard_index);
45 }
46
47 static struct devlink_linecard *
48 devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
49 {
50         if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) {
51                 u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
52                 struct devlink_linecard *linecard;
53
54                 linecard = devlink_linecard_get_by_index(devlink, linecard_index);
55                 if (!linecard)
56                         return ERR_PTR(-ENODEV);
57                 return linecard;
58         }
59         return ERR_PTR(-EINVAL);
60 }
61
62 static struct devlink_linecard *
63 devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
64 {
65         return devlink_linecard_get_from_attrs(devlink, info->attrs);
66 }
67
68 static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
69                                         struct devlink *devlink)
70 {
71         struct nlattr *nested_attr;
72
73         nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK);
74         if (!nested_attr)
75                 return -EMSGSIZE;
76         if (devlink_nl_put_handle(msg, devlink))
77                 goto nla_put_failure;
78         if (!net_eq(net, devlink_net(devlink))) {
79                 int id = peernet2id_alloc(net, devlink_net(devlink),
80                                           GFP_KERNEL);
81
82                 if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
83                         return -EMSGSIZE;
84         }
85
86         nla_nest_end(msg, nested_attr);
87         return 0;
88
89 nla_put_failure:
90         nla_nest_cancel(msg, nested_attr);
91         return -EMSGSIZE;
92 }
93
94 struct devlink_linecard_type {
95         const char *type;
96         const void *priv;
97 };
98
99 static int devlink_nl_linecard_fill(struct sk_buff *msg,
100                                     struct devlink *devlink,
101                                     struct devlink_linecard *linecard,
102                                     enum devlink_command cmd, u32 portid,
103                                     u32 seq, int flags,
104                                     struct netlink_ext_ack *extack)
105 {
106         struct devlink_linecard_type *linecard_type;
107         struct nlattr *attr;
108         void *hdr;
109         int i;
110
111         hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
112         if (!hdr)
113                 return -EMSGSIZE;
114
115         if (devlink_nl_put_handle(msg, devlink))
116                 goto nla_put_failure;
117         if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
118                 goto nla_put_failure;
119         if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
120                 goto nla_put_failure;
121         if (linecard->type &&
122             nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
123                 goto nla_put_failure;
124
125         if (linecard->types_count) {
126                 attr = nla_nest_start(msg,
127                                       DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
128                 if (!attr)
129                         goto nla_put_failure;
130                 for (i = 0; i < linecard->types_count; i++) {
131                         linecard_type = &linecard->types[i];
132                         if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
133                                            linecard_type->type)) {
134                                 nla_nest_cancel(msg, attr);
135                                 goto nla_put_failure;
136                         }
137                 }
138                 nla_nest_end(msg, attr);
139         }
140
141         if (linecard->nested_devlink &&
142             devlink_nl_put_nested_handle(msg, devlink_net(devlink),
143                                          linecard->nested_devlink))
144                 goto nla_put_failure;
145
146         genlmsg_end(msg, hdr);
147         return 0;
148
149 nla_put_failure:
150         genlmsg_cancel(msg, hdr);
151         return -EMSGSIZE;
152 }
153
154 static void devlink_linecard_notify(struct devlink_linecard *linecard,
155                                     enum devlink_command cmd)
156 {
157         struct devlink *devlink = linecard->devlink;
158         struct sk_buff *msg;
159         int err;
160
161         WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
162                 cmd != DEVLINK_CMD_LINECARD_DEL);
163
164         if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
165                 return;
166
167         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
168         if (!msg)
169                 return;
170
171         err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
172                                        NULL);
173         if (err) {
174                 nlmsg_free(msg);
175                 return;
176         }
177
178         genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
179                                 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
180 }
181
182 void devlink_linecards_notify_register(struct devlink *devlink)
183 {
184         struct devlink_linecard *linecard;
185
186         list_for_each_entry(linecard, &devlink->linecard_list, list)
187                 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
188 }
189
190 void devlink_linecards_notify_unregister(struct devlink *devlink)
191 {
192         struct devlink_linecard *linecard;
193
194         list_for_each_entry_reverse(linecard, &devlink->linecard_list, list)
195                 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
196 }
197
198 int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info)
199 {
200         struct devlink *devlink = info->user_ptr[0];
201         struct devlink_linecard *linecard;
202         struct sk_buff *msg;
203         int err;
204
205         linecard = devlink_linecard_get_from_info(devlink, info);
206         if (IS_ERR(linecard))
207                 return PTR_ERR(linecard);
208
209         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
210         if (!msg)
211                 return -ENOMEM;
212
213         mutex_lock(&linecard->state_lock);
214         err = devlink_nl_linecard_fill(msg, devlink, linecard,
215                                        DEVLINK_CMD_LINECARD_NEW,
216                                        info->snd_portid, info->snd_seq, 0,
217                                        info->extack);
218         mutex_unlock(&linecard->state_lock);
219         if (err) {
220                 nlmsg_free(msg);
221                 return err;
222         }
223
224         return genlmsg_reply(msg, info);
225 }
226
227 static int devlink_nl_linecard_get_dump_one(struct sk_buff *msg,
228                                             struct devlink *devlink,
229                                             struct netlink_callback *cb,
230                                             int flags)
231 {
232         struct devlink_nl_dump_state *state = devlink_dump_state(cb);
233         struct devlink_linecard *linecard;
234         int idx = 0;
235         int err = 0;
236
237         list_for_each_entry(linecard, &devlink->linecard_list, list) {
238                 if (idx < state->idx) {
239                         idx++;
240                         continue;
241                 }
242                 mutex_lock(&linecard->state_lock);
243                 err = devlink_nl_linecard_fill(msg, devlink, linecard,
244                                                DEVLINK_CMD_LINECARD_NEW,
245                                                NETLINK_CB(cb->skb).portid,
246                                                cb->nlh->nlmsg_seq, flags,
247                                                cb->extack);
248                 mutex_unlock(&linecard->state_lock);
249                 if (err) {
250                         state->idx = idx;
251                         break;
252                 }
253                 idx++;
254         }
255
256         return err;
257 }
258
259 int devlink_nl_linecard_get_dumpit(struct sk_buff *skb,
260                                    struct netlink_callback *cb)
261 {
262         return devlink_nl_dumpit(skb, cb, devlink_nl_linecard_get_dump_one);
263 }
264
265 static struct devlink_linecard_type *
266 devlink_linecard_type_lookup(struct devlink_linecard *linecard,
267                              const char *type)
268 {
269         struct devlink_linecard_type *linecard_type;
270         int i;
271
272         for (i = 0; i < linecard->types_count; i++) {
273                 linecard_type = &linecard->types[i];
274                 if (!strcmp(type, linecard_type->type))
275                         return linecard_type;
276         }
277         return NULL;
278 }
279
280 static int devlink_linecard_type_set(struct devlink_linecard *linecard,
281                                      const char *type,
282                                      struct netlink_ext_ack *extack)
283 {
284         const struct devlink_linecard_ops *ops = linecard->ops;
285         struct devlink_linecard_type *linecard_type;
286         int err;
287
288         mutex_lock(&linecard->state_lock);
289         if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
290                 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
291                 err = -EBUSY;
292                 goto out;
293         }
294         if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
295                 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
296                 err = -EBUSY;
297                 goto out;
298         }
299
300         linecard_type = devlink_linecard_type_lookup(linecard, type);
301         if (!linecard_type) {
302                 NL_SET_ERR_MSG(extack, "Unsupported line card type provided");
303                 err = -EINVAL;
304                 goto out;
305         }
306
307         if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
308             linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
309                 NL_SET_ERR_MSG(extack, "Line card already provisioned");
310                 err = -EBUSY;
311                 /* Check if the line card is provisioned in the same
312                  * way the user asks. In case it is, make the operation
313                  * to return success.
314                  */
315                 if (ops->same_provision &&
316                     ops->same_provision(linecard, linecard->priv,
317                                         linecard_type->type,
318                                         linecard_type->priv))
319                         err = 0;
320                 goto out;
321         }
322
323         linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
324         linecard->type = linecard_type->type;
325         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
326         mutex_unlock(&linecard->state_lock);
327         err = ops->provision(linecard, linecard->priv, linecard_type->type,
328                              linecard_type->priv, extack);
329         if (err) {
330                 /* Provisioning failed. Assume the linecard is unprovisioned
331                  * for future operations.
332                  */
333                 mutex_lock(&linecard->state_lock);
334                 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
335                 linecard->type = NULL;
336                 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
337                 mutex_unlock(&linecard->state_lock);
338         }
339         return err;
340
341 out:
342         mutex_unlock(&linecard->state_lock);
343         return err;
344 }
345
346 static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
347                                        struct netlink_ext_ack *extack)
348 {
349         int err;
350
351         mutex_lock(&linecard->state_lock);
352         if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
353                 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
354                 err = -EBUSY;
355                 goto out;
356         }
357         if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
358                 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
359                 err = -EBUSY;
360                 goto out;
361         }
362         if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
363                 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
364                 linecard->type = NULL;
365                 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
366                 err = 0;
367                 goto out;
368         }
369
370         if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
371                 NL_SET_ERR_MSG(extack, "Line card is not provisioned");
372                 err = 0;
373                 goto out;
374         }
375         linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
376         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
377         mutex_unlock(&linecard->state_lock);
378         err = linecard->ops->unprovision(linecard, linecard->priv,
379                                          extack);
380         if (err) {
381                 /* Unprovisioning failed. Assume the linecard is unprovisioned
382                  * for future operations.
383                  */
384                 mutex_lock(&linecard->state_lock);
385                 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
386                 linecard->type = NULL;
387                 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
388                 mutex_unlock(&linecard->state_lock);
389         }
390         return err;
391
392 out:
393         mutex_unlock(&linecard->state_lock);
394         return err;
395 }
396
397 int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
398                                      struct genl_info *info)
399 {
400         struct netlink_ext_ack *extack = info->extack;
401         struct devlink *devlink = info->user_ptr[0];
402         struct devlink_linecard *linecard;
403         int err;
404
405         linecard = devlink_linecard_get_from_info(devlink, info);
406         if (IS_ERR(linecard))
407                 return PTR_ERR(linecard);
408
409         if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
410                 const char *type;
411
412                 type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
413                 if (strcmp(type, "")) {
414                         err = devlink_linecard_type_set(linecard, type, extack);
415                         if (err)
416                                 return err;
417                 } else {
418                         err = devlink_linecard_type_unset(linecard, extack);
419                         if (err)
420                                 return err;
421                 }
422         }
423
424         return 0;
425 }
426
427 static int devlink_linecard_types_init(struct devlink_linecard *linecard)
428 {
429         struct devlink_linecard_type *linecard_type;
430         unsigned int count;
431         int i;
432
433         count = linecard->ops->types_count(linecard, linecard->priv);
434         linecard->types = kmalloc_array(count, sizeof(*linecard_type),
435                                         GFP_KERNEL);
436         if (!linecard->types)
437                 return -ENOMEM;
438         linecard->types_count = count;
439
440         for (i = 0; i < count; i++) {
441                 linecard_type = &linecard->types[i];
442                 linecard->ops->types_get(linecard, linecard->priv, i,
443                                          &linecard_type->type,
444                                          &linecard_type->priv);
445         }
446         return 0;
447 }
448
449 static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
450 {
451         kfree(linecard->types);
452 }
453
454 /**
455  *      devl_linecard_create - Create devlink linecard
456  *
457  *      @devlink: devlink
458  *      @linecard_index: driver-specific numerical identifier of the linecard
459  *      @ops: linecards ops
460  *      @priv: user priv pointer
461  *
462  *      Create devlink linecard instance with provided linecard index.
463  *      Caller can use any indexing, even hw-related one.
464  *
465  *      Return: Line card structure or an ERR_PTR() encoded error code.
466  */
467 struct devlink_linecard *
468 devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
469                      const struct devlink_linecard_ops *ops, void *priv)
470 {
471         struct devlink_linecard *linecard;
472         int err;
473
474         if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
475                     !ops->types_count || !ops->types_get))
476                 return ERR_PTR(-EINVAL);
477
478         if (devlink_linecard_index_exists(devlink, linecard_index))
479                 return ERR_PTR(-EEXIST);
480
481         linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
482         if (!linecard)
483                 return ERR_PTR(-ENOMEM);
484
485         linecard->devlink = devlink;
486         linecard->index = linecard_index;
487         linecard->ops = ops;
488         linecard->priv = priv;
489         linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
490         mutex_init(&linecard->state_lock);
491
492         err = devlink_linecard_types_init(linecard);
493         if (err) {
494                 mutex_destroy(&linecard->state_lock);
495                 kfree(linecard);
496                 return ERR_PTR(err);
497         }
498
499         list_add_tail(&linecard->list, &devlink->linecard_list);
500         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
501         return linecard;
502 }
503 EXPORT_SYMBOL_GPL(devl_linecard_create);
504
505 /**
506  *      devl_linecard_destroy - Destroy devlink linecard
507  *
508  *      @linecard: devlink linecard
509  */
510 void devl_linecard_destroy(struct devlink_linecard *linecard)
511 {
512         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
513         list_del(&linecard->list);
514         devlink_linecard_types_fini(linecard);
515         mutex_destroy(&linecard->state_lock);
516         kfree(linecard);
517 }
518 EXPORT_SYMBOL_GPL(devl_linecard_destroy);
519
520 /**
521  *      devlink_linecard_provision_set - Set provisioning on linecard
522  *
523  *      @linecard: devlink linecard
524  *      @type: linecard type
525  *
526  *      This is either called directly from the provision() op call or
527  *      as a result of the provision() op call asynchronously.
528  */
529 void devlink_linecard_provision_set(struct devlink_linecard *linecard,
530                                     const char *type)
531 {
532         mutex_lock(&linecard->state_lock);
533         WARN_ON(linecard->type && strcmp(linecard->type, type));
534         linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
535         linecard->type = type;
536         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
537         mutex_unlock(&linecard->state_lock);
538 }
539 EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
540
541 /**
542  *      devlink_linecard_provision_clear - Clear provisioning on linecard
543  *
544  *      @linecard: devlink linecard
545  *
546  *      This is either called directly from the unprovision() op call or
547  *      as a result of the unprovision() op call asynchronously.
548  */
549 void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
550 {
551         mutex_lock(&linecard->state_lock);
552         WARN_ON(linecard->nested_devlink);
553         linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
554         linecard->type = NULL;
555         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
556         mutex_unlock(&linecard->state_lock);
557 }
558 EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
559
560 /**
561  *      devlink_linecard_provision_fail - Fail provisioning on linecard
562  *
563  *      @linecard: devlink linecard
564  *
565  *      This is either called directly from the provision() op call or
566  *      as a result of the provision() op call asynchronously.
567  */
568 void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
569 {
570         mutex_lock(&linecard->state_lock);
571         WARN_ON(linecard->nested_devlink);
572         linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
573         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
574         mutex_unlock(&linecard->state_lock);
575 }
576 EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
577
578 /**
579  *      devlink_linecard_activate - Set linecard active
580  *
581  *      @linecard: devlink linecard
582  */
583 void devlink_linecard_activate(struct devlink_linecard *linecard)
584 {
585         mutex_lock(&linecard->state_lock);
586         WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED);
587         linecard->state = DEVLINK_LINECARD_STATE_ACTIVE;
588         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
589         mutex_unlock(&linecard->state_lock);
590 }
591 EXPORT_SYMBOL_GPL(devlink_linecard_activate);
592
593 /**
594  *      devlink_linecard_deactivate - Set linecard inactive
595  *
596  *      @linecard: devlink linecard
597  */
598 void devlink_linecard_deactivate(struct devlink_linecard *linecard)
599 {
600         mutex_lock(&linecard->state_lock);
601         switch (linecard->state) {
602         case DEVLINK_LINECARD_STATE_ACTIVE:
603                 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
604                 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
605                 break;
606         case DEVLINK_LINECARD_STATE_UNPROVISIONING:
607                 /* Line card is being deactivated as part
608                  * of unprovisioning flow.
609                  */
610                 break;
611         default:
612                 WARN_ON(1);
613                 break;
614         }
615         mutex_unlock(&linecard->state_lock);
616 }
617 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
618
619 /**
620  *      devlink_linecard_nested_dl_set - Attach/detach nested devlink
621  *                                       instance to linecard.
622  *
623  *      @linecard: devlink linecard
624  *      @nested_devlink: devlink instance to attach or NULL to detach
625  */
626 void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
627                                     struct devlink *nested_devlink)
628 {
629         mutex_lock(&linecard->state_lock);
630         linecard->nested_devlink = nested_devlink;
631         devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
632         mutex_unlock(&linecard->state_lock);
633 }
634 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);