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

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

Pablo Neira Ayuso says:

====================
Netfilter fixes for net (v2)

The following patchset contains Netfilter fixes for net:

1) Move back the defrag users fields to the global netns_nf area.
   Kernel fails to boot if conntrack is builtin and kernel is booted
   with: nf_conntrack.enable_hooks=1. From Florian Westphal.

2) Rule event notification is missing relevant context such as
   the position handle and the NLM_F_APPEND flag.

3) Rule replacement is expanded to add + delete using the existing
   rule handle, reverse order of this operation so it makes sense
   from rule notification standpoint.

4) Propagate to userspace the NLM_F_CREATE and NLM_F_EXCL flags
   from the rule notification path.

Patches #2, #3 and #4 are used by 'nft monitor' and 'iptables-monitor'
userspace utilities which are not correctly representing the following
operations through netlink notifications:

- rule insertions
- rule addition/insertion from position handle
- create table/chain/set/map/flowtable/...
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5cfe5109 6fb721cf
...@@ -17,7 +17,6 @@ struct inet_frags_ctl; ...@@ -17,7 +17,6 @@ struct inet_frags_ctl;
struct nft_ct_frag6_pernet { struct nft_ct_frag6_pernet {
struct ctl_table_header *nf_frag_frags_hdr; struct ctl_table_header *nf_frag_frags_hdr;
struct fqdir *fqdir; struct fqdir *fqdir;
unsigned int users;
}; };
#endif /* _NF_DEFRAG_IPV6_H */ #endif /* _NF_DEFRAG_IPV6_H */
...@@ -1202,7 +1202,7 @@ struct nft_object *nft_obj_lookup(const struct net *net, ...@@ -1202,7 +1202,7 @@ struct nft_object *nft_obj_lookup(const struct net *net,
void nft_obj_notify(struct net *net, const struct nft_table *table, void nft_obj_notify(struct net *net, const struct nft_table *table,
struct nft_object *obj, u32 portid, u32 seq, struct nft_object *obj, u32 portid, u32 seq,
int event, int family, int report, gfp_t gfp); int event, u16 flags, int family, int report, gfp_t gfp);
/** /**
* struct nft_object_type - stateful object type * struct nft_object_type - stateful object type
......
...@@ -27,5 +27,11 @@ struct netns_nf { ...@@ -27,5 +27,11 @@ struct netns_nf {
#if IS_ENABLED(CONFIG_DECNET) #if IS_ENABLED(CONFIG_DECNET)
struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS]; struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS];
#endif #endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
unsigned int defrag_ipv4_users;
#endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
unsigned int defrag_ipv6_users;
#endif
}; };
#endif #endif
...@@ -20,13 +20,8 @@ ...@@ -20,13 +20,8 @@
#endif #endif
#include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_conntrack_zones.h>
static unsigned int defrag4_pernet_id __read_mostly;
static DEFINE_MUTEX(defrag4_mutex); static DEFINE_MUTEX(defrag4_mutex);
struct defrag4_pernet {
unsigned int users;
};
static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb, static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
u_int32_t user) u_int32_t user)
{ {
...@@ -111,19 +106,15 @@ static const struct nf_hook_ops ipv4_defrag_ops[] = { ...@@ -111,19 +106,15 @@ static const struct nf_hook_ops ipv4_defrag_ops[] = {
static void __net_exit defrag4_net_exit(struct net *net) static void __net_exit defrag4_net_exit(struct net *net)
{ {
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id); if (net->nf.defrag_ipv4_users) {
if (nf_defrag->users) {
nf_unregister_net_hooks(net, ipv4_defrag_ops, nf_unregister_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops)); ARRAY_SIZE(ipv4_defrag_ops));
nf_defrag->users = 0; net->nf.defrag_ipv4_users = 0;
} }
} }
static struct pernet_operations defrag4_net_ops = { static struct pernet_operations defrag4_net_ops = {
.exit = defrag4_net_exit, .exit = defrag4_net_exit,
.id = &defrag4_pernet_id,
.size = sizeof(struct defrag4_pernet),
}; };
static int __init nf_defrag_init(void) static int __init nf_defrag_init(void)
...@@ -138,24 +129,23 @@ static void __exit nf_defrag_fini(void) ...@@ -138,24 +129,23 @@ static void __exit nf_defrag_fini(void)
int nf_defrag_ipv4_enable(struct net *net) int nf_defrag_ipv4_enable(struct net *net)
{ {
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
int err = 0; int err = 0;
mutex_lock(&defrag4_mutex); mutex_lock(&defrag4_mutex);
if (nf_defrag->users == UINT_MAX) { if (net->nf.defrag_ipv4_users == UINT_MAX) {
err = -EOVERFLOW; err = -EOVERFLOW;
goto out_unlock; goto out_unlock;
} }
if (nf_defrag->users) { if (net->nf.defrag_ipv4_users) {
nf_defrag->users++; net->nf.defrag_ipv4_users++;
goto out_unlock; goto out_unlock;
} }
err = nf_register_net_hooks(net, ipv4_defrag_ops, err = nf_register_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops)); ARRAY_SIZE(ipv4_defrag_ops));
if (err == 0) if (err == 0)
nf_defrag->users = 1; net->nf.defrag_ipv4_users = 1;
out_unlock: out_unlock:
mutex_unlock(&defrag4_mutex); mutex_unlock(&defrag4_mutex);
...@@ -165,12 +155,10 @@ EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable); ...@@ -165,12 +155,10 @@ EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
void nf_defrag_ipv4_disable(struct net *net) void nf_defrag_ipv4_disable(struct net *net)
{ {
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
mutex_lock(&defrag4_mutex); mutex_lock(&defrag4_mutex);
if (nf_defrag->users) { if (net->nf.defrag_ipv4_users) {
nf_defrag->users--; net->nf.defrag_ipv4_users--;
if (nf_defrag->users == 0) if (net->nf.defrag_ipv4_users == 0)
nf_unregister_net_hooks(net, ipv4_defrag_ops, nf_unregister_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops)); ARRAY_SIZE(ipv4_defrag_ops));
} }
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
static const char nf_frags_cache_name[] = "nf-frags"; static const char nf_frags_cache_name[] = "nf-frags";
unsigned int nf_frag_pernet_id __read_mostly; static unsigned int nf_frag_pernet_id __read_mostly;
static struct inet_frags nf_frags; static struct inet_frags nf_frags;
static struct nft_ct_frag6_pernet *nf_frag_pernet(struct net *net) static struct nft_ct_frag6_pernet *nf_frag_pernet(struct net *net)
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_defrag_ipv6.h> #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
extern unsigned int nf_frag_pernet_id;
static DEFINE_MUTEX(defrag6_mutex); static DEFINE_MUTEX(defrag6_mutex);
static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
...@@ -91,12 +89,10 @@ static const struct nf_hook_ops ipv6_defrag_ops[] = { ...@@ -91,12 +89,10 @@ static const struct nf_hook_ops ipv6_defrag_ops[] = {
static void __net_exit defrag6_net_exit(struct net *net) static void __net_exit defrag6_net_exit(struct net *net)
{ {
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id); if (net->nf.defrag_ipv6_users) {
if (nf_frag->users) {
nf_unregister_net_hooks(net, ipv6_defrag_ops, nf_unregister_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops)); ARRAY_SIZE(ipv6_defrag_ops));
nf_frag->users = 0; net->nf.defrag_ipv6_users = 0;
} }
} }
...@@ -134,24 +130,23 @@ static void __exit nf_defrag_fini(void) ...@@ -134,24 +130,23 @@ static void __exit nf_defrag_fini(void)
int nf_defrag_ipv6_enable(struct net *net) int nf_defrag_ipv6_enable(struct net *net)
{ {
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
int err = 0; int err = 0;
mutex_lock(&defrag6_mutex); mutex_lock(&defrag6_mutex);
if (nf_frag->users == UINT_MAX) { if (net->nf.defrag_ipv6_users == UINT_MAX) {
err = -EOVERFLOW; err = -EOVERFLOW;
goto out_unlock; goto out_unlock;
} }
if (nf_frag->users) { if (net->nf.defrag_ipv6_users) {
nf_frag->users++; net->nf.defrag_ipv6_users++;
goto out_unlock; goto out_unlock;
} }
err = nf_register_net_hooks(net, ipv6_defrag_ops, err = nf_register_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops)); ARRAY_SIZE(ipv6_defrag_ops));
if (err == 0) if (err == 0)
nf_frag->users = 1; net->nf.defrag_ipv6_users = 1;
out_unlock: out_unlock:
mutex_unlock(&defrag6_mutex); mutex_unlock(&defrag6_mutex);
...@@ -161,12 +156,10 @@ EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); ...@@ -161,12 +156,10 @@ EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
void nf_defrag_ipv6_disable(struct net *net) void nf_defrag_ipv6_disable(struct net *net)
{ {
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
mutex_lock(&defrag6_mutex); mutex_lock(&defrag6_mutex);
if (nf_frag->users) { if (net->nf.defrag_ipv6_users) {
nf_frag->users--; net->nf.defrag_ipv6_users--;
if (nf_frag->users == 0) if (net->nf.defrag_ipv6_users == 0)
nf_unregister_net_hooks(net, ipv6_defrag_ops, nf_unregister_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops)); ARRAY_SIZE(ipv6_defrag_ops));
} }
......
...@@ -780,6 +780,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) ...@@ -780,6 +780,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
{ {
struct nftables_pernet *nft_net; struct nftables_pernet *nft_net;
struct sk_buff *skb; struct sk_buff *skb;
u16 flags = 0;
int err; int err;
if (!ctx->report && if (!ctx->report &&
...@@ -790,8 +791,11 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) ...@@ -790,8 +791,11 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
if (skb == NULL) if (skb == NULL)
goto err; goto err;
if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL))
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
err = nf_tables_fill_table_info(skb, ctx->net, ctx->portid, ctx->seq, err = nf_tables_fill_table_info(skb, ctx->net, ctx->portid, ctx->seq,
event, 0, ctx->family, ctx->table); event, flags, ctx->family, ctx->table);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
goto err; goto err;
...@@ -1563,6 +1567,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event) ...@@ -1563,6 +1567,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
{ {
struct nftables_pernet *nft_net; struct nftables_pernet *nft_net;
struct sk_buff *skb; struct sk_buff *skb;
u16 flags = 0;
int err; int err;
if (!ctx->report && if (!ctx->report &&
...@@ -1573,8 +1578,11 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event) ...@@ -1573,8 +1578,11 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
if (skb == NULL) if (skb == NULL)
goto err; goto err;
if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL))
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq,
event, 0, ctx->family, ctx->table, event, flags, ctx->family, ctx->table,
ctx->chain); ctx->chain);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
...@@ -2866,8 +2874,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, ...@@ -2866,8 +2874,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
u32 flags, int family, u32 flags, int family,
const struct nft_table *table, const struct nft_table *table,
const struct nft_chain *chain, const struct nft_chain *chain,
const struct nft_rule *rule, const struct nft_rule *rule, u64 handle)
const struct nft_rule *prule)
{ {
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
const struct nft_expr *expr, *next; const struct nft_expr *expr, *next;
...@@ -2887,9 +2894,8 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, ...@@ -2887,9 +2894,8 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
NFTA_RULE_PAD)) NFTA_RULE_PAD))
goto nla_put_failure; goto nla_put_failure;
if (event != NFT_MSG_DELRULE && prule) { if (event != NFT_MSG_DELRULE && handle) {
if (nla_put_be64(skb, NFTA_RULE_POSITION, if (nla_put_be64(skb, NFTA_RULE_POSITION, cpu_to_be64(handle),
cpu_to_be64(prule->handle),
NFTA_RULE_PAD)) NFTA_RULE_PAD))
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -2925,7 +2931,10 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx, ...@@ -2925,7 +2931,10 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
const struct nft_rule *rule, int event) const struct nft_rule *rule, int event)
{ {
struct nftables_pernet *nft_net = nft_pernet(ctx->net); struct nftables_pernet *nft_net = nft_pernet(ctx->net);
const struct nft_rule *prule;
struct sk_buff *skb; struct sk_buff *skb;
u64 handle = 0;
u16 flags = 0;
int err; int err;
if (!ctx->report && if (!ctx->report &&
...@@ -2936,9 +2945,20 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx, ...@@ -2936,9 +2945,20 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
if (skb == NULL) if (skb == NULL)
goto err; goto err;
if (event == NFT_MSG_NEWRULE &&
!list_is_first(&rule->list, &ctx->chain->rules) &&
!list_is_last(&rule->list, &ctx->chain->rules)) {
prule = list_prev_entry(rule, list);
handle = prule->handle;
}
if (ctx->flags & (NLM_F_APPEND | NLM_F_REPLACE))
flags |= NLM_F_APPEND;
if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL))
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq, err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq,
event, 0, ctx->family, ctx->table, event, flags, ctx->family, ctx->table,
ctx->chain, rule, NULL); ctx->chain, rule, handle);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
goto err; goto err;
...@@ -2964,6 +2984,7 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2964,6 +2984,7 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
const struct nft_rule *rule, *prule; const struct nft_rule *rule, *prule;
unsigned int s_idx = cb->args[0]; unsigned int s_idx = cb->args[0];
u64 handle;
prule = NULL; prule = NULL;
list_for_each_entry_rcu(rule, &chain->rules, list) { list_for_each_entry_rcu(rule, &chain->rules, list) {
...@@ -2975,12 +2996,17 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2975,12 +2996,17 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
memset(&cb->args[1], 0, memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0])); sizeof(cb->args) - sizeof(cb->args[0]));
} }
if (prule)
handle = prule->handle;
else
handle = 0;
if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid, if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
NFT_MSG_NEWRULE, NFT_MSG_NEWRULE,
NLM_F_MULTI | NLM_F_APPEND, NLM_F_MULTI | NLM_F_APPEND,
table->family, table->family,
table, chain, rule, prule) < 0) table, chain, rule, handle) < 0)
return 1; return 1;
nl_dump_check_consistent(cb, nlmsg_hdr(skb)); nl_dump_check_consistent(cb, nlmsg_hdr(skb));
...@@ -3143,7 +3169,7 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -3143,7 +3169,7 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid, err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0, info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
family, table, chain, rule, NULL); family, table, chain, rule, 0);
if (err < 0) if (err < 0)
goto err_fill_rule_info; goto err_fill_rule_info;
...@@ -3403,17 +3429,15 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -3403,17 +3429,15 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
} }
if (info->nlh->nlmsg_flags & NLM_F_REPLACE) { if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
err = nft_delrule(&ctx, old_rule);
if (err < 0)
goto err_destroy_flow_rule;
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
if (trans == NULL) { if (trans == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto err_destroy_flow_rule; goto err_destroy_flow_rule;
} }
err = nft_delrule(&ctx, old_rule);
if (err < 0) {
nft_trans_destroy(trans);
goto err_destroy_flow_rule;
}
list_add_tail_rcu(&rule->list, &old_rule->list); list_add_tail_rcu(&rule->list, &old_rule->list);
} else { } else {
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
...@@ -3943,8 +3967,9 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx, ...@@ -3943,8 +3967,9 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
gfp_t gfp_flags) gfp_t gfp_flags)
{ {
struct nftables_pernet *nft_net = nft_pernet(ctx->net); struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
u32 portid = ctx->portid; u32 portid = ctx->portid;
struct sk_buff *skb;
u16 flags = 0;
int err; int err;
if (!ctx->report && if (!ctx->report &&
...@@ -3955,7 +3980,10 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx, ...@@ -3955,7 +3980,10 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
if (skb == NULL) if (skb == NULL)
goto err; goto err;
err = nf_tables_fill_set(skb, ctx, set, event, 0); if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL))
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
err = nf_tables_fill_set(skb, ctx, set, event, flags);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
goto err; goto err;
...@@ -5231,12 +5259,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb, ...@@ -5231,12 +5259,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
static void nf_tables_setelem_notify(const struct nft_ctx *ctx, static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
const struct nft_set *set, const struct nft_set *set,
const struct nft_set_elem *elem, const struct nft_set_elem *elem,
int event, u16 flags) int event)
{ {
struct nftables_pernet *nft_net; struct nftables_pernet *nft_net;
struct net *net = ctx->net; struct net *net = ctx->net;
u32 portid = ctx->portid; u32 portid = ctx->portid;
struct sk_buff *skb; struct sk_buff *skb;
u16 flags = 0;
int err; int err;
if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
...@@ -5246,6 +5275,9 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx, ...@@ -5246,6 +5275,9 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
if (skb == NULL) if (skb == NULL)
goto err; goto err;
if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL))
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags, err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags,
set, elem); set, elem);
if (err < 0) { if (err < 0) {
...@@ -6921,7 +6953,7 @@ static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -6921,7 +6953,7 @@ static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
void nft_obj_notify(struct net *net, const struct nft_table *table, void nft_obj_notify(struct net *net, const struct nft_table *table,
struct nft_object *obj, u32 portid, u32 seq, int event, struct nft_object *obj, u32 portid, u32 seq, int event,
int family, int report, gfp_t gfp) u16 flags, int family, int report, gfp_t gfp)
{ {
struct nftables_pernet *nft_net = nft_pernet(net); struct nftables_pernet *nft_net = nft_pernet(net);
struct sk_buff *skb; struct sk_buff *skb;
...@@ -6946,8 +6978,9 @@ void nft_obj_notify(struct net *net, const struct nft_table *table, ...@@ -6946,8 +6978,9 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
if (skb == NULL) if (skb == NULL)
goto err; goto err;
err = nf_tables_fill_obj_info(skb, net, portid, seq, event, 0, family, err = nf_tables_fill_obj_info(skb, net, portid, seq, event,
table, obj, false); flags & (NLM_F_CREATE | NLM_F_EXCL),
family, table, obj, false);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
goto err; goto err;
...@@ -6964,7 +6997,7 @@ static void nf_tables_obj_notify(const struct nft_ctx *ctx, ...@@ -6964,7 +6997,7 @@ static void nf_tables_obj_notify(const struct nft_ctx *ctx,
struct nft_object *obj, int event) struct nft_object *obj, int event)
{ {
nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event, nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event,
ctx->family, ctx->report, GFP_KERNEL); ctx->flags, ctx->family, ctx->report, GFP_KERNEL);
} }
/* /*
...@@ -7745,6 +7778,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, ...@@ -7745,6 +7778,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
{ {
struct nftables_pernet *nft_net = nft_pernet(ctx->net); struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb; struct sk_buff *skb;
u16 flags = 0;
int err; int err;
if (!ctx->report && if (!ctx->report &&
...@@ -7755,8 +7789,11 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, ...@@ -7755,8 +7789,11 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
if (skb == NULL) if (skb == NULL)
goto err; goto err;
if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL))
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid,
ctx->seq, event, 0, ctx->seq, event, flags,
ctx->family, flowtable, hook_list); ctx->family, flowtable, hook_list);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
...@@ -8634,7 +8671,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) ...@@ -8634,7 +8671,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_setelem_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);
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_DELSETELEM: case NFT_MSG_DELSETELEM:
...@@ -8642,7 +8679,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) ...@@ -8642,7 +8679,7 @@ 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);
nft_setelem_remove(net, te->set, &te->elem); nft_setelem_remove(net, te->set, &te->elem);
if (!nft_setelem_is_catchall(te->set, &te->elem)) { if (!nft_setelem_is_catchall(te->set, &te->elem)) {
atomic_dec(&te->set->nelems); atomic_dec(&te->set->nelems);
......
...@@ -60,7 +60,7 @@ static void nft_quota_obj_eval(struct nft_object *obj, ...@@ -60,7 +60,7 @@ static void nft_quota_obj_eval(struct nft_object *obj,
if (overquota && if (overquota &&
!test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags)) !test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0, nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
NFT_MSG_NEWOBJ, nft_pf(pkt), 0, GFP_ATOMIC); NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);
} }
static int nft_quota_do_init(const struct nlattr * const tb[], static int nft_quota_do_init(const struct nlattr * const tb[],
......
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