[CRIU] [PATCH 7/9] sockets: dump netlink sockets

Andrey Vagin avagin at openvz.org
Thu Mar 14 09:24:11 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 +
 protobuf/sk-netlink.proto |  1 -
 sk-netlink.c              | 80 +++++++++++++++++++++++++++++++++++++++++++++--
 sockets.c                 |  4 ++-
 5 files changed, 82 insertions(+), 5 deletions(-)

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/protobuf/sk-netlink.proto b/protobuf/sk-netlink.proto
index a82119b..593848b 100644
--- a/protobuf/sk-netlink.proto
+++ b/protobuf/sk-netlink.proto
@@ -6,7 +6,6 @@ message netlink_sk_entry {
 	required uint32			ino		=  2;
 	required uint32			protocol	=  3;
 	required uint32			state		=  4;
-	required uint32			type		=  5;
 	required uint32			flags		=  6;
 	required uint32			portid		=  7;
 	repeated uint32			groups		=  8;
diff --git a/sk-netlink.c b/sk-netlink.c
index c8279ea..627608a 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"
@@ -19,7 +20,6 @@ struct netlink_sk_desc {
 	u32			groups;
 	u32                     dst_portid;
 	u32			dst_group;
-	u32			rmem;
 	u8			state;
 	u8			protocol;
 };
@@ -31,10 +31,10 @@ int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
 	struct netlink_sk_desc *sd;
 
 	m = NLMSG_DATA(hdr);
-	pr_info("Collect netlink sock %u\n", m->ndiag_ino);
+	pr_info("Collect netlink sock 0x%x\n", m->ndiag_ino);
 
 	if (m->ndiag_ngroups > 32) {
-		pr_err("The netlink socket has more thatn 32 groups\n");
+		pr_err("The netlink socket 0x%x has more than 32 groups (%d)\n", m->ndiag_ino, m->ndiag_ngroups);
 		return -1;
 	}
 
@@ -59,3 +59,77 @@ 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 = 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 54a882b..9767860 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;
@@ -517,7 +519,7 @@ int collect_sockets(int pid)
 		err = tmp;
 
 	req.r.n.sdiag_family	= AF_NETLINK;
-	req.r.n.ndiag_show	= NDIAG_SHOW_MEMINFO | NDIAG_SHOW_GROUPS;
+	req.r.n.ndiag_show	= NDIAG_SHOW_GROUPS;
 	tmp = do_rtnl_req(nl, &req, sizeof(req), netlink_receive_one, NULL);
 	if (tmp)
 		err = tmp;
-- 
1.7.11.7



More information about the CRIU mailing list