Commit 52a623bd 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 your net-next
tree. This batch contains connection tracking updates for the cleanup
iteration path, patches from Florian Westphal:

X) Skip unconfirmed conntracks in nf_ct_iterate_cleanup_net(), just set
   dying bit to let the CPU release them.

X) Add nf_ct_iterate_destroy() to be used on module removal, to kill
   conntrack from all namespace.

X) Restart iteration on hashtable resizing, since both may occur at
   the same time.

X) Use the new nf_ct_iterate_destroy() to remove conntrack with NAT
   mapping on module removal.

X) Use nf_ct_iterate_destroy() to remove conntrack entries helper
   module removal, from Liping Zhang.

X) Use nf_ct_iterate_cleanup_net() to remove the timeout extension
   if user requests this, also from Liping.

X) Add net_ns_barrier() and use it from FTP helper, so make sure
   no concurrent namespace removal happens at the same time while
   the helper module is being removed.

X) Use NFPROTO_MAX in layer 3 conntrack protocol array, to reduce
   module size. Same thing in nf_tables.

Updates for the nf_tables infrastructure:

X) Prepare usage of the extended ACK reporting infrastructure for
   nf_tables.

X) Remove unnecessary forward declaration in nf_tables hash set.

X) Skip set size estimation if number of element is not specified.

X) Changes to accomodate a (faster) unresizable hash set implementation,
   for anonymous sets and dynamic size fixed sets with no timeouts.

X) Faster lookup function for unresizable hash table for 2 and 4
   bytes key.

And, finally, a bunch of asorted small updates and cleanups:

X) Do not hold reference to netdev from ipt_CLUSTER, instead subscribe
   to device events and look up for index from the packet path, this
   is fixing an issue that is present since the very beginning, patch
   from Xin Long.

X) Use nf_register_net_hook() in ipt_CLUSTER, from Florian Westphal.

X) Use ebt_invalid_target() whenever possible in the ebtables tree,
   from Gao Feng.

X) Calm down compilation warning in nf_dup infrastructure, patch from
   stephen hemminger.

X) Statify functions in nftables rt expression, also from stephen.

X) Update Makefile to use canonical method to specify nf_tables-objs.
   From Jike Song.

X) Use nf_conntrack_helpers_register() in amanda and H323.

