]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
Introduce struct nftnl_str_array
authorPhil Sutter <phil@nwl.cc>
Mon, 30 Aug 2021 12:38:27 +0000 (14:38 +0200)
committerPhil Sutter <phil@nwl.cc>
Tue, 29 Oct 2024 22:26:43 +0000 (23:26 +0100)
This data structure holds an array of allocated strings for use in
nftnl_chain and nftnl_flowtable structs. For convenience, implement
functions to clear, populate and iterate over contents.

While at it, extend chain and flowtable tests to cover these attributes,
too.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/Makefile.am
include/internal.h
include/str_array.h [new file with mode: 0644]
src/Makefile.am
src/chain.c
src/flowtable.c
src/str_array.c [new file with mode: 0644]
tests/nft-chain-test.c
tests/nft-flowtable-test.c

index 738f80708ca0fc60f0900b0b7089e7ac664a1ee5..665532a01b9d162c4bc4a47a751ff40ab5bc63fc 100644 (file)
@@ -11,5 +11,6 @@ noinst_HEADERS = internal.h   \
                 expr.h         \
                 rule.h         \
                 set_elem.h     \
+                str_array.h    \
                 udata.h        \
                 utils.h
index 1f96731589c0418f3379c6e49c7da1861aed3a19..b8fc7f129c76e4928eec8d2c81c55fe00f526881 100644 (file)
@@ -12,5 +12,6 @@
 #include "expr.h"
 #include "expr_ops.h"
 #include "rule.h"
+#include "str_array.h"
 
 #endif /* _LIBNFTNL_INTERNAL_H_ */
diff --git a/include/str_array.h b/include/str_array.h
new file mode 100644 (file)
index 0000000..98c9b4f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef LIBNFTNL_STR_ARRAY_H
+#define LIBNFTNL_STR_ARRAY_H 1
+
+#include <stdint.h>
+
+struct nlattr;
+
+struct nftnl_str_array {
+       char            **array;
+       uint32_t        len;
+};
+
+void nftnl_str_array_clear(struct nftnl_str_array *sa);
+int nftnl_str_array_set(struct nftnl_str_array *sa, const char * const *array);
+int nftnl_parse_devs(struct nftnl_str_array *sa, const struct nlattr *nest);
+
+#define nftnl_str_array_foreach(ptr, sa, idx)  \
+       for (idx = 0, ptr = (sa)->array[idx];   \
+            idx < (sa)->len;                   \
+            ptr = (sa)->array[++idx])
+
+#endif /* LIBNFTNL_STR_ARRAY_H */
index 3cd259c04d1c33f3057466f67573211bda835848..1c38d00c4e180f9346fc62d43707499be5547197 100644 (file)
@@ -17,6 +17,7 @@ libnftnl_la_SOURCES = utils.c         \
                      rule.c            \
                      set.c             \
                      set_elem.c        \
+                     str_array.c       \
                      ruleset.c         \
                      udata.c           \
                      expr.c            \
index 0b68939fe21a7a725503625444eee680cd29d6a8..c9fbc3a87314b6fc21d73909c64ed81f2bafeebf 100644 (file)
@@ -37,8 +37,7 @@ struct nftnl_chain {
        const char      *type;
        const char      *table;
        const char      *dev;
-       const char      **dev_array;
-       int             dev_array_len;
+       struct nftnl_str_array  dev_array;
        uint32_t        family;
        uint32_t        policy;
        uint32_t        hooknum;
@@ -117,7 +116,6 @@ EXPORT_SYMBOL(nftnl_chain_free);
 void nftnl_chain_free(const struct nftnl_chain *c)
 {
        struct nftnl_rule *r, *tmp;
-       int i;
 
        list_for_each_entry_safe(r, tmp, &c->rule_list, head)
                nftnl_rule_free(r);
@@ -132,12 +130,8 @@ void nftnl_chain_free(const struct nftnl_chain *c)
                xfree(c->dev);
        if (c->flags & (1 << NFTNL_CHAIN_USERDATA))
                xfree(c->user.data);
-       if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
-               for (i = 0; i < c->dev_array_len; i++)
-                       xfree(c->dev_array[i]);
-
-               xfree(c->dev_array);
-       }
+       if (c->flags & (1 << NFTNL_CHAIN_DEVICES))
+               nftnl_str_array_clear((struct nftnl_str_array *)&c->dev_array);
        xfree(c);
 }
 
