Whamcloud - gitweb
LU-15220 lnet: use 'fallthrough' pseudo keyword for switch
[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         struct yaml_nl_node     *cur;
321         struct yaml_nl_node     *root;
322 };
323
324 /* Sadly this is not exported out of libyaml. We want to
325  * give descent error message to help people track down
326  * issues. This is internal only to this code. The end
327  * user will never need to use this.
328  */
329 static int
330 yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
331                              size_t offset, int value)
332 {
333         parser->error = YAML_READER_ERROR;
334         parser->problem = problem;
335         parser->problem_offset = offset;
336         parser->problem_value = value;
337
338         return 0;
339 }
340
341 /* This is used to handle all the Netlink packets containing the keys
342  * for the key/value pairs. Instead of creating unique code to handle
343  * every type of Netlink attributes possible we create a generic
344  * abstract so the same code be used with everything. To make this
345  * work the key table trasmitted must report the tree structure and
346  * state of the keys. We use nested attributes as a way to notify libyaml
347  * we have a new collection. This is used to create the tree structure
348  * of the YAML document. Each collection of attributes define the following:
349  *
350  * LN_SCALAR_ATTR_INDEX:
351  *      enum XXX_ATTR that defines which value we are dealing with. This
352  *      varies greatly depending on the subsystem we have developed for.
353  *
354  * LN_SCALAR_ATTR_NLA_TYPE:
355  *      The Netlink attribute type (NLA_STRING, NLA_U32, etc..) the coming
356  *      value will be.
357  *
358  * LN_SCALAR_ATTR_VALUE:
359  *      The string represnting key's actually scalar value.
360  *
361  * LN_SCALAR_ATTR_INT_VALUE:
362  *      For this case the key is an integer value. This shouldn't be
363  *      sent for the receive case since we are going to just turn it
364  *      into a string for YAML. Sending packets will make use of this.
365  *
366  * LN_SCALAR_ATTR_KEY_TYPE:
367  *      What YAML format is it? block or flow. Only useful for
368  *      LN_SCALAR_ATTR_NLA_TYPE of type NLA_NESTED or NLA_NUL_STRING
369  *
370  * LN_SCALAR_ATTR_LIST + LN_SCALAR_LIST_SIZE:
371  *      Defined the next collection which is a collection of nested
372  *      attributes of the above.
373  */
374 static struct nla_policy scalar_attr_policy[LN_SCALAR_MAX + 1] = {
375         [LN_SCALAR_ATTR_LIST]           = { .type = NLA_NESTED },
376         [LN_SCALAR_ATTR_LIST_SIZE]      = { .type = NLA_U16 },
377         [LN_SCALAR_ATTR_INDEX]          = { .type = NLA_U16 },
378         [LN_SCALAR_ATTR_NLA_TYPE]       = { .type = NLA_U16 },
379         [LN_SCALAR_ATTR_VALUE]          = { .type = NLA_STRING },
380         [LN_SCALAR_ATTR_INT_VALUE]      = { .type = NLA_S64 },
381         [LN_SCALAR_ATTR_KEY_FORMAT]     = { .type = NLA_U16 },
382 };
383
384 static int yaml_parse_key_list(struct yaml_netlink_input *data,
385                                struct yaml_nl_node *parent,
386                                struct nlattr *list)
387 {
388         struct nlattr *tbl_info[LN_SCALAR_MAX + 1];
389         struct yaml_nl_node *node = NULL;
390         struct nlattr *attr;
391         int rem;
392
393         nla_for_each_nested(attr, list, rem) {
394                 uint16_t index = 0;
395
396                 if (nla_parse_nested(tbl_info, LN_SCALAR_MAX, attr,
397                                      scalar_attr_policy))
398                         break;
399
400                 if (tbl_info[LN_SCALAR_ATTR_LIST_SIZE]) {
401                         size_t cnt;
402
403                         cnt = nla_get_u16(tbl_info[LN_SCALAR_ATTR_LIST_SIZE]) + 1;
404                         if (!node) {
405                                 size_t len = sizeof(struct nl_list_head) * 2;
406
407                                 len += sizeof(struct ln_key_props) * cnt;
408                                 node = calloc(1, len);
409                                 if (!node)
410                                         return NL_STOP;
411
412                                 node->keys.lkl_maxattr = cnt;
413                                 NL_INIT_LIST_HEAD(&node->children);
414                                 nl_init_list_head(&node->list);
415
416                                 if (!data->root)
417                                         data->root = node;
418                                 if (!data->cur)
419                                         data->cur = node;
420                                 if (parent)
421                                         nl_list_add_tail(&node->list,
422                                                          &parent->children);
423                         }
424                 }
425
426                 if (tbl_info[LN_SCALAR_ATTR_INDEX])
427                         index = nla_get_u16(tbl_info[LN_SCALAR_ATTR_INDEX]);
428
429                 if (!node || index == 0)
430                         return NL_STOP;
431
432                 if (tbl_info[LN_SCALAR_ATTR_KEY_FORMAT]) {
433                         uint16_t format;
434
435                         format = nla_get_u16(tbl_info[LN_SCALAR_ATTR_KEY_FORMAT]);
436                         node->keys.lkl_list[index].lkp_key_format = format;
437                 }
438
439                 if (tbl_info[LN_SCALAR_ATTR_NLA_TYPE]) {
440                         uint16_t type;
441
442                         type = nla_get_u16(tbl_info[LN_SCALAR_ATTR_NLA_TYPE]);
443                         node->keys.lkl_list[index].lkp_data_type = type;
444                 }
445
446                 if (tbl_info[LN_SCALAR_ATTR_VALUE]) {
447                         char *name;
448
449                         name = nla_strdup(tbl_info[LN_SCALAR_ATTR_VALUE]);
450                         if (!name)
451                                 return NL_STOP;
452                         node->keys.lkl_list[index].lkp_value = name;
453                 }
454
455                 if (tbl_info[LN_SCALAR_ATTR_LIST]) {
456                         int rc = yaml_parse_key_list(data, node,
457                                                      tbl_info[LN_SCALAR_ATTR_LIST]);
458                         if (rc != NL_OK)
459                                 return rc;
460                 }
461         }
462         return NL_OK;
463 }
464
465 static struct yaml_nl_node *get_next_child(struct yaml_nl_node *node,
466                                            unsigned int idx)
467 {
468         struct yaml_nl_node *child;
469         unsigned int i = 0;
470
471         nl_list_for_each_entry(child, &node->children, list)
472                 if (idx == i++)
473                         return child;
474
475         return NULL;
476 }
477
478 /**
479  * In the YAML C implementation the scanner transforms the input stream
480  * (Netlink in this case) into a sequence of keys. First we need to
481  * examine the potential keys involved to see the mapping to Netlink.
482  * We have chosen to examine the YAML stack with keys since they are
483  * more detailed when compared to yaml_document_t / yaml_nodes and
484  * yaml_event_t.
485  *
486  *      STREAM-START(encoding)          # The stream start.
487  *      STREAM-END                      # The stream end.
488  *      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
489  *      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
490  *      DOCUMENT-START                  # '---'
491  *      DOCUMENT-END                    # '...'
492  *      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
493  *      BLOCK-MAPPING-START             # sequence or a block mapping.
494  *      BLOCK-END                       # Indentation decrease.
495  *      FLOW-SEQUENCE-START             # '['
496  *      FLOW-SEQUENCE-END               # ']'
497  *      FLOW-MAPPING-START              # '{'
498  *      FLOW-MAPPING-END                # '}'
499  *      BLOCK-ENTRY                     # '-'
500  *      FLOW-ENTRY                      # ','
501  *      KEY                             # '?' or nothing (simple keys).
502  *      VALUE                           # ':'
503  *      ALIAS(anchor)                   # '*anchor'
504  *      ANCHOR(anchor)                  # '&anchor'
505  *      TAG(handle,suffix)              # '!handle!suffix'
506  *      SCALAR(value,style)             # A scalar.
507  *
508  * For our read_handler / write_handler STREAM-START / STREAM-END,
509  * VERSION-DIRECTIVE, and TAG-DIRECTIVE are hanndler by the libyaml
510  * internal scanner so we don't need to deal with it. Normally for
511  * LNet / Lustre DOCUMENT-START / DOCUMENT-END are not needed but it
512  * could be easily handled. In the case of multiplex streams we could
513  * see these used to differentiate data coming in.
514  *
515  * It is here we handle any simple scalars or values of the key /value
516  * pair. How the YAML document is formated is dependent on the key
517  * table's data.
518  */
519 static void yaml_parse_value_list(struct yaml_netlink_input *data, int *size,
520                                   struct nlattr *attr_array[],
521                                   struct ln_key_props *parent)
522 {
523         struct yaml_nl_node *node = data->cur;
524         struct ln_key_props *keys = node->keys.lkl_list;
525         int mapping = parent->lkp_key_format;
526         int child_idx = 0, len = 0, i;
527
528         for (i = 1; i < node->keys.lkl_maxattr; i++) {
529                 struct nlattr *attr;
530
531                 attr = attr_array[i];
532                 if (!attr && !keys[i].lkp_value)
533                         continue;
534
535                 if (keys[i].lkp_data_type != NLA_NUL_STRING &&
536                     keys[i].lkp_data_type != NLA_NESTED) {
537                         if (!attr)
538                                 continue;
539
540                         if (!(mapping & LNKF_FLOW)) {
541                                 unsigned int indent = data->indent ?
542                                                       data->indent : 2;
543
544                                 memset(data->buffer, ' ', indent);
545                                 if (mapping & LNKF_SEQUENCE) {
546                                         ((char *)data->buffer)[indent - 2] = '-';
547                                         if (mapping & LNKF_MAPPING)
548                                                 mapping &= ~LNKF_SEQUENCE;
549                                 }
550                                 data->buffer += indent;
551                                 *size -= indent;
552                         }
553
554                         if (mapping & LNKF_MAPPING) {
555                                 len = snprintf(data->buffer, *size, "%s: ",
556                                                keys[i].lkp_value);
557                                 if (len < 0)
558                                         goto unwind;
559                                 data->buffer += len;
560                                 *size -= len;
561                         }
562                 }
563
564                 switch (keys[i].lkp_data_type) {
565                 case NLA_NESTED: {
566                         struct yaml_nl_node *next = get_next_child(node,
567                                                                    child_idx++);
568                         int num = next->keys.lkl_maxattr;
569                         struct nla_policy nest_policy[num];
570                         struct yaml_nl_node *old;
571                         struct nlattr *cnt_attr;
572                         int rem, j;
573
574                         if (!attr)
575                                 continue;
576
577                         memset(nest_policy, 0, sizeof(struct nla_policy) * num);
578                         for (j = 1; j < num; j++)
579                                 nest_policy[j].type = next->keys.lkl_list[j].lkp_data_type;
580
581                         old = data->cur;
582                         data->cur = next;
583                         nla_for_each_nested(cnt_attr, attr, rem) {
584                                 struct nlattr *nest_info[num];
585                                 uint16_t indent = 0;
586
587                                 if (nla_parse_nested(nest_info, num, cnt_attr,
588                                                      nest_policy))
589                                         break;
590
591                                 if (keys[i].lkp_key_format & LNKF_FLOW) {
592                                         char brace = '{';
593
594                                         if (keys[i].lkp_key_format &
595                                             LNKF_SEQUENCE)
596                                                 brace = '[';
597
598                                         len = snprintf(data->buffer, *size,
599                                                        "%*s%s: %c ",
600                                                        data->indent, "",
601                                                        keys[i].lkp_value,
602                                                        brace);
603                                 } else {
604                                         if (keys[i].lkp_key_format &
605                                             LNKF_MAPPING)
606                                                 indent += 2;
607                                         if (keys[i].lkp_key_format &
608                                             LNKF_SEQUENCE)
609                                                 indent += 2;
610
611                                         len = snprintf(data->buffer, *size,
612                                                        "%*s%s:\n",
613                                                        data->indent, "",
614                                                        keys[i].lkp_value);
615                                 }
616                                 if (len < 0)
617                                         goto unwind;
618                                 data->buffer += len;
619                                 *size -= len;
620                                 len = 0;
621
622                                 data->indent += indent;
623                                 yaml_parse_value_list(data, size, nest_info,
624                                                       &keys[i]);
625                                 data->indent -= indent;
626
627                                 if (keys[i].lkp_key_format & LNKF_FLOW) {
628                                         char *tmp = (char *)data->buffer - 2;
629                                         char *brace = " }\n";
630
631                                         if (keys[i].lkp_key_format &
632                                             LNKF_SEQUENCE)
633                                                 brace = " ]\n";
634
635                                         memcpy(tmp, brace, strlen(brace));
636                                         data->buffer++;
637                                         *size -= 1;
638                                 }
639                         }
640                         data->cur = old;
641                         break;
642                 }
643
644                 case NLA_NUL_STRING:
645                         if (i == 1) {
646                                 if (data->cur != data->root)
647                                         goto not_first;
648
649                                 /* The top level is special so only print
650                                  * once
651                                  */
652                                 if (strlen(keys[i].lkp_value)) {
653                                         len = snprintf(data->buffer,
654                                                        *size, "%s:\n",
655                                                        keys[i].lkp_value);
656                                         if (len < 0)
657                                                 goto unwind;
658                                         data->buffer += len;
659                                         *size -= len;
660                                         len = 0;
661                                 }
662                                 data->indent = 0;
663                                 if (!(mapping & LNKF_FLOW)) {
664                                         if (mapping & LNKF_SEQUENCE)
665                                                 data->indent += 2;
666                                         else if (mapping & LNKF_MAPPING)
667                                                 data->indent += 2;
668                                 }
669 not_first:
670                                 if (attr && parent->lkp_value) {
671                                         free(parent->lkp_value);
672                                         parent->lkp_value = nla_strdup(attr);
673                                 }
674                         }
675                         break;
676
677                 case NLA_STRING:
678                         len = snprintf(data->buffer, *size, "%s",
679                                        nla_get_string(attr));
680                         break;
681
682                 case NLA_U16:
683                         len = snprintf(data->buffer, *size, "%hu",
684                                        nla_get_u16(attr));
685                         break;
686
687                 case NLA_U32:
688                         len = snprintf(data->buffer, *size, "%u",
689                                        nla_get_u32(attr));
690                         break;
691
692                 case NLA_U64:
693                         len = snprintf(data->buffer, *size, "%ju",
694                                        nla_get_u64(attr));
695                         break;
696
697                 case NLA_S16:
698                         len = snprintf(data->buffer, *size, "%hd",
699                                        nla_get_u16(attr));
700                         break;
701
702                 case NLA_S32:
703                         len = snprintf(data->buffer, *size, "%d",
704                                        nla_get_s32(attr));
705                         break;
706
707                 case NLA_S64:
708                         len = snprintf(data->buffer, *size, "%jd",
709                                        nla_get_s64(attr));
710                         fallthrough;
711                 default:
712                         break;
713                 }
714
715                 if (len) {
716                         if (mapping & LNKF_FLOW) {
717                                 strcat((char *)data->buffer, ", ");
718                                 len += 2;
719                         } else {
720                                 ((char *)data->buffer)[len++] = '\n';
721                         }
722                         data->buffer += len;
723                         *size += len;
724                 } else if (len < 0) {
725 unwind:
726                         data->buffer -= data->indent + 2;
727                         *size -= data->indent + 2;
728                 }
729         }
730 }
731
732 /* This is the CB_VALID callback for the Netlink library that we
733  * have hooked into. Any successful Netlink message is passed to
734  * this function which handles both the incoming key tables and
735  * the values of the key/value pairs being received. We use
736  * the NLM_F_CREATE flag to determine if the incoming Netlink
737  * message is a key table or a packet containing value pairs.
738  */
739 static int yaml_netlink_msg_parse(struct nl_msg *msg, void *arg)
740 {
741         struct yaml_netlink_input *data = arg;
742         struct nlmsghdr *nlh = nlmsg_hdr(msg);
743
744         if (nlh->nlmsg_flags & NLM_F_CREATE) {
745                 struct nlattr *attrs[LN_SCALAR_MAX + 1];
746
747                 if (genlmsg_parse(nlh, 0, attrs, LN_SCALAR_MAX + 1,
748                                   scalar_attr_policy))
749                         return NL_SKIP;
750
751                 if (attrs[LN_SCALAR_ATTR_LIST]) {
752                         int rc = yaml_parse_key_list(data, NULL,
753                                                      attrs[LN_SCALAR_ATTR_LIST]);
754                         if (rc != NL_OK)
755                                 return rc;
756
757                         /* reset to root node */
758                         data->cur = data->root;
759                 }
760
761                 /* For streaming insert '---' to define start of
762                  * YAML document. This allows use to extract
763                  * documents out of a multiplexed stream.
764                  */
765                 if (data->async) {
766                         char *start_doc = "---\n";
767                         size_t len = strlen(start_doc) + 1;
768
769                         strncpy(data->buffer, start_doc, len);
770                         data->buffer += len - 1;
771                 }
772         } else {
773                 uint16_t maxtype = data->cur->keys.lkl_maxattr;
774                 struct nla_policy policy[maxtype];
775                 struct nlattr *attrs[maxtype];
776                 int size, i;
777
778                 memset(policy, 0, sizeof(struct nla_policy) * maxtype);
779                 for (i = 1; i < maxtype; i++)
780                         policy[i].type = data->cur->keys.lkl_list[i].lkp_data_type;
781
782                 if (genlmsg_parse(nlh, 0, attrs, maxtype, policy))
783                         return NL_SKIP;
784
785                 size = data->parser->raw_buffer.end -
786                        (unsigned char *)data->buffer;
787                 yaml_parse_value_list(data, &size, attrs,
788                                       &data->cur->keys.lkl_list[1]);
789         }
790
791         /* Let yaml_netlink_msg_complete end collecting data */
792         return NL_OK;
793 }
794
795 static bool cleanup_children(struct yaml_nl_node *parent)
796 {
797         struct yaml_nl_node *child;
798
799         if (nl_list_empty(&parent->children)) {
800                 struct ln_key_props *keys = parent->keys.lkl_list;
801                 int i;
802
803                 for (i = 1; i < parent->keys.lkl_maxattr; i++)
804                         if (keys[i].lkp_value)
805                                 free(keys[i].lkp_value);
806                 nl_list_del(&parent->list);
807                 return true;
808         }
809
810         while ((child = get_next_child(parent, 0)) != NULL) {
811                 if (cleanup_children(child))
812                         free(child);
813         }
814
815         return false;
816 }
817
818 /* This is the libnl callback for when the last Netlink packet
819  * is finished being parsed or its called right away in case
820  * the Linux kernel reports back an error from the Netlink layer.
821  */
822 static int yaml_netlink_msg_complete(struct nl_msg *msg, void *arg)
823 {
824         struct yaml_netlink_input *data = arg;
825         struct nlmsghdr *nlh = nlmsg_hdr(msg);
826         struct nlmsgerr *errmsg = nlmsg_data(nlh);
827
828         if ((nlh->nlmsg_type == NLMSG_ERROR ||
829              nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) {
830                 /* libyaml stomps on the reader error so we need to
831                  * cache the source of the error.
832                  */
833                 data->errmsg = nl_geterror(nl_syserr2nlerr(errmsg->error));
834 #ifdef HAVE_USRSPC_NLMSGERR
835                 /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags
836                  * which gives greater detail why we failed.
837                  */
838                 if (nlh->nlmsg_flags & NLM_F_ACK_TLVS &&
839                     !(nlh->nlmsg_flags & NLM_F_CAPPED)) {
840                         struct nlattr *head = ((void *)&errmsg->msg);
841                         struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
842
843                         if (nla_parse(tb, NLMSGERR_ATTR_MAX + 1, head,
844                                       nlmsg_attrlen(nlh, 0), NULL) == 0) {
845                                 if (tb[NLMSGERR_ATTR_MSG])
846                                         data->errmsg = nla_strdup(tb[NLMSGERR_ATTR_MSG]);
847                         }
848                 }
849 #endif /* HAVE_USRSPC_NLMSGERR */
850                 data->parser->error = YAML_READER_ERROR;
851                 data->complete = true;
852
853                 return NL_STOP;
854         } else {
855                 if (data->root) {
856                         cleanup_children(data->root);
857                         free(data->root);
858                         data->root = NULL;
859                 }
860                 /* For streaming insert '...' to define end of
861                  * YAML document
862                  */
863                 if (data->async) {
864                         char *end_doc = "...\n";
865                         size_t len = strlen(end_doc) + 1;
866
867                         strncpy(data->buffer, end_doc, len);
868                         data->buffer += len - 1;
869                 } else
870                         data->complete = true;
871         }
872
873         return data->async ? NL_OK : NL_STOP;
874 }
875
876 /**
877  * In order for yaml_parser_set_input_netlink() to work we have to
878  * register a yaml_read_handler_t callback. This is that call back
879  * which listens for Netlink packets. Internally nl_recvmsg_report()
880  * calls the various callbacks discussed above.
881  */
882 static int yaml_netlink_read_handler(void *arg, unsigned char *buffer,
883                                      size_t size, size_t *size_read)
884 {
885         struct yaml_netlink_input *data = arg;
886         struct nl_sock *nl = data->nl;
887         struct nl_cb *cb;
888         int rc = 0;
889
890         if (data->complete) {
891                 *size_read = 0;
892                 return 1;
893         }
894
895         data->buffer = buffer;
896
897         cb = nl_socket_get_cb(nl);
898         rc = nl_recvmsgs_report(nl, cb);
899         if (rc == -NLE_INTR) {
900                 *size_read = 0;
901                 return 1;
902         } else if (rc < 0) {
903                 data->errmsg = nl_geterror(rc);
904                 return 0;
905         } else if (data->parser->error) {
906                 /* data->errmsg is set in NL_CB_FINISH */
907                 return 0;
908         }
909
910         rc = (unsigned char *)data->buffer - buffer;
911         if ((int)size > rc)
912                 size = rc;
913
914         *size_read = size;
915         return 1;
916 }
917
918 /* libyaml by default just reports "input error" for parser read_handler_t
919  * issues which is not useful. This provides away to get better debugging
920  * info.
921  */
922 YAML_DECLARE(const char *)
923 yaml_parser_get_reader_error(yaml_parser_t *parser)
924 {
925         struct yaml_netlink_input *buf = parser->read_handler_data;
926
927         if (!buf)
928                 return NULL;
929
930         return buf->errmsg;
931 }
932
933 /* yaml_parser_set_input_netlink() mirrors the libyaml function
934  * yaml_parser_set_input_file(). Internally it does setup of the
935  * libnl socket callbacks to parse the Netlink messages received
936  * as well as register the special yaml_read_handler_t for libyaml.
937  * This is exposed for public use.
938  */
939 YAML_DECLARE(int)
940 yaml_parser_set_input_netlink(yaml_parser_t *reply, struct nl_sock *nl,
941                               bool stream)
942 {
943         struct yaml_netlink_input *buf;
944         int rc;
945
946         buf = calloc(1, sizeof(*buf));
947         if (!buf) {
948                 reply->error = YAML_MEMORY_ERROR;
949                 return false;
950         }
951
952         rc = lustre_netlink_register(nl, stream);
953         if (rc < 0) {
954                 yaml_parser_set_reader_error(reply,
955                                              "netlink setup failed", 0,
956                                              -rc);
957                 goto failed;
958         }
959
960         buf->nl = nl;
961         buf->async = stream;
962         buf->parser = reply;
963         yaml_parser_set_input(buf->parser, yaml_netlink_read_handler, buf);
964
965         rc = nl_socket_modify_cb(buf->nl, NL_CB_VALID, NL_CB_CUSTOM,
966                                  yaml_netlink_msg_parse, buf);
967         if (rc < 0) {
968                 yaml_parser_set_reader_error(reply,
969                                              "netlink msg recv setup failed",
970                                              0, -rc);
971                 goto failed;
972         }
973
974         rc = nl_socket_modify_cb(buf->nl, NL_CB_FINISH, NL_CB_CUSTOM,
975                                  yaml_netlink_msg_complete, buf);
976         if (rc < 0) {
977                 yaml_parser_set_reader_error(reply,
978                                              "netlink msg cleanup setup failed",
979                                              0, -rc);
980 failed:
981                 free(buf);
982         }
983         return rc < 0 ? false : true;
984 }
985
986 /* The role of the YAML emitter for us is to take a YAML document and
987  * change into a Netlink stream to send to the kernel to be processed.
988  * This provides the infrastructure to do this.
989  */
990 struct yaml_netlink_output {
991         yaml_emitter_t          *emitter;
992         struct nl_sock          *nl;
993         char                    *family;
994         int                     family_id;
995         int                     version;
996         int                     cmd;
997         int                     pid;
998         int                     flags;
999 };
1000
1001 /* Internal use for this file only. We fill in details of why creating
1002  * a Netlink packet to send failed. The end user will be able to debug
1003  * what went wrong.
1004  */
1005 static int
1006 yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem)
1007 {
1008         emitter->error = YAML_WRITER_ERROR;
1009         emitter->problem = problem;
1010
1011         return 0;
1012 }
1013
1014 static unsigned int indent_level(const char *str)
1015 {
1016         char *tmp = (char *)str;
1017
1018         while (isspace(*tmp))
1019                 ++tmp;
1020         return tmp - str;
1021 }
1022
1023 #define LNKF_END 8
1024
1025 static enum lnet_nl_key_format yaml_format_type(yaml_emitter_t *emitter,
1026                                                 char *line,
1027                                                 unsigned int *offset,
1028                                                 enum lnet_nl_key_format prev)
1029 {
1030         enum lnet_nl_key_format fmt = 0;
1031         unsigned int indent = *offset;
1032         unsigned int new_indent = 0;
1033
1034         if (strchr(line, '{') || strchr(line, '[')) {
1035                 fmt = LNKF_FLOW;
1036                 if (strchr(line, '{'))
1037                         fmt |= LNKF_MAPPING;
1038                 return fmt;
1039         }
1040
1041         new_indent = indent_level(line);
1042         if (new_indent < indent) {
1043                 *offset = indent - emitter->best_indent;
1044                 return LNKF_END;
1045         }
1046
1047         if (strncmp(line + new_indent, "- ", 2) == 0) {
1048                 *offset = new_indent + emitter->best_indent;
1049                 fmt = LNKF_SEQUENCE;
1050
1051                 if (strstr(line + new_indent, ": "))
1052                         fmt |= LNKF_MAPPING;
1053                 return fmt;
1054         }
1055
1056         if (indent != new_indent) {
1057                 *offset = new_indent;
1058                 if (prev != LNKF_MAPPING)
1059                         return LNKF_MAPPING;
1060         }
1061
1062         return fmt;
1063 }
1064
1065 static int yaml_fill_scalar_data(struct nl_msg *msg,
1066                                  enum lnet_nl_key_format fmt,
1067                                  char *line)
1068 {
1069         char *sep = strchr(line, ':');
1070         int rc = 0;
1071
1072         if (sep)
1073                 *sep++ = '\0';
1074
1075         NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, line);
1076         if (fmt & LNKF_MAPPING && sep) {
1077                 while (isspace(*sep))
1078                         ++sep;
1079
1080                 if (strspn(sep, "0123456789") == strlen(sep)) {
1081                         unsigned long num = strtoull(sep, NULL, 0);
1082
1083                         NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, num);
1084                 } else {
1085                         NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, sep);
1086                 }
1087         }
1088 nla_put_failure:
1089         return rc;
1090 }
1091
1092 static int yaml_create_nested_list(struct yaml_netlink_output *out,
1093                                    struct nl_msg *msg, char **hdr,
1094                                    char **entry, unsigned int *indent,
1095                                    enum lnet_nl_key_format fmt)
1096 {
1097         struct nlattr *list = NULL;
1098         char *line;
1099         int rc = 0;
1100
1101         list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
1102         if (!list) {
1103                 yaml_emitter_set_writer_error(out->emitter,
1104                                               "Emmitter netlink list creation failed");
1105                 rc = -EINVAL;
1106                 goto nla_put_failure;
1107         }
1108
1109         if (fmt & LNKF_FLOW) {
1110                 char *tmp = NULL;
1111
1112                 tmp = strchr(*hdr, '{');
1113                 if (!tmp) {
1114                         tmp = strchr(*hdr, '[');
1115                         if (!tmp) {
1116                                 yaml_emitter_set_writer_error(out->emitter,
1117                                                               "Emmitter flow format invalid");
1118                                 rc = -EINVAL;
1119                                 goto nla_put_failure;
1120                         }
1121                 }
1122                 *tmp = ' ';
1123
1124                 tmp = strchr(*hdr, '}');
1125                 if (!tmp) {
1126                         tmp = strchr(*hdr, ']');
1127                         if (!tmp) {
1128                                 yaml_emitter_set_writer_error(out->emitter,
1129                                                               "Emmitter flow format invalid");
1130                                 rc = -EINVAL;
1131                                 goto nla_put_failure;
1132                         }
1133                 }
1134                 *tmp = '\0';
1135
1136                 while ((line = strsep(hdr, ",")) != NULL) {
1137                         if (isspace(line[0]))
1138                                 line++;
1139                         rc = yaml_fill_scalar_data(msg, fmt, line);
1140                         if (rc < 0)
1141                                 goto nla_put_failure;
1142                 }
1143                 nla_nest_end(msg, list);
1144                 return 0;
1145         }
1146
1147         rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent);
1148         if (rc < 0)
1149                 goto nla_put_failure;
1150         do {
1151                 line = strsep(entry, "\n");
1152 have_next_line:
1153                 if (!line || !strlen(line) || strcmp(line, "...") == 0)
1154                         break;
1155
1156                 fmt = yaml_format_type(out->emitter, line, indent, fmt);
1157                 if (fmt == LNKF_END)
1158                         break;
1159
1160                 if (fmt & ~LNKF_MAPPING) { /* Filter out mappings */
1161                         rc = yaml_create_nested_list(out, msg, &line, entry,
1162                                                      indent, fmt);
1163                         if (rc)
1164                                 goto nla_put_failure;
1165
1166                         goto have_next_line;
1167                 } else {
1168                         rc = yaml_fill_scalar_data(msg, fmt, line + *indent);
1169                         if (rc)
1170                                 goto nla_put_failure;
1171                 }
1172         } while (strcmp(line, ""));
1173
1174         nla_nest_end(msg, list);
1175         /* strsep in the above loop moves entry to a value pass the end of the
1176          * nested list. So to avoid losing this value we replace hdr with line
1177          */
1178         *hdr = line;
1179 nla_put_failure:
1180         return rc;
1181 }
1182
1183 /* YAML allows ' and " in its documents but those characters really
1184  * confuse libc string handling. The workaround is to replace
1185  * ' and " with another reserved character for YAML '%' which is
1186  * for tags which shouldn't matter if we send in a Netlink packet.
1187  * The kernel side will need to handle % in a special way.
1188  */
1189 static void yaml_quotation_handling(char *buf)
1190 {
1191         char *tmp = buf, *line;
1192
1193         line = strstr(tmp, "! \'");
1194         if (line)
1195                 line[0] = ' ';
1196
1197         while ((line = strchr(tmp, '\"')) != NULL) {
1198                 line[0] = ' ';
1199                 tmp = strchr(line, '\"');
1200                 tmp[0] = ' ';
1201         }
1202
1203         while ((line = strchr(tmp, '\'')) != NULL) {
1204                 line[0] = ' ';
1205                 tmp = strchr(line, '\'');
1206                 tmp[0] = ' ';
1207         }
1208 }
1209
1210 /* libyaml takes the YAML documents and places the data into an
1211  * internal buffer to the library. We take each line and turn it
1212  * into a Netlink message using the same format as the key table.
1213  * The reason for this approach is that we can do filters at the
1214  * key level or the key + value level.
1215  */
1216 static int yaml_netlink_write_handler(void *data, unsigned char *buffer,
1217                                       size_t size)
1218 {
1219         struct yaml_netlink_output *out = data;
1220         char *buf = strndup((char *)buffer, size);
1221         char *entry = buf, *tmp = buf, *line;
1222         enum lnet_nl_key_format fmt = 0;
1223         struct nl_msg *msg = NULL;
1224         unsigned int indent = 0;
1225         bool nogroups = true;
1226         int rc = 0;
1227
1228         yaml_quotation_handling(entry);
1229
1230         while (entry && strcmp(line = strsep(&entry, "\n"), "")) {
1231 already_have_line:
1232                 if (strcmp(line, "---") == 0 || strcmp(line, "...") == 0)
1233                         continue;
1234
1235                 /* In theory we could have a sequence of groups but a bug in
1236                  * libyaml prevents this from happing
1237                  */
1238                 if (line[0] != ' ' && line[0] != '-') {
1239                         tmp = strchr(line, ':');
1240                         if (!tmp)
1241                                 continue;
1242                         *tmp = '\0';
1243
1244                         rc = lustre_netlink_add_group(out->nl, out->family,
1245                                                       line);
1246                         if (rc < 0) {
1247                                 yaml_emitter_set_writer_error(out->emitter,
1248                                                               "Netlink group does not exist");
1249                                 goto nla_put_failure;
1250                         }
1251                         nogroups = false;
1252
1253                         /* Handle case first line contains more than a
1254                          * simple key
1255                          */
1256                         line = tmp + 2;
1257                         if (strchr(line, '{') || strchr(line, '['))
1258                                 goto complicated;
1259                 } else {
1260 complicated:
1261                         if (!msg) {
1262                                 void *usr_hdr;
1263
1264                                 msg = nlmsg_alloc();
1265                                 if (!msg) {
1266                                         out->emitter->error = YAML_MEMORY_ERROR;
1267                                         goto nla_put_failure;
1268                                 }
1269
1270                                 usr_hdr = genlmsg_put(msg, out->pid,
1271                                                       NL_AUTO_SEQ,
1272                                                       out->family_id, 0,
1273                                                       out->flags, out->cmd,
1274                                                       out->version);
1275                                 if (!usr_hdr) {
1276                                         out->emitter->error = YAML_MEMORY_ERROR;
1277                                         nlmsg_free(msg);
1278                                         goto nla_put_failure;
1279                                 }
1280                         }
1281
1282                         fmt = yaml_format_type(out->emitter, line, &indent,
1283                                                fmt);
1284                         if (fmt & ~LNKF_MAPPING) {
1285                                 rc = yaml_create_nested_list(out, msg, &line,
1286                                                              &entry, &indent,
1287                                                              fmt);
1288                                 if (rc < 0) {
1289                                         yaml_emitter_set_writer_error(out->emitter,
1290                                                                       nl_geterror(rc));
1291                                         nlmsg_free(msg);
1292                                         goto nla_put_failure;
1293                                 }
1294                                 /* yaml_created_nested_list set line to the next
1295                                  * entry. We can just add it to the msg directly.
1296                                  */
1297                                 if (line)
1298                                         goto already_have_line;
1299                         } else {
1300                                 rc = yaml_fill_scalar_data(msg, fmt,
1301                                                            line + indent);
1302                                 if (rc < 0) {
1303                                         yaml_emitter_set_writer_error(out->emitter,
1304                                                                       nl_geterror(rc));
1305                                         nlmsg_free(msg);
1306                                         goto nla_put_failure;
1307                                 }
1308                         }
1309                 }
1310         }
1311
1312         /* Don't success if no valid groups found */
1313         if (nogroups) {
1314                 yaml_emitter_set_writer_error(out->emitter,
1315                                               "Emitter contains no valid Netlink groups");
1316                 goto nla_put_failure;
1317         }
1318
1319         if (msg) {
1320                 rc = nl_send_auto(out->nl, msg);
1321                 nlmsg_free(msg);
1322         } else {
1323                 rc = genl_send_simple(out->nl, out->family_id, out->cmd,
1324                                       out->version, out->flags);
1325         }
1326         if (rc < 0)
1327                 yaml_emitter_set_writer_error(out->emitter,
1328                                               nl_geterror(rc));
1329 nla_put_failure:
1330         free(buf);
1331         return out->emitter->error == YAML_NO_ERROR ? 1 : 0;
1332 }
1333
1334 /* This is the libnl callback for when an error has happened
1335  * kernel side. An error message is sent back to the user.
1336  */
1337 static int yaml_netlink_write_error(struct sockaddr_nl *who,
1338                                     struct nlmsgerr *errmsg, void *arg)
1339 {
1340         struct yaml_netlink_output *data = arg;
1341         struct nlmsghdr *nlh = &errmsg->msg;
1342
1343         if ((nlh->nlmsg_type == NLMSG_ERROR ||
1344              nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) {
1345                 const char *errstr = nl_geterror(nl_syserr2nlerr(errmsg->error));
1346
1347 #ifdef HAVE_USRSPC_NLMSGERR
1348                 /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags
1349                  * which gives greater detail why we failed.
1350                  */
1351                 if (nlh->nlmsg_flags & NLM_F_ACK_TLVS &&
1352                     !(nlh->nlmsg_flags & NLM_F_CAPPED)) {
1353                         struct nlattr *head = ((void *)&errmsg->msg);
1354                         struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
1355
1356                         if (nla_parse(tb, NLMSGERR_ATTR_MAX + 1, head,
1357                                       nlmsg_attrlen(nlh, 0), NULL) == 0) {
1358                                 if (tb[NLMSGERR_ATTR_MSG])
1359                                         errstr = nla_strdup(tb[NLMSGERR_ATTR_MSG]);
1360                         }
1361                 }
1362 #endif /* HAVE_USRSPC_NLMSGERR */
1363                 yaml_emitter_set_writer_error(data->emitter, errstr);
1364         }
1365         return NL_STOP;
1366 }
1367
1368 /* This function is used by external utilities to use Netlink with
1369  * libyaml so we can turn YAML documentations into Netlink message
1370  * to send. This behavior mirrors yaml_emitter_set_output_file()
1371  * which is used to write out a YAML document to a file.
1372  */
1373 YAML_DECLARE(int)
1374 yaml_emitter_set_output_netlink(yaml_emitter_t *sender, struct nl_sock *nl,
1375                                 char *family, int version, int cmd, int flags)
1376 {
1377         struct yaml_netlink_output *out;
1378         int rc;
1379
1380         out = calloc(1, sizeof(*out));
1381         if (!out) {
1382                 sender->error = YAML_MEMORY_ERROR;
1383                 return false;
1384         }
1385
1386         /* Get family ID */
1387         out->family_id = genl_ctrl_resolve(nl, family);
1388         if (out->family_id < 0) {
1389                 yaml_emitter_set_writer_error(sender,
1390                                               "failed to resolve Netlink family id");
1391                 free(out);
1392                 return false;
1393         }
1394
1395         rc = nl_socket_modify_err_cb(nl, NL_CB_CUSTOM,
1396                                      yaml_netlink_write_error, out);
1397         if (rc < 0) {
1398                 yaml_emitter_set_writer_error(sender,
1399                                               "failed to register error handling");
1400                 free(out);
1401                 return false;
1402         }
1403
1404         rc = nl_socket_enable_broadcast_error(nl);
1405         if (rc < 0) {
1406                 yaml_emitter_set_writer_error(sender,
1407                                               "failed to enable broadcast errors");
1408                 free(out);
1409                 return false;
1410         }
1411
1412         rc = nl_socket_set_ext_ack(nl, true);
1413         if (rc < 0) {
1414                 yaml_emitter_set_writer_error(sender,
1415                                               "failed to enable ext ack");
1416                 free(out);
1417                 return false;
1418         }
1419
1420         out->emitter = sender;
1421         out->nl = nl;
1422         out->family = family;
1423         out->version = version;
1424         out->cmd = cmd;
1425         out->flags = flags;
1426         out->pid = nl_socket_get_local_port(nl);
1427         yaml_emitter_set_output(sender, yaml_netlink_write_handler, out);
1428         return true;
1429 }
1430
1431 /* Error handling helpers */
1432 void yaml_emitter_log_error(yaml_emitter_t *emitter, FILE *log)
1433 {
1434         /* YAML_WRITER_ERROR means no Netlink support so use old API */
1435         switch (emitter->error) {
1436         case YAML_MEMORY_ERROR:
1437                 fprintf(log, "Memory error: Not enough memory for emitting\n");
1438                         break;
1439         case YAML_WRITER_ERROR:
1440                 fprintf(log, "Writer error: %s\n", emitter->problem);
1441                 break;
1442         case YAML_EMITTER_ERROR:
1443                 fprintf(log, "Emitter error: %s\n", emitter->problem);
1444         default:
1445                 break;
1446         }
1447 }
1448
1449 void yaml_parser_log_error(yaml_parser_t *parser, FILE *log, const char *errmsg)
1450 {
1451         const char *extra;
1452
1453         switch (parser->error) {
1454         case YAML_MEMORY_ERROR:
1455                 fprintf(log, "Memory error: Not enough memory for parser\n");
1456                 break;
1457
1458         case YAML_SCANNER_ERROR:
1459         case YAML_PARSER_ERROR:
1460                 if (parser->context) {
1461                         fprintf(log,
1462                                 "%s error: %s at line %d, column %d\n%s at line %d, column %d\n",
1463                                 parser->error == YAML_SCANNER_ERROR ? "Scanner" : "Parser",
1464                                 parser->context,
1465                                 (int)parser->context_mark.line + 1,
1466                                 (int)parser->context_mark.column + 1,
1467                                 parser->problem,
1468                                 (int)parser->problem_mark.line + 1,
1469                                 (int)parser->problem_mark.column + 1);
1470                 } else {
1471                         fprintf(log, "%s error: %s at line %d, column %d\n",
1472                                 parser->error == YAML_SCANNER_ERROR ? "Scanner" : "Parser",
1473                                 parser->problem,
1474                                 (int)parser->problem_mark.line + 1,
1475                                 (int)parser->problem_mark.column + 1);
1476                 }
1477                 break;
1478
1479         case YAML_READER_ERROR:
1480                 extra = yaml_parser_get_reader_error(parser);
1481                 if (!extra)
1482                         extra = parser->problem;
1483
1484                 if (parser->problem_value != -1) {
1485                         fprintf(log, "Reader error: '%s':#%X at %ld'\n",
1486                                 extra, parser->problem_value,
1487                                 (long)parser->problem_offset);
1488                 } else {
1489                         fprintf(log, "Reader error: '%s' at %ld\n",
1490                                 extra, (long)parser->problem_offset);
1491                 }
1492                 fallthrough;
1493         default:
1494                 break;
1495         }
1496 }