IPv6 support for VServer
authorDaniel Hokka Zakrisson <dhokka@cs.princeton.edu>
Fri, 6 Jul 2007 14:55:57 +0000 (14:55 +0000)
committerDaniel Hokka Zakrisson <dhokka@cs.princeton.edu>
Fri, 6 Jul 2007 14:55:57 +0000 (14:55 +0000)
22 files changed:
Documentation/vserver/debug.txt
include/linux/vs_network.h
include/linux/vserver/debug.h
include/linux/vserver/network.h
include/linux/vserver/network_cmd.h
include/net/addrconf.h
include/net/ipv6.h
kernel/vserver/network.c
kernel/vserver/proc.c
net/ipv4/af_inet.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_output.c
net/ipv6/ndisc.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_policy.c
net/sctp/ipv6.c
net/socket.c

index 4464a0f..188b49f 100644 (file)
@@ -51,9 +51,17 @@ debug_misc:
 debug_net:
 
  2   4 "nx_addr_conflict(%p,%p) %d.%d,%d.%d"
+       "nx_addr6_conflict(%u,%u)"
  3   8 "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d"
        "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d"
+       "inet6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL"
+       "inet6_bind(" NIP6_FMT ", %d): PASS"
+       "rawv6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL"
+       "rawv6_bind(" NIP6_FMT ", %d): PASS"
  4  10 "ip_route_connect(%p) %p,%p;%lx"
+       "inet6_create(%p, %d): %d"
+       "tcp_v6_connect(dest ::1 redirected to: " NIP6_FMT ", %d)"
+       "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT"
  5  20 "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx"
  6  40 "sk,egf: %p [#%d] (from %d)"
        "sk,egn: %p [#%d] (from %d)"
@@ -73,6 +81,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"
index a99d0e4..0600425 100644 (file)
@@ -162,6 +162,9 @@ static inline int addr_in_nx_info(struct nx_info *nxi, uint32_t addr)
                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<n; i++) {
@@ -177,6 +180,34 @@ static inline void exit_nx_info(struct task_struct *p)
                release_nx_info(p->nx_info, p);
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+#include <net/ipv6.h>
+
+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; i<n; i++) {
+               if (ipv6_addr_equal(&(nxi->ipv6[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 */
 
 #ifdef CONFIG_NETWORK_SECMARK
 #define skb_tag secmark
index 1b1f34c..44c9702 100644 (file)
@@ -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]"
index 0866bc8..6195c32 100644 (file)
@@ -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 */
 
@@ -49,7 +49,9 @@
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 #include <asm/atomic.h>
-
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <linux/in6.h>
+#endif
 
 struct nx_info {
        struct hlist_node nx_hlist;     /* linked list of nxinfos */
@@ -70,10 +72,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 */
 
@@ -111,7 +132,6 @@ extern int nx_migrate_task(struct task_struct *, struct nx_info *);
 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 *);
index fd6bdde..37c30b9 100644 (file)
@@ -35,11 +35,26 @@ 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 <linux/in.h>
+#include <linux/in6.h>
+#else
+#include <arpa/inet.h>
+#endif /* __KERNEL__ */
+
 struct vcmd_net_addr_v0 {
        uint16_t type;
        uint16_t count;
-       uint32_t ip[4];
-       uint32_t mask[4];
+       union {
+               struct {
+                       struct in_addr ip[4];
+                       struct in_addr mask[4];
+               };
+               struct {
+                       struct in6_addr ip6;
+                       uint32_t prefix;
+               };
+       };
        /* more to come */
 };
 
index 88df8fc..8fd5cc8 100644 (file)
@@ -69,10 +69,12 @@ extern struct inet6_ifaddr *        ipv6_get_ifaddr(struct in6_addr *addr,
                                                int strict);
 extern int                     ipv6_get_saddr(struct dst_entry *dst, 
                                               struct in6_addr *daddr,
-                                              struct in6_addr *saddr);
+                                              struct in6_addr *saddr,
+                                              struct nx_info *nxi);
 extern int                     ipv6_dev_get_saddr(struct net_device *dev, 
                                               struct in6_addr *daddr,
-                                              struct in6_addr *saddr);
+                                              struct in6_addr *saddr,
+                                              struct nx_info *nxi);
 extern int                     ipv6_get_lladdr(struct net_device *dev, struct in6_addr *);
 extern int                     ipv6_rcv_saddr_equal(const struct sock *sk, 
                                                      const struct sock *sk2);
index 00328b7..60b6613 100644 (file)
@@ -260,6 +260,7 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
                                          struct ipv6_txoptions *opt);
 
 extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb);
