Skip to content

Commit

Permalink
IPVS: init and cleanup restructuring
Browse files Browse the repository at this point in the history
DESCRIPTION
This patch tries to restore the initial init and cleanup
sequences that was before namspace patch.
Netns also requires action when net devices unregister
which has never been implemented. I.e this patch also
covers when a device moves into a network namespace,
and has to be released.

IMPLEMENTATION
The number of calls to register_pernet_device have been
reduced to one for the ip_vs.ko
Schedulers still have their own calls.

This patch adds a function __ip_vs_service_cleanup()
and an enable flag for the netfilter hooks.

The nf hooks will be enabled when the first service is loaded
and never disabled again, except when a namespace exit starts.

Signed-off-by: Hans Schillstrom <hans@schillstrom.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
[horms@verge.net.au: minor edit to changelog]
Signed-off-by: Simon Horman <horms@verge.net.au>
  • Loading branch information
Hans Schillstrom authored and Pablo Neira Ayuso committed May 10, 2011
1 parent 1ae132b commit 7a4f076
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 80 deletions.
17 changes: 17 additions & 0 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,7 @@ struct ip_vs_app {
/* IPVS in network namespace */
struct netns_ipvs {
int gen; /* Generation */
int enable; /* enable like nf_hooks do */
/*
* Hash table: for real service lookups
*/
Expand Down Expand Up @@ -1089,6 +1090,22 @@ ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp)
atomic_inc(&ctl_cp->n_control);
}

/*
* IPVS netns init & cleanup functions
*/
extern int __ip_vs_estimator_init(struct net *net);
extern int __ip_vs_control_init(struct net *net);
extern int __ip_vs_protocol_init(struct net *net);
extern int __ip_vs_app_init(struct net *net);
extern int __ip_vs_conn_init(struct net *net);
extern int __ip_vs_sync_init(struct net *net);
extern void __ip_vs_conn_cleanup(struct net *net);
extern void __ip_vs_app_cleanup(struct net *net);
extern void __ip_vs_protocol_cleanup(struct net *net);
extern void __ip_vs_control_cleanup(struct net *net);
extern void __ip_vs_estimator_cleanup(struct net *net);
extern void __ip_vs_sync_cleanup(struct net *net);
extern void __ip_vs_service_cleanup(struct net *net);

/*
* IPVS application functions
Expand Down
15 changes: 3 additions & 12 deletions net/netfilter/ipvs/ip_vs_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ static const struct file_operations ip_vs_app_fops = {
};
#endif

static int __net_init __ip_vs_app_init(struct net *net)
int __net_init __ip_vs_app_init(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);

Expand All @@ -585,26 +585,17 @@ static int __net_init __ip_vs_app_init(struct net *net)
return 0;
}

static void __net_exit __ip_vs_app_cleanup(struct net *net)
void __net_exit __ip_vs_app_cleanup(struct net *net)
{
proc_net_remove(net, "ip_vs_app");
}

static struct pernet_operations ip_vs_app_ops = {
.init = __ip_vs_app_init,
.exit = __ip_vs_app_cleanup,
};

int __init ip_vs_app_init(void)
{
int rv;

rv = register_pernet_subsys(&ip_vs_app_ops);
return rv;
return 0;
}


void ip_vs_app_cleanup(void)
{
unregister_pernet_subsys(&ip_vs_app_ops);
}
12 changes: 2 additions & 10 deletions net/netfilter/ipvs/ip_vs_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1258,22 +1258,17 @@ int __net_init __ip_vs_conn_init(struct net *net)
return 0;
}

static void __net_exit __ip_vs_conn_cleanup(struct net *net)
void __net_exit __ip_vs_conn_cleanup(struct net *net)
{
/* flush all the connection entries first */
ip_vs_conn_flush(net);
proc_net_remove(net, "ip_vs_conn");
proc_net_remove(net, "ip_vs_conn_sync");
}
static struct pernet_operations ipvs_conn_ops = {
.init = __ip_vs_conn_init,
.exit = __ip_vs_conn_cleanup,
};

int __init ip_vs_conn_init(void)
{
int idx;
int retc;

/* Compute size and mask */
ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits;
Expand Down Expand Up @@ -1309,17 +1304,14 @@ int __init ip_vs_conn_init(void)
rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);
}

retc = register_pernet_subsys(&ipvs_conn_ops);

/* calculate the random value for connection hash */
get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));

return retc;
return 0;
}

void ip_vs_conn_cleanup(void)
{
unregister_pernet_subsys(&ipvs_conn_ops);
/* Release the empty cache */
kmem_cache_destroy(ip_vs_conn_cachep);
vfree(ip_vs_conn_tab);
Expand Down
101 changes: 92 additions & 9 deletions net/netfilter/ipvs/ip_vs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
return NF_ACCEPT;

net = skb_net(skb);
if (!net_ipvs(net)->enable)
return NF_ACCEPT;

ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
Expand Down Expand Up @@ -1343,6 +1346,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
return NF_ACCEPT; /* The packet looks wrong, ignore */

net = skb_net(skb);

pd = ip_vs_proto_data_get(net, cih->protocol);
if (!pd)
return NF_ACCEPT;
Expand Down Expand Up @@ -1529,6 +1533,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
IP_VS_DBG_ADDR(af, &iph.daddr), hooknum);
return NF_ACCEPT;
}
/* ipvs enabled in this netns ? */
net = skb_net(skb);
if (!net_ipvs(net)->enable)
return NF_ACCEPT;

ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);

/* Bad... Do not break raw sockets */
Expand Down Expand Up @@ -1562,7 +1571,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
}

net = skb_net(skb);
/* Protocol supported? */
pd = ip_vs_proto_data_get(net, iph.protocol);
if (unlikely(!pd))
Expand All @@ -1588,7 +1596,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
}

IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet");
net = skb_net(skb);
ipvs = net_ipvs(net);
/* Check the server status */
if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
Expand Down Expand Up @@ -1743,10 +1750,16 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
int r;
struct net *net;

if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
return NF_ACCEPT;

/* ipvs enabled in this netns ? */
net = skb_net(skb);
if (!net_ipvs(net)->enable)
return NF_ACCEPT;

return ip_vs_in_icmp(skb, &r, hooknum);
}

Expand All @@ -1757,10 +1770,16 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
int r;
struct net *net;

if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
return NF_ACCEPT;

/* ipvs enabled in this netns ? */
net = skb_net(skb);
if (!net_ipvs(net)->enable)
return NF_ACCEPT;

return ip_vs_in_icmp_v6(skb, &r, hooknum);
}
#endif
Expand Down Expand Up @@ -1884,39 +1903,90 @@ static int __net_init __ip_vs_init(struct net *net)
pr_err("%s(): no memory.\n", __func__);
return -ENOMEM;
}
/* Hold the beast until a service is registerd */
ipvs->enable = 0;
ipvs->net = net;
/* Counters used for creating unique names */
ipvs->gen = atomic_read(&ipvs_netns_cnt);
atomic_inc(&ipvs_netns_cnt);
net->ipvs = ipvs;

if (__ip_vs_estimator_init(net) < 0)
goto estimator_fail;

if (__ip_vs_control_init(net) < 0)
goto control_fail;

if (__ip_vs_protocol_init(net) < 0)
goto protocol_fail;

if (__ip_vs_app_init(net) < 0)
goto app_fail;

if (__ip_vs_conn_init(net) < 0)
goto conn_fail;

if (__ip_vs_sync_init(net) < 0)
goto sync_fail;

printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n",
sizeof(struct netns_ipvs), ipvs->gen);
return 0;
/*
* Error handling
*/

sync_fail:
__ip_vs_conn_cleanup(net);
conn_fail:
__ip_vs_app_cleanup(net);
app_fail:
__ip_vs_protocol_cleanup(net);
protocol_fail:
__ip_vs_control_cleanup(net);
control_fail:
__ip_vs_estimator_cleanup(net);
estimator_fail:
return -ENOMEM;
}

static void __net_exit __ip_vs_cleanup(struct net *net)
{
__ip_vs_service_cleanup(net); /* ip_vs_flush() with locks */
__ip_vs_conn_cleanup(net);
__ip_vs_app_cleanup(net);
__ip_vs_protocol_cleanup(net);
__ip_vs_control_cleanup(net);
__ip_vs_estimator_cleanup(net);
IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen);
}

static void __net_exit __ip_vs_dev_cleanup(struct net *net)
{
EnterFunction(2);
net_ipvs(net)->enable = 0; /* Disable packet reception */
__ip_vs_sync_cleanup(net);
LeaveFunction(2);
}

static struct pernet_operations ipvs_core_ops = {
.init = __ip_vs_init,
.exit = __ip_vs_cleanup,
.id = &ip_vs_net_id,
.size = sizeof(struct netns_ipvs),
};

static struct pernet_operations ipvs_core_dev_ops = {
.exit = __ip_vs_dev_cleanup,
};

/*
* Initialize IP Virtual Server
*/
static int __init ip_vs_init(void)
{
int ret;

ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */
if (ret < 0)
return ret;

ip_vs_estimator_init();
ret = ip_vs_control_init();
if (ret < 0) {
Expand Down Expand Up @@ -1944,15 +2014,28 @@ static int __init ip_vs_init(void)
goto cleanup_conn;
}

ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */
if (ret < 0)
goto cleanup_sync;

ret = register_pernet_device(&ipvs_core_dev_ops);
if (ret < 0)
goto cleanup_sub;

ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
if (ret < 0) {
pr_err("can't register hooks.\n");
goto cleanup_sync;
goto cleanup_dev;
}

pr_info("ipvs loaded.\n");

return ret;

cleanup_dev:
unregister_pernet_device(&ipvs_core_dev_ops);
cleanup_sub:
unregister_pernet_subsys(&ipvs_core_ops);
cleanup_sync:
ip_vs_sync_cleanup();
cleanup_conn:
Expand All @@ -1964,20 +2047,20 @@ static int __init ip_vs_init(void)
ip_vs_control_cleanup();
cleanup_estimator:
ip_vs_estimator_cleanup();
unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */
return ret;
}

static void __exit ip_vs_cleanup(void)
{
nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
unregister_pernet_device(&ipvs_core_dev_ops);
unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */
ip_vs_sync_cleanup();
ip_vs_conn_cleanup();
ip_vs_app_cleanup();
ip_vs_protocol_cleanup();
ip_vs_control_cleanup();
ip_vs_estimator_cleanup();
unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */
pr_info("ipvs unloaded.\n");
}

Expand Down
Loading

0 comments on commit 7a4f076

Please sign in to comment.