4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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
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.
22 * Copyright (c) 2021 UT-Battelle, LLC
24 * Author: James Simmons <jsimmons@infradead.org>
32 #include <linux/lnet/lnet-nl.h>
33 #include "liblnetconfig.h"
35 #ifndef SOL_NETLINK /* for glibc < 2.24 */
36 # define SOL_NETLINK 270
39 #ifndef NETLINK_EXT_ACK
40 #define NETLINK_EXT_ACK 11
43 #ifndef NLM_F_ACK_TLVS
44 #define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
47 #ifndef NLA_NUL_STRING
48 # define NLA_NUL_STRING 10
55 #ifndef HAVE_NLA_GET_S32
60 * Return payload of 32 bit signed integer attribute.
62 * @arg nla 32 bit integer attribute.
64 * @return Payload as 32 bit integer.
66 int32_t nla_get_s32(const struct nlattr *nla)
68 return *(const int32_t *) nla_data(nla);
70 #endif /* ! HAVE_NLA_GET_S32 */
72 #ifndef HAVE_NLA_GET_S64
77 * Return payload of s64 attribute
79 * @arg nla s64 netlink attribute
81 * @return Payload as 64 bit integer.
83 int64_t nla_get_s64(const struct nlattr *nla)
87 if (nla && nla_len(nla) >= sizeof(tmp))
88 memcpy(&tmp, nla_data(nla), sizeof(tmp));
92 #endif /* ! HAVE_NLA_GET_S64 */
95 * Set NETLINK_BROADCAST_ERROR flags on socket to report ENOBUFS errors.
97 * @sk Socket to change the flags.
99 * Return 0 on success or a Netlink error code.
101 int nl_socket_enable_broadcast_error(struct nl_sock *sk)
103 const int state = 1; /* enable errors */
106 if (nl_socket_get_fd(sk) < 0)
107 return -NLE_BAD_SOCK;
109 err = setsockopt(nl_socket_get_fd(sk), SOL_NETLINK,
110 NETLINK_BROADCAST_ERROR, &state, sizeof(state));
112 return -nl_syserr2nlerr(errno);
118 * Enable/disable extending ACK for netlink socket. Used for
119 * sending extra debugging information.
121 * @arg sk Netlink socket.
122 * @arg state New state (0 - disabled, 1 - enabled)
124 * @return 0 on success or a negative error code
126 int nl_socket_set_ext_ack(struct nl_sock *sk, int state)
130 if (nl_socket_get_fd(sk) < 0)
131 return -NLE_BAD_SOCK;
133 err = setsockopt(nl_socket_get_fd(sk), SOL_NETLINK,
134 NETLINK_EXT_ACK, &state, sizeof(state));
135 if (err < 0 && errno != ENOPROTOOPT)
136 return -nl_syserr2nlerr(errno);
142 * Create a Netlink socket
144 * @sk The nl_sock which we used to handle the Netlink
146 * @async_events tell the Netlink socket this will receive asynchronous
149 * Return 0 on success or a negative error code.
151 int lustre_netlink_register(struct nl_sock *sk, bool async_events)
155 rc = genl_connect(sk);
159 rc = nl_socket_enable_broadcast_error(sk);
163 rc = nl_socket_set_ext_ack(sk, true);
168 /* Required to receive async netlink event notifications */
169 nl_socket_disable_seq_check(sk);
170 /* Don't need ACK for events generated by kernel */
171 nl_socket_disable_auto_ack(sk);
178 * Filter Netlink socket by groups
181 * @family The family name of the Netlink socket.
182 * @group Netlink messages will only been sent if they belong to this
185 * Return 0 on success or a negative error code.
187 int lustre_netlink_add_group(struct nl_sock *nl, const char *family,
193 group_id = genl_ctrl_resolve_grp(nl, family, group);
197 /* subscribe to generic netlink multicast group */
198 return nl_socket_add_membership(nl, group_id);
201 /* A YAML file is used to describe data. In a YAML document the content is
202 * all about a collection of scalars used to create new data types such as
203 * key-value pairs. This allows complex documents to represent anything from
204 * a string to a tree.
208 * YAML scalars are a simple value which can be a string, number or Boolean.
209 * They are the simplest data types. They can exist in a YAML document but
210 * are typically used to build more complex data formats.
214 * In YAML collections are scalar elements presented in the form of
215 * an array, called a sequence, or mappings (hashes) that are scalar
216 * key value pairs. All elements belonging to the same collection are
217 * the lines that begin at the same indentation level
219 * Sequences use a dash followed by a space.
220 * Mappings use a colon followed by a space (: ) to mark each key/value pair:
222 * Collections can be represented in two forms, flow and block.
223 * Note they are equivalent. Example of block sequence is;
229 * and a block mapping example is:
235 * YAML flow styles for collections uses explicit indicators rather than
236 * indentation to denote scope.
238 * A sequence can be written as a comma separated list within
239 * square brackets ([]):
241 * [ PHP, Perl, Python ]
243 * A mapping can be written as a comma separated list of key/values within
246 * { PHP: 5.2, MySQL: 5.1, Apache: 2.2.20 }
248 * NOTE!! flow and block are equivalent.
252 * A list is a defined array of data which can be either an flow or block
253 * sequence. Lists can be nested. Example
255 * numbers: [ 1, 2, 3, 4 ]
265 * Are comprised of a key: value format with contents indented. This is
266 * built on top of the flow or block mapping. Like lists they can be nested.
274 /* In YAML you have the concept of parsers and emitters. Parser
275 * consume YAML input from a file, character buffer, or in our
276 * case Netlink and emitters take data from some source and
277 * present it in a YAML format.
279 * In this section of the code we are handling the parsing of the
280 * Netlink packets coming in and using them to piece together a
281 * YAML document. We could in theory just dump a YAML document
282 * one line at a time over Netlink but the amount of data could
283 * become very large and impact performance. Additionally, having
284 * pseudo-YAML code in the kernel would be frowned on. We can
285 * optimize the network traffic by taking advantage of the fact
286 * that for key/value pairs the keys rarely change. We can
287 * break up the data into keys and the values. The first Netlink
288 * data packets received will be a nested keys table which we
289 * can cache locally. As we receive the value pairs we can then
290 * reconstruct the key : value pair by looking up the the key
291 * in the stored table. In effect we end up with a one key to
292 * many values stream of data.
294 * The data structures below are used to create a tree data
295 * structure which is the natural flow of both YAML and
298 struct yaml_nl_node {
299 struct nl_list_head list;
300 struct nl_list_head children;
301 struct ln_key_list keys;
304 struct yaml_netlink_input {
305 yaml_parser_t *parser;
311 struct yaml_nl_node *cur;
312 struct yaml_nl_node *root;
315 /* Sadly this is not exported out of libyaml. We want to
316 * give descent error message to help people track down
317 * issues. This is internal only to this code. The end
318 * user will never need to use this.
321 yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
322 size_t offset, int value)
324 parser->error = YAML_READER_ERROR;
325 parser->problem = problem;
326 parser->problem_offset = offset;
327 parser->problem_value = value;
332 /* This is used to handle all the Netlink packets containing the keys
333 * for the key/value pairs. Instead of creating unique code to handle
334 * every type of Netlink attributes possible we create a generic
335 * abstract so the same code be used with everything. To make this
336 * work the key table trasmitted must report the tree structure and
337 * state of the keys. We use nested attributes as a way to notify libyaml
338 * we have a new collection. This is used to create the tree structure
339 * of the YAML document. Each collection of attributes define the following:
341 * LN_SCALAR_ATTR_INDEX:
342 * enum XXX_ATTR that defines which value we are dealing with. This
343 * varies greatly depending on the subsystem we have developed for.
345 * LN_SCALAR_ATTR_NLA_TYPE:
346 * The Netlink attribute type (NLA_STRING, NLA_U32, etc..) the coming
349 * LN_SCALAR_ATTR_VALUE:
350 * The key's actually scalar value.
352 * LN_SCALAR_ATTR_KEY_TYPE:
353 * What YAML format is it? block or flow. Only useful for
354 * LN_SCALAR_ATTR_NLA_TYPE of type NLA_NESTED or NLA_NUL_STRING
356 * LN_SCALAR_ATTR_LIST + CFS_SCALAR_LIST_SIZE:
357 * Defined the next collection which is a collection of nested
358 * attributes of the above.
360 static struct nla_policy scalar_attr_policy[LN_SCALAR_CNT + 1] = {
361 [LN_SCALAR_ATTR_LIST] = { .type = NLA_NESTED },
362 [LN_SCALAR_ATTR_LIST_SIZE] = { .type = NLA_U16 },
363 [LN_SCALAR_ATTR_INDEX] = { .type = NLA_U16 },
364 [LN_SCALAR_ATTR_NLA_TYPE] = { .type = NLA_U16 },
365 [LN_SCALAR_ATTR_VALUE] = { .type = NLA_STRING },
366 [LN_SCALAR_ATTR_KEY_FORMAT] = { .type = NLA_U16 },
369 static int yaml_parse_key_list(struct yaml_netlink_input *data,
370 struct yaml_nl_node *parent,
373 struct nlattr *tbl_info[LN_SCALAR_CNT + 1];
374 struct yaml_nl_node *node = NULL;
378 nla_for_each_nested(attr, list, rem) {
381 if (nla_parse_nested(tbl_info, LN_SCALAR_CNT, attr,
385 if (tbl_info[LN_SCALAR_ATTR_LIST_SIZE]) {
388 cnt = nla_get_u16(tbl_info[LN_SCALAR_ATTR_LIST_SIZE]) + 1;
390 size_t len = sizeof(struct nl_list_head) * 2;
392 len += sizeof(struct ln_key_props) * cnt;
393 node = calloc(1, len);
397 node->keys.lkl_maxattr = cnt;
398 NL_INIT_LIST_HEAD(&node->children);
399 nl_init_list_head(&node->list);
406 nl_list_add_tail(&node->list,
411 if (tbl_info[LN_SCALAR_ATTR_INDEX])
412 index = nla_get_u16(tbl_info[LN_SCALAR_ATTR_INDEX]);
414 if (!node || index == 0)
417 if (tbl_info[LN_SCALAR_ATTR_KEY_FORMAT]) {
420 format = nla_get_u16(tbl_info[LN_SCALAR_ATTR_KEY_FORMAT]);
421 node->keys.lkl_list[index].lkp_key_format = format;
424 if (tbl_info[LN_SCALAR_ATTR_NLA_TYPE]) {
427 type = nla_get_u16(tbl_info[LN_SCALAR_ATTR_NLA_TYPE]);
428 node->keys.lkl_list[index].lkp_data_type = type;
431 if (tbl_info[LN_SCALAR_ATTR_VALUE]) {
434 name = nla_strdup(tbl_info[LN_SCALAR_ATTR_VALUE]);
437 node->keys.lkl_list[index].lkp_values = name;
440 if (tbl_info[LN_SCALAR_ATTR_LIST]) {
441 int rc = yaml_parse_key_list(data, node,
442 tbl_info[LN_SCALAR_ATTR_LIST]);
450 static struct yaml_nl_node *get_next_child(struct yaml_nl_node *node,
453 struct yaml_nl_node *child;
456 nl_list_for_each_entry(child, &node->children, list)
464 * In the YAML C implementation the scanner transforms the input stream
465 * (Netlink in this case) into a sequence of keys. First we need to
466 * examine the potential keys involved to see the mapping to Netlink.
467 * We have chosen to examine the YAML stack with keys since they are
468 * more detailed when compared to yaml_document_t / yaml_nodes and
471 * STREAM-START(encoding) # The stream start.
472 * STREAM-END # The stream end.
473 * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
474 * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
475 * DOCUMENT-START # '---'
476 * DOCUMENT-END # '...'
477 * BLOCK-SEQUENCE-START # Indentation increase denoting a block
478 * BLOCK-MAPPING-START # sequence or a block mapping.
479 * BLOCK-END # Indentation decrease.
480 * FLOW-SEQUENCE-START # '['
481 * FLOW-SEQUENCE-END # ']'
482 * FLOW-MAPPING-START # '{'
483 * FLOW-MAPPING-END # '}'
486 * KEY # '?' or nothing (simple keys).
488 * ALIAS(anchor) # '*anchor'
489 * ANCHOR(anchor) # '&anchor'
490 * TAG(handle,suffix) # '!handle!suffix'
491 * SCALAR(value,style) # A scalar.
493 * For our read_handler / write_handler STREAM-START / STREAM-END,
494 * VERSION-DIRECTIVE, and TAG-DIRECTIVE are hanndler by the libyaml
495 * internal scanner so we don't need to deal with it. Normally for
496 * LNet / Lustre DOCUMENT-START / DOCUMENT-END are not needed but it
497 * could be easily handled. In the case of multiplex streams we could
498 * see these used to differentiate data coming in.
500 * It is here we handle any simple scalars or values of the key /value
501 * pair. How the YAML document is formated is dependent on the key
504 static void yaml_parse_value_list(struct yaml_netlink_input *data, int *size,
505 struct nlattr *attr_array[],
506 struct ln_key_props *parent)
508 struct yaml_nl_node *node = data->cur;
509 struct ln_key_props *keys = node->keys.lkl_list;
510 int mapping = parent->lkp_key_format;
511 int child_idx = 0, len = 0, i;
513 for (i = 1; i < node->keys.lkl_maxattr; i++) {
516 attr = attr_array[i];
517 if (!attr && !keys[i].lkp_values)
520 if (keys[i].lkp_data_type != NLA_NUL_STRING &&
521 keys[i].lkp_data_type != NLA_NESTED) {
525 if (!(mapping & LNKF_FLOW)) {
526 unsigned int indent = data->indent ?
529 memset(data->buffer, ' ', indent);
530 if (mapping & LNKF_SEQUENCE) {
531 ((char *)data->buffer)[indent - 2] = '-';
532 if (mapping & LNKF_MAPPING)
533 mapping &= ~LNKF_SEQUENCE;
535 data->buffer += indent;
539 if (mapping & LNKF_MAPPING) {
540 len = snprintf(data->buffer, *size, "%s: ",
549 switch (keys[i].lkp_data_type) {
551 struct yaml_nl_node *next = get_next_child(node,
553 int num = next->keys.lkl_maxattr;
554 struct nla_policy nest_policy[num];
555 struct yaml_nl_node *old;
556 struct nlattr *cnt_attr;
562 memset(nest_policy, 0, sizeof(struct nla_policy) * num);
563 for (j = 1; j < num; j++)
564 nest_policy[j].type = next->keys.lkl_list[j].lkp_data_type;
568 nla_for_each_nested(cnt_attr, attr, rem) {
569 struct nlattr *nest_info[num];
572 if (nla_parse_nested(nest_info, num, cnt_attr,
576 if (keys[i].lkp_key_format & LNKF_FLOW) {
579 if (keys[i].lkp_key_format &
583 len = snprintf(data->buffer, *size,
589 if (keys[i].lkp_key_format &
592 if (keys[i].lkp_key_format &
596 len = snprintf(data->buffer, *size,
607 data->indent += indent;
608 yaml_parse_value_list(data, size, nest_info,
610 data->indent -= indent;
612 if (keys[i].lkp_key_format & LNKF_FLOW) {
613 char *tmp = (char *)data->buffer - 2;
614 char *brace = " }\n";
616 if (keys[i].lkp_key_format &
620 memcpy(tmp, brace, strlen(brace));
631 if (data->cur != data->root)
634 /* The top level is special so only print
637 if (strlen(keys[i].lkp_values)) {
638 len = snprintf(data->buffer,
648 if (!(mapping & LNKF_FLOW)) {
649 if (mapping & LNKF_SEQUENCE)
651 else if (mapping & LNKF_MAPPING)
655 if (attr && parent->lkp_values) {
656 free(parent->lkp_values);
657 parent->lkp_values = nla_strdup(attr);
663 len = snprintf(data->buffer, *size, "%s",
664 nla_get_string(attr));
668 len = snprintf(data->buffer, *size, "%hu",
673 len = snprintf(data->buffer, *size, "%u",
678 len = snprintf(data->buffer, *size, "%ju",
683 len = snprintf(data->buffer, *size, "%hd",
688 len = snprintf(data->buffer, *size, "%d",
693 len = snprintf(data->buffer, *size, "%jd",
701 if (mapping & LNKF_FLOW) {
702 strcat((char *)data->buffer, ", ");
705 ((char *)data->buffer)[len++] = '\n';
709 } else if (len < 0) {
711 data->buffer -= data->indent + 2;
712 *size -= data->indent + 2;
717 /* This is the CB_VALID callback for the Netlink library that we
718 * have hooked into. Any successful Netlink message is passed to
719 * this function which handles both the incoming key tables and
720 * the values of the key/value pairs being received. We use
721 * the NLM_F_CREATE flag to determine if the incoming Netlink
722 * message is a key table or a packet containing value pairs.
724 static int yaml_netlink_msg_parse(struct nl_msg *msg, void *arg)
726 struct yaml_netlink_input *data = arg;
727 struct nlmsghdr *nlh = nlmsg_hdr(msg);
729 if (nlh->nlmsg_flags & NLM_F_CREATE) {
730 struct nlattr *attrs[LN_SCALAR_CNT + 1];
732 if (genlmsg_parse(nlh, 0, attrs, LN_SCALAR_CNT + 1,
736 if (attrs[LN_SCALAR_ATTR_LIST]) {
737 int rc = yaml_parse_key_list(data, NULL,
738 attrs[LN_SCALAR_ATTR_LIST]);
742 /* reset to root node */
743 data->cur = data->root;
746 uint16_t maxtype = data->cur->keys.lkl_maxattr;
747 struct nla_policy policy[maxtype];
748 struct nlattr *attrs[maxtype];
751 memset(policy, 0, sizeof(struct nla_policy) * maxtype);
752 for (i = 1; i < maxtype; i++)
753 policy[i].type = data->cur->keys.lkl_list[i].lkp_data_type;
755 if (genlmsg_parse(nlh, 0, attrs, maxtype, policy))
758 size = data->parser->raw_buffer.end -
759 (unsigned char *)data->buffer;
760 yaml_parse_value_list(data, &size, attrs,
761 &data->cur->keys.lkl_list[1]);
764 if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_type != NLMSG_DONE)
770 static bool cleanup_children(struct yaml_nl_node *parent)
772 struct yaml_nl_node *child;
774 if (nl_list_empty(&parent->children)) {
775 struct ln_key_props *keys = parent->keys.lkl_list;
778 for (i = 1; i < parent->keys.lkl_maxattr; i++)
779 if (keys[i].lkp_values)
780 free(keys[i].lkp_values);
781 nl_list_del(&parent->list);
785 while ((child = get_next_child(parent, 0)) != NULL) {
786 if (cleanup_children(child))
793 /* This is the libnl callback for when the last Netlink packet
794 * is finished being parsed or its called right away in case
795 * the Linux kernel reports back an error from the Netlink layer.
797 static int yaml_netlink_msg_complete(struct nl_msg *msg, void *arg)
799 struct yaml_netlink_input *data = arg;
800 struct nlmsghdr *nlh = nlmsg_hdr(msg);
801 struct nlmsgerr *errmsg = nlmsg_data(nlh);
803 if ((nlh->nlmsg_type == NLMSG_ERROR ||
804 nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) {
805 /* libyaml stomps on the reader error so we need to
806 * cache the source of the error.
808 data->errmsg = nl_geterror(nl_syserr2nlerr(errmsg->error));
809 #ifdef HAVE_USRSPC_NLMSGERR
810 /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags
811 * which gives greater detail why we failed.
813 if (nlh->nlmsg_flags & NLM_F_ACK_TLVS) {
814 struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
815 [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING },
816 [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 },
818 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
820 if (nlmsg_parse(nlh, 0, tb, sizeof(extack_policy),
821 extack_policy) == 0) {
822 if (tb[NLMSGERR_ATTR_MSG])
823 data->errmsg = nla_get_string(tb[NLMSGERR_ATTR_MSG]);
826 #endif /* HAVE_USRSPC_NLMSGERR */
827 data->parser->error = YAML_READER_ERROR;
829 cleanup_children(data->root);
833 data->complete = true;
838 * In order for yaml_parser_set_input_netlink() to work we have to
839 * register a yaml_read_handler_t callback. This is that call back
840 * which listens for Netlink packets. Internally nl_recvmsg_report()
841 * calls the various callbacks discussed above.
843 static int yaml_netlink_read_handler(void *arg, unsigned char *buffer,
844 size_t size, size_t *size_read)
846 struct yaml_netlink_input *data = arg;
847 struct nl_sock *nl = data->nl;
851 if (data->complete) {
856 data->buffer = buffer;
858 cb = nl_socket_get_cb(nl);
859 rc = nl_recvmsgs_report(nl, cb);
860 if (rc == -NLE_INTR) {
864 data->errmsg = nl_geterror(rc);
866 } else if (data->parser->error) {
867 /* data->errmsg is set in NL_CB_FINISH */
871 rc = (unsigned char *)data->buffer - buffer;
879 /* libyaml by default just reports "input error" for parser read_handler_t
880 * issues which is not useful. This provides away to get better debugging
883 YAML_DECLARE(const char *)
884 yaml_parser_get_reader_error(yaml_parser_t *parser)
886 struct yaml_netlink_input *buf = parser->read_handler_data;
894 /* yaml_parser_set_input_netlink() mirrors the libyaml function
895 * yaml_parser_set_input_file(). Internally it does setup of the
896 * libnl socket callbacks to parse the Netlink messages received
897 * as well as register the special yaml_read_handler_t for libyaml.
898 * This is exposed for public use.
901 yaml_parser_set_input_netlink(yaml_parser_t *reply, struct nl_sock *nl,
904 struct yaml_netlink_input *buf;
907 buf = calloc(1, sizeof(*buf));
909 reply->error = YAML_MEMORY_ERROR;
913 rc = lustre_netlink_register(nl, stream);
915 yaml_parser_set_reader_error(reply,
916 "netlink setup failed", 0,
923 yaml_parser_set_input(buf->parser, yaml_netlink_read_handler, buf);
925 rc = nl_socket_modify_cb(buf->nl, NL_CB_VALID, NL_CB_CUSTOM,
926 yaml_netlink_msg_parse, buf);
928 yaml_parser_set_reader_error(reply,
929 "netlink msg recv setup failed",
934 rc = nl_socket_modify_cb(buf->nl, NL_CB_FINISH, NL_CB_CUSTOM,
935 yaml_netlink_msg_complete, buf);
937 yaml_parser_set_reader_error(reply,
938 "netlink msg cleanup setup failed",
943 return rc < 0 ? false : true;
946 /* The role of the YAML emitter for us is to take a YAML document and
947 * change into a Netlink stream to send to the kernel to be processed.
948 * This provides the infrastructure to do this.
950 struct yaml_netlink_output {
951 yaml_emitter_t *emitter;
961 /* Internal use for this file only. We fill in details of why creating
962 * a Netlink packet to send failed. The end user will be able to debug
966 yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem)
968 emitter->error = YAML_WRITER_ERROR;
969 emitter->problem = problem;
974 static unsigned int indent_level(const char *str)
976 char *tmp = (char *)str;
978 while (isspace(*tmp))
985 static enum lnet_nl_key_format yaml_format_type(yaml_emitter_t *emitter,
987 unsigned int *offset,
988 enum lnet_nl_key_format prev)
990 unsigned int indent = *offset;
991 unsigned int new_indent = 0;
993 if (strchr(line, '{') || strchr(line, '['))
996 new_indent = indent_level(line);
997 if (new_indent < indent) {
998 *offset = indent - emitter->best_indent;
1002 if (strncmp(line + new_indent, "- ", 2) == 0) {
1003 *offset = new_indent + emitter->best_indent;
1004 return LNKF_SEQUENCE;
1007 if (indent != new_indent) {
1008 *offset = new_indent;
1009 if (prev != LNKF_MAPPING)
1010 return LNKF_MAPPING;
1016 static int yaml_create_nested_list(struct yaml_netlink_output *out,
1017 struct nl_msg *msg, char **hdr,
1018 char **entry, unsigned int *indent,
1019 enum lnet_nl_key_format fmt)
1021 struct nlattr *list = NULL;
1025 list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
1027 yaml_emitter_set_writer_error(out->emitter,
1028 "Emmitter netlink list creation failed");
1031 goto nla_put_failure;
1034 if (fmt & LNKF_FLOW) {
1035 while ((line = strsep(hdr, ",")) != NULL) {
1038 if (strchr(line, '{') ||
1039 strchr(line, '[') ||
1043 tmp = strchr(line, '}');
1045 tmp = strchr(line, ']');
1050 LN_SCALAR_ATTR_VALUE,
1053 nla_nest_end(msg, list);
1057 NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, *hdr + *indent);
1059 line = strsep(entry, "\n");
1061 if (!line || !strlen(line) || strcmp(line, "...") == 0)
1064 fmt = yaml_format_type(out->emitter, line, indent, fmt);
1065 if (fmt == LNKF_END)
1069 rc = yaml_create_nested_list(out, msg, &line, entry,
1072 goto nla_put_failure;
1074 goto have_next_line;
1076 NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE,
1079 } while (strcmp(line, ""));
1081 nla_nest_end(msg, list);
1082 /* strsep in the above loop moves entry to a value pass the end of the
1083 * nested list. So to avoid losing this value we replace hdr with line
1090 /* YAML allows ' and " in its documents but those characters really
1091 * confuse libc string handling. The workaround is to replace
1092 * ' and " with another reserved character for YAML '%' which is
1093 * for tags which shouldn't matter if we send in a Netlink packet.
1094 * The kernel side will need to handle % in a special way.
1096 static void yaml_quotation_handling(char *buf)
1098 char *tmp = buf, *line;
1100 while ((line = strchr(tmp, '\"')) != NULL) {
1103 tmp = strchr(line, '\"') - 1;
1108 while ((line = strchr(tmp, '\'')) != NULL) {
1111 tmp = strchr(line, '\'') - 1;
1117 /* libyaml takes the YAML documents and places the data into an
1118 * internal buffer to the library. We take each line and turn it
1119 * into a Netlink message using the same format as the key table.
1120 * The reason for this approach is that we can do filters at the
1121 * key level or the key + value level.
1123 static int yaml_netlink_write_handler(void *data, unsigned char *buffer,
1126 struct yaml_netlink_output *out = data;
1127 char *buf = strndup((char *)buffer, size);
1128 char *entry = buf, *tmp = buf, *line;
1129 enum lnet_nl_key_format fmt = 0;
1130 struct nl_msg *msg = NULL;
1131 unsigned int indent = 0;
1132 bool nogroups = true;
1135 yaml_quotation_handling(entry);
1137 while (entry && strcmp(line = strsep(&entry, "\n"), "")) {
1139 if (strcmp(line, "---") == 0 || strcmp(line, "...") == 0)
1142 /* In theory we could have a sequence of groups but a bug in
1143 * libyaml prevents this from happing
1145 if (line[0] != ' ' && line[0] != '-') {
1146 tmp = strchr(line, ':');
1151 rc = lustre_netlink_add_group(out->nl, out->family,
1154 yaml_emitter_set_writer_error(out->emitter,
1155 "Netlink group does not exist");
1156 goto nla_put_failure;
1160 /* Handle case first line contains more than a
1164 if (strchr(line, '{') || strchr(line, '['))
1171 msg = nlmsg_alloc();
1173 out->emitter->error = YAML_MEMORY_ERROR;
1174 goto nla_put_failure;
1177 usr_hdr = genlmsg_put(msg, out->pid,
1180 out->flags, out->cmd,
1183 out->emitter->error = YAML_MEMORY_ERROR;
1185 goto nla_put_failure;
1189 fmt = yaml_format_type(out->emitter, line, &indent,
1192 rc = yaml_create_nested_list(out, msg, &line,
1196 yaml_emitter_set_writer_error(out->emitter,
1199 goto nla_put_failure;
1201 /* yaml_created_nested_list set line to the next
1202 * entry. We can just add it to the msg directly.
1205 goto already_have_line;
1207 NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE,
1213 /* Don't success if no valid groups found */
1215 yaml_emitter_set_writer_error(out->emitter,
1216 "Emitter contains no valid Netlink groups");
1217 goto nla_put_failure;
1221 rc = nl_send_auto(out->nl, msg);
1224 rc = genl_send_simple(out->nl, out->family_id, out->cmd,
1225 out->version, out->flags);
1228 yaml_emitter_set_writer_error(out->emitter,
1232 return out->emitter->error == YAML_NO_ERROR ? 1 : 0;
1235 /* This function is used by external utilities to use Netlink with
1236 * libyaml so we can turn YAML documentations into Netlink message
1237 * to send. This behavior mirrors yaml_emitter_set_output_file()
1238 * which is used to write out a YAML document to a file.
1241 yaml_emitter_set_output_netlink(yaml_emitter_t *sender, struct nl_sock *nl,
1242 char *family, int version, int cmd, int flags)
1244 struct yaml_netlink_output *out;
1246 out = calloc(1, sizeof(*out));
1248 sender->error = YAML_MEMORY_ERROR;
1253 out->family_id = genl_ctrl_resolve(nl, family);
1254 if (out->family_id < 0) {
1255 yaml_emitter_set_writer_error(sender,
1256 "failed to resolve Netlink family id");
1260 out->emitter = sender;
1262 out->family = family;
1263 out->version = version;
1266 out->pid = nl_socket_get_local_port(nl);
1267 yaml_emitter_set_output(sender, yaml_netlink_write_handler, out);
1271 /* Error handling helpers */
1272 void yaml_emitter_log_error(yaml_emitter_t *emitter, FILE *log)
1274 /* YAML_WRITER_ERROR means no Netlink support so use old API */
1275 switch (emitter->error) {
1276 case YAML_MEMORY_ERROR:
1277 fprintf(log, "Memory error: Not enough memory for emitting\n");
1279 case YAML_WRITER_ERROR:
1280 fprintf(log, "Writer error: %s\n", emitter->problem);
1282 case YAML_EMITTER_ERROR:
1283 fprintf(log, "Emitter error: %s\n", emitter->problem);
1289 void yaml_parser_log_error(yaml_parser_t *parser, FILE *log, const char *errmsg)
1293 switch (parser->error) {
1294 case YAML_MEMORY_ERROR:
1295 fprintf(log, "Memory error: Not enough memory for parser\n");
1298 case YAML_SCANNER_ERROR:
1299 case YAML_PARSER_ERROR:
1300 if (parser->context) {
1302 "%s error: %s at line %d, column %d\n%s at line %d, column %d\n",
1303 parser->error == YAML_SCANNER_ERROR ? "Scanner" : "Parser",
1305 (int)parser->context_mark.line + 1,
1306 (int)parser->context_mark.column + 1,
1308 (int)parser->problem_mark.line + 1,
1309 (int)parser->problem_mark.column + 1);
1311 fprintf(log, "%s error: %s at line %d, column %d\n",
1312 parser->error == YAML_SCANNER_ERROR ? "Scanner" : "Parser",
1314 (int)parser->problem_mark.line + 1,
1315 (int)parser->problem_mark.column + 1);
1319 case YAML_READER_ERROR:
1320 extra = yaml_parser_get_reader_error(parser);
1322 extra = parser->problem;
1324 if (parser->problem_value != -1) {
1326 "Failed to %s: reader error '%s':#%X at %ld'\n",
1327 errmsg, extra, parser->problem_value,
1328 (long)parser->problem_offset);
1331 "Failed to %s: reader error '%s' at %ld\n",
1332 errmsg, extra, (long)parser->problem_offset);