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