@@ -12,4 +12,5 @@ noinst_HEADERS = internal.h \
expr.h \
json.h \
set_elem.h \
+ attr.h \
utils.h
new file mode 100644
@@ -0,0 +1,29 @@
+#ifndef _LIBNFTNL_ATTR_INTERNAL_H_
+#define _LIBNFTNL_ATTR_INTERNAL_H_
+
+#include <stdint.h>
+
+/*
+ * TLV structures:
+ * nftnl_attr
+ * <-------- HEADER --------> <------ PAYLOAD ------>
+ * +------------+-------------+- - - - - - - - - - - -+
+ * | type | len | value |
+ * | (1 byte) | (1 byte) | |
+ * +--------------------------+- - - - - - - - - - - -+
+ * <-- sizeof(nftnl_attr) --> <-- nftnl_attr->len -->
+ * <------------- nftnl_attr_get_size() ------------>
+ */
+
+struct __attribute__((__packed__)) nftnl_attr {
+ uint8_t type;
+ uint8_t len;
+ unsigned char value[];
+};
+
+struct nftnl_attrbuf {
+ struct nftnl_attr *tail;
+ unsigned char data[];
+};
+
+#endif
@@ -7,4 +7,5 @@ pkginclude_HEADERS = batch.h \
set.h \
ruleset.h \
common.h \
+ attr.h \
gen.h
new file mode 100644
@@ -0,0 +1,68 @@
+#ifndef _LIBNFTNL_ATTR_H_
+#define _LIBNFTNL_ATTR_H_
+
+#include <stdio.h>
+#include <stdint.h>
+
+/*
+ * 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);
+
+size_t nftnl_attrbuf_get_len(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_get_size(const struct nftnl_attrbuf *attrbuf);
+void *nftnl_attrbuf_get_data(const struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_set_data(struct nftnl_attrbuf *attrbuf, const void *data,
+ size_t len);
+struct nftnl_attr *nftnl_attrbuf_get_head(const struct nftnl_attrbuf *attrbuf);
+struct nftnl_attr *nftnl_attrbuf_get_tail(const struct nftnl_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint8_t nftnl_attr_get_type(const struct nftnl_attr *attr);
+uint8_t nftnl_attr_get_len(const struct nftnl_attr *attr);
+void *nftnl_attr_get_value(const struct nftnl_attr *attr);
+uint16_t nftnl_attr_get_size(const struct nftnl_attr *attr);
+
+/* TLV attribute putters */
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+ uint8_t type, uint8_t len, const void *data);
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+ size_t bufsize, uint8_t type,
+ size_t len, const void *data);
+
+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_BINARY,
+ __NFTNL_ATTR_TYPE_MAX,
+};
+#define NFTNL_ATTR_TYPE_MAX (__NFTNL_ATTR_TYPE_MAX - 1)
+
+/* 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 *) \
+ nftnl_attr_get_value(nftnl_attrbuf_data(attrbuf)); \
+ (char *)(nftnl_attrbuf_tail(attrbuf)) > (char *)(attr); \
+ (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);
+
+#endif /* _LIBNFTNL_ATTR_H_ */
@@ -19,6 +19,7 @@ libnftnl_la_SOURCES = utils.c \
ruleset.c \
mxml.c \
jansson.c \
+ attr.c \
expr.c \
expr_ops.c \
expr/bitwise.c \
new file mode 100644
@@ -0,0 +1,208 @@
+#include <libnftnl/attr.h>
+#include <attr.h>
+#include <utils.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <ctype.h>
+
+
+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(nftnl_attrbuf_alloc);
+
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf)
+{
+ attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+}
+EXPORT_SYMBOL(nftnl_attrbuf_delete);
+
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf)
+{
+ nftnl_attrbuf_delete(attrbuf);
+ free((void *)attrbuf);
+}
+EXPORT_SYMBOL(nftnl_attrbuf_free);
+
+size_t nftnl_attrbuf_get_len(const struct nftnl_attrbuf *attrbuf)
+{
+ return (size_t)((char *)attrbuf->tail - (char *)attrbuf->data);
+}
+EXPORT_SYMBOL(nftnl_attrbuf_get_len);
+
+size_t nftnl_attrbuf_get_size(const struct nftnl_attrbuf *attrbuf)
+{
+ return (size_t)((char *)attrbuf->tail - (char *)attrbuf);
+}
+EXPORT_SYMBOL(nftnl_attrbuf_get_size);
+
+struct nftnl_attr *nftnl_attrbuf_get_head(const struct nftnl_attrbuf *attrbuf)
+{
+ return (struct nftnl_attr *)attrbuf->data;
+}
+EXPORT_SYMBOL(nftnl_attrbuf_get_head);
+
+struct nftnl_attr *nftnl_attrbuf_get_tail(const struct nftnl_attrbuf *attrbuf)
+{
+ return attrbuf->tail;
+}
+EXPORT_SYMBOL(nftnl_attrbuf_get_tail);
+
+void *nftnl_attrbuf_get_data(const struct nftnl_attrbuf *attrbuf)
+{
+ return (void *)attrbuf->data;
+}
+EXPORT_SYMBOL(nftnl_attrbuf_get_data);
+
+void nftnl_attrbuf_set_data(struct nftnl_attrbuf *attrbuf, const void *data,
+ size_t len)
+{
+ memcpy(attrbuf->data, data, len);
+ attrbuf->tail = (struct nftnl_attr *)(attrbuf->data + len);
+}
+EXPORT_SYMBOL(nftnl_attrbuf_set_data);
+
+uint8_t nftnl_attr_get_type(const struct nftnl_attr *attr)
+{
+ return attr->type;
+}
+EXPORT_SYMBOL(nftnl_attr_get_type);
+
+uint8_t nftnl_attr_get_len(const struct nftnl_attr *attr)
+{
+ return attr->len;
+}
+EXPORT_SYMBOL(nftnl_attr_get_len);
+
+void *nftnl_attr_get_value(const struct nftnl_attr *attr)
+{
+ return (void *)attr->value;
+}
+EXPORT_SYMBOL(nftnl_attr_get_value);
+
+uint16_t nftnl_attr_get_size(const struct nftnl_attr *attr)
+{
+ return (char *)nftnl_attr_next(attr) - (char *)attr;
+}
+EXPORT_SYMBOL(nftnl_attr_get_size);
+
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+ uint8_t type, uint8_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(nftnl_attr_put);
+
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+ size_t bufsize, uint8_t type,
+ size_t len, const void *data)
+{
+ // Check if there is enough space
+ if (bufsize <
+ len +
+ sizeof(struct nftnl_attr) +
+ nftnl_attrbuf_get_len(attrbuf)
+ )
+ return NULL;
+
+ return nftnl_attr_put(attrbuf, type, len, data);
+}
+EXPORT_SYMBOL(nftnl_attr_put_check);
+
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr)
+{
+ return (struct nftnl_attr *)&attr->value[attr->len];
+}
+EXPORT_SYMBOL(nftnl_attr_next);
+
+static int __attr_snprint(const struct nftnl_attr *attr,
+ char *buf, size_t bsize)
+{
+ int i;
+ int written, blen, boffset;
+ uint8_t alen;
+ char *aval;
+
+ 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);
+
+ 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);
+ }
+ if (boffset) {
+ /* delete last comma */
+ boffset--;
+ *(buf + boffset) = '\0';
+ }
+
+ return boffset;
+}
+EXPORT_SYMBOL(nftnl_attr_payload_snprint);
@@ -336,6 +336,24 @@ global:
nftnl_set_snprintf;
nftnl_set_fprintf;
+ nftnl_attrbuf_alloc;
+ nftnl_attrbuf_delete;
+ nftnl_attrbuf_free;
+ nftnl_attrbuf_get_len;
+ nftnl_attrbuf_get_size;
+ nftnl_attrbuf_get_head;
+ nftnl_attrbuf_get_tail;
+ nftnl_attrbuf_get_data;
+ nftnl_attrbuf_set_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_next;
+ nftnl_attr_payload_snprint;
+
nftnl_set_list_alloc;
nftnl_set_list_free;
nftnl_set_list_add;
These functions allow to create a buffer (nftnl_attrbuf) of TLV objects (nftnl_attr). It is inspired by libmnl/src/attr.c. Example usage: ``` char print_buf[PBUF_SIZE]; struct nftnl_attrbuf *attrbuf; const char str[] = "Hello World!"; attrbuf = nftnl_attrbuf_alloc(ATTRBUF_SIZE); if (!nftnl_attr_put_check(attrbuf, ATTRBUF_SIZE, NFTNL_ATTR_TYPE_STRING, strlen(str), str)) { fprintf(stderr, "Can't put attribute \"%s\"", str); } nftnl_attr_payload_snprint(nftnl_attrbuf_data(attrbuf), nftnl_attrbuf_len(attrbuf), print_buf, PBUF_SIZE); printf("attrbuf = { %s }\n", print_buf); free (attrbuf); ``` Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net> --- include/Makefile.am | 1 + include/attr.h | 29 ++++++ include/libnftnl/Makefile.am | 1 + include/libnftnl/attr.h | 68 ++++++++++++++ src/Makefile.am | 1 + src/attr.c | 208 +++++++++++++++++++++++++++++++++++++++++++ src/libnftnl.map | 18 ++++ 7 files changed, 326 insertions(+) create mode 100644 include/attr.h create mode 100644 include/libnftnl/attr.h create mode 100644 src/attr.c