Skip to contentSkip to conversation

A modular approach to handling netdev address c/r

PATCH In review Dan Smith 4 participants 23 messages Apr 8, 2010 – Apr 26, 2010 16 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

Dan Smith

author
#0 lore raw

Based on Serge's obsession with avoiding build breaks, I've changed around the ipv6 patch to make the whole process more modular. This set now:

1. Introduces a registration system for interface address families to declare support for checkpoint and provide handlers to do it
2. Moves the inet4 code into net/ipv4/devinet.c in much the same form as it was generalized in the previous set of ipv6 patches
3. Adds the ipv6 code to net/ipv6/addrconf.c
4. Compiles for every combination of checkpoint, netns, ipv4, and ipv6 support that I can think of

(not necessarily in the above order).

I think it makes it all much nicer.

Comments?

A message that is not in the archive (sent off-list or not yet received): 1270748932-26745-1-git-send-email-danms-r/[email protected]

author
#2 lore raw

PATCH 1/4 Modularize the handling of netdev address c/r

This moves the INET4 address checkpoint and restart routines into net/ipv4/devinet.c and introduces a registration method to present the checkpoint code with the handler functions.

This makes it easier to add additional address types, and also makes the cases where inet4 is absent, inet6 is a module, etc much easier. It also elminates the need for a couple of helper functions.

---
 include/linux/checkpoint.h     |   18 +++++-
 include/linux/checkpoint_hdr.h |    1 +
 net/checkpoint_dev.c           |  152 ++++++++++++++++++++++++----------------
 net/ipv4/devinet.c             |   75 ++++++++++++++++++++
 4 files changed, 184 insertions(+), 62 deletions(-)
include/linux/checkpoint.h +17 -1
index 96693e2..5fdbd01 100644
@@ -132,7 +132,8 @@ 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 ckpt_ctx *ctx,
+				  struct net_device *dev,
 				  struct ckpt_netdev_addr *list[]);
 extern int ckpt_netdev_hwaddr(struct net_device *dev,
 			      struct ckpt_hdr_netdev *h);
@@ -513,6 +514,21 @@ extern void _ckpt_msg_complete(struct ckpt_ctx *ctx);
 	_do_ckpt_msg(ctx, err, "[E @ %s:%d]" fmt, __func__, __LINE__, ##args); \
 } while (0)
 
+struct ckpt_netdev_addr_handler {
+	int type;
+	struct module *owner;
+	int (*checkpoint_addr)(struct ckpt_ctx *ctx,
+			       struct net_device *dev,
+			       int index, int max,
+			       struct ckpt_netdev_addr *addrs);
+	int (*restore_addr)(struct ckpt_ctx *ctx,
+			    struct net_device *dev,
+			    struct net *net,
+			    struct ckpt_netdev_addr *addr);
+};
+extern int ckpt_netdev_addr_register(struct ckpt_netdev_addr_handler *);
+extern int ckpt_netdev_addr_unregister(struct ckpt_netdev_addr_handler *);
+
 #endif /* CONFIG_CHECKPOINT */
 #endif /* __KERNEL__ */
 
include/linux/checkpoint_hdr.h +1 -0
index 36386ad..13bf62c 100644
@@ -804,6 +804,7 @@ struct ckpt_hdr_netdev {
 
 enum ckpt_netdev_addr_types {
 	CKPT_NETDEV_ADDR_IPV4,
+	CKPT_NETDEV_ADDR_MAX
 };
 
 struct ckpt_netdev_addr {
net/checkpoint_dev.c +91 -61

207 lines not on this page · raw message

net/ipv4/devinet.c +75 -0

92 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): 1270748932-26745-2-git-send-email-danms-r/[email protected]

#4 lore raw

Re: [PATCH 1/4] Modularize the handling of netdev address c/r

Quoted 82 lines · Dan Smith

This moves the INET4 address checkpoint and restart routines into net/ipv4/devinet.c and introduces a registration method to present the checkpoint code with the handler functions.

This makes it easier to add additional address types, and also makes the cases where inet4 is absent, inet6 is a module, etc much easier. It also elminates the need for a couple of helper functions.

---
 include/linux/checkpoint.h     |   18 +++++-
 include/linux/checkpoint_hdr.h |    1 +
 net/checkpoint_dev.c           |  152 ++++++++++++++++++++++++----------------
 net/ipv4/devinet.c             |   75 ++++++++++++++++++++
 4 files changed, 184 insertions(+), 62 deletions(-)
include/linux/checkpoint.h +17 -1
index 96693e2..5fdbd01 100644
@@ -132,7 +132,8 @@ 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 ckpt_ctx *ctx,
+				  struct net_device *dev,
 				  struct ckpt_netdev_addr *list[]);
 extern int ckpt_netdev_hwaddr(struct net_device *dev,
 			      struct ckpt_hdr_netdev *h);
