diff -uprN aa/include/linux/ve.h bb/include/linux/ve.h --- aa/include/linux/ve.h 2007-09-12 14:50:21.000000000 +0400 +++ bb/include/linux/ve.h 2007-09-12 15:03:49.000000000 +0400 @@ -49,6 +49,10 @@ struct veip_struct; struct ve_monitor; struct nsproxy; +#if defined(CONFIG_VE) && defined(CONFIG_NET) +struct ve_ipip_tunnels; +#endif /* CONFIG_VE && CONFIG_NET */ + #if defined(CONFIG_VE) && defined(CONFIG_INET) struct fib_table; struct devcnfv4_struct; @@ -193,6 +197,7 @@ struct ve_struct { int ifindex; struct net_device *_loopback_dev; struct net_device_stats *_loopback_stats; + struct ve_ipip_tunnels *_ve_ipip_tunnels; #ifdef CONFIG_INET struct ipv4_devconf *_ipv4_devconf; struct ipv4_devconf *_ipv4_devconf_dflt; diff -uprN aa/include/net/ipip.h bb/include/net/ipip.h --- aa/include/net/ipip.h 2007-09-12 14:47:17.000000000 +0400 +++ bb/include/net/ipip.h 2007-09-12 15:28:53.000000000 +0400 @@ -48,4 +48,18 @@ struct ip_tunnel extern int sit_init(void); extern void sit_cleanup(void); +#define HASH_SIZE_IPIP 16 + +#if defined(CONFIG_VE) && defined(CONFIG_NET) +struct ve_ipip_tunnels { + struct net_device *ipip_fb_tunnel_dev; + struct ip_tunnel *tunnels_r_l[HASH_SIZE_IPIP]; + struct ip_tunnel *tunnels_r[HASH_SIZE_IPIP]; + struct ip_tunnel *tunnels_l[HASH_SIZE_IPIP]; + struct ip_tunnel *tunnels_wc[1]; + struct ip_tunnel **tunnels[4]; + rwlock_t ipip_lock; +}; +#endif /* CONFIG_VE */ + #endif diff -uprN aa/net/ipv4/ipip.c bb/net/ipv4/ipip.c --- aa/net/ipv4/ipip.c 2007-09-12 14:47:32.000000000 +0400 +++ bb/net/ipv4/ipip.c 2007-09-13 10:41:18.000000000 +0400 @@ -116,14 +116,25 @@ #include #include #include +#include -#define HASH_SIZE 16 +#define HASH_SIZE HASH_SIZE_IPIP #define HASH(addr) ((addr^(addr>>4))&0xF) static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); +#if defined(CONFIG_VE) && defined(CONFIG_NET) +#define ve_ipip_fb_tunnel_dev \ + (get_exec_env()->_ve_ipip_tunnels->ipip_fb_tunnel_dev) +#define ve_tunnels_r_l (get_exec_env()->_ve_ipip_tunnels->tunnels_r_l) +#define ve_tunnels_r (get_exec_env()->_ve_ipip_tunnels->tunnels_r) +#define ve_tunnels_l (get_exec_env()->_ve_ipip_tunnels->tunnels_l) +#define ve_tunnels_wc (get_exec_env()->_ve_ipip_tunnels->tunnels_wc) +#define ve_tunnels (get_exec_env()->_ve_ipip_tunnels->tunnels) +#define ve_ipip_lock (get_exec_env()->_ve_ipip_tunnels->ipip_lock) +#else static struct net_device *ipip_fb_tunnel_dev; static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; @@ -134,26 +145,35 @@ static struct ip_tunnel **tunnels[4] = { static DEFINE_RWLOCK(ipip_lock); +#define ve_ipip_fb_tunnel_dev ipip_fb_tunnel_dev +#define ve_tunnels_r_l tunnels_r_l +#define ve_tunnels_r tunnels_r +#define ve_tunnels_l tunnels_l +#define ve_tunnels_wc tunnels_wc +#define ve_tunnels tunnels +#define ve_ipip_lock ipip_lock +#endif /* CONFIG_VE && CONFIG_NET */ + static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); struct ip_tunnel *t; - for (t = tunnels_r_l[h0^h1]; t; t = t->next) { + for (t = ve_tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; } - for (t = tunnels_r[h0]; t; t = t->next) { + for (t = ve_tunnels_r[h0]; t; t = t->next) { if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; } - for (t = tunnels_l[h1]; t; t = t->next) { + for (t = ve_tunnels_l[h1]; t; t = t->next) { if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) return t; } - if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) + if ((t = ve_tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) return t; return NULL; } @@ -173,7 +193,7 @@ static struct ip_tunnel **ipip_bucket(st prio |= 1; h ^= HASH(local); } - return &tunnels[prio][h]; + return &ve_tunnels[prio][h]; } @@ -183,9 +203,9 @@ static void ipip_tunnel_unlink(struct ip for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) { if (t == *tp) { - write_lock_bh(&ipip_lock); + write_lock_bh(&ve_ipip_lock); *tp = t->next; - write_unlock_bh(&ipip_lock); + write_unlock_bh(&ve_ipip_lock); break; } } @@ -196,9 +216,9 @@ static void ipip_tunnel_link(struct ip_t struct ip_tunnel **tp = ipip_bucket(t); t->next = *tp; - write_lock_bh(&ipip_lock); + write_lock_bh(&ve_ipip_lock); *tp = t; - write_unlock_bh(&ipip_lock); + write_unlock_bh(&ve_ipip_lock); } static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) @@ -219,7 +239,7 @@ static struct ip_tunnel * ipip_tunnel_lo prio |= 1; h ^= HASH(local); } - for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) { + for (tp = &ve_tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) return t; } @@ -263,10 +283,10 @@ failed: static void ipip_tunnel_uninit(struct net_device *dev) { - if (dev == ipip_fb_tunnel_dev) { - write_lock_bh(&ipip_lock); - tunnels_wc[0] = NULL; - write_unlock_bh(&ipip_lock); + if (dev == ve_ipip_fb_tunnel_dev) { + write_lock_bh(&ve_ipip_lock); + ve_tunnels_wc[0] = NULL; + write_unlock_bh(&ve_ipip_lock); } else ipip_tunnel_unlink(netdev_priv(dev)); dev_put(dev); @@ -316,7 +336,7 @@ static int ipip_err(struct sk_buff *skb, err = -ENOENT; - read_lock(&ipip_lock); + read_lock(&ve_ipip_lock); t = ipip_tunnel_lookup(iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -331,7 +351,7 @@ static int ipip_err(struct sk_buff *skb, t->err_count = 1; t->err_time = jiffies; out: - read_unlock(&ipip_lock); + read_unlock(&ve_ipip_lock); return err; #else struct iphdr *iph = (struct iphdr*)dp; @@ -475,10 +495,10 @@ static int ipip_rcv(struct sk_buff *skb) iph = skb->nh.iph; - read_lock(&ipip_lock); + read_lock(&ve_ipip_lock); if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - read_unlock(&ipip_lock); + read_unlock(&ve_ipip_lock); kfree_skb(skb); return 0; } @@ -498,10 +518,10 @@ static int ipip_rcv(struct sk_buff *skb) nf_reset(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); - read_unlock(&ipip_lock); + read_unlock(&ve_ipip_lock); return 0; } - read_unlock(&ipip_lock); + read_unlock(&ve_ipip_lock); return -1; } @@ -666,7 +686,7 @@ ipip_tunnel_ioctl (struct net_device *de switch (cmd) { case SIOCGETTUNNEL: t = NULL; - if (dev == ipip_fb_tunnel_dev) { + if (dev == ve_ipip_fb_tunnel_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { err = -EFAULT; break; @@ -683,7 +703,11 @@ ipip_tunnel_ioctl (struct net_device *de case SIOCADDTUNNEL: case SIOCCHGTUNNEL: err = -EPERM; - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN) +#if defined(CONFIG_VE) && defined(CONFIG_NET) + && !capable(CAP_VE_NET_ADMIN) +#endif /* CONFIG_VE && CONFIG_NET */ + ) goto done; err = -EFAULT; @@ -699,7 +723,7 @@ ipip_tunnel_ioctl (struct net_device *de t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL); - if (dev != ipip_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { + if (dev != ve_ipip_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; @@ -737,10 +761,14 @@ ipip_tunnel_ioctl (struct net_device *de case SIOCDELTUNNEL: err = -EPERM; - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN) +#if defined(CONFIG_VE) && defined(CONFIG_NET) + && !capable(CAP_VE_NET_ADMIN) +#endif /* CONFIG_VE && CONFIG_NET */ + ) goto done; - if (dev == ipip_fb_tunnel_dev) { + if (dev == ve_ipip_fb_tunnel_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; @@ -748,7 +776,7 @@ ipip_tunnel_ioctl (struct net_device *de if ((t = ipip_tunnel_locate(&p, 0)) == NULL) goto done; err = -EPERM; - if (t->dev == ipip_fb_tunnel_dev) + if (t->dev == ve_ipip_fb_tunnel_dev) goto done; dev = t->dev; } @@ -792,6 +820,9 @@ static void ipip_tunnel_setup(struct net dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; +#if defined(CONFIG_VE) && defined(CONFIG_NET) + dev->features = NETIF_F_VIRTUAL; +#endif /* CONFIG_VE && CONFIG_NET */ } static int ipip_tunnel_init(struct net_device *dev) @@ -836,7 +867,7 @@ static int ipip_tunnel_init(struct net_d return 0; } -static int __init ipip_fb_tunnel_init(struct net_device *dev) +static int ipip_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -849,7 +880,7 @@ static int __init ipip_fb_tunnel_init(st iph->ihl = 5; dev_hold(dev); - tunnels_wc[0] = tunnel; + ve_tunnels_wc[0] = tunnel; return 0; } @@ -859,6 +890,96 @@ static struct xfrm_tunnel ipip_handler = .priority = 1, }; +static void ipip_destroy_tunnels(void) +{ + int prio; + + for (prio = 1; prio < 4; prio++) { + int h; + for (h = 0; h < HASH_SIZE; h++) { + struct ip_tunnel *t; + while ((t = ve_tunnels[prio][h]) != NULL) + unregister_netdevice(t->dev); + } + } +} + +#if defined(CONFIG_VE) && defined(CONFIG_NET) +static int ipip_ve_start(void *data) +{ + struct ve_struct *env; + int err; + + env = (struct ve_struct *)data; + if (!ve_is_super(env)) + __module_get(THIS_MODULE); + + env->_ve_ipip_tunnels = + kmalloc(sizeof(struct ve_ipip_tunnels), GFP_KERNEL); + if (!env->_ve_ipip_tunnels) { + err = -ENOMEM; + goto out; + } + memset(env->_ve_ipip_tunnels, 0, sizeof(struct ve_ipip_tunnels)); + ve_tunnels[0] = ve_tunnels_wc; + ve_tunnels[1] = ve_tunnels_l; + ve_tunnels[2] = ve_tunnels_r; + ve_tunnels[3] = ve_tunnels_r_l; + rwlock_init(&ve_ipip_lock); + + if (ve_is_super(env)) + return 0; + + ve_ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), + "tunl0", + ipip_tunnel_setup); + if (!ve_ipip_fb_tunnel_dev) { + err = -ENOMEM; + goto free_tunnel; + } + ve_ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init; + if ((err = register_netdev(ve_ipip_fb_tunnel_dev))) + goto free_netdev; + return 0; + + free_netdev: + free_netdev(ve_ipip_fb_tunnel_dev); + free_tunnel: + kfree(env->_ve_ipip_tunnels); + env->_ve_ipip_tunnels = NULL; + if (!ve_is_super(env)) + module_put(THIS_MODULE); + out: + return err; +} + +static void ipip_ve_stop(void *data) +{ + struct ve_struct *env; + + env = (struct ve_struct *)data; + if (env->_ve_ipip_tunnels == NULL) + return; + if (!ve_is_super(env)) { + rtnl_lock(); + ipip_destroy_tunnels(); + unregister_netdevice(ve_ipip_fb_tunnel_dev); + rtnl_unlock(); + } + kfree(env->_ve_ipip_tunnels); + env->_ve_ipip_tunnels = NULL; + if (!ve_is_super(env)) + module_put(THIS_MODULE); +} + +static struct ve_hook ipip_ve_hook = { + .init = ipip_ve_start, + .fini = ipip_ve_stop, + .owner = THIS_MODULE, + .priority = HOOK_PRIO_NET_POST, +}; +#endif /* CONFIG_VE && CONFIG_NET */ + static char banner[] __initdata = KERN_INFO "IPv4 over IPv4 tunneling driver\n"; @@ -873,50 +994,56 @@ static int __init ipip_init(void) return -EAGAIN; } - ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), +#if defined(CONFIG_VE) && defined(CONFIG_NET) + err = ipip_ve_start(get_exec_env()); + if (err) + goto err1; +#endif /* CONFIG_VE && CONFIG_NET */ + ve_ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "tunl0", ipip_tunnel_setup); - if (!ipip_fb_tunnel_dev) { + if (!ve_ipip_fb_tunnel_dev) { err = -ENOMEM; - goto err1; + goto err2; } - ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init; + ve_ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init; + + if ((err = register_netdev(ve_ipip_fb_tunnel_dev))) + goto err3; + +#if defined(CONFIG_VE) && defined(CONFIG_NET) + ve_hook_register(VE_SS_CHAIN, &ipip_ve_hook); +#endif /* CONFIG_VE && CONFIG_NET */ - if ((err = register_netdev(ipip_fb_tunnel_dev))) - goto err2; out: return err; + err3: + free_netdev(ve_ipip_fb_tunnel_dev); err2: - free_netdev(ipip_fb_tunnel_dev); +#if defined(CONFIG_VE) && defined(CONFIG_NET) + ipip_ve_stop(get_exec_env()); err1: +#endif /* CONFIG_VE && CONFIG_NET */ xfrm4_tunnel_deregister(&ipip_handler); goto out; } -static void __exit ipip_destroy_tunnels(void) -{ - int prio; - - for (prio = 1; prio < 4; prio++) { - int h; - for (h = 0; h < HASH_SIZE; h++) { - struct ip_tunnel *t; - while ((t = tunnels[prio][h]) != NULL) - unregister_netdevice(t->dev); - } - } -} - static void __exit ipip_fini(void) { +#if defined(CONFIG_VE) && defined(CONFIG_NET) + ve_hook_unregister(&ipip_ve_hook); +#endif /* CONFIG_VE && CONFIG_NET */ if (xfrm4_tunnel_deregister(&ipip_handler)) printk(KERN_INFO "ipip close: can't deregister tunnel\n"); rtnl_lock(); ipip_destroy_tunnels(); - unregister_netdevice(ipip_fb_tunnel_dev); + unregister_netdevice(ve_ipip_fb_tunnel_dev); rtnl_unlock(); +#if defined(CONFIG_VE) && defined(CONFIG_NET) + ipip_ve_stop(get_exec_env()); +#endif /* CONFIG_VE && CONFIG_NET */ } module_init(ipip_init);