mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 01:51:51 +00:00
inet: remember ipv6 connections' ifindex for restore
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@canonical.com> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
c1b1880b34
commit
7209c4ec28
@ -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;
|
||||
}
|
||||
|
42
sk-inet.c
42
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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user