@@ -150,8 +144,6 @@ bool nftnl_chain_is_set(const struct nftnl_chain *c, uint16_t attr)
 EXPORT_SYMBOL(nftnl_chain_unset);
 void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
 {
-       int i;
-
        if (!(c->flags & (1 << attr)))
                return;
 
@@ -181,9 +173,7 @@ void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
                xfree(c->dev);
                break;
        case NFTNL_CHAIN_DEVICES:
-               for (i = 0; i < c->dev_array_len; i++)
-                       xfree(c->dev_array[i]);
-               xfree(c->dev_array);
+               nftnl_str_array_clear(&c->dev_array);
                break;
        case NFTNL_CHAIN_USERDATA:
                xfree(c->user.data);
@@ -212,9 +202,6 @@ EXPORT_SYMBOL(nftnl_chain_set_data);
 int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
                         const void *data, uint32_t data_len)
 {
-       const char **dev_array;
-       int len = 0, i;
-
        nftnl_assert_attr_exists(attr, NFTNL_CHAIN_MAX);
        nftnl_assert_validate(data, nftnl_chain_validate, attr, data_len);
 
@@ -256,24 +243,8 @@ int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
                return nftnl_set_str_attr(&c->dev, &c->flags,
                                          attr, data, data_len);
        case NFTNL_CHAIN_DEVICES:
-               dev_array = (const char **)data;
-               while (dev_array[len] != NULL)
-                       len++;
-
-               if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
-                       for (i = 0; i < c->dev_array_len; i++)
-                               xfree(c->dev_array[i]);
-                       xfree(c->dev_array);
-               }
-
-               c->dev_array = calloc(len + 1, sizeof(char *));
-               if (!c->dev_array)
+               if (nftnl_str_array_set(&c->dev_array, data) < 0)
                        return -1;
-
-               for (i = 0; i < len; i++)
-                       c->dev_array[i] = strdup(dev_array[i]);
-
-               c->dev_array_len = len;
                break;
        case NFTNL_CHAIN_FLAGS:
                memcpy(&c->chain_flags, data, sizeof(c->chain_flags));
@@ -385,7 +356,7 @@ const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
                return c->dev;
        case NFTNL_CHAIN_DEVICES:
                *data_len = 0;
-               return &c->dev_array[0];
+               return c->dev_array.array;
        case NFTNL_CHAIN_FLAGS:
                *data_len = sizeof(uint32_t);
                return &c->chain_flags;
@@ -493,11 +464,11 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch
                mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
        else if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
                struct nlattr *nest_dev;
+               const char *dev;
 
                nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
-               for (i = 0; i < c->dev_array_len; i++)
-                       mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
-                                         c->dev_array[i]);
+               nftnl_str_array_foreach(dev, &c->dev_array, i)
+                       mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev);
                mnl_attr_nest_end(nlh, nest_dev);
        }
 
@@ -664,42 +635,6 @@ static int nftnl_chain_parse_hook_cb(const struct nlattr *attr, void *data)
        return MNL_CB_OK;
 }
 