+extern int ipv6_dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi);
 
 extern int ip6_frag_nqueues;
 extern atomic_t ip6_frag_mem;
index 9dd1637..5388efc 100644 (file)
@@ -439,6 +439,27 @@ out:
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
 
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+#include <net/addrconf.h>
+
+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)
@@ -448,11 +469,86 @@ int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi)
        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)
@@ -460,18 +556,33 @@ int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi)
 
        if (!dev)
                goto out;
-       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);
+
+#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
+
 out:
        return ret;
 }
@@ -488,8 +599,8 @@ static inline int __addr_in_socket(const struct sock *sk, uint32_t addr)
        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) {
@@ -508,8 +619,8 @@ static inline int __addr_in_socket(const struct sock *sk, uint32_t addr)
 int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, const 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 */
@@ -645,6 +756,40 @@ int vc_net_migrate(struct nx_info *nxi, void __user *data)
        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;
@@ -659,6 +804,14 @@ int vc_net_add(struct nx_info *nxi, void __user *data)
                        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;
        }
@@ -666,21 +819,51 @@ int vc_net_add(struct nx_info *nxi, void __user *data)
        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[index].s_addr, vc_data.mask[index].s_addr) == -1) {
+                               /* Only add if address is new */
+                               vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIPQUAD_FMT,
+                                       nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr));
+                               nxi->ipv4[pos] = vc_data.ip[index].s_addr;
+                               nxi->mask[pos] = vc_data.mask[index].s_addr;
+                               nxi->nbipv4++;
+                               ret++;
+                       } else
+                               vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIPQUAD_FMT " EXISTS",
+                                       nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr));
                        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[0].s_addr;
                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.ip6, vc_data.prefix) == -1) {
+                               /* Only add if address is new */
+                               vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIP6_FMT,
+                                       nxi->nx_id, index, NIP6(vc_data.ip6));
+                               nxi->ipv6[nxi->nbipv6] = vc_data.ip6;
+                               nxi->prefix6[nxi->nbipv6] = vc_data.prefix;
+                               nxi->nbipv6++;
+                               ret++;
+                       } else
+                               vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIP6_FMT " EXISTS",
+                                       nxi->nx_id, index, NIP6(vc_data.ip6));
+                       index++;
+               }
+               break;
+#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
+
        default:
                ret = -EINVAL;
                break;
@@ -691,19 +874,68 @@ int vc_net_add(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;
 
        switch (vc_data.type) {
        case NXA_TYPE_ANY:
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               ret = nxi->nbipv6;
+               nxi->nbipv6 = 0;
+#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
+               ret += nxi->nbipv4;
                nxi->nbipv4 = 0;
                break;
 
+       case NXA_TYPE_IPV4:
+               index = 0;
+               ret = 0;
+               while (index < vc_data.count) {
+                       pos = vc_net_find_v4(nxi, vc_data.ip[index].s_addr, vc_data.mask[index].s_addr);
+                       if (pos >= 0) {
+                               nxi->nbipv4--;
+                               ret++;
+                               vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%d, data[%d]): " NIPQUAD_FMT,
+                                               nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr));
+                       }
+                       while (pos >= 0 && 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.ip6), vc_data.prefix);
+                       if (pos >= 0) {
+                               nxi->nbipv6--;
+                               ret++;
+                               vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%d, data[%d]): " NIP6_FMT " EXISTS",
+                                               nxi->nx_id, index, NIP6(vc_data.ip6));
+                       }
+                       while (pos >= 0 && 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)
@@ -770,3 +1002,10 @@ int vc_set_ncaps(struct nx_info *nxi, void __user *data)
 EXPORT_SYMBOL_GPL(free_nx_info);
 EXPORT_SYMBOL_GPL(unhash_nx_info);
 
+#ifdef CONFIG_IPV6_MODULE
+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 */
index f21e283..4e6c15c 100644 (file)
@@ -187,6 +187,13 @@ int proc_nxi_info (struct nx_info *nxi, 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; i<nxi->nbipv6;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 */
        return length;
 }
 
index 865c850..27653af 100644 (file)
@@ -426,10 +426,10 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        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];
@@ -453,8 +453,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        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
index 2c23f08..529e397 100644 (file)
@@ -917,7 +917,7 @@ static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
 }
 
 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;
@@ -962,6 +962,11 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 
                        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
@@ -1172,9 +1177,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 ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);
+       return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr, nxi);
 }
 
 
