[CRIU] [PATCH 2/2] netlink: Diag core and basic socket info dumping

Andrey Vagin avagin at openvz.org
Mon Mar 11 15:53:53 EDT 2013


The netlink_diag can be built as a module, just like it's done in unix sockets.

The core dumping message carries the basic info about netlink sockets:
family, type and protocol, portis, groups[0], dst_group, dst_portid, state.

Here is only first part of groups[0], because nobody in kernel doesn't
use groups upwards of 32. Later it can be expanded, if someone will
require this.

The socket inode number and cookie is reserved for future per-socket info
retrieving. The per-protocol filtering is also reserved for future by
requiring the sdiag_protocol to be zero.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/uapi/linux/netlink_diag.h |  37 ++++++++++++
 net/Kconfig                       |   1 +
 net/netlabel/Makefile             |   1 -
 net/netlink/Kconfig               |  10 +++
 net/netlink/Makefile              |   2 +
 net/netlink/netlink_diag.c        | 124 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 174 insertions(+), 1 deletion(-)
 create mode 100644 include/uapi/linux/netlink_diag.h
 create mode 100644 net/netlink/Kconfig
 create mode 100644 net/netlink/netlink_diag.c

diff --git a/include/uapi/linux/netlink_diag.h b/include/uapi/linux/netlink_diag.h
new file mode 100644
index 0000000..42c4f9a
--- /dev/null
+++ b/include/uapi/linux/netlink_diag.h
@@ -0,0 +1,37 @@
+#ifndef __NETLINK_DIAG_H__
+#define __NETLINK_DIAG_H__
+
+#include <linux/types.h>
+
+struct netlink_diag_req {
+	__u8	sdiag_family;
+	__u8	sdiag_protocol;
+	__u16	pad;
+	__u32	ndiag_ino;
+	__u32	ndiag_show;
+	__u32	ndiag_cookie[2];
+};
+
+struct netlink_diag_msg {
+	__u8	ndiag_family;
+	__u8	ndiag_type;
+	__u8	ndiag_protocol;
+	__u8	ndiag_state;
+
+	__u32	ndiag_portid;
+	__u32	ndiag_groups;
+	__u32	ndiag_dst_portid;
+	__u32	ndiag_dst_group;
+	__u32	ndiag_ino;
+	__u32	ndiag_cookie[2];
+};
+
+enum {
+	NETLINK_DIAG_MEMINFO,
+
+	NETLINK_DIAG_MAX,
+};
+
+#define NDIAG_SHOW_MEMINFO	0x00000001 /* show memory info of a socket */
+
+#endif
diff --git a/net/Kconfig b/net/Kconfig
index 30b48f5..8686743 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -218,6 +218,7 @@ source "net/dcb/Kconfig"
 source "net/dns_resolver/Kconfig"
 source "net/batman-adv/Kconfig"
 source "net/openvswitch/Kconfig"
+source "net/netlink/Kconfig"
 
 config RPS
 	boolean
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
index d2732fc..1b78a8c 100644
--- a/net/netlabel/Makefile
+++ b/net/netlabel/Makefile
@@ -12,4 +12,3 @@ obj-y	+= netlabel_mgmt.o
 # protocol modules
 obj-y	+= netlabel_unlabeled.o
 obj-y	+= netlabel_cipso_v4.o
-
diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig
new file mode 100644
index 0000000..5d6e8c0
--- /dev/null
+++ b/net/netlink/Kconfig
@@ -0,0 +1,10 @@
+#
+# Netlink Sockets
+#
+
+config NETLINK_DIAG
+	tristate "NETLINK: socket monitoring interface"
+	default n
+	---help---
+	  Support for NETLINK socket monitoring interface used by the ss tool.
+	  If unsure, say Y.
diff --git a/net/netlink/Makefile b/net/netlink/Makefile
index bdd6ddf..f50acc5 100644
--- a/net/netlink/Makefile
+++ b/net/netlink/Makefile
@@ -3,3 +3,5 @@
 #
 
 obj-y  				:= af_netlink.o genetlink.o
