diff mbox series

[libnftnl,4/4] device: Introduce nftnl_device

Message ID 20241002191941.8410-5-phil@nwl.cc
State New
Headers show
Series Support wildcard netdev hooks and events | expand

Commit Message

Phil Sutter Oct. 2, 2024, 7:19 p.m. UTC
A data structure used to parse NFT_MSG_(NEW|DEL)DEV messages into. Since
the kernel does not support these message types in requests yet,
implement a parser and getters only.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 include/libnftnl/Makefile.am        |   1 +
 include/libnftnl/device.h           |  39 +++++++
 include/linux/netfilter/nf_tables.h |   8 ++
 src/Makefile.am                     |   1 +
 src/device.c                        | 153 ++++++++++++++++++++++++++++
 src/libnftnl.map                    |  10 ++
 6 files changed, 212 insertions(+)
 create mode 100644 include/libnftnl/device.h
 create mode 100644 src/device.c
diff mbox series

Patch

diff --git a/include/libnftnl/Makefile.am b/include/libnftnl/Makefile.am
index d846a574f4386..feaa7285f0070 100644
--- a/include/libnftnl/Makefile.am
+++ b/include/libnftnl/Makefile.am
@@ -2,6 +2,7 @@  pkginclude_HEADERS = batch.h		\
 		     table.h		\
 		     trace.h		\
 		     chain.h		\
+		     device.h		\
 		     object.h		\
 		     rule.h		\
 		     expr.h		\
