[CRIU] [PATCH 6/8] sockets: dump netlink sockets

Andrey Vagin avagin at openvz.org
Mon Mar 25 11:28:47 EDT 2013


All info about bound sockets are got via socket diag interface.
All connected sockets are automatically bound.
For other sockets only protocol must be dumped, which is got
with help getsockopt.

A netlink sockets with pending data are not supported yet and
probably will not be supported in a near future.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/sockets.h     |  1 +
 protobuf/fdinfo.proto |  1 +
 sk-netlink.c          | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sockets.c             |  2 ++
 4 files changed, 97 insertions(+)

diff --git a/include/sockets.h b/include/sockets.h
index 42509dc..02b0584 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -54,6 +54,7 @@ extern struct socket_desc *lookup_socket(int ino, int family);
 extern int dump_one_inet(struct fd_parms *p, int lfd, const int fdinfo);
 extern int dump_one_inet6(struct fd_parms *p, int lfd, const int fdinfo);
 extern int dump_one_unix(struct fd_parms *p, int lfd, const int fdinfo);
+extern int dump_one_netlink(struct fd_parms *p, int lfd, const int fdinfo);
 
 extern int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto);
 extern int unix_receive_one(struct nlmsghdr *h, void *);
diff --git a/protobuf/fdinfo.proto b/protobuf/fdinfo.proto
index c55a8ab..e74488b 100644
--- a/protobuf/fdinfo.proto
+++ b/protobuf/fdinfo.proto
@@ -12,6 +12,7 @@ enum fd_types {
 	PACKETSK	= 10;
 	TTY		= 11;
 	FANOTIFY	= 12;
+	NETLINKSK	= 13;
 }
 
 message fdinfo_entry {
diff --git a/sk-netlink.c b/sk-netlink.c
index fe26317..e387cc1 100644
--- a/sk-netlink.c
+++ b/sk-netlink.c
@@ -2,6 +2,7 @@
 #include <linux/sock_diag.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <poll.h>
 
 #include "crtools.h"
 #include "files.h"
@@ -69,3 +70,95 @@ void show_netlinksk(int fd, struct cr_options *o)
 {
 	pb_show_plain(fd, PB_NETLINKSK);
 }
+
+static bool can_dump_netlink_sk(int lfd)
+{
+	struct pollfd pfd = {lfd, POLLIN, 0};
+	int ret;
+
+	ret = poll(&pfd, 1, 0);
+	if (ret < 0) {
+		pr_perror("poll() failed");
+	} else if (ret == 1)
+		pr_err("The socket has data to read\n");
+
+	return ret == 0;
+}
+
+static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
+{
+	struct netlink_sk_desc *sk;
+	NetlinkSkEntry ne = NETLINK_SK_ENTRY__INIT;
+	SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
+
+	sk = (struct netlink_sk_desc *)lookup_socket(p->stat.st_ino, PF_NETLINK);
+
+	ne.id = id;
+	ne.ino = p->stat.st_ino;
+
+	if (!can_dump_netlink_sk(lfd))
+		goto err;
+
+	if (sk) {
+		BUG_ON(sk->sd.already_dumped);
+
+		ne.protocol = sk->protocol;
+		ne.portid = sk->portid;
+		ne.groups = sk->groups;
+
+
+		ne.n_groups = sk->gsize / sizeof(ne.groups[0]);
+		/*
+		 * On 64-bit sk->gsize is multiple to 8 bytes (sizeof(long)),
+		 * so remove the last 4 bytes if they are empty.
+		 */
+		if (ne.n_groups && sk->groups[ne.n_groups - 1] == 0)
+			ne.n_groups -= 1;
+
+		if (ne.n_groups > 1) {
+			pr_err("%d %x\n", sk->gsize, sk->groups[1]);
+			pr_err("The netlink socket 0x%x has more than 32 groups\n", ne.ino);
+			return -1;
+		}
+		if (sk->groups && !sk->portid) {
+			pr_err("The netlink socket 0x%x is bound to groups but not to portid\n", ne.ino);
+			return -1;
+		}
+		ne.state = sk->state;
+		ne.dst_portid = sk->dst_portid;
+		ne.dst_group = sk->dst_group;
+	} else { /* unconnected and unbound socket */
+		int val;
+		socklen_t aux = sizeof(val);
+
+		if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
+			pr_perror("Unable to get protocol for netlink socket");
+			goto err;
+		}
+
+		ne.protocol = val;
+	}
+
+	ne.fown = (FownEntry *)&p->fown;
+	ne.opts	= &skopts;
+
+	if (dump_socket_opts(lfd, &skopts))
+		goto err;
+
+	if (pb_write_one(fdset_fd(glob_fdset, CR_FD_NETLINKSK), &ne, PB_NETLINKSK))
+		goto err;
+
+	return 0;
+err:
+	return -1;
+}
+
+static const struct fdtype_ops netlink_dump_ops = {
+	.type		= FD_TYPES__NETLINKSK,
+	.dump		= dump_one_netlink_fd,
+};
+
+int dump_one_netlink(struct fd_parms *p, int lfd, const int fdinfo)
+{
+	return do_dump_gen_file(p, lfd, &netlink_dump_ops, fdinfo);
+}
diff --git a/sockets.c b/sockets.c
index ee5d381..2568367 100644
--- a/sockets.c
+++ b/sockets.c
@@ -378,6 +378,8 @@ int dump_socket(struct fd_parms *p, int lfd, const int fdinfo)
 		return dump_one_inet6(p, lfd, fdinfo);
 	case AF_PACKET:
 		return dump_one_packet_sk(p, lfd, fdinfo);
+	case AF_NETLINK:
+		return dump_one_netlink(p, lfd, fdinfo);
 	default:
 		pr_err("BUG! Unknown socket collected (family %d)\n", family);
 		break;
-- 
1.7.11.7



More information about the CRIU mailing list