-static int nftnl_chain_parse_devs(struct nlattr *nest, struct nftnl_chain *c)
-{
-       const char **dev_array, **tmp;
-       int len = 0, size = 8;
-       struct nlattr *attr;
-
-       dev_array = calloc(8, sizeof(char *));
-       if (!dev_array)
-               return -1;
-
-       mnl_attr_for_each_nested(attr, nest) {
-               if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
-                       goto err;
-               dev_array[len++] = strdup(mnl_attr_get_str(attr));
-               if (len >= size) {
-                       tmp = realloc(dev_array, size * 2 * sizeof(char *));
-                       if (!tmp)
-                               goto err;
-
-                       size *= 2;
-                       memset(&tmp[len], 0, (size - len) * sizeof(char *));
-                       dev_array = tmp;
-               }
-       }
-
-       c->dev_array = dev_array;
-       c->dev_array_len = len;
-
-       return 0;
-err:
-       while (len--)
-               xfree(dev_array[len]);
-       xfree(dev_array);
-       return -1;
-}
-
 static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
 {
        struct nlattr *tb[NFTA_HOOK_MAX+1] = {};
@@ -723,7 +658,7 @@ static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
                c->flags |= (1 << NFTNL_CHAIN_DEV);
        }
        if (tb[NFTA_HOOK_DEVS]) {
-               ret = nftnl_chain_parse_devs(tb[NFTA_HOOK_DEVS], c);
+               ret = nftnl_parse_devs(&c->dev_array, tb[NFTA_HOOK_DEVS]);
                if (ret < 0)
                        return -1;
                c->flags |= (1 << NFTNL_CHAIN_DEVICES);
@@ -823,6 +758,7 @@ static int nftnl_chain_snprintf_default(char *buf, size_t remain,
                                        const struct nftnl_chain *c)
 {
        int ret, offset = 0, i;
+       const char *dev;
 
        ret = snprintf(buf, remain, "%s %s %s use %u",
                       nftnl_family2str(c->family), c->table, c->name, c->use);
@@ -854,9 +790,9 @@ static int nftnl_chain_snprintf_default(char *buf, size_t remain,
                        ret = snprintf(buf + offset, remain, " dev { ");
                        SNPRINTF_BUFFER_SIZE(ret, remain, offset);
 
-                       for (i = 0; i < c->dev_array_len; i++) {
+                       nftnl_str_array_foreach(dev, &c->dev_array, i) {
                                ret = snprintf(buf + offset, remain, " %s ",
-                                              c->dev_array[i]);
+                                              dev);
                                SNPRINTF_BUFFER_SIZE(ret, remain, offset);
                        }
                        ret = snprintf(buf + offset, remain, " } ");
index 41a1456bb19b2d09673a1490c8206179fae4d6d3..2a8d374541b0b2de45192bca47b5ce8430880dd8 100644 (file)
@@ -26,8 +26,7 @@ struct nftnl_flowtable {
        uint32_t                hooknum;
        int32_t                 prio;
        uint32_t                size;
-       const char              **dev_array;
-       uint32_t                dev_array_len;
+       struct nftnl_str_array  dev_array;
        uint32_t                ft_flags;
        uint32_t                use;
        uint32_t                flags;
@@ -43,18 +42,12 @@ struct nftnl_flowtable *nftnl_flowtable_alloc(void)
 EXPORT_SYMBOL(nftnl_flowtable_free);
 void nftnl_flowtable_free(const struct nftnl_flowtable *c)
 {
-       int i;
-
        if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
                xfree(c->name);
        if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
                xfree(c->table);
-       if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
-               for (i = 0; i < c->dev_array_len; i++)
-                       xfree(c->dev_array[i]);
-
-               xfree(c->dev_array);
-       }
+       if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES))
+               nftnl_str_array_clear((struct nftnl_str_array *)&c->dev_array);
        xfree(c);
 }
 
@@ -67,8 +60,6 @@ bool nftnl_flowtable_is_set(const struct nftnl_flowtable *c, uint16_t attr)
 EXPORT_SYMBOL(nftnl_flowtable_unset);
 void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr)
 {
-       int i;
-
        if (!(c->flags & (1 << attr)))
                return;
 
@@ -87,9 +78,7 @@ void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr)
        case NFTNL_FLOWTABLE_HANDLE:
                break;
        case NFTNL_FLOWTABLE_DEVICES:
-               for (i = 0; i < c->dev_array_len; i++)
-                       xfree(c->dev_array[i]);
-               xfree(c->dev_array);
+               nftnl_str_array_clear(&c->dev_array);
                break;
        default:
                return;