@@ -513,6 +514,21 @@ extern void _ckpt_msg_complete(struct ckpt_ctx *ctx);
 	_do_ckpt_msg(ctx, err, "[E @ %s:%d]" fmt, __func__, __LINE__, ##args); \
 } while (0)
 
+struct ckpt_netdev_addr_handler {
+	int type;
+	struct module *owner;
+	int (*checkpoint_addr)(struct ckpt_ctx *ctx,
+			       struct net_device *dev,
+			       int index, int max,
+			       struct ckpt_netdev_addr *addrs);
+	int (*restore_addr)(struct ckpt_ctx *ctx,
+			    struct net_device *dev,
+			    struct net *net,
+			    struct ckpt_netdev_addr *addr);
+};
+extern int ckpt_netdev_addr_register(struct ckpt_netdev_addr_handler *);
+extern int ckpt_netdev_addr_unregister(struct ckpt_netdev_addr_handler *);
+
 #endif /* CONFIG_CHECKPOINT */
 #endif /* __KERNEL__ */
 
include/linux/checkpoint_hdr.h +1 -0
index 36386ad..13bf62c 100644
@@ -804,6 +804,7 @@ struct ckpt_hdr_netdev {
 
 enum ckpt_netdev_addr_types {
 	CKPT_NETDEV_ADDR_IPV4,
+	CKPT_NETDEV_ADDR_MAX
 };
 
 struct ckpt_netdev_addr {
net/checkpoint_dev.c +1 -1
index 5a4a95b..4ef06e3 100644
@@ -12,11 +12,11 @@
 #include <linux/sched.h>
 #include <linux/if.h>
 #include <linux/if_arp.h>
-#include <linux/inetdevice.h>
 #include <linux/veth.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 #include <linux/deferqueue.h>
+#include <linux/module.h>
 
 #include <net/net_namespace.h>
 #include <net/sch_generic.h>

net/checkpoint_dev.c struct mvl_newlink { · line 42

Quoted 10 lines
net/checkpoint_dev.c +6 -1
@@ -34,17 +34,64 @@ struct mvl_newlink {
 
 typedef int (*new_link_fn)(struct sk_buff *, void *);
 
-static int __kern_devinet_ioctl(struct net *net, unsigned int cmd, void *arg)
+static struct ckpt_netdev_addr_handler *addr_handlers[CKPT_NETDEV_ADDR_MAX];
+
+static char *addr_modules[] = {
+	"ipv4",		/* CKPT_NETDEV_ADDR_IPV4 */
+	"ipv6",		/* CKPT_NETDEV_ADDR_IPV6 */
+};

Looks good to me, thanks Dan.

Just one comment:

Should ckpt_netdev_addr_types/CKPT_NETDEV_ADDR_MAX somehow be sanity-checked against the size of array?

-serge

#5 lore raw

Re: [PATCH 1/4] Modularize the handling of netdev address c/r

In reply to a message not in the archive

Looks good, thanks. Please see comments below:

Quoted 38 lines · Dan Smith

This moves the INET4 address checkpoint and restart routines into net/ipv4/devinet.c and introduces a registration method to present the checkpoint code with the handler functions.

This makes it easier to add additional address types, and also makes the cases where inet4 is absent, inet6 is a module, etc much easier. It also elminates the need for a couple of helper functions.

---
 include/linux/checkpoint.h     |   18 +++++-
 include/linux/checkpoint_hdr.h |    1 +
 net/checkpoint_dev.c           |  152 ++++++++++++++++++++++++----------------
 net/ipv4/devinet.c             |   75 ++++++++++++++++++++
 4 files changed, 184 insertions(+), 62 deletions(-)
include/linux/checkpoint.h +6 -1
index 96693e2..5fdbd01 100644
@@ -132,7 +132,8 @@ 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 ckpt_ctx *ctx,
+				  struct net_device *dev,
 				  struct ckpt_netdev_addr *list[]);
 extern int ckpt_netdev_hwaddr(struct net_device *dev,
 			      struct ckpt_hdr_netdev *h);
@@ -513,6 +514,21 @@ extern void _ckpt_msg_complete(struct ckpt_ctx *ctx);
 	_do_ckpt_msg(ctx, err, "[E @ %s:%d]" fmt, __func__, __LINE__, ##args); \
 } while (0)
 
+struct ckpt_netdev_addr_handler {
+	int type;
+	struct module *owner;
+	int (*checkpoint_addr)(struct ckpt_ctx *ctx,

include/linux/checkpoint.h extern void _ckpt_msg_complete(struct ckpt_ctx *ctx); · line 530

Quoted 10 lines
include/linux/checkpoint.h +10 -0
+			       struct net_device *dev,
+			       int index, int max,
+			       struct ckpt_netdev_addr *addrs);
+	int (*restore_addr)(struct ckpt_ctx *ctx,
+			    struct net_device *dev,
+			    struct net *net,
+			    struct ckpt_netdev_addr *addr);
+};
+extern int ckpt_netdev_addr_register(struct ckpt_netdev_addr_handler *);
+extern int ckpt_netdev_addr_unregister(struct ckpt_netdev_addr_handler *);

In another context, Matt pointed out that the naming convention should start with "register", so something like:

register_checkpoint_netdev_addr()
unregister_checkpoint_netdev_addr()

Quoted 41 lines
include/linux/checkpoint.h +1 -0
+
 #endif /* CONFIG_CHECKPOINT */
 #endif /* __KERNEL__ */
 
include/linux/checkpoint_hdr.h +1 -0
index 36386ad..13bf62c 100644
@@ -804,6 +804,7 @@ struct ckpt_hdr_netdev {
 
 enum ckpt_netdev_addr_types {
 	CKPT_NETDEV_ADDR_IPV4,
+	CKPT_NETDEV_ADDR_MAX
 };
 
 struct ckpt_netdev_addr {
net/checkpoint_dev.c +4 -2
index 5a4a95b..4ef06e3 100644
@@ -12,11 +12,11 @@
 #include <linux/sched.h>
 #include <linux/if.h>
 #include <linux/if_arp.h>
-#include <linux/inetdevice.h>
 #include <linux/veth.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 #include <linux/deferqueue.h>
+#include <linux/module.h>
 
 #include <net/net_namespace.h>
 #include <net/sch_generic.h>
@@ -34,17 +34,64 @@ struct mvl_newlink {
 
 typedef int (*new_link_fn)(struct sk_buff *, void *);
 
-static int __kern_devinet_ioctl(struct net *net, unsigned int cmd, void *arg)
+static struct ckpt_netdev_addr_handler *addr_handlers[CKPT_NETDEV_ADDR_MAX];
+
+static char *addr_modules[] = {

net/checkpoint_dev.c struct mvl_newlink { · line 47

Quoted 10 lines
net/checkpoint_dev.c +7 -2
+	"ipv4",		/* CKPT_NETDEV_ADDR_IPV4 */
+	"ipv6",		/* CKPT_NETDEV_ADDR_IPV6 */
+};
+
+int ckpt_netdev_addr_register(struct ckpt_netdev_addr_handler *h)
 {
-	mm_segment_t fs;
-	int ret;
+	if (h->type >= CKPT_NETDEV_ADDR_MAX)
+		return -EINVAL;

h->type is 'int' and can be negative :(
Either test for it, or better - change to unsigned int (above).

net/checkpoint_dev.c struct mvl_newlink { · line 50

Quoted 7 lines
net/checkpoint_dev.c +2 -4
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = devinet_ioctl(net, cmd, arg);
-	set_fs(fs);
+	if (addr_handlers[h->type] != NULL)
+		return -EEXIST;

Does this test-and-set need locking ?

Quoted 9 lines
net/checkpoint_dev.c +7 -1
-	return ret;
+	ckpt_debug("Registered addr type %s\n", addr_modules[h->type]);
+	addr_handlers[h->type] = h;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ckpt_netdev_addr_register);
+

net/checkpoint_dev.c struct mvl_newlink { · line 68

Quoted 10 lines
net/checkpoint_dev.c +10 -0
+int ckpt_netdev_addr_unregister(struct ckpt_netdev_addr_handler *h)
+{
+	if (h->type >= CKPT_NETDEV_ADDR_MAX)
+		return -EINVAL;
+
+	if (addr_handlers[h->type] == NULL)
+		return -ESRCH;
+
+	ckpt_debug("Unregistered addr type %s\n", addr_modules[h->type]);
+	addr_handlers[h->type] = NULL;

Ditto ?

net/checkpoint_dev.c struct mvl_newlink { · line 79

Quoted 11 lines
net/checkpoint_dev.c +11 -0
+
+	return 0;
+}
+EXPORT_SYMBOL(ckpt_netdev_addr_unregister);
+
+static struct ckpt_netdev_addr_handler *get_addr_handler(int type)
+{
+	struct ckpt_netdev_addr_handler *h;
+
+	if (type >= CKPT_NETDEV_ADDR_MAX)
+		return ERR_PTR(-EINVAL);

type is 'int' - same comment as above.

net/checkpoint_dev.c struct mvl_newlink { · line 79

Quoted 2 lines
net/checkpoint_dev.c +2 -0
+
+	h = addr_handlers[type];

Ditto for locking ? (try_module_get below should be inside the lock, of course).

net/checkpoint_dev.c struct mvl_newlink { · line 89

Quoted 8 lines
net/checkpoint_dev.c +8 -0
+
+	if (h == NULL)
+		return NULL;
+
+	if (try_module_get(h->owner))
+		return h;
+	else
+		return ERR_PTR(-EBUSY);

Maybe some ckpt_err() here ? I can feel the frustration of trying to figure out where _this_ came from !

net/checkpoint_dev.c struct mvl_newlink { · line 95

Quoted 6 lines
net/checkpoint_dev.c +5 -0
+}
+
+static void put_addr_handler(struct ckpt_netdev_addr_handler *h)
+{
+	module_put(h->owner);
 }

[...]

The rest looks ok :)

Oren.

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#7 lore raw

Re: [PATCH 1/4] Modularize the handling of netdev address c/r

OL> Does this test-and-set need locking ?

No, I was just planning on getting lucky each time. Er, okay, yes :)

Quoted 4 lines

net/checkpoint_dev.c struct mvl_newlink { · line 89

Quoted 4 lines
net/checkpoint_dev.c +4 -0
+	if (try_module_get(h->owner))
+		return h;
+	else
+		return ERR_PTR(-EBUSY);

OL> Maybe some ckpt_err() here ? I can feel the frustration of trying OL> to figure out where _this_ came from !

I'd prefer not to do that this deep. I think the varying depth at which we call ckpt_err() starts to get confusing. Regardless, the call of this function is checked and reported, which I think will make tracking down an error result rather easy:

  h = get_addr_handler(i);
  if (!h)
  	continue;
  else if (IS_ERR(h)) {
  	addrs = PTR_ERR(h);
  	ckpt_err(ctx, addrs,
  		 "Unable to handle netdev addr type %s\n",
  		 addr_modules[i]);
  	break;
  }

no?

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): 874oiyfdv1.fsf-FLMGYpZoEPULwtHQx/[email protected]

#9 lore raw

Re: [PATCH 1/4] Modularize the handling of netdev address c/r

Quoted 12 lines · Dan Smith

OL> Does this test-and-set need locking ?

No, I was just planning on getting lucky each time. Er, okay, yes :)

Quoted 4 lines

net/checkpoint_dev.c struct mvl_newlink { · line 89

Quoted 4 lines
net/checkpoint_dev.c +4 -0
+	if (try_module_get(h->owner))
+		return h;
+	else
+		return ERR_PTR(-EBUSY);

OL> Maybe some ckpt_err() here ? I can feel the frustration of trying OL> to figure out where _this_ came from !

Quoted 2 lines

I'd prefer not to do that this deep. I think the varying depth at which we call ckpt_err() starts to get confusing. Regardless, the

True.

I was just thinking about a user seeing EBUSY and a message about the netdev addr, and how he/she would reason that this is because a module is missing ...

On the other hand, we could keep the scheme you have now, and then document this possibility in a FAQ, readme, manual etc.

Quoted 14 lines

call of this function is checked and reported, which I think will make tracking down an error result rather easy:

  h = get_addr_handler(i);
  if (!h)
  	continue;
  else if (IS_ERR(h)) {
  	addrs = PTR_ERR(h);
  	ckpt_err(ctx, addrs,
  		 "Unable to handle netdev addr type %s\n",
  		 addr_modules[i]);
  	break;
  }
Quoted 1 line

no?

Sure.

Oren.

author
#10 lore raw

PATCH 2/4 Fail checkpoint if IPv4 multicast addresses are configured

In reply to a message not in the archive

This causes checkpoint to fail if an interface actually has a multicast membership.

---
 net/ipv4/devinet.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)
net/ipv4/devinet.c +15 -0
index fa7799c..83411fc 100644
@@ -1624,6 +1624,7 @@ static int devinet_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev,
 {
 	struct in_device *indev = dev->ip_ptr;
 	struct in_ifaddr *addr = indev->ifa_list;
+	struct ip_mc_list *mcaddr;
 
 	for (addr = indev->ifa_list; addr ; addr = addr->ifa_next) {
 		addrs[index].type = CKPT_NETDEV_ADDR_IPV4;
@@ -1636,6 +1637,20 @@ static int devinet_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev,
 			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

A message that is not in the archive (sent off-list or not yet received): 1270748932-26745-3-git-send-email-danms-r/[email protected]

#12 lore raw

Re: [PATCH 2/4] Fail checkpoint if IPv4 multicast addresses are configured

Quoted 25 lines · Dan Smith

This causes checkpoint to fail if an interface actually has a multicast membership.

---
 net/ipv4/devinet.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)
net/ipv4/devinet.c +2 -0
index fa7799c..83411fc 100644
@@ -1624,6 +1624,7 @@ static int devinet_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev,
 {
 	struct in_device *indev = dev->ip_ptr;
 	struct in_ifaddr *addr = indev->ifa_list;
+	struct ip_mc_list *mcaddr;
 
 	for (addr = indev->ifa_list; addr ; addr = addr->ifa_next) {
 		addrs[index].type = CKPT_NETDEV_ADDR_IPV4;
@@ -1636,6 +1637,20 @@ static int devinet_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev,
 			return -E2BIG;
 	}
 
+	for (mcaddr = indev->mc_list; mcaddr; mcaddr = mcaddr->next) {

net/ipv4/devinet.c static int devinet_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev, · line 1650

Quoted 10 lines
net/ipv4/devinet.c +10 -0
+		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");

Could you use a ckpt_err() here? This ultimately will be the most informative reason for the failed checkpoint...

Quoted 8 lines
net/ipv4/devinet.c +3 -0
+		return -EINVAL;
+	}
+
 	return index;
 }
 
Signature · 1 line
1.6.2.5
author
#13 lore raw

PATCH 3/4 Add IPv6 address checkpoint handler

In reply to a message not in the archive
---
 include/linux/checkpoint_hdr.h |    8 +++
 net/ipv6/addrconf.c            |   95 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 0 deletions(-)
include/linux/checkpoint_hdr.h +8 -0
index 13bf62c..98aa79c 100644
@@ -804,6 +804,7 @@ struct ckpt_hdr_netdev {
 
 enum ckpt_netdev_addr_types {
 	CKPT_NETDEV_ADDR_IPV4,
+	CKPT_NETDEV_ADDR_IPV6,
 	CKPT_NETDEV_ADDR_MAX
 };
 
@@ -816,6 +817,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/ipv6/addrconf.c +95 -0

119 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): 1270748932-26745-4-git-send-email-danms-r/[email protected]

#15 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

Quoted 46 lines · Dan Smith
---
 include/linux/checkpoint_hdr.h |    8 +++
 net/ipv6/addrconf.c            |   95 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 0 deletions(-)
include/linux/checkpoint_hdr.h +8 -0
index 13bf62c..98aa79c 100644
@@ -804,6 +804,7 @@ struct ckpt_hdr_netdev {
 
 enum ckpt_netdev_addr_types {
 	CKPT_NETDEV_ADDR_IPV4,
+	CKPT_NETDEV_ADDR_IPV6,
 	CKPT_NETDEV_ADDR_MAX
 };
 
@@ -816,6 +817,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/ipv6/addrconf.c +2 -0
index 143791d..75cc3b8 100644
@@ -87,6 +87,8 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <linux/checkpoint.h>
+
 /* Set to 3 to get tracing... */
 #define ACONF_DEBUG 2
 

net/ipv6/addrconf.c int unregister_inet6addr_notifier(struct notifier_block *nb) · line 4519

Quoted 4 lines
net/ipv6/addrconf.c +1 -0
@@ -4514,6 +4516,91 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
 
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
 
+#ifdef CONFIG_NETNS_CHECKPOING

How could that be defined? :)

Quoted 28 lines
net/ipv6/addrconf.c +28 -0
+static int inet6_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev,
+			    int index, int max,
+			    struct ckpt_netdev_addr *addrs)
+{
+	struct inet6_dev *indev = dev->ip6_ptr;
+	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 */
+
+		addrs[index].type = CKPT_NETDEV_ADDR_IPV6;
+
+		ipv6_addr_copy(&addrs[index].inet6_addr, &addr->addr);
+
+		ckpt_debug("Checkpointed inet6: %pI6\n", &addr->addr);
+
+		addrs[index].inet6_prefix_len = addr->prefix_len;
+		addrs[index].inet6_valid_lft = addr->valid_lft;
+		addrs[index].inet6_prefered_lft = addr->prefered_lft;
+		addrs[index].inet6_scope = addr->scope;
+
+		if (++index >= max)
+			return -E2BIG;
+	}
+

net/ipv6/addrconf.c int unregister_inet6addr_notifier(struct notifier_block *nb) · line 4557

Quoted 10 lines
net/ipv6/addrconf.c +10 -0
+	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");

Again, I'd prefer ckpt_err here.

Note that in my last email that really was a q - if you're under spinlock here, then you can't use ckpt_err().

net/ipv6/addrconf.c int unregister_inet6addr_notifier(struct notifier_block *nb) · line 4570

Quoted 13 lines
net/ipv6/addrconf.c +13 -0
+		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");

and here

Quoted 60 lines
net/ipv6/addrconf.c +41 -0
+		return -EINVAL;
+	}
+
+	return index;
+}
+
+static int inet6_restore(struct ckpt_ctx *ctx,
+			 struct net_device *dev,
+			 struct net *net,
+			 struct ckpt_netdev_addr *addr)
+{
+	int ret;
+
+	rtnl_lock();
+	ret = inet6_addr_add(net, dev->ifindex, &addr->inet6_addr,
+			     addr->inet6_prefix_len, IFA_F_PERMANENT,
+			     INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+	rtnl_unlock();
+	if (ret < 0)
+		ckpt_err(ctx, ret, "Failed to set address %pI6\n",
+			 &addr->inet6_addr);
+
+	return ret;
+}
+
+struct ckpt_netdev_addr_handler inet6_addr_handler = {
+	.type =			CKPT_NETDEV_ADDR_IPV6,
+	.owner =		THIS_MODULE,
+	.checkpoint_addr =	inet6_checkpoint,
+	.restore_addr =		inet6_restore,
+};
+#endif /* CONFIG_NETNS_CHECKPOINT */
+
 /*
  *	Init / cleanup code
  */
@@ -4572,6 +4659,10 @@ int __init addrconf_init(void)
 
 	ipv6_addr_label_rtnl_register();
 
+#ifdef CONFIG_NETNS_CHECKPOINT
+	ckpt_netdev_addr_register(&inet6_addr_handler);
+#endif
+
 	return 0;
 errout:
 	unregister_netdevice_notifier(&ipv6_dev_notf);
@@ -4590,6 +4681,10 @@ void addrconf_cleanup(void)
 	unregister_netdevice_notifier(&ipv6_dev_notf);
 	unregister_pernet_subsys(&addrconf_ops);
 
+#ifdef CONFIG_NETNS_CHECKPOINT
+	ckpt_netdev_addr_unregister(&inet6_addr_handler);
+#endif
+
 	rtnl_lock();
 
 	/* clean dev list */
Signature · 1 line
1.6.2.5

A message that is not in the archive (sent off-list or not yet received): 20100412161148.GC23380-r/[email protected]

author
#17 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

Quoted 1 line
Quoted 1 line

+#ifdef CONFIG_NETNS_CHECKPOING

SH> How could that be defined? :)

Hmm, I must have typo'd that after I did all my config testing because otherwise I wouldn't have been able to test checkpointing ipv6 stuff.

SH> Again, I'd prefer ckpt_err here.

SH> Note that in my last email that really was a q - if you're under SH> spinlock here, then you can't use ckpt_err().

Right, the point of this loop was to iterate the list quickly while holding the device lock, so we could write out the results after we release it.

I think these two cases (and the ipv4 case) are pretty unlikely to be a problem as they would only be triggered if you actually have active multicast or anycast sessions configured. This will not trigger for the default addresses.

I don't think that dropping the lock to do ckpt_err() would be very pretty, nor would introducing a result string for an error message. This is plumbed a couple levels deep.

Is there some way you see this being handled better?

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): 871vekbmen.fsf-FLMGYpZoEPULwtHQx/[email protected]

#19 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

Quoted 16 lines · Dan Smith
Quoted 1 line
Quoted 1 line

+#ifdef CONFIG_NETNS_CHECKPOING

SH> How could that be defined? :)

Hmm, I must have typo'd that after I did all my config testing because otherwise I wouldn't have been able to test checkpointing ipv6 stuff.

SH> Again, I'd prefer ckpt_err here.

SH> Note that in my last email that really was a q - if you're under SH> spinlock here, then you can't use ckpt_err().

Right, the point of this loop was to iterate the list quickly while holding the device lock, so we could write out the results after we release it.

Quoted 7 lines

I think these two cases (and the ipv4 case) are pretty unlikely to be a problem as they would only be triggered if you actually have active multicast or anycast sessions configured. This will not trigger for the default addresses.

I don't think that dropping the lock to do ckpt_err() would be very pretty, nor would introducing a result string for an error message.

Agreed.

Quoted 3 lines

This is plumbed a couple levels deep.

Is there some way you see this being handled better?

Not really... looks like we're doing what we can at the moment then, good enough :)

thanks,
-serge

author
#20 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

SH> Not really... looks like we're doing what we can at the moment SH> then, good enough :)

Okay, well, I've got the ifdef issue fixed locally. I'll wait to resend until Brian and Oren have a little more time to review the set.

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): 20100412174756.GA15269-r/[email protected]

#22 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

Quoted 24 lines · Serge E. Hallyn
Quoted 15 lines · Dan Smith
Quoted 1 line
Quoted 1 line

+#ifdef CONFIG_NETNS_CHECKPOING

SH> How could that be defined? :)

Hmm, I must have typo'd that after I did all my config testing because otherwise I wouldn't have been able to test checkpointing ipv6 stuff.

SH> Again, I'd prefer ckpt_err here.

SH> Note that in my last email that really was a q - if you're under SH> spinlock here, then you can't use ckpt_err().

Right, the point of this loop was to iterate the list quickly while holding the device lock, so we could write out the results after we release it.

Quoted 7 lines

I think these two cases (and the ipv4 case) are pretty unlikely to be a problem as they would only be triggered if you actually have active multicast or anycast sessions configured. This will not trigger for the default addresses.

I don't think that dropping the lock to do ckpt_err() would be very pretty, nor would introducing a result string for an error message.

Quoted 8 lines

Agreed.

Quoted 3 lines

This is plumbed a couple levels deep.

Is there some way you see this being handled better?

Not really... looks like we're doing what we can at the moment then, good enough :)

Actually, you can use _ckpt_err() which can be called under spinlock, and then the caller should call _ckpt_msg_complete() after it drops the lock, to flush the message out.

Oren.

#23 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

In reply to a message not in the archive

net/ipv6/addrconf.c int unregister_inet6addr_notifier(struct notifier_block *nb) · line 4588

Quoted 12 lines · Dan Smith
net/ipv6/addrconf.c +12 -0
+static int inet6_restore(struct ckpt_ctx *ctx,
+			 struct net_device *dev,
+			 struct net *net,
+			 struct ckpt_netdev_addr *addr)
+{
+	int ret;
+
+	rtnl_lock();
+	ret = inet6_addr_add(net, dev->ifindex, &addr->inet6_addr,
+			     addr->inet6_prefix_len, IFA_F_PERMANENT,
+			     INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+	rtnl_unlock();

Is using IFA_F_PERMANENT correct here? Should you save the flags from the address when checkpointing? Permanent means it was added by the user, not by the kernel, so you could be changing things slightly.

-Brian

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#25 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

BH> Is using IFA_F_PERMANENT correct here? Should you save the flags BH> from the address when checkpointing? Permanent means it was added BH> by the user, not by the kernel, so you could be changing things BH> slightly.

Does the kernel create global scope addresses? Maybe it does in some more advanced IPv6 environments, but it seemed like excluding global scope addresses in checkpoint meant that we only saved (and thus restore) the permanent ones anyway.

I guess it's a better idea to just save the flags anyhow now that I have a way to restore them.

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): 87vdbs1oty.fsf-FLMGYpZoEPULwtHQx/[email protected]

#27 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

Quoted 9 lines · Dan Smith

BH> Is using IFA_F_PERMANENT correct here? Should you save the flags BH> from the address when checkpointing? Permanent means it was added BH> by the user, not by the kernel, so you could be changing things BH> slightly.

Does the kernel create global scope addresses? Maybe it does in some more advanced IPv6 environments, but it seemed like excluding global scope addresses in checkpoint meant that we only saved (and thus restore) the permanent ones anyway.

It adds global-scope addresses through the auto-configuration process, i.e. by receiving a prefix in a router advertisement.

Quoted 2 lines

I guess it's a better idea to just save the flags anyhow now that I have a way to restore them.

Yes, and I just realized something else. This code:

+ ret = inet6_addr_add(net, dev->ifindex, &addr->inet6_addr,
+ addr->inet6_prefix_len, IFA_F_PERMANENT,
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);

isn't using the saved lifetimes either, so it won't ever go away.

And calling inet6_addr_add() isn't correct in all cases - you can use it for manually-configured addresses (marked permanent), but not for those added through address-autoconfiguration - for those you'll want to use ipv6_add_addr(). But if you do that you'll need to duplicate what's done after the add succeeds:

	ifp = ipv6_add_addr(idev, pfx, plen, addr_scope, addr_flags);

        if (!IS_ERR(ifp)) {
                spin_lock_bh(&ifp->lock);
                ifp->valid_lft = valid_lft;
                ifp->prefered_lft = prefered_lft;
                ifp->tstamp = jiffies;
                spin_unlock_bh(&ifp->lock);

                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
                                      expires, flags);
                /*
                 * Note that section 3.1 of RFC 4429 indicates
                 * that the Optimistic flag should not be set for
                 * manually configured addresses
                 */
                addrconf_dad_start(ifp, 0);
                in6_ifa_put(ifp);
                addrconf_verify(0);
                return 0;
        }

That's just an example, not exactly correct.

-Brian

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#29 lore raw

Re: [PATCH 3/4] Add IPv6 address checkpoint handler

BH> Yes, and I just realized something else. This code:

BH> + ret = inet6_addr_add(net, dev->ifindex, &addr->inet6_addr,
BH> + addr->inet6_prefix_len, IFA_F_PERMANENT,
BH> + INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);

BH> isn't using the saved lifetimes either, so it won't ever go away.

I again have to plead ignorance here. Do permanent addresses ever have anything other than INFINITY_LIFE_TIME? Assuming not, I think it's reasonable (for now, at least) to stick to (correctly) saving and restoring the permanent addresses. What do you think?

Signature · 3 lines
Dan Smith
IBM Linux Technology Center
email: danms-r/[email protected]
author
#30 lore raw

PATCH 4/4 C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag (v2)

In reply to a message not in the archive

The 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.

Changes in v2:
- Export the inet_* symbols used by inet6 so that CONFIG_IPV6=m will compile

---
 include/linux/checkpoint_hdr.h |   13 +++++++++++--
 net/ipv4/checkpoint.c          |   37 +++++++++++++++++++++++--------------
 net/ipv6/af_inet6.c            |    2 ++
 3 files changed, 36 insertions(+), 16 deletions(-)
include/linux/checkpoint_hdr.h +11 -2
index 98aa79c..7fde6b5 100644
@@ -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 +23 -14
index b4024e7..1c43570 100644
@@ -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;
 
@@ -296,11 +299,13 @@ 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)
 {
 	return ckpt_obj_collect(ctx, sock->sk, CKPT_OBJ_SOCK);
 }
+EXPORT_SYMBOL_GPL(inet_collect);
 
 static int inet_read_buffer(struct ckpt_ctx *ctx,
 			    struct sk_buff_head *queue,
@@ -387,19 +392,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;
 	}
@@ -496,11 +501,14 @@ int inet_restore(struct ckpt_ctx *ctx,
 	 */
 	if ((h->sock.state == TCP_LISTEN) ||
 	    ((h->sock.state == TCP_CLOSE) && (in->laddr_len > 0))) {
+		if (in->inet6.ipv6only) {
+			struct ipv6_pinfo *np = inet6_sk(sock->sk);
+			np->ipv6only = 1;
+		}
+
 		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;
@@ -547,3 +555,4 @@ int inet_restore(struct ckpt_ctx *ctx,
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(inet_restore);
net/ipv6/af_inet6.c +2 -0
index 12e69d3..9acb55a 100644
@@ -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): 1270748932-26745-5-git-send-email-danms-r/[email protected]

#32 lore raw

Re: [PATCH 4/4] C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag (v2)

Hi Dan,

Quoted 91 lines · Dan Smith

The 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.

Changes in v2:
- Export the inet_* symbols used by inet6 so that CONFIG_IPV6=m will compile

---
 include/linux/checkpoint_hdr.h |   13 +++++++++++--
 net/ipv4/checkpoint.c          |   37 +++++++++++++++++++++++--------------
 net/ipv6/af_inet6.c            |    2 ++
 3 files changed, 36 insertions(+), 16 deletions(-)
include/linux/checkpoint_hdr.h +11 -2
index 98aa79c..7fde6b5 100644
@@ -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 +10 -7
index b4024e7..1c43570 100644
@@ -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;
 

net/ipv4/checkpoint.c int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock) · line 302

Quoted 4 lines
net/ipv4/checkpoint.c +1 -0
@@ -296,11 +299,13 @@ int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(inet_checkpoint);

This belongs to a separate patch ? Especially for as long as we need to keep our patchset clean, until it makes it to -mm

net/ipv4/checkpoint.c int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock) · line 308

Quoted 6 lines
net/ipv4/checkpoint.c +1 -0
 int inet_collect(struct ckpt_ctx *ctx, struct socket *sock)
 {
 	return ckpt_obj_collect(ctx, sock->sk, CKPT_OBJ_SOCK);
 }
+EXPORT_SYMBOL_GPL(inet_collect);

Ditto.

Quoted 46 lines
net/ipv4/checkpoint.c +10 -7
 static int inet_read_buffer(struct ckpt_ctx *ctx,
 			    struct sk_buff_head *queue,
@@ -387,19 +392,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;
 	}
@@ -496,11 +501,14 @@ int inet_restore(struct ckpt_ctx *ctx,
 	 */
 	if ((h->sock.state == TCP_LISTEN) ||
 	    ((h->sock.state == TCP_CLOSE) && (in->laddr_len > 0))) {
+		if (in->inet6.ipv6only) {
+			struct ipv6_pinfo *np = inet6_sk(sock->sk);
+			np->ipv6only = 1;
+		}
+
 		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;

net/ipv4/checkpoint.c int inet_restore(struct ckpt_ctx *ctx, · line 558

Quoted 4 lines
net/ipv4/checkpoint.c +1 -0
@@ -547,3 +555,4 @@ int inet_restore(struct ckpt_ctx *ctx,
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(inet_restore);

Ditto.

net/ipv6/af_inet6.c const struct proto_ops inet6_stream_ops = { · line 530

Quoted 13 lines
net/ipv6/af_inet6.c +2 -0
index 12e69d3..9acb55a 100644
@@ -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,

Oren.

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#34 lore raw

Re: [PATCH 4/4] C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag (v2)

Quoted 1 line
Quoted 1 line

+EXPORT_SYMBOL_GPL(inet_checkpoint);

OL> This belongs to a separate patch ? Especially for as long as we OL> need to keep our patchset clean, until it makes it to -mm

Does it? It's just exporting a symbol that is already in the tree so we can use it. Are you saying you just want the export to be done in its own patch?

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): 87d3xmfhzx.fsf-FLMGYpZoEPULwtHQx/[email protected]

#36 lore raw

Re: [PATCH 4/4] C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag (v2)

Quoted 9 lines · Dan Smith
Quoted 1 line
Quoted 1 line

+EXPORT_SYMBOL_GPL(inet_checkpoint);

OL> This belongs to a separate patch ? Especially for as long as we OL> need to keep our patchset clean, until it makes it to -mm

Does it? It's just exporting a symbol that is already in the tree so we can use it. Are you saying you just want the export to be done in its own patch?

I guess I was too quick on the trigger. If you have other future users for inet_checkpoint and co., then yes, a separate patch - since I would fold it into the original inet patches (assuming we are not yet in -mm).

Oren.

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#38 lore raw

Re: [PATCH 4/4] C/R: Fix storing IPv6 addresses and handle the "ipv6only" socket flag (v2)

OL> I guess I was too quick on the trigger. If you have other future OL> users for inet_checkpoint and co., then yes, a separate patch - OL> since I would fold it into the original inet patches (assuming we OL> are not yet in -mm).

I don't think that there will be any additional users besides inet4 and inet6, so I'm still not sure what the issue is. Regardless, I'll break that out into a separate patch for you when I re-post that set.

Thanks!

Signature · 3 lines
Dan Smith
IBM Linux Technology Center
email: danms-r/[email protected]