[Devel] [PATCH 1/2] C/R: Support for IPv6 addresses on network devices

Dan Smith danms at us.ibm.com
Wed Mar 24 12:40:24 PDT 2010


Signed-off-by: Dan Smith <danms at us.ibm.com>
---
 include/linux/checkpoint.h     |    2 +-
 include/linux/checkpoint_hdr.h |    8 ++
 net/checkpoint_dev.c           |  252 +++++++++++++++++++++++++++++++---------
 3 files changed, 208 insertions(+), 54 deletions(-)

diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
index efbc049..a8131bd 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -129,7 +129,7 @@ extern void *restore_netdev(struct ckpt_ctx *ctx);
 
 extern int ckpt_netdev_in_init_netns(struct ckpt_ctx *ctx,
 				     struct net_device *dev);
-extern int ckpt_netdev_inet_addrs(struct in_device *indev,
+extern int ckpt_netdev_inet_addrs(struct net_device *dev,
 				  struct ckpt_netdev_addr *list[]);
 extern int ckpt_netdev_hwaddr(struct net_device *dev,
 			      struct ckpt_hdr_netdev *h);
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index 01553b4..913d76d 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -802,6 +802,7 @@ struct ckpt_hdr_netdev {
 
 enum ckpt_netdev_addr_types {
 	CKPT_NETDEV_ADDR_IPV4,
+	CKPT_NETDEV_ADDR_IPV6,
 };
 
 struct ckpt_netdev_addr {
@@ -813,6 +814,13 @@ struct ckpt_netdev_addr {
 			__be32 inet4_mask;
 			__be32 inet4_broadcast;
 		};
+		struct {
+			__be32 inet6_addr[4];
+			__u32  inet6_prefix_len;
+			__u32  inet6_valid_lft;
+			__u32  inet6_prefered_lft;
+			__u16  inet6_scope;
+		};
 	} __attribute__((aligned(8)));
 } __attribute__((aligned(8)));
 
diff --git a/net/checkpoint_dev.c b/net/checkpoint_dev.c
index 2bb3d4d..173c2ea 100644
--- a/net/checkpoint_dev.c
+++ b/net/checkpoint_dev.c
@@ -18,8 +18,11 @@
 #include <linux/checkpoint_hdr.h>
 #include <linux/deferqueue.h>
 
+#include <net/if_inet6.h>
+#include <net/ipv6.h>
 #include <net/net_namespace.h>
 #include <net/sch_generic.h>
+#include <net/addrconf.h>
 
 struct veth_newlink {
 	char *peer;
@@ -47,6 +50,24 @@ static int __kern_devinet_ioctl(struct net *net, unsigned int cmd, void *arg)
 	return ret;
 }
 
+#ifdef CONFIG_IPV6
+static int __kern_addrconf(struct net *net, unsigned int cmd, void *arg)
+{
+	mm_segment_t fs;
+	int ret;
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == SIOCSIFADDR)
+		ret = addrconf_add_ifaddr(net, arg);
+	else
+		ret = -EINVAL;
+	set_fs(fs);
+
+	return ret;
+}
+#endif
+
 static int __kern_dev_ioctl(struct net *net, unsigned int cmd, void *arg)
 {
 	mm_segment_t fs;
@@ -149,11 +170,81 @@ int ckpt_netdev_hwaddr(struct net_device *dev, struct ckpt_hdr_netdev *h)
 	return 0;
 }
 
