* [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length user data.
2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
@ 2016-01-03 19:38 ` Carlos Falgueras García
2016-01-03 19:38 ` [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects Carlos Falgueras García
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo, kaber
The new structure 'user' holds a pointer to user data and its length. The
kernel must have the flag NFTA_SET_USERDATA to support this feature.
Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
include/libnftnl/set.h | 2 ++
include/linux/netfilter/nf_tables.h | 2 ++
include/set.h | 4 +++
src/set.c | 50 +++++++++++++++++++++++++++++++++++++
4 files changed, 58 insertions(+)
diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 11243f5..7a5a512 100644
--- a/include/libnftnl/set.h
+++ b/include/libnftnl/set.h
@@ -22,6 +22,7 @@ enum nftnl_set_attr {
NFTNL_SET_DESC_SIZE,
NFTNL_SET_TIMEOUT,
NFTNL_SET_GC_INTERVAL,
+ NFTNL_SET_USERDATA,
__NFTNL_SET_MAX
};
#define NFTNL_SET_MAX (__NFTNL_SET_MAX - 1)
@@ -158,6 +159,7 @@ enum {
NFT_SET_ATTR_DESC_SIZE,
NFT_SET_ATTR_TIMEOUT,
NFT_SET_ATTR_GC_INTERVAL,
+ NFT_SET_ATTR_USERDATA,
__NFT_SET_ATTR_MAX
};
#define NFT_SET_ATTR_MAX (__NFT_SET_ATTR_MAX - 1)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index f77693b..9beddc5 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -291,6 +291,7 @@ enum nft_set_desc_attributes {
* @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
* @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
* @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
+ * @NFTA_SET_USERDATA: user data (NLA_BINARY)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -306,6 +307,7 @@ enum nft_set_attributes {
NFTA_SET_ID,
NFTA_SET_TIMEOUT,
NFTA_SET_GC_INTERVAL,
+ NFTA_SET_USERDATA,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
diff --git a/include/set.h b/include/set.h
index c3b96f2..85bd389 100644
--- a/include/set.h
+++ b/include/set.h
@@ -14,6 +14,10 @@ struct nftnl_set {
uint32_t key_len;
uint32_t data_type;
uint32_t data_len;
+ struct {
+ void *data;
+ uint32_t len;
+ } user;
uint32_t id;
enum nft_set_policies policy;
struct {
diff --git a/src/set.c b/src/set.c
index 8369f7f..315bced 100644
--- a/src/set.c
+++ b/src/set.c
@@ -19,6 +19,7 @@
#include <netinet/in.h>
#include <limits.h>
#include <errno.h>
+#include <ctype.h>
#include <libmnl/libmnl.h>
#include <linux/netfilter/nfnetlink.h>
@@ -91,6 +92,7 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
case NFTNL_SET_DESC_SIZE:
case NFTNL_SET_TIMEOUT:
case NFTNL_SET_GC_INTERVAL:
+ case NFTNL_SET_USERDATA:
break;
default:
return;
@@ -167,6 +169,10 @@ void nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
case NFTNL_SET_GC_INTERVAL:
s->gc_interval = *((uint32_t *)data);
break;
+ case NFTNL_SET_USERDATA:
+ s->user.data = (void *)data;
+ s->user.len = data_len;
+ break;
}
s->flags |= (1 << attr);
}
@@ -240,6 +246,9 @@ const void *nftnl_set_get_data(struct nftnl_set *s, uint16_t attr,
case NFTNL_SET_GC_INTERVAL:
*data_len = sizeof(uint32_t);
return &s->gc_interval;
+ case NFTNL_SET_USERDATA:
+ *data_len = s->user.len;
+ return s->user.data;
}
return NULL;
}
@@ -348,6 +357,8 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
mnl_attr_put_u64(nlh, NFTA_SET_TIMEOUT, htobe64(s->timeout));
if (s->flags & (1 << NFTNL_SET_GC_INTERVAL))
mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval));
+ if (s->flags & (1 << NFTNL_SET_USERDATA))
+ mnl_attr_put(nlh, NFTA_SET_USERDATA, s->user.len, s->user.data);
}
EXPORT_SYMBOL_ALIAS(nftnl_set_nlmsg_build_payload, nft_set_nlmsg_build_payload);
@@ -376,6 +387,10 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
abi_breakage();
break;
+ case NFTA_SET_USERDATA:
+ if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
+ abi_breakage();
+ break;
case NFTA_SET_TIMEOUT:
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
abi_breakage();
@@ -480,6 +495,20 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
s->gc_interval = ntohl(mnl_attr_get_u32(tb[NFTA_SET_GC_INTERVAL]));
s->flags |= (1 << NFTNL_SET_GC_INTERVAL);
}
+ if (tb[NFTA_SET_USERDATA]) {
+ const void *udata =
+ mnl_attr_get_payload(tb[NFTA_SET_USERDATA]);
+
+ if (s->user.data)
+ xfree(s->user.data);
+
+ s->user.len = mnl_attr_get_payload_len(tb[NFTA_SET_USERDATA]);
+ s->user.data = malloc(s->user.len);
+ if (s->user.data == NULL)
+ return -1;
+ memcpy(s->user.data, udata, s->user.len);
+ s->flags |= (1 << NFTNL_SET_USERDATA);
+ }
if (tb[NFTA_SET_DESC])
ret = nftnl_set_desc_parse(s, tb[NFTA_SET_DESC]);
@@ -775,6 +804,7 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
uint32_t type, uint32_t flags)
{
int len = size, offset = 0, ret;
+ int i;
struct nftnl_set_elem *elem;
ret = snprintf(buf, len, "{\"set\":{");
@@ -826,6 +856,26 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
}
+ if (s->flags & (1 << NFTNL_SET_USERDATA)) {
+ ret = snprintf(buf + offset, len, ",\"userdata_len\":%u",
+ s->user.len);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+ ret = snprintf(buf + offset, len, ",\"userdata\":\"");
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+ char *c = s->user.data;
+
+ for (i = 0; i < s->user.len; i++) {
+ ret = snprintf(buf + offset, len, "%c",
+ isprint(c[i]) ? c[i] : ' ');
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ ret = snprintf(buf + offset, len, "\"");
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ }
+
if (s->flags & (1 << NFTNL_SET_DESC_SIZE)) {
ret = snprintf(buf + offset, len, ",\"desc_size\":%u",
s->desc.size);
--
2.6.4
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects.
2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
2016-01-03 19:38 ` [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length " Carlos Falgueras García
@ 2016-01-03 19:38 ` Carlos Falgueras García
2016-01-04 12:06 ` Patrick McHardy
2016-01-03 19:38 ` [PATCH 4/4] libnftnl: examples: Modify the example to allow add TLV objects as user data Carlos Falgueras García
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo, kaber
These functions allow create a buffer (nftnl_attrbuf) of TLV objects
(nftnl_attr). It is inspired in libmnl/src/attr.c.
Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
include/libnftnl/set.h | 133 ++++++++++++++++++++
include/set.h | 39 ++++++
src/libnftnl.map | 47 +++++++
src/set.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 536 insertions(+), 10 deletions(-)
diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 7a5a512..ec15603 100644
--- a/include/libnftnl/set.h
+++ b/include/libnftnl/set.h
@@ -278,4 +278,137 @@ void nft_set_elems_iter_destroy(struct nft_set_elems_iter *iter);
int nft_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh,
struct nft_set_elems_iter *iter);
+/*
+ * nftnl attributes API
+ */
+struct nftnl_attr;
+struct nftnl_attrbuf;
+
+/* nftnl_attrbuf */
+struct nftnl_attrbuf *nftnl_attrbuf_alloc(size_t size);
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_printf(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_len(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_size(const struct nftnl_attrbuf *attrbuf);
+void *nftnl_attrbuf_data(const struct nftnl_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint16_t nftnl_attr_get_type(const struct nftnl_attr *attr);
+uint16_t nftnl_attr_get_len(const struct nftnl_attr *attr);
+void *nftnl_attr_get_value(const struct nftnl_attr *attr);
+uint32_t nftnl_attr_get_size(const struct nftnl_attr *attr);
+
+/* TLV attribute putters */
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+ uint16_t type, size_t len, const void *data);
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+ size_t bufsize, uint16_t type,
+ size_t len, const void *data);
+
+/* TLV attribute nesting */
+struct nftnl_attr *nftnl_attr_nest_start(struct nftnl_attrbuf *attrbuf,
+ uint16_t type);
+struct nftnl_attr *nftnl_attr_nest_start_check(struct nftnl_attrbuf *attrbuf,
+ size_t bufsize, uint16_t type);
+void nftnl_attr_nest_end(struct nftnl_attrbuf *attrbuf,
+ struct nftnl_attr *start);
+void nftnl_attr_nest_cancel(struct nftnl_attrbuf *attrbuf,
+ struct nftnl_attr *start);
+
+/* TLV validation */
+enum nftnl_attr_data_type {
+ NFTNL_ATTR_TYPE_UNSPEC,
+ NFTNL_ATTR_TYPE_U8,
+ NFTNL_ATTR_TYPE_U16,
+ NFTNL_ATTR_TYPE_U32,
+ NFTNL_ATTR_TYPE_U64,
+ NFTNL_ATTR_TYPE_STRING,
+ NFTNL_ATTR_TYPE_FLAG,
+ NFTNL_ATTR_TYPE_MSECS,
+ NFTNL_ATTR_TYPE_NESTED,
+ NFTNL_ATTR_TYPE_NESTED_COMPAT,
+ NFTNL_ATTR_TYPE_NUL_STRING,
+ NFTNL_ATTR_TYPE_BINARY,
+ __NFTNL_ATTR_TYPE_MAX,
+};
+#define NFTNL_ATTR_TYPE_MAX (__NFTNL_ATTR_TYPE_MAX - 1)
+
+int nftnl_attr_type_valid(const struct nftnl_attr *attr);
+int nftnl_attr_validate(const struct nftnl_attr *attr);
+int nftnl_attr_validate2(const struct nftnl_attr *attr, size_t exp_len);
+
+/* TLV iterators */
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr);
+
+#define nftnl_attr_for_each(attr, attrbuf) \
+ for ((attr) = (struct nftnl_attr *)(attrbuf)->data; \
+ (char *)(attrbuf)->tail > (char *)(attr); \
+ (attr) = nftnl_attr_next(attr))
+
+#define nftnl_attr_for_each_nested(attr, nest) \
+ for ((attr) = (struct nftnl_attr *)nftnl_attr_get_value(nest); \
+ (char *)(attr) - (char *)(nest) < nftnl_attr_get_len(nest);\
+ (attr) = nftnl_attr_next(attr))
+
+#define nftnl_attr_for_each_payload(attr, payload, payload_len) \
+ for ((attr) = (struct nftnl_attr *)(payload); \
+ (char *)(attr) - (char *)(payload) < (payload_len);\
+ (attr) = nftnl_attr_next(attr))
+
+int nftnl_attr_payload_snprint(const void *payload, size_t payload_len,
+ char *buf, int bsize);
+/*
+ * Compact
+ */
+struct nft_attr;
+struct nft_attrbuf;
+
+struct nft_attrbuf *nft_attrbuf_alloc(size_t size);
+void nft_attrbuf_delete(struct nft_attrbuf *attrbuf);
+void nft_attrbuf_free(struct nft_attrbuf *attrbuf);
+void nft_attrbuf_printf(const struct nft_attrbuf *attrbuf);
+size_t nft_attrbuf_len(const struct nft_attrbuf *attrbuf);
+size_t nft_attrbuf_size(const struct nft_attrbuf *attrbuf);
+void *nft_attrbuf_data(const struct nft_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint16_t nft_attr_get_type(const struct nft_attr *attr);
+uint16_t nft_attr_get_len(const struct nft_attr *attr);
+void *nft_attr_get_value(const struct nft_attr *attr);
+uint16_t nft_attr_get_size(const struct nft_attr *attr);
+
+/* TLV attribute putters */
+struct nft_attr *nft_attr_put(struct nft_attrbuf *attrbuf,
+ uint16_t type, size_t len, const void *data);
+struct nft_attr *nft_attr_put_check(struct nft_attrbuf *attrbuf,
+ size_t bufsize, uint16_t type,
+ size_t len, const void *data);
+
+/* TLV attribute nesting */
+struct nft_attr *nft_attr_nest_start(struct nft_attrbuf *attrbuf,
+ uint16_t type);
+struct nft_attr *nft_attr_nest_start_check(struct nft_attrbuf *attrbuf,
+ size_t bufsize, uint16_t type);
+void nft_attr_nest_end(struct nft_attrbuf *attrbuf,
+ struct nft_attr *start);
+void nft_attr_nest_cancel(struct nft_attrbuf *attrbuf,
+ struct nft_attr *start);
+
+/* TLV validation */
+int nft_attr_type_valid(const struct nft_attr *attr);
+int nft_attr_validate(const struct nft_attr *attr);
+int nft_attr_validate2(const struct nft_attr *attr, size_t exp_len);
+
+/* TLV iterators */
+struct nft_attr *nft_attr_next(const struct nft_attr *attr);
+
+#define nft_attr_for_each(attr, attrbuf) nftnl_attr_for_each(attr, attrbuf)
+
+#define nft_attr_for_each_nested(attr, nest) \
+ nftnl_attr_for_each_nested(attr, attrbuf)
+
+int nft_attr_payload_snprint(const void *payload, size_t payload_len,
+ char *buf, int bsize);
+
#endif /* _LIBNFTNL_SET_H_ */
diff --git a/include/set.h b/include/set.h
index 85bd389..2b5ce98 100644
--- a/include/set.h
+++ b/include/set.h
@@ -35,4 +35,43 @@ struct nftnl_expr;
int nftnl_set_lookup_id(struct nftnl_expr *e, struct nftnl_set_list *set_list,
uint32_t *set_id);
+/*
+ * TLV structures:
+ * nftnl_attr
+ * <-- sizeof(nftnl_attr) --> <-- nftnl_attr->len -->
+ * +--------------------------+- - - - - -+- - - - - -- - - - - -+- - - - - +
+ * | Header | Pading | Payload | Pading |
+ * | (4 bytes) | (4 bytes) | | |
+ * +--------------------------+- - - - - -+- - - - - - - - - - - -+- - - - - +
+ * <------------------------ nftnl_attr_get_size() ------------------------>
+ *
+ *
+ * nftnl_attr->type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+
+struct nftnl_attr {
+ uint16_t type;
+ uint16_t len;
+ unsigned char value[] __aligned(__alignof__(uint64_t));
+};
+
+#define NFTNLA_F_NESTED (1 << 15)
+#define NFTNLA_F_NET_BYTEORDER (1 << 14)
+#define NFTNLA_TYPE_MASK ~(NFTNLA_F_NESTED | NFTNLA_F_NET_BYTEORDER)
+
+#define NFTNL_ALIGNTO 8
+#define NFTNL_ALIGN(len) (((len)+NFTNL_ALIGNTO-1) & ~(NFTNL_ALIGNTO-1))
+
+struct nftnl_attrbuf {
+ struct nftnl_attr *tail;
+ unsigned char data[] __aligned(__alignof__(uint64_t);
+};
+
#endif
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 2e193b7..80f7ff5 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -136,6 +136,29 @@ global:
nft_set_snprintf;
nft_set_fprintf;
+ nft_attrbuf_alloc;
+ nft_attrbuf_delete;
+ nft_attrbuf_free;
+ nft_attrbuf_printf;
+ nft_attrbuf_len;
+ nft_attrbuf_size;
+ nft_attrbuf_data;
+ nft_attr_get_type;
+ nft_attr_get_len;
+ nft_attr_get_value;
+ nft_attr_get_size;
+ nft_attr_put;
+ nft_attr_put_check;
+ nft_attr_nest_start;
+ nft_attr_nest_start_check;
+ nft_attr_nest_end;
+ nft_attr_nest_cancel;
+ nft_attr_type_valid;
+ nft_attr_validate;
+ nft_attr_validate2;
+ nft_attr_next;
+ nft_attr_payload_snprint;
+
nft_set_list_alloc;
nft_set_list_free;
nft_set_list_add;
@@ -336,6 +359,30 @@ global:
nftnl_set_snprintf;
nftnl_set_fprintf;
+ nftnl_attrbuf_alloc;
+ nftnl_attrbuf_delete;
+ nftnl_attrbuf_free;
+ nftnl_attrbuf_printf;
+ nftnl_attrbuf_len;
+ nftnl_attrbuf_size;
+ nftnl_attrbuf_data;
+ nftnl_attr_get_type;
+ nftnl_attr_get_len;
+ nftnl_attr_get_value;
+ nftnl_attr_get_size;
+ nftnl_attr_put;
+ nftnl_attr_put_check;
+ nftnl_attr_nest_start;
+ nftnl_attr_nest_start_check;
+ nftnl_attr_nest_end;
+ nftnl_attr_nest_cancel;
+ nftnl_attr_type_valid;
+ nftnl_attr_validate;
+ nftnl_attr_validate2;
+ nftnl_attr_next;
+ nftnl_attr_payload_snprint;
+
+
nftnl_set_list_alloc;
nftnl_set_list_free;
nftnl_set_list_add;
diff --git a/src/set.c b/src/set.c
index 315bced..b9031e1 100644
--- a/src/set.c
+++ b/src/set.c
@@ -28,6 +28,12 @@
#include <libnftnl/set.h>
#include <libnftnl/expr.h>
+#define ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, attr_len) ( \
+ (bufsize) >= \
+ NFTNL_ALIGN(attr_len) + \
+ sizeof(struct nftnl_attr) + \
+ nftnl_attrbuf_len(attrbuf))
+
struct nftnl_set *nftnl_set_alloc(void)
{
struct nftnl_set *s;
@@ -804,7 +810,6 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
uint32_t type, uint32_t flags)
{
int len = size, offset = 0, ret;
- int i;
struct nftnl_set_elem *elem;
ret = snprintf(buf, len, "{\"set\":{");
@@ -861,18 +866,14 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
s->user.len);
SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
- ret = snprintf(buf + offset, len, ",\"userdata\":\"");
+ ret = snprintf(buf + offset, len, ",\"userdata\":[");
SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
- char *c = s->user.data;
-
- for (i = 0; i < s->user.len; i++) {
- ret = snprintf(buf + offset, len, "%c",
- isprint(c[i]) ? c[i] : ' ');
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
- }
+ ret = nftnl_attr_payload_snprint(s->user.data, s->user.len,
+ buf + offset, len);
+ SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
- ret = snprintf(buf + offset, len, "\"");
+ ret = snprintf(buf + offset, len, "]");
SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
}
@@ -1270,3 +1271,309 @@ int nftnl_set_lookup_id(struct nftnl_expr *e,
*set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
return 1;
}
+
+/* TLV */
+struct nftnl_attrbuf *nftnl_attrbuf_alloc(size_t size)
+{
+ struct nftnl_attrbuf *attrbuf;
+
+ attrbuf =
+ (struct nftnl_attrbuf *)malloc(sizeof(struct nftnl_attrbuf) +
+ size
+ );
+ attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+
+ return attrbuf;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_alloc, nft_attrbuf_alloc);
+
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf)
+{
+ attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_delete, nft_attrbuf_delete);
+
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf)
+{
+ nftnl_attrbuf_delete(attrbuf);
+ free((void *)attrbuf);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_free, nft_attrbuf_free);
+
+size_t nftnl_attrbuf_len(const struct nftnl_attrbuf *attrbuf)
+{
+ return (size_t)((char *)attrbuf->tail - (char *)attrbuf->data);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_len, nft_attrbuf_len);
+
+size_t nftnl_attrbuf_size(const struct nftnl_attrbuf *attrbuf)
+{
+ return (size_t)((char *)attrbuf->tail - (char *)attrbuf);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_size, nft_attrbuf_size);
+
+void *nftnl_attrbuf_data(const struct nftnl_attrbuf *attrbuf)
+{
+ return (void *)attrbuf->data;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_data, nft_attrbuf_data);
+
+uint16_t nftnl_attr_get_type(const struct nftnl_attr *attr)
+{
+ return attr->type;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_type, nft_attr_get_type);
+
+uint16_t nftnl_attr_get_len(const struct nftnl_attr *attr)
+{
+ return attr->len;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_len, nft_attr_get_len);
+
+void *nftnl_attr_get_value(const struct nftnl_attr *attr)
+{
+ return (void *)attr->value;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_value, nft_attr_get_value);
+
+uint32_t nftnl_attr_get_size(const struct nftnl_attr *attr)
+{
+ return (char *)nftnl_attr_next(attr) - (char *)attr;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_size, nft_attr_get_size);
+
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+ uint16_t type, size_t len, const void *data)
+{
+ struct nftnl_attr *attr = attrbuf->tail;
+
+ attr->len = len;
+ attr->type = type;
+ memcpy(attr->value, data, len);
+
+ attrbuf->tail = nftnl_attr_next(attr);
+
+ return attr;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_put, nft_attr_put);
+
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+ size_t bufsize, uint16_t type,
+ size_t len, const void *data)
+{
+ if (!ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, len))
+ return NULL;
+ return nftnl_attr_put(attrbuf, type, len, data);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_put_check, nft_attr_put_check);
+
+struct nftnl_attr *nftnl_attr_nest_start(struct nftnl_attrbuf *attrbuf,
+ uint16_t type)
+{
+ struct nftnl_attr *start;
+
+ start = attrbuf->tail;
+ start->len = 0;
+ start->type = NFTNLA_F_NESTED | type;
+
+ attrbuf->tail = nftnl_attr_next(attrbuf->tail);
+
+ return start;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_start, nft_attr_nest_start);
+
+struct nftnl_attr *nftnl_attr_nest_start_check(struct nftnl_attrbuf *attrbuf,
+ size_t bufsize, uint16_t type)
+{
+ if (!ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, 0))
+ return NULL;
+ return nftnl_attr_nest_start(attrbuf, type);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_start_check, nft_attr_nest_start_check);
+
+void nftnl_attr_nest_end(struct nftnl_attrbuf *attrbuf,
+ struct nftnl_attr *start)
+{
+ start->len = (char *)attrbuf->tail - (char *)start->value;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_end, nft_attr_nest_end);
+
+int nftnl_attr_type_valid(const struct nftnl_attr *attr)
+{
+ if (nftnl_attr_get_type(attr) > NFTNL_ATTR_TYPE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 1;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_type_valid, nft_attr_type_valid);
+
+static const size_t nftnl_attr_data_type_len[MNL_TYPE_MAX] = {
+ [NFTNL_ATTR_TYPE_U8] = sizeof(uint8_t),
+ [NFTNL_ATTR_TYPE_U16] = sizeof(uint16_t),
+ [NFTNL_ATTR_TYPE_U32] = sizeof(uint32_t),
+ [NFTNL_ATTR_TYPE_U64] = sizeof(uint64_t),
+ [NFTNL_ATTR_TYPE_MSECS] = sizeof(uint64_t),
+};
+
+int nftnl_attr_validate(const struct nftnl_attr *attr)
+{
+ int exp_len;
+
+ exp_len = nftnl_attr_data_type_len[nftnl_attr_get_type(attr)];
+ return nftnl_attr_validate2(attr, exp_len);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_validate, nft_attr_validate);
+
+int nftnl_attr_validate2(const struct nftnl_attr *attr, size_t exp_len)
+{
+ uint16_t type = nftnl_attr_get_type(attr);
+ uint16_t len = nftnl_attr_get_len(attr);
+ const char *val = nftnl_attr_get_value(attr);
+
+ if (len != exp_len) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ switch (type) {
+ case MNL_TYPE_FLAG:
+ if (len > 0) {
+ errno = ERANGE;
+ return -1;
+ }
+ break;
+ case MNL_TYPE_NUL_STRING:
+ if (len == 0) {
+ errno = ERANGE;
+ return -1;
+ }
+ if (val[len-1] != '\0') {
+ errno = EINVAL;
+ return -1;
+ }
+ break;
+ case MNL_TYPE_STRING:
+ if (len == 0) {
+ errno = ERANGE;
+ return -1;
+ }
+ break;
+ case MNL_TYPE_NESTED:
+ /*
+ * Empty nested attributes are OK. If not empty,
+ * they must contain one header
+ */
+ if (len > 0 && len < sizeof(struct nftnl_attr)) {
+ errno = ERANGE;
+ return -1;
+ }
+ break;
+ default:
+ if (!nftnl_attr_type_valid(attr))
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_validate2, nft_attr_validate2);
+
+void nftnl_attr_nest_cancel(struct nftnl_attrbuf *attrbuf,
+ struct nftnl_attr *start)
+{
+ attrbuf->tail = start;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_cancel, nft_attr_nest_cancel);
+
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr)
+{
+ return (struct nftnl_attr *)&attr->value[NFTNL_ALIGN(attr->len)];
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_next, nft_attr_next);
+
+static int __attr_snprint(const struct nftnl_attr *attr,
+ char *buf, size_t bsize)
+{
+ int i;
+ int written, blen, boffset;
+ uint16_t alen;
+ char *aval;
+ struct nftnl_attr *pattr;
+
+ written = 0;
+ boffset = 0;
+ blen = bsize;
+ alen = nftnl_attr_get_len(attr);
+ aval = (char *)nftnl_attr_get_value(attr);
+
+
+ /* type */
+ written = snprintf(buf + boffset, blen, "{\"type\":%u,",
+ nftnl_attr_get_type(attr));
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ /* len */
+ written = snprintf(buf + boffset, blen, "\"len\":%u,", alen);
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ /* value as string */
+ written = snprintf(buf + boffset, blen, "\"val\":");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ if (attr->type & NFTNLA_F_NESTED) {
+ written = snprintf(buf + boffset, blen, "[");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ nftnl_attr_for_each_nested(pattr, attr) {
+ written = __attr_snprint(pattr, buf + boffset, blen);
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ written = snprintf(buf + boffset, blen, ",");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+ }
+ boffset--; /* delete last comma */
+
+ written = snprintf(buf + boffset, blen, "]");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+ } else {
+ written = snprintf(buf + boffset, blen, "\"");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ for (i = 0; i < alen; i++) {
+ written = snprintf(buf + boffset, blen, "%c",
+ isprint(aval[i]) ? aval[i] : ' ');
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+ }
+
+ written = snprintf(buf + boffset, blen, "\"");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+ }
+
+ written = snprintf(buf + boffset, blen, "}");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ return boffset;
+}
+
+int nftnl_attr_payload_snprint(const void *payload, size_t payload_len,
+ char *buf, int bsize)
+{
+ struct nftnl_attr *attr;
+ int written, blen, boffset;
+
+ written = 0;
+ boffset = 0;
+ blen = bsize;
+
+ nftnl_attr_for_each_payload(attr, payload, payload_len) {
+ written = __attr_snprint(attr, buf + boffset, blen);
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+ written = snprintf(buf + boffset, blen, ",");
+ SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+ }
+
+ return boffset-1; /* delete last comma */
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_payload_snprint, nft_attr_payload_snprint);
--
2.6.4
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/4] libnftnl: examples: Modify the example to allow add TLV objects as user data.
2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
2016-01-03 19:38 ` [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length " Carlos Falgueras García
2016-01-03 19:38 ` [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects Carlos Falgueras García
@ 2016-01-03 19:38 ` Carlos Falgueras García
2016-01-04 12:32 ` [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store " Patrick McHardy
2016-01-05 10:34 ` Pablo Neira Ayuso
4 siblings, 0 replies; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo, kaber
Example usage:
> nft add table mytable
> exmample/nft-set-add ip mytable myset "5:my data 0" "5:my data 1"
> example/nft-set-get ip json | jq #jq: https://stedolan.github.io/jq/
{
"set": {
"name": "myset",
"table": "mytable",
"flags": 2,
"family": "ip",
"key_type": 0,
"key_len": 2,
"userdata_len": 48,
"userdata": [
{
"type": 5,
"len": 9,
"val": "my data 0"
},
{
"type": 5,
"len": 9,
"val": "my data 1"
}
]
}
}
Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
examples/nft-set-add.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 49 insertions(+), 4 deletions(-)
diff --git a/examples/nft-set-add.c b/examples/nft-set-add.c
index e040aca..42ff3c8 100644
--- a/examples/nft-set-add.c
+++ b/examples/nft-set-add.c
@@ -28,8 +28,14 @@
#include <libmnl/libmnl.h>
#include <libnftnl/set.h>
+#define ATTRBUF_SIZE 256
+
+static bool parse_user_data(char *argv[], int argc,
+ struct nftnl_attrbuf *attrbuf);
+
static struct nftnl_set *setup_set(uint8_t family, const char *table,
- const char *name)
+ const char *name, const char *udata,
+ unsigned int udlen)
{
struct nftnl_set *s = NULL;
@@ -44,6 +50,8 @@ static struct nftnl_set *setup_set(uint8_t family, const char *table,
nftnl_set_set_u32(s, NFTNL_SET_FAMILY, family);
nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, 2);
nftnl_set_set_u32(s, NFTNL_SET_ID, 1);
+ if (udata != NULL)
+ nftnl_set_set_data(s, NFTNL_SET_USERDATA, udata, udlen);
nftnl_set_set_u32(s, NFTNL_SET_FLAGS, NFT_SET_CONSTANT);
return s;
@@ -71,13 +79,17 @@ int main(int argc, char *argv[])
struct nftnl_set *s;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
+ struct nftnl_attrbuf *attrbuf = NULL;
uint8_t family;
char buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t seq = time(NULL);
int ret;
- if (argc != 4) {
- fprintf(stderr, "Usage: %s <family> <table> <setname>\n", argv[0]);
+ if (argc < 4) {
+ fprintf(stderr,
+ "Usage: %s <family> <table> <setname> [<type:user_data>[ <type:user_data>...]]\n",
+ argv[0]
+ );
exit(EXIT_FAILURE);
}
@@ -94,7 +106,21 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- s = setup_set(family, argv[2], argv[3]);
+ if (argc >= 5) {
+ attrbuf = nftnl_attrbuf_alloc(ATTRBUF_SIZE);
+ if (!parse_user_data(argv, argc, attrbuf)) {
+ fprintf(stderr, "Error parsing user data\n");
+ free(attrbuf);
+ return EXIT_FAILURE;
+ }
+
+ s = setup_set(family, argv[2], argv[3],
+ (char *)nftnl_attrbuf_data(attrbuf),
+ nftnl_attrbuf_len(attrbuf)
+ );
+ } else {
+ s = setup_set(family, argv[2], argv[3], NULL, 0);
+ }
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
@@ -147,6 +173,25 @@ int main(int argc, char *argv[])
}
mnl_socket_close(nl);
+ if (attrbuf)
+ free(attrbuf);
return EXIT_SUCCESS;
}
+
+static bool parse_user_data(char *argv[], int argc,
+ struct nftnl_attrbuf *attrbuf)
+{
+ int i;
+ char *type, *value;
+
+ for (i = 4; i < argc; i++) {
+ type = strchr(argv[i], ':') - 1;
+ value = type + 2;
+ if (!nftnl_attr_put_check(attrbuf, ATTRBUF_SIZE, atoi(type),
+ strlen(value), value))
+ return false;
+ }
+
+ return true;
+}
--
2.6.4
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 7+ messages in thread