[LTP] [PATCH v4 1/4] tst_netlink: Add helper functions for handling generic attributes

Martin Doucha mdoucha@suse.cz
Tue Nov 21 16:42:23 CET 2023


Refactor struct tst_rtnl_attr_list for generic use and add helper
functions for handling generic struct nlattr message attributes.

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
Reviewed-by: Petr Vorel <pvorel@suse.cz>
---

Changes since v1: New patch
Changes since v2: None
Changes since v3: Updated docs

NETLINK_ADD_ATTR_STRING() is currently unused but it was added for future use.

 doc/C-Test-Network-API.asciidoc | 66 +++++++++++++++++---------
 include/tst_netdevice.h         |  6 +--
 include/tst_netlink.h           | 38 ++++++++++++---
 lib/tst_netdevice.c             | 20 ++++----
 lib/tst_netlink.c               | 82 ++++++++++++++++++++++++++++++++-
 testcases/cve/tcindex01.c       | 12 ++---
 6 files changed, 176 insertions(+), 48 deletions(-)

diff --git a/doc/C-Test-Network-API.asciidoc b/doc/C-Test-Network-API.asciidoc
index 6145e6718..feedd5a95 100644
--- a/doc/C-Test-Network-API.asciidoc
+++ b/doc/C-Test-Network-API.asciidoc
@@ -293,11 +293,11 @@ stage.
 -------------------------------------------------------------------------------
 struct tst_netlink_context;
 
-struct tst_rtnl_attr_list {
+struct tst_netlink_attr_list {
 	unsigned short type;
 	const void *data;
 	ssize_t len;
-	const struct tst_rtnl_attr_list *sublist;
+	const struct tst_netlink_attr_list *sublist;
 };
 
 struct tst_netlink_message {
@@ -313,12 +313,13 @@ constructing and sending arbitrary messages using the functions described
 below. Create a new context using +NETLINK_CREATE_CONTEXT()+, then free it
 using +NETLINK_DESTROY_CONTEXT()+ when you're done with it.
 
-+struct tst_rtnl_attr_list+ is a helper structure for defining complex
++struct tst_netlink_attr_list+ is a helper structure for defining complex
 rtnetlink message attribute payloads, including nested attribute lists. Every
 list and sublist defined using this structure is terminated by item with
 negative +len+.
 
-- +type+ is the attribute type that will be stored in +struct rtattr.rta_type+.
+- +type+ is the attribute type that will be stored in +struct nlattr.nla_type+
+  or +struct rtattr.rta_type+.
 
 - +data+ contains arbitrary attribute payload.
 
@@ -326,10 +327,10 @@ negative +len+.
   set +len+ to 0. The last item in a list or sublist must have negative length.
 
 - +sublist+ contains a nested attribute list which will be appended after
-  +data+ as part of the attribute payload. +struct rtattr.rta_len+ will be
-  calculated automatically with proper alignment, do _not_ add the sublist size
-  to the +len+ field. If you do not want to add nested attributes, set
-  +sublist+ to +NULL+.
+  +data+ as part of the attribute payload. +struct nlattr.nla_len+ or
+  +struct rtattr.rta_len+ will be calculated automatically with proper
+  alignment, do _not_ add the sublist size to the +len+ field. If you do not
+  want to add nested attributes, set +sublist+ to +NULL+.
 
 +struct tst_netlink_message+ is a structure holding partially parsed netlink
 messages received from the kernel. +NETLINK_RECV()+ returns an array of these
@@ -412,24 +413,47 @@ structures with the last item having +NULL+ in the +header+ field. Call
   and +NETLINK_CHECK_ACKS()+ will not work correctly until the next
   +NETLINK_SEND()+.
 
+- +int NETLINK_ADD_ATTR(struct tst_netlink_context *ctx, unsigned short type,
+  const void *data, unsigned short len)+ – Adds new +struct nlattr+ attribute
+  to the last message in +ctx+ buffer. See +NETLINK_ADD_MESSAGE()+. You need
+  to provide attribute +type+ which will be stored in +struct nlattr.nla_type+,
+  optional payload +data+ and payload size +len+ in bytes. If you don't want
+  to add any payload, set +data+ to +NULL+ and +len+ to 0. Returns 1 on
+  success, 0 on error.
+
+- +int NETLINK_ADD_ATTR_STRING(struct tst_netlink_context *ctx, unsigned short
+  type, const char *data)+ – Adds new +struct nlattr+ string attribute to the
+  last message in +ctx+ buffer. Parameters and return value are the same as
+  for +NETLINK_ADD_ATTR()+, except the payload length is calculated using
+  +strlen()+.
+
+- +int NETLINK_ADD_ATTR_LIST(struct tst_netlink_context *ctx, const struct
+  tst_netlink_attr_list *list)+ – Adds a list of +struct nlattr+ attributes
+  to the last message in +ctx+ buffer. See description of
+  +struct tst_netlink_attr_list+ and +NETLINK_ADD_MESSAGE()+ above. Returns
+  the number of added attributes on success (nested attributes are not
+  counted), -1 on error.
+
 - +int RTNL_ADD_ATTR(struct tst_netlink_context *ctx, unsigned short type,
-  const void *data, unsigned short len)+ – Adds new attribute to the last
-  message in +ctx+ buffer. See +NETLINK_ADD_MESSAGE()+. You need to provide
-  attribute +type+ which will be stored in +struct rtattr.rta_type+, optional
-  payload +data+ and payload size +len+ in bytes. If you don't want to add any
-  payload, set +data+ to +NULL+ and +len+ to 0. Returns 1 on success,
-  0 on error.
+  const void *data, unsigned short len)+ – Adds new +struct rtattr+ attribute
+  to the last message in +ctx+ buffer. See +NETLINK_ADD_MESSAGE()+. You need
+  to provide attribute +type+ which will be stored in +struct rtattr.rta_type+,
+  optional payload +data+ and payload size +len+ in bytes. If you don't want
+  to add any payload, set +data+ to +NULL+ and +len+ to 0. Returns 1 on
+  success, 0 on error.
 
 - +int RTNL_ADD_ATTR_STRING(struct tst_netlink_context *ctx, unsigned short
-  type, const char *data)+ – Adds new string attribute to the last message
-  in +ctx+ buffer. Parameters and return value are the same as for
-  +RTNL_ADD_ATTR()+, except the payload length is calculated using +strlen()+.
+  type, const char *data)+ – Adds new +struct rtattr+ string attribute to the
+  last message in +ctx+ buffer. Parameters and return value are the same as
+  for +RTNL_ADD_ATTR()+, except the payload length is calculated using
+  +strlen()+.
 
 - +int RTNL_ADD_ATTR_LIST(struct tst_netlink_context *ctx, const struct
-  tst_rtnl_attr_list *list)+ – Adds a list of attributes to the last message
-  in +ctx+ buffer. See description of +struct tst_rtnl_attr_list+ and
-  +NETLINK_ADD_MESSAGE()+ above.  Returns the number of added attributes on
-  success (nested attributes are not counted), -1 on error.
+  tst_netlink_attr_list *list)+ – Adds a list of +struct rtattr+ attributes
+  to the last message in +ctx+ buffer. See description of
+  +struct tst_netlink_attr_list+ and +NETLINK_ADD_MESSAGE()+ above. Returns
+  the number of added attributes on success (nested attributes are not
+  counted), -1 on error.
 
 Example Usage
 +++++++++++++
