c/r: IPv6 support
This version of the patch set incorporates feedback from Brian, as well as a new patch at the end to check for IPv4 multicast addresses when doing the checkpoint.
A message that is not in the archive (sent off-list or not yet received): 1270563183-9351-1-git-send-email-danms-r/[email protected]
PATCH 1/3 C/R: Support for IPv6 addresses on network devices (v2)
Changes in v2:
- Store an in6_addr structure in the checkpoint stream
- Fix network byte order conversion
- Don't checkpoint and restore non-global scope addresses
- Fail checkpoint if we find global scope multicast or anycast addresses
--- include/linux/checkpoint.h | 2 +- include/linux/checkpoint_hdr.h | 8 ++ net/checkpoint_dev.c | 272 ++++++++++++++++++++++++++++++++-------- 3 files changed, 228 insertions(+), 54 deletions(-)
include/linux/checkpoint.h +1 -1
@@ -132,7 +132,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);
include/linux/checkpoint_hdr.h +8 -0
@@ -804,6 +804,7 @@ struct ckpt_hdr_netdev {enum ckpt_netdev_addr_types {CKPT_NETDEV_ADDR_IPV4 , +CKPT_NETDEV_ADDR_IPV6 , };struct ckpt_netdev_addr {
@@ -815,6 +816,13 @@ struct ckpt_netdev_addr {__be32 inet4_mask;__be32 inet4_broadcast; }; +struct { +struct in6_addr inet6_addr; +__u32 inet6_prefix_len; +__u32 inet6_valid_lft; +__u32 inet6_prefered_lft; +__u16 inet6_scope; + }; } __attribute__((aligned(8))); } __attribute__((aligned(8)));
net/checkpoint_dev.c +219 -53
327 lines not on this page · raw message
Signature · 1 line
1.6.2.5
A message that is not in the archive (sent off-list or not yet received): 1270563183-9351-2-git-send-email-danms-r/[email protected]
Re: [PATCH 1/3] C/R: Support for IPv6 addresses on network devices (v2)
net/checkpoint_dev.c int ckpt_netdev_hwaddr(struct net_device *dev, struct ckpt_hdr_netdev *h) · line 220
Quoted 11 lines · Dan Smith
net/checkpoint_dev.c +11
-0+static int ckpt_netdev_inet6_addrs (struct inet6_dev *indev, +int index,int max, +struct ckpt_netdev_addr *abuf) +{ +struct inet6_ifaddr *addr; +struct ifmcaddr6 *mcaddr; +struct ifacaddr6 *acaddr; + +for (addr = indev->addr_list; addr; addr = addr->if_next) { +if (ipv6_addr_scope (&addr->addr)) +continue ;/* Ignore non-global scope addresses */
This will prevent the loopback address (::1) from getting checkpointed since it's host-local. The ipv6 module will add it anyways so it's probably not a big deal.
-Brian
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH 1/3] C/R: Support for IPv6 addresses on network devices (v2)
BH> This will prevent the loopback address (::1) from getting BH> checkpointed since it's host-local. The ipv6 module will add it BH> anyways so it's probably not a big deal.
Yep, and it does.
Thanks!
Signature · 3 lines
Dan Smith IBM Linux Technology Center email: danms-r/[email protected]
A message that is not in the archive (sent off-list or not yet received): 87eiisblkn.fsf-FLMGYpZoEPULwtHQx/[email protected]
Re: [PATCH 1/3] C/R: Support for IPv6 addresses on network devices (v2)
Quoted 5 lines · Dan Smith
BH> This will prevent the loopback address (::1) from getting BH> checkpointed since it's host-local. The ipv6 module will add it BH> anyways so it's probably not a big deal.
Yep, and it does.
Probably worth a comment inline ?
Oren.
Re: [PATCH 1/3] C/R: Support for IPv6 addresses on network devices (v2)
In reply to a message not in the archiveQuoting Dan Smith (danms-r/[email protected]):
Two related problems here:
Quoted 1 line
+#ifdef
CONFIG_IPV6
1. this will only trigger if CONFIG_IPV6=y, not if it =m. So you might have meant
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
or something. But I'm not sure that if it's a module but not yet loaded that that suffices?
Quoted 106 lines
net/checkpoint_dev.c +81
-14+ +#define __BYTE_ORDER_COPY (op, dst, src) \ + do { \ + int i; \ + for (i = 0; i < 16; i++) { \ + (dst)->in6_u.u6_addr8[i] = \ + (src)->in6_u.u6_addr8[16-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; +struct ifmcaddr6 *mcaddr; +struct ifacaddr6 *acaddr; + +for (addr = indev->addr_list; addr; addr = addr->if_next) { +if (ipv6_addr_scope (&addr->addr)) +continue ;/* Ignore non-global scope addresses */ + + abuf[index].type =CKPT_NETDEV_ADDR_IPV6 ; + +HTON_IPV6 (&abuf[index].inet6_addr, &addr->addr); + +ckpt_debug ("Checkpointed inet6: %pI6\n" , &addr->addr); + + 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; + +if (++index >= max) +return -E2BIG ; + } + +for (mcaddr = indev->mc_list; mcaddr; mcaddr = mcaddr->next) { +if (ipv6_addr_scope (&mcaddr->mca_addr)) +continue ;/* Ignore non-global scope addresses */ + +/* TODO */ + +/* Multicast addresses are not supported, so do not +* allow checkpoint to continue if one is assigned +*/ +ckpt_debug ("ipv6 multicast addresses are not supported\n" ); +return -EINVAL ; + } + +for (acaddr = indev->ac_list; acaddr; acaddr = acaddr->aca_next) { +if (ipv6_addr_scope (&acaddr->aca_addr)) +continue ;/* Ignore non-global scope addresses */ + +/* TODO */ + +/* Anycast addresses are not supported, so do not +* allow checkpoint to continue if one is assigned +*/ +ckpt_debug ("ipv6 anycast addresses are not supported\n" ); +return -EINVAL ; + } + +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 ;@@ -169,21 +288,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 ) {
net/checkpoint_dev.c int ckpt_netdev_inet_addrs(struct in_device *indev, · line 304
Quoted 10 lines
net/checkpoint_dev.c +9
-0+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; + }
This is the second problem. If CONFIG_IPV6=n or CONFIG_IPV6=m, then ckpt_netdev_inet6_addrs() will return -ENOSYS, and you'll fail here. So in those cases there is now no way to do a checkpoint with CHECKPOINT_NETNS (or without CHECKPOINT_NONETNS :).
The fix of course can't be quite as simple as ignoring return value of -ENOSYS since you'll have lost the passed-in addrs from ckpt_netdev_inet4_addrs.
net/checkpoint_dev.c int ckpt_netdev_inet_addrs(struct in_device *indev, · line 308
Quoted 4 lines
net/checkpoint_dev.c +1
-0+ unlock:read_unlock (&dev_base_lock); out:if (addrs <0 ) {
-serge
A message that is not in the archive (sent off-list or not yet received): 20100407041858.GA12287-r/[email protected]
Re: [PATCH 1/3] C/R: Support for IPv6 addresses on network devices (v2)
SH> 1. this will only trigger if CONFIG_IPV6=y, not if it =m. So you SH> might have meant
SH> #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Ah, okay, right.
Quoted 5 lines
net/checkpoint_dev.c int ckpt_netdev_inet_addrs(struct in_device *indev, · line 304
Quoted 5 lines
net/checkpoint_dev.c +5
-0+ addrs =ckpt_netdev_inet6_addrs (dev->ip6_ptr, addrs, max, abuf); +if (addrs == -E2BIG ) { +read_unlock (&dev_base_lock); + goto retry; + }
SH> This is the second problem. If CONFIG_IPV6=n or CONFIG_IPV6=m, then SH> ckpt_netdev_inet6_addrs() will return -ENOSYS, and you'll fail here. SH> So in those cases there is now no way to do a checkpoint with SH> CHECKPOINT_NETNS (or without CHECKPOINT_NONETNS :).
SH> The fix of course can't be quite as simple as ignoring return SH> value of -ENOSYS since you'll have lost the passed-in addrs from SH> ckpt_netdev_inet4_addrs.
If I change it to compile in with CONFIG_IPV6_MODULE as you stated above, then it won't return -ENOSYS, right? The code will still be there, and will not traverse the ipv6 address list (if I make it check for an empty dev->ip6_ptr) until the module is loaded and the devices gain some IPv6 information.
I'll test this and resend the patch appropriately.
Thanks!
Signature · 3 lines
Dan Smith IBM Linux Technology Center email: danms-r/[email protected]
A message that is not in the archive (sent off-list or not yet received): 87aatfbbtk.fsf-FLMGYpZoEPULwtHQx/[email protected]
Re: [PATCH 1/3] C/R: Support for IPv6 addresses on network devices (v2)
Quoted 17 lines · Dan Smith
SH> 1. this will only trigger if
CONFIG_IPV6=y, not if it =m. So you SH> might have meant
SH> #ifdefined(CONFIG_IPV6)||defined(CONFIG_IPV6_MODULE)Ah, okay, right.
Quoted 5 lines
net/checkpoint_dev.c int ckpt_netdev_inet_addrs(struct in_device *indev, · line 304
Quoted 5 lines
net/checkpoint_dev.c +5
-0+ addrs =ckpt_netdev_inet6_addrs (dev->ip6_ptr, addrs, max, abuf); +if (addrs == -E2BIG ) { +read_unlock (&dev_base_lock); + goto retry; + }SH> This is the second problem. If
CONFIG_IPV6=norCONFIG_IPV6=m, then SH>ckpt_netdev_inet6_addrs()will return-ENOSYS, and you'll fail here. SH> So in those cases there is now no way to do a checkpoint with SH>CHECKPOINT_NETNS(or withoutCHECKPOINT_NONETNS:).
Quoted 6 lines
SH> The fix of course can't be quite as simple as ignoring return SH> value of
-ENOSYSsince you'll have lost the passed-in addrs from SH>ckpt_netdev_inet4_addrs.If I change it to compile in with
CONFIG_IPV6_MODULEas you stated above, then it won't return-ENOSYS, right? The code will still be
But it'll return -ENOSYS if CONFIG_IPV6=n.
Quoted 16 lines
there, and will not traverse the ipv6 address list (if I make it check for an empty
dev->ip6_ptr) until the module is loaded and the devices gain some IPv6 information.I'll test this and resend the patch appropriately.
Thanks!
Signature · 7 lines
Dan Smith IBM Linux Technology Center email: danms-r/[email protected] _______________________________________________ Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org https://lists.linux-foundation.org/mailman/listinfo/containers
PATCH 2/3 C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag
In reply to a message not in the archiveThe first item is a result of sockaddr_in6 being larger than the base sockaddr structure, thus not being long enough to reserve enough space in the checkpoint header.
The second comes into play when things (like sshd) bind to INADDR6_ANY, set the "ipv6only" socket flag and then bind an IPv4 socket to the same port.
--- include/linux/checkpoint_hdr.h | 13 +++++++++++-- net/ipv4/checkpoint.c | 34 ++++++++++++++++++++-------------- net/ipv6/af_inet6.c | 2 ++ 3 files changed, 33 insertions(+), 16 deletions(-)
include/linux/checkpoint_hdr.h +11 -2
@@ -758,12 +758,21 @@ struct ckpt_hdr_socket_inet {struct in6_addr saddr;struct in6_addr rcv_saddr;struct in6_addr daddr; +__u8 ipv6only; } inet6 __attribute__ ((aligned(8)));__u32 laddr_len;__u32 raddr_len; -struct sockaddr_in laddr; -struct sockaddr_in raddr; +union { +struct sockaddr laddr; +struct sockaddr_in laddr4; +struct sockaddr_in6 laddr6; + }; +union { +struct sockaddr raddr; +struct sockaddr_in raddr4; +struct sockaddr_in6 raddr6; + }; } __attribute__((aligned(8)));struct ckpt_hdr_file_socket {
net/ipv4/checkpoint.c +20 -14
@@ -190,12 +190,14 @@ static int sock_inet_restore_connection(struct sock *sk,struct inet_sock *inet =inet_sk (sk);int tcp_gso = sk->sk_family ==AF_INET ?SKB_GSO_TCPV4 :SKB_GSO_TCPV6 ; - inet->inet_daddr = hh->raddr.sin_addr.s_addr; - inet->inet_saddr = hh->laddr.sin_addr.s_addr; - inet->inet_rcv_saddr = inet->inet_saddr; +if (sk->sk_family ==AF_INET ) { + inet->inet_daddr = hh->raddr4.sin_addr.s_addr; + inet->inet_saddr = hh->laddr4.sin_addr.s_addr; + inet->inet_rcv_saddr = inet->inet_saddr; - inet->inet_dport = hh->raddr.sin_port; - inet->inet_sport = hh->laddr.sin_port; + inet->inet_dport = hh->raddr4.sin_port; + inet->inet_sport = hh->laddr4.sin_port; + }if (sk->sk_protocol ==IPPROTO_TCP ) sk->sk_gso_type = tcp_gso;
@@ -266,6 +268,7 @@ static int sock_inet_cptrst(struct ckpt_ctx *ctx,ipv6_addr_copy (&inet6->rcv_saddr, &hh->inet6.rcv_saddr);ipv6_addr_copy (&inet6->daddr, &hh->inet6.daddr); } +CKPT_COPY (op, hh->inet6.ipv6only, inet6->ipv6only); }return ret;
@@ -281,8 +284,8 @@ int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)return -EINVAL ; ret =ckpt_sock_getnames (ctx, sock, - (struct sockaddr *)&in->laddr, &in->laddr_len, - (struct sockaddr *)&in->raddr, &in->raddr_len); + &in->laddr, &in->laddr_len, + &in->raddr, &in->raddr_len);if (ret) goto out;
@@ -387,19 +390,19 @@ static int inet_precheck(struct socket *sock, struct ckpt_hdr_socket_inet *in)__u8 nonagle_mask =TCP_NAGLE_OFF |TCP_NAGLE_CORK |TCP_NAGLE_PUSH ;__u8 ecn_mask =TCP_ECN_OK |TCP_ECN_QUEUE_CWR |TCP_ECN_DEMAND_CWR ; -if ((htons (in->laddr.sin_port) <PROT_SOCK ) && +if ((htons (in->laddr4.sin_port) <PROT_SOCK ) && !capable (CAP_NET_BIND_SERVICE )) {ckpt_debug ("unable to bind to port %hu\n" , -htons (in->laddr.sin_port)); +htons (in->laddr4.sin_port));return -EINVAL ; } -if (in->laddr_len >sizeof (struct sockaddr_in )) { +if (in->laddr_len >sizeof (in->laddr6)) {ckpt_debug ("laddr_len is too big\n" );return -EINVAL ; } -if (in->raddr_len >sizeof (struct sockaddr_in )) { +if (in->raddr_len >sizeof (in->laddr6)) {ckpt_debug ("raddr_len is too big\n" );return -EINVAL ; }
@@ -498,13 +501,16 @@ int inet_restore(struct ckpt_ctx *ctx, ((h->sock.state == TCP_CLOSE) && (in->laddr_len > 0))) { sock->sk->sk_reuse =2 ;inet_sk (sock->sk)->freebind =1 ; - ret = sock->ops->bind (sock, - (struct sockaddr *)&in->laddr, - in->laddr_len); + ret = sock->ops->bind (sock, &in->laddr, in->laddr_len);ckpt_debug ("inet bind: %i\n" , ret);if (ret <0 ) goto out; +if (in->inet6.ipv6only) { +struct ipv6_pinfo *np =inet6_sk (sock->sk); + np->ipv6only =1 ; + } +if (h->sock.state ==TCP_LISTEN ) { ret = sock->ops->listen (sock, h->sock.backlog);ckpt_debug ("inet listen: %i\n" , ret);
net/ipv6/af_inet6.c +2 -0
@@ -523,6 +523,8 @@ const struct proto_ops inet6_stream_ops = { .mmap = sock_no_mmap, .sendpage = tcp_sendpage, .splice_read = tcp_splice_read, + .checkpoint = inet_checkpoint, + .restore = inet_restore, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_sock_common_setsockopt, .compat_getsockopt = compat_sock_common_getsockopt,
Signature · 1 line
1.6.2.5
A message that is not in the archive (sent off-list or not yet received): 1270563183-9351-3-git-send-email-danms-r/[email protected]
Re: [PATCH 2/3] C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag
Quoted 9 lines · Dan Smith
The first item is a result of
sockaddr_in6being larger than the base sockaddr structure, thus not being long enough to reserve enough space in the checkpoint header.The second comes into play when things (like sshd) bind to
INADDR6_ANY, set the "ipv6only" socket flag and then bind an IPv4 socket to the same port.Signed-off-by Dan Smith <danms-r/[email protected]>
since ipv6 can be a module, this requires:
From 7132840517ecc258a2d972dae7011a6666e91c56 Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <serue-r/[email protected]>
Date: Tue, 6 Apr 2010 12:35:54 -0500
Subject: [PATCH 1/1] export needed symbols needed by ipv6
--- net/ipv4/checkpoint.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
net/ipv4/checkpoint.c +2 -0
@@ -299,6 +299,7 @@ int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)return ret; } +EXPORT_SYMBOL_GPL (inet_checkpoint);int inet_collect (struct ckpt_ctx *ctx,struct socket *sock) {
@@ -553,3 +554,4 @@ int inet_restore(struct ckpt_ctx *ctx,return ret; } +EXPORT_SYMBOL_GPL (inet_restore);
Signature · 1 line
1.6.0.6
PATCH 3/3 Fail checkpoint if IPv4 multicast addresses are configured
In reply to a message not in the archiveThis causes checkpoint to fail if an interface actually has a multicast membership.
--- net/checkpoint_dev.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
net/checkpoint_dev.c +15 -0
@@ -17,6 +17,7 @@#include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h> #include <linux/deferqueue.h> +#include <linux/igmp.h> #include <net/if_inet6.h> #include <net/ipv6.h>
@@ -177,6 +178,7 @@ static int ckpt_netdev_inet4_addrs(struct in_device *indev, struct ckpt_netdev_addr *abuf) {struct in_ifaddr *addr = indev->ifa_list; +struct ip_mc_list *mcaddr;while (addr) { abuf[index].type =CKPT_NETDEV_ADDR_IPV4 ;
@@ -190,6 +192,19 @@ static int ckpt_netdev_inet4_addrs(struct in_device *indev,return -E2BIG ; } +for (mcaddr = indev->mc_list; mcaddr; mcaddr = mcaddr->next) { +if ((mcaddr->multiaddr &IGMP_LOCAL_GROUP_MASK ) ==IGMP_LOCAL_GROUP ) +continue ; + +/* TODO */ + +/* Multicast addresses are not supported, so do not +* allow checkpoint to continue if one is assigned +*/ +ckpt_debug ("ipv4 multicast addresses are not supported\n" ); +return -EINVAL ; + } +return index; }
Signature · 1 line
1.6.2.5