-int ckpt_netdev_inet_addrs(struct in_device *indev,
+static int ckpt_netdev_inet4_addrs(struct in_device *indev,
+				   int index, int max,
+				   struct ckpt_netdev_addr *abuf)
+{
+	struct in_ifaddr *addr = indev->ifa_list;
+
+	while (addr) {
+		abuf[index].type = CKPT_NETDEV_ADDR_IPV4;
+		abuf[index].inet4_local = htonl(addr->ifa_local);
+		abuf[index].inet4_address = htonl(addr->ifa_address);
+		abuf[index].inet4_mask = htonl(addr->ifa_mask);
+		abuf[index].inet4_broadcast = htonl(addr->ifa_broadcast);
+
+		addr = addr->ifa_next;
+		if (++index >= max)
+			return -E2BIG;
+	}
+
+	return index;
+}
+
+#ifdef CONFIG_IPV6
+
+#define __BYTE_ORDER_COPY(op, dst, src)		\
+	do {					\
+	int i;					\
+	for (i = 0; i < 4; i++)			\
+		dst[i] = op(src[i]);		\
+	} while (0);
+
+#define HTON_IPV6(dst, src) __BYTE_ORDER_COPY(htonl, dst, src)
+#define NTOH_IPV6(dst, src) __BYTE_ORDER_COPY(ntohl, dst, src)
+
+static int ckpt_netdev_inet6_addrs(struct inet6_dev *indev,
+				   int index, int max,
+				   struct ckpt_netdev_addr *abuf)
+{
+	struct inet6_ifaddr *addr = indev->addr_list;
+
+	while (addr) {
+		abuf[index].type = CKPT_NETDEV_ADDR_IPV6;
+
+		HTON_IPV6(abuf[index].inet6_addr, addr->addr.in6_u.u6_addr32);
+
+		ckpt_debug("Checkpointed inet6: %x:%x:%x:%x\n",
+			   abuf[index].inet6_addr[0],
+			   abuf[index].inet6_addr[1],
+			   abuf[index].inet6_addr[2],
+			   abuf[index].inet6_addr[3]);
+
+		abuf[index].inet6_prefix_len = addr->prefix_len;
+		abuf[index].inet6_valid_lft = addr->valid_lft;
+		abuf[index].inet6_prefered_lft = addr->prefered_lft;
+		abuf[index].inet6_scope = addr->scope;
+
+		addr = addr->if_next;
+		if (++index >= max)
+			return -E2BIG;
+	}
+
+	return index;
+}
+#else
+static int ckpt_netdev_inet6_addrs(struct inet6_dev *indev,
+				   int index, int max,
+				   struct ckpt_netdev_addr *abuf)
+{
+	return -ENOSYS;
+}
+#endif
+
+int ckpt_netdev_inet_addrs(struct net_device *dev,
 			   struct ckpt_netdev_addr *_abuf[])
 {
 	struct ckpt_netdev_addr *abuf = NULL;
-	struct in_ifaddr *addr = indev->ifa_list;
 	int addrs = 0;
 	int max = 32;
 
@@ -167,21 +258,21 @@ int ckpt_netdev_inet_addrs(struct in_device *indev,
 
 	read_lock(&dev_base_lock);
 
-	while (addr) {
-		abuf[addrs].type = CKPT_NETDEV_ADDR_IPV4; /* Only IPv4 now */
-		abuf[addrs].inet4_local = htonl(addr->ifa_local);
-		abuf[addrs].inet4_address = htonl(addr->ifa_address);
-		abuf[addrs].inet4_mask = htonl(addr->ifa_mask);
-		abuf[addrs].inet4_broadcast = htonl(addr->ifa_broadcast);
+	addrs = 0;
 
-		addr = addr->ifa_next;
-		if (++addrs >= max) {
-			read_unlock(&dev_base_lock);
-			max *= 2;
-			goto retry;
-		}
-	}
+	addrs = ckpt_netdev_inet4_addrs(dev->ip_ptr, addrs, max, abuf);
+	if (addrs == -E2BIG) {
+		read_unlock(&dev_base_lock);
+		goto retry;
+	} else if (addrs < 0)
+		goto unlock;
 
+	addrs = ckpt_netdev_inet6_addrs(dev->ip6_ptr, addrs, max, abuf);
+	if (addrs == -E2BIG) {
+		read_unlock(&dev_base_lock);
+		goto retry;
+	}
+ unlock:
 	read_unlock(&dev_base_lock);
  out:
 	if (addrs < 0) {
@@ -208,7 +299,7 @@ struct ckpt_hdr_netdev *ckpt_netdev_base(struct ckpt_ctx *ctx,
 		goto out;
 
 	*addrs = NULL;
-	ret = h->inet_addrs = ckpt_netdev_inet_addrs(dev->ip_ptr, addrs);
+	ret = h->inet_addrs = ckpt_netdev_inet_addrs(dev, addrs);
 	if (ret < 0)
 		goto out;
 
@@ -278,6 +369,93 @@ int checkpoint_netns(struct ckpt_ctx *ctx, void *ptr)
 	return ret;
 }
 
+static int restore_inet4_addr(struct ckpt_ctx *ctx,
+			      struct net_device *dev,
+			      struct net *net,
+			      struct ckpt_netdev_addr *addr)
+{
+	struct ifreq req;
+	struct sockaddr_in *inaddr;
+	int ret;
+
+	ckpt_debug("restoring %s: %x/%x/%x\n",
+		   dev->name,
+		   addr->inet4_address,
+		   addr->inet4_mask,
+		   addr->inet4_broadcast);
+
+	memcpy(req.ifr_name, dev->name, IFNAMSIZ);
+
+	inaddr = (struct sockaddr_in *)&req.ifr_addr;
+	inaddr->sin_addr.s_addr = ntohl(addr->inet4_address);
+	inaddr->sin_family = AF_INET;
+	ret = __kern_devinet_ioctl(net, SIOCSIFADDR, &req);
+	if (ret < 0) {
+		ckpt_err(ctx, ret, "Failed to set address\n");
+		return ret;
+	}
+
+	inaddr = (struct sockaddr_in *)&req.ifr_addr;
+	inaddr->sin_addr.s_addr = ntohl(addr->inet4_mask);
+	inaddr->sin_family = AF_INET;
+	ret = __kern_devinet_ioctl(net, SIOCSIFNETMASK, &req);
+	if (ret < 0) {
+		ckpt_err(ctx, ret, "Failed to set netmask\n");
+		return ret;
+	}
+
+	inaddr = (struct sockaddr_in *)&req.ifr_addr;
+	inaddr->sin_addr.s_addr = ntohl(addr->inet4_broadcast);
+	inaddr->sin_family = AF_INET;
+	ret = __kern_devinet_ioctl(net, SIOCSIFBRDADDR, &req);
+	if (ret < 0) {
+		ckpt_err(ctx, ret, "Failed to set broadcast\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_IPV6
+static int restore_inet6_addr(struct ckpt_ctx *ctx,
+			      struct net_device *dev,
+			      struct net *net,
+			      struct ckpt_netdev_addr *addr)
+{
+	struct in6_ifreq req;
+	int ret;
+
+	ckpt_debug("restoring %s: %x:%x:%x:%x/%i\n",
+		   dev->name,
+		   addr->inet6_addr[0],
+		   addr->inet6_addr[1],
+		   addr->inet6_addr[2],
+		   addr->inet6_addr[3],
+		   addr->inet6_prefix_len);
+
+	req.ifr6_ifindex = dev->ifindex;
+	NTOH_IPV6(req.ifr6_addr.in6_u.u6_addr32, &addr->inet6_addr);
+	req.ifr6_prefixlen = addr->inet6_prefix_len;
+
+	ret = __kern_addrconf(net, SIOCSIFADDR, &req);
+	if (ret == -EEXIST)
+		ret = 0;
+	else if (ret < 0)
+		ckpt_err(ctx, ret, "Failed to set address");
+
+	return ret;
+}
+#else
+static int restore_inet6_addr(struct ckpt_ctx *ctx,
+			      struct net_device *dev,
+			      struct net *net,
+			      struct ckpt_netdev_addr *addr)
+{
+	ckpt_err(ctx, -ENOSYS, "IPv6 not supported");
+	return -ENOSYS;
+}
+#endif
+
 static int restore_in_addrs(struct ckpt_ctx *ctx,
 			    __u32 naddrs,
 			    struct net *net,
@@ -294,49 +472,17 @@ static int restore_in_addrs(struct ckpt_ctx *ctx,
 
 	for (i = 0; i < naddrs; i++) {
 		struct ckpt_netdev_addr *addr = &addrs[i];
-		struct ifreq req;
-		struct sockaddr_in *inaddr;
 
-		if (addr->type != CKPT_NETDEV_ADDR_IPV4) {
+		if (addr->type == CKPT_NETDEV_ADDR_IPV4)
+			ret = restore_inet4_addr(ctx, dev, net, addr);
+		else if (addr->type == CKPT_NETDEV_ADDR_IPV6)
+			ret = restore_inet6_addr(ctx, dev, net, addr);
+		else {
 			ret = -EINVAL;
 			ckpt_err(ctx, ret, "Unsupported netdev addr type %i\n",
 				 addr->type);
 			break;
 		}
-
-		ckpt_debug("restoring %s: %x/%x/%x\n", dev->name,
-			   addr->inet4_address,
-			   addr->inet4_mask,
-			   addr->inet4_broadcast);
-
-		memcpy(req.ifr_name, dev->name, IFNAMSIZ);
-
-		inaddr = (struct sockaddr_in *)&req.ifr_addr;
-		inaddr->sin_addr.s_addr = ntohl(addr->inet4_address);
-		inaddr->sin_family = AF_INET;
-		ret = __kern_devinet_ioctl(net, SIOCSIFADDR, &req);
-		if (ret < 0) {
-			ckpt_err(ctx, ret, "Failed to set address\n");
-			break;
-		}
-
-		inaddr = (struct sockaddr_in *)&req.ifr_addr;
-		inaddr->sin_addr.s_addr = ntohl(addr->inet4_mask);
-		inaddr->sin_family = AF_INET;
-		ret = __kern_devinet_ioctl(net, SIOCSIFNETMASK, &req);
-		if (ret < 0) {
-			ckpt_err(ctx, ret, "Failed to set netmask\n");
-			break;
-		}
-
-		inaddr = (struct sockaddr_in *)&req.ifr_addr;
-		inaddr->sin_addr.s_addr = ntohl(addr->inet4_broadcast);
-		inaddr->sin_family = AF_INET;
-		ret = __kern_devinet_ioctl(net, SIOCSIFBRDADDR, &req);
-		if (ret < 0) {
-			ckpt_err(ctx, ret, "Failed to set broadcast\n");
-			break;
-		}
 	}
 
  out:
-- 
1.6.2.5

_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list