netfilter: nfnetlink: netns support
Make nfnl socket per-petns. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
parent
7f635d0d1b
commit
cd8c20b650
|
@ -73,11 +73,11 @@ struct nfnetlink_subsystem {
|
||||||
extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
|
extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
|
||||||
extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
|
extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
|
||||||
|
|
||||||
extern int nfnetlink_has_listeners(unsigned int group);
|
extern int nfnetlink_has_listeners(struct net *net, unsigned int group);
|
||||||
extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
|
extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group,
|
||||||
int echo, gfp_t flags);
|
int echo, gfp_t flags);
|
||||||
extern void nfnetlink_set_err(u32 pid, u32 group, int error);
|
extern void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
|
||||||
extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
|
extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
|
||||||
|
|
||||||
extern void nfnl_lock(void);
|
extern void nfnl_lock(void);
|
||||||
extern void nfnl_unlock(void);
|
extern void nfnl_unlock(void);
|
||||||
|
|
|
@ -81,6 +81,8 @@ struct net {
|
||||||
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
||||||
struct netns_ct ct;
|
struct netns_ct ct;
|
||||||
#endif
|
#endif
|
||||||
|
struct sock *nfnl;
|
||||||
|
struct sock *nfnl_stash;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
struct netns_xfrm xfrm;
|
struct netns_xfrm xfrm;
|
||||||
|
|
|
@ -482,7 +482,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
|
||||||
} else
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!item->report && !nfnetlink_has_listeners(group))
|
if (!item->report && !nfnetlink_has_listeners(&init_net, group))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC);
|
skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC);
|
||||||
|
@ -559,7 +559,8 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
nlmsg_end(skb, nlh);
|
nlmsg_end(skb, nlh);
|
||||||
err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC);
|
err = nfnetlink_send(skb, &init_net, item->pid, group, item->report,
|
||||||
|
GFP_ATOMIC);
|
||||||
if (err == -ENOBUFS || err == -EAGAIN)
|
if (err == -ENOBUFS || err == -EAGAIN)
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
@ -571,7 +572,7 @@ nla_put_failure:
|
||||||
nlmsg_failure:
|
nlmsg_failure:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
errout:
|
errout:
|
||||||
nfnetlink_set_err(0, group, -ENOBUFS);
|
nfnetlink_set_err(&init_net, 0, group, -ENOBUFS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NF_CONNTRACK_EVENTS */
|
#endif /* CONFIG_NF_CONNTRACK_EVENTS */
|
||||||
|
@ -1539,7 +1540,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!item->report &&
|
if (!item->report &&
|
||||||
!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW))
|
!nfnetlink_has_listeners(&init_net, NFNLGRP_CONNTRACK_EXP_NEW))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
||||||
|
@ -1562,7 +1563,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
nlmsg_end(skb, nlh);
|
nlmsg_end(skb, nlh);
|
||||||
nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW,
|
nfnetlink_send(skb, &init_net, item->pid, NFNLGRP_CONNTRACK_EXP_NEW,
|
||||||
item->report, GFP_ATOMIC);
|
item->report, GFP_ATOMIC);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1572,7 +1573,7 @@ nla_put_failure:
|
||||||
nlmsg_failure:
|
nlmsg_failure:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
errout:
|
errout:
|
||||||
nfnetlink_set_err(0, 0, -ENOBUFS);
|
nfnetlink_set_err(&init_net, 0, 0, -ENOBUFS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,7 +40,6 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
|
||||||
|
|
||||||
static char __initdata nfversion[] = "0.30";
|
static char __initdata nfversion[] = "0.30";
|
||||||
|
|
||||||
static struct sock *nfnl = NULL;
|
|
||||||
static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
|
static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
|
||||||
static DEFINE_MUTEX(nfnl_mutex);
|
static DEFINE_MUTEX(nfnl_mutex);
|
||||||
|
|
||||||
|
@ -101,34 +100,35 @@ nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss)
|
||||||
return &ss->cb[cb_id];
|
return &ss->cb[cb_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfnetlink_has_listeners(unsigned int group)
|
int nfnetlink_has_listeners(struct net *net, unsigned int group)
|
||||||
{
|
{
|
||||||
return netlink_has_listeners(nfnl, group);
|
return netlink_has_listeners(net->nfnl, group);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
|
EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
|
||||||
|
|
||||||
int nfnetlink_send(struct sk_buff *skb, u32 pid,
|
int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid,
|
||||||
unsigned group, int echo, gfp_t flags)
|
unsigned group, int echo, gfp_t flags)
|
||||||
{
|
{
|
||||||
return nlmsg_notify(nfnl, skb, pid, group, echo, flags);
|
return nlmsg_notify(net->nfnl, skb, pid, group, echo, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfnetlink_send);
|
EXPORT_SYMBOL_GPL(nfnetlink_send);
|
||||||
|
|
||||||
void nfnetlink_set_err(u32 pid, u32 group, int error)
|
void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error)
|
||||||
{
|
{
|
||||||
netlink_set_err(nfnl, pid, group, error);
|
netlink_set_err(net->nfnl, pid, group, error);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
|
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
|
||||||
|
|
||||||
int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
|
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags)
|
||||||
{
|
{
|
||||||
return netlink_unicast(nfnl, skb, pid, flags);
|
return netlink_unicast(net->nfnl, skb, pid, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
|
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
|
||||||
|
|
||||||
/* Process one complete nfnetlink message. */
|
/* Process one complete nfnetlink message. */
|
||||||
static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||||
{
|
{
|
||||||
|
struct net *net = sock_net(skb->sk);
|
||||||
const struct nfnl_callback *nc;
|
const struct nfnl_callback *nc;
|
||||||
const struct nfnetlink_subsystem *ss;
|
const struct nfnetlink_subsystem *ss;
|
||||||
int type, err;
|
int type, err;
|
||||||
|
@ -170,7 +170,7 @@ replay:
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = nc->call(nfnl, skb, nlh, (const struct nlattr **)cda);
|
err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda);
|
||||||
if (err == -EAGAIN)
|
if (err == -EAGAIN)
|
||||||
goto replay;
|
goto replay;
|
||||||
return err;
|
return err;
|
||||||
|
@ -184,26 +184,45 @@ static void nfnetlink_rcv(struct sk_buff *skb)
|
||||||
nfnl_unlock();
|
nfnl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit nfnetlink_exit(void)
|
static int __net_init nfnetlink_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
printk("Removing netfilter NETLINK layer.\n");
|
struct sock *nfnl;
|
||||||
netlink_kernel_release(nfnl);
|
|
||||||
return;
|
nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, NFNLGRP_MAX,
|
||||||
|
nfnetlink_rcv, NULL, THIS_MODULE);
|
||||||
|
if (!nfnl)
|
||||||
|
return -ENOMEM;
|
||||||
|
net->nfnl_stash = nfnl;
|
||||||
|
rcu_assign_pointer(net->nfnl, nfnl);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
|
||||||
|
{
|
||||||
|
struct net *net;
|
||||||
|
|
||||||
|
list_for_each_entry(net, net_exit_list, exit_list)
|
||||||
|
rcu_assign_pointer(net->nfnl, NULL);
|
||||||
|
synchronize_net();
|
||||||
|
list_for_each_entry(net, net_exit_list, exit_list)
|
||||||
|
netlink_kernel_release(net->nfnl_stash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pernet_operations nfnetlink_net_ops = {
|
||||||
|
.init = nfnetlink_net_init,
|
||||||
|
.exit_batch = nfnetlink_net_exit_batch,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init nfnetlink_init(void)
|
static int __init nfnetlink_init(void)
|
||||||
{
|
{
|
||||||
printk("Netfilter messages via NETLINK v%s.\n", nfversion);
|
printk("Netfilter messages via NETLINK v%s.\n", nfversion);
|
||||||
|
return register_pernet_subsys(&nfnetlink_net_ops);
|
||||||
nfnl = netlink_kernel_create(&init_net, NETLINK_NETFILTER, NFNLGRP_MAX,
|
|
||||||
nfnetlink_rcv, NULL, THIS_MODULE);
|
|
||||||
if (!nfnl) {
|
|
||||||
printk(KERN_ERR "cannot initialize nfnetlink!\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
static void __exit nfnetlink_exit(void)
|
||||||
|
{
|
||||||
|
printk("Removing netfilter NETLINK layer.\n");
|
||||||
|
unregister_pernet_subsys(&nfnetlink_net_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(nfnetlink_init);
|
module_init(nfnetlink_init);
|
||||||
module_exit(nfnetlink_exit);
|
module_exit(nfnetlink_exit);
|
||||||
|
|
|
@ -323,7 +323,8 @@ __nfulnl_send(struct nfulnl_instance *inst)
|
||||||
NLMSG_DONE,
|
NLMSG_DONE,
|
||||||
sizeof(struct nfgenmsg));
|
sizeof(struct nfgenmsg));
|
||||||
|
|
||||||
status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT);
|
status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_pid,
|
||||||
|
MSG_DONTWAIT);
|
||||||
|
|
||||||
inst->qlen = 0;
|
inst->qlen = 0;
|
||||||
inst->skb = NULL;
|
inst->skb = NULL;
|
||||||
|
|
|
@ -420,7 +420,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nfnetlink_unicast will either free the nskb or add it to a socket */
|
/* nfnetlink_unicast will either free the nskb or add it to a socket */
|
||||||
err = nfnetlink_unicast(nskb, queue->peer_pid, MSG_DONTWAIT);
|
err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
queue->queue_user_dropped++;
|
queue->queue_user_dropped++;
|
||||||
goto err_out_unlock;
|
goto err_out_unlock;
|
||||||
|
|
Loading…
Reference in New Issue