+
+obj-$(CONFIG_NETLINK_DIAG)	+= netlink_diag.o
diff --git a/net/netlink/netlink_diag.c b/net/netlink/netlink_diag.c
new file mode 100644
index 0000000..9c8cef2
--- /dev/null
+++ b/net/netlink/netlink_diag.c
@@ -0,0 +1,124 @@
+#include <linux/module.h>
+
+#include <linux/sock_diag.h>
+#include <linux/netlink_diag.h>
+#include <net/sock.h>
+
+#include "af_netlink.h"
+
+static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+			struct netlink_diag_req *req,
+			u32 portid, u32 seq, u32 flags, int sk_ino)
+{
+	struct nlmsghdr *nlh;
+	struct netlink_diag_msg *rep;
+	struct netlink_sock *nlk = nlk_sk(sk);
+
+	nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
+			flags);
+	if (!nlh)
+		return -EMSGSIZE;
+
+	rep = nlmsg_data(nlh);
+	rep->ndiag_family = AF_NETLINK;
+	rep->ndiag_type = sk->sk_type;
+	rep->ndiag_protocol = sk->sk_protocol;
+	rep->ndiag_state = sk->sk_state;
+
+	rep->ndiag_ino = sk_ino;
+	rep->ndiag_portid = nlk->portid;
+	rep->ndiag_groups = nlk->groups ? (u32)nlk->groups[0] : 0;
+	rep->ndiag_dst_portid = nlk->dst_portid;
+	rep->ndiag_dst_group = nlk->dst_group;
+	sock_diag_save_cookie(sk, rep->ndiag_cookie);
+
+	if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) &&
+	    sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
+		goto out_nlmsg_trim;
+
+	return nlmsg_end(skb, nlh);
+
+out_nlmsg_trim:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	int num = 0, s_num = cb->args[0];
+	struct net *net = sock_net(skb->sk);
+	struct netlink_diag_req *req;
+	struct sock *sk;
+	struct hlist_node *node;
+	int i, j;
+
+	req = nlmsg_data(cb->nlh);
+
+	/* Make it possible to support protocol filtering later */
+	if (req->sdiag_protocol)
+		return -EINVAL;
+
+	read_lock(&nl_table_lock);
+	for (i = 0; i < MAX_LINKS; i++) {
+		struct nl_portid_hash *hash = &nl_table[i].hash;
+
+		for (j = 0; j <= hash->mask; j++) {
+			sk_for_each(sk, node, &hash->table[j]) {
+				if (!net_eq(sock_net(sk), net))
+					continue;
+				if (num < s_num)
+					goto next;
+				if (sk_diag_fill(sk, skb, req,
+						 NETLINK_CB(cb->skb).portid,
+						 cb->nlh->nlmsg_seq,
+						 NLM_F_MULTI,
+						 sock_i_ino(sk)) < 0)
+					goto done;
+next:
+				num++;
+			}
+		}
+	}
+done:
+	read_unlock(&nl_table_lock);
+	cb->args[0] = num;
+
+	return 0;
+}
+
+static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
+{
+	int hdrlen = sizeof(struct netlink_diag_req);
+	struct net *net = sock_net(skb->sk);
+
+	if (nlmsg_len(h) < hdrlen)
+		return -EINVAL;
+
+	if (h->nlmsg_flags & NLM_F_DUMP) {
+		struct netlink_dump_control c = {
+			.dump = netlink_diag_dump,
+		};
+		return netlink_dump_start(net->diag_nlsk, skb, h, &c);
+	} else
+		return -EOPNOTSUPP;
+}
+
+static const struct sock_diag_handler netlink_diag_handler = {
+	.family = AF_NETLINK,
+	.dump = netlink_diag_handler_dump,
+};
+
+static int __init netlink_diag_init(void)
+{
+	return sock_diag_register(&netlink_diag_handler);
+}
+
+static void __exit netlink_diag_exit(void)
+{
+	sock_diag_unregister(&netlink_diag_handler);
+}
+
+module_init(netlink_diag_init);
+module_exit(netlink_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */);
-- 
1.7.11.7



More information about the CRIU mailing list