diff --git a/Makefile b/Makefile index cada041d7..2fcedd045 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ OBJS += sockets.o OBJS += sk-inet.o OBJS += sk-tcp.o OBJS += sk-unix.o +OBJS += sk-packet.o OBJS += sk-queue.o OBJS += files.o OBJS += files-reg.o diff --git a/cr-restore.c b/cr-restore.c index ba49f6b7e..b5c2a054e 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -32,6 +32,7 @@ #include "syscall.h" #include "restorer.h" #include "sockets.h" +#include "sk-packet.h" #include "lock.h" #include "files.h" #include "files-reg.h" @@ -102,6 +103,9 @@ static int prepare_shared(void) if (collect_unix_sockets()) return -1; + if (collect_packet_sockets()) + return -1; + if (collect_eventfd()) return -1; diff --git a/image.c b/image.c index 91f440f93..dcbb6ddcf 100644 --- a/image.c +++ b/image.c @@ -9,6 +9,7 @@ #include "uts_ns.h" #include "ipc_ns.h" #include "sk-inet.h" +#include "sk-packet.h" #include "mount.h" #include "net.h" #include "protobuf.h" @@ -107,6 +108,7 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = { FD_ENTRY(SIGACT, "sigacts-%d", show_sigacts), FD_ENTRY(UNIXSK, "unixsk", show_unixsk), FD_ENTRY(INETSK, "inetsk", show_inetsk), + FD_ENTRY(PACKETSK, "packetsk", show_packetsk), FD_ENTRY(SK_QUEUES, "sk-queues", show_sk_queues), FD_ENTRY(ITIMERS, "itimers-%d", show_itimers), FD_ENTRY(CREDS, "creds-%d", show_creds), diff --git a/include/crtools.h b/include/crtools.h index 63758b270..b45d4152c 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -61,6 +61,7 @@ enum { CR_FD_REG_FILES, CR_FD_INETSK, CR_FD_UNIXSK, + CR_FD_PACKETSK, CR_FD_PIPES, CR_FD_PIPES_DATA, CR_FD_FIFO, diff --git a/include/image.h b/include/image.h index 345edc553..97201219c 100644 --- a/include/image.h +++ b/include/image.h @@ -36,6 +36,7 @@ #define SIGACT_MAGIC 0x55344201 /* Murom */ #define UNIXSK_MAGIC 0x54373943 /* Ryazan */ #define INETSK_MAGIC 0x56443851 /* Pereslavl */ +#define PACKETSK_MAGIC 0x60454618 /* Veliky Ustyug */ #define ITIMERS_MAGIC 0x57464056 /* Kostroma */ #define SK_QUEUES_MAGIC 0x56264026 /* Suzdal */ #define UTSNS_MAGIC 0x54473203 /* Smolensk */ diff --git a/include/protobuf.h b/include/protobuf.h index 6120eedd0..fca883e09 100644 --- a/include/protobuf.h +++ b/include/protobuf.h @@ -30,6 +30,7 @@ enum { PB_REG_FILES, PB_INETSK, PB_UNIXSK, + PB_PACKETSK, PB_PIPES, PB_FIFO, PB_PIPES_DATA, diff --git a/include/sk-packet.h b/include/sk-packet.h new file mode 100644 index 000000000..a73c6bb47 --- /dev/null +++ b/include/sk-packet.h @@ -0,0 +1,10 @@ +#ifndef __CR_SK_PACKET_H__ +#define __CR_SK_PACKET_H__ +struct cr_fdset; +struct fd_parms; +struct cr_options; + +int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds); +int collect_packet_sockets(void); +void show_packetsk(int fd, struct cr_options *); +#endif diff --git a/include/sockets.h b/include/sockets.h index 8637587bc..228d47243 100644 --- a/include/sockets.h +++ b/include/sockets.h @@ -56,5 +56,6 @@ extern int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto) extern int unix_receive_one(struct nlmsghdr *h, void *); extern int do_dump_opt(int sk, int name, void *val, int len); +#define dump_opt(s, n, f) do_dump_opt(s, n, f, sizeof(*f)) #endif /* CR_SOCKETS_H__ */ diff --git a/protobuf.c b/protobuf.c index 023f22839..ca34a2b01 100644 --- a/protobuf.c +++ b/protobuf.c @@ -29,6 +29,7 @@ #include "protobuf/sa.pb-c.h" #include "protobuf/sk-unix.pb-c.h" #include "protobuf/sk-inet.pb-c.h" +#include "protobuf/packet-sock.pb-c.h" #include "protobuf/sk-packet.pb-c.h" #include "protobuf/creds.pb-c.h" #include "protobuf/itimer.pb-c.h" @@ -116,6 +117,7 @@ void cr_pb_init(void) CR_PB_DESC(TCP_STREAM, TcpStream, tcp_stream); CR_PB_DESC(MOUNTPOINTS, Mnt, mnt); CR_PB_DESC(NETDEV, NetDevice, net_device); + CR_PB_DESC(PACKETSK, PacketSock, packet_sock); } /* diff --git a/protobuf/Makefile b/protobuf/Makefile index 178fd2e45..901fbf848 100644 --- a/protobuf/Makefile +++ b/protobuf/Makefile @@ -44,6 +44,7 @@ PROTO_FILES += mm.proto PROTO_FILES += sk-opts.proto PROTO_FILES += sk-unix.proto PROTO_FILES += sk-inet.proto +PROTO_FILES += packet-sock.proto PROTO_FILES += ipc-var.proto PROTO_FILES += ipc-desc.proto PROTO_FILES += ipc-shm.proto diff --git a/protobuf/fdinfo.proto b/protobuf/fdinfo.proto index 057b3ff89..5ad78de38 100644 --- a/protobuf/fdinfo.proto +++ b/protobuf/fdinfo.proto @@ -9,6 +9,7 @@ enum fd_types { EVENTPOLL = 7; INOTIFY = 8; SIGNALFD = 9; + PACKETSK = 10; } message fdinfo_entry { diff --git a/protobuf/packet-sock.proto b/protobuf/packet-sock.proto new file mode 100644 index 000000000..bb079fb14 --- /dev/null +++ b/protobuf/packet-sock.proto @@ -0,0 +1,13 @@ +import "fown.proto"; +import "sk-opts.proto"; + +message packet_sock_entry { + required uint32 id = 1; + required uint32 type = 2; + required uint32 protocol = 3; + required uint32 flags = 4; + required uint32 ifindex = 5; + + required fown_entry fown = 6; + required sk_opts_entry opts = 7; +} diff --git a/sk-packet.c b/sk-packet.c new file mode 100644 index 000000000..b2ea8555f --- /dev/null +++ b/sk-packet.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include "crtools.h" +#include "types.h" +#include "files.h" +#include "sockets.h" +#include "sk-packet.h" + +#include "protobuf.h" +#include "protobuf/packet-sock.pb-c.h" +#include "protobuf/fdinfo.pb-c.h" + +struct packet_sock_info { + PacketSockEntry *pse; + struct file_desc d; +}; + +void show_packetsk(int fd, struct cr_options *o) +{ + pb_show_plain(fd, PB_PACKETSK); +} + +static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) +{ + int type; + PacketSockEntry psk = PACKET_SOCK_ENTRY__INIT; + SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; + struct sockaddr_ll addr; + socklen_t alen; + + pr_info("Dumping packet socket fd %d id %#x\n", lfd, id); + + if (dump_opt(lfd, SO_TYPE, &type)) + return -1; + + psk.id = id; + psk.type = type; + psk.flags = p->flags; + psk.fown = (FownEntry *)&p->fown; + psk.opts = &skopts; + + if (dump_socket_opts(lfd, &skopts)) + return -1; + + alen = sizeof(addr); + if (getsockname(lfd, (struct sockaddr *)&addr, &alen) < 0) { + pr_perror("Can't get packet sock name"); + return -1; + } + + psk.protocol = addr.sll_protocol; + psk.ifindex = addr.sll_ifindex; + + return pb_write_one(fdset_fd(glob_fdset, CR_FD_PACKETSK), &psk, PB_PACKETSK); +} + +static const struct fdtype_ops packet_dump_ops = { + .type = FD_TYPES__PACKETSK, + .make_gen_id = make_gen_id, + .dump = dump_one_packet_fd, +}; + +int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds) +{ + return do_dump_gen_file(p, lfd, &packet_dump_ops, fds); +} + +static int open_packet_sk(struct file_desc *d) +{ + struct packet_sock_info *psi; + PacketSockEntry *pse; + struct sockaddr_ll addr; + int sk; + + psi = container_of(d, struct packet_sock_info, d); + pse = psi->pse; + + pr_info("Opening packet socket id %#x\n", pse->id); + + sk = socket(PF_PACKET, pse->type, pse->protocol); + if (sk < 0) { + pr_perror("Can't create packet sock"); + goto err; + } + + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = pse->ifindex; + + if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + pr_perror("Can't bind packet socket"); + goto err_cl; + } + + if (rst_file_params(sk, pse->fown, pse->flags)) + goto err_cl; + + if (restore_socket_opts(sk, pse->opts)) + goto err_cl; + + return sk; + +err_cl: + close(sk); +err: + return -1; +} + +static struct file_desc_ops packet_sock_desc_ops = { + .type = FD_TYPES__PACKETSK, + .open = open_packet_sk, +}; + +static int collect_one_packet_sk(void *o, ProtobufCMessage *base) +{ + struct packet_sock_info *si = o; + + si->pse = pb_msg(base, PacketSockEntry); + file_desc_add(&si->d, si->pse->id, &packet_sock_desc_ops); + + return 0; +} + +int collect_packet_sockets(void) +{ + return collect_image(CR_FD_PACKETSK, PB_PACKETSK, + sizeof(struct packet_sock_info), collect_one_packet_sk); +} diff --git a/sockets.c b/sockets.c index e45cc5351..33a152ca1 100644 --- a/sockets.c +++ b/sockets.c @@ -9,6 +9,7 @@ #include "inet_diag.h" #include "files.h" #include "util-net.h" +#include "sk-packet.h" #ifndef NETLINK_SOCK_DIAG #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG @@ -99,8 +100,6 @@ int do_dump_opt(int sk, int name, void *val, int len) return 0; } -#define dump_opt(s, n, f) do_dump_opt(s, n, f, sizeof(*f)) - int dump_socket_opts(int sk, SkOptsEntry *soe) { int ret = 0; @@ -133,6 +132,8 @@ int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset) case AF_INET: case AF_INET6: return dump_one_inet(p, lfd, cr_fdset); + case AF_PACKET: + return dump_one_packet_sk(p, lfd, cr_fdset); default: pr_err("BUG! Unknown socket collected\n"); break;