diff --git a/include/libnftnl/device.h b/include/libnftnl/device.h
new file mode 100644
index 0000000000000..8c437a1fe3ccf
--- /dev/null
+++ b/include/libnftnl/device.h
@@ -0,0 +1,39 @@ 
+#ifndef _LIBNFTNL_DEVICE_H_
+#define _LIBNFTNL_DEVICE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nftnl_device;
+
+struct nftnl_device *nftnl_device_alloc(void);
+void nftnl_device_free(const struct nftnl_device *);
+
+enum nftnl_device_attr {
+	NFTNL_DEVICE_NAME	= 0,
+	NFTNL_DEVICE_TABLE,
+	NFTNL_DEVICE_FLOWTABLE,
+	NFTNL_DEVICE_CHAIN,
+	NFTNL_DEVICE_SPEC,
+	NFTNL_DEVICE_FAMILY,
+	__NFTNL_DEVICE_MAX,
+};
+#define NFTNL_DEVICE_MAX (__NFTNL_DEVICE_MAX - 1)
+
+bool nftnl_device_is_set(const struct nftnl_device *d, uint16_t attr);
+
+const void *nftnl_device_get_data(const struct nftnl_device *d,
+				  uint16_t attr, uint32_t *data_len);
+const char *nftnl_device_get_str(const struct nftnl_device *d, uint16_t attr);
+int32_t nftnl_device_get_s32(const struct nftnl_device *d, uint16_t attr);
+
+struct nlmsghdr;
+
+int nftnl_device_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_device *d);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _LIBNFTNL_DEVICE_H_ */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index c48b19333630d..2f73d367cf429 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1740,10 +1740,18 @@  enum nft_synproxy_attributes {
  * enum nft_device_attributes - nf_tables device netlink attributes
  *
  * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
+ * @NFTA_DEVICE_TABLE: table containing the flowtable or chain hooking into the device (NLA_STRING)
+ * @NFTA_DEVICE_FLOWTABLE: flowtable hooking into the device (NLA_STRING)
+ * @NFTA_DEVICE_CHAIN: chain hooking into the device (NLA_STRING)
+ * @NFTA_DEVICE_SPEC: hook spec matching the device (NLA_STRING)
  */
 enum nft_devices_attributes {
 	NFTA_DEVICE_UNSPEC,
 	NFTA_DEVICE_NAME,
+	NFTA_DEVICE_TABLE,
+	NFTA_DEVICE_FLOWTABLE,
+	NFTA_DEVICE_CHAIN,
+	NFTA_DEVICE_SPEC,
 	__NFTA_DEVICE_MAX
 };
 #define NFTA_DEVICE_MAX		(__NFTA_DEVICE_MAX - 1)
diff --git a/src/Makefile.am b/src/Makefile.am
index 3cd259c04d1c3..34dbe7ced1a2a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,7 @@  libnftnl_la_SOURCES = utils.c		\
 		      table.c		\
 		      trace.c		\
 		      chain.c		\
+		      device.c		\
 		      object.c		\
 		      rule.c		\
 		      set.c		\
diff --git a/src/device.c b/src/device.c
new file mode 100644
index 0000000000000..79102f34752ea
--- /dev/null
+++ b/src/device.c
@@ -0,0 +1,153 @@ 
+/*
+ * (C) 2024 Red Hat GmbH
+ * Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "internal.h"
+
+#include <linux/netfilter/nfnetlink.h>
+
+#include <libnftnl/device.h>
+
+struct nftnl_device {
+	const char	*name;
+	const char	*table;
+	const char	*flowtable;
+	const char	*chain;
+	const char	*spec;
+	int32_t		family;
+	uint32_t	flags;
+};
+
+EXPORT_SYMBOL(nftnl_device_alloc);
+struct nftnl_device *nftnl_device_alloc(void)
+{
+	return calloc(1, sizeof(struct nftnl_device));
+}
+
+EXPORT_SYMBOL(nftnl_device_free);
+void nftnl_device_free(const struct nftnl_device *d)
+{
+	if (d->flags & (1 << NFTNL_DEVICE_NAME))
+		xfree(d->name);
+	if (d->flags & (1 << NFTNL_DEVICE_TABLE))
+		xfree(d->table);
+	if (d->flags & (1 << NFTNL_DEVICE_FLOWTABLE))
+		xfree(d->flowtable);
+	if (d->flags & (1 << NFTNL_DEVICE_CHAIN))
+		xfree(d->chain);
+	if (d->flags & (1 << NFTNL_DEVICE_SPEC))
+		xfree(d->spec);
+	xfree(d);
+}
+
+EXPORT_SYMBOL(nftnl_device_is_set);
+bool nftnl_device_is_set(const struct nftnl_device *d, uint16_t attr)
+{
+	return d->flags & (1 << attr);
+}
+
+EXPORT_SYMBOL(nftnl_device_get_data);
+const void *nftnl_device_get_data(const struct nftnl_device *d,
+				  uint16_t attr, uint32_t *data_len)
+{
+	if (!(d->flags & (1 << attr)))
+		return NULL;
+
+	switch (attr) {
+	case NFTNL_DEVICE_NAME:
+		*data_len = strlen(d->name) + 1;
+		return d->name;
+	case NFTNL_DEVICE_TABLE:
+		*data_len = strlen(d->table) + 1;
+		return d->table;
+	case NFTNL_DEVICE_FLOWTABLE:
+		*data_len = strlen(d->flowtable) + 1;
+		return d->flowtable;
+	case NFTNL_DEVICE_CHAIN:
+		*data_len = strlen(d->chain) + 1;
+		return d->chain;
+	case NFTNL_DEVICE_SPEC:
+		*data_len = strlen(d->spec) + 1;
+		return d->spec;
+	case NFTNL_DEVICE_FAMILY:
+		*data_len = sizeof(int32_t);
+		return &d->family;
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(nftnl_device_get_str);
+const char *nftnl_device_get_str(const struct nftnl_device *d, uint16_t attr)
+{
+	uint32_t data_len;
+
+	return nftnl_device_get_data(d, attr, &data_len);
+}
+
+EXPORT_SYMBOL(nftnl_device_get_s32);
+int32_t nftnl_device_get_s32(const struct nftnl_device *d, uint16_t attr)
+{
+	uint32_t data_len = 0;
+	const int32_t *val = nftnl_device_get_data(d, attr, &data_len);
+
+	nftnl_assert(val, attr, data_len == sizeof(int32_t));
+
+	return val ? *val : 0;
+}
+
+static int nftnl_device_parse_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_DEVICE_MAX) < 0)
+		return MNL_CB_OK;
+
+	/* all attributes are of string type */
+	if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+		abi_breakage();
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+EXPORT_SYMBOL(nftnl_device_nlmsg_parse);
+int nftnl_device_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_device *d)
+{
+	struct nlattr *tb[NFTA_DEVICE_MAX + 1] = {};
+	struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+	int ret = 0;
+
+	if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_device_parse_attr_cb, tb) < 0)
+		return -1;
+
+	if (nftnl_parse_str_attr(tb[NFTA_DEVICE_NAME], NFTNL_DEVICE_NAME,
+				 &d->name, &d->flags) < 0)
+		return -1;
+	if (nftnl_parse_str_attr(tb[NFTA_DEVICE_TABLE], NFTNL_DEVICE_TABLE,
+				 &d->table, &d->flags) < 0)
+		return -1;
+	if (nftnl_parse_str_attr(tb[NFTA_DEVICE_FLOWTABLE],
+				 NFTNL_DEVICE_FLOWTABLE,
+				 &d->flowtable, &d->flags) < 0)
+		return -1;
+	if (nftnl_parse_str_attr(tb[NFTA_DEVICE_CHAIN], NFTNL_DEVICE_CHAIN,
+				 &d->chain, &d->flags) < 0)
+		return -1;
+	if (tb[NFTA_DEVICE_SPEC]) {
+		d->spec = strdup(mnl_attr_get_ifname(tb[NFTA_DEVICE_SPEC]));
+		if (!d->spec)
+			return -1;
+		d->flags |= (1 << NFTNL_DEVICE_SPEC);
+	}
+
+	d->family = nfg->nfgen_family;
+	d->flags |= (1 << NFTNL_DEVICE_FAMILY);
+
+	return ret;
+}
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 8fffff19eb2e2..96ee683fb0611 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -383,3 +383,13 @@  LIBNFTNL_16 {
 LIBNFTNL_17 {
   nftnl_set_elem_nlmsg_build;
 } LIBNFTNL_16;
+
+LIBNFTNL_18 {
+  nftnl_device_alloc;
+  nftnl_device_free;
+  nftnl_device_is_set;
+  nftnl_device_get_data;
+  nftnl_device_get_str;
+  nftnl_device_get_s32;
+  nftnl_device_nlmsg_parse;
+} LIBNFTNL_17;