@@ -43,7 +43,9 @@
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/kref.h>
+#include <net/genetlink.h>
+#include <uapi/linux/lnet/lnet-nl.h>
#include <uapi/linux/lnet/lnet-types.h>
#include <uapi/linux/lnet/lnetctl.h>
#include <uapi/linux/lnet/lnet-dlc.h>
@@ -1280,4 +1282,17 @@ struct lnet {
struct list_head ln_udsp_list;
};
+static const struct nla_policy scalar_attr_policy[LN_SCALAR_CNT + 1] = {
+ [LN_SCALAR_ATTR_LIST] = { .type = NLA_NESTED },
+ [LN_SCALAR_ATTR_LIST_SIZE] = { .type = NLA_U16 },
+ [LN_SCALAR_ATTR_INDEX] = { .type = NLA_U16 },
+ [LN_SCALAR_ATTR_NLA_TYPE] = { .type = NLA_U16 },
+ [LN_SCALAR_ATTR_VALUE] = { .type = NLA_STRING },
+ [LN_SCALAR_ATTR_KEY_FORMAT] = { .type = NLA_U16 },
+};
+
+int lnet_genl_send_scalar_list(struct sk_buff *msg, u32 portid, u32 seq,
+ const struct genl_family *family, int flags,
+ u8 cmd, const struct ln_key_list *data[]);
+
#endif
new file mode 100644
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: LGPL-2.0+ WITH Linux-syscall-note */
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.
+ *
+ * LGPL HEADER END
+ *
+ */
+/* Copyright (c) 2021, UT-Battelle, LLC
+ *
+ * Author: James Simmons <jsimmons@infradead.org>
+ */
+
+#ifndef __UAPI_LNET_NL_H__
+#define __UAPI_LNET_NL_H__
+
+#include <linux/types.h>
+
+enum lnet_nl_key_format {
+ /* Is it FLOW or BLOCK */
+ LNKF_FLOW = 1,
+ /* Is it SEQUENCE or MAPPING */
+ LNKF_MAPPING = 2,
+ LNKF_SEQUENCE = 4,
+};
+
+enum lnet_nl_scalar_attrs {
+ LN_SCALAR_ATTR_UNSPEC = 0,
+ LN_SCALAR_ATTR_LIST,
+
+ LN_SCALAR_ATTR_LIST_SIZE,
+ LN_SCALAR_ATTR_INDEX,
+ LN_SCALAR_ATTR_NLA_TYPE,
+ LN_SCALAR_ATTR_VALUE,
+ LN_SCALAR_ATTR_KEY_FORMAT,
+
+ __LN_SCALAR_ATTR_LAST,
+};
+
+#define LN_SCALAR_CNT (__LN_SCALAR_ATTR_LAST - 1)
+
+struct ln_key_props {
+ char *lkp_values;
+ __u16 lkp_key_format;
+ __u16 lkp_data_type;
+};
+
+struct ln_key_list {
+ __u16 lkl_maxattr;
+ struct ln_key_props lkl_list[];
+};
+
+#endif /* __UAPI_LNET_NL_H__ */
@@ -2572,6 +2572,87 @@ static void lnet_push_target_fini(void)
return rc;
}
+static int lnet_genl_parse_list(struct sk_buff *msg,
+ const struct ln_key_list *data[], u16 idx)
+{
+ const struct ln_key_list *list = data[idx];
+ const struct ln_key_props *props;
+ struct nlattr *node;
+ u16 count;
+
+ if (!list)
+ return 0;
+
+ if (!list->lkl_maxattr)
+ return -ERANGE;
+
+ props = list->lkl_list;
+ if (!props)
+ return -EINVAL;
+
+ node = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
+ if (!node)
+ return -ENOBUFS;
+
+ for (count = 1; count <= list->lkl_maxattr; count++) {
+ struct nlattr *key = nla_nest_start(msg, count);
+
+ if (count == 1)
+ nla_put_u16(msg, LN_SCALAR_ATTR_LIST_SIZE,
+ list->lkl_maxattr);
+
+ nla_put_u16(msg, LN_SCALAR_ATTR_INDEX, count);
+ if (props[count].lkp_values)
+ nla_put_string(msg, LN_SCALAR_ATTR_VALUE,
+ props[count].lkp_values);
+ if (props[count].lkp_key_format)
+ nla_put_u16(msg, LN_SCALAR_ATTR_KEY_FORMAT,
+ props[count].lkp_key_format);
+ nla_put_u16(msg, LN_SCALAR_ATTR_NLA_TYPE,
+ props[count].lkp_data_type);
+ if (props[count].lkp_data_type == NLA_NESTED) {
+ int rc;
+
+ rc = lnet_genl_parse_list(msg, data, ++idx);
+ if (rc < 0)
+ return rc;
+ }
+
+ nla_nest_end(msg, key);
+ }
+
+ nla_nest_end(msg, node);
+ return 0;
+}
+
+int lnet_genl_send_scalar_list(struct sk_buff *msg, u32 portid, u32 seq,
+ const struct genl_family *family, int flags,
+ u8 cmd, const struct ln_key_list *data[])
+{
+ int rc = 0;
+ void *hdr;
+
+ if (!data[0])
+ return -EINVAL;
+
+ hdr = genlmsg_put(msg, portid, seq, family, flags, cmd);
+ if (!hdr) {
+ rc = -EMSGSIZE;
+ goto canceled;
+ }
+
+ rc = lnet_genl_parse_list(msg, data, 0);
+ if (rc < 0)
+ goto canceled;
+
+ genlmsg_end(msg, hdr);
+canceled:
+ if (rc < 0)
+ genlmsg_cancel(msg, hdr);
+ return rc;
+}
+EXPORT_SYMBOL(lnet_genl_send_scalar_list);
+
/**
* Initialize LNet library.
*