diff --git a/include/tst_netdevice.h b/include/tst_netdevice.h
index 4239d0960..8d40148a6 100644
--- a/include/tst_netdevice.h
+++ b/include/tst_netdevice.h
@@ -132,7 +132,7 @@ int tst_netdev_remove_route_inet(const char *file, const int lineno,
 int tst_netdev_add_qdisc(const char *file, const int lineno, int strict,
 	const char *ifname, unsigned int family, unsigned int parent,
 	unsigned int handle, const char *qd_kind,
-	const struct tst_rtnl_attr_list *config);
+	const struct tst_netlink_attr_list *config);
 #define NETDEV_ADD_QDISC(ifname, family, parent, handle, qd_kind, config) \
 	tst_netdev_add_qdisc(__FILE__, __LINE__, 1, (ifname), (family), \
 		(parent), (handle), (qd_kind), (config))
@@ -154,7 +154,7 @@ int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict,
 int tst_netdev_add_traffic_class(const char *file, const int lineno,
 	int strict, const char *ifname, unsigned int parent,
 	unsigned int handle, const char *qd_kind,
-	const struct tst_rtnl_attr_list *config);
+	const struct tst_netlink_attr_list *config);
 #define NETDEV_ADD_TRAFFIC_CLASS(ifname, parent, handle, qd_kind, config) \
 	tst_netdev_add_traffic_class(__FILE__, __LINE__, 1, (ifname), \
 		(parent), (handle), (qd_kind), (config))