@@ -111,9 +100,6 @@ EXPORT_SYMBOL(nftnl_flowtable_set_data);
 int nftnl_flowtable_set_data(struct nftnl_flowtable *c, uint16_t attr,
                             const void *data, uint32_t data_len)
 {
-       const char **dev_array;
-       int len = 0, i;
-
        nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
        nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
 
@@ -135,24 +121,8 @@ int nftnl_flowtable_set_data(struct nftnl_flowtable *c, uint16_t attr,
                memcpy(&c->family, data, sizeof(c->family));
                break;
        case NFTNL_FLOWTABLE_DEVICES:
-               dev_array = (const char **)data;
-               while (dev_array[len] != NULL)
-                       len++;
-
-               if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
-                       for (i = 0; i < c->dev_array_len; i++)
-                               xfree(c->dev_array[i]);
-                       xfree(c->dev_array);
-               }
-
-               c->dev_array = calloc(len + 1, sizeof(char *));
-               if (!c->dev_array)
+               if (nftnl_str_array_set(&c->dev_array, data) < 0)
                        return -1;
-
-               for (i = 0; i < len; i++)
-                       c->dev_array[i] = strdup(dev_array[i]);
-
-               c->dev_array_len = len;
                break;
        case NFTNL_FLOWTABLE_SIZE:
                memcpy(&c->size, data, sizeof(c->size));
@@ -230,7 +200,7 @@ const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c,
                return &c->family;
        case NFTNL_FLOWTABLE_DEVICES:
                *data_len = 0;
-               return &c->dev_array[0];
+               return c->dev_array.array;
        case NFTNL_FLOWTABLE_SIZE:
                *data_len = sizeof(int32_t);
                return &c->size;
@@ -325,12 +295,11 @@ void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh,
 
        if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
                struct nlattr *nest_dev;
+               const char *dev;
 
                nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
-               for (i = 0; i < c->dev_array_len; i++) {
-                       mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
-                                         c->dev_array[i]);
-               }
+               nftnl_str_array_foreach(dev, &c->dev_array, i)
+                       mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev);
                mnl_attr_nest_end(nlh, nest_dev);
        }
 
@@ -402,43 +371,6 @@ static int nftnl_flowtable_parse_hook_cb(const struct nlattr *attr, void *data)
        return MNL_CB_OK;
 }
 
-static int nftnl_flowtable_parse_devs(struct nlattr *nest,
-                                     struct nftnl_flowtable *c)
-{
-       const char **dev_array, **tmp;
-       int len = 0, size = 8;
-       struct nlattr *attr;
-
-       dev_array = calloc(8, sizeof(char *));
-       if (!dev_array)
-               return -1;
-
-       mnl_attr_for_each_nested(attr, nest) {
-               if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
-                       goto err;
-               dev_array[len++] = strdup(mnl_attr_get_str(attr));
-               if (len >= size) {
-                       tmp = realloc(dev_array, size * 2 * sizeof(char *));
-                       if (!tmp)
-                               goto err;
-
-                       size *= 2;
-                       memset(&tmp[len], 0, (size - len) * sizeof(char *));
-                       dev_array = tmp;
-               }
-       }
-
-       c->dev_array = dev_array;
-       c->dev_array_len = len;
-
-       return 0;
-err:
-       while (len--)
-               xfree(dev_array[len]);
-       xfree(dev_array);
-       return -1;
-}
-
 static int nftnl_flowtable_parse_hook(struct nlattr *attr, struct nftnl_flowtable *c)
 {
        struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
@@ -456,7 +388,8 @@ static int nftnl_flowtable_parse_hook(struct nlattr *attr, struct nftnl_flowtabl
                c->flags |= (1 << NFTNL_FLOWTABLE_PRIO);
        }
        if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
-               ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
+               ret = nftnl_parse_devs(&c->dev_array,
+                                      tb[NFTA_FLOWTABLE_HOOK_DEVS]);
                if (ret < 0)
                        return -1;
                c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
@@ -587,6 +520,7 @@ static int nftnl_flowtable_snprintf_default(char *buf, size_t remain,
                                            const struct nftnl_flowtable *c)
 {
        int ret, offset = 0, i;
+       const char *dev;
 
        ret = snprintf(buf, remain, "flow table %s %s use %u size %u flags %x",
                       c->table, c->name, c->use, c->size, c->ft_flags);
@@ -602,9 +536,9 @@ static int nftnl_flowtable_snprintf_default(char *buf, size_t remain,
                        ret = snprintf(buf + offset, remain, " dev { ");
                        SNPRINTF_BUFFER_SIZE(ret, remain, offset);
 
-                       for (i = 0; i < c->dev_array_len; i++) {
+                       nftnl_str_array_foreach(dev, &c->dev_array, i) {
                                ret = snprintf(buf + offset, remain, " %s ",
-                                              c->dev_array[i]);
+                                              dev);
                                SNPRINTF_BUFFER_SIZE(ret, remain, offset);
                        }
                        ret = snprintf(buf + offset, remain, " } ");
diff --git a/src/str_array.c b/src/str_array.c
new file mode 100644 (file)
index 0000000..63471bd
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * (C) 2024 Red Hat GmbH
+ * Author: Phil Sutter <phil@nwl.cc>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include "str_array.h"
+#include "utils.h"
+
+void nftnl_str_array_clear(struct nftnl_str_array *sa)
+{
+       while (sa->len > 0)
+               free(sa->array[--sa->len]);
+       free(sa->array);
+}
+
+int nftnl_str_array_set(struct nftnl_str_array *sa, const char * const *array)
+{
+       int len = 0;
+
+       while (array[len])
+               len++;
+
+       nftnl_str_array_clear(sa);
+       sa->array = calloc(len + 1, sizeof(char *));
+       if (!sa->array)
+               return -1;
+
+       while (sa->len < len) {
+               sa->array[sa->len] = strdup(array[sa->len]);
+               if (!sa->array[sa->len]) {
+                       nftnl_str_array_clear(sa);
+                       return -1;
+               }
+               sa->len++;
+       }
+       return 0;
+}
+
+int nftnl_parse_devs(struct nftnl_str_array *sa, const struct nlattr *nest)
+{
+       struct nlattr *attr;
+       int len = 0;
+
+       mnl_attr_for_each_nested(attr, nest) {
+               if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
+                       return -1;
+               len++;
+       }
+
+       nftnl_str_array_clear(sa);
+       sa->array = calloc(len + 1, sizeof(char *));
+       if (!sa->array)
+               return -1;
+
+       mnl_attr_for_each_nested(attr, nest) {
+               sa->array[sa->len] = strdup(mnl_attr_get_str(attr));
+               if (!sa->array[sa->len]) {
+                       nftnl_str_array_clear(sa);
+                       return -1;
+               }
+               sa->len++;
+       }
+       return 0;
+}
index 35a65be8d1587ff7e7244dc56e8c4131898364d3..64c506eb62a1506b246e9ba67f1f53d498409768 100644 (file)
@@ -23,9 +23,25 @@ static void print_err(const char *msg)
        printf("\033[31mERROR:\e[0m %s\n", msg);
 }
 
-static void cmp_nftnl_chain(struct nftnl_chain *a, struct nftnl_chain *b)
+static void cmp_devices(const char * const *adevs,
+                       const char * const *bdevs)
 {
+       int i;
+
+       if (!adevs && !bdevs)
+               return;
+       if (!!adevs ^ !!bdevs)
+               print_err("Chain devices mismatches");
+       for (i = 0; adevs[i] && bdevs[i]; i++) {
+               if (strcmp(adevs[i], bdevs[i]))
+                       break;
+       }
+       if (adevs[i] || bdevs[i])
+               print_err("Chain devices mismatches");
+}
 
+static void cmp_nftnl_chain(struct nftnl_chain *a, struct nftnl_chain *b)
+{
        if (strcmp(nftnl_chain_get_str(a, NFTNL_CHAIN_NAME),
                   nftnl_chain_get_str(b, NFTNL_CHAIN_NAME)) != 0)
                print_err("Chain name mismatches");
@@ -59,13 +75,17 @@ static void cmp_nftnl_chain(struct nftnl_chain *a, struct nftnl_chain *b)
        if (strcmp(nftnl_chain_get_str(a, NFTNL_CHAIN_TYPE),
                   nftnl_chain_get_str(b, NFTNL_CHAIN_TYPE)) != 0)
                print_err("Chain type mismatches");
-       if (strcmp(nftnl_chain_get_str(a, NFTNL_CHAIN_DEV),
+       if (nftnl_chain_is_set(a, NFTNL_CHAIN_DEV) &&
+           strcmp(nftnl_chain_get_str(a, NFTNL_CHAIN_DEV),
                   nftnl_chain_get_str(b, NFTNL_CHAIN_DEV)) != 0)
                print_err("Chain device mismatches");
+       cmp_devices(nftnl_chain_get_array(a, NFTNL_CHAIN_DEVICES),
+                   nftnl_chain_get_array(b, NFTNL_CHAIN_DEVICES));
 }
 
 int main(int argc, char *argv[])
 {
+       const char *devs[] = { "eth0", "eth1", "eth2", NULL };
        struct nftnl_chain *a, *b;
        char buf[4096];
        struct nlmsghdr *nlh;
@@ -97,6 +117,19 @@ int main(int argc, char *argv[])
 
        cmp_nftnl_chain(a, b);
 
+       /* repeat test with multiple devices */
+
+       nftnl_chain_unset(a, NFTNL_CHAIN_DEV);
+       nftnl_chain_set_array(a, NFTNL_CHAIN_DEVICES, devs);
+
+       nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET, 0, 1234);
+       nftnl_chain_nlmsg_build_payload(nlh, a);
+
+       if (nftnl_chain_nlmsg_parse(nlh, b) < 0)
+               print_err("parsing problems");
+
+       cmp_nftnl_chain(a, b);
+
        nftnl_chain_free(a);
        nftnl_chain_free(b);
 
index 8ab8d4c5347a42241b0d753154e3fccd927c25a4..49bc0a1c5e04358dda96974ea7b81a2766a33a24 100644 (file)
@@ -13,6 +13,23 @@ static void print_err(const char *msg)
        printf("\033[31mERROR:\e[0m %s\n", msg);
 }
 
+static void cmp_devices(const char * const *adevs,
+                       const char * const *bdevs)
+{
+       int i;
+
+       if (!adevs && !bdevs)
+               return;
+       if (!!adevs ^ !!bdevs)
+               print_err("Flowtable devices mismatches");
+       for (i = 0; adevs[i] && bdevs[i]; i++) {
+               if (strcmp(adevs[i], bdevs[i]))
+                       break;
+       }
+       if (adevs[i] || bdevs[i])
+               print_err("Flowtable devices mismatches");
+}
+
 static void cmp_nftnl_flowtable(struct nftnl_flowtable *a, struct nftnl_flowtable *b)
 {
        if (strcmp(nftnl_flowtable_get_str(a, NFTNL_FLOWTABLE_NAME),
@@ -44,10 +61,13 @@ static void cmp_nftnl_flowtable(struct nftnl_flowtable *a, struct nftnl_flowtabl
        if (nftnl_flowtable_get_u64(a, NFTNL_FLOWTABLE_HANDLE) !=
            nftnl_flowtable_get_u64(b, NFTNL_FLOWTABLE_HANDLE))
                print_err("Flowtable handle mismatches");
+       cmp_devices(nftnl_flowtable_get_array(a, NFTNL_FLOWTABLE_DEVICES),
+                   nftnl_flowtable_get_array(b, NFTNL_FLOWTABLE_DEVICES));
 }
 
 int main(int argc, char *argv[])
 {
+       const char *devs[] = { "eth0", "eth1", "eth2", NULL };
        struct nftnl_flowtable *a, *b;
        char buf[4096];
        struct nlmsghdr *nlh;
@@ -66,6 +86,7 @@ int main(int argc, char *argv[])
        nftnl_flowtable_set_u32(a, NFTNL_FLOWTABLE_SIZE, 0x89016745);
        nftnl_flowtable_set_u32(a, NFTNL_FLOWTABLE_FLAGS, 0x45016723);
        nftnl_flowtable_set_u64(a, NFTNL_FLOWTABLE_HANDLE, 0x2345016789);
+       nftnl_flowtable_set_array(a, NFTNL_FLOWTABLE_DEVICES, devs);
 
        nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_NEWFLOWTABLE, AF_INET,
                                    0, 1234);