X) Space cleanup for ctnetlink, from linzhang.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fcce2fdb 04ba724b
#ifndef _NFNETLINK_H #ifndef _NFNETLINK_H
#define _NFNETLINK_H #define _NFNETLINK_H
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <net/netlink.h> #include <net/netlink.h>
...@@ -10,13 +9,16 @@ ...@@ -10,13 +9,16 @@
struct nfnl_callback { struct nfnl_callback {
int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb, int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]); const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb, int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]); const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb, int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]); const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
const struct nla_policy *policy; /* netlink attribute policy */ const struct nla_policy *policy; /* netlink attribute policy */
const u_int16_t attr_count; /* number of nlattr's */ const u_int16_t attr_count; /* number of nlattr's */
}; };
......
...@@ -122,8 +122,6 @@ extern unsigned int ebt_do_table(struct sk_buff *skb, ...@@ -122,8 +122,6 @@ extern unsigned int ebt_do_table(struct sk_buff *skb,
#define BASE_CHAIN (par->hook_mask & (1 << NF_BR_NUMHOOKS)) #define BASE_CHAIN (par->hook_mask & (1 << NF_BR_NUMHOOKS))
/* Clear the bit in the hook mask that tells if the rule is on a base chain */ /* Clear the bit in the hook mask that tells if the rule is on a base chain */
#define CLEAR_BASE_CHAIN_BIT (par->hook_mask &= ~(1 << NF_BR_NUMHOOKS)) #define CLEAR_BASE_CHAIN_BIT (par->hook_mask &= ~(1 << NF_BR_NUMHOOKS))
/* True if the target is not a standard target */
#define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0)
static inline bool ebt_invalid_target(int target) static inline bool ebt_invalid_target(int target)
{ {
......
...@@ -158,6 +158,7 @@ extern struct net init_net; ...@@ -158,6 +158,7 @@ extern struct net init_net;
struct net *copy_net_ns(unsigned long flags, struct user_namespace *user_ns, struct net *copy_net_ns(unsigned long flags, struct user_namespace *user_ns,
struct net *old_net); struct net *old_net);
void net_ns_barrier(void);
#else /* CONFIG_NET_NS */ #else /* CONFIG_NET_NS */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
...@@ -168,6 +169,8 @@ static inline struct net *copy_net_ns(unsigned long flags, ...@@ -168,6 +169,8 @@ static inline struct net *copy_net_ns(unsigned long flags,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return old_net; return old_net;
} }
static inline void net_ns_barrier(void) {}
#endif /* CONFIG_NET_NS */ #endif /* CONFIG_NET_NS */
......
...@@ -225,9 +225,13 @@ extern s32 (*nf_ct_nat_offset)(const struct nf_conn *ct, ...@@ -225,9 +225,13 @@ extern s32 (*nf_ct_nat_offset)(const struct nf_conn *ct,
u32 seq); u32 seq);
/* Iterate over all conntracks: if iter returns true, it's deleted. */ /* Iterate over all conntracks: if iter returns true, it's deleted. */
void nf_ct_iterate_cleanup(struct net *net, void nf_ct_iterate_cleanup_net(struct net *net,
int (*iter)(struct nf_conn *i, void *data), int (*iter)(struct nf_conn *i, void *data),
void *data, u32 portid, int report); void *data, u32 portid, int report);
/* also set unconfirmed conntracks as dying. Only use in module exit path. */
void nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data),
void *data);
struct nf_conntrack_zone; struct nf_conntrack_zone;
......
...@@ -71,7 +71,7 @@ struct nf_conntrack_l3proto { ...@@ -71,7 +71,7 @@ struct nf_conntrack_l3proto {
struct module *me; struct module *me;
}; };
extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX]; extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[NFPROTO_NUMPROTO];
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
/* Protocol pernet registration. */ /* Protocol pernet registration. */
...@@ -100,7 +100,7 @@ extern struct nf_conntrack_l3proto nf_conntrack_l3proto_generic; ...@@ -100,7 +100,7 @@ extern struct nf_conntrack_l3proto nf_conntrack_l3proto_generic;
static inline struct nf_conntrack_l3proto * static inline struct nf_conntrack_l3proto *
__nf_ct_l3proto_find(u_int16_t l3proto) __nf_ct_l3proto_find(u_int16_t l3proto)
{ {
if (unlikely(l3proto >= AF_MAX)) if (unlikely(l3proto >= NFPROTO_NUMPROTO))
return &nf_conntrack_l3proto_generic; return &nf_conntrack_l3proto_generic;
return rcu_dereference(nf_ct_l3protos[l3proto]); return rcu_dereference(nf_ct_l3protos[l3proto]);
} }
......
...@@ -281,6 +281,23 @@ struct nft_set_estimate { ...@@ -281,6 +281,23 @@ struct nft_set_estimate {
enum nft_set_class space; enum nft_set_class space;
}; };
/**
* struct nft_set_type - nf_tables set type
*
* @select_ops: function to select nft_set_ops
* @ops: default ops, used when no select_ops functions is present
* @list: used internally
* @owner: module reference
*/
struct nft_set_type {
const struct nft_set_ops *(*select_ops)(const struct nft_ctx *,
const struct nft_set_desc *desc,
u32 flags);
const struct nft_set_ops *ops;
struct list_head list;
struct module *owner;
};
struct nft_set_ext; struct nft_set_ext;
struct nft_expr; struct nft_expr;
...@@ -297,8 +314,6 @@ struct nft_expr; ...@@ -297,8 +314,6 @@ struct nft_expr;
* @privsize: function to return size of set private data * @privsize: function to return size of set private data
* @init: initialize private data of new set instance * @init: initialize private data of new set instance
* @destroy: destroy private data of set instance * @destroy: destroy private data of set instance
* @list: nf_tables_set_ops list node
* @owner: module reference
* @elemsize: element private size * @elemsize: element private size
* @features: features supported by the implementation * @features: features supported by the implementation
*/ */
...@@ -336,7 +351,8 @@ struct nft_set_ops { ...@@ -336,7 +351,8 @@ struct nft_set_ops {
struct nft_set *set, struct nft_set *set,
struct nft_set_iter *iter); struct nft_set_iter *iter);
unsigned int (*privsize)(const struct nlattr * const nla[]); unsigned int (*privsize)(const struct nlattr * const nla[],
const struct nft_set_desc *desc);
bool (*estimate)(const struct nft_set_desc *desc, bool (*estimate)(const struct nft_set_desc *desc,
u32 features, u32 features,
struct nft_set_estimate *est); struct nft_set_estimate *est);
...@@ -345,14 +361,13 @@ struct nft_set_ops { ...@@ -345,14 +361,13 @@ struct nft_set_ops {
const struct nlattr * const nla[]); const struct nlattr * const nla[]);
void (*destroy)(const struct nft_set *set); void (*destroy)(const struct nft_set *set);
struct list_head list;
struct module *owner;
unsigned int elemsize; unsigned int elemsize;
u32 features; u32 features;
const struct nft_set_type *type;
}; };
int nft_register_set(struct nft_set_ops *ops); int nft_register_set(struct nft_set_type *type);
void nft_unregister_set(struct nft_set_ops *ops); void nft_unregister_set(struct nft_set_type *type);
/** /**
* struct nft_set - nf_tables set instance * struct nft_set - nf_tables set instance
......
...@@ -61,7 +61,7 @@ static int ebt_dnat_tg_check(const struct xt_tgchk_param *par) ...@@ -61,7 +61,7 @@ static int ebt_dnat_tg_check(const struct xt_tgchk_param *par)
(strcmp(par->table, "broute") != 0 || (strcmp(par->table, "broute") != 0 ||
hook_mask & ~(1 << NF_BR_BROUTING))) hook_mask & ~(1 << NF_BR_BROUTING)))
return -EINVAL; return -EINVAL;
if (INVALID_TARGET) if (ebt_invalid_target(info->target))
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
......
...@@ -44,7 +44,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par) ...@@ -44,7 +44,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
tmp = info->target | ~EBT_VERDICT_BITS; tmp = info->target | ~EBT_VERDICT_BITS;
if (BASE_CHAIN && tmp == EBT_RETURN) if (BASE_CHAIN && tmp == EBT_RETURN)
return -EINVAL; return -EINVAL;
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) if (ebt_invalid_target(tmp))
return -EINVAL; return -EINVAL;
tmp = info->target & ~EBT_VERDICT_BITS; tmp = info->target & ~EBT_VERDICT_BITS;
if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
......
...@@ -47,7 +47,7 @@ static int ebt_redirect_tg_check(const struct xt_tgchk_param *par) ...@@ -47,7 +47,7 @@ static int ebt_redirect_tg_check(const struct xt_tgchk_param *par)
(strcmp(par->table, "broute") != 0 || (strcmp(par->table, "broute") != 0 ||
hook_mask & ~(1 << NF_BR_BROUTING))) hook_mask & ~(1 << NF_BR_BROUTING)))
return -EINVAL; return -EINVAL;
if (INVALID_TARGET) if (ebt_invalid_target(info->target))
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
......
...@@ -51,7 +51,7 @@ static int ebt_snat_tg_check(const struct xt_tgchk_param *par) ...@@ -51,7 +51,7 @@ static int ebt_snat_tg_check(const struct xt_tgchk_param *par)
if (BASE_CHAIN && tmp == EBT_RETURN) if (BASE_CHAIN && tmp == EBT_RETURN)
return -EINVAL; return -EINVAL;
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) if (ebt_invalid_target(tmp))
return -EINVAL; return -EINVAL;
tmp = info->target | EBT_VERDICT_BITS; tmp = info->target | EBT_VERDICT_BITS;
if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT)
......
...@@ -501,6 +501,23 @@ static void cleanup_net(struct work_struct *work) ...@@ -501,6 +501,23 @@ static void cleanup_net(struct work_struct *work)
net_drop_ns(net); net_drop_ns(net);
} }
} }
/**
* net_ns_barrier - wait until concurrent net_cleanup_work is done
*
* cleanup_net runs from work queue and will first remove namespaces
* from the global list, then run net exit functions.
*
* Call this in module exit path to make sure that all netns
* ->exit ops have been invoked before the function is removed.
*/
void net_ns_barrier(void)
{
mutex_lock(&net_mutex);
mutex_unlock(&net_mutex);
}
EXPORT_SYMBOL(net_ns_barrier);
static DECLARE_WORK(net_cleanup_work, cleanup_net); static DECLARE_WORK(net_cleanup_work, cleanup_net);
void __put_net(struct net *net) void __put_net(struct net *net)
......
...@@ -47,7 +47,7 @@ struct clusterip_config { ...@@ -47,7 +47,7 @@ struct clusterip_config {
__be32 clusterip; /* the IP address */ __be32 clusterip; /* the IP address */
u_int8_t clustermac[ETH_ALEN]; /* the MAC address */ u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
struct net_device *dev; /* device */ int ifindex; /* device ifindex */
u_int16_t num_total_nodes; /* total number of nodes */ u_int16_t num_total_nodes; /* total number of nodes */
unsigned long local_nodes; /* node number array */ unsigned long local_nodes; /* node number array */
...@@ -57,6 +57,9 @@ struct clusterip_config { ...@@ -57,6 +57,9 @@ struct clusterip_config {
enum clusterip_hashmode hash_mode; /* which hashing mode */ enum clusterip_hashmode hash_mode; /* which hashing mode */
u_int32_t hash_initval; /* hash initialization */ u_int32_t hash_initval; /* hash initialization */
struct rcu_head rcu; struct rcu_head rcu;
char ifname[IFNAMSIZ]; /* device ifname */
struct notifier_block notifier; /* refresh c->ifindex in it */
}; };
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -98,9 +101,8 @@ clusterip_config_put(struct clusterip_config *c) ...@@ -98,9 +101,8 @@ clusterip_config_put(struct clusterip_config *c)
* entry(rule) is removed, remove the config from lists, but don't free it * entry(rule) is removed, remove the config from lists, but don't free it
* yet, since proc-files could still be holding references */ * yet, since proc-files could still be holding references */
static inline void static inline void
clusterip_config_entry_put(struct clusterip_config *c) clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
{ {
struct net *net = dev_net(c->dev);
struct clusterip_net *cn = net_generic(net, clusterip_net_id); struct clusterip_net *cn = net_generic(net, clusterip_net_id);
local_bh_disable(); local_bh_disable();
...@@ -109,8 +111,7 @@ clusterip_config_entry_put(struct clusterip_config *c) ...@@ -109,8 +111,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
spin_unlock(&cn->lock); spin_unlock(&cn->lock);
local_bh_enable(); local_bh_enable();
dev_mc_del(c->dev, c->clustermac); unregister_netdevice_notifier(&c->notifier);
dev_put(c->dev);
/* In case anyone still accesses the file, the open/close /* In case anyone still accesses the file, the open/close
* functions are also incrementing the refcount on their own, * functions are also incrementing the refcount on their own,
...@@ -170,19 +171,55 @@ clusterip_config_init_nodelist(struct clusterip_config *c, ...@@ -170,19 +171,55 @@ clusterip_config_init_nodelist(struct clusterip_config *c,
set_bit(i->local_nodes[n] - 1, &c->local_nodes); set_bit(i->local_nodes[n] - 1, &c->local_nodes);
} }
static struct clusterip_config * static int
clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, clusterip_netdev_event(struct notifier_block *this, unsigned long event,
struct net_device *dev) void *ptr)
{ {
struct net *net = dev_net(dev); struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct clusterip_config *c; struct clusterip_config *c;
c = container_of(this, struct clusterip_config, notifier);
switch (event) {
case NETDEV_REGISTER:
if (!strcmp(dev->name, c->ifname)) {
c->ifindex = dev->ifindex;
dev_mc_add(dev, c->clustermac);
}
break;
case NETDEV_UNREGISTER:
if (dev->ifindex == c->ifindex) {
dev_mc_del(dev, c->clustermac);
c->ifindex = -1;
}
break;
case NETDEV_CHANGENAME:
if (!strcmp(dev->name, c->ifname)) {
c->ifindex = dev->ifindex;
dev_mc_add(dev, c->clustermac);
} else if (dev->ifindex == c->ifindex) {
dev_mc_del(dev, c->clustermac);
c->ifindex = -1;
}
break;
}
return NOTIFY_DONE;
}
static struct clusterip_config *
clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
__be32 ip, const char *iniface)
{
struct clusterip_net *cn = net_generic(net, clusterip_net_id); struct clusterip_net *cn = net_generic(net, clusterip_net_id);
struct clusterip_config *c;
int err;
c = kzalloc(sizeof(*c), GFP_ATOMIC); c = kzalloc(sizeof(*c), GFP_ATOMIC);
if (!c) if (!c)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
c->dev = dev; strcpy(c->ifname, iniface);
c->ifindex = -1;
c->clusterip = ip; c->clusterip = ip;
memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
c->num_total_nodes = i->num_total_nodes; c->num_total_nodes = i->num_total_nodes;
...@@ -213,17 +250,27 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, ...@@ -213,17 +250,27 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
cn->procdir, cn->procdir,
&clusterip_proc_fops, c); &clusterip_proc_fops, c);
if (!c->pde) { if (!c->pde) {
spin_lock_bh(&cn->lock); err = -ENOMEM;
list_del_rcu(&c->list); goto err;
spin_unlock_bh(&cn->lock);
kfree(c);
return ERR_PTR(-ENOMEM);
} }
} }
#endif #endif
return c; c->notifier.notifier_call = clusterip_netdev_event;
err = register_netdevice_notifier(&c->notifier);
if (!err)
return c;
#ifdef CONFIG_PROC_FS
proc_remove(c->pde);
err:
#endif
spin_lock_bh(&cn->lock);
list_del_rcu(&c->list);
spin_unlock_bh(&cn->lock);
kfree(c);
return ERR_PTR(err);
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -425,14 +472,13 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) ...@@ -425,14 +472,13 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
e->ip.iniface); e->ip.iniface);
return -ENOENT; return -ENOENT;
} }
dev_put(dev);
config = clusterip_config_init(cipinfo, config = clusterip_config_init(par->net, cipinfo,
e->ip.dst.s_addr, dev); e->ip.dst.s_addr,
if (IS_ERR(config)) { e->ip.iniface);
dev_put(dev); if (IS_ERR(config))
return PTR_ERR(config); return PTR_ERR(config);
}
dev_mc_add(config->dev, config->clustermac);
} }
} }
cipinfo->config = config; cipinfo->config = config;
...@@ -458,7 +504,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par) ...@@ -458,7 +504,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
/* if no more entries are referencing the config, remove it /* if no more entries are referencing the config, remove it
* from the list and destroy the proc entry */ * from the list and destroy the proc entry */
clusterip_config_entry_put(cipinfo->config); clusterip_config_entry_put(par->net, cipinfo->config);
clusterip_config_put(cipinfo->config); clusterip_config_put(cipinfo->config);
...@@ -558,10 +604,9 @@ arp_mangle(void *priv, ...@@ -558,10 +604,9 @@ arp_mangle(void *priv,
* addresses on different interfacs. However, in the CLUSTERIP case * addresses on different interfacs. However, in the CLUSTERIP case
* this wouldn't work, since we didn't subscribe the mcast group on * this wouldn't work, since we didn't subscribe the mcast group on
* other interfaces */ * other interfaces */
if (c->dev != state->out) { if (c->ifindex != state->out->ifindex) {
pr_debug("not mangling arp reply on different " pr_debug("not mangling arp reply on different interface: cip'%d'-skb'%d'\n",
"interface: cip'%s'-skb'%s'\n", c->ifindex, state->out->ifindex);
c->dev->name, state->out->name);
clusterip_config_put(c); clusterip_config_put(c);
return NF_ACCEPT; return NF_ACCEPT;
} }
...@@ -743,14 +788,20 @@ static const struct file_operations clusterip_proc_fops = { ...@@ -743,14 +788,20 @@ static const struct file_operations clusterip_proc_fops = {
static int clusterip_net_init(struct net *net) static int clusterip_net_init(struct net *net)
{ {
struct clusterip_net *cn = net_generic(net, clusterip_net_id); struct clusterip_net *cn = net_generic(net, clusterip_net_id);
int ret;
INIT_LIST_HEAD(&cn->configs); INIT_LIST_HEAD(&cn->configs);
spin_lock_init(&cn->lock); spin_lock_init(&cn->lock);
ret = nf_register_net_hook(net, &cip_arp_ops);
if (ret < 0)
return ret;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net); cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net);
if (!cn->procdir) { if (!cn->procdir) {
nf_unregister_net_hook(net, &cip_arp_ops);
pr_err("Unable to proc dir entry\n"); pr_err("Unable to proc dir entry\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -765,6 +816,7 @@ static void clusterip_net_exit(struct net *net) ...@@ -765,6 +816,7 @@ static void clusterip_net_exit(struct net *net)
struct clusterip_net *cn = net_generic(net, clusterip_net_id); struct clusterip_net *cn = net_generic(net, clusterip_net_id);
proc_remove(cn->procdir); proc_remove(cn->procdir);
#endif #endif
nf_unregister_net_hook(net, &cip_arp_ops);
} }
static struct pernet_operations clusterip_net_ops = { static struct pernet_operations clusterip_net_ops = {
...@@ -786,17 +838,11 @@ static int __init clusterip_tg_init(void) ...@@ -786,17 +838,11 @@ static int __init clusterip_tg_init(void)
if (ret < 0) if (ret < 0)
goto cleanup_subsys; goto cleanup_subsys;
ret = nf_register_hook(&cip_arp_ops);
if (ret < 0)
goto cleanup_target;
pr_info("ClusterIP Version %s loaded successfully\n", pr_info("ClusterIP Version %s loaded successfully\n",
CLUSTERIP_VERSION); CLUSTERIP_VERSION);
return 0; return 0;
cleanup_target:
xt_unregister_target(&clusterip_tg_reg);
cleanup_subsys: cleanup_subsys:
unregister_pernet_subsys(&clusterip_net_ops); unregister_pernet_subsys(&clusterip_net_ops);
return ret; return ret;
...@@ -806,7 +852,6 @@ static void __exit clusterip_tg_exit(void) ...@@ -806,7 +852,6 @@ static void __exit clusterip_tg_exit(void)
{ {
pr_info("ClusterIP Version %s unloading\n", CLUSTERIP_VERSION); pr_info("ClusterIP Version %s unloading\n", CLUSTERIP_VERSION);
nf_unregister_hook(&cip_arp_ops);
xt_unregister_target(&clusterip_tg_reg); xt_unregister_target(&clusterip_tg_reg);
unregister_pernet_subsys(&clusterip_net_ops); unregister_pernet_subsys(&clusterip_net_ops);
......
...@@ -98,8 +98,8 @@ static int masq_device_event(struct notifier_block *this, ...@@ -98,8 +98,8 @@ static int masq_device_event(struct notifier_block *this,
*/ */
NF_CT_ASSERT(dev->ifindex != 0); NF_CT_ASSERT(dev->ifindex != 0);
nf_ct_iterate_cleanup(net, device_cmp, nf_ct_iterate_cleanup_net(net, device_cmp,
(void *)(long)dev->ifindex, 0, 0); (void *)(long)dev->ifindex, 0, 0);
} }
return NOTIFY_DONE; return NOTIFY_DONE;
......
...@@ -75,8 +75,8 @@ static int masq_device_event(struct notifier_block *this, ...@@ -75,8 +75,8 @@ static int masq_device_event(struct notifier_block *this,
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
if (event == NETDEV_DOWN) if (event == NETDEV_DOWN)
nf_ct_iterate_cleanup(net, device_cmp, nf_ct_iterate_cleanup_net(net, device_cmp,
(void *)(long)dev->ifindex, 0, 0); (void *)(long)dev->ifindex, 0, 0);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -99,7 +99,7 @@ static void iterate_cleanup_work(struct work_struct *work) ...@@ -99,7 +99,7 @@ static void iterate_cleanup_work(struct work_struct *work)
w = container_of(work, struct masq_dev_work, work); w = container_of(work, struct masq_dev_work, work);
index = w->ifindex; index = w->ifindex;
nf_ct_iterate_cleanup(w->net, device_cmp, (void *)index, 0, 0); nf_ct_iterate_cleanup_net(w->net, device_cmp, (void *)index, 0, 0);
put_net(w->net); put_net(w->net);
kfree(w); kfree(w);
...@@ -110,12 +110,12 @@ static void iterate_cleanup_work(struct work_struct *work) ...@@ -110,12 +110,12 @@ static void iterate_cleanup_work(struct work_struct *work)
/* ipv6 inet notifier is an atomic notifier, i.e. we cannot /* ipv6 inet notifier is an atomic notifier, i.e. we cannot
* schedule. * schedule.
* *
* Unfortunately, nf_ct_iterate_cleanup can run for a long * Unfortunately, nf_ct_iterate_cleanup_net can run for a long
* time if there are lots of conntracks and the system * time if there are lots of conntracks and the system
* handles high softirq load, so it frequently calls cond_resched * handles high softirq load, so it frequently calls cond_resched
* while iterating the conntrack table. * while iterating the conntrack table.
* *
* So we defer nf_ct_iterate_cleanup walk to the system workqueue. * So we defer nf_ct_iterate_cleanup_net walk to the system workqueue.
* *
* As we can have 'a lot' of inet_events (depending on amount * As we can have 'a lot' of inet_events (depending on amount
* of ipv6 addresses being deleted), we also need to add an upper * of ipv6 addresses being deleted), we also need to add an upper
......
...@@ -70,10 +70,9 @@ obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o ...@@ -70,10 +70,9 @@ obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o
# nf_tables # nf_tables
nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o nf_tables-objs := nf_tables_core.o nf_tables_api.o nf_tables_trace.o \
nf_tables-objs += nft_immediate.o nft_cmp.o nft_range.o nft_immediate.o nft_cmp.o nft_range.o nft_bitwise.o \
nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o nft_byteorder.o nft_payload.o nft_lookup.o nft_dynset.o
nf_tables-objs += nft_lookup.o nft_dynset.o
obj-$(CONFIG_NF_TABLES) += nf_tables.o obj-$(CONFIG_NF_TABLES) += nf_tables.o
obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o
......
...@@ -841,14 +841,16 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index, ...@@ -841,14 +841,16 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
static int ip_set_none(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_none(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int ip_set_create(struct net *net, struct sock *ctnl, static int ip_set_create(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set, *clash = NULL; struct ip_set *set, *clash = NULL;
...@@ -989,7 +991,8 @@ ip_set_destroy_set(struct ip_set *set) ...@@ -989,7 +991,8 @@ ip_set_destroy_set(struct ip_set *set)
static int ip_set_destroy(struct net *net, struct sock *ctnl, static int ip_set_destroy(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *s; struct ip_set *s;
...@@ -1067,7 +1070,8 @@ ip_set_flush_set(struct ip_set *set) ...@@ -1067,7 +1070,8 @@ ip_set_flush_set(struct ip_set *set)
static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *s; struct ip_set *s;
...@@ -1106,7 +1110,8 @@ ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = { ...@@ -1106,7 +1110,8 @@ ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = {
static int ip_set_rename(struct net *net, struct sock *ctnl, static int ip_set_rename(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set, *s; struct ip_set *set, *s;
...@@ -1155,7 +1160,8 @@ static int ip_set_rename(struct net *net, struct sock *ctnl, ...@@ -1155,7 +1160,8 @@ static int ip_set_rename(struct net *net, struct sock *ctnl,
static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *from, *to; struct ip_set *from, *to;
...@@ -1428,7 +1434,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1428,7 +1434,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
if (unlikely(protocol_failed(attr))) if (unlikely(protocol_failed(attr)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -1513,7 +1520,8 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, ...@@ -1513,7 +1520,8 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set; struct ip_set *set;
...@@ -1567,7 +1575,8 @@ static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1567,7 +1575,8 @@ static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set; struct ip_set *set;
...@@ -1621,7 +1630,8 @@ static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1621,7 +1630,8 @@ static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb,
static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set; struct ip_set *set;
...@@ -1656,7 +1666,8 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1656,7 +1666,8 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
static int ip_set_header(struct net *net, struct sock *ctnl, static int ip_set_header(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
const struct ip_set *set; const struct ip_set *set;
...@@ -1712,7 +1723,8 @@ static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = { ...@@ -1712,7 +1723,8 @@ static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = {
static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
...@@ -1770,7 +1782,8 @@ ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = { ...@@ -1770,7 +1782,8 @@ ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = {
static int ip_set_protocol(struct net *net, struct sock *ctnl, static int ip_set_protocol(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
......
...@@ -197,8 +197,8 @@ static void __exit nf_conntrack_amanda_fini(void) ...@@ -197,8 +197,8 @@ static void __exit nf_conntrack_amanda_fini(void)
{ {
int i; int i;
nf_conntrack_helper_unregister(&amanda_helper[0]); nf_conntrack_helpers_unregister(amanda_helper,
nf_conntrack_helper_unregister(&amanda_helper[1]); ARRAY_SIZE(amanda_helper));
for (i = 0; i < ARRAY_SIZE(search); i++) for (i = 0; i < ARRAY_SIZE(search); i++)
textsearch_destroy(search[i].ts); textsearch_destroy(search[i].ts);
} }
...@@ -218,16 +218,12 @@ static int __init nf_conntrack_amanda_init(void) ...@@ -218,16 +218,12 @@ static int __init nf_conntrack_amanda_init(void)
goto err1; goto err1;
} }
} }
ret = nf_conntrack_helper_register(&amanda_helper[0]); ret = nf_conntrack_helpers_register(amanda_helper,
ARRAY_SIZE(amanda_helper));
if (ret < 0) if (ret < 0)
goto err1; goto err1;
ret = nf_conntrack_helper_register(&amanda_helper[1]);
if (ret < 0)
goto err2;
return 0; return 0;
err2:
nf_conntrack_helper_unregister(&amanda_helper[0]);
err1: err1:
while (--i >= 0) while (--i >= 0)
textsearch_destroy(search[i].ts); textsearch_destroy(search[i].ts);
......
...@@ -1586,13 +1586,12 @@ static void nf_conntrack_attach(struct sk_buff *nskb, const struct sk_buff *skb) ...@@ -1586,13 +1586,12 @@ static void nf_conntrack_attach(struct sk_buff *nskb, const struct sk_buff *skb)
/* Bring out ya dead! */ /* Bring out ya dead! */
static struct nf_conn * static struct nf_conn *
get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
void *data, unsigned int *bucket) void *data, unsigned int *bucket)
{ {
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct; struct nf_conn *ct;
struct hlist_nulls_node *n; struct hlist_nulls_node *n;
int cpu;
spinlock_t *lockp; spinlock_t *lockp;
for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
...@@ -1604,8 +1603,7 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), ...@@ -1604,8 +1603,7 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
continue; continue;
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (net_eq(nf_ct_net(ct), net) && if (iter(ct, data))
iter(ct, data))
goto found; goto found;
} }
} }
...@@ -1614,51 +1612,150 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), ...@@ -1614,51 +1612,150 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
cond_resched(); cond_resched();
} }
return NULL;
found:
atomic_inc(&ct->ct_general.use);
spin_unlock(lockp);
local_bh_enable();
return ct;
}
static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data),
void *data, u32 portid, int report)
{
unsigned int bucket = 0, sequence;
struct nf_conn *ct;
might_sleep();
for (;;) {
sequence = read_seqcount_begin(&nf_conntrack_generation);
while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) {
/* Time to push up daises... */
nf_ct_delete(ct, portid, report);
nf_ct_put(ct);
cond_resched();
}
if (!read_seqcount_retry(&nf_conntrack_generation, sequence))
break;
bucket = 0;
}
}
struct iter_data {
int (*iter)(struct nf_conn *i, void *data);
void *data;
struct net *net;
};
static int iter_net_only(struct nf_conn *i, void *data)
{
struct iter_data *d = data;
if (!net_eq(d->net, nf_ct_net(i)))
return 0;
return d->iter(i, d->data);
}
static void
__nf_ct_unconfirmed_destroy(struct net *net)
{
int cpu;
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n;
struct ct_pcpu *pcpu;
pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
spin_lock_bh(&pcpu->lock); spin_lock_bh(&pcpu->lock);
hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) { hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
struct nf_conn *ct;
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (iter(ct, data))
set_bit(IPS_DYING_BIT, &ct->status); /* we cannot call iter() on unconfirmed list, the
* owning cpu can reallocate ct->ext at any time.
*/
set_bit(IPS_DYING_BIT, &ct->status);
} }
spin_unlock_bh(&pcpu->lock); spin_unlock_bh(&pcpu->lock);
cond_resched(); cond_resched();
} }
return NULL;
found:
atomic_inc(&ct->ct_general.use);
spin_unlock(lockp);
local_bh_enable();
return ct;
} }
void nf_ct_iterate_cleanup(struct net *net, void nf_ct_iterate_cleanup_net(struct net *net,
int (*iter)(struct nf_conn *i, void *data), int (*iter)(struct nf_conn *i, void *data),
void *data, u32 portid, int report) void *data, u32 portid, int report)
{ {
struct nf_conn *ct; struct iter_data d;
unsigned int bucket = 0;
might_sleep(); might_sleep();
if (atomic_read(&net->ct.count) == 0) if (atomic_read(&net->ct.count) == 0)
return; return;
while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) { __nf_ct_unconfirmed_destroy(net);
/* Time to push up daises... */
nf_ct_delete(ct, portid, report); d.iter = iter;
nf_ct_put(ct); d.data = data;
cond_resched(); d.net = net;
synchronize_net();
nf_ct_iterate_cleanup(iter_net_only, &d, portid, report);
}
EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net);
/**
* nf_ct_iterate_destroy - destroy unconfirmed conntracks and iterate table
* @iter: callback to invoke for each conntrack
* @data: data to pass to @iter
*
* Like nf_ct_iterate_cleanup, but first marks conntracks on the
* unconfirmed list as dying (so they will not be inserted into
* main table).
*
* Can only be called in module exit path.
*/
void
nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data)
{
struct net *net;
rtnl_lock();
for_each_net(net) {
if (atomic_read(&net->ct.count) == 0)
continue;
__nf_ct_unconfirmed_destroy(net);
} }
rtnl_unlock();
/* Need to wait for netns cleanup worker to finish, if its
* running -- it might have deleted a net namespace from
* the global list, so our __nf_ct_unconfirmed_destroy() might
* not have affected all namespaces.
*/
net_ns_barrier();
/* a conntrack could have been unlinked from unconfirmed list
* before we grabbed pcpu lock in __nf_ct_unconfirmed_destroy().
* This makes sure its inserted into conntrack table.
*/
synchronize_net();
nf_ct_iterate_cleanup(iter, data, 0, 0);
} }
EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); EXPORT_SYMBOL_GPL(nf_ct_iterate_destroy);
static int kill_all(struct nf_conn *i, void *data) static int kill_all(struct nf_conn *i, void *data)
{ {
return 1; return net_eq(nf_ct_net(i), data);
} }
void nf_ct_free_hashtable(void *hash, unsigned int size) void nf_ct_free_hashtable(void *hash, unsigned int size)
...@@ -1723,7 +1820,7 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) ...@@ -1723,7 +1820,7 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
i_see_dead_people: i_see_dead_people:
busy = 0; busy = 0;
list_for_each_entry(net, net_exit_list, exit_list) { list_for_each_entry(net, net_exit_list, exit_list) {
nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0); nf_ct_iterate_cleanup(kill_all, net, 0, 0);
if (atomic_read(&net->ct.count) != 0) if (atomic_read(&net->ct.count) != 0)
busy = 1; busy = 1;
} }
......
...@@ -1815,14 +1815,44 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = { ...@@ -1815,14 +1815,44 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
}, },
}; };
static int __init h323_helper_init(void)
{
int ret;
ret = nf_conntrack_helper_register(&nf_conntrack_helper_h245);
if (ret < 0)
return ret;
ret = nf_conntrack_helpers_register(nf_conntrack_helper_q931,
ARRAY_SIZE(nf_conntrack_helper_q931));
if (ret < 0)
goto err1;
ret = nf_conntrack_helpers_register(nf_conntrack_helper_ras,
ARRAY_SIZE(nf_conntrack_helper_ras));
if (ret < 0)
goto err2;
return 0;
err2:
nf_conntrack_helpers_unregister(nf_conntrack_helper_q931,
ARRAY_SIZE(nf_conntrack_helper_q931));
err1:
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
return ret;
}
static void __exit h323_helper_exit(void)
{
nf_conntrack_helpers_unregister(nf_conntrack_helper_ras,
ARRAY_SIZE(nf_conntrack_helper_ras));
nf_conntrack_helpers_unregister(nf_conntrack_helper_q931,
ARRAY_SIZE(nf_conntrack_helper_q931));
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
}
/****************************************************************************/ /****************************************************************************/
static void __exit nf_conntrack_h323_fini(void) static void __exit nf_conntrack_h323_fini(void)
{ {
nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[1]); h323_helper_exit();
nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[0]);
nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]);
nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]);
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
kfree(h323_buffer); kfree(h323_buffer);
pr_debug("nf_ct_h323: fini\n"); pr_debug("nf_ct_h323: fini\n");
} }
...@@ -1837,32 +1867,11 @@ static int __init nf_conntrack_h323_init(void) ...@@ -1837,32 +1867,11 @@ static int __init nf_conntrack_h323_init(void)
h323_buffer = kmalloc(65536, GFP_KERNEL); h323_buffer = kmalloc(65536, GFP_KERNEL);
if (!h323_buffer) if (!h323_buffer)
return -ENOMEM; return -ENOMEM;
ret = nf_conntrack_helper_register(&nf_conntrack_helper_h245); ret = h323_helper_init();
if (ret < 0) if (ret < 0)
goto err1; goto err1;
ret = nf_conntrack_helper_register(&nf_conntrack_helper_q931[0]);
if (ret < 0)
goto err2;
ret = nf_conntrack_helper_register(&nf_conntrack_helper_q931[1]);
if (ret < 0)
goto err3;
ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[0]);
if (ret < 0)
goto err4;
ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[1]);
if (ret < 0)
goto err5;
pr_debug("nf_ct_h323: init success\n"); pr_debug("nf_ct_h323: init success\n");
return 0; return 0;
err5:
nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[0]);
err4:
nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]);
err3:
nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]);
err2:
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
err1: err1:
kfree(h323_buffer); kfree(h323_buffer);
return ret; return ret;
......
...@@ -285,16 +285,16 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, ...@@ -285,16 +285,16 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper); EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
/* appropriate ct lock protecting must be taken by caller */ /* appropriate ct lock protecting must be taken by caller */
static inline int unhelp(struct nf_conntrack_tuple_hash *i, static int unhelp(struct nf_conn *ct, void *me)
const struct nf_conntrack_helper *me)
{ {
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
struct nf_conn_help *help = nfct_help(ct); struct nf_conn_help *help = nfct_help(ct);
if (help && rcu_dereference_raw(help->helper) == me) { if (help && rcu_dereference_raw(help->helper) == me) {
nf_conntrack_event(IPCT_HELPER, ct); nf_conntrack_event(IPCT_HELPER, ct);
RCU_INIT_POINTER(help->helper, NULL); RCU_INIT_POINTER(help->helper, NULL);
} }
/* We are not intended to delete this conntrack. */
return 0; return 0;
} }
...@@ -437,33 +437,10 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) ...@@ -437,33 +437,10 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
} }
EXPORT_SYMBOL_GPL(nf_conntrack_helper_register); EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
struct net *net)
{
struct nf_conntrack_tuple_hash *h;
const struct hlist_nulls_node *nn;
int cpu;
/* Get rid of expecteds, set helpers to NULL. */
for_each_possible_cpu(cpu) {
struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
spin_lock_bh(&pcpu->lock);
hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
unhelp(h, me);
spin_unlock_bh(&pcpu->lock);
}
}
void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
{ {
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
const struct hlist_node *next; const struct hlist_node *next;
const struct hlist_nulls_node *nn;
unsigned int last_hsize;
spinlock_t *lock;
struct net *net;
unsigned int i; unsigned int i;
mutex_lock(&nf_ct_helper_mutex); mutex_lock(&nf_ct_helper_mutex);
...@@ -491,26 +468,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) ...@@ -491,26 +468,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
} }
spin_unlock_bh(&nf_conntrack_expect_lock); spin_unlock_bh(&nf_conntrack_expect_lock);
rtnl_lock(); nf_ct_iterate_destroy(unhelp, me);
for_each_net(net)
__nf_conntrack_helper_unregister(me, net);
rtnl_unlock();
local_bh_disable();
restart:
last_hsize = nf_conntrack_htable_size;
for (i = 0; i < last_hsize; i++) {
lock = &nf_conntrack_locks[i % CONNTRACK_LOCKS];
nf_conntrack_lock(lock);
if (last_hsize != nf_conntrack_htable_size) {
spin_unlock(lock);
goto restart;
}
hlist_nulls_for_each_entry(h, nn, &nf_conntrack_hash[i], hnnode)
unhelp(h, me);
spin_unlock(lock);
}
local_bh_enable();
} }
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
......
...@@ -636,11 +636,11 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) ...@@ -636,11 +636,11 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
if (events & (1 << IPCT_DESTROY)) { if (events & (1 << IPCT_DESTROY)) {
type = IPCTNL_MSG_CT_DELETE; type = IPCTNL_MSG_CT_DELETE;
group = NFNLGRP_CONNTRACK_DESTROY; group = NFNLGRP_CONNTRACK_DESTROY;
} else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) { } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) {
type = IPCTNL_MSG_CT_NEW; type = IPCTNL_MSG_CT_NEW;
flags = NLM_F_CREATE|NLM_F_EXCL; flags = NLM_F_CREATE|NLM_F_EXCL;
group = NFNLGRP_CONNTRACK_NEW; group = NFNLGRP_CONNTRACK_NEW;
} else if (events) { } else if (events) {
type = IPCTNL_MSG_CT_NEW; type = IPCTNL_MSG_CT_NEW;
group = NFNLGRP_CONNTRACK_UPDATE; group = NFNLGRP_CONNTRACK_UPDATE;
} else } else
...@@ -1122,8 +1122,8 @@ static int ctnetlink_flush_conntrack(struct net *net, ...@@ -1122,8 +1122,8 @@ static int ctnetlink_flush_conntrack(struct net *net,
return PTR_ERR(filter); return PTR_ERR(filter);
} }
nf_ct_iterate_cleanup(net, ctnetlink_filter_match, filter, nf_ct_iterate_cleanup_net(net, ctnetlink_filter_match, filter,
portid, report); portid, report);
kfree(filter); kfree(filter);
return 0; return 0;
...@@ -1132,7 +1132,8 @@ static int ctnetlink_flush_conntrack(struct net *net, ...@@ -1132,7 +1132,8 @@ static int ctnetlink_flush_conntrack(struct net *net,
static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
...@@ -1184,7 +1185,8 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, ...@@ -1184,7 +1185,8 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl, static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
...@@ -1345,7 +1347,8 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1345,7 +1347,8 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl, static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
...@@ -1367,7 +1370,8 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1367,7 +1370,8 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl, static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
...@@ -1906,7 +1910,8 @@ ctnetlink_create_conntrack(struct net *net, ...@@ -1906,7 +1910,8 @@ ctnetlink_create_conntrack(struct net *net,
static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_tuple_hash *h = NULL; struct nf_conntrack_tuple_hash *h = NULL;
...@@ -2071,7 +2076,8 @@ ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2071,7 +2076,8 @@ ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl, static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
...@@ -2116,7 +2122,8 @@ ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, ...@@ -2116,7 +2122,8 @@ ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl, static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
int err; int err;
...@@ -2778,7 +2785,8 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2778,7 +2785,8 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl, static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
int err; int err;
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfgenmsg *nfmsg = nlmsg_data(nlh);
...@@ -2822,7 +2830,8 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl, ...@@ -2822,7 +2830,8 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
static int ctnetlink_get_expect(struct net *net, struct sock *ctnl, static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
...@@ -2834,7 +2843,8 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl, ...@@ -2834,7 +2843,8 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (cda[CTA_EXPECT_MASTER]) if (cda[CTA_EXPECT_MASTER])
return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda); return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda,
extack);
else { else {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_exp_dump_table, .dump = ctnetlink_exp_dump_table,
...@@ -2902,7 +2912,8 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl, ...@@ -2902,7 +2912,8 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
static int ctnetlink_del_expect(struct net *net, struct sock *ctnl, static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
...@@ -3190,7 +3201,8 @@ ctnetlink_create_expect(struct net *net, ...@@ -3190,7 +3201,8 @@ ctnetlink_create_expect(struct net *net,
static int ctnetlink_new_expect(struct net *net, struct sock *ctnl, static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
...@@ -3296,7 +3308,8 @@ ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -3296,7 +3308,8 @@ ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl, static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
......
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_core.h>
static struct nf_conntrack_l4proto __rcu **nf_ct_protos[PF_MAX] __read_mostly; static struct nf_conntrack_l4proto __rcu **nf_ct_protos[NFPROTO_NUMPROTO] __read_mostly;
struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX] __read_mostly; struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[NFPROTO_NUMPROTO] __read_mostly;
EXPORT_SYMBOL_GPL(nf_ct_l3protos); EXPORT_SYMBOL_GPL(nf_ct_l3protos);
static DEFINE_MUTEX(nf_ct_proto_mutex); static DEFINE_MUTEX(nf_ct_proto_mutex);
...@@ -68,7 +68,7 @@ nf_ct_unregister_sysctl(struct ctl_table_header **header, ...@@ -68,7 +68,7 @@ nf_ct_unregister_sysctl(struct ctl_table_header **header,
struct nf_conntrack_l4proto * struct nf_conntrack_l4proto *
__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
{ {
if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) if (unlikely(l3proto >= NFPROTO_NUMPROTO || nf_ct_protos[l3proto] == NULL))
return &nf_conntrack_l4proto_generic; return &nf_conntrack_l4proto_generic;
return rcu_dereference(nf_ct_protos[l3proto][l4proto]); return rcu_dereference(nf_ct_protos[l3proto][l4proto]);
...@@ -212,7 +212,7 @@ int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto) ...@@ -212,7 +212,7 @@ int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto)
int ret = 0; int ret = 0;
struct nf_conntrack_l3proto *old; struct nf_conntrack_l3proto *old;
if (proto->l3proto >= AF_MAX) if (proto->l3proto >= NFPROTO_NUMPROTO)
return -EBUSY; return -EBUSY;
if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size) if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size)
...@@ -254,7 +254,7 @@ EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_register); ...@@ -254,7 +254,7 @@ EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_register);
void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto) void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto)
{ {
BUG_ON(proto->l3proto >= AF_MAX); BUG_ON(proto->l3proto >= NFPROTO_NUMPROTO);
mutex_lock(&nf_ct_proto_mutex); mutex_lock(&nf_ct_proto_mutex);
BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto], BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
...@@ -265,6 +265,8 @@ void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto) ...@@ -265,6 +265,8 @@ void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto)
mutex_unlock(&nf_ct_proto_mutex); mutex_unlock(&nf_ct_proto_mutex);
synchronize_rcu(); synchronize_rcu();
/* Remove all contrack entries for this protocol */
nf_ct_iterate_destroy(kill_l3proto, proto);
} }
EXPORT_SYMBOL_GPL(nf_ct_l3proto_unregister); EXPORT_SYMBOL_GPL(nf_ct_l3proto_unregister);
...@@ -280,9 +282,6 @@ void nf_ct_l3proto_pernet_unregister(struct net *net, ...@@ -280,9 +282,6 @@ void nf_ct_l3proto_pernet_unregister(struct net *net,
*/ */
if (proto->net_ns_put) if (proto->net_ns_put)
proto->net_ns_put(net); proto->net_ns_put(net);
/* Remove all contrack entries for this protocol */
nf_ct_iterate_cleanup(net, kill_l3proto, proto, 0, 0);
} }
EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_unregister); EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_unregister);
...@@ -342,7 +341,7 @@ int nf_ct_l4proto_register_one(struct nf_conntrack_l4proto *l4proto) ...@@ -342,7 +341,7 @@ int nf_ct_l4proto_register_one(struct nf_conntrack_l4proto *l4proto)
{ {
int ret = 0; int ret = 0;
if (l4proto->l3proto >= PF_MAX) if (l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos))
return -EBUSY; return -EBUSY;
if ((l4proto->to_nlattr && !l4proto->nlattr_size) || if ((l4proto->to_nlattr && !l4proto->nlattr_size) ||
...@@ -421,17 +420,23 @@ int nf_ct_l4proto_pernet_register_one(struct net *net, ...@@ -421,17 +420,23 @@ int nf_ct_l4proto_pernet_register_one(struct net *net,
} }
EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register_one); EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register_one);
void nf_ct_l4proto_unregister_one(struct nf_conntrack_l4proto *l4proto) static void __nf_ct_l4proto_unregister_one(struct nf_conntrack_l4proto *l4proto)
{ {
BUG_ON(l4proto->l3proto >= PF_MAX); BUG_ON(l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos));
mutex_lock(&nf_ct_proto_mutex);
BUG_ON(rcu_dereference_protected( BUG_ON(rcu_dereference_protected(
nf_ct_protos[l4proto->l3proto][l4proto->l4proto], nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
lockdep_is_held(&nf_ct_proto_mutex) lockdep_is_held(&nf_ct_proto_mutex)
) != l4proto); ) != l4proto);
rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
&nf_conntrack_l4proto_generic); &nf_conntrack_l4proto_generic);
}
void nf_ct_l4proto_unregister_one(struct nf_conntrack_l4proto *l4proto)
{
mutex_lock(&nf_ct_proto_mutex);
__nf_ct_l4proto_unregister_one(l4proto);
mutex_unlock(&nf_ct_proto_mutex); mutex_unlock(&nf_ct_proto_mutex);
synchronize_rcu(); synchronize_rcu();
...@@ -448,9 +453,6 @@ void nf_ct_l4proto_pernet_unregister_one(struct net *net, ...@@ -448,9 +453,6 @@ void nf_ct_l4proto_pernet_unregister_one(struct net *net,
pn->users--; pn->users--;
nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
/* Remove all contrack entries for this protocol */
nf_ct_iterate_cleanup(net, kill_l4proto, l4proto, 0, 0);
} }
EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one); EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one);
...@@ -500,8 +502,14 @@ EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); ...@@ -500,8 +502,14 @@ EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register);
void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto[], void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto[],
unsigned int num_proto) unsigned int num_proto)
{ {
mutex_lock(&nf_ct_proto_mutex);
while (num_proto-- != 0) while (num_proto-- != 0)
nf_ct_l4proto_unregister_one(l4proto[num_proto]); __nf_ct_l4proto_unregister_one(l4proto[num_proto]);
mutex_unlock(&nf_ct_proto_mutex);
synchronize_net();
/* Remove all contrack entries for this protocol */
nf_ct_iterate_destroy(kill_l4proto, l4proto);
} }
EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister); EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister);
...@@ -548,7 +556,7 @@ void nf_conntrack_proto_pernet_fini(struct net *net) ...@@ -548,7 +556,7 @@ void nf_conntrack_proto_pernet_fini(struct net *net)
int nf_conntrack_proto_init(void) int nf_conntrack_proto_init(void)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < AF_MAX; i++) for (i = 0; i < NFPROTO_NUMPROTO; i++)
rcu_assign_pointer(nf_ct_l3protos[i], rcu_assign_pointer(nf_ct_l3protos[i],
&nf_conntrack_l3proto_generic); &nf_conntrack_l3proto_generic);
return 0; return 0;
...@@ -558,6 +566,6 @@ void nf_conntrack_proto_fini(void) ...@@ -558,6 +566,6 @@ void nf_conntrack_proto_fini(void)
{ {
unsigned int i; unsigned int i;
/* free l3proto protocol tables */ /* free l3proto protocol tables */
for (i = 0; i < PF_MAX; i++) for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++)
kfree(nf_ct_protos[i]); kfree(nf_ct_protos[i]);
} }
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_dup_netdev.h>
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev) static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev)
{ {
......
...@@ -582,12 +582,8 @@ static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto) ...@@ -582,12 +582,8 @@ static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
.l3proto = l3proto, .l3proto = l3proto,
.l4proto = l4proto, .l4proto = l4proto,
}; };
struct net *net;
rtnl_lock(); nf_ct_iterate_destroy(nf_nat_proto_remove, &clean);
for_each_net(net)
nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean, 0, 0);
rtnl_unlock();
} }
static void nf_nat_l3proto_clean(u8 l3proto) static void nf_nat_l3proto_clean(u8 l3proto)
...@@ -595,13 +591,8 @@ static void nf_nat_l3proto_clean(u8 l3proto) ...@@ -595,13 +591,8 @@ static void nf_nat_l3proto_clean(u8 l3proto)
struct nf_nat_proto_clean clean = { struct nf_nat_proto_clean clean = {
.l3proto = l3proto, .l3proto = l3proto,
}; };
struct net *net;
rtnl_lock(); nf_ct_iterate_destroy(nf_nat_proto_remove, &clean);
for_each_net(net)
nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean, 0, 0);
rtnl_unlock();
} }
/* Protocol registration. */ /* Protocol registration. */
...@@ -822,17 +813,6 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, ...@@ -822,17 +813,6 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct,
} }
#endif #endif
static void __net_exit nf_nat_net_exit(struct net *net)
{
struct nf_nat_proto_clean clean = {};
nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean, 0, 0);
}
static struct pernet_operations nf_nat_net_ops = {
.exit = nf_nat_net_exit,
};
static struct nf_ct_helper_expectfn follow_master_nat = { static struct nf_ct_helper_expectfn follow_master_nat = {
.name = "nat-follow-master", .name = "nat-follow-master",
.expectfn = nf_nat_follow_master, .expectfn = nf_nat_follow_master,
...@@ -853,10 +833,6 @@ static int __init nf_nat_init(void) ...@@ -853,10 +833,6 @@ static int __init nf_nat_init(void)
return ret; return ret;
} }
ret = register_pernet_subsys(&nf_nat_net_ops);
if (ret < 0)
goto cleanup_extend;
nf_ct_helper_expectfn_register(&follow_master_nat); nf_ct_helper_expectfn_register(&follow_master_nat);
BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
...@@ -867,18 +843,15 @@ static int __init nf_nat_init(void) ...@@ -867,18 +843,15 @@ static int __init nf_nat_init(void)
RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session); RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session);
#endif #endif
return 0; return 0;
cleanup_extend:
rhltable_destroy(&nf_nat_bysource_table);
nf_ct_extend_unregister(&nat_extend);
return ret;
} }
static void __exit nf_nat_cleanup(void) static void __exit nf_nat_cleanup(void)
{ {
struct nf_nat_proto_clean clean = {};
unsigned int i; unsigned int i;
unregister_pernet_subsys(&nf_nat_net_ops); nf_ct_iterate_destroy(nf_nat_proto_clean, &clean);
nf_ct_extend_unregister(&nat_extend); nf_ct_extend_unregister(&nat_extend);
nf_ct_helper_expectfn_unregister(&follow_master_nat); nf_ct_helper_expectfn_unregister(&follow_master_nat);
RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
......
This diff is collapsed.
...@@ -201,7 +201,8 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -201,7 +201,8 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
if (nc->call_rcu) { if (nc->call_rcu) {
err = nc->call_rcu(net, net->nfnl, skb, nlh, err = nc->call_rcu(net, net->nfnl, skb, nlh,
(const struct nlattr **)cda); (const struct nlattr **)cda,
extack);
rcu_read_unlock(); rcu_read_unlock();
} else { } else {
rcu_read_unlock(); rcu_read_unlock();
...@@ -211,7 +212,8 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -211,7 +212,8 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
err = -EAGAIN; err = -EAGAIN;
else if (nc->call) else if (nc->call)
err = nc->call(net, net->nfnl, skb, nlh, err = nc->call(net, net->nfnl, skb, nlh,
(const struct nlattr **)cda); (const struct nlattr **)cda,
extack);
else else
err = -EINVAL; err = -EINVAL;
nfnl_unlock(subsys_id); nfnl_unlock(subsys_id);
...@@ -226,9 +228,11 @@ struct nfnl_err { ...@@ -226,9 +228,11 @@ struct nfnl_err {
struct list_head head; struct list_head head;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
int err; int err;
struct netlink_ext_ack extack;
}; };
static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err) static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err,
const struct netlink_ext_ack *extack)
{ {
struct nfnl_err *nfnl_err; struct nfnl_err *nfnl_err;
...@@ -238,6 +242,7 @@ static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err) ...@@ -238,6 +242,7 @@ static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err)
nfnl_err->nlh = nlh; nfnl_err->nlh = nlh;
nfnl_err->err = err; nfnl_err->err = err;
nfnl_err->extack = *extack;
list_add_tail(&nfnl_err->head, list); list_add_tail(&nfnl_err->head, list);
return 0; return 0;
...@@ -262,7 +267,8 @@ static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb) ...@@ -262,7 +267,8 @@ static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb)
struct nfnl_err *nfnl_err, *next; struct nfnl_err *nfnl_err, *next;
list_for_each_entry_safe(nfnl_err, next, err_list, head) { list_for_each_entry_safe(nfnl_err, next, err_list, head) {
netlink_ack(skb, nfnl_err->nlh, nfnl_err->err, NULL); netlink_ack(skb, nfnl_err->nlh, nfnl_err->err,
&nfnl_err->extack);
nfnl_err_del(nfnl_err); nfnl_err_del(nfnl_err);
} }
} }
...@@ -280,6 +286,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -280,6 +286,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
const struct nfnetlink_subsystem *ss; const struct nfnetlink_subsystem *ss;
const struct nfnl_callback *nc; const struct nfnl_callback *nc;
struct netlink_ext_ack extack;
LIST_HEAD(err_list); LIST_HEAD(err_list);
u32 status; u32 status;
int err; int err;
...@@ -325,6 +332,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -325,6 +332,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
while (skb->len >= nlmsg_total_size(0)) { while (skb->len >= nlmsg_total_size(0)) {
int msglen, type; int msglen, type;
memset(&extack, 0, sizeof(extack));
nlh = nlmsg_hdr(skb); nlh = nlmsg_hdr(skb);
err = 0; err = 0;
...@@ -384,7 +392,8 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -384,7 +392,8 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
if (nc->call_batch) { if (nc->call_batch) {
err = nc->call_batch(net, net->nfnl, skb, nlh, err = nc->call_batch(net, net->nfnl, skb, nlh,
(const struct nlattr **)cda); (const struct nlattr **)cda,
&extack);
} }
/* The lock was released to autoload some module, we /* The lock was released to autoload some module, we
...@@ -402,7 +411,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -402,7 +411,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
* processed, this avoids that the same error is * processed, this avoids that the same error is
* reported several times when replaying the batch. * reported several times when replaying the batch.
*/ */
if (nfnl_err_add(&err_list, nlh, err) < 0) { if (nfnl_err_add(&err_list, nlh, err, &extack) < 0) {
/* We failed to enqueue an error, reset the /* We failed to enqueue an error, reset the
* list of errors and send OOM to userspace * list of errors and send OOM to userspace
* pointing to the batch header. * pointing to the batch header.
......
...@@ -49,7 +49,8 @@ struct nfacct_filter { ...@@ -49,7 +49,8 @@ struct nfacct_filter {
static int nfnl_acct_new(struct net *net, struct sock *nfnl, static int nfnl_acct_new(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nf_acct *nfacct, *matching = NULL; struct nf_acct *nfacct, *matching = NULL;
char *acct_name; char *acct_name;
...@@ -264,7 +265,8 @@ nfacct_filter_alloc(const struct nlattr * const attr) ...@@ -264,7 +265,8 @@ nfacct_filter_alloc(const struct nlattr * const attr)
static int nfnl_acct_get(struct net *net, struct sock *nfnl, static int nfnl_acct_get(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
int ret = -ENOENT; int ret = -ENOENT;
struct nf_acct *cur; struct nf_acct *cur;
...@@ -343,7 +345,8 @@ static int nfnl_acct_try_del(struct nf_acct *cur) ...@@ -343,7 +345,8 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
static int nfnl_acct_del(struct net *net, struct sock *nfnl, static int nfnl_acct_del(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nf_acct *cur, *tmp; struct nf_acct *cur, *tmp;
int ret = -ENOENT; int ret = -ENOENT;
......
...@@ -398,7 +398,8 @@ nfnl_cthelper_update(const struct nlattr * const tb[], ...@@ -398,7 +398,8 @@ nfnl_cthelper_update(const struct nlattr * const tb[],
static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
const char *helper_name; const char *helper_name;
struct nf_conntrack_helper *cur, *helper = NULL; struct nf_conntrack_helper *cur, *helper = NULL;
...@@ -599,7 +600,8 @@ nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -599,7 +600,8 @@ nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
int ret = -ENOENT; int ret = -ENOENT;
struct nf_conntrack_helper *cur; struct nf_conntrack_helper *cur;
...@@ -666,7 +668,8 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, ...@@ -666,7 +668,8 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
char *helper_name = NULL; char *helper_name = NULL;
struct nf_conntrack_helper *cur; struct nf_conntrack_helper *cur;
......
...@@ -69,7 +69,8 @@ ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto, ...@@ -69,7 +69,8 @@ ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
static int cttimeout_new_timeout(struct net *net, struct sock *ctnl, static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
__u16 l3num; __u16 l3num;
__u8 l4num; __u8 l4num;
...@@ -239,7 +240,8 @@ ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -239,7 +240,8 @@ ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
static int cttimeout_get_timeout(struct net *net, struct sock *ctnl, static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
int ret = -ENOENT; int ret = -ENOENT;
char *name; char *name;
...@@ -287,49 +289,20 @@ static int cttimeout_get_timeout(struct net *net, struct sock *ctnl, ...@@ -287,49 +289,20 @@ static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
return ret; return ret;
} }
static void untimeout(struct nf_conntrack_tuple_hash *i, static int untimeout(struct nf_conn *ct, void *timeout)
struct ctnl_timeout *timeout)
{ {
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct); struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct);
if (timeout_ext && (!timeout || timeout_ext->timeout == timeout)) if (timeout_ext && (!timeout || timeout_ext->timeout == timeout))
RCU_INIT_POINTER(timeout_ext->timeout, NULL); RCU_INIT_POINTER(timeout_ext->timeout, NULL);
/* We are not intended to delete this conntrack. */
return 0;
} }
static void ctnl_untimeout(struct net *net, struct ctnl_timeout *timeout) static void ctnl_untimeout(struct net *net, struct ctnl_timeout *timeout)
{ {
struct nf_conntrack_tuple_hash *h; nf_ct_iterate_cleanup_net(net, untimeout, timeout, 0, 0);
const struct hlist_nulls_node *nn;
unsigned int last_hsize;
spinlock_t *lock;
int i, cpu;
for_each_possible_cpu(cpu) {
struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
spin_lock_bh(&pcpu->lock);
hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
untimeout(h, timeout);
spin_unlock_bh(&pcpu->lock);
}
local_bh_disable();
restart:
last_hsize = nf_conntrack_htable_size;
for (i = 0; i < last_hsize; i++) {
lock = &nf_conntrack_locks[i % CONNTRACK_LOCKS];
nf_conntrack_lock(lock);
if (last_hsize != nf_conntrack_htable_size) {
spin_unlock(lock);
goto restart;
}
hlist_nulls_for_each_entry(h, nn, &nf_conntrack_hash[i], hnnode)
untimeout(h, timeout);
spin_unlock(lock);
}
local_bh_enable();
} }
/* try to delete object, fail if it is still in use. */ /* try to delete object, fail if it is still in use. */
...@@ -355,7 +328,8 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout) ...@@ -355,7 +328,8 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
static int cttimeout_del_timeout(struct net *net, struct sock *ctnl, static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct ctnl_timeout *cur, *tmp; struct ctnl_timeout *cur, *tmp;
int ret = -ENOENT; int ret = -ENOENT;
...@@ -386,7 +360,8 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl, ...@@ -386,7 +360,8 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
static int cttimeout_default_set(struct net *net, struct sock *ctnl, static int cttimeout_default_set(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
__u16 l3num; __u16 l3num;
__u8 l4num; __u8 l4num;
...@@ -475,7 +450,8 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, ...@@ -475,7 +450,8 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
static int cttimeout_default_get(struct net *net, struct sock *ctnl, static int cttimeout_default_get(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const cda[]) const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
__u16 l3num; __u16 l3num;
__u8 l4num; __u8 l4num;
......
...@@ -795,7 +795,8 @@ static struct notifier_block nfulnl_rtnl_notifier = { ...@@ -795,7 +795,8 @@ static struct notifier_block nfulnl_rtnl_notifier = {
static int nfulnl_recv_unsupp(struct net *net, struct sock *ctnl, static int nfulnl_recv_unsupp(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[]) const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -818,7 +819,8 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = { ...@@ -818,7 +819,8 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = {
static int nfulnl_recv_config(struct net *net, struct sock *ctnl, static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfula[]) const struct nlattr * const nfula[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int16_t group_num = ntohs(nfmsg->res_id); u_int16_t group_num = ntohs(nfmsg->res_id);
......
...@@ -1032,7 +1032,8 @@ static int nfq_id_after(unsigned int id, unsigned int max) ...@@ -1032,7 +1032,8 @@ static int nfq_id_after(unsigned int id, unsigned int max)
static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl, static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[]) const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nf_queue_entry *entry, *tmp; struct nf_queue_entry *entry, *tmp;
...@@ -1136,7 +1137,8 @@ static int nfqa_parse_bridge(struct nf_queue_entry *entry, ...@@ -1136,7 +1137,8 @@ static int nfqa_parse_bridge(struct nf_queue_entry *entry,
static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl, static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[]) const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id); u_int16_t queue_num = ntohs(nfmsg->res_id);
...@@ -1200,7 +1202,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl, ...@@ -1200,7 +1202,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl, static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[]) const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -1217,7 +1220,8 @@ static const struct nf_queue_handler nfqh = { ...@@ -1217,7 +1220,8 @@ static const struct nf_queue_handler nfqh = {
static int nfqnl_recv_config(struct net *net, struct sock *ctnl, static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[]) const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id); u_int16_t queue_num = ntohs(nfmsg->res_id);
......
...@@ -530,7 +530,8 @@ nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, ...@@ -530,7 +530,8 @@ nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
static int nfnl_compat_get(struct net *net, struct sock *nfnl, static int nfnl_compat_get(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[]) const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
int ret = 0, target; int ret = 0, target;
struct nfgenmsg *nfmsg; struct nfgenmsg *nfmsg;
......
...@@ -23,9 +23,9 @@ struct nft_rt { ...@@ -23,9 +23,9 @@ struct nft_rt {
enum nft_registers dreg:8; enum nft_registers dreg:8;
}; };
void nft_rt_get_eval(const struct nft_expr *expr, static void nft_rt_get_eval(const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_pktinfo *pkt) const struct nft_pktinfo *pkt)
{ {
const struct nft_rt *priv = nft_expr_priv(expr); const struct nft_rt *priv = nft_expr_priv(expr);
const struct sk_buff *skb = pkt->skb; const struct sk_buff *skb = pkt->skb;
...@@ -72,9 +72,9 @@ const struct nla_policy nft_rt_policy[NFTA_RT_MAX + 1] = { ...@@ -72,9 +72,9 @@ const struct nla_policy nft_rt_policy[NFTA_RT_MAX + 1] = {
[NFTA_RT_KEY] = { .type = NLA_U32 }, [NFTA_RT_KEY] = { .type = NLA_U32 },
}; };
int nft_rt_get_init(const struct nft_ctx *ctx, static int nft_rt_get_init(const struct nft_ctx *ctx,
const struct nft_expr *expr, const struct nft_expr *expr,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_rt *priv = nft_expr_priv(expr); struct nft_rt *priv = nft_expr_priv(expr);
unsigned int len; unsigned int len;
...@@ -103,8 +103,8 @@ int nft_rt_get_init(const struct nft_ctx *ctx, ...@@ -103,8 +103,8 @@ int nft_rt_get_init(const struct nft_ctx *ctx,
NFT_DATA_VALUE, len); NFT_DATA_VALUE, len);
} }
int nft_rt_get_dump(struct sk_buff *skb, static int nft_rt_get_dump(struct sk_buff *skb,
const struct nft_expr *expr) const struct nft_expr *expr)
{ {
const struct nft_rt *priv = nft_expr_priv(expr); const struct nft_rt *priv = nft_expr_priv(expr);
......
...@@ -236,7 +236,8 @@ static inline u32 nft_bitmap_total_size(u32 klen) ...@@ -236,7 +236,8 @@ static inline u32 nft_bitmap_total_size(u32 klen)
return sizeof(struct nft_bitmap) + nft_bitmap_size(klen); return sizeof(struct nft_bitmap) + nft_bitmap_size(klen);
} }
static unsigned int nft_bitmap_privsize(const struct nlattr * const nla[]) static unsigned int nft_bitmap_privsize(const struct nlattr * const nla[],
const struct nft_set_desc *desc)
{ {
u32 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN])); u32 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
...@@ -278,7 +279,9 @@ static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -278,7 +279,9 @@ static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
return true; return true;
} }
static struct nft_set_type nft_bitmap_type;
static struct nft_set_ops nft_bitmap_ops __read_mostly = { static struct nft_set_ops nft_bitmap_ops __read_mostly = {
.type = &nft_bitmap_type,
.privsize = nft_bitmap_privsize, .privsize = nft_bitmap_privsize,
.elemsize = offsetof(struct nft_bitmap_elem, ext), .elemsize = offsetof(struct nft_bitmap_elem, ext),
.estimate = nft_bitmap_estimate, .estimate = nft_bitmap_estimate,
...@@ -291,17 +294,21 @@ static struct nft_set_ops nft_bitmap_ops __read_mostly = { ...@@ -291,17 +294,21 @@ static struct nft_set_ops nft_bitmap_ops __read_mostly = {
.activate = nft_bitmap_activate, .activate = nft_bitmap_activate,
.lookup = nft_bitmap_lookup, .lookup = nft_bitmap_lookup,
.walk = nft_bitmap_walk, .walk = nft_bitmap_walk,
};
static struct nft_set_type nft_bitmap_type __read_mostly = {
.ops = &nft_bitmap_ops,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int __init nft_bitmap_module_init(void) static int __init nft_bitmap_module_init(void)
{ {
return nft_register_set(&nft_bitmap_ops); return nft_register_set(&nft_bitmap_type);
} }
static void __exit nft_bitmap_module_exit(void) static void __exit nft_bitmap_module_exit(void)
{ {
nft_unregister_set(&nft_bitmap_ops); nft_unregister_set(&nft_bitmap_type);
} }
module_init(nft_bitmap_module_init); module_init(nft_bitmap_module_init);
......
This diff is collapsed.
...@@ -251,7 +251,8 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, ...@@ -251,7 +251,8 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
read_unlock_bh(&priv->lock); read_unlock_bh(&priv->lock);
} }
static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[]) static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[],
const struct nft_set_desc *desc)
{ {
return sizeof(struct nft_rbtree); return sizeof(struct nft_rbtree);
} }
...@@ -283,13 +284,11 @@ static void nft_rbtree_destroy(const struct nft_set *set) ...@@ -283,13 +284,11 @@ static void nft_rbtree_destroy(const struct nft_set *set)
static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
struct nft_set_estimate *est) struct nft_set_estimate *est)
{ {
unsigned int nsize;
nsize = sizeof(struct nft_rbtree_elem);
if (desc->size) if (desc->size)
est->size = sizeof(struct nft_rbtree) + desc->size * nsize; est->size = sizeof(struct nft_rbtree) +
desc->size * sizeof(struct nft_rbtree_elem);
else else
est->size = nsize; est->size = ~0;
est->lookup = NFT_SET_CLASS_O_LOG_N; est->lookup = NFT_SET_CLASS_O_LOG_N;
est->space = NFT_SET_CLASS_O_N; est->space = NFT_SET_CLASS_O_N;
...@@ -297,7 +296,9 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -297,7 +296,9 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
return true; return true;
} }
static struct nft_set_type nft_rbtree_type;
static struct nft_set_ops nft_rbtree_ops __read_mostly = { static struct nft_set_ops nft_rbtree_ops __read_mostly = {
.type = &nft_rbtree_type,
.privsize = nft_rbtree_privsize, .privsize = nft_rbtree_privsize,
.elemsize = offsetof(struct nft_rbtree_elem, ext), .elemsize = offsetof(struct nft_rbtree_elem, ext),
.estimate = nft_rbtree_estimate, .estimate = nft_rbtree_estimate,
...@@ -311,17 +312,21 @@ static struct nft_set_ops nft_rbtree_ops __read_mostly = { ...@@ -311,17 +312,21 @@ static struct nft_set_ops nft_rbtree_ops __read_mostly = {
.lookup = nft_rbtree_lookup, .lookup = nft_rbtree_lookup,
.walk = nft_rbtree_walk, .walk = nft_rbtree_walk,
.features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT, .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT,
};
static struct nft_set_type nft_rbtree_type __read_mostly = {
.ops = &nft_rbtree_ops,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int __init nft_rbtree_module_init(void) static int __init nft_rbtree_module_init(void)
{ {
return nft_register_set(&nft_rbtree_ops); return nft_register_set(&nft_rbtree_type);
} }
static void __exit nft_rbtree_module_exit(void) static void __exit nft_rbtree_module_exit(void)
{ {
nft_unregister_set(&nft_rbtree_ops); nft_unregister_set(&nft_rbtree_type);
} }
module_init(nft_rbtree_module_init); module_init(nft_rbtree_module_init);
......
...@@ -63,7 +63,8 @@ static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = { ...@@ -63,7 +63,8 @@ static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
static int xt_osf_add_callback(struct net *net, struct sock *ctnl, static int xt_osf_add_callback(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const osf_attrs[]) const struct nlattr * const osf_attrs[],
struct netlink_ext_ack *extack)
{ {
struct xt_osf_user_finger *f; struct xt_osf_user_finger *f;
struct xt_osf_finger *kf = NULL, *sf; struct xt_osf_finger *kf = NULL, *sf;
...@@ -107,7 +108,8 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl, ...@@ -107,7 +108,8 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl,
static int xt_osf_remove_callback(struct net *net, struct sock *ctnl, static int xt_osf_remove_callback(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const osf_attrs[]) const struct nlattr * const osf_attrs[],
struct netlink_ext_ack *extack)
{ {
struct xt_osf_user_finger *f; struct xt_osf_user_finger *f;
struct xt_osf_finger *sf; struct xt_osf_finger *sf;
......
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