@@ -173,7 +173,7 @@ int tst_netdev_remove_traffic_class(const char *file, const int lineno,
 int tst_netdev_add_traffic_filter(const char *file, const int lineno,
 	int strict, const char *ifname, unsigned int parent,
 	unsigned int handle, unsigned int protocol, unsigned int priority,
-	const char *f_kind, const struct tst_rtnl_attr_list *config);
+	const char *f_kind, const struct tst_netlink_attr_list *config);
 #define NETDEV_ADD_TRAFFIC_FILTER(ifname, parent, handle, protocol, priority, \
 	f_kind, config) \
 	tst_netdev_add_traffic_filter(__FILE__, __LINE__, 1, (ifname), \
diff --git a/include/tst_netlink.h b/include/tst_netlink.h
index f10f1cf5d..7d96fd711 100644
--- a/include/tst_netlink.h
+++ b/include/tst_netlink.h
@@ -9,11 +9,11 @@
 
 struct tst_netlink_context;
 
-struct tst_rtnl_attr_list {
+struct tst_netlink_attr_list {
 	unsigned short type;
 	const void *data;
 	ssize_t len;
-	const struct tst_rtnl_attr_list *sublist;
+	const struct tst_netlink_attr_list *sublist;
 };
 
 struct tst_netlink_message {
@@ -72,25 +72,49 @@ int tst_netlink_add_message(const char *file, const int lineno,
 	tst_netlink_add_message(__FILE__, __LINE__, (ctx), (header), \
 		(payload), (psize))
 
-/* Add arbitrary attribute to last message */
+/* Add arbitrary nlattr attribute to last message */
+int tst_netlink_add_attr(const char *file, const int lineno,
+	struct tst_netlink_context *ctx, unsigned short type, const void *data,
+	unsigned short len);
+#define NETLINK_ADD_ATTR(ctx, type, data, len) \
+	tst_netlink_add_attr(__FILE__, __LINE__, (ctx), (type), (data), (len))
+
+/* Add string nlattr attribute to last message */
+int tst_netlink_add_attr_string(const char *file, const int lineno,
+	struct tst_netlink_context *ctx, unsigned short type, const char *data);
+#define NETLINK_ADD_ATTR_STRING(ctx, type, data) \
+	tst_netlink_add_attr_string(__FILE__, __LINE__, (ctx), (type), (data))
+
+/*
+ * Add list of arbitrary nlattr attributes to last message. The list is
+ * terminated by attribute with negative length. Nested sublists are supported.
+ */
+int tst_netlink_add_attr_list(const char *file, const int lineno,
+	struct tst_netlink_context *ctx,
+	const struct tst_netlink_attr_list *list);
+#define NETLINK_ADD_ATTR_LIST(ctx, list) \
+	tst_netlink_add_attr_list(__FILE__, __LINE__, (ctx), (list))
+
+/* Add arbitrary rtattr attribute to last message */
 int tst_rtnl_add_attr(const char *file, const int lineno,
 	struct tst_netlink_context *ctx, unsigned short type, const void *data,
 	unsigned short len);
 #define RTNL_ADD_ATTR(ctx, type, data, len) \
 	tst_rtnl_add_attr(__FILE__, __LINE__, (ctx), (type), (data), (len))
 
-/* Add string attribute to last message */
+/* Add string rtattr attribute to last message */
 int tst_rtnl_add_attr_string(const char *file, const int lineno,
 	struct tst_netlink_context *ctx, unsigned short type, const char *data);
 #define RTNL_ADD_ATTR_STRING(ctx, type, data) \
 	tst_rtnl_add_attr_string(__FILE__, __LINE__, (ctx), (type), (data))
 
 /*
- * Add list of arbitrary attributes to last message. The list is terminated
- * by attribute with negative length. Nested sublists are supported.
+ * Add list of arbitrary rtattr attributes to last message. The list is
+ * terminated by attribute with negative length. Nested sublists are supported.
  */
 int tst_rtnl_add_attr_list(const char *file, const int lineno,
-	struct tst_netlink_context *ctx, const struct tst_rtnl_attr_list *list);
+	struct tst_netlink_context *ctx,
+	const struct tst_netlink_attr_list *list);
 #define RTNL_ADD_ATTR_LIST(ctx, list) \
 	tst_rtnl_add_attr_list(__FILE__, __LINE__, (ctx), (list))
 
diff --git a/lib/tst_netdevice.c b/lib/tst_netdevice.c
index 6f86b8089..1042466bf 100644
--- a/lib/tst_netdevice.c
+++ b/lib/tst_netdevice.c
@@ -105,17 +105,17 @@ int tst_create_veth_pair(const char *file, const int lineno, int strict,
 	int ret;
 	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
 	struct tst_netlink_context *ctx;
-	struct tst_rtnl_attr_list peerinfo[] = {
+	struct tst_netlink_attr_list peerinfo[] = {
 		{IFLA_IFNAME, ifname2, strlen(ifname2) + 1, NULL},
 		{0, NULL, -1, NULL}
 	};
-	struct tst_rtnl_attr_list peerdata[] = {
+	struct tst_netlink_attr_list peerdata[] = {
 		{VETH_INFO_PEER, &info, sizeof(info), peerinfo},
 		{0, NULL, -1, NULL}
 	};
-	struct tst_rtnl_attr_list attrs[] = {
+	struct tst_netlink_attr_list attrs[] = {
 		{IFLA_IFNAME, ifname1, strlen(ifname1) + 1, NULL},
-		{IFLA_LINKINFO, NULL, 0, (const struct tst_rtnl_attr_list[]){
+		{IFLA_LINKINFO, NULL, 0, (const struct tst_netlink_attr_list[]){
 			{IFLA_INFO_KIND, "veth", 4, NULL},
 			{IFLA_INFO_DATA, NULL, 0, peerdata},
 			{0, NULL, -1, NULL}
@@ -164,9 +164,9 @@ int tst_netdev_add_device(const char *file, const int lineno, int strict,
 	int ret;
 	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
 	struct tst_netlink_context *ctx;
-	struct tst_rtnl_attr_list attrs[] = {
+	struct tst_netlink_attr_list attrs[] = {
 		{IFLA_IFNAME, ifname, strlen(ifname) + 1, NULL},
-		{IFLA_LINKINFO, NULL, 0, (const struct tst_rtnl_attr_list[]){
+		{IFLA_LINKINFO, NULL, 0, (const struct tst_netlink_attr_list[]){
 			{IFLA_INFO_KIND, devtype, strlen(devtype), NULL},
 			{0, NULL, -1, NULL}
 		}},
@@ -527,7 +527,7 @@ static int modify_qdisc(const char *file, const int lineno, int strict,
 	const char *object, unsigned int action, unsigned int nl_flags,
 	const char *ifname, unsigned int family, unsigned int parent,
 	unsigned int handle, unsigned int info, const char *qd_kind,
-	const struct tst_rtnl_attr_list *config)
+	const struct tst_netlink_attr_list *config)
 {
 	struct tst_netlink_context *ctx;
 	int ret;
@@ -585,7 +585,7 @@ static int modify_qdisc(const char *file, const int lineno, int strict,
 int tst_netdev_add_qdisc(const char *file, const int lineno, int strict,
 	const char *ifname, unsigned int family, unsigned int parent,
 	unsigned int handle, const char *qd_kind,
-	const struct tst_rtnl_attr_list *config)
+	const struct tst_netlink_attr_list *config)
 {
 	return modify_qdisc(file, lineno, strict, "queueing discipline",
 		RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL, ifname, family,
@@ -604,7 +604,7 @@ int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict,
 int tst_netdev_add_traffic_class(const char *file, const int lineno,
 	int strict, const char *ifname, unsigned int parent,
 	unsigned int handle, const char *qd_kind,
-	const struct tst_rtnl_attr_list *config)
+	const struct tst_netlink_attr_list *config)
 {
 	return modify_qdisc(file, lineno, strict, "traffic class",
 		RTM_NEWTCLASS, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC,
@@ -623,7 +623,7 @@ int tst_netdev_remove_traffic_class(const char *file, const int lineno,
 int tst_netdev_add_traffic_filter(const char *file, const int lineno,
 	int strict, const char *ifname, unsigned int parent,
 	unsigned int handle, unsigned int protocol, unsigned int priority,
-	const char *f_kind, const struct tst_rtnl_attr_list *config)
+	const char *f_kind, const struct tst_netlink_attr_list *config)
 {
 	return modify_qdisc(file, lineno, strict, "traffic filter",
 		RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC,
diff --git a/lib/tst_netlink.c b/lib/tst_netlink.c
index bd05df81a..7bc98af56 100644
--- a/lib/tst_netlink.c
+++ b/lib/tst_netlink.c
@@ -283,6 +283,86 @@ int tst_netlink_add_message(const char *file, const int lineno,
 	return 1;
 }
 
+int tst_netlink_add_attr(const char *file, const int lineno,
+	struct tst_netlink_context *ctx, unsigned short type,
+	const void *data, unsigned short len)
+{
+	size_t size = NLA_HDRLEN + NLA_ALIGN(len);
+	struct nlattr *attr;
+
+	if (!ctx->curmsg) {
+		tst_brk_(file, lineno, TBROK,
+			"%s(): No message to add attributes to", __func__);
+		return 0;
+	}
+
+	if (!netlink_grow_buffer(file, lineno, ctx, size))
+		return 0;
+
+	size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len);
+	attr = (struct nlattr *)(((char *)ctx->curmsg) + size);
+	attr->nla_type = type;
+	attr->nla_len = NLA_HDRLEN + len;
+	memcpy(((char *)attr) + NLA_HDRLEN, data, len);
+	ctx->curmsg->nlmsg_len = size + attr->nla_len;
+	ctx->datalen = NLMSG_ALIGN(ctx->datalen) + attr->nla_len;
+
+	return 1;
+}
+
+int tst_netlink_add_attr_string(const char *file, const int lineno,
+	struct tst_netlink_context *ctx, unsigned short type,
+	const char *data)
+{
+	return tst_netlink_add_attr(file, lineno, ctx, type, data,
+		strlen(data) + 1);
+}
+
+int tst_netlink_add_attr_list(const char *file, const int lineno,
+	struct tst_netlink_context *ctx,
+	const struct tst_netlink_attr_list *list)
+{
+	int i, ret;
+	size_t offset;
+
+	for (i = 0; list[i].len >= 0; i++) {
+		if (list[i].len > USHRT_MAX) {
+			tst_brk_(file, lineno, TBROK,
+				"%s(): Attribute value too long", __func__);
+			return -1;
+		}
+
+		offset = NLMSG_ALIGN(ctx->datalen);
+		ret = tst_netlink_add_attr(file, lineno, ctx, list[i].type,
+			list[i].data, list[i].len);
+
+		if (!ret)
+			return -1;
+
+		if (list[i].sublist) {
+			struct rtattr *attr;
+
+			ret = tst_netlink_add_attr_list(file, lineno, ctx,
+				list[i].sublist);
+
+			if (ret < 0)
+				return ret;
+
+			attr = (struct rtattr *)(ctx->buffer + offset);
+
+			if (ctx->datalen - offset > USHRT_MAX) {
+				tst_brk_(file, lineno, TBROK,
+					"%s(): Sublist too long", __func__);
+				return -1;
+			}
+
+			attr->rta_len = ctx->datalen - offset;
+		}
+	}
+
+	return i;
+}
+
 int tst_rtnl_add_attr(const char *file, const int lineno,
 	struct tst_netlink_context *ctx, unsigned short type,
 	const void *data, unsigned short len)
@@ -320,7 +400,7 @@ int tst_rtnl_add_attr_string(const char *file, const int lineno,
 
 int tst_rtnl_add_attr_list(const char *file, const int lineno,
 	struct tst_netlink_context *ctx,
-	const struct tst_rtnl_attr_list *list)
+	const struct tst_netlink_attr_list *list)
 {
 	int i, ret;
 	size_t offset;
diff --git a/testcases/cve/tcindex01.c b/testcases/cve/tcindex01.c
index d441a2449..b4f2bb01a 100644
--- a/testcases/cve/tcindex01.c
+++ b/testcases/cve/tcindex01.c
@@ -46,15 +46,15 @@ static const struct tc_htb_glob qd_opt = {
 static struct tc_htb_opt cls_opt = {};
 
 /* htb qdisc and class options */
-static const struct tst_rtnl_attr_list qd_config[] = {
-	{TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){
+static const struct tst_netlink_attr_list qd_config[] = {
+	{TCA_OPTIONS, NULL, 0, (const struct tst_netlink_attr_list[]){
 		{TCA_HTB_INIT, &qd_opt, sizeof(qd_opt), NULL},
 		{0, NULL, -1, NULL}
 	}},
 	{0, NULL, -1, NULL}
 };
-static const struct tst_rtnl_attr_list cls_config[] = {
-	{TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){
+static const struct tst_netlink_attr_list cls_config[] = {
+	{TCA_OPTIONS, NULL, 0, (const struct tst_netlink_attr_list[]){
 		{TCA_HTB_PARMS, &cls_opt, sizeof(cls_opt), NULL},
 		{0, NULL, -1, NULL}
 	}},
@@ -62,8 +62,8 @@ static const struct tst_rtnl_attr_list cls_config[] = {
 };
 
 /* tcindex filter options */
-static const struct tst_rtnl_attr_list f_config[] = {
-	{TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){
+static const struct tst_netlink_attr_list f_config[] = {
+	{TCA_OPTIONS, NULL, 0, (const struct tst_netlink_attr_list[]){
 		{TCA_TCINDEX_MASK, &mask, sizeof(mask), NULL},
 		{TCA_TCINDEX_SHIFT, &shift, sizeof(shift), NULL},
 		{TCA_TCINDEX_CLASSID, &clsid, sizeof(clsid), NULL},
-- 
2.42.1



More information about the ltp mailing list