@@ -1277,26 +1282,48 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
        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 (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_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 (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 (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;
 }
 
@@ -2744,8 +2771,9 @@ static int if6_seq_show(struct seq_file *seq, void *v)
 {
        struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
 
-       /* no ipv6 inside a vserver for now */
-       if (nx_check(0, VS_ADMIN|VS_WATCH))
+       /* Only addresses visible to vserver context */
+       if (nx_check(0, VS_ADMIN|VS_WATCH) ||
+               addr6_in_nx_info(current_nx_info(), &ifp->addr))
                seq_printf(seq,
                   NIP6_SEQFMT " %02x %02x %02x %02x %8s\n",
                   NIP6(ifp->addr),
@@ -3218,8 +3246,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
        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];
@@ -3242,6 +3270,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                             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,
@@ -3255,6 +3285,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                             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,
@@ -3268,6 +3300,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                             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,
@@ -3494,14 +3528,16 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        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 if no addr set */
+       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 && !ipv6_dev_in_nx_info6(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, 
index 0e0e426..f9a16d0 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
+#include <linux/vs_context.h>
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -147,9 +148,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;
@@ -233,6 +236,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();
@@ -306,6 +311,18 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                                }
                        }
 
+                       /* 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.
                         */
@@ -692,6 +709,31 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
 
 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)
 {
@@ -760,6 +802,17 @@ static void cleanup_ipv6_mibs(void)
        snmp6_mib_free((void **)udplite_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;
@@ -877,6 +930,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;
@@ -930,6 +988,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();
index ba13f74..dd991f6 100644 (file)
@@ -102,6 +102,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)
@@ -127,6 +147,10 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
                                        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;
index 7b7bd44..3acad4d 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/in6.h>
 #include <linux/tcp.h>
 #include <linux/route.h>
-#include <linux/module.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
@@ -856,7 +855,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
                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;
        }
index 39bb658..b1907d9 100644 (file)
@@ -449,7 +449,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
                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;
        }
index 9479fbd..74ef1f0 100644 (file)
@@ -103,7 +103,8 @@ struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
                                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))
@@ -261,7 +262,19 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                                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.
                 */
@@ -585,6 +598,11 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        if (err)
                goto error_fault;
 
+       err = -EPERM;
+       if (!nx_check(0, VS_ADMIN) && !capable(CAP_NET_RAW)
+               && (!addr6_in_nx_info(sk->sk_nx_info, &iph->saddr)))
+               goto error_free;
+
        IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
        err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
                      dst_output);
@@ -597,6 +615,7 @@ out:
 
 error_fault:
        err = -EFAULT;
+error_free:
        kfree_skb(skb);
 error:
        IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
index 01bcf4a..04ca7aa 100644 (file)
@@ -2109,7 +2109,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
                NLA_PUT_U32(skb, RTA_IIF, 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)
                        NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
        }
 
index a2d41ba..bf1fc22 100644 (file)
@@ -160,8 +160,19 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
         *      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);
 
index b5dc5db..1f1eb94 100644 (file)
@@ -58,6 +58,17 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
        return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
 }
 
+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; i<n; i++)
+               if (ipv6_addr_equal(&nx_info->ipv6[i], addr))
+                       return 1;
+       return 0;
+}
+
 static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
                                      struct in6_addr *daddr, __be16 dport,
                                      int dif, struct hlist_head udptable[])
@@ -83,6 +94,11 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
                                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))
index 8dffd4d..a09fece 100644 (file)
@@ -49,7 +49,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
 
        if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
                ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
-                              (struct in6_addr *)&saddr->a6);
+                              (struct in6_addr *)&saddr->a6, NULL);
                dst_release(&rt->u.dst);
                return 0;
        }
index ef36be0..8f91d07 100644 (file)
@@ -306,7 +306,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
                          __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;
index 2506f9d..d81381f 100644 (file)
@@ -94,6 +94,7 @@
 #include <linux/netfilter.h>
 #include <linux/vs_base.h>
 #include <linux/vs_socket.h>
+#include <linux/vs_network.h>
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
 static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
@@ -1096,9 +1097,14 @@ static int __sock_create(int family, int type, int protocol,
        if (type < 0 || type >= SOCK_MAX)
                return -EINVAL;
 
-       /* disable IPv6 inside vservers for now */
-       if (family == PF_INET6 && !nx_check(0, VS_ADMIN))
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       /* disable IPv6 inside vservers that have no IPv6 address configured */
+       if (family == PF_INET6 && current_nx_info() && current_nx_info()->nbipv6 == 0) {
+               vxdprintk(VXD_CBIT(net, 4), "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT",
+                   family, type, protocol, res, kern);
                return -EAFNOSUPPORT;
+       }
+#endif
 
        /* Compatibility.