[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