Whamcloud - gitweb
LU-9680 utils: fix Netlink / YAML library handling
[fs/lustre-release.git] / lnet / utils / lnetconfig / liblnetconfig_netlink.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the GNU Lesser General Public License
8  * LGPL version 2.1 or (at your discretion) any later version.
9  * LGPL version 2.1 accompanies this distribution, and is available at
10  * http://www.gnu.org/licenses/lgpl-2.1.html
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * LGPL HEADER END
18  */
19 /**
20  * Netlink handling.
21  *
22  * Copyright (c) 2021  UT-Battelle, LLC
23  *
24  * Author: James Simmons <jsimmons@infradead.org>
25  */
26
27 #include <ctype.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <yaml.h>
31
32 #include <linux/lnet/lnet-nl.h>
33 #include "liblnetconfig.h"
34
35 #ifndef fallthrough
36 #define fallthrough do {} while (0)  /* fallthrough */
37 #endif
38
39 #ifndef SOL_NETLINK /* for glibc < 2.24 */
40 # define SOL_NETLINK 270
41 #endif
42
43 #ifndef NETLINK_EXT_ACK
44 #define NETLINK_EXT_ACK 11
45 #endif
46
47 #ifndef NLM_F_ACK_TLVS
48 #define NLM_F_ACK_TLVS  0x200   /* extended ACK TVLs were included */
49 #endif
50
51 #ifndef NLA_NUL_STRING
52 # define NLA_NUL_STRING 10
53 #endif
54
55 #ifndef NLA_S16
56 # define NLA_S16 13
57 #endif
58
59 #ifndef HAVE_NLA_GET_S32
60
61 #define NLA_S32 14
62
63 /**
64  * Return payload of 32 bit signed integer attribute.
65  *
66  * @arg nla             32 bit integer attribute.
67  *
68  * @return Payload as 32 bit integer.
69  */
70 int32_t nla_get_s32(const struct nlattr *nla)
71 {
72         return *(const int32_t *) nla_data(nla);
73 }
74 #endif /* ! HAVE_NLA_GET_S32 */
75
76 #ifndef HAVE_NLA_GET_S64
77
78 #define NLA_S64 15
79
80 /**
81  * Return payload of s64 attribute
82  *
83  * @arg nla     s64 netlink attribute
84  *
85  * @return Payload as 64 bit integer.
86  */
87 int64_t nla_get_s64(const struct nlattr *nla)
88 {
89         int64_t tmp = 0;
90
91         if (nla && nla_len(nla) >= sizeof(tmp))
92                 memcpy(&tmp, nla_data(nla), sizeof(tmp));
93
94         return tmp;
95 }
96
97 #define NLA_PUT_S64(msg, attrtype, value) \
98         NLA_PUT_TYPE(msg, int64_t, attrtype, value)
99
100 #endif /* ! HAVE_NLA_GET_S64 */
101
102 /**
103  * Set NETLINK_BROADCAST_ERROR flags on socket to report ENOBUFS errors.
104  *
105  * @sk          Socket to change the flags.
106  *
107  * Return       0 on success or a Netlink error code.
108  */
109 int nl_socket_enable_broadcast_error(struct nl_sock *sk)
110 {
111         const int state = 1; /* enable errors */
112         int err;
113
114         if (nl_socket_get_fd(sk) < 0)
115                 return -NLE_BAD_SOCK;
116
117         err = setsockopt(nl_socket_get_fd(sk), SOL_NETLINK,
118                          NETLINK_BROADCAST_ERROR, &state, sizeof(state));
119         if (err < 0)
120                 return -nl_syserr2nlerr(errno);
121
122         return 0;
123 }
124
125 /**
126  * Enable/disable extending ACK for netlink socket. Used for
127  * sending extra debugging information.
128  *
129  * @arg sk              Netlink socket.
130  * @arg state           New state (0 - disabled, 1 - enabled)
131  *
132  * @return 0 on success or a negative error code
133  */
134 int nl_socket_set_ext_ack(struct nl_sock *sk, int state)
135 {
136         int err;
137
138         if (nl_socket_get_fd(sk) < 0)
139                 return -NLE_BAD_SOCK;
140
141         err = setsockopt(nl_socket_get_fd(sk), SOL_NETLINK,
142                          NETLINK_EXT_ACK, &state, sizeof(state));
143         if (err < 0 && errno != ENOPROTOOPT)
144                 return -nl_syserr2nlerr(errno);
145
146         return 0;
147 }
148
149 /**
150  * Create a Netlink socket
151  *
152  * @sk                  The nl_sock which we used to handle the Netlink
153  *                      connection.
154  * @async_events        tell the Netlink socket this will receive asynchronous
155  *                      data
156  *
157  * Return               0 on success or a negative error code.
158  */
159 int lustre_netlink_register(struct nl_sock *sk, bool async_events)
160 {
161         int rc;
162
163         rc = genl_connect(sk);
164         if (rc < 0)
165                 return rc;
166
167         rc = nl_socket_enable_broadcast_error(sk);
168         if (rc < 0)
169                 return rc;
170
171         rc = nl_socket_set_ext_ack(sk, true);
172         if (rc < 0)
173                 return rc;
174
175         if (async_events) {
176                 /* Required to receive async netlink event notifications */
177                 nl_socket_disable_seq_check(sk);
178                 /* Don't need ACK for events generated by kernel */
179                 nl_socket_disable_auto_ack(sk);
180         }
181
182         return rc;
183 }
184
185 /**
186  * Filter Netlink socket by groups
187  *
188  * @nl          Netlink socket
189  * @family      The family name of the Netlink socket.
190  * @group       Netlink messages will only been sent if they belong to this
191  *              group
192  *
193  * Return       0 on success or a negative error code.
194  */
195 int lustre_netlink_add_group(struct nl_sock *nl, const char *family,
196                              const char *group)
197 {
198         int group_id;
199
200         /* Get group ID */
201         group_id = genl_ctrl_resolve_grp(nl, family, group);
202         if (group_id < 0)
203                 return group_id;
204
205         /* subscribe to generic netlink multicast group */
206         return nl_socket_add_membership(nl, group_id);
207 }
208
209 /* A YAML file is used to describe data. In a YAML document the content is
210  * all about a collection of scalars used to create new data types such as
211  * key-value pairs. This allows complex documents to represent anything from
212  * a string to a tree.
213  *
214  * Scalar:
215  * ---------
216  * YAML scalars are a simple value which can be a string, number or Boolean.
217  * They are the simplest data types. They can exist in a YAML document but
218  * are typically used to build more complex data formats.
219  *
220  * Collections:
221  * ------------
222  * In YAML collections are scalar elements presented in the form of
223  * an array, called a sequence, or mappings (hashes) that are scalar
224  * key value pairs. All elements belonging to the same collection are
225  * the lines that begin at the same indentation level
226  *
227  * Sequences use a dash followed by a space.
228  * Mappings use a colon followed by a space (: ) to mark each key/value pair:
229  *
230  * Collections can be represented in two forms, flow and block.
231  * Note they are equivalent. Example of block sequence is;
232  *
233  * - string
234  * - integer
235  * - boolean
236  *
237  * and a block mapping example is:
238  *
239  * string: hello
240  * integer: 5
241  * boolean: False
242  *
243  * YAML flow styles for collections uses explicit indicators rather than
244  * indentation to denote scope.
245  *
246  * A sequence can be written as a comma separated list within
247  * square brackets ([]):
248  *
249  * [ PHP, Perl, Python ]
250  *
251  * A mapping can be written as a comma separated list of key/values within
252  * curly braces ({}):
253  *
254  * { PHP: 5.2, MySQL: 5.1, Apache: 2.2.20 }
255  *
256  * NOTE!! flow and block are equivalent.
257  *
258  * List:
259  * ------
260  * A list is a defined array of data which can be either an flow or block
261  * sequence. Lists can be nested. Example
262  *
263  * numbers: [ 1, 2, 3, 4 ]
264  *
265  * numbers:
266  *  - 1
267  *  - 2
268  *  - 3
269  *  - 4
270  *
271  * Dictionaries:
272  * --------------
273  * Are comprised of a key: value format with contents indented. This is
274  * built on top of the flow or block mapping. Like lists they can be nested.
275  *
276  * ports:
277  * - port: 8080
278  *     targetPort: 8080
279  *       nodePort: 30012
280  */
281
282 /* In YAML you have the concept of parsers and emitters. Parser
283  * consume YAML input from a file, character buffer, or in our
284  * case Netlink and emitters take data from some source and
285  * present it in a YAML format.
286  *
287  * In this section of the code we are handling the parsing of the
288  * Netlink packets coming in and using them to piece together a
289  * YAML document. We could in theory just dump a YAML document
290  * one line at a time over Netlink but the amount of data could
291  * become very large and impact performance. Additionally, having
292  * pseudo-YAML code in the kernel would be frowned on. We can
293  * optimize the network traffic by taking advantage of the fact
294  * that for key/value pairs the keys rarely change. We can
295  * break up the data into keys and the values. The first Netlink
296  * data packets received will be a nested keys table which we
297  * can cache locally. As we receive the value pairs we can then
298  * reconstruct the key : value pair by looking up the the key
299  * in the stored table. In effect we end up with a one key to
300  * many values stream of data.
301  *
302  * The data structures below are used to create a tree data
303  * structure which is the natural flow of both YAML and
304  * Netlink.
305  */
306 struct yaml_nl_node {
307         struct nl_list_head     list;
308         struct nl_list_head     children;
309         struct ln_key_list      keys;
310 };
311
312 struct yaml_netlink_input {
313         yaml_parser_t           *parser;
314         void                    *buffer;
315         const char              *errmsg;
316         struct nl_sock          *nl;
317         bool                    complete;
318         bool                    async;
319         unsigned int            indent;
320         unsigned int            version;
321         struct yaml_nl_node     *cur;
322         struct yaml_nl_node     *root;
323 };
324
325 /* Sadly this is not exported out of libyaml. We want to
326  * give descent error message to help people track down
327  * issues. This is internal only to this code. The end
328  * user will never need to use this.
329  */
330 static int
331 yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
332                              size_t offset, int value)
333 {
334         parser->error = YAML_READER_ERROR;
335         parser->problem = problem;
336         parser->problem_offset = offset;
337         parser->problem_value = value;
338
339         return 0;
340 }
341
342 /* This is used to handle all the Netlink packets containing the keys
343  * for the key/value pairs. Instead of creating unique code to handle
344  * every type of Netlink attributes possible we create a generic
345  * abstract so the same code be used with everything. To make this
346  * work the key table trasmitted must report the tree structure and
347  * state of the keys. We use nested attributes as a way to notify libyaml
348  * we have a new collection. This is used to create the tree structure
349  * of the YAML document. Each collection of attributes define the following:
350  *
351  * LN_SCALAR_ATTR_INDEX:
352  *      enum XXX_ATTR that defines which value we are dealing with. This
353  *      varies greatly depending on the subsystem we have developed for.
354  *
355  * LN_SCALAR_ATTR_NLA_TYPE:
356  *      The Netlink attribute type (NLA_STRING, NLA_U32, etc..) the coming
357  *      value will be.
358  *
359  * LN_SCALAR_ATTR_VALUE:
360  *      The string represnting key's actually scalar value.
361  *
362  * LN_SCALAR_ATTR_INT_VALUE:
363  *      For this case the key is an integer value. This shouldn't be
364  *      sent for the receive case since we are going to just turn it
365  *      into a string for YAML. Sending packets will make use of this.
366  *
367  * LN_SCALAR_ATTR_KEY_TYPE:
368  *      What YAML format is it? block or flow. Only useful for
369  *      LN_SCALAR_ATTR_NLA_TYPE of type NLA_NESTED or NLA_NUL_STRING
370  *
371  * LN_SCALAR_ATTR_LIST + LN_SCALAR_LIST_SIZE:
372  *      Defined the next collection which is a collection of nested
373  *      attributes of the above.
374  */
375 static struct nla_policy scalar_attr_policy[LN_SCALAR_MAX + 1] = {
376         [LN_SCALAR_ATTR_LIST]           = { .type = NLA_NESTED },
377         [LN_SCALAR_ATTR_LIST_SIZE]      = { .type = NLA_U16 },
378         [LN_SCALAR_ATTR_INDEX]          = { .type = NLA_U16 },
379         [LN_SCALAR_ATTR_NLA_TYPE]       = { .type = NLA_U16 },
380         [LN_SCALAR_ATTR_VALUE]          = { .type = NLA_STRING },
381         [LN_SCALAR_ATTR_INT_VALUE]      = { .type = NLA_S64 },
382         [LN_SCALAR_ATTR_KEY_FORMAT]     = { .type = NLA_U16 },
383 };
384
385 static int yaml_parse_key_list(struct yaml_netlink_input *data,
386                                struct yaml_nl_node *parent,
387                                struct nlattr *list)
388 {
389         struct nlattr *tbl_info[LN_SCALAR_MAX + 1];
390         struct yaml_nl_node *node = NULL;
391         struct nlattr *attr;
392         int rem;
393
394         nla_for_each_nested(attr, list, rem) {
395                 uint16_t index = 0;
396
397                 if (nla_parse_nested(tbl_info, LN_SCALAR_MAX, attr,
398                                      scalar_attr_policy))
399                         break;
400
401                 if (tbl_info[LN_SCALAR_ATTR_LIST_SIZE]) {
402                         size_t cnt;
403
404                         cnt = nla_get_u16(tbl_info[LN_SCALAR_ATTR_LIST_SIZE]) + 1;
405                         if (!node) {
406                                 size_t len = sizeof(struct nl_list_head) * 2;
407
408                                 len += sizeof(struct ln_key_props) * cnt;
409                                 node = calloc(1, len);
410                                 if (!node)
411                                         return NL_STOP;
412
413                                 node->keys.lkl_maxattr = cnt;
414                                 NL_INIT_LIST_HEAD(&node->children);
415                                 nl_init_list_head(&node->list);
416
417                                 if (!data->root)
418                                         data->root = node;
419                                 if (!data->cur)
420                                         data->cur = node;
421                                 if (parent)
422                                         nl_list_add_tail(&node->list,
423                                                          &parent->children);
424                         }
425                 }
426
427                 if (tbl_info[LN_SCALAR_ATTR_INDEX])
428                         index = nla_get_u16(tbl_info[LN_SCALAR_ATTR_INDEX]);
429
430                 if (!node || index == 0)
431                         return NL_STOP;
432
433                 if (tbl_info[LN_SCALAR_ATTR_KEY_FORMAT]) {
434                         uint16_t format;
435
436                         format = nla_get_u16(tbl_info[LN_SCALAR_ATTR_KEY_FORMAT]);
437                         node->keys.lkl_list[index].lkp_key_format = format;
438                 }
439
440                 if (tbl_info[LN_SCALAR_ATTR_NLA_TYPE]) {
441                         uint16_t type;
442
443                         type = nla_get_u16(tbl_info[LN_SCALAR_ATTR_NLA_TYPE]);
444                         node->keys.lkl_list[index].lkp_data_type = type;
445                 }
446
447                 if (tbl_info[LN_SCALAR_ATTR_VALUE]) {
448                         char *name;
449
450                         name = nla_strdup(tbl_info[LN_SCALAR_ATTR_VALUE]);
451                         if (!name)
452                                 return NL_STOP;
453                         node->keys.lkl_list[index].lkp_value = name;
454                 }
455
456                 if (tbl_info[LN_SCALAR_ATTR_LIST]) {
457                         int rc = yaml_parse_key_list(data, node,
458                                                      tbl_info[LN_SCALAR_ATTR_LIST]);
459                         if (rc != NL_OK)
460                                 return rc;
461                 }
462         }
463         return NL_OK;
464 }
465
466 static struct yaml_nl_node *get_next_child(struct yaml_nl_node *node,
467                                            unsigned int idx)
468 {
469         struct yaml_nl_node *child;
470         unsigned int i = 0;
471
472         nl_list_for_each_entry(child, &node->children, list)
473                 if (idx == i++)
474                         return child;
475
476         return NULL;
477 }
478
479 /**
480  * In the YAML C implementation the scanner transforms the input stream
481  * (Netlink in this case) into a sequence of keys. First we need to
482  * examine the potential keys involved to see the mapping to Netlink.
483  * We have chosen to examine the YAML stack with keys since they are
484  * more detailed when compared to yaml_document_t / yaml_nodes and
485  * yaml_event_t.
486  *
487  *      STREAM-START(encoding)          # The stream start.
488  *      STREAM-END                      # The stream end.
489  *      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
490  *      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
491  *      DOCUMENT-START                  # '---'
492  *      DOCUMENT-END                    # '...'
493  *      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
494  *      BLOCK-MAPPING-START             # sequence or a block mapping.
495  *      BLOCK-END                       # Indentation decrease.
496  *      FLOW-SEQUENCE-START             # '['
497  *      FLOW-SEQUENCE-END               # ']'
498  *      FLOW-MAPPING-START              # '{'
499  *      FLOW-MAPPING-END                # '}'
500  *      BLOCK-ENTRY                     # '-'
501  *      FLOW-ENTRY                      # ','
502  *      KEY                             # '?' or nothing (simple keys).
503  *      VALUE                           # ':'
504  *      ALIAS(anchor)                   # '*anchor'
505  *      ANCHOR(anchor)                  # '&anchor'
506  *      TAG(handle,suffix)              # '!handle!suffix'
507  *      SCALAR(value,style)             # A scalar.
508  *
509  * For our read_handler / write_handler STREAM-START / STREAM-END,
510  * VERSION-DIRECTIVE, and TAG-DIRECTIVE are hanndler by the libyaml
511  * internal scanner so we don't need to deal with it. Normally for
512  * LNet / Lustre DOCUMENT-START / DOCUMENT-END are not needed but it
513  * could be easily handled. In the case of multiplex streams we could
514  * see these used to differentiate data coming in.
515  *
516  * It is here we handle any simple scalars or values of the key /value
517  * pair. How the YAML document is formated is dependent on the key
518  * table's data.
519  */
520 static void yaml_parse_value_list(struct yaml_netlink_input *data, int *size,
521                                   struct nlattr *attr_array[],
522                                   struct ln_key_props *parent)
523 {
524         struct yaml_nl_node *node = data->cur;
525         struct ln_key_props *keys = node->keys.lkl_list;
526         int mapping = parent->lkp_key_format;
527         int child_idx = 0, len = 0, i;
528
529         for (i = 1; i < node->keys.lkl_maxattr; i++) {
530                 struct nlattr *attr;
531
532                 attr = attr_array[i];
533                 if (!attr && !keys[i].lkp_value)
534                         continue;
535
536                 if (keys[i].lkp_data_type != NLA_NUL_STRING &&
537                     keys[i].lkp_data_type != NLA_NESTED) {
538                         if (!attr)
539                                 continue;
540
541                         if (!(mapping & LNKF_FLOW)) {
542                                 unsigned int indent = data->indent ?
543                                                       data->indent : 2;
544
545                                 memset(data->buffer, ' ', indent);
546                                 if (mapping & LNKF_SEQUENCE) {
547                                         ((char *)data->buffer)[indent - 2] = '-';
548                                         if (mapping & LNKF_MAPPING)
549                                                 mapping &= ~LNKF_SEQUENCE;
550                                 }
551                                 data->buffer += indent;
552                                 *size -= indent;
553                         }
554
555                         if (mapping & LNKF_MAPPING) {
556                                 len = snprintf(data->buffer, *size, "%s: ",
557                                                keys[i].lkp_value);
558                                 if (len < 0)
559                                         goto unwind;
560                                 data->buffer += len;
561                                 *size -= len;
562                         }
563                 }
564
565                 switch (keys[i].lkp_data_type) {
566                 case NLA_NESTED: {
567                         struct yaml_nl_node *next = get_next_child(node,
568                                                                    child_idx++);
569                         int num = next->keys.lkl_maxattr;
570                         struct nla_policy nest_policy[num];
571                         struct yaml_nl_node *old;
572                         struct nlattr *cnt_attr;
573                         int rem, j;
574
575                         if (!attr)
576                                 continue;
577
578                         memset(nest_policy, 0, sizeof(struct nla_policy) * num);
579                         for (j = 1; j < num; j++)
580                                 nest_policy[j].type = next->keys.lkl_list[j].lkp_data_type;
581
582                         old = data->cur;
583                         data->cur = next;
584                         nla_for_each_nested(cnt_attr, attr, rem) {
585                                 struct nlattr *nest_info[num];
586                                 uint16_t indent = 0;
587
588                                 if (nla_parse_nested(nest_info, num, cnt_attr,
589                                                      nest_policy))
590                                         break;
591
592                                 if (keys[i].lkp_key_format & LNKF_FLOW) {
593                                         char brace = '{';
594
595                                         if (keys[i].lkp_key_format &
596                                             LNKF_SEQUENCE)
597                                                 brace = '[';
598
599                                         len = snprintf(data->buffer, *size,
600                                                        "%*s%s: %c ",
601                                                        data->indent, "",
602                                                        keys[i].lkp_value,
603                                                        brace);
604                                 } else {
605                                         if (keys[i].lkp_key_format &
606                                             LNKF_MAPPING)
607                                                 indent += 2;
608                                         if (keys[i].lkp_key_format &
609                                             LNKF_SEQUENCE)
610                                                 indent += 2;
611
612                                         if (keys[i].lkp_value) {
613                                                 len = snprintf(data->buffer,
614                                                                *size,
615                                                                "%*s%s:\n",
616                                                                data->indent, "",
617                                                                keys[i].lkp_value);
618                                         } else {
619                                                 len = 0;
620                                         }
621                                 }
622                                 if (len < 0)
623                                         goto unwind;
624                                 data->buffer += len;
625                                 *size -= len;
626                                 len = 0;
627
628                                 data->indent += indent;
629                                 yaml_parse_value_list(data, size, nest_info,
630                                                       &keys[i]);
631                                 data->indent -= indent;
632
633                                 if (keys[i].lkp_key_format & LNKF_FLOW) {
634                                         char *tmp = (char *)data->buffer - 2;
635                                         char *brace = " }\n";
636
637                                         if (keys[i].lkp_key_format &
638                                             LNKF_SEQUENCE)
639                                                 brace = " ]\n";
640
641                                         memcpy(tmp, brace, strlen(brace));
642                                         data->buffer++;
643                                         *size -= 1;
644                                 }
645                         }
646                         data->cur = old;
647                         break;
648                 }
649
650                 case NLA_NUL_STRING:
651                         if (i == 1) {
652                                 if (data->cur != data->root)
653                                         goto not_first;
654
655                                 /* The top level is special so only print
656                                  * once
657                                  */
658                                 if (strlen(keys[i].lkp_value)) {
659                                         len = snprintf(data->buffer,
660                                                        *size, "%s:\n",
661                                                        keys[i].lkp_value);
662                                         if (len < 0)
663                                                 goto unwind;
664                                         data->buffer += len;
665                                         *size -= len;
666                                         len = 0;
667                                 }
668                                 data->indent = 0;
669                                 if (!(mapping & LNKF_FLOW)) {
670                                         if (mapping & LNKF_SEQUENCE)
671                                                 data->indent += 2;
672                                         else if (mapping & LNKF_MAPPING)
673                                                 data->indent += 2;
674                                 }
675 not_first:
676                                 if (attr && parent->lkp_value) {
677                                         free(parent->lkp_value);
678                                         parent->lkp_value = nla_strdup(attr);
679                                 }
680                         }
681                         break;
682
683                 case NLA_STRING:
684                         len = snprintf(data->buffer, *size, "%s",
685                                        nla_get_string(attr));
686                         break;
687
688                 case NLA_U16:
689                         len = snprintf(data->buffer, *size, "%hu",
690                                        nla_get_u16(attr));
691                         break;
692
693                 case NLA_U32:
694                         len = snprintf(data->buffer, *size, "%u",
695                                        nla_get_u32(attr));
696                         break;
697
698                 case NLA_U64:
699                         len = snprintf(data->buffer, *size, "%ju",
700                                        nla_get_u64(attr));
701                         break;
702
703                 case NLA_S16:
704                         len = snprintf(data->buffer, *size, "%hd",
705                                        nla_get_u16(attr));
706                         break;
707
708                 case NLA_S32:
709                         len = snprintf(data->buffer, *size, "%d",
710                                        nla_get_s32(attr));
711                         break;
712
713                 case NLA_S64:
714                         len = snprintf(data->buffer, *size, "%jd",
715                                        nla_get_s64(attr));
716                         fallthrough;
717                 default:
718                         break;
719                 }
720
721                 if (len) {
722                         if (mapping & LNKF_FLOW) {
723                                 strcat((char *)data->buffer, ", ");
724                                 len += 2;
725                         } else {
726                                 if ((mapping == LNKF_SEQUENCE) &&
727                                     !keys[i].lkp_value)
728                                         ((char *)data->buffer)[len++] = ':';
729
730                                 ((char *)data->buffer)[len++] = '\n';
731                         }
732                         data->buffer += len;
733                         *size += len;
734                 } else if (len < 0) {
735 unwind:
736                         data->buffer -= data->indent + 2;
737                         *size -= data->indent + 2;
738                 }
739         }
740 }
741
742 /* This is the CB_VALID callback for the Netlink library that we
743  * have hooked into. Any successful Netlink message is passed to
744  * this function which handles both the incoming key tables and
745  * the values of the key/value pairs being received. We use
746  * the NLM_F_CREATE flag to determine if the incoming Netlink
747  * message is a key table or a packet containing value pairs.
748  */
749 static int yaml_netlink_msg_parse(struct nl_msg *msg, void *arg)
750 {
751         struct yaml_netlink_input *data = arg;
752         struct nlmsghdr *nlh = nlmsg_hdr(msg);
753
754         if (nlh->nlmsg_flags & NLM_F_CREATE) {
755                 struct genlmsghdr *ghdr = genlmsg_hdr(nlh);
756                 struct nlattr *attrs[LN_SCALAR_MAX + 1];
757
758                 if (genlmsg_parse(nlh, 0, attrs, LN_SCALAR_MAX + 1,
759                                   scalar_attr_policy))
760                         return NL_SKIP;
761
762                 if (attrs[LN_SCALAR_ATTR_LIST]) {
763                         int rc = yaml_parse_key_list(data, NULL,
764                                                      attrs[LN_SCALAR_ATTR_LIST]);
765                         if (rc != NL_OK)
766                                 return rc;
767
768                         /* reset to root node */
769                         data->cur = data->root;
770                 }
771
772                 /* For streaming insert '---' to define start of
773                  * YAML document. This allows use to extract
774                  * documents out of a multiplexed stream.
775                  */
776                 if (data->async) {
777                         char *start_doc = "---\n";
778                         size_t len = strlen(start_doc) + 1;
779
780                         strncpy(data->buffer, start_doc, len);
781                         data->buffer += len - 1;
782                 }
783                 data->version = ghdr->version;
784         } else {
785                 uint16_t maxtype = data->cur->keys.lkl_maxattr;
786                 struct nla_policy policy[maxtype];
787                 struct nlattr *attrs[maxtype];
788                 int size, i;
789
790                 memset(policy, 0, sizeof(struct nla_policy) * maxtype);
791                 for (i = 1; i < maxtype; i++)
792                         policy[i].type = data->cur->keys.lkl_list[i].lkp_data_type;
793
794                 if (genlmsg_parse(nlh, 0, attrs, maxtype, policy))
795                         return NL_SKIP;
796
797                 size = data->parser->raw_buffer.end -
798                        (unsigned char *)data->buffer;
799                 yaml_parse_value_list(data, &size, attrs,
800                                       &data->cur->keys.lkl_list[1]);
801         }
802
803         /* Let yaml_netlink_msg_complete end collecting data */
804         return NL_OK;
805 }
806
807 /* This is the libnl callback for when an error has happened
808  * kernel side. An error message is sent back to the user.
809  */
810 static int yaml_netlink_msg_error(struct sockaddr_nl *who,
811                                   struct nlmsgerr *errmsg, void *arg)
812 {
813         struct nlmsghdr *nlh = (void *)errmsg - NLMSG_HDRLEN;
814         struct yaml_netlink_input *data = arg;
815
816         if ((nlh->nlmsg_type == NLMSG_ERROR ||
817              nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) {
818                 /* libyaml stomps on the reader error so we need to
819                  * cache the source of the error.
820                  */
821                 const char *errstr = nl_geterror(nl_syserr2nlerr(errmsg->error));
822
823 #ifdef HAVE_USRSPC_NLMSGERR
824                 /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags
825                  * which gives greater detail why we failed.
826                  */
827                 if ((nlh->nlmsg_flags & NLM_F_ACK_TLVS) &&
828                     !(nlh->nlmsg_flags & NLM_F_CAPPED)) {
829                         struct nlattr *head = ((void *)&errmsg->msg);
830                         struct nlattr *tb[NLMSGERR_ATTR_MAX];
831
832                         if (nla_parse(tb, NLMSGERR_ATTR_MAX, head,
833                                       nlmsg_attrlen(nlh, 0), NULL) == 0) {
834                                 if (tb[NLMSGERR_ATTR_MSG])
835                                         errstr = nla_strdup(tb[NLMSGERR_ATTR_MSG]);
836                         }
837                 }
838 #endif /* HAVE_USRSPC_NLMSGERR */
839                 data->errmsg = errstr;
840                 data->parser->error = YAML_READER_ERROR;
841                 data->complete = true;
842         }
843         return NL_STOP;
844 }
845
846 static bool cleanup_children(struct yaml_nl_node *parent)
847 {
848         struct yaml_nl_node *child;
849
850         if (nl_list_empty(&parent->children)) {
851                 struct ln_key_props *keys = parent->keys.lkl_list;
852                 int i;
853
854                 for (i = 1; i < parent->keys.lkl_maxattr; i++)
855                         if (keys[i].lkp_value)
856                                 free(keys[i].lkp_value);
857                 nl_list_del(&parent->list);
858                 return true;
859         }
860
861         while ((child = get_next_child(parent, 0)) != NULL) {
862                 if (cleanup_children(child))
863                         free(child);
864         }
865
866         return false;
867 }
868
869 /* This is the libnl callback for when the last Netlink packet
870  * is finished being parsed or its called right away in case
871  * the Linux kernel reports back an error from the Netlink layer.
872  */
873 static int yaml_netlink_msg_complete(struct nl_msg *msg, void *arg)
874 {
875         struct yaml_netlink_input *data = arg;
876         struct nlmsghdr *nlh = nlmsg_hdr(msg);
877
878         /* For the case of NLM_F_DUMP the kernel will send error msgs
879          * yet not be labled NLMSG_ERROR which results in this code
880          * path being executed.
881          */
882         yaml_netlink_msg_error(NULL, nlmsg_data(nlh), arg);
883         if (data->parser->error == YAML_READER_ERROR)
884                 return NL_STOP;
885
886         /* Free internal data. */
887         if (data->root) {
888                 cleanup_children(data->root);
889                 free(data->root);
890                 data->root = NULL;
891         }
892
893         /* For streaming insert '...' to define end of
894          * YAML document
895          */
896         if (data->async) {
897                 char *end_doc = "...\n";
898                 size_t len = strlen(end_doc) + 1;
899
900                 strncpy(data->buffer, end_doc, len);
901                 data->buffer += len - 1;
902         } else {
903                 data->complete = true;
904         }
905
906         return data->async ? NL_OK : NL_STOP;
907 }
908
909 /**
910  * In order for yaml_parser_set_input_netlink() to work we have to
911  * register a yaml_read_handler_t callback. This is that call back
912  * which listens for Netlink packets. Internally nl_recvmsg_report()
913  * calls the various callbacks discussed above.
914  */
915 static int yaml_netlink_read_handler(void *arg, unsigned char *buffer,
916                                      size_t size, size_t *size_read)
917 {
918         struct yaml_netlink_input *data = arg;
919         struct nl_sock *nl = data->nl;
920         struct nl_cb *cb;
921         int rc = 0;
922
923         if (data->complete) {
924                 *size_read = 0;
925                 return 1;
926         }
927
928         data->buffer = buffer;
929
930         cb = nl_socket_get_cb(nl);
931         rc = nl_recvmsgs_report(nl, cb);
932         if (rc == -NLE_INTR) {
933                 *size_read = 0;
934                 return 1;
935         } else if (!data->errmsg && rc < 0) {
936                 data->errmsg = nl_geterror(rc);
937                 return 0;
938         } else if (data->parser->error) {
939                 /* data->errmsg is set in NL_CB_FINISH */
940                 return 0;
941         }
942
943         rc = (unsigned char *)data->buffer - buffer;
944         if ((int)size > rc)
945                 size = rc;
946
947         *size_read = size;
948         return 1;
949 }
950
951 /* libyaml by default just reports "input error" for parser read_handler_t
952  * issues which is not useful. This provides away to get better debugging
953  * info.
954  */
955 YAML_DECLARE(const char *)
956 yaml_parser_get_reader_error(yaml_parser_t *parser)
957 {
958         struct yaml_netlink_input *buf = parser->read_handler_data;
959
960         if (!buf)
961                 return NULL;
962
963         return buf->errmsg;
964 }
965
966 YAML_DECLARE(int)
967 yaml_parser_get_reader_proto_version(yaml_parser_t *parser)
968 {
969         struct yaml_netlink_input *buf = parser->read_handler_data;
970
971         if (!buf)
972                 return 0;
973
974         return buf->version;
975 }
976
977 /* yaml_parser_set_input_netlink() mirrors the libyaml function
978  * yaml_parser_set_input_file(). Internally it does setup of the
979  * libnl socket callbacks to parse the Netlink messages received
980  * as well as register the special yaml_read_handler_t for libyaml.
981  * This is exposed for public use.
982  */
983 YAML_DECLARE(int)
984 yaml_parser_set_input_netlink(yaml_parser_t *reply, struct nl_sock *nl,
985                               bool stream)
986 {
987         struct yaml_netlink_input *buf;
988         int rc;
989
990         buf = calloc(1, sizeof(*buf));
991         if (!buf) {
992                 reply->error = YAML_MEMORY_ERROR;
993                 return false;
994         }
995
996         rc = lustre_netlink_register(nl, stream);
997         if (rc < 0) {
998                 yaml_parser_set_reader_error(reply,
999                                              "netlink setup failed", 0,
1000                                              -rc);
1001                 goto failed;
1002         }
1003
1004         buf->nl = nl;
1005         buf->async = stream;
1006         buf->parser = reply;
1007         yaml_parser_set_input(buf->parser, yaml_netlink_read_handler, buf);
1008
1009         rc = nl_socket_modify_cb(buf->nl, NL_CB_VALID, NL_CB_CUSTOM,
1010                                  yaml_netlink_msg_parse, buf);
1011         if (rc < 0) {
1012                 yaml_parser_set_reader_error(reply,
1013                                              "netlink msg recv setup failed",
1014                                              0, -rc);
1015                 goto failed;
1016         }
1017
1018         rc = nl_socket_modify_cb(buf->nl, NL_CB_FINISH, NL_CB_CUSTOM,
1019                                  yaml_netlink_msg_complete, buf);
1020         if (rc < 0) {
1021                 yaml_parser_set_reader_error(reply,
1022                                              "netlink msg cleanup setup failed",
1023                                              0, -rc);
1024                 goto failed;
1025         }
1026
1027         rc = nl_socket_modify_err_cb(nl, NL_CB_CUSTOM, yaml_netlink_msg_error,
1028                                      buf);
1029         if (rc < 0) {
1030                 yaml_parser_set_reader_error(reply,
1031                                              "failed to register error handling",
1032                                              0, -rc);
1033 failed:
1034                 free(buf);
1035         }
1036
1037         return rc < 0 ? false : true;
1038 }
1039
1040 /* The role of the YAML emitter for us is to take a YAML document and
1041  * change into a Netlink stream to send to the kernel to be processed.
1042  * This provides the infrastructure to do this.
1043  */
1044 struct yaml_netlink_output {
1045         yaml_emitter_t          *emitter;
1046         struct nl_sock          *nl;
1047         char                    *family;
1048         int                     family_id;
1049         int                     version;
1050         int                     cmd;
1051         int                     pid;
1052         int                     flags;
1053 };
1054
1055 /* Internal use for this file only. We fill in details of why creating
1056  * a Netlink packet to send failed. The end user will be able to debug
1057  * what went wrong.
1058  */
1059 static int
1060 yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem)
1061 {
1062         emitter->error = YAML_WRITER_ERROR;
1063         emitter->problem = problem;
1064
1065         return 0;
1066 }
1067
1068 static unsigned int indent_level(const char *str)
1069 {
1070         char *tmp = (char *)str;
1071
1072         while (isspace(*tmp))
1073                 ++tmp;
1074         return tmp - str;
1075 }
1076
1077 #define LNKF_END 8
1078
1079 static enum lnet_nl_key_format yaml_format_type(yaml_emitter_t *emitter,
1080                                                 char *line,
1081                                                 unsigned int *offset)
1082 {
1083         unsigned int indent = *offset, new_indent = 0;
1084         enum lnet_nl_key_format fmt = 0;
1085         char *tmp;
1086
1087         new_indent = indent_level(line);
1088         if (new_indent < indent) {
1089                 *offset = indent - emitter->best_indent;
1090                 return LNKF_END;
1091         }
1092
1093         if (strncmp(line + new_indent, "- ", 2) == 0) {
1094                 memset(line + new_indent, ' ', 2);
1095                 new_indent += 2;
1096         }
1097
1098         /* hdr: [ a : 1, b : 2, c : 3 ] */
1099         tmp = strstr(line + new_indent, ": ");
1100         if (!tmp)
1101                 tmp = line + new_indent;
1102         else
1103                 fmt |= LNKF_MAPPING;
1104
1105         if (strchr(tmp, '{') || strchr(tmp, '[')) {
1106                 fmt |= LNKF_FLOW;
1107         } else if (strchr(tmp, '}') || strchr(tmp, ']')) {
1108                 fmt &= ~LNKF_MAPPING;
1109                 fmt |= LNKF_FLOW;
1110         }
1111
1112         if (indent != new_indent) {
1113                 *offset = new_indent;
1114                 fmt |= LNKF_SEQUENCE;
1115         }
1116
1117         return fmt;
1118 }
1119
1120 static int yaml_fill_scalar_data(struct nl_msg *msg,
1121                                  enum lnet_nl_key_format fmt,
1122                                  char *line)
1123 {
1124         char *sep = strchr(line, ':');
1125         int rc = 0;
1126         long num;
1127
1128         if (sep)
1129                 *sep++ = '\0';
1130
1131         if (strspn(line, "-0123456789") == strlen(line)) {
1132                 num = strtoll(line, NULL, 0);
1133
1134                 NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, num);
1135         } else {
1136                 NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, line);
1137         }
1138
1139         if (fmt & LNKF_FLOW) {
1140                 memset(line, ' ', strlen(line) + 1);
1141                 goto nla_put_failure;
1142         }
1143
1144         if (fmt & LNKF_MAPPING && sep && strlen(sep)) {
1145                 while (isspace(*sep))
1146                         ++sep;
1147
1148                 if (strspn(sep, "-0123456789") == strlen(sep)) {
1149                         num = strtoll(sep, NULL, 0);
1150                         NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, num);
1151                 } else {
1152                         NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, sep);
1153                 }
1154         }
1155 nla_put_failure:
1156         return rc;
1157 }
1158
1159 static int yaml_create_nested_list(struct yaml_netlink_output *out,
1160                                    struct nl_msg *msg, char **hdr,
1161                                    char **entry, unsigned int *indent,
1162                                    enum lnet_nl_key_format fmt)
1163 {
1164         bool nested = fmt & LNKF_SEQUENCE;
1165         struct nlattr *list = NULL;
1166         char *line;
1167         int rc = 0;
1168
1169         /* Not needed for FLOW only case */
1170         if (nested) {
1171                 list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
1172                 if (!list) {
1173                         yaml_emitter_set_writer_error(out->emitter,
1174                                                       "Emmitter netlink list creation failed");
1175                         rc = -EINVAL;
1176                         goto nla_put_failure;
1177                 }
1178         }
1179
1180         if (fmt != LNKF_FLOW) {
1181                 rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent);
1182                 if (rc < 0)
1183                         goto nla_put_failure;
1184         }
1185
1186         if (fmt & LNKF_FLOW) {
1187                 char *tmp = strchr(*hdr, '{');
1188                 bool format = false;
1189
1190                 if (!tmp) {
1191                         tmp = strchr(*hdr, '[');
1192                         if (!tmp) {
1193                                 yaml_emitter_set_writer_error(out->emitter,
1194                                                               "Emmitter flow format invalid");
1195                                 rc = -EINVAL;
1196                                 goto nla_put_failure;
1197                         }
1198                         fmt |= LNKF_SEQUENCE;
1199                 } else
1200                         fmt |= LNKF_MAPPING;
1201                 *tmp = ' ';
1202
1203                 list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
1204                 if (!list) {
1205                         yaml_emitter_set_writer_error(out->emitter,
1206                                                       "Emmitter netlink list creation failed");
1207                         rc = -EINVAL;
1208                         goto nla_put_failure;
1209                 }
1210
1211                 while ((line = strsep(hdr, ",")) != NULL) {
1212                         while (!isalnum(line[0]))
1213                                 line++;
1214
1215                         /* Flow can be splt across lines by libyaml library.
1216                          * This is executed only once.
1217                          */
1218                         tmp = strchr(line, '}');
1219                         if (!tmp)
1220                                 tmp = strchr(line, ']');
1221                         if (tmp) {
1222                                 format = true;
1223                                 *tmp = '\0';
1224                         }
1225
1226                         rc = yaml_fill_scalar_data(msg, fmt, line);
1227                         if (rc < 0)
1228                                 goto nla_put_failure;
1229
1230                         /* Move to next YAML line */
1231                         tmp = strstr(*entry, line);
1232                         if (tmp && strcmp(tmp, line) == 0)
1233                                 strsep(entry, "\n");
1234                 }
1235
1236                 if (!format) {
1237                         yaml_emitter_set_writer_error(out->emitter,
1238                                                       "Emmitter flow format invalid");
1239                         rc = -EINVAL;
1240                         goto nla_put_failure;
1241                 }
1242
1243                 nla_nest_end(msg, list);
1244         } else {
1245                 do {
1246                         line = strsep(entry, "\n");
1247 have_next_line:
1248                         if (!line || !strlen(line) || strcmp(line, "...") == 0)
1249                                 break;
1250
1251                         fmt = yaml_format_type(out->emitter, line, indent);
1252                         if (fmt == LNKF_END)
1253                                 break;
1254
1255                         if (fmt & ~LNKF_MAPPING) { /* Filter out mappings */
1256                                 rc = yaml_create_nested_list(out, msg, &line,
1257                                                              entry, indent,
1258                                                              fmt);
1259                                 if (rc < 0)
1260                                         goto nla_put_failure;
1261
1262                                 if (line)
1263                                         goto have_next_line;
1264                         } else {
1265                                 rc = yaml_fill_scalar_data(msg, fmt,
1266                                                            line + *indent);
1267                                 if (rc < 0)
1268                                         goto nla_put_failure;
1269                         }
1270                 } while (strcmp(*entry, ""));
1271
1272                 /* strsep in the above loop moves entry to a value pass the
1273                  * end of the nested list. So to avoid losing this value we
1274                  * replace hdr with line.
1275                  */
1276                 *hdr = line;
1277         }
1278
1279         if (nested)
1280                 nla_nest_end(msg, list);
1281 nla_put_failure:
1282         return rc;
1283 }
1284
1285 /* YAML allows ' and " in its documents but those characters really
1286  * confuse libc string handling. The workaround is to replace
1287  * ' and " with another reserved character for YAML '%' which is
1288  * for tags which shouldn't matter if we send in a Netlink packet.
1289  * The kernel side will need to handle % in a special way.
1290  */
1291 static void yaml_quotation_handling(char *buf)
1292 {
1293         char *tmp = buf, *line;
1294
1295         line = strstr(tmp, "! \'");
1296         if (line)
1297                 line[0] = ' ';
1298
1299         while ((line = strchr(tmp, '\"')) != NULL) {
1300                 line[0] = ' ';
1301                 tmp = strchr(line, '\"');
1302                 tmp[0] = ' ';
1303         }
1304
1305         while ((line = strchr(tmp, '\'')) != NULL) {
1306                 line[0] = ' ';
1307                 tmp = strchr(line, '\'');
1308                 tmp[0] = ' ';
1309         }
1310 }
1311
1312 /* libyaml takes the YAML documents and places the data into an
1313  * internal buffer to the library. We take each line and turn it
1314  * into a Netlink message using the same format as the key table.
1315  * The reason for this approach is that we can do filters at the
1316  * key level or the key + value level.
1317  */
1318 static int yaml_netlink_write_handler(void *data, unsigned char *buffer,
1319                                       size_t size)
1320 {
1321         struct yaml_netlink_output *out = data;
1322         char *buf = strndup((char *)buffer, size);
1323         char *entry = buf, *tmp = buf, *line;
1324         enum lnet_nl_key_format fmt = 0;
1325         struct nl_msg *msg = NULL;
1326         unsigned int indent = 0;
1327         bool nogroups = true;
1328         int rc = 0;
1329
1330         yaml_quotation_handling(entry);
1331
1332         while (entry && strcmp(line = strsep(&entry, "\n"), "")) {
1333 already_have_line:
1334                 if (strcmp(line, "---") == 0 || strcmp(line, "...") == 0)
1335                         continue;
1336
1337                 /* In theory we could have a sequence of groups but a bug in
1338                  * libyaml prevents this from happing
1339                  */
1340                 if (line[0] != ' ' && line[0] != '-') {
1341                         bool extra = false;
1342
1343                         if (strchr(line, '{') || strchr(line, '['))
1344                                 extra = true;
1345
1346                         tmp = strchr(line, ':');
1347                         if (!tmp)
1348                                 continue;
1349                         *tmp = '\0';
1350
1351                         rc = lustre_netlink_add_group(out->nl, out->family,
1352                                                       line);
1353                         if (rc < 0) {
1354                                 yaml_emitter_set_writer_error(out->emitter,
1355                                                               "Netlink group does not exist");
1356                                 goto nla_put_failure;
1357                         }
1358                         nogroups = false;
1359                         /* Handle case first line contains more than a
1360                          * simple key
1361                          */
1362                         if (extra) {
1363                                 line = ++tmp;
1364                                 indent = 1;
1365                                 goto already_have_line;
1366                         }
1367                 } else {
1368                         if (!msg) {
1369                                 void *usr_hdr;
1370
1371                                 msg = nlmsg_alloc();
1372                                 if (!msg) {
1373                                         out->emitter->error = YAML_MEMORY_ERROR;
1374                                         goto nla_put_failure;
1375                                 }
1376
1377                                 usr_hdr = genlmsg_put(msg, out->pid,
1378                                                       NL_AUTO_SEQ,
1379                                                       out->family_id, 0,
1380                                                       out->flags, out->cmd,
1381                                                       out->version);
1382                                 if (!usr_hdr) {
1383                                         out->emitter->error = YAML_MEMORY_ERROR;
1384                                         nlmsg_free(msg);
1385                                         goto nla_put_failure;
1386                                 }
1387                         }
1388
1389                         fmt = yaml_format_type(out->emitter, line, &indent);
1390                         if (fmt & ~LNKF_MAPPING) {
1391                                 rc = yaml_create_nested_list(out, msg, &line,
1392                                                              &entry, &indent,
1393                                                              fmt);
1394                                 if (rc < 0) {
1395                                         yaml_emitter_set_writer_error(out->emitter,
1396                                                                       nl_geterror(rc));
1397                                         nlmsg_free(msg);
1398                                         goto nla_put_failure;
1399                                 }
1400                                 /* yaml_create_nested_list set line to the next
1401                                  * entry. We can just add it to the msg directly.
1402                                  */
1403                                 if (line)
1404                                         goto already_have_line;
1405                         } else {
1406                                 rc = yaml_fill_scalar_data(msg, fmt,
1407                                                            line + indent);
1408                                 if (rc < 0) {
1409                                         yaml_emitter_set_writer_error(out->emitter,
1410                                                                       nl_geterror(rc));
1411                                         nlmsg_free(msg);
1412                                         goto nla_put_failure;
1413                                 }
1414                         }
1415                 }
1416         }
1417
1418         /* Don't success if no valid groups found */
1419         if (nogroups) {
1420                 yaml_emitter_set_writer_error(out->emitter,
1421                                               "Emitter contains no valid Netlink groups");
1422                 goto nla_put_failure;
1423         }
1424
1425         if (msg) {
1426                 rc = nl_send_auto(out->nl, msg);
1427                 nlmsg_free(msg);
1428         } else {
1429                 rc = genl_send_simple(out->nl, out->family_id, out->cmd,
1430                                       out->version, out->flags);
1431         }
1432         if (rc < 0)
1433                 yaml_emitter_set_writer_error(out->emitter,
1434                                               nl_geterror(rc));
1435 nla_put_failure:
1436         free(buf);
1437         return out->emitter->error == YAML_NO_ERROR ? 1 : 0;
1438 }
1439
1440 /* This function is used by external utilities to use Netlink with
1441  * libyaml so we can turn YAML documentations into Netlink message
1442  * to send. This behavior mirrors yaml_emitter_set_output_file()
1443  * which is used to write out a YAML document to a file.
1444  */
1445 YAML_DECLARE(int)
1446 yaml_emitter_set_output_netlink(yaml_emitter_t *sender, struct nl_sock *nl,
1447                                 char *family, int version, int cmd, int flags)
1448 {
1449         struct yaml_netlink_output *out;
1450
1451         out = calloc(1, sizeof(*out));
1452         if (!out) {
1453                 sender->error = YAML_MEMORY_ERROR;
1454                 return false;
1455         }
1456
1457         /* Get family ID */
1458         out->family_id = genl_ctrl_resolve(nl, family);
1459         if (out->family_id < 0) {
1460                 yaml_emitter_set_writer_error(sender,
1461                                               "failed to resolve Netlink family id");
1462                 free(out);
1463                 return false;
1464         }
1465
1466         out->emitter = sender;
1467         out->nl = nl;
1468         out->family = family;
1469         out->version = version;
1470         out->cmd = cmd;
1471         out->flags = flags;
1472         out->pid = nl_socket_get_local_port(nl);
1473         yaml_emitter_set_output(sender, yaml_netlink_write_handler, out);
1474         return true;
1475 }
1476
1477 /* Error handling helpers */
1478 void yaml_emitter_log_error(yaml_emitter_t *emitter, FILE *log)
1479 {
1480         /* YAML_WRITER_ERROR means no Netlink support so use old API */
1481         switch (emitter->error) {
1482         case YAML_MEMORY_ERROR:
1483                 fprintf(log, "Memory error: Not enough memory for emitting\n");
1484                         break;
1485         case YAML_WRITER_ERROR:
1486                 fprintf(log, "Writer error: %s\n", emitter->problem);
1487                 break;
1488         case YAML_EMITTER_ERROR:
1489                 fprintf(log, "Emitter error: %s\n", emitter->problem);
1490         default:
1491                 break;
1492         }
1493 }
1494
1495 void yaml_parser_log_error(yaml_parser_t *parser, FILE *log, const char *errmsg)
1496 {
1497         const char *extra;
1498
1499         switch (parser->error) {
1500         case YAML_MEMORY_ERROR:
1501                 fprintf(log, "Memory error: Not enough memory for parser\n");
1502                 break;
1503
1504         case YAML_SCANNER_ERROR:
1505         case YAML_PARSER_ERROR:
1506                 if (parser->context) {
1507                         fprintf(log,
1508                                 "%s error: %s at line %d, column %d\n%s at line %d, column %d\n",
1509                                 parser->error == YAML_SCANNER_ERROR ? "Scanner" : "Parser",
1510                                 parser->context,
1511                                 (int)parser->context_mark.line + 1,
1512                                 (int)parser->context_mark.column + 1,
1513                                 parser->problem,
1514                                 (int)parser->problem_mark.line + 1,
1515                                 (int)parser->problem_mark.column + 1);
1516                 } else {
1517                         fprintf(log, "%s error: %s at line %d, column %d\n",
1518                                 parser->error == YAML_SCANNER_ERROR ? "Scanner" : "Parser",
1519                                 parser->problem,
1520                                 (int)parser->problem_mark.line + 1,
1521                                 (int)parser->problem_mark.column + 1);
1522                 }
1523                 break;
1524
1525         case YAML_READER_ERROR:
1526                 extra = yaml_parser_get_reader_error(parser);
1527                 if (!extra)
1528                         extra = parser->problem;
1529
1530                 if (parser->problem_value != -1) {
1531                         fprintf(log, "Reader error: '%s':#%X at %ld'\n",
1532                                 extra, parser->problem_value,
1533                                 (long)parser->problem_offset);
1534                 } else {
1535                         fprintf(log, "Reader error: '%s' at %ld\n",
1536                                 extra, (long)parser->problem_offset);
1537                 }
1538                 fallthrough;
1539         default:
1540                 break;
1541         }
1542 }