[CRIU] [PATCH v2 2/3] inet: remember ipv6 connections' ifindex for restore
Tycho Andersen
tycho.andersen at canonical.com
Tue Nov 24 13:28:17 PST 2015
For some ipv6 scope types (link local, amongo others), we need to tell the
kernel the ifindex of the interface whose address we want to bind to as
well as the address itself.
v2: use SO_BINDTODEVICE to get the ifname, and pass that through instead of
using netlink to grab all the ipv6 sockets via rtnetlink.
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
protobuf/sk-inet.proto | 4 ++++
sk-inet.c | 42 +++++++++++++++++++++++++++++++++++++-----
2 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/protobuf/sk-inet.proto b/protobuf/sk-inet.proto
index ad49928..a2770df 100644
--- a/protobuf/sk-inet.proto
+++ b/protobuf/sk-inet.proto
@@ -33,4 +33,8 @@ message inet_sk_entry {
required sk_opts_entry opts = 14;
optional bool v6only = 15;
optional ip_opts_entry ip_opts = 16;
+
+ /* for ipv6, we need to send the ifindex to bind(); we keep the ifname
+ * here and convert it on restore */
+ optional string ifname = 17;
}
diff --git a/sk-inet.c b/sk-inet.c
index e08b2be..53e568c 100644
--- a/sk-inet.c
+++ b/sk-inet.c
@@ -2,6 +2,7 @@
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <net/if.h>
#include <sys/mman.h>
#include <unistd.h>
#include <netinet/tcp.h>
@@ -288,6 +289,8 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
ie.n_dst_addr = PB_ALEN_INET;
if (ie.family == AF_INET6) {
int val;
+ char device[IFNAMSIZ];
+ socklen_t len = sizeof(device);
ie.n_src_addr = PB_ALEN_INET6;
ie.n_dst_addr = PB_ALEN_INET6;
@@ -298,6 +301,21 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
ie.v6only = val ? true : false;
ie.has_v6only = true;
+
+ /* ifindex only matters on source ports for bind, so let's
+ * find only that ifindex. */
+ if (getsockopt(lfd, SOL_SOCKET, SO_BINDTODEVICE, device, &len) < 0) {
+ pr_perror("can't get ifname");
+ goto err;
+ }
+
+ if (len > 0) {
+ ie.ifname = xstrdup(device);
+ if (!ie.ifname)
+ goto err;
+ } else {
+ pr_warn("couldn't find ifname for %d, can't bind\n", id);
+ }
}
ie.src_addr = xmalloc(pb_repeated_size(&ie, src_addr));
@@ -607,7 +625,7 @@ union sockaddr_inet {
};
static int restore_sockaddr(union sockaddr_inet *sa,
- int family, u32 pb_port, u32 *pb_addr)
+ int family, u32 pb_port, u32 *pb_addr, u32 ifindex)
{
BUILD_BUG_ON(sizeof(sa->v4.sin_addr.s_addr) > PB_ALEN_INET * sizeof(u32));
BUILD_BUG_ON(sizeof(sa->v6.sin6_addr.s6_addr) > PB_ALEN_INET6 * sizeof(u32));
@@ -625,6 +643,12 @@ static int restore_sockaddr(union sockaddr_inet *sa,
sa->v6.sin6_family = AF_INET6;
sa->v6.sin6_port = htons(pb_port);
memcpy(sa->v6.sin6_addr.s6_addr, pb_addr, sizeof(sa->v6.sin6_addr.s6_addr));
+
+ /* Here although the struct member is called scope_id, the
+ * kernel really wants ifindex. See
+ * /net/ipv6/af_inet6.c:inet6_bind for details.
+ */
+ sa->v6.sin6_scope_id = ifindex;
return sizeof(sa->v6);
}
@@ -636,10 +660,18 @@ int inet_bind(int sk, struct inet_sk_info *ii)
{
bool rst_freebind = false;
union sockaddr_inet addr;
- int addr_size;
+ int addr_size, ifindex = 0;
+
+ if (ii->ie->ifname) {
+ ifindex = if_nametoindex(ii->ie->ifname);
+ if (!ifindex) {
+ pr_err("couldn't find ifindex for %s\n", ii->ie->ifname);
+ return -1;
+ }
+ }
addr_size = restore_sockaddr(&addr, ii->ie->family,
- ii->ie->src_port, ii->ie->src_addr);
+ ii->ie->src_port, ii->ie->src_addr, ifindex);
/*
* ipv6 addresses go through a “tentative” phase and
@@ -663,7 +695,7 @@ int inet_bind(int sk, struct inet_sk_info *ii)
}
if (bind(sk, (struct sockaddr *)&addr, addr_size) == -1) {
- pr_perror("Can't bind inet socket");
+ pr_perror("Can't bind inet socket (id %d)", ii->ie->id);
return -1;
}
@@ -687,7 +719,7 @@ int inet_connect(int sk, struct inet_sk_info *ii)
int addr_size;
addr_size = restore_sockaddr(&addr, ii->ie->family,
- ii->ie->dst_port, ii->ie->dst_addr);
+ ii->ie->dst_port, ii->ie->dst_addr, 0);
if (connect(sk, (struct sockaddr *)&addr, addr_size) == -1) {
pr_perror("Can't connect inet socket back");
--
2.6.2
More information about the CRIU
mailing list