Parsing of dev_array fields in flowtable and chain are identical, merge them into a shared function nftnl_parse_devs() which does a quick scan through the nested attributes to check validity and calculate required array size instead of calling realloc() as needed. This required to align structs nftnl_chain and nftnl_flowtable field dev_array_len types, though uint32_t should match the size of int on both 32 and 64 bit architectures. Signed-off-by: Phil Sutter <phil@xxxxxx> --- include/utils.h | 4 ++++ src/chain.c | 41 +++-------------------------------------- src/flowtable.c | 40 ++-------------------------------------- src/utils.c | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 76 deletions(-) diff --git a/include/utils.h b/include/utils.h index eed61277595e2..dd8fbd05213b0 100644 --- a/include/utils.h +++ b/include/utils.h @@ -82,4 +82,8 @@ int nftnl_fprintf(FILE *fpconst, const void *obj, uint32_t cmd, uint32_t type, int nftnl_set_str_attr(const char **dptr, uint32_t *flags, uint16_t attr, const void *data, uint32_t data_len); +struct nlattr; +int nftnl_parse_devs(struct nlattr *nest, + const char ***dev_array_p, uint32_t *len_p); + #endif diff --git a/src/chain.c b/src/chain.c index 0b68939fe21a7..5bd2fc45b2137 100644 --- a/src/chain.c +++ b/src/chain.c @@ -38,7 +38,7 @@ struct nftnl_chain { const char *table; const char *dev; const char **dev_array; - int dev_array_len; + uint32_t dev_array_len; uint32_t family; uint32_t policy; uint32_t hooknum; @@ -664,42 +664,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 +687,8 @@ 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(tb[NFTA_HOOK_DEVS], + &c->dev_array, &c->dev_array_len); if (ret < 0) return -1; c->flags |= (1 << NFTNL_CHAIN_DEVICES); diff --git a/src/flowtable.c b/src/flowtable.c index 41a1456bb19b2..d54b3627371ef 100644 --- a/src/flowtable.c +++ b/src/flowtable.c @@ -402,43 +402,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 +419,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(tb[NFTA_FLOWTABLE_HOOK_DEVS], + &c->dev_array, &c->dev_array_len); if (ret < 0) return -1; c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES); diff --git a/src/utils.c b/src/utils.c index 2f1ffd6227583..9235806b2c95e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -19,6 +19,7 @@ #include <libnftnl/common.h> +#include <libmnl/libmnl.h> #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> @@ -150,3 +151,41 @@ int nftnl_set_str_attr(const char **dptr, uint32_t *flags, *flags |= (1 << attr); return 0; } + +int nftnl_parse_devs(struct nlattr *nest, + const char ***dev_array_p, uint32_t *len_p) +{ + struct nlattr *attr; + const char *dup; + int len = 0; + + mnl_attr_for_each_nested(attr, nest) { + if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME) + return -1; + len++; + } + + if (dev_array_p) { + *dev_array_p = calloc(len, sizeof(char *)); + if (!*dev_array_p) + return -1; + + len = 0; + mnl_attr_for_each_nested(attr, nest) { + dup = strdup(mnl_attr_get_str(attr)); + if (!dup) + goto err_free; + + (*dev_array_p)[len++] = dup; + } + } + if (len_p) + *len_p = len; + + return 0; +err_free: + while (len--) + xfree((*dev_array_p)[len]); + xfree(*dev_array_p); + return -1; +} -- 2.47.0