Commit 07114590 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) Add support for the catch-all set element. This special element
   can be used to define a default action to be applied in case that
   the set lookup returns no matching element.

2) Fix incorrect #ifdef dependencies in the nftables cgroupsv2
   support, from Arnd Bergmann.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 69e16d01 7acc0bb4
...@@ -497,6 +497,7 @@ struct nft_set { ...@@ -497,6 +497,7 @@ struct nft_set {
u8 dlen; u8 dlen;
u8 num_exprs; u8 num_exprs;
struct nft_expr *exprs[NFT_SET_EXPR_MAX]; struct nft_expr *exprs[NFT_SET_EXPR_MAX];
struct list_head catchall_list;
unsigned char data[] unsigned char data[]
__attribute__((aligned(__alignof__(u64)))); __attribute__((aligned(__alignof__(u64))));
}; };
...@@ -522,6 +523,10 @@ struct nft_set *nft_set_lookup_global(const struct net *net, ...@@ -522,6 +523,10 @@ struct nft_set *nft_set_lookup_global(const struct net *net,
const struct nlattr *nla_set_id, const struct nlattr *nla_set_id,
u8 genmask); u8 genmask);
struct nft_set_ext *nft_set_catchall_lookup(const struct net *net,
const struct nft_set *set);
void *nft_set_catchall_gc(const struct nft_set *set);
static inline unsigned long nft_set_gc_interval(const struct nft_set *set) static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
{ {
return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ; return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ;
......
...@@ -398,9 +398,11 @@ enum nft_set_attributes { ...@@ -398,9 +398,11 @@ enum nft_set_attributes {
* enum nft_set_elem_flags - nf_tables set element flags * enum nft_set_elem_flags - nf_tables set element flags
* *
* @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
* @NFT_SET_ELEM_CATCHALL: special catch-all element
*/ */
enum nft_set_elem_flags { enum nft_set_elem_flags {
NFT_SET_ELEM_INTERVAL_END = 0x1, NFT_SET_ELEM_INTERVAL_END = 0x1,
NFT_SET_ELEM_CATCHALL = 0x2,
}; };
/** /**
......
...@@ -4389,6 +4389,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -4389,6 +4389,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
} }
INIT_LIST_HEAD(&set->bindings); INIT_LIST_HEAD(&set->bindings);
INIT_LIST_HEAD(&set->catchall_list);
set->table = table; set->table = table;
write_pnet(&set->net, net); write_pnet(&set->net, net);
set->ops = ops; set->ops = ops;
...@@ -4434,6 +4435,24 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -4434,6 +4435,24 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
return err; return err;
} }
struct nft_set_elem_catchall {
struct list_head list;
struct rcu_head rcu;
void *elem;
};
static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
struct nft_set *set)
{
struct nft_set_elem_catchall *catchall;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
list_del_rcu(&catchall->list);
nft_set_elem_destroy(set, catchall->elem, true);
kfree_rcu(catchall);
}
}
static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
{ {
int i; int i;
...@@ -4445,6 +4464,7 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) ...@@ -4445,6 +4464,7 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
nft_expr_destroy(ctx, set->exprs[i]); nft_expr_destroy(ctx, set->exprs[i]);
set->ops->destroy(set); set->ops->destroy(set);
nft_set_catchall_destroy(ctx, set);
kfree(set->name); kfree(set->name);
kvfree(set); kvfree(set);
} }
...@@ -4499,9 +4519,8 @@ static int nft_validate_register_store(const struct nft_ctx *ctx, ...@@ -4499,9 +4519,8 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
enum nft_data_types type, enum nft_data_types type,
unsigned int len); unsigned int len);
static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, static int nft_setelem_data_validate(const struct nft_ctx *ctx,
struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter,
struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
...@@ -4514,6 +4533,37 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, ...@@ -4514,6 +4533,37 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
set->dlen); set->dlen);
} }
static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
struct nft_set *set,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
return nft_setelem_data_validate(ctx, set, elem);
}
static int nft_set_catchall_bind_check(const struct nft_ctx *ctx,
struct nft_set *set)
{
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set_elem_catchall *catchall;
struct nft_set_elem elem;
struct nft_set_ext *ext;
int ret = 0;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
continue;
elem.priv = catchall->elem;
ret = nft_setelem_data_validate(ctx, set, &elem);
if (ret < 0)
break;
}
return ret;
}
int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding) struct nft_set_binding *binding)
{ {
...@@ -4543,6 +4593,9 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -4543,6 +4593,9 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
iter.fn = nf_tables_bind_check_setelem; iter.fn = nf_tables_bind_check_setelem;
set->ops->walk(ctx, set, &iter); set->ops->walk(ctx, set, &iter);
if (!iter.err)
iter.err = nft_set_catchall_bind_check(ctx, set);
if (iter.err < 0) if (iter.err < 0)
return iter.err; return iter.err;
} }
...@@ -4729,7 +4782,8 @@ static int nf_tables_fill_setelem(struct sk_buff *skb, ...@@ -4729,7 +4782,8 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
if (nest == NULL) if (nest == NULL)
goto nla_put_failure; goto nla_put_failure;
if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, nft_set_ext_key(ext), if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY) &&
nft_data_dump(skb, NFTA_SET_ELEM_KEY, nft_set_ext_key(ext),
NFT_DATA_VALUE, set->klen) < 0) NFT_DATA_VALUE, set->klen) < 0)
goto nla_put_failure; goto nla_put_failure;
...@@ -4818,6 +4872,29 @@ struct nft_set_dump_ctx { ...@@ -4818,6 +4872,29 @@ struct nft_set_dump_ctx {
struct nft_ctx ctx; struct nft_ctx ctx;
}; };
static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
const struct nft_set *set)
{
struct nft_set_elem_catchall *catchall;
u8 genmask = nft_genmask_cur(net);
struct nft_set_elem elem;
struct nft_set_ext *ext;
int ret = 0;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask) ||
nft_set_elem_expired(ext))
continue;
elem.priv = catchall->elem;
ret = nf_tables_fill_setelem(skb, set, &elem);
break;
}
return ret;
}
static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
{ {
struct nft_set_dump_ctx *dump_ctx = cb->data; struct nft_set_dump_ctx *dump_ctx = cb->data;
...@@ -4882,6 +4959,9 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -4882,6 +4959,9 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
args.iter.err = 0; args.iter.err = 0;
args.iter.fn = nf_tables_dump_setelem; args.iter.fn = nf_tables_dump_setelem;
set->ops->walk(&dump_ctx->ctx, set, &args.iter); set->ops->walk(&dump_ctx->ctx, set, &args.iter);
if (!args.iter.err && args.iter.count == cb->args[0])
args.iter.err = nft_set_catchall_dump(net, skb, set);
rcu_read_unlock(); rcu_read_unlock();
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
...@@ -4961,8 +5041,8 @@ static int nft_setelem_parse_flags(const struct nft_set *set, ...@@ -4961,8 +5041,8 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
return 0; return 0;
*flags = ntohl(nla_get_be32(attr)); *flags = ntohl(nla_get_be32(attr));
if (*flags & ~NFT_SET_ELEM_INTERVAL_END) if (*flags & ~(NFT_SET_ELEM_INTERVAL_END | NFT_SET_ELEM_CATCHALL))
return -EINVAL; return -EOPNOTSUPP;
if (!(set->flags & NFT_SET_INTERVAL) && if (!(set->flags & NFT_SET_INTERVAL) &&
*flags & NFT_SET_ELEM_INTERVAL_END) *flags & NFT_SET_ELEM_INTERVAL_END)
return -EINVAL; return -EINVAL;
...@@ -5007,6 +5087,46 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5007,6 +5087,46 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
return 0; return 0;
} }
static void *nft_setelem_catchall_get(const struct net *net,
const struct nft_set *set)
{
struct nft_set_elem_catchall *catchall;
u8 genmask = nft_genmask_cur(net);
struct nft_set_ext *ext;
void *priv = NULL;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask) ||
nft_set_elem_expired(ext))
continue;
priv = catchall->elem;
break;
}
return priv;
}
static int nft_setelem_get(struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_elem *elem, u32 flags)
{
void *priv;
if (!(flags & NFT_SET_ELEM_CATCHALL)) {
priv = set->ops->get(ctx->net, set, elem, flags);
if (IS_ERR(priv))
return PTR_ERR(priv);
} else {
priv = nft_setelem_catchall_get(ctx->net, set);
if (!priv)
return -ENOENT;
}
elem->priv = priv;
return 0;
}
static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr) const struct nlattr *attr)
{ {
...@@ -5014,7 +5134,6 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5014,7 +5134,6 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_elem elem; struct nft_set_elem elem;
struct sk_buff *skb; struct sk_buff *skb;
uint32_t flags = 0; uint32_t flags = 0;
void *priv;
int err; int err;
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr, err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
...@@ -5022,17 +5141,19 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5022,17 +5141,19 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0) if (err < 0)
return err; return err;
if (!nla[NFTA_SET_ELEM_KEY])
return -EINVAL;
err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags); err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
if (err < 0) if (err < 0)
return err; return err;
if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
return -EINVAL;
if (nla[NFTA_SET_ELEM_KEY]) {
err = nft_setelem_parse_key(ctx, set, &elem.key.val, err = nft_setelem_parse_key(ctx, set, &elem.key.val,
nla[NFTA_SET_ELEM_KEY]); nla[NFTA_SET_ELEM_KEY]);
if (err < 0) if (err < 0)
return err; return err;
}
if (nla[NFTA_SET_ELEM_KEY_END]) { if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val, err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
...@@ -5041,11 +5162,9 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5041,11 +5162,9 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
return err; return err;
} }
priv = set->ops->get(ctx->net, set, &elem, flags); err = nft_setelem_get(ctx, set, &elem, flags);
if (IS_ERR(priv)) if (err < 0)
return PTR_ERR(priv); return err;
elem.priv = priv;
err = -ENOMEM; err = -ENOMEM;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
...@@ -5205,6 +5324,7 @@ void *nft_set_elem_init(const struct nft_set *set, ...@@ -5205,6 +5324,7 @@ void *nft_set_elem_init(const struct nft_set *set,
ext = nft_set_elem_ext(set, elem); ext = nft_set_elem_ext(set, elem);
nft_set_ext_init(ext, tmpl); nft_set_ext_init(ext, tmpl);
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY))
memcpy(nft_set_ext_key(ext), key, set->klen); memcpy(nft_set_ext_key(ext), key, set->klen);
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
memcpy(nft_set_ext_key_end(ext), key_end, set->klen); memcpy(nft_set_ext_key_end(ext), key_end, set->klen);
...@@ -5263,8 +5383,8 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem, ...@@ -5263,8 +5383,8 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
} }
EXPORT_SYMBOL_GPL(nft_set_elem_destroy); EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
/* Only called from commit path, nft_set_elem_deactivate() already deals with /* Only called from commit path, nft_setelem_data_deactivate() already deals
* the refcounting from the preparation phase. * with the refcounting from the preparation phase.
*/ */
static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx, static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem) const struct nft_set *set, void *elem)
...@@ -5336,6 +5456,192 @@ static int nft_set_elem_expr_setup(struct nft_ctx *ctx, ...@@ -5336,6 +5456,192 @@ static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
return -ENOMEM; return -ENOMEM;
} }
struct nft_set_ext *nft_set_catchall_lookup(const struct net *net,
const struct nft_set *set)
{
struct nft_set_elem_catchall *catchall;
u8 genmask = nft_genmask_cur(net);
struct nft_set_ext *ext;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (nft_set_elem_active(ext, genmask) &&
!nft_set_elem_expired(ext))
return ext;
}
return NULL;
}
EXPORT_SYMBOL_GPL(nft_set_catchall_lookup);
void *nft_set_catchall_gc(const struct nft_set *set)
{
struct nft_set_elem_catchall *catchall, *next;
struct nft_set_ext *ext;
void *elem = NULL;
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_expired(ext) ||
nft_set_elem_mark_busy(ext))
continue;
elem = catchall->elem;
list_del_rcu(&catchall->list);
kfree_rcu(catchall, rcu);
break;
}
return elem;
}
EXPORT_SYMBOL_GPL(nft_set_catchall_gc);
static int nft_setelem_catchall_insert(const struct net *net,
struct nft_set *set,
const struct nft_set_elem *elem,
struct nft_set_ext **pext)
{
struct nft_set_elem_catchall *catchall;
u8 genmask = nft_genmask_next(net);
struct nft_set_ext *ext;
list_for_each_entry(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (nft_set_elem_active(ext, genmask)) {
*pext = ext;
return -EEXIST;
}
}
catchall = kmalloc(sizeof(*catchall), GFP_KERNEL);
if (!catchall)
return -ENOMEM;
catchall->elem = elem->priv;
list_add_tail_rcu(&catchall->list, &set->catchall_list);
return 0;
}
static int nft_setelem_insert(const struct net *net,
struct nft_set *set,
const struct nft_set_elem *elem,
struct nft_set_ext **ext, unsigned int flags)
{
int ret;
if (flags & NFT_SET_ELEM_CATCHALL)
ret = nft_setelem_catchall_insert(net, set, elem, ext);
else
ret = set->ops->insert(net, set, elem, ext);
return ret;
}
static bool nft_setelem_is_catchall(const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
*nft_set_ext_flags(ext) & NFT_SET_ELEM_CATCHALL)
return true;
return false;
}
static void nft_setelem_activate(struct net *net, struct nft_set *set,
struct nft_set_elem *elem)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
if (nft_setelem_is_catchall(set, elem)) {
nft_set_elem_change_active(net, set, ext);
nft_set_elem_clear_busy(ext);
} else {
set->ops->activate(net, set, elem);
}
}
static int nft_setelem_catchall_deactivate(const struct net *net,
struct nft_set *set,
struct nft_set_elem *elem)
{
struct nft_set_elem_catchall *catchall;
struct nft_set_ext *ext;
list_for_each_entry(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_is_active(net, ext) ||
nft_set_elem_mark_busy(ext))
continue;
kfree(elem->priv);
elem->priv = catchall->elem;
nft_set_elem_change_active(net, set, ext);
return 0;
}
return -ENOENT;
}
static int __nft_setelem_deactivate(const struct net *net,
struct nft_set *set,
struct nft_set_elem *elem)
{
void *priv;
priv = set->ops->deactivate(net, set, elem);
if (!priv)
return -ENOENT;
kfree(elem->priv);
elem->priv = priv;
set->ndeact++;
return 0;
}
static int nft_setelem_deactivate(const struct net *net,
struct nft_set *set,
struct nft_set_elem *elem, u32 flags)
{
int ret;
if (flags & NFT_SET_ELEM_CATCHALL)
ret = nft_setelem_catchall_deactivate(net, set, elem);
else
ret = __nft_setelem_deactivate(net, set, elem);
return ret;
}
static void nft_setelem_catchall_remove(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_set_elem_catchall *catchall, *next;
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
if (catchall->elem == elem->priv) {
list_del_rcu(&catchall->list);
kfree_rcu(catchall);
break;
}
}
}
static void nft_setelem_remove(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem)
{
if (nft_setelem_is_catchall(set, elem))
nft_setelem_catchall_remove(net, set, elem);
else
set->ops->remove(net, set, elem);
}
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr, u32 nlmsg_flags) const struct nlattr *attr, u32 nlmsg_flags)
{ {
...@@ -5362,14 +5668,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5362,14 +5668,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0) if (err < 0)
return err; return err;
if (nla[NFTA_SET_ELEM_KEY] == NULL)
return -EINVAL;
nft_set_ext_prepare(&tmpl); nft_set_ext_prepare(&tmpl);
err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags); err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
if (err < 0) if (err < 0)
return err; return err;
if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
return -EINVAL;
if (flags != 0) if (flags != 0)
nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS); nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
...@@ -5474,12 +5781,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5474,12 +5781,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
num_exprs = set->num_exprs; num_exprs = set->num_exprs;
} }
if (nla[NFTA_SET_ELEM_KEY]) {
err = nft_setelem_parse_key(ctx, set, &elem.key.val, err = nft_setelem_parse_key(ctx, set, &elem.key.val,
nla[NFTA_SET_ELEM_KEY]); nla[NFTA_SET_ELEM_KEY]);
if (err < 0) if (err < 0)
goto err_set_elem_expr; goto err_set_elem_expr;
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen); nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
}
if (nla[NFTA_SET_ELEM_KEY_END]) { if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val, err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
...@@ -5596,7 +5905,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5596,7 +5905,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
} }
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
err = set->ops->insert(ctx->net, set, &elem, &ext2);
err = nft_setelem_insert(ctx->net, set, &elem, &ext2, flags);
if (err) { if (err) {
if (err == -EEXIST) { if (err == -EEXIST) {
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^ if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^
...@@ -5623,7 +5933,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5623,7 +5933,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
goto err_element_clash; goto err_element_clash;
} }
if (set->size && if (!(flags & NFT_SET_ELEM_CATCHALL) && set->size &&
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) { !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) {
err = -ENFILE; err = -ENFILE;
goto err_set_full; goto err_set_full;
...@@ -5634,7 +5944,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5634,7 +5944,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
return 0; return 0;
err_set_full: err_set_full:
set->ops->remove(ctx->net, set, &elem); nft_setelem_remove(ctx->net, set, &elem);
err_element_clash: err_element_clash:
kfree(trans); kfree(trans);
err_elem_expr: err_elem_expr:
...@@ -5733,7 +6043,7 @@ void nft_data_hold(const struct nft_data *data, enum nft_data_types type) ...@@ -5733,7 +6043,7 @@ void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
} }
} }
static void nft_set_elem_activate(const struct net *net, static void nft_setelem_data_activate(const struct net *net,
const struct nft_set *set, const struct nft_set *set,
struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
...@@ -5745,7 +6055,7 @@ static void nft_set_elem_activate(const struct net *net, ...@@ -5745,7 +6055,7 @@ static void nft_set_elem_activate(const struct net *net,
(*nft_set_ext_obj(ext))->use++; (*nft_set_ext_obj(ext))->use++;
} }
static void nft_set_elem_deactivate(const struct net *net, static void nft_setelem_data_deactivate(const struct net *net,
const struct nft_set *set, const struct nft_set *set,
struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
...@@ -5766,7 +6076,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5766,7 +6076,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_ext *ext; struct nft_set_ext *ext;
struct nft_trans *trans; struct nft_trans *trans;
u32 flags = 0; u32 flags = 0;
void *priv;
int err; int err;
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr, err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
...@@ -5774,23 +6083,26 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5774,23 +6083,26 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0) if (err < 0)
return err; return err;
if (nla[NFTA_SET_ELEM_KEY] == NULL) err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
if (err < 0)
return err;
if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
return -EINVAL; return -EINVAL;
nft_set_ext_prepare(&tmpl); nft_set_ext_prepare(&tmpl);
err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
if (err < 0)
return err;
if (flags != 0) if (flags != 0)
nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS); nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
if (nla[NFTA_SET_ELEM_KEY]) {
err = nft_setelem_parse_key(ctx, set, &elem.key.val, err = nft_setelem_parse_key(ctx, set, &elem.key.val,
nla[NFTA_SET_ELEM_KEY]); nla[NFTA_SET_ELEM_KEY]);
if (err < 0) if (err < 0)
return err; return err;
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen); nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
}
if (nla[NFTA_SET_ELEM_KEY_END]) { if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val, err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
...@@ -5816,15 +6128,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5816,15 +6128,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
if (trans == NULL) if (trans == NULL)
goto fail_trans; goto fail_trans;
priv = set->ops->deactivate(ctx->net, set, &elem); err = nft_setelem_deactivate(ctx->net, set, &elem, flags);
if (priv == NULL) { if (err < 0)
err = -ENOENT;
goto fail_ops; goto fail_ops;
}
kfree(elem.priv);
elem.priv = priv;
nft_set_elem_deactivate(ctx->net, set, &elem); nft_setelem_data_deactivate(ctx->net, set, &elem);
nft_trans_elem(trans) = elem; nft_trans_elem(trans) = elem;
nft_trans_commit_list_add_tail(ctx->net, trans); nft_trans_commit_list_add_tail(ctx->net, trans);
...@@ -5839,7 +6147,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5839,7 +6147,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
return err; return err;
} }
static int nft_flush_set(const struct nft_ctx *ctx, static int nft_setelem_flush(const struct nft_ctx *ctx,
struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
struct nft_set_elem *elem) struct nft_set_elem *elem)
...@@ -5858,7 +6166,7 @@ static int nft_flush_set(const struct nft_ctx *ctx, ...@@ -5858,7 +6166,7 @@ static int nft_flush_set(const struct nft_ctx *ctx,
} }
set->ndeact++; set->ndeact++;
nft_set_elem_deactivate(ctx->net, set, elem); nft_setelem_data_deactivate(ctx->net, set, elem);
nft_trans_elem_set(trans) = set; nft_trans_elem_set(trans) = set;
nft_trans_elem(trans) = *elem; nft_trans_elem(trans) = *elem;
nft_trans_commit_list_add_tail(ctx->net, trans); nft_trans_commit_list_add_tail(ctx->net, trans);
...@@ -5869,6 +6177,63 @@ static int nft_flush_set(const struct nft_ctx *ctx, ...@@ -5869,6 +6177,63 @@ static int nft_flush_set(const struct nft_ctx *ctx,
return err; return err;
} }
static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
struct nft_set *set,
struct nft_set_elem *elem)
{
struct nft_trans *trans;
trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
sizeof(struct nft_trans_elem), GFP_KERNEL);
if (!trans)
return -ENOMEM;
nft_setelem_data_deactivate(ctx->net, set, elem);
nft_trans_elem_set(trans) = set;
nft_trans_elem(trans) = *elem;
nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
}
static int nft_set_catchall_flush(const struct nft_ctx *ctx,
struct nft_set *set)
{
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set_elem_catchall *catchall;
struct nft_set_elem elem;
struct nft_set_ext *ext;
int ret = 0;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask) ||
nft_set_elem_mark_busy(ext))
continue;
elem.priv = catchall->elem;
ret = __nft_set_catchall_flush(ctx, set, &elem);
if (ret < 0)
break;
}
return ret;
}
static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
{
struct nft_set_iter iter = {
.genmask = genmask,
.fn = nft_setelem_flush,
};
set->ops->walk(ctx, set, &iter);
if (!iter.err)
iter.err = nft_set_catchall_flush(ctx, set);
return iter.err;
}
static int nf_tables_delsetelem(struct sk_buff *skb, static int nf_tables_delsetelem(struct sk_buff *skb,
const struct nfnl_info *info, const struct nfnl_info *info,
const struct nlattr * const nla[]) const struct nlattr * const nla[])
...@@ -5892,22 +6257,13 @@ static int nf_tables_delsetelem(struct sk_buff *skb, ...@@ -5892,22 +6257,13 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
return -EBUSY; return -EBUSY;
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) { if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
struct nft_set_iter iter = { return nft_set_flush(&ctx, set, genmask);
.genmask = genmask,
.fn = nft_flush_set,
};
set->ops->walk(&ctx, set, &iter);
return iter.err;
}
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_del_setelem(&ctx, set, attr); err = nft_del_setelem(&ctx, set, attr);
if (err < 0) if (err < 0)
break; break;
set->ndeact++;
} }
return err; return err;
} }
...@@ -8258,7 +8614,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) ...@@ -8258,7 +8614,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWSETELEM: case NFT_MSG_NEWSETELEM:
te = (struct nft_trans_elem *)trans->data; te = (struct nft_trans_elem *)trans->data;
te->set->ops->activate(net, te->set, &te->elem); nft_setelem_activate(net, te->set, &te->elem);
nf_tables_setelem_notify(&trans->ctx, te->set, nf_tables_setelem_notify(&trans->ctx, te->set,
&te->elem, &te->elem,
NFT_MSG_NEWSETELEM, 0); NFT_MSG_NEWSETELEM, 0);
...@@ -8270,9 +8626,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) ...@@ -8270,9 +8626,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_setelem_notify(&trans->ctx, te->set, nf_tables_setelem_notify(&trans->ctx, te->set,
&te->elem, &te->elem,
NFT_MSG_DELSETELEM, 0); NFT_MSG_DELSETELEM, 0);
te->set->ops->remove(net, te->set, &te->elem); nft_setelem_remove(net, te->set, &te->elem);
if (!nft_setelem_is_catchall(te->set, &te->elem)) {
atomic_dec(&te->set->nelems); atomic_dec(&te->set->nelems);
te->set->ndeact--; te->set->ndeact--;
}
break; break;
case NFT_MSG_NEWOBJ: case NFT_MSG_NEWOBJ:
if (nft_trans_obj_update(trans)) { if (nft_trans_obj_update(trans)) {
...@@ -8473,14 +8831,16 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) ...@@ -8473,14 +8831,16 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
break; break;
} }
te = (struct nft_trans_elem *)trans->data; te = (struct nft_trans_elem *)trans->data;
te->set->ops->remove(net, te->set, &te->elem); nft_setelem_remove(net, te->set, &te->elem);
if (!nft_setelem_is_catchall(te->set, &te->elem))
atomic_dec(&te->set->nelems); atomic_dec(&te->set->nelems);
break; break;
case NFT_MSG_DELSETELEM: case NFT_MSG_DELSETELEM:
te = (struct nft_trans_elem *)trans->data; te = (struct nft_trans_elem *)trans->data;
nft_set_elem_activate(net, te->set, &te->elem); nft_setelem_data_activate(net, te->set, &te->elem);
te->set->ops->activate(net, te->set, &te->elem); nft_setelem_activate(net, te->set, &te->elem);
if (!nft_setelem_is_catchall(te->set, &te->elem))
te->set->ndeact--; te->set->ndeact--;
nft_trans_destroy(trans); nft_trans_destroy(trans);
...@@ -8626,26 +8986,59 @@ EXPORT_SYMBOL_GPL(nft_chain_validate_hooks); ...@@ -8626,26 +8986,59 @@ EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
static int nf_tables_check_loops(const struct nft_ctx *ctx, static int nf_tables_check_loops(const struct nft_ctx *ctx,
const struct nft_chain *chain); const struct nft_chain *chain);
static int nft_check_loops(const struct nft_ctx *ctx,
const struct nft_set_ext *ext)
{
const struct nft_data *data;
int ret;
data = nft_set_ext_data(ext);
switch (data->verdict.code) {
case NFT_JUMP:
case NFT_GOTO:
ret = nf_tables_check_loops(ctx, data->verdict.chain);
break;
default:
ret = 0;
break;
}
return ret;
}
static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx, static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
const struct nft_data *data;
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) && if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END) *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
return 0; return 0;
data = nft_set_ext_data(ext); return nft_check_loops(ctx, ext);
switch (data->verdict.code) { }
case NFT_JUMP:
case NFT_GOTO: static int nft_set_catchall_loops(const struct nft_ctx *ctx,
return nf_tables_check_loops(ctx, data->verdict.chain); struct nft_set *set)
default: {
return 0; u8 genmask = nft_genmask_next(ctx->net);
struct nft_set_elem_catchall *catchall;
struct nft_set_ext *ext;
int ret = 0;
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
continue;
ret = nft_check_loops(ctx, ext);
if (ret < 0)
return ret;
} }
return ret;
} }
static int nf_tables_check_loops(const struct nft_ctx *ctx, static int nf_tables_check_loops(const struct nft_ctx *ctx,
...@@ -8707,6 +9100,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, ...@@ -8707,6 +9100,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
iter.fn = nf_tables_loop_check_setelem; iter.fn = nf_tables_loop_check_setelem;
set->ops->walk(ctx, set, &iter); set->ops->walk(ctx, set, &iter);
if (!iter.err)
iter.err = nft_set_catchall_loops(ctx, set);
if (iter.err < 0) if (iter.err < 0)
return iter.err; return iter.err;
} }
......
...@@ -30,14 +30,18 @@ void nft_lookup_eval(const struct nft_expr *expr, ...@@ -30,14 +30,18 @@ void nft_lookup_eval(const struct nft_expr *expr,
const struct nft_lookup *priv = nft_expr_priv(expr); const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set; const struct nft_set *set = priv->set;
const struct nft_set_ext *ext = NULL; const struct nft_set_ext *ext = NULL;
const struct net *net = nft_net(pkt);
bool found; bool found;
found = set->ops->lookup(nft_net(pkt), set, &regs->data[priv->sreg], found = set->ops->lookup(net, set, &regs->data[priv->sreg], &ext) ^
&ext) ^ priv->invert; priv->invert;
if (!found) { if (!found) {
ext = nft_set_catchall_lookup(net, set);
if (!ext) {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
return; return;
} }
}
if (ext) { if (ext) {
if (set->flags & NFT_SET_MAP) if (set->flags & NFT_SET_MAP)
......
...@@ -105,16 +105,19 @@ static void nft_objref_map_eval(const struct nft_expr *expr, ...@@ -105,16 +105,19 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
{ {
struct nft_objref_map *priv = nft_expr_priv(expr); struct nft_objref_map *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set; const struct nft_set *set = priv->set;
struct net *net = nft_net(pkt);
const struct nft_set_ext *ext; const struct nft_set_ext *ext;
struct nft_object *obj; struct nft_object *obj;
bool found; bool found;
found = set->ops->lookup(nft_net(pkt), set, &regs->data[priv->sreg], found = set->ops->lookup(net, set, &regs->data[priv->sreg], &ext);
&ext);
if (!found) { if (!found) {
ext = nft_set_catchall_lookup(net, set);
if (!ext) {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
return; return;
} }
}
obj = *nft_set_ext_obj(ext); obj = *nft_set_ext_obj(ext);
obj->ops->eval(obj, regs, pkt); obj->ops->eval(obj, regs, pkt);
} }
......
...@@ -350,6 +350,12 @@ static void nft_rhash_gc(struct work_struct *work) ...@@ -350,6 +350,12 @@ static void nft_rhash_gc(struct work_struct *work)
rhashtable_walk_stop(&hti); rhashtable_walk_stop(&hti);
rhashtable_walk_exit(&hti); rhashtable_walk_exit(&hti);
he = nft_set_catchall_gc(set);
if (he) {
gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
if (gcb)
nft_set_gc_batch_add(gcb, he);
}
nft_set_gc_batch_complete(gcb); nft_set_gc_batch_complete(gcb);
queue_delayed_work(system_power_efficient_wq, &priv->gc_work, queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
nft_set_gc_interval(set)); nft_set_gc_interval(set));
......
...@@ -1529,11 +1529,11 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m) ...@@ -1529,11 +1529,11 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m)
{ {
struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo *priv = nft_set_priv(set);
int rules_f0, first_rule = 0; int rules_f0, first_rule = 0;
struct nft_pipapo_elem *e;
while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) { while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS]; union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
struct nft_pipapo_field *f; struct nft_pipapo_field *f;
struct nft_pipapo_elem *e;
int i, start, rules_fx; int i, start, rules_fx;
start = first_rule; start = first_rule;
...@@ -1569,6 +1569,10 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m) ...@@ -1569,6 +1569,10 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m)
} }
} }
e = nft_set_catchall_gc(set);
if (e)
nft_set_elem_destroy(set, e, true);
priv->last_gc = jiffies; priv->last_gc = jiffies;
} }
......
...@@ -541,6 +541,12 @@ static void nft_rbtree_gc(struct work_struct *work) ...@@ -541,6 +541,12 @@ static void nft_rbtree_gc(struct work_struct *work)
write_seqcount_end(&priv->count); write_seqcount_end(&priv->count);
write_unlock_bh(&priv->lock); write_unlock_bh(&priv->lock);
rbe = nft_set_catchall_gc(set);
if (rbe) {
gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
if (gcb)
nft_set_gc_batch_add(gcb, rbe);
}
nft_set_gc_batch_complete(gcb); nft_set_gc_batch_complete(gcb);
queue_delayed_work(system_power_efficient_wq, &priv->gc_work, queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
......
...@@ -34,7 +34,7 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt, ...@@ -34,7 +34,7 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt,
} }
} }
#ifdef CONFIG_CGROUPS #ifdef CONFIG_SOCK_CGROUP_DATA
static noinline bool static noinline bool
nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level) nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level)
{ {
...@@ -106,7 +106,7 @@ static void nft_socket_eval(const struct nft_expr *expr, ...@@ -106,7 +106,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
} }
nft_socket_wildcard(pkt, regs, sk, dest); nft_socket_wildcard(pkt, regs, sk, dest);
break; break;
#ifdef CONFIG_CGROUPS #ifdef CONFIG_SOCK_CGROUP_DATA
case NFT_SOCKET_CGROUPV2: case NFT_SOCKET_CGROUPV2:
if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) { if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
...@@ -134,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -134,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_socket *priv = nft_expr_priv(expr); struct nft_socket *priv = nft_expr_priv(expr);
unsigned int len, level; unsigned int len;
if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY]) if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
return -EINVAL; return -EINVAL;
...@@ -160,7 +160,9 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -160,7 +160,9 @@ static int nft_socket_init(const struct nft_ctx *ctx,
len = sizeof(u32); len = sizeof(u32);
break; break;
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
case NFT_SOCKET_CGROUPV2: case NFT_SOCKET_CGROUPV2: {
unsigned int level;
if (!tb[NFTA_SOCKET_LEVEL]) if (!tb[NFTA_SOCKET_LEVEL])
return -EINVAL; return -EINVAL;
...@@ -171,6 +173,7 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -171,6 +173,7 @@ static int nft_socket_init(const struct nft_ctx *ctx,
priv->level = level; priv->level = level;
len = sizeof(u64); len = sizeof(u64);
break; break;
}
#endif #endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment