Whamcloud - gitweb
LU-17705 ptlrpc: replace synchronize_rcu() with rcu_barrier()
[fs/lustre-release.git] / lnet / utils / lnetconfig / liblnetconfig_udsp.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2011, 2017, Intel Corporation.
7  *
8  * Copyright (c) 2018-2020 Data Direct Networks.
9  *
10  * Copyright (c) 2020, Whamcloud.
11  */
12
13 /*
14  * This file is part of Lustre, http://www.lustre.org/
15  *
16  * Author: Sonia Sharma
17  */
18
19 #include <errno.h>
20 #include <limits.h>
21 #include <byteswap.h>
22 #include <netdb.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/ioctl.h>
28 #include <libcfs/util/ioctl.h>
29 #include <linux/lnet/lnetctl.h>
30 #include "liblnd.h"
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <linux/lnet/lnet-dlc.h>
35 #include "liblnetconfig.h"
36
37 static inline bool
38 lnet_udsp_criteria_present(struct lnet_ud_nid_descr *descr)
39 {
40         return descr->ud_net_id.udn_net_type != 0;
41 }
42
43 static struct lnet_udsp *lnet_udsp_alloc(void)
44 {
45         struct lnet_udsp *udsp;
46
47         udsp = calloc(1, sizeof(*udsp));
48
49         if (!udsp)
50                 return NULL;
51
52         INIT_LIST_HEAD(&udsp->udsp_on_list);
53         INIT_LIST_HEAD(&udsp->udsp_src.ud_addr_range);
54         INIT_LIST_HEAD(&udsp->udsp_src.ud_net_id.udn_net_num_range);
55         INIT_LIST_HEAD(&udsp->udsp_dst.ud_addr_range);
56         INIT_LIST_HEAD(&udsp->udsp_dst.ud_net_id.udn_net_num_range);
57         INIT_LIST_HEAD(&udsp->udsp_rte.ud_addr_range);
58         INIT_LIST_HEAD(&udsp->udsp_rte.ud_net_id.udn_net_num_range);
59
60         return udsp;
61 }
62
63 static void
64 lnet_udsp_nid_descr_free(struct lnet_ud_nid_descr *nid_descr, bool blk)
65 {
66         struct list_head *net_range = &nid_descr->ud_net_id.udn_net_num_range;
67
68         if (!lnet_udsp_criteria_present(nid_descr))
69                 return;
70
71         /* memory management is a bit tricky here. When we allocate the
72          * memory to store the NID descriptor we allocate a large buffer
73          * for all the data, so we need to free the entire buffer at
74          * once. If the net is present the net_range->next points to that
75          * buffer otherwise if the ud_addr_range is present then it's the
76          * ud_addr_range.next
77          */
78         if (blk) {
79                 if (!list_empty(net_range))
80                         free(net_range->next);
81                 else if (!list_empty(&nid_descr->ud_addr_range))
82                         free(nid_descr->ud_addr_range.next);
83         } else {
84                 cfs_expr_list_free_list(net_range);
85                 cfs_expr_list_free_list(&nid_descr->ud_addr_range);
86         }
87 }
88
89 static void
90 lnet_udsp_free(struct lnet_udsp *udsp, bool blk)
91 {
92         lnet_udsp_nid_descr_free(&udsp->udsp_src, blk);
93         lnet_udsp_nid_descr_free(&udsp->udsp_dst, blk);
94         lnet_udsp_nid_descr_free(&udsp->udsp_rte, blk);
95
96         free(udsp);
97 }
98
99 static void
100 copy_range_info(void __user **bulk, void **buf, struct list_head *list,
101                 int count)
102 {
103         struct lnet_range_expr *range_expr;
104         struct cfs_range_expr *range;
105         struct cfs_expr_list *exprs;
106         int range_count = count;
107         int i;
108
109         if (range_count == 0)
110                 return;
111
112         if (range_count == -1) {
113                 struct lnet_expressions *e;
114
115                 e = *bulk;
116                 range_count = e->le_count;
117                 *bulk += sizeof(*e);
118         }
119
120         exprs = *buf;
121         INIT_LIST_HEAD(&exprs->el_link);
122         INIT_LIST_HEAD(&exprs->el_exprs);
123         list_add_tail(&exprs->el_link, list);
124         *buf += sizeof(*exprs);
125
126         for (i = 0; i < range_count; i++) {
127                 range_expr = *bulk;
128                 range = *buf;
129                 INIT_LIST_HEAD(&range->re_link);
130                 range->re_lo = range_expr->re_lo;
131                 range->re_hi = range_expr->re_hi;
132                 range->re_stride = range_expr->re_stride;
133                 list_add_tail(&range->re_link, &exprs->el_exprs);
134                 *bulk += sizeof(*range_expr);
135                 *buf += sizeof(*range);
136         }
137 }
138
139 static int
140 copy_ioc_udsp_descr(struct lnet_ud_nid_descr *nid_descr, char *type,
141                     void **bulk, __u32 *bulk_size)
142 {
143         struct lnet_ioctl_udsp_descr *ioc_nid = *bulk;
144         struct lnet_expressions *exprs;
145         __u32 descr_type;
146         int expr_count = 0;
147         int range_count = 0;
148         int i;
149         __u32 size;
150         int remaining_size = *bulk_size;
151         void *tmp = *bulk;
152         __u32 alloc_size;
153         void *buf;
154         size_t range_expr_s = sizeof(struct lnet_range_expr);
155         size_t lnet_exprs_s = sizeof(struct lnet_expressions);
156
157         /* criteria not present, skip over the static part of the
158          * bulk, which is included for each NID descriptor
159          */
160         if (ioc_nid->iud_net.ud_net_type == 0) {
161                 remaining_size -= sizeof(*ioc_nid);
162                 if (remaining_size < 0)
163                         return -EINVAL;
164                 *bulk += sizeof(*ioc_nid);
165                 *bulk_size = remaining_size;
166                 return 0;
167         }
168
169         descr_type = ioc_nid->iud_src_hdr.ud_descr_type;
170         if (descr_type != *(__u32 *)type)
171                 return -EINVAL;
172
173         /* calculate the total size to verify we have enough buffer.
174          * Start of by finding how many ranges there are for the net
175          * expression.
176          */
177         range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
178         size = sizeof(*ioc_nid) + (range_count * range_expr_s);
179         remaining_size -= size;
180         if (remaining_size < 0)
181                 return -EINVAL;
182
183         /* the number of expressions for the NID. IE 4 for IP, 1 for GNI */
184         expr_count = ioc_nid->iud_src_hdr.ud_descr_count;
185         /* point tmp to the beginning of the NID expressions */
186         tmp += size;
187         for (i = 0; i < expr_count; i++) {
188                 /* get the number of ranges per expression */
189                 exprs = tmp;
190                 range_count += exprs->le_count;
191                 size = (range_expr_s * exprs->le_count) + lnet_exprs_s;
192                 remaining_size -= size;
193                 if (remaining_size < 0)
194                         return -EINVAL;
195                 tmp += size;
196         }
197
198         *bulk_size = remaining_size;
199
200         /* copy over the net type */
201         nid_descr->ud_net_id.udn_net_type = ioc_nid->iud_net.ud_net_type;
202
203         /* allocate the total memory required to copy this NID descriptor */
204         alloc_size = (sizeof(struct cfs_expr_list) * (expr_count + 1)) +
205                      (sizeof(struct cfs_range_expr) * (range_count));
206         buf = calloc(alloc_size, 1);
207         if (!buf)
208                 return -ENOMEM;
209
210         /* copy over the net number range */
211         range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
212         *bulk += sizeof(*ioc_nid);
213         copy_range_info(bulk, &buf, &nid_descr->ud_net_id.udn_net_num_range,
214                         range_count);
215
216         /* copy over the NID descriptor */
217         for (i = 0; i < expr_count; i++)
218                 copy_range_info(bulk, &buf, &nid_descr->ud_addr_range, -1);
219
220         return 0;
221 }
222
223 static struct lnet_udsp *
224 lnet_udsp_demarshal(void *bulk, __u32 bulk_size)
225 {
226         struct lnet_ioctl_udsp *ioc_udsp;
227         struct lnet_udsp *udsp;
228         int rc = -ENOMEM;
229
230         if (bulk_size < sizeof(*ioc_udsp))
231                 return NULL;
232
233         udsp = lnet_udsp_alloc();
234         if (!udsp)
235                 return NULL;
236
237         ioc_udsp = bulk;
238
239         udsp->udsp_action_type = ioc_udsp->iou_action_type;
240         udsp->udsp_action.udsp_priority = ioc_udsp->iou_action.priority;
241         udsp->udsp_idx = ioc_udsp->iou_idx;
242
243         bulk = ioc_udsp->iou_bulk;
244         bulk_size -= sizeof(*ioc_udsp);
245
246         if (bulk_size != ioc_udsp->iou_bulk_size)
247                 goto failed;
248
249         rc = copy_ioc_udsp_descr(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
250         if (rc < 0)
251                 goto failed;
252
253         rc = copy_ioc_udsp_descr(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
254         if (rc < 0)
255                 goto failed;
256
257         rc = copy_ioc_udsp_descr(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
258         if (rc < 0)
259                 goto failed;
260
261         return udsp;
262
263 failed:
264         lnet_udsp_free(udsp, true);
265         return NULL;
266 }
267
268 static inline int
269 lnet_get_list_len(struct list_head *list)
270 {
271         struct list_head *l;
272         int count = 0;
273
274         list_for_each(l, list)
275                 count++;
276
277         return count;
278 }
279
280 static size_t
281 lnet_size_marshaled_nid_descr(struct lnet_ud_nid_descr *descr)
282 {
283         struct cfs_expr_list *expr;
284         int expr_count = 0;
285         int range_count = 0;
286         size_t size = sizeof(struct lnet_ioctl_udsp_descr);
287
288         if (!lnet_udsp_criteria_present(descr))
289                 return size;
290
291         if (!list_empty(&descr->ud_net_id.udn_net_num_range)) {
292                 expr = list_first_entry(&descr->ud_net_id.udn_net_num_range,
293                                         struct cfs_expr_list, el_link);
294                 range_count = lnet_get_list_len(&expr->el_exprs);
295         }
296
297         /* count the number of cfs_range_expr in the address expressions */
298         list_for_each_entry(expr, &descr->ud_addr_range, el_link) {
299                 expr_count++;
300                 range_count += lnet_get_list_len(&expr->el_exprs);
301         }
302
303         size += (sizeof(struct lnet_expressions) * expr_count);
304         size += (sizeof(struct lnet_range_expr) * range_count);
305
306         return size;
307 }
308
309 static size_t
310 lnet_get_udsp_size(struct lnet_udsp *udsp)
311 {
312         size_t size = sizeof(struct lnet_ioctl_udsp);
313
314         size += lnet_size_marshaled_nid_descr(&udsp->udsp_src);
315         size += lnet_size_marshaled_nid_descr(&udsp->udsp_dst);
316         size += lnet_size_marshaled_nid_descr(&udsp->udsp_rte);
317
318         return size;
319 }
320
321 static void
322 copy_exprs(struct cfs_expr_list *expr, void __user **bulk,
323            __s32 *bulk_size)
324 {
325         struct cfs_range_expr *range;
326         struct lnet_range_expr range_expr;
327
328         /* copy over the net range expressions to the bulk */
329         list_for_each_entry(range, &expr->el_exprs, re_link) {
330                 range_expr.re_lo = range->re_lo;
331                 range_expr.re_hi = range->re_hi;
332                 range_expr.re_stride = range->re_stride;
333                 memcpy(*bulk, &range_expr, sizeof(range_expr));
334                 *bulk += sizeof(range_expr);
335                 *bulk_size -= sizeof(range_expr);
336         }
337 }
338
339 static int
340 copy_nid_range(struct lnet_ud_nid_descr *nid_descr, char *type,
341                 void __user **bulk, __s32 *bulk_size)
342 {
343         struct lnet_ioctl_udsp_descr ioc_udsp_descr = { { 0 } };
344         struct cfs_expr_list *expr;
345         struct lnet_expressions ioc_expr;
346         int expr_count;
347         int net_expr_count = 0;
348
349         ioc_udsp_descr.iud_src_hdr.ud_descr_type = *(__u32 *)type;
350
351         /* if criteria not present, copy over the static part of the NID
352          * descriptor
353          */
354         if (!lnet_udsp_criteria_present(nid_descr)) {
355                 memcpy(*bulk, &ioc_udsp_descr,
356                         sizeof(ioc_udsp_descr));
357                 *bulk += sizeof(ioc_udsp_descr);
358                 *bulk_size -= sizeof(ioc_udsp_descr);
359                 return 0;
360         }
361
362         expr_count = lnet_get_list_len(&nid_descr->ud_addr_range);
363
364         /* copy the net information */
365         if (!list_empty(&nid_descr->ud_net_id.udn_net_num_range)) {
366                 expr = list_first_entry(&nid_descr->ud_net_id.udn_net_num_range,
367                                         struct cfs_expr_list, el_link);
368                 net_expr_count = lnet_get_list_len(&expr->el_exprs);
369         } else {
370                 net_expr_count = 0;
371         }
372
373         /* set the total expression count */
374         ioc_udsp_descr.iud_src_hdr.ud_descr_count = expr_count;
375         ioc_udsp_descr.iud_net.ud_net_type =
376                 nid_descr->ud_net_id.udn_net_type;
377         ioc_udsp_descr.iud_net.ud_net_num_expr.le_count = net_expr_count;
378
379         /* copy over the header info to the bulk */
380         memcpy(*bulk, &ioc_udsp_descr, sizeof(ioc_udsp_descr));
381         *bulk += sizeof(ioc_udsp_descr);
382         *bulk_size -= sizeof(ioc_udsp_descr);
383
384         /* copy over the net num expression if it exists */
385         if (net_expr_count)
386                 copy_exprs(expr, bulk, bulk_size);
387
388         /* copy the address range */
389         list_for_each_entry(expr, &nid_descr->ud_addr_range, el_link) {
390                 ioc_expr.le_count = lnet_get_list_len(&expr->el_exprs);
391                 memcpy(*bulk, &ioc_expr, sizeof(ioc_expr));
392                 *bulk += sizeof(ioc_expr);
393                 *bulk_size -= sizeof(ioc_expr);
394
395                 copy_exprs(expr, bulk, bulk_size);
396         }
397
398         return 0;
399 }
400
401 static int
402 lnet_udsp_marshal(struct lnet_udsp *udsp, void *bulk,
403                   __s32 bulk_size)
404 {
405         struct lnet_ioctl_udsp *ioc_udsp;
406         int rc = -ENOMEM;
407
408         /* make sure user space allocated enough buffer to marshal the
409          * udsp
410          */
411         if (bulk_size < lnet_get_udsp_size(udsp))
412                 return -EINVAL;
413
414         ioc_udsp = bulk;
415
416         ioc_udsp->iou_idx = udsp->udsp_idx;
417         ioc_udsp->iou_action_type = udsp->udsp_action_type;
418         ioc_udsp->iou_action.priority = udsp->udsp_action.udsp_priority;
419
420         bulk += sizeof(*ioc_udsp);
421         bulk_size -= sizeof(*ioc_udsp);
422
423         rc = copy_nid_range(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
424         if (rc != 0)
425                 return rc;
426
427         rc = copy_nid_range(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
428         if (rc != 0)
429                 return rc;
430
431         rc = copy_nid_range(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
432
433         return rc;
434 }
435
436 static enum lnet_udsp_action_type
437 lnet_str2udsp_action(char *type)
438 {
439         if (!type)
440                 return EN_LNET_UDSP_ACTION_NONE;
441
442         if (!strncmp(type, "priority", strlen("priority")))
443                 return EN_LNET_UDSP_ACTION_PRIORITY;
444
445         if (!strncmp(type, "pref", strlen("pref")))
446                 return EN_LNET_UDSP_ACTION_PREFERRED_LIST;
447
448         return EN_LNET_UDSP_ACTION_NONE;
449 }
450
451 int lustre_lnet_add_udsp(char *src, char *dst, char *rte,
452                          char *type, union lnet_udsp_action *action,
453                          int idx, int seq_no, struct cYAML **err_rc)
454 {
455         struct lnet_udsp *udsp = NULL;
456         struct lnet_ioctl_udsp *udsp_bulk;
457         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
458         void *bulk = NULL;
459         __u32 bulk_size;
460         char err_str[LNET_MAX_STR_LEN];
461         enum lnet_udsp_action_type action_type;
462
463         snprintf(err_str, sizeof(err_str), "\"success\"");
464
465         action_type = lnet_str2udsp_action(type);
466         if (action_type == EN_LNET_UDSP_ACTION_NONE) {
467                 snprintf(err_str, sizeof(err_str),
468                          "\"bad action type specified: %s\"", type);
469                 rc = LUSTRE_CFG_RC_BAD_PARAM;
470                 goto out;
471         }
472
473         if (!(src || rte || dst)) {
474                 snprintf(err_str, sizeof(err_str),
475                          "\"Missing required argument(s)\"");
476                 rc = LUSTRE_CFG_RC_BAD_PARAM;
477                 goto out;
478         }
479
480         /* sanitize parameters:
481          * src-dst can be simultaneously present
482          * dst-rte can be simultaneously present
483          */
484         if (src && rte && dst) {
485                 snprintf(err_str, sizeof(err_str),
486                   "\"The combination of src, dst and rte is not supported\"");
487                 rc = LUSTRE_CFG_RC_BAD_PARAM;
488                 goto out;
489         }
490
491         if (src && rte) {
492                 snprintf(err_str, sizeof(err_str),
493                          "\"src and rte cannot be combined\"");
494                 rc = LUSTRE_CFG_RC_BAD_PARAM;
495                 goto out;
496         }
497
498         udsp = lnet_udsp_alloc();
499         if (!udsp) {
500                 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
501                 goto out;
502         }
503
504         udsp->udsp_idx = idx;
505         udsp->udsp_action_type = action_type;
506
507         /* a priority of -1 will result in the lowest possible priority */
508         if (action_type == EN_LNET_UDSP_ACTION_PRIORITY)
509                 udsp->udsp_action.udsp_priority = action->udsp_priority;
510
511          /* override with the default
512           * if priority is expected, but not specified
513           */
514         if (!rte && ((dst && !src) || (src && !dst)) &&
515              action_type != EN_LNET_UDSP_ACTION_PRIORITY) {
516                 udsp->udsp_action_type = EN_LNET_UDSP_ACTION_PRIORITY;
517                 udsp->udsp_action.udsp_priority = 0;
518         }
519
520         if (src) {
521                 rc = cfs_parse_nid_parts(src, &udsp->udsp_src.ud_addr_range,
522                                 &udsp->udsp_src.ud_net_id.udn_net_num_range,
523                                 &udsp->udsp_src.ud_net_id.udn_net_type);
524                 if (rc < 0) {
525                         snprintf(err_str,
526                                  sizeof(err_str),
527                                  "\"failed to parse src parameter\"");
528                         goto out;
529                 }
530         }
531         if (dst) {
532                 rc = cfs_parse_nid_parts(dst, &udsp->udsp_dst.ud_addr_range,
533                                 &udsp->udsp_dst.ud_net_id.udn_net_num_range,
534                                 &udsp->udsp_dst.ud_net_id.udn_net_type);
535                 if (rc < 0) {
536                         snprintf(err_str,
537                                  sizeof(err_str),
538                                  "\"failed to parse dst parameter\"");
539                         goto out;
540                 }
541         }
542         if (rte) {
543                 rc = cfs_parse_nid_parts(rte, &udsp->udsp_rte.ud_addr_range,
544                                 &udsp->udsp_rte.ud_net_id.udn_net_num_range,
545                                 &udsp->udsp_rte.ud_net_id.udn_net_type);
546                 if (rc < 0) {
547                         snprintf(err_str,
548                                  sizeof(err_str),
549                                  "\"failed to parse rte parameter\"");
550                         goto out;
551                 }
552         }
553
554         bulk_size = lnet_get_udsp_size(udsp);
555         bulk = calloc(1, bulk_size);
556         if (!bulk) {
557                 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
558                 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
559                 goto out;
560         }
561
562         udsp_bulk = bulk;
563         LIBCFS_IOC_INIT_V2(*udsp_bulk, iou_hdr);
564         udsp_bulk->iou_hdr.ioc_len = bulk_size;
565         udsp_bulk->iou_bulk_size = bulk_size - sizeof(*udsp_bulk);
566
567         rc = lnet_udsp_marshal(udsp, bulk, bulk_size);
568         if (rc != LUSTRE_CFG_RC_NO_ERR) {
569                 rc = LUSTRE_CFG_RC_MARSHAL_FAIL;
570                 snprintf(err_str,
571                          sizeof(err_str),
572                          "\"failed to marshal udsp\"");
573                 goto out;
574         }
575
576         udsp_bulk->iou_bulk = bulk + sizeof(*udsp_bulk);
577
578         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_UDSP, bulk);
579         if (rc < 0) {
580                 rc = errno;
581                 snprintf(err_str, sizeof(err_str),
582                          "\"cannot add udsp: %s\"", strerror(errno));
583                 goto out;
584         }
585
586         rc = LUSTRE_CFG_RC_NO_ERR;
587
588 out:
589         if (bulk)
590                 free(bulk);
591         if (udsp)
592                 lnet_udsp_free(udsp, false);
593         cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
594         return rc;
595 }
596
597 int lustre_lnet_del_udsp(unsigned int idx, int seq_no, struct cYAML **err_rc)
598 {
599         int rc;
600         char err_str[LNET_MAX_STR_LEN];
601         struct lnet_ioctl_udsp udsp_bulk;
602
603         snprintf(err_str, sizeof(err_str), "\"success\"");
604
605         LIBCFS_IOC_INIT_V2(udsp_bulk, iou_hdr);
606         udsp_bulk.iou_idx = idx;
607
608         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_UDSP, &udsp_bulk);
609         if (rc < 0)
610                 snprintf(err_str, sizeof(err_str),
611                          "\"cannot del udsp: %s\"", strerror(errno));
612
613         cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
614         return rc;
615 }
616
617 static int lustre_lnet_nid_descr2str(struct lnet_ud_nid_descr *d,
618                                      char *str, size_t size)
619 {
620         int left = size;
621         int len;
622         char *net;
623         bool addr_found = false;
624
625         /* criteria not defined */
626         if (d->ud_net_id.udn_net_type == 0) {
627                 strncat(str, "NA", left - 1);
628                 return 0;
629         }
630
631         left = cfs_expr2str(&d->ud_addr_range, str, left);
632         if (left < 0)
633                 return left;
634         net = libcfs_net2str(LNET_MKNET(d->ud_net_id.udn_net_type, 0));
635         if (left < size) {
636                 len = strlen(net) + 2; /* account for @ and NULL termination */
637                 addr_found = true;
638         } else {
639                 len = strlen(net) + 1; /* account for NULL termination */
640         }
641
642         if (left - len < 0)
643                 return -ENOBUFS;
644
645         if (addr_found) {
646                 strncat(str, "@", left);
647                 left -= 1;
648         }
649
650         strncat(str, net, left);
651
652         left -= strlen(net) + 1;
653
654         left = cfs_expr2str(&d->ud_net_id.udn_net_num_range, str, left);
655         if (left < 0)
656                 return left;
657
658         return 0;
659 }
660
661 static int yaml_add_udsp_action(struct cYAML *y, struct lnet_udsp *udsp)
662 {
663         struct cYAML *action;
664
665         switch (udsp->udsp_action_type) {
666                 case EN_LNET_UDSP_ACTION_PRIORITY:
667                         action = cYAML_create_object(y, "action");
668                         if (!action)
669                                 return -ENOMEM;
670                         if (!cYAML_create_number(action, "priority",
671                                 udsp->udsp_action.udsp_priority))
672                                 return -ENOMEM;
673
674                 default:
675                         return 0;
676         }
677
678         return 0;
679 }
680
681 int lustre_lnet_show_udsp(int idx, int seq_no, struct cYAML **show_rc,
682                           struct cYAML **err_rc)
683 {
684         struct lnet_ioctl_udsp *data = NULL;
685         char *ioctl_buf = NULL;
686         struct lnet_ioctl_udsp get_size;
687         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i;
688         int l_errno = 0;
689         int use_idx = 0;
690         struct cYAML *root = NULL, *udsp_node = NULL,
691                      *first_seq = NULL;
692         struct cYAML *item = NULL;
693         char err_str[LNET_MAX_STR_LEN];
694         char tmp[LNET_MAX_STR_LEN];
695         struct lnet_udsp *udsp = NULL;
696         bool exist = false;
697
698         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
699
700         root = cYAML_create_object(NULL, NULL);
701         if (!root)
702                 goto out;
703
704         udsp_node = cYAML_create_seq(root, "udsp");
705         if (!udsp_node)
706                 goto out;
707
708         for (i = 0;; i++) {
709                 data = NULL;
710                 ioctl_buf = NULL;
711                 udsp = NULL;
712
713                 LIBCFS_IOC_INIT_V2(get_size, iou_hdr);
714                 if (idx != -1)
715                         use_idx = idx;
716                 else
717                         use_idx = i;
718
719                 get_size.iou_idx = use_idx;
720
721                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_UDSP_SIZE, &get_size);
722                 if (rc != 0) {
723                         l_errno = errno;
724                         break;
725                 }
726
727                 ioctl_buf = calloc(get_size.iou_idx, 1);
728                 if (!ioctl_buf) {
729                         l_errno = errno;
730                         break;
731                 }
732
733                 data = (struct lnet_ioctl_udsp *)ioctl_buf;
734
735                 LIBCFS_IOC_INIT_V2(*data, iou_hdr);
736                 data->iou_bulk_size = get_size.iou_idx - sizeof(*data);
737                 data->iou_bulk = ioctl_buf + sizeof(*data);
738                 data->iou_idx = use_idx;
739
740                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_UDSP, ioctl_buf);
741                 if (rc != 0) {
742                         l_errno = errno;
743                         break;
744                 }
745
746                 udsp = lnet_udsp_demarshal(ioctl_buf,
747                         data->iou_hdr.ioc_len + data->iou_bulk_size);
748                 if (!udsp) {
749                         l_errno = -EFAULT;
750                         break;
751                 }
752
753                 rc = -EINVAL;
754                 exist = true;
755
756                 /* create the tree to be printed. */
757                 item = cYAML_create_seq_item(udsp_node);
758                 if (item == NULL)
759                         goto out;
760
761                 if (!first_seq)
762                         first_seq = item;
763
764                 if (cYAML_create_number(item, "idx",
765                                         udsp->udsp_idx) == NULL)
766                         goto out;
767
768                 memset(tmp, 0, LNET_MAX_STR_LEN);
769                 rc = lustre_lnet_nid_descr2str(&udsp->udsp_src, tmp,
770                                                LNET_MAX_STR_LEN);
771
772                 if (rc)
773                         goto out;
774
775                 if (cYAML_create_string(item, "src", tmp) == NULL)
776                         goto out;
777                 memset(tmp, 0, LNET_MAX_STR_LEN);
778                 rc = lustre_lnet_nid_descr2str(&udsp->udsp_dst, tmp,
779                                                LNET_MAX_STR_LEN);
780
781                 if (rc)
782                         goto out;
783
784                 if (cYAML_create_string(item, "dst", tmp) == NULL)
785                         goto out;
786
787                 memset(tmp, 0, LNET_MAX_STR_LEN);
788                 rc = lustre_lnet_nid_descr2str(&udsp->udsp_rte, tmp,
789                                                LNET_MAX_STR_LEN);
790
791                 if (rc)
792                         goto out;
793
794                 if (cYAML_create_string(item, "rte", tmp) == NULL)
795                         goto out;
796
797                 if (yaml_add_udsp_action(item, udsp))
798                         goto out;
799
800                 if (ioctl_buf)
801                         free(ioctl_buf);
802                 if (udsp)
803                         lnet_udsp_free(udsp, true);
804                 /* did we show the given index? */
805                 if (idx != -1)
806                         break;
807         }
808
809         /* Print out the net information only if show_rc is not provided */
810         if (show_rc == NULL)
811                 cYAML_print_tree(root);
812
813         if (l_errno != ENOENT) {
814                 snprintf(err_str,
815                          sizeof(err_str),
816                          "\"cannot get udsp: %s\"",
817                          strerror(l_errno));
818                 rc = -l_errno;
819                 goto out;
820         } else {
821                 rc = LUSTRE_CFG_RC_NO_ERR;
822         }
823
824         snprintf(err_str, sizeof(err_str), "\"success\"");
825 out:
826         if (ioctl_buf)
827                 free(ioctl_buf);
828         if (udsp)
829                 lnet_udsp_free(udsp, true);
830
831         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
832                 cYAML_free_tree(root);
833         } else if (show_rc != NULL && *show_rc != NULL) {
834                 struct cYAML *show_node;
835                 /* find the net node, if one doesn't exist
836                  * then insert one.  Otherwise add to the one there
837                  */
838                 show_node = cYAML_get_object_item(*show_rc, "udsp");
839                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
840                         cYAML_insert_child(show_node, first_seq);
841                         free(udsp_node);
842                         free(root);
843                 } else if (show_node == NULL) {
844                         cYAML_insert_sibling((*show_rc)->cy_child,
845                                                 udsp_node);
846                         free(root);
847                 } else {
848                         cYAML_free_tree(root);
849                 }
850         } else {
851                 *show_rc = root;
852         }
853
854         cYAML_build_error(rc, seq_no, SHOW_CMD, "udsp", err_str, err_rc);
855
856         return rc;
857 }
858