diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/Documentation/vserver/debug.txt linux-2.6.17.13-vs2.1.1-rc35.ipv6/Documentation/vserver/debug.txt --- linux-2.6.17.13-vs2.1.1-rc35/Documentation/vserver/debug.txt 2006-09-15 17:26:38.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/Documentation/vserver/debug.txt 2006-09-22 23:24:25.000000000 +0200 @@ -48,6 +48,12 @@ debug_nid: "dealloc_nx_info(%p)" 1 2 "alloc_nx_info(%d)*" "create_nx_info(%d)*" + "vc_net_add(%d, data[%d]): %d.%d.%d.%d" + "vc_net_add(%d, data[%d]): %d.%d.%d.%d EXISTS" + "vc_net_add(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x" + "vc_net_add(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x EXISTS" + "vc_net_remove(%d, data[%d]): %d.%d.%d.%d" + "vc_net_remove(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x" 2 4 "get_nx_info(%p[#%d.%d])" "put_nx_info(%p[#%d.%d])" 3 8 "claim_nx_info(%p[#%d.%d.%d]) %p" diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/include/linux/vserver/debug.h linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vserver/debug.h --- linux-2.6.17.13-vs2.1.1-rc35/include/linux/vserver/debug.h 2006-09-15 17:26:47.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vserver/debug.h 2006-09-22 23:24:25.000000000 +0200 @@ -6,11 +6,6 @@ #define VXD_CMIN(n,m) (vx_debug_ ## n > (m)) #define VXD_MASK(n,m) (vx_debug_ ## n & (m)) -#define VXD_QPOS(v,p) (((uint32_t)(v) >> ((p)*8)) & 0xFF) -#define VXD_QUAD(v) VXD_QPOS(v,0), VXD_QPOS(v,1), \ - VXD_QPOS(v,2), VXD_QPOS(v,3) -#define VXF_QUAD "%u.%u.%u.%u" - #define VXD_DEV(d) (d), (d)->bd_inode->i_ino, \ imajor((d)->bd_inode), iminor((d)->bd_inode) #define VXF_DEV "%p[%lu,%d:%d]" diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/include/linux/vserver/network_cmd.h linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vserver/network_cmd.h --- linux-2.6.17.13-vs2.1.1-rc35/include/linux/vserver/network_cmd.h 2006-09-15 17:26:47.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vserver/network_cmd.h 2006-09-22 23:24:25.000000000 +0200 @@ -35,10 +35,19 @@ struct vcmd_net_create { #define VCMD_net_add VC_CMD(NETALT, 1, 0) #define VCMD_net_remove VC_CMD(NETALT, 2, 0) +#ifdef __KERNEL__ +#include +#else +#include +#endif /* __KERNEL__ */ + struct vcmd_net_addr_v0 { uint16_t type; uint16_t count; - uint32_t ip[4]; + union { + uint32_t ip4[4]; + struct in6_addr ip6; + } ip; uint32_t mask[4]; /* more to come */ }; diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/include/linux/vserver/network.h linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vserver/network.h --- linux-2.6.17.13-vs2.1.1-rc35/include/linux/vserver/network.h 2006-09-15 17:26:47.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vserver/network.h 2006-09-22 23:24:25.000000000 +0200 @@ -9,7 +9,7 @@ #define NX_DYNAMIC_ID ((uint32_t)-1) /* id for dynamic context */ #define NB_IPV4ROOT 16 - +#define NB_IPV6ROOT 16 /* network flags */ @@ -42,7 +42,9 @@ #include #include #include - +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include +#endif struct nx_info { struct hlist_node nx_hlist; /* linked list of nxinfos */ @@ -63,10 +65,29 @@ struct nx_info { /* Used to select the proper source */ /* address for sockets */ __u32 v4_bcast; /* Broadcast address to receive UDP */ - +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + int nbipv6; + struct in6_addr ipv6[NB_IPV6ROOT]; /* equivalent to ipv4, but for IPv6 */ + int prefix6[NB_IPV6ROOT]; /* IPv6 prefix length (in bits) */ +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ char nx_name[65]; /* network context name */ }; +struct net_device; + +#ifdef CONFIG_IPV6_MODULE + +struct nx_ipv6_mod { + struct module *owner; + /* Function to check if dev in network context through IPv6 address */ + int (*dev_in_nx_info6)(struct net_device *dev, struct nx_info *nxi); +}; + +extern void vc_net_register_ipv6(struct nx_ipv6_mod *modv6); + +extern void vc_net_unregister_ipv6(void); + +#endif /* status flags */ @@ -104,7 +125,6 @@ extern int nx_migrate_task(struct task_s extern long vs_net_change(struct nx_info *, unsigned int); struct in_ifaddr; -struct net_device; #ifdef CONFIG_INET int ifa_in_nx_info(struct in_ifaddr *, struct nx_info *); diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/include/linux/vs_network.h linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vs_network.h --- linux-2.6.17.13-vs2.1.1-rc35/include/linux/vs_network.h 2006-09-15 17:26:47.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/include/linux/vs_network.h 2006-09-22 23:24:25.000000000 +0200 @@ -214,6 +214,34 @@ static inline int __nx_check(nid_t cid, #define nx_ncaps(c) nx_info_ncaps(current->nx_info,(c)) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#include + +static inline int addr6_in_nx_info(struct nx_info *nxi, const struct in6_addr *addr) +{ + int n,i; + + if (!nxi) + return 1; + + n = nxi->nbipv6; + /* Special case accept anything if addr[0] == :: + * FIXME either accept this on any position or adjust address + * addition in kernel/vserver/network.c */ + if (n && nxi->ipv6[0].s6_addr32[0] == 0 && nxi->ipv6[0].s6_addr32[1] == 0 && + nxi->ipv6[0].s6_addr32[2] == 0 && nxi->ipv6[0].s6_addr32[3] == 0) + return 1; + for (i=0; iipv6[i]), addr)) + return 1; + } + return 0; +} + +extern int nx_addr6_conflict(struct nx_info *nxi, struct nx_info *nix2); + +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ static inline int addr_in_nx_info(struct nx_info *nxi, uint32_t addr) { @@ -223,6 +251,9 @@ static inline int addr_in_nx_info(struct return 1; n = nxi->nbipv4; + /* Special case accept anything if addr[0] == :: + * FIXME either accept this on any position or adjust address + * addition in kernel/vserver/network.c */ if (n && (nxi->ipv4[0] == 0)) return 1; for (i=0; i #include + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#include + +int nx_addr6_conflict(struct nx_info *nxi, struct nx_info *nxi2) +{ + vxdprintk(VXD_CBIT(net, 2), "nx_addr6_conflict(%u,%u)", + nxi ? nxi->nx_id : 0, nxi2 ? nxi2->nx_id : 0); + + if (nxi && nxi2 && nxi->nbipv6 > 0 && nxi2->nbipv6 > 0) { + int i = 0; + for (i = 0; i < nxi->nbipv6; i++) + if (addr6_in_nx_info(nxi2, &(nxi->ipv6[i]))) + return 1; + } + return 0; +} + +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) { if (!nxi) @@ -429,29 +450,117 @@ int ifa_in_nx_info(struct in_ifaddr *ifa return addr_in_nx_info(nxi, ifa->ifa_local); } +#ifdef CONFIG_IPV6_MODULE + +struct nx_ipv6_mod vc_net_ipv6 = { + .dev_in_nx_info6 = NULL, + .owner = NULL +}; + +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) +static atomic_t nx_ipv6mod_lockct = ATOMIC_INIT(0); +static DEFINE_SPINLOCK(nx_ipv6mod_lock); + +/* The strategy is: modifications of vc_net_ipv6 are short, do not + sleep and veeery rare, but read access should be free of any exclusive + locks. (copied from socket.c) + This should prevent any possible issues with module unloading! + */ + +static void nx_ipv6mod_write_lock(void) +{ + spin_lock(&nx_ipv6mod_lock); + while (atomic_read(&nx_ipv6mod_lockct) != 0) { + spin_unlock(&nx_ipv6mod_lock); + + yield(); + + spin_lock(&nx_ipv6mod_lock); + } +} + +static __inline__ void nx_ipv6mod_write_unlock(void) +{ + spin_unlock(&nx_ipv6mod_lock); +} + +static __inline__ void nx_ipv6mod_read_lock(void) +{ + atomic_inc(&nx_ipv6mod_lockct); + spin_unlock_wait(&nx_ipv6mod_lock); +} + +static __inline__ void nx_ipv6mod_read_unlock(void) +{ + atomic_dec(&nx_ipv6mod_lockct); +} + +#else +#define nx_ipv6mod_write_lock() do { } while(0) +#define nx_ipv6mod_write_unlock() do { } while(0) +#define nx_ipv6mod_read_lock() do { } while(0) +#define nx_ipv6mod_read_unlock() do { } while(0) +#endif + +void vc_net_register_ipv6(struct nx_ipv6_mod *modv6) { + nx_ipv6mod_write_lock(); + memcpy(&vc_net_ipv6, modv6, sizeof(struct nx_ipv6_mod)); + nx_ipv6mod_write_unlock(); +} + +void vc_net_unregister_ipv6() { + nx_ipv6mod_write_lock(); + memset(&vc_net_ipv6, 0, sizeof(struct nx_ipv6_mod)); + nx_ipv6mod_write_unlock(); +} + +inline int dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi) { + nx_ipv6mod_read_lock(); + if (try_module_get(vc_net_ipv6.owner)) { + if (vc_net_ipv6.dev_in_nx_info6) + return vc_net_ipv6.dev_in_nx_info6(dev, nxi); + else + return 0; + module_put(vc_net_ipv6.owner); + } else + return 0; + nx_ipv6mod_read_unlock(); +} +#endif + int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) { - struct in_device *in_dev; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; int ret = 0; if (!nxi) return 1; - in_dev = in_dev_get(dev); - if (!in_dev) - goto out; - - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { - if (addr_in_nx_info(nxi, ifa->ifa_local)) { - ret = 1; - break; + if (nxi->nbipv4 > 0) { + struct in_device *in_dev; + struct in_ifaddr **ifap; + struct in_ifaddr *ifa; + + in_dev = in_dev_get(dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (addr_in_nx_info(nxi, ifa->ifa_local)) { + ret = 1; + break; + } + } + in_dev_put(in_dev); } } - in_dev_put(in_dev); -out: + +#if defined(CONFIG_IPV6_MODULE) + if (ret == 0) + ret = dev_in_nx_info6(dev, nxi); +#elif defined(CONFIG_IPV6) + if (ret == 0) + ret = ipv6_dev_in_nx_info6(dev, nxi); +#endif + return ret; } @@ -467,8 +576,8 @@ static inline int __addr_in_socket(struc uint32_t saddr = inet_rcv_saddr(sk); vxdprintk(VXD_CBIT(net, 5), - "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx", - sk, VXD_QUAD(addr), nxi, VXD_QUAD(saddr), sk->sk_socket, + "__addr_in_socket(%p," NIPQUAD_FMT ") %p:" NIPQUAD_FMT " %p;%lx", + sk, NIPQUAD(addr), nxi, NIPQUAD(saddr), sk->sk_socket, (sk->sk_socket?sk->sk_socket->flags:0)); if (saddr) { @@ -487,8 +596,8 @@ static inline int __addr_in_socket(struc int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, struct sock *sk) { vxdprintk(VXD_CBIT(net, 2), - "nx_addr_conflict(%p,%p) %d.%d,%d.%d", - nxi, sk, VXD_QUAD(addr)); + "nx_addr_conflict(%p,%p) " NIPQUAD_FMT, + nxi, sk, NIPQUAD(addr)); if (addr) { /* check real address */ @@ -625,6 +734,40 @@ int vc_net_migrate(struct nx_info *nxi, return nx_migrate_task(current, nxi); } +/* + * Lookup address/mask pair in list of v4 addresses + * Returns position if found, -1 if not found + */ +int vc_net_find_v4(const struct nx_info *nxi, uint32_t addr, uint32_t mask) +{ + int ret = nxi->nbipv4 - 1; + while (ret >= 0) { + if (nxi->ipv4[ret] == addr && nxi->mask[ret] == mask) + break; + else + ret--; + } + return ret; +} + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +/* + * Lookup address/prefix pair list of v6 addresses + * Returns position if found, -1 if not found + */ +int vc_net_find_v6(const struct nx_info *nxi, const struct in6_addr *addr, int prefix) +{ + int ret = nxi->nbipv6 - 1; + while (ret >= 0) { + if (memcmp(&(nxi->ipv6[ret]), addr, sizeof(struct in6_addr)) == 0 && nxi->prefix6[ret] == prefix) + break; + else + ret--; + } + return ret; +} +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + int vc_net_add(struct nx_info *nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; @@ -639,6 +782,14 @@ int vc_net_add(struct nx_info *nxi, void return -EINVAL; break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + /* Note: all 4 items of IP and MASK must be set, but its 1 IPv6 address */ + if ((vc_data.count != 1)) + return -EINVAL; + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: break; } @@ -646,21 +797,50 @@ int vc_net_add(struct nx_info *nxi, void switch (vc_data.type) { case NXA_TYPE_IPV4: index = 0; + ret = 0; while ((index < vc_data.count) && ((pos = nxi->nbipv4) < NB_IPV4ROOT)) { - nxi->ipv4[pos] = vc_data.ip[index]; - nxi->mask[pos] = vc_data.mask[index]; + if (vc_net_find_v4(nxi, vc_data.ip.ip4[index], vc_data.mask[index]) == -1) { + /* Only add if address is new */ + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%p, data[%d]): " NIPQUAD_FMT, + nxi, index, NIPQUAD(vc_data.ip.ip4[index])); + nxi->ipv4[pos] = vc_data.ip.ip4[index]; + nxi->mask[pos] = vc_data.mask[index]; + nxi->nbipv4++; + ret++; + } else + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%p, data[%d]): " NIPQUAD_FMT " EXISTS", + nxi, index, NIPQUAD(vc_data.ip.ip4[index])); index++; - nxi->nbipv4++; } - ret = index; break; case NXA_TYPE_IPV4|NXA_MOD_BCAST: - nxi->v4_bcast = vc_data.ip[0]; + nxi->v4_bcast = vc_data.ip.ip4[0]; ret = 1; break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + index = 0; + ret = 0; + while (nxi->nbipv6 < NB_IPV6ROOT && index < vc_data.count) { + if (vc_net_find_v6(nxi, &(vc_data.ip.ip6), vc_data.mask[index]) == -1) { + /* Only add if address is new */ + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%p, data[%d]): " NIP6_FMT, + nxi, index, NIP6(vc_data.ip.ip6)); + nxi->ipv6[nxi->nbipv6] = vc_data.ip.ip6; + nxi->prefix6[nxi->nbipv6] = vc_data.mask[index]; + nxi->nbipv6++; + ret++; + } else + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%p, data[%d]): " NIP6_FMT " EXISTS", + nxi, index, NIP6(vc_data.ip.ip6)); + index++; + } + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: ret = -EINVAL; break; @@ -668,9 +848,10 @@ int vc_net_add(struct nx_info *nxi, void return ret; } -int vc_net_remove(struct nx_info * nxi, void __user *data) +int vc_net_remove(struct nx_info *nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; + int index, pos, ret = 0; if (data && copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; @@ -678,12 +859,60 @@ int vc_net_remove(struct nx_info * nxi, switch (vc_data.type) { case NXA_TYPE_ANY: nxi->nbipv4 = 0; + ret = nxi->nbipv4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + nxi->nbipv6 = 0; + ret += nxi->nbipv6; +#endif + break; + + case NXA_TYPE_IPV4: + index = 0; + ret = 0; + while (index < vc_data.count) { + pos = vc_net_find_v4(nxi, vc_data.ip.ip4[index], vc_data.mask[index]); + if (pos >= 0) { + nxi->nbipv4--; + ret++; + vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%p, data[%d]): " NIPQUAD_FMT, + nxi, index, NIPQUAD(vc_data.ip.ip4[index])); + while (pos < nxi->nbipv4) { + nxi->ipv4[pos] = nxi->ipv4[pos+1]; + nxi->mask[pos] = nxi->mask[pos+1]; + pos++; + } + } + index++; + } break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + index = 0; + ret = 0; + while (index < vc_data.count) { + pos = vc_net_find_v6(nxi, &(vc_data.ip.ip6), vc_data.mask[index]); + if (pos >= 0) { + nxi->nbipv6--; + ret++; + vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%p, data[%d]): " NIP6_FMT " EXISTS", + nxi, index, NIP6(vc_data.ip.ip6)); + while (pos < nxi->nbipv6) { + nxi->ipv6[pos] = nxi->ipv6[pos+1]; + nxi->prefix6[pos] = nxi->prefix6[pos+1]; + pos++; + } + } + index++; + } + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; + return ret; } int vc_get_nflags(struct nx_info *nxi, void __user *data) @@ -750,3 +979,11 @@ int vc_set_ncaps(struct nx_info *nxi, vo EXPORT_SYMBOL_GPL(free_nx_info); EXPORT_SYMBOL_GPL(unhash_nx_info); +#ifdef CONFIG_IPV6_MODULE +EXPORT_SYMBOL_GPL(dev_in_nx_info); +EXPORT_SYMBOL_GPL(nx_addr6_conflict); +EXPORT_SYMBOL_GPL(vc_net_register_ipv6); +EXPORT_SYMBOL_GPL(vc_net_unregister_ipv6); +#elif defined(CONFIG_IPV6) +EXPORT_SYMBOL_GPL(nx_addr6_conflict); +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/kernel/vserver/proc.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/kernel/vserver/proc.c --- linux-2.6.17.13-vs2.1.1-rc35/kernel/vserver/proc.c 2006-09-15 17:26:48.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/kernel/vserver/proc.c 2006-09-22 23:24:25.000000000 +0200 @@ -224,6 +224,13 @@ int proc_nid_info (int vid, char *buffer "%d:\t" NIPQUAD_FMT "/" NIPQUAD_FMT "\n", i, NIPQUAD(nxi->ipv4[i]), NIPQUAD(nxi->mask[i])); } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + for (i=0; inbipv6;i++) { + length += sprintf(buffer + length, + "%d:\t" NIP6_FMT "/%d\n", i, + NIP6(nxi->ipv6[i]), nxi->prefix6[i]); + } +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ put_nx_info(nxi); return length; } diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/Makefile linux-2.6.17.13-vs2.1.1-rc35.ipv6/Makefile --- linux-2.6.17.13-vs2.1.1-rc35/Makefile 2006-09-22 23:19:45.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/Makefile 2006-09-22 23:24:52.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 17 -EXTRAVERSION = .13-vs2.1.1-rc35 +EXTRAVERSION = .13-vs2.1.1-rc35.ipv6 NAME=Crazed Snow-Weasel # *DOCUMENTATION* diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv4/af_inet.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv4/af_inet.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv4/af_inet.c 2006-09-15 17:26:49.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv4/af_inet.c 2006-09-22 23:24:25.000000000 +0200 @@ -423,10 +423,10 @@ int inet_bind(struct socket *sock, struc s_addr2 = 0xffffffffl; vxdprintk(VXD_CBIT(net, 3), - "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d", + "inet_bind(%p)* %p,%p;%lx " NIPQUAD_FMT, sk, sk->sk_nx_info, sk->sk_socket, (sk->sk_socket?sk->sk_socket->flags:0), - VXD_QUAD(s_addr)); + NIPQUAD(s_addr)); if (nxi) { __u32 v4_bcast = nxi->v4_bcast; __u32 ipv4root = nxi->ipv4[0]; @@ -450,8 +450,8 @@ int inet_bind(struct socket *sock, struc chk_addr_ret = inet_addr_type(s_addr); vxdprintk(VXD_CBIT(net, 3), - "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d", - sk, VXD_QUAD(s_addr), VXD_QUAD(s_addr1), VXD_QUAD(s_addr2)); + "inet_bind(%p) " NIPQUAD_FMT ", " NIPQUAD_FMT ", " NIPQUAD_FMT, + sk, NIPQUAD(s_addr), NIPQUAD(s_addr1), NIPQUAD(s_addr2)); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/addrconf.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/addrconf.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/addrconf.c 2006-09-15 17:26:49.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/addrconf.c 2006-09-22 23:24:25.000000000 +0200 @@ -881,7 +881,7 @@ static int inline ipv6_saddr_label(const } int ipv6_dev_get_saddr(struct net_device *daddr_dev, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, struct in6_addr *saddr, struct nx_info *nxi) { struct ipv6_saddr_score hiscore; struct inet6_ifaddr *ifa_result = NULL; @@ -926,6 +926,11 @@ int ipv6_dev_get_saddr(struct net_device score.addr_type = __ipv6_addr_type(&ifa->addr); + /* Linux-VServer: only take into account addresses + available in guest context! */ + if (!addr6_in_nx_info(nxi, &ifa->addr)) + continue; + /* Rule 0: * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered @@ -1118,9 +1123,9 @@ record_it: int ipv6_get_saddr(struct dst_entry *dst, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, struct in6_addr *saddr, struct nx_info *nxi) { - return ipv6_dev_get_saddr(dst ? ((struct rt6_info *)dst)->rt6i_idev->dev : NULL, daddr, saddr); + return ipv6_dev_get_saddr(dst ? ((struct rt6_info *)dst)->rt6i_idev->dev : NULL, daddr, saddr, nxi); } @@ -1223,26 +1228,48 @@ int ipv6_rcv_saddr_equal(const struct so int addr_type = ipv6_addr_type(sk_rcv_saddr6); int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; - if (!sk2_rcv_saddr && !sk_ipv6only) - return 1; - - if (addr_type2 == IPV6_ADDR_ANY && - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) - return 1; - - if (addr_type == IPV6_ADDR_ANY && - !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) - return 1; - - if (sk2_rcv_saddr6 && - ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) - return 1; - - if (addr_type == IPV6_ADDR_MAPPED && - !sk2_ipv6only && - (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) - return 1; + if (sk->sk_nid != sk2->sk_nid) { + // either socket is in host context and bound to everything + if (sk->sk_nx_info == NULL && addr_type == IPV6_ADDR_ANY && !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; + if (sk2->sk_nx_info == NULL && addr_type2 == IPV6_ADDR_ANY && !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; + // If both addresses are equal + if (sk2_rcv_saddr6 && ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + // If one socket bound to everything and the addr bound by other socket is in first context + if (addr_type2 == IPV6_ADDR_ANY && !(addr_type == IPV6_ADDR_ANY || addr_type == IPV6_ADDR_MAPPED) && + addr6_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6)) + return 1; + if (addr_type == IPV6_ADDR_ANY && !(addr_type2 == IPV6_ADDR_ANY || addr_type2 == IPV6_ADDR_MAPPED) && + sk2_rcv_saddr6 && addr6_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr6)) + return 1; + // both sockets are in guests and bound to everything with addr-overlap between guests + if (sk->sk_nx_info && sk2->sk_nx_info && addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY && + nx_addr6_conflict(sk->sk_nx_info, sk2->sk_nx_info)) + return 1; + // TODO: handle the IPv4 addresses mapped in IPv6 completely... + } else { + if (!sk2_rcv_saddr && !sk_ipv6only) + return 1; + if (addr_type2 == IPV6_ADDR_ANY && + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; + + if (addr_type == IPV6_ADDR_ANY && + !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; + + if (sk2_rcv_saddr6 && + ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + + if (addr_type == IPV6_ADDR_MAPPED && + !sk2_ipv6only && + (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) + return 1; + } return 0; } @@ -2656,7 +2683,7 @@ static int if6_seq_show(struct seq_file struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; /* no ipv6 inside a vserver for now */ - if (vx_check(0, VX_ADMIN|VX_WATCH)) + if (vx_check(0, VX_ADMIN|VX_WATCH) || addr6_in_nx_info(task_get_nx_info(current), &ifp->addr)) seq_printf(seq, NIP6_SEQFMT " %02x %02x %02x %02x %8s\n", NIP6(ifp->addr), @@ -3017,8 +3044,8 @@ static int inet6_dump_addr(struct sk_buf struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; - /* no ipv6 inside a vserver for now */ - if (skb->sk && skb->sk->sk_vx_info) + /* no ipv6 inside a vserver if no addr set */ + if (skb->sk && skb->sk->sk_nx_info && skb->sk->sk_nx_info->nbipv6 == 0) return skb->len; s_idx = cb->args[0]; @@ -3041,6 +3068,8 @@ static int inet6_dump_addr(struct sk_buf ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifa->addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR, @@ -3054,6 +3083,8 @@ static int inet6_dump_addr(struct sk_buf ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifmca->mca_addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifmcaddr(skb, ifmca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETMULTICAST, @@ -3067,6 +3098,8 @@ static int inet6_dump_addr(struct sk_buf ifaca = ifaca->aca_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifaca->aca_addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifacaddr(skb, ifaca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETANYCAST, @@ -3246,14 +3279,18 @@ static int inet6_dump_ifinfo(struct sk_b struct net_device *dev; struct inet6_dev *idev; - /* no ipv6 inside a vserver for now */ - if (skb->sk && skb->sk->sk_vx_info) + /* no ipv6 inside a vserver without IPv6 address + TODO: filter output here too + */ + if (skb->sk && skb->sk->sk_nx_info && skb->sk->sk_nx_info->nbipv6 == 0) return skb->len; read_lock(&dev_base_lock); for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !dev_in_nx_info(dev, skb->sk->sk_nx_info)) + continue; if ((idev = in6_dev_get(dev)) == NULL) continue; err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/af_inet6.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/af_inet6.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/af_inet6.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/af_inet6.c 2006-09-22 23:24:25.000000000 +0200 @@ -144,9 +144,11 @@ lookup_protocol: } err = -EPERM; + if ((protocol == IPPROTO_ICMPV6) && vx_ccaps(VXC_RAW_ICMP)) + goto override; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - +override: sock->ops = answer->ops; answer_prot = answer->prot; answer_no_check = answer->no_check; @@ -230,6 +232,8 @@ lookup_protocol: } } out: + vxdprintk(VXD_CBIT(net, 4), "inet6_create(%p, %d): %d", + sock, protocol, err); return err; out_rcu_unlock: rcu_read_unlock(); @@ -303,6 +307,18 @@ int inet6_bind(struct socket *sock, stru } } + /* VServer: Only accept if we have the address available */ + if (sk->sk_nx_info && !addr6_in_nx_info(sk->sk_nx_info, &addr->sin6_addr)) { + vxdprintk(VXD_CBIT(net, 3), "inet6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL", + NIP6(addr->sin6_addr), sk->sk_nx_info->nx_id); + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } else + vxdprintk(VXD_CBIT(net, 3), "inet6_bind(" NIP6_FMT ", %d): PASS", + NIP6(addr->sin6_addr), sk->sk_nx_info ? sk->sk_nx_info->nx_id : 0); + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -690,6 +706,31 @@ int ipv6_opt_accepted(struct sock *sk, s EXPORT_SYMBOL_GPL(ipv6_opt_accepted); +int ipv6_dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi) { + int ret = 0; + + if (nxi->nbipv6 > 0) { + struct inet6_dev *in_dev; + struct inet6_ifaddr **ifap; + struct inet6_ifaddr *ifa; + + in_dev = in6_dev_get(dev); + if (in_dev) { + for (ifap = &in_dev->addr_list; (ifa = *ifap) != NULL; + ifap = &ifa->if_next) { + if (addr6_in_nx_info(nxi, &(ifa->addr))) { + ret = 1; + break; + } + } + in6_dev_put(in_dev); + } + } + return ret; +} + +EXPORT_SYMBOL_GPL(ipv6_dev_in_nx_info6); + int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) { @@ -754,6 +795,17 @@ static void cleanup_ipv6_mibs(void) snmp6_mib_free((void **)udp_stats_in6); } +#ifdef CONFIG_IPV6_MODULE +static void vc_net_register_init(void) +{ + struct nx_ipv6_mod mymod = { + .dev_in_nx_info6 = ipv6_dev_in_nx_info6, + .owner = THIS_MODULE + }; + vc_net_register_ipv6(&mymod); +} +#endif + static int __init inet6_init(void) { struct sk_buff *dummy_skb; @@ -865,6 +917,11 @@ static int __init inet6_init(void) tcpv6_init(); ipv6_packet_init(); + +#ifdef CONFIG_IPV6_MODULE + vc_net_register_init(); +#endif + err = 0; out: return err; @@ -914,6 +971,9 @@ static void __exit inet6_exit(void) { /* First of all disallow new sockets creation. */ sock_unregister(PF_INET6); +#ifdef CONFIG_IPV6_MODULE + vc_net_unregister_ipv6(); +#endif #ifdef CONFIG_PROC_FS if6_proc_exit(); ac6_proc_exit(); diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/inet6_hashtables.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/inet6_hashtables.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/inet6_hashtables.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/inet6_hashtables.c 2006-09-22 23:24:25.000000000 +0200 @@ -103,6 +103,26 @@ hit: } EXPORT_SYMBOL(__inet6_lookup_established); +/* + * Check if a given address matches for an inet socket + * + * nxi: the socket's nx_info if any + * addr: to be verified address + * saddr: socket addresses + */ +static inline int inet6_addr_match( + struct nx_info *nxi, + const struct in6_addr *addr, + const struct in6_addr *saddr) +{ + if ((addr->s6_addr32[0] || addr->s6_addr32[1] || addr->s6_addr32[2] || addr->s6_addr32[3]) && + memcmp(saddr,addr, sizeof(struct in6_addr)) == 0) + return 1; + if (!(saddr->s6_addr32[0] || saddr->s6_addr32[1] || saddr->s6_addr32[2] || saddr->s6_addr32[3])) + return addr6_in_nx_info(nxi, addr); + return 0; +} + struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, const unsigned short hnum, const int dif) @@ -128,6 +148,10 @@ struct sock *inet6_lookup_listener(struc continue; score++; } + if (!inet6_addr_match(sk->sk_nx_info, daddr, &(np->rcv_saddr))) { + /* No, this address is not available for guest */ + continue; + } if (score == 3) { result = sk; break; diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/ip6_output.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/ip6_output.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/ip6_output.c 2006-09-09 13:15:48.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/ip6_output.c 2006-09-22 23:24:25.000000000 +0200 @@ -770,7 +770,7 @@ int ip6_dst_lookup(struct sock *sk, stru goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); + err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src, sk->sk_nx_info); if (err) goto out_err_release; diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/ndisc.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/ndisc.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/ndisc.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/ndisc.c 2006-09-22 23:24:25.000000000 +0200 @@ -446,7 +446,7 @@ static void ndisc_send_na(struct net_dev src_addr = solicited_addr; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) + if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, NULL)) return; src_addr = &tmpaddr; } diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/raw.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/raw.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/raw.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/raw.c 2006-09-22 23:24:25.000000000 +0200 @@ -100,7 +100,8 @@ struct sock *__raw_v6_lookup(struct sock continue; if (!ipv6_addr_any(&np->rcv_saddr)) { - if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + if (ipv6_addr_equal(&np->rcv_saddr, loc_addr) && + addr6_in_nx_info(sk->sk_nx_info, loc_addr)) goto found; if (is_multicast && inet6_mc_check(sk, loc_addr, rmt_addr)) @@ -234,7 +235,19 @@ static int rawv6_bind(struct sock *sk, s goto out; } } - + + /* VServer: Only accept if we have the address available */ + if (sk->sk_nx_info && !addr6_in_nx_info(sk->sk_nx_info, &addr->sin6_addr)) { + vxdprintk(VXD_CBIT(net, 3), "rawv6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL", + NIP6(addr->sin6_addr), sk->sk_nx_info->nx_id); + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } else + vxdprintk(VXD_CBIT(net, 3), "rawv6_bind(" NIP6_FMT ", %d): PASS", + NIP6(addr->sin6_addr), sk->sk_nx_info ? sk->sk_nx_info->nx_id : 0); + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -558,6 +571,11 @@ static int rawv6_send_hdrinc(struct sock if (err) goto error_fault; + err = -EPERM; + if (!vx_check(0, VX_ADMIN) && !capable(CAP_NET_RAW) + && (!addr6_in_nx_info(sk->sk_nx_info, &iph->saddr))) + goto error_free; + IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); @@ -570,6 +588,7 @@ out: error_fault: err = -EFAULT; +error_free: kfree_skb(skb); error: IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/route.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/route.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/route.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/route.c 2006-09-22 23:24:25.000000000 +0200 @@ -1781,7 +1781,7 @@ static int rt6_fill_node(struct sk_buff RTA_PUT(skb, RTA_IIF, 4, &iif); else if (dst) { struct in6_addr saddr_buf; - if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) + if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf, NULL) == 0) RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/tcp_ipv6.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/tcp_ipv6.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/tcp_ipv6.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/tcp_ipv6.c 2006-09-22 23:24:25.000000000 +0200 @@ -161,8 +161,19 @@ static int tcp_v6_connect(struct sock *s * connect() to INADDR_ANY means loopback (BSD'ism). */ - if(ipv6_addr_any(&usin->sin6_addr)) - usin->sin6_addr.s6_addr[15] = 0x1; + if(ipv6_addr_any(&usin->sin6_addr)) { + if (sk->sk_nx_info) { + if (sk->sk_nx_info->nbipv6) { + /* Linux-VServer: redirects to first IPv6 address set for guest + TODO: search for existing loopback address in guest context... */ + usin->sin6_addr = sk->sk_nx_info->ipv6[0]; + vxdprintk(VXD_CBIT(net, 4), "tcp_v6_connect(dest ::1 redirected to: " NIP6_FMT ", %d)", + NIP6(usin->sin6_addr), sk->sk_nx_info->nx_id); + } else + return -ENETUNREACH; + } else + usin->sin6_addr.s6_addr[15] = 0x1; + } addr_type = ipv6_addr_type(&usin->sin6_addr); diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/udp.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/udp.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/udp.c 2006-06-18 15:25:05.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/udp.c 2006-09-22 23:24:25.000000000 +0200 @@ -154,6 +154,17 @@ static void udp_v6_unhash(struct sock *s write_unlock_bh(&udp_hash_lock); } +static inline int udp_v6_in_list(struct nx_info *nx_info, struct in6_addr *addr) +{ + int n = nx_info->nbipv6; + int i; + + for (i=0; iipv6[i], addr)) + return 1; + return 0; +} + static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, struct in6_addr *daddr, u16 dport, int dif) { @@ -178,6 +189,11 @@ static struct sock *udp_v6_lookup(struct if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) continue; score++; + } else if (sk->sk_nx_info) { + if (udp_v6_in_list(sk->sk_nx_info, daddr)) + score++; + else + continue; } if (!ipv6_addr_any(&np->daddr)) { if (!ipv6_addr_equal(&np->daddr, saddr)) diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/xfrm6_state.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/xfrm6_state.c --- linux-2.6.17.13-vs2.1.1-rc35/net/ipv6/xfrm6_state.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/ipv6/xfrm6_state.c 2006-09-22 23:24:25.000000000 +0200 @@ -54,7 +54,7 @@ __xfrm6_init_tempsel(struct xfrm_state * if (!xfrm_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel, AF_INET6)) { ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr, - (struct in6_addr *)&x->props.saddr); + (struct in6_addr *)&x->props.saddr, NULL); dst_release(&rt->u.dst); } } diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/sctp/ipv6.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/sctp/ipv6.c --- linux-2.6.17.13-vs2.1.1-rc35/net/sctp/ipv6.c 2006-07-08 22:23:15.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/sctp/ipv6.c 2006-09-22 23:24:25.000000000 +0200 @@ -273,7 +273,7 @@ static void sctp_v6_get_saddr(struct sct __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr)); if (!asoc) { - ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr); + ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr, NULL); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; diff -Nurp linux-2.6.17.13-vs2.1.1-rc35/net/socket.c linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/socket.c --- linux-2.6.17.13-vs2.1.1-rc35/net/socket.c 2006-09-15 17:26:49.000000000 +0200 +++ linux-2.6.17.13-vs2.1.1-rc35.ipv6/net/socket.c 2006-09-22 23:24:25.000000000 +0200 @@ -95,6 +95,7 @@ #include #include #include +#include static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf, @@ -1159,9 +1160,14 @@ static int __sock_create(int family, int if (type < 0 || type >= SOCK_MAX) return -EINVAL; - /* disable IPv6 inside vservers for now */ - if (family == PF_INET6 && !vx_check(0, VX_ADMIN)) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + /* disable IPv6 inside vservers that have no IPv6 address configured */ + if (family == PF_INET6 && task_get_nx_info(current) && task_get_nx_info(current)->nbipv6 == 0) { + vxdprintk(VXD_CBIT(net, 4), "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT", + family, type, protocol, res, kern); return -EAFNOSUPPORT; + } +#endif /* Compatibility.