netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/11] Generalize the inet_diag infrastructure
@ 2011-12-06 17:56 Pavel Emelyanov
  2011-12-06 17:56 ` [PATCH 1/11] inet_diag: Partly rename inet_ to sock_ Pavel Emelyanov
                   ` (12 more replies)
  0 siblings, 13 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:56 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

This is an attempt to prepare the existing inet_diag infrastructure to work with
arbitrary address family and protocol pair, not only AF_INET(6) and TCP/DCCP.

This set adds the sock_diag infrastructure, that handles the new SOCK_DIAG_BY_FAMILY
message type by the NETLINK_INET_DIAG socket. The core API struct for this (called
sock_diag_req) contains two fields - family and type - which specify which sockets 
to dump. Additional information is considered to be family handler specific.

The existing inet_diag code is patched to register himself inside the sock_diag and
provide callbacks for dumping AF_INET/AF_INET6 IPPROTO_TCP/IPPROTO_DCCP sockets. The
existing API facilities such as state filtering and bytecode is of course preserved
and is treated by inet_diag specific data.

Binary compatibility with existing NETLINK_INET_DIAG is also kept.

No additional stuff in this set. The support for IPPROTO_UDP protocol and AF_UNIX
family will come later if this set is approved.

Applies to net-next, patch for iproute2's ss tool (proving that the new code ... pretends
to work) is at the end of the thread.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/11] inet_diag: Partly rename inet_ to sock_
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
@ 2011-12-06 17:56 ` Pavel Emelyanov
  2011-12-06 18:24   ` Stephen Hemminger
  2011-12-06 17:57 ` [PATCH 2/11] sock_diag: Introduce new message type Pavel Emelyanov
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:56 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

The ultimate goal is to get the sock_diag module, that works in
family+protocol terms. Currently this is suitable to do on the
inet_diag basis, so rename parts of the code. It will be moved
to sock_diag.c later.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/netlink.h  |    2 +-
 net/dccp/diag.c          |    2 +-
 net/ipv4/inet_diag.c     |   33 +++++++++++++++++++--------------
 net/ipv4/tcp_diag.c      |    2 +-
 security/selinux/hooks.c |    2 +-
 5 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 8374d29..9827ebf 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -8,7 +8,7 @@
 #define NETLINK_UNUSED		1	/* Unused number				*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
-#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
+#define NETLINK_SOCK_DIAG	4	/* socket monitoring				*/
 #define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
 #define NETLINK_XFRM		6	/* ipsec */
 #define NETLINK_SELINUX		7	/* SELinux event notifications */
diff --git a/net/dccp/diag.c b/net/dccp/diag.c
index b21f261..d92ba7d 100644
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -71,4 +71,4 @@ module_exit(dccp_diag_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP inet_diag handler");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, DCCPDIAG_GETSOCK);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, DCCPDIAG_GETSOCK);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 0a46c54..a5f3c40 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -45,7 +45,7 @@ struct inet_diag_entry {
 	u16 userlocks;
 };
 
-static struct sock *idiagnl;
+static struct sock *sdiagnl;
 
 #define INET_DIAG_PUT(skb, attrtype, attrlen) \
 	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
@@ -56,7 +56,7 @@ static const struct inet_diag_handler *inet_diag_lock_handler(int type)
 {
 	if (!inet_diag_table[type])
 		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-			       NETLINK_INET_DIAG, type);
+			       NETLINK_SOCK_DIAG, type);
 
 	mutex_lock(&inet_diag_table_mutex);
 	if (!inet_diag_table[type])
@@ -312,7 +312,7 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
 		kfree_skb(rep);
 		goto out;
 	}
-	err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
+	err = netlink_unicast(sdiagnl, rep, NETLINK_CB(in_skb).pid,
 			      MSG_DONTWAIT);
 	if (err > 0)
 		err = 0;
@@ -870,20 +870,25 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 				return -EINVAL;
 		}
 
-		return netlink_dump_start(idiagnl, skb, nlh,
+		return netlink_dump_start(sdiagnl, skb, nlh,
 					  inet_diag_dump, NULL, 0);
 	}
 
 	return inet_diag_get_exact(skb, nlh);
 }
 
-static DEFINE_MUTEX(inet_diag_mutex);
+static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	return inet_diag_rcv_msg(skb, nlh);
+}
+
+static DEFINE_MUTEX(sock_diag_mutex);
 
-static void inet_diag_rcv(struct sk_buff *skb)
+static void sock_diag_rcv(struct sk_buff *skb)
 {
-	mutex_lock(&inet_diag_mutex);
-	netlink_rcv_skb(skb, &inet_diag_rcv_msg);
-	mutex_unlock(&inet_diag_mutex);
+	mutex_lock(&sock_diag_mutex);
+	netlink_rcv_skb(skb, &sock_diag_rcv_msg);
+	mutex_unlock(&sock_diag_mutex);
 }
 
 int inet_diag_register(const struct inet_diag_handler *h)
@@ -929,9 +934,9 @@ static int __init inet_diag_init(void)
 	if (!inet_diag_table)
 		goto out;
 
-	idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0,
-					inet_diag_rcv, NULL, THIS_MODULE);
-	if (idiagnl == NULL)
+	sdiagnl = netlink_kernel_create(&init_net, NETLINK_SOCK_DIAG, 0,
+					sock_diag_rcv, NULL, THIS_MODULE);
+	if (sdiagnl == NULL)
 		goto out_free_table;
 	err = 0;
 out:
@@ -943,11 +948,11 @@ out_free_table:
 
 static void __exit inet_diag_exit(void)
 {
-	netlink_kernel_release(idiagnl);
+	netlink_kernel_release(sdiagnl);
 	kfree(inet_diag_table);
 }
 
 module_init(inet_diag_init);
 module_exit(inet_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_INET_DIAG);
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG);
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 939edb3..9e276b8 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -54,4 +54,4 @@ static void __exit tcp_diag_exit(void)
 module_init(tcp_diag_init);
 module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, TCPDIAG_GETSOCK);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, TCPDIAG_GETSOCK);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index cca09bb..86305c2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1090,7 +1090,7 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
 			return SECCLASS_NETLINK_ROUTE_SOCKET;
 		case NETLINK_FIREWALL:
 			return SECCLASS_NETLINK_FIREWALL_SOCKET;
-		case NETLINK_INET_DIAG:
+		case NETLINK_SOCK_DIAG:
 			return SECCLASS_NETLINK_TCPDIAG_SOCKET;
 		case NETLINK_NFLOG:
 			return SECCLASS_NETLINK_NFLOG_SOCKET;
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/11] sock_diag: Introduce new message type
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
  2011-12-06 17:56 ` [PATCH 1/11] inet_diag: Partly rename inet_ to sock_ Pavel Emelyanov
@ 2011-12-06 17:57 ` Pavel Emelyanov
  2011-12-06 17:57 ` [PATCH 3/11] inet_diag: Move byte-code finding up the call-stack Pavel Emelyanov
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:57 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

This type will run the family+protocol based socket dumping.
Also prepare the stub function for it.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/inet_diag.h |    1 +
 net/ipv4/inet_diag.c      |   17 +++++++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index abf5028..f7baaf6 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -6,6 +6,7 @@
 /* Just some random number */
 #define TCPDIAG_GETSOCK 18
 #define DCCPDIAG_GETSOCK 19
+#define SOCK_DIAG_BY_FAMILY 20
 
 #define INET_DIAG_GETSOCK_MAX 24
 
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index a5f3c40..e106e3b 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -850,7 +850,7 @@ unlock:
 	return skb->len;
 }
 
-static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	int hdrlen = sizeof(struct inet_diag_req);
 
@@ -877,9 +877,22 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	return inet_diag_get_exact(skb, nlh);
 }
 
+static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	return -EOPNOTSUPP;
+}
+
 static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	return inet_diag_rcv_msg(skb, nlh);
+	switch (nlh->nlmsg_type) {
+	case TCPDIAG_GETSOCK:
+	case DCCPDIAG_GETSOCK:
+		return inet_diag_rcv_msg_compat(skb, nlh);
+	case SOCK_DIAG_BY_FAMILY:
+		return __sock_diag_rcv_msg(skb, nlh);
+	default:
+		return -EINVAL;
+	}
 }
 
 static DEFINE_MUTEX(sock_diag_mutex);
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/11] inet_diag: Move byte-code finding up the call-stack
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
  2011-12-06 17:56 ` [PATCH 1/11] inet_diag: Partly rename inet_ to sock_ Pavel Emelyanov
  2011-12-06 17:57 ` [PATCH 2/11] sock_diag: Introduce new message type Pavel Emelyanov
@ 2011-12-06 17:57 ` Pavel Emelyanov
  2011-12-06 17:58 ` [PATCH 5/11] sock_diag: Initial skeleton Pavel Emelyanov
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:57 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Current code calculates it at fixed offset. This offset will change, so
move the BC calculation upper to make the further patching simpler.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/ipv4/inet_diag.c |   36 +++++++++++++++++-------------------
 1 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index e106e3b..a406caf 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -488,15 +488,13 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
 
 static int inet_csk_diag_dump(struct sock *sk,
 			      struct sk_buff *skb,
-			      struct netlink_callback *cb)
+			      struct netlink_callback *cb,
+			      const struct nlattr *bc)
 {
 	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-	if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
+	if (bc != NULL) {
 		struct inet_diag_entry entry;
-		const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
-							  sizeof(*r),
-							  INET_DIAG_REQ_BYTECODE);
 		struct inet_sock *inet = inet_sk(sk);
 
 		entry.family = sk->sk_family;
@@ -527,15 +525,13 @@ static int inet_csk_diag_dump(struct sock *sk,
 
 static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 			       struct sk_buff *skb,
-			       struct netlink_callback *cb)
+			       struct netlink_callback *cb,
+			       const struct nlattr *bc)
 {
 	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-	if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
+	if (bc != NULL) {
 		struct inet_diag_entry entry;
-		const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
-							  sizeof(*r),
-							  INET_DIAG_REQ_BYTECODE);
 
 		entry.family = tw->tw_family;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -616,13 +612,13 @@ nlmsg_failure:
 }
 
 static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
-			       struct netlink_callback *cb)
+			       struct netlink_callback *cb,
+			       const struct nlattr *bc)
 {
 	struct inet_diag_entry entry;
 	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct listen_sock *lopt;
-	const struct nlattr *bc = NULL;
 	struct inet_sock *inet = inet_sk(sk);
 	int j, s_j;
 	int reqnum, s_reqnum;
@@ -642,9 +638,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
 	if (!lopt || !lopt->qlen)
 		goto out;
 
-	if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
-		bc = nlmsg_find_attr(cb->nlh, sizeof(*r),
-				     INET_DIAG_REQ_BYTECODE);
+	if (bc != NULL) {
 		entry.sport = inet->inet_num;
 		entry.userlocks = sk->sk_userlocks;
 	}
@@ -708,6 +702,10 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 	const struct inet_diag_handler *handler;
 	struct inet_hashinfo *hashinfo;
+	const struct nlattr *bc = NULL;
+
+	if (nlmsg_attrlen(cb->nlh, sizeof(struct inet_diag_req)))
+		bc = nlmsg_find_attr(cb->nlh, sizeof(*r), INET_DIAG_REQ_BYTECODE);
 
 	handler = inet_diag_lock_handler(cb->nlh->nlmsg_type);
 	if (IS_ERR(handler))
@@ -747,7 +745,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 				    cb->args[3] > 0)
 					goto syn_recv;
 
-				if (inet_csk_diag_dump(sk, skb, cb) < 0) {
+				if (inet_csk_diag_dump(sk, skb, cb, bc) < 0) {
 					spin_unlock_bh(&ilb->lock);
 					goto done;
 				}
@@ -756,7 +754,7 @@ syn_recv:
 				if (!(r->idiag_states & TCPF_SYN_RECV))
 					goto next_listen;
 
-				if (inet_diag_dump_reqs(skb, sk, cb) < 0) {
+				if (inet_diag_dump_reqs(skb, sk, cb, bc) < 0) {
 					spin_unlock_bh(&ilb->lock);
 					goto done;
 				}
@@ -809,7 +807,7 @@ skip_listen_ht:
 			if (r->id.idiag_dport != inet->inet_dport &&
 			    r->id.idiag_dport)
 				goto next_normal;
-			if (inet_csk_diag_dump(sk, skb, cb) < 0) {
+			if (inet_csk_diag_dump(sk, skb, cb, bc) < 0) {
 				spin_unlock_bh(lock);
 				goto done;
 			}
@@ -831,7 +829,7 @@ next_normal:
 				if (r->id.idiag_dport != tw->tw_dport &&
 				    r->id.idiag_dport)
 					goto next_dying;
-				if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
+				if (inet_twsk_diag_dump(tw, skb, cb, bc) < 0) {
 					spin_unlock_bh(lock);
 					goto done;
 				}
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 5/11] sock_diag: Initial skeleton
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (2 preceding siblings ...)
  2011-12-06 17:57 ` [PATCH 3/11] inet_diag: Move byte-code finding up the call-stack Pavel Emelyanov
@ 2011-12-06 17:58 ` Pavel Emelyanov
  2011-12-06 17:58 ` [PATCH 6/11] inet_diag: Introduce new inet_diag_req header Pavel Emelyanov
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:58 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

When receiving the SOCK_DIAG_BY_FAMILY message we have to find the
handler for provided family and pass the nl message to it.

This patch describes an infrastructure to work with such nandlers
and implements stubs for AF_INET(6) ones.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/sock_diag.h |   23 ++++++++++
 net/ipv4/inet_diag.c      |  102 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 123 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/sock_diag.h

diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
new file mode 100644
index 0000000..ba4933b
--- /dev/null
+++ b/include/linux/sock_diag.h
@@ -0,0 +1,23 @@
+#ifndef __SOCK_DIAG_H__
+#define __SOCK_DIAG_H__
+struct sk_buff;
+struct nlmsghdr;
+
+struct sock_diag_req {
+	__u8	sdiag_family;
+	__u8	sdiag_protocol;
+};
+
+struct sock_diag_handler {
+	__u8 family;
+	int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh);
+};
+
+int sock_diag_register(struct sock_diag_handler *h);
+void sock_diag_unregister(struct sock_diag_handler *h);
+
+void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh));
+void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh));
+
+extern struct sock *sock_diag_nlsk;
+#endif
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index cf8be3e..ccbe8ea 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -33,6 +33,7 @@
 #include <linux/stddef.h>
 
 #include <linux/inet_diag.h>
+#include <linux/sock_diag.h>
 
 static const struct inet_diag_handler **inet_diag_table;
 
@@ -887,9 +888,91 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 	return inet_diag_get_exact(skb, nlh);
 }
 
+static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
+{
+	int hdrlen = sizeof(struct inet_diag_req);
+
+	if (nlmsg_len(h) < hdrlen)
+		return -EINVAL;
+
+	if (h->nlmsg_flags & NLM_F_DUMP) {
+		return -EAFNOSUPPORT;
+	}
+
+	return -EAFNOSUPPORT;
+}
+
+static struct sock_diag_handler inet_diag_handler = {
+	.family = AF_INET,
+	.dump = inet_diag_handler_dump,
+};
+
+static struct sock_diag_handler inet6_diag_handler = {
+	.family = AF_INET6,
+	.dump = inet_diag_handler_dump,
+};
+
+static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
+static DEFINE_MUTEX(sock_diag_table_mutex);
+
+int sock_diag_register(struct sock_diag_handler *hndl)
+{
+	int err = 0;
+
+	if (hndl->family > AF_MAX)
+		return -EINVAL;
+
+	mutex_lock(&sock_diag_table_mutex);
+	if (sock_diag_handlers[hndl->family])
+		err = -EBUSY;
+	else
+		sock_diag_handlers[hndl->family] = hndl;
+	mutex_unlock(&sock_diag_table_mutex);
+
+	return err;
+}
+
+void sock_diag_unregister(struct sock_diag_handler *hnld)
+{
+	int family = hnld->family;
+
+	if (family > AF_MAX)
+		return;
+
+	mutex_lock(&sock_diag_table_mutex);
+	BUG_ON(sock_diag_handlers[family] != hnld);
+	sock_diag_handlers[family] = NULL;
+	mutex_unlock(&sock_diag_table_mutex);
+}
+
+static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
+{
+	mutex_lock(&sock_diag_table_mutex);
+	return sock_diag_handlers[family];
+}
+
+static inline void sock_diag_unlock_handler(struct sock_diag_handler *h)
+{
+	mutex_unlock(&sock_diag_table_mutex);
+}
+
 static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	return -EOPNOTSUPP;
+	int err;
+	struct sock_diag_req *req = NLMSG_DATA(nlh);
+	struct sock_diag_handler *hndl;
+
+	if (nlmsg_len(nlh) < sizeof(*req))
+		return -EINVAL;
+
+	hndl = sock_diag_lock_handler(req->sdiag_family);
+	if (hndl == NULL)
+		err = -ENOENT;
+	else
+		err = hndl->dump(skb, nlh);
+	sock_diag_unlock_handler(hndl);
+
+	return err;
 }
 
 static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
@@ -961,9 +1044,22 @@ static int __init inet_diag_init(void)
 					sock_diag_rcv, NULL, THIS_MODULE);
 	if (sdiagnl == NULL)
 		goto out_free_table;
-	err = 0;
+
+	err = sock_diag_register(&inet_diag_handler);
+	if (err)
+		goto out_free_nl;
+
+	err = sock_diag_register(&inet6_diag_handler);
+	if (err)
+		goto out_free_inet;
+
 out:
 	return err;
+
+out_free_inet:
+	sock_diag_unregister(&inet_diag_handler);
+out_free_nl:
+	netlink_kernel_release(sdiagnl);
 out_free_table:
 	kfree(inet_diag_table);
 	goto out;
@@ -971,6 +1067,8 @@ out_free_table:
 
 static void __exit inet_diag_exit(void)
 {
+	sock_diag_unregister(&inet6_diag_handler);
+	sock_diag_unregister(&inet_diag_handler);
 	netlink_kernel_release(sdiagnl);
 	kfree(inet_diag_table);
 }
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 6/11] inet_diag: Introduce new inet_diag_req header
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (3 preceding siblings ...)
  2011-12-06 17:58 ` [PATCH 5/11] sock_diag: Initial skeleton Pavel Emelyanov
@ 2011-12-06 17:58 ` Pavel Emelyanov
  2011-12-06 17:58 ` [PATCH 7/11] inet_diag: Switch the _get_exact to work with new header Pavel Emelyanov
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:58 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

This one coinsides with the sock_diag_req in the beginning and 
contains only used fields from its previous analogue.

The existing code is patched to use the _compat version of it
for now.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/inet_diag.h |   11 ++++++++++-
 net/ipv4/inet_diag.c      |   14 +++++++-------
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index f7baaf6..defe8ff 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -23,7 +23,7 @@ struct inet_diag_sockid {
 
 /* Request structure */
 
-struct inet_diag_req {
+struct inet_diag_req_compat {
 	__u8	idiag_family;		/* Family of addresses. */
 	__u8	idiag_src_len;
 	__u8	idiag_dst_len;
@@ -35,6 +35,15 @@ struct inet_diag_req {
 	__u32	idiag_dbs;		/* Tables to dump (NI) */
 };
 
+struct inet_diag_req {
+	__u8	sdiag_family;
+	__u8	sdiag_protocol;
+	__u8	idiag_ext;
+	__u8	pad;
+	__u32	idiag_states;
+	struct inet_diag_sockid id;
+};
+
 enum {
 	INET_DIAG_REQ_NONE,
 	INET_DIAG_REQ_BYTECODE,
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index ccbe8ea..9a6a6de 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -265,7 +265,7 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
 {
 	int err;
 	struct sock *sk;
-	struct inet_diag_req *req = NLMSG_DATA(nlh);
+	struct inet_diag_req_compat *req = NLMSG_DATA(nlh);
 	struct sk_buff *rep;
 	struct inet_hashinfo *hashinfo;
 	const struct inet_diag_handler *handler;
@@ -504,7 +504,7 @@ static int inet_csk_diag_dump(struct sock *sk,
 			      struct netlink_callback *cb,
 			      const struct nlattr *bc)
 {
-	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
 
 	if (bc != NULL) {
 		struct inet_diag_entry entry;
@@ -541,7 +541,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 			       struct netlink_callback *cb,
 			       const struct nlattr *bc)
 {
-	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
 
 	if (bc != NULL) {
 		struct inet_diag_entry entry;
@@ -629,7 +629,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
 			       const struct nlattr *bc)
 {
 	struct inet_diag_entry entry;
-	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct listen_sock *lopt;
 	struct inet_sock *inet = inet_sk(sk);
@@ -712,12 +712,12 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int i, num;
 	int s_i, s_num;
-	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
 	const struct inet_diag_handler *handler;
 	struct inet_hashinfo *hashinfo;
 	const struct nlattr *bc = NULL;
 
-	if (nlmsg_attrlen(cb->nlh, sizeof(struct inet_diag_req)))
+	if (nlmsg_attrlen(cb->nlh, sizeof(struct inet_diag_req_compat)))
 		bc = nlmsg_find_attr(cb->nlh, sizeof(*r), INET_DIAG_REQ_BYTECODE);
 
 	handler = inet_diag_lock_handler(inet_diag_type2proto(cb->nlh->nlmsg_type));
@@ -863,7 +863,7 @@ unlock:
 
 static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	int hdrlen = sizeof(struct inet_diag_req);
+	int hdrlen = sizeof(struct inet_diag_req_compat);
 
 	if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
 	    nlmsg_len(nlh) < hdrlen)
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 7/11] inet_diag: Switch the _get_exact to work with new header
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (4 preceding siblings ...)
  2011-12-06 17:58 ` [PATCH 6/11] inet_diag: Introduce new inet_diag_req header Pavel Emelyanov
@ 2011-12-06 17:58 ` Pavel Emelyanov
  2011-12-06 17:58 ` [PATCH 8/11] inet_diag: Switch the _dump " Pavel Emelyanov
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:58 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Make inet_diag_get_exact work with given header instead of calculating
one from the nl message.

The SOCK_DIAG_BY_FAMILY just passes skb's one through, the compat code
converts the old header to new one.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/ipv4/inet_diag.c |   29 ++++++++++++++++++++++-------
 1 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 9a6a6de..6b34071 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -261,16 +261,16 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
 }
 
 static int inet_diag_get_exact(struct sk_buff *in_skb,
-			       const struct nlmsghdr *nlh)
+			       const struct nlmsghdr *nlh,
+			       struct inet_diag_req *req)
 {
 	int err;
 	struct sock *sk;
-	struct inet_diag_req_compat *req = NLMSG_DATA(nlh);
 	struct sk_buff *rep;
 	struct inet_hashinfo *hashinfo;
 	const struct inet_diag_handler *handler;
 
-	handler = inet_diag_lock_handler(inet_diag_type2proto(nlh->nlmsg_type));
+	handler = inet_diag_lock_handler(req->sdiag_protocol);
 	if (IS_ERR(handler)) {
 		err = PTR_ERR(handler);
 		goto unlock;
@@ -279,13 +279,13 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
 	hashinfo = handler->idiag_hashinfo;
 	err = -EINVAL;
 
-	if (req->idiag_family == AF_INET) {
+	if (req->sdiag_family == AF_INET) {
 		sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0],
 				 req->id.idiag_dport, req->id.idiag_src[0],
 				 req->id.idiag_sport, req->id.idiag_if);
 	}
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-	else if (req->idiag_family == AF_INET6) {
+	else if (req->sdiag_family == AF_INET6) {
 		sk = inet6_lookup(&init_net, hashinfo,
 				  (struct in6_addr *)req->id.idiag_dst,
 				  req->id.idiag_dport,
@@ -861,6 +861,21 @@ unlock:
 	return skb->len;
 }
 
+static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
+			       const struct nlmsghdr *nlh)
+{
+	struct inet_diag_req_compat *rc = NLMSG_DATA(nlh);
+	struct inet_diag_req req;
+
+	req.sdiag_family = rc->idiag_family;
+	req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type);
+	req.idiag_ext = rc->idiag_ext;
+	req.idiag_states = rc->idiag_states;
+	req.id = rc->id;
+
+	return inet_diag_get_exact(in_skb, nlh, &req);
+}
+
 static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	int hdrlen = sizeof(struct inet_diag_req_compat);
@@ -885,7 +900,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 					  inet_diag_dump, NULL, 0);
 	}
 
-	return inet_diag_get_exact(skb, nlh);
+	return inet_diag_get_exact_compat(skb, nlh);
 }
 
 static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
@@ -899,7 +914,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 		return -EAFNOSUPPORT;
 	}
 
-	return -EAFNOSUPPORT;
+	return inet_diag_get_exact(skb, h, (struct inet_diag_req *)NLMSG_DATA(h));
 }
 
 static struct sock_diag_handler inet_diag_handler = {
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 8/11] inet_diag: Switch the _dump to work with new header
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (5 preceding siblings ...)
  2011-12-06 17:58 ` [PATCH 7/11] inet_diag: Switch the _get_exact to work with new header Pavel Emelyanov
@ 2011-12-06 17:58 ` Pavel Emelyanov
  2011-12-06 17:59 ` [PATCH 9/11] inet_diag: Introduce socket family checks Pavel Emelyanov
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:58 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Make inet_diag_dumo work with given header instead of calculating
one from the nl message.

The SOCK_DIAG_BY_FAMILY just passes skb's one through, the compat code
converts the old header to new one.

Also fix the bytecode calculation to find one at proper offset.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/ipv4/inet_diag.c |   71 +++++++++++++++++++++++++++++++++++++------------
 1 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 6b34071..d655f0a 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -502,10 +502,9 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
 static int inet_csk_diag_dump(struct sock *sk,
 			      struct sk_buff *skb,
 			      struct netlink_callback *cb,
+			      struct inet_diag_req *r,
 			      const struct nlattr *bc)
 {
-	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
-
 	if (bc != NULL) {
 		struct inet_diag_entry entry;
 		struct inet_sock *inet = inet_sk(sk);
@@ -539,10 +538,9 @@ static int inet_csk_diag_dump(struct sock *sk,
 static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 			       struct sk_buff *skb,
 			       struct netlink_callback *cb,
+			       struct inet_diag_req *r,
 			       const struct nlattr *bc)
 {
-	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
-
 	if (bc != NULL) {
 		struct inet_diag_entry entry;
 
@@ -626,10 +624,10 @@ nlmsg_failure:
 
 static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
 			       struct netlink_callback *cb,
+			       struct inet_diag_req *r,
 			       const struct nlattr *bc)
 {
 	struct inet_diag_entry entry;
-	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct listen_sock *lopt;
 	struct inet_sock *inet = inet_sk(sk);
@@ -708,19 +706,15 @@ out:
 	return err;
 }
 
-static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
+		struct inet_diag_req *r, struct nlattr *bc)
 {
 	int i, num;
 	int s_i, s_num;
-	struct inet_diag_req_compat *r = NLMSG_DATA(cb->nlh);
 	const struct inet_diag_handler *handler;
 	struct inet_hashinfo *hashinfo;
-	const struct nlattr *bc = NULL;
-
-	if (nlmsg_attrlen(cb->nlh, sizeof(struct inet_diag_req_compat)))
-		bc = nlmsg_find_attr(cb->nlh, sizeof(*r), INET_DIAG_REQ_BYTECODE);
 
-	handler = inet_diag_lock_handler(inet_diag_type2proto(cb->nlh->nlmsg_type));
+	handler = inet_diag_lock_handler(r->sdiag_protocol);
 	if (IS_ERR(handler))
 		goto unlock;
 
@@ -758,7 +752,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 				    cb->args[3] > 0)
 					goto syn_recv;
 
-				if (inet_csk_diag_dump(sk, skb, cb, bc) < 0) {
+				if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
 					spin_unlock_bh(&ilb->lock);
 					goto done;
 				}
@@ -767,7 +761,7 @@ syn_recv:
 				if (!(r->idiag_states & TCPF_SYN_RECV))
 					goto next_listen;
 
-				if (inet_diag_dump_reqs(skb, sk, cb, bc) < 0) {
+				if (inet_diag_dump_reqs(skb, sk, cb, r, bc) < 0) {
 					spin_unlock_bh(&ilb->lock);
 					goto done;
 				}
@@ -820,7 +814,7 @@ skip_listen_ht:
 			if (r->id.idiag_dport != inet->inet_dport &&
 			    r->id.idiag_dport)
 				goto next_normal;
-			if (inet_csk_diag_dump(sk, skb, cb, bc) < 0) {
+			if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
 				spin_unlock_bh(lock);
 				goto done;
 			}
@@ -842,7 +836,7 @@ next_normal:
 				if (r->id.idiag_dport != tw->tw_dport &&
 				    r->id.idiag_dport)
 					goto next_dying;
-				if (inet_twsk_diag_dump(tw, skb, cb, bc) < 0) {
+				if (inet_twsk_diag_dump(tw, skb, cb, r, bc) < 0) {
 					spin_unlock_bh(lock);
 					goto done;
 				}
@@ -861,6 +855,36 @@ unlock:
 	return skb->len;
 }
 
+static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nlattr *bc = NULL;
+	int hdrlen = sizeof(struct inet_diag_req);
+
+	if (nlmsg_attrlen(cb->nlh, hdrlen))
+		bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);
+
+	return __inet_diag_dump(skb, cb, (struct inet_diag_req *)NLMSG_DATA(cb->nlh), bc);
+}
+
+static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh);
+	struct inet_diag_req req;
+	struct nlattr *bc = NULL;
+	int hdrlen = sizeof(struct inet_diag_req_compat);
+
+	req.sdiag_family = rc->idiag_family;
+	req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type);
+	req.idiag_ext = rc->idiag_ext;
+	req.idiag_states = rc->idiag_states;
+	req.id = rc->id;
+
+	if (nlmsg_attrlen(cb->nlh, hdrlen))
+		bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);
+
+	return __inet_diag_dump(skb, cb, &req, bc);
+}
+
 static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
 			       const struct nlmsghdr *nlh)
 {
@@ -897,7 +921,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 		}
 
 		return netlink_dump_start(sdiagnl, skb, nlh,
-					  inet_diag_dump, NULL, 0);
+					  inet_diag_dump_compat, NULL, 0);
 	}
 
 	return inet_diag_get_exact_compat(skb, nlh);
@@ -911,7 +935,18 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 		return -EINVAL;
 
 	if (h->nlmsg_flags & NLM_F_DUMP) {
-		return -EAFNOSUPPORT;
+		if (nlmsg_attrlen(h, hdrlen)) {
+			struct nlattr *attr;
+			attr = nlmsg_find_attr(h, hdrlen,
+					       INET_DIAG_REQ_BYTECODE);
+			if (attr == NULL ||
+			    nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
+			    inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
+				return -EINVAL;
+		}
+
+		return netlink_dump_start(sdiagnl, skb, h,
+					  inet_diag_dump, NULL, 0);
 	}
 
 	return inet_diag_get_exact(skb, h, (struct inet_diag_req *)NLMSG_DATA(h));
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 9/11] inet_diag: Introduce socket family checks
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (6 preceding siblings ...)
  2011-12-06 17:58 ` [PATCH 8/11] inet_diag: Switch the _dump " Pavel Emelyanov
@ 2011-12-06 17:59 ` Pavel Emelyanov
  2011-12-06 17:59 ` [PATCH 10/11] inet_diag: Cleanup type2proto last user Pavel Emelyanov
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:59 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

The new API will specify family to work with. Teach the existing
socket walking code to bypass not interesting ones.

To preserve compatibility with existing behavior the _compat code
sets interesting family to AF_UNSPEC to dump them all.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/ipv4/inet_diag.c |   12 +++++++++++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index d655f0a..f1aaaec 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -743,6 +743,10 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 					continue;
 				}
 
+				if (r->sdiag_family != AF_UNSPEC &&
+						sk->sk_family != r->sdiag_family)
+					goto next_listen;
+
 				if (r->id.idiag_sport != inet->inet_sport &&
 				    r->id.idiag_sport)
 					goto next_listen;
@@ -808,6 +812,9 @@ skip_listen_ht:
 				goto next_normal;
 			if (!(r->idiag_states & (1 << sk->sk_state)))
 				goto next_normal;
+			if (r->sdiag_family != AF_UNSPEC &&
+					sk->sk_family != r->sdiag_family)
+				goto next_normal;
 			if (r->id.idiag_sport != inet->inet_sport &&
 			    r->id.idiag_sport)
 				goto next_normal;
@@ -830,6 +837,9 @@ next_normal:
 
 				if (num < s_num)
 					goto next_dying;
+				if (r->sdiag_family != AF_UNSPEC &&
+						tw->tw_family != r->sdiag_family)
+					goto next_dying;
 				if (r->id.idiag_sport != tw->tw_sport &&
 				    r->id.idiag_sport)
 					goto next_dying;
@@ -873,7 +883,7 @@ static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *c
 	struct nlattr *bc = NULL;
 	int hdrlen = sizeof(struct inet_diag_req_compat);
 
-	req.sdiag_family = rc->idiag_family;
+	req.sdiag_family = AF_UNSPEC; /* compatibility */
 	req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type);
 	req.idiag_ext = rc->idiag_ext;
 	req.idiag_states = rc->idiag_states;
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 10/11] inet_diag: Cleanup type2proto last user
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (7 preceding siblings ...)
  2011-12-06 17:59 ` [PATCH 9/11] inet_diag: Introduce socket family checks Pavel Emelyanov
@ 2011-12-06 17:59 ` Pavel Emelyanov
  2011-12-06 17:59 ` [PATCH 11/11] sock_diag: Move the sock_ code to net/core/ Pavel Emelyanov
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:59 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Now all the code works with sock_diag_req-compatible structs, so it's
possible to stop using the inet_diag_type2proto in inet_csk_diag_fill.
Pass the inet_diag_req into it and use the sdiag_protocol field. At the
same time remove the explicit ext argument, since it's also on the req.

However, this conversion is still required in _compat code, so just move
this routine, not remove.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/ipv4/inet_diag.c |   47 ++++++++++++++++++++++++-----------------------
 1 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index f1aaaec..d5ca77c 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -51,18 +51,6 @@ static struct sock *sdiagnl;
 #define INET_DIAG_PUT(skb, attrtype, attrlen) \
 	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
 
-static inline int inet_diag_type2proto(int type)
-{
-	switch (type) {
-	case TCPDIAG_GETSOCK:
-		return IPPROTO_TCP;
-	case DCCPDIAG_GETSOCK:
-		return IPPROTO_DCCP;
-	default:
-		return 0;
-	}
-}
-
 static DEFINE_MUTEX(inet_diag_table_mutex);
 
 static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
@@ -85,8 +73,8 @@ static inline void inet_diag_unlock_handler(
 }
 
 static int inet_csk_diag_fill(struct sock *sk,
-			      struct sk_buff *skb,
-			      int ext, u32 pid, u32 seq, u16 nlmsg_flags,
+			      struct sk_buff *skb, struct inet_diag_req *req,
+			      u32 pid, u32 seq, u16 nlmsg_flags,
 			      const struct nlmsghdr *unlh)
 {
 	const struct inet_sock *inet = inet_sk(sk);
@@ -97,8 +85,9 @@ static int inet_csk_diag_fill(struct sock *sk,
 	struct inet_diag_meminfo  *minfo = NULL;
 	unsigned char	 *b = skb_tail_pointer(skb);
 	const struct inet_diag_handler *handler;
+	int ext = req->idiag_ext;
 
-	handler = inet_diag_table[inet_diag_type2proto(unlh->nlmsg_type)];
+	handler = inet_diag_table[req->sdiag_protocol];
 	BUG_ON(handler == NULL);
 
 	nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
@@ -198,8 +187,8 @@ nlmsg_failure:
 }
 
 static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
-			       struct sk_buff *skb, int ext, u32 pid,
-			       u32 seq, u16 nlmsg_flags,
+			       struct sk_buff *skb, struct inet_diag_req *req,
+			       u32 pid, u32 seq, u16 nlmsg_flags,
 			       const struct nlmsghdr *unlh)
 {
 	long tmo;
@@ -250,14 +239,14 @@ nlmsg_failure:
 }
 
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
-			int ext, u32 pid, u32 seq, u16 nlmsg_flags,
+			struct inet_diag_req *r, u32 pid, u32 seq, u16 nlmsg_flags,
 			const struct nlmsghdr *unlh)
 {
 	if (sk->sk_state == TCP_TIME_WAIT)
 		return inet_twsk_diag_fill((struct inet_timewait_sock *)sk,
-					   skb, ext, pid, seq, nlmsg_flags,
+					   skb, r, pid, seq, nlmsg_flags,
 					   unlh);
-	return inet_csk_diag_fill(sk, skb, ext, pid, seq, nlmsg_flags, unlh);
+	return inet_csk_diag_fill(sk, skb, r, pid, seq, nlmsg_flags, unlh);
 }
 
 static int inet_diag_get_exact(struct sk_buff *in_skb,
@@ -317,7 +306,7 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
 	if (!rep)
 		goto out;
 
-	err = sk_diag_fill(sk, rep, req->idiag_ext,
+	err = sk_diag_fill(sk, rep, req,
 			   NETLINK_CB(in_skb).pid,
 			   nlh->nlmsg_seq, 0, nlh);
 	if (err < 0) {
@@ -530,7 +519,7 @@ static int inet_csk_diag_dump(struct sock *sk,
 			return 0;
 	}
 
-	return inet_csk_diag_fill(sk, skb, r->idiag_ext,
+	return inet_csk_diag_fill(sk, skb, r,
 				  NETLINK_CB(cb->skb).pid,
 				  cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
 }
@@ -565,7 +554,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 			return 0;
 	}
 
-	return inet_twsk_diag_fill(tw, skb, r->idiag_ext,
+	return inet_twsk_diag_fill(tw, skb, r,
 				   NETLINK_CB(cb->skb).pid,
 				   cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
 }
@@ -876,6 +865,18 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	return __inet_diag_dump(skb, cb, (struct inet_diag_req *)NLMSG_DATA(cb->nlh), bc);
 }
 
+static inline int inet_diag_type2proto(int type)
+{
+	switch (type) {
+	case TCPDIAG_GETSOCK:
+		return IPPROTO_TCP;
+	case DCCPDIAG_GETSOCK:
+		return IPPROTO_DCCP;
+	default:
+		return 0;
+	}
+}
+
 static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh);
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 11/11] sock_diag: Move the sock_ code to net/core/
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (8 preceding siblings ...)
  2011-12-06 17:59 ` [PATCH 10/11] inet_diag: Cleanup type2proto last user Pavel Emelyanov
@ 2011-12-06 17:59 ` Pavel Emelyanov
  2011-12-06 18:02 ` [PATCH] iproute: Use SOCK_DIAG_BY_FAMILY messages Pavel Emelyanov
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 17:59 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

This patch moves the sock_ code from inet_diag.c to generic sock_diag.c
file and provides necessary request_module-s calls and a pointer on
inet_diag_compat dumping routine.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/core/Makefile    |    3 +-
 net/core/sock_diag.c |  150 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/inet_diag.c |  105 ++---------------------------------
 3 files changed, 158 insertions(+), 100 deletions(-)
 create mode 100644 net/core/sock_diag.c

diff --git a/net/core/Makefile b/net/core/Makefile
index c4ecc86..674641b 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -8,7 +8,8 @@ obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
 obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
-			neighbour.o rtnetlink.o utils.o link_watch.o filter.o
+			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
+			sock_diag.o
 
 obj-$(CONFIG_XFRM) += flow.o
 obj-y += net-sysfs.o
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
new file mode 100644
index 0000000..6367ae8
--- /dev/null
+++ b/net/core/sock_diag.c
@@ -0,0 +1,150 @@
+#include <linux/mutex.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+#include <net/net_namespace.h>
+#include <linux/module.h>
+
+#include <linux/inet_diag.h>
+#include <linux/sock_diag.h>
+
+static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
+static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
+static DEFINE_MUTEX(sock_diag_table_mutex);
+
+void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
+{
+	mutex_lock(&sock_diag_table_mutex);
+	inet_rcv_compat = fn;
+	mutex_unlock(&sock_diag_table_mutex);
+}
+EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat);
+
+void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
+{
+	mutex_lock(&sock_diag_table_mutex);
+	inet_rcv_compat = NULL;
+	mutex_unlock(&sock_diag_table_mutex);
+}
+EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
+
+int sock_diag_register(struct sock_diag_handler *hndl)
+{
+	int err = 0;
+
+	if (hndl->family > AF_MAX)
+		return -EINVAL;
+
+	mutex_lock(&sock_diag_table_mutex);
+	if (sock_diag_handlers[hndl->family])
+		err = -EBUSY;
+	else
+		sock_diag_handlers[hndl->family] = hndl;
+	mutex_unlock(&sock_diag_table_mutex);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(sock_diag_register);
+
+void sock_diag_unregister(struct sock_diag_handler *hnld)
+{
+	int family = hnld->family;
+
+	if (family > AF_MAX)
+		return;
+
+	mutex_lock(&sock_diag_table_mutex);
+	BUG_ON(sock_diag_handlers[family] != hnld);
+	sock_diag_handlers[family] = NULL;
+	mutex_unlock(&sock_diag_table_mutex);
+}
+EXPORT_SYMBOL_GPL(sock_diag_unregister);
+
+static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
+{
+	if (sock_diag_handlers[family] == NULL)
+		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
+				NETLINK_SOCK_DIAG, IPPROTO_IP);
+
+	mutex_lock(&sock_diag_table_mutex);
+	return sock_diag_handlers[family];
+}
+
+static inline void sock_diag_unlock_handler(struct sock_diag_handler *h)
+{
+	mutex_unlock(&sock_diag_table_mutex);
+}
+
+static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	int err;
+	struct sock_diag_req *req = NLMSG_DATA(nlh);
+	struct sock_diag_handler *hndl;
+
+	if (nlmsg_len(nlh) < sizeof(*req))
+		return -EINVAL;
+
+	hndl = sock_diag_lock_handler(req->sdiag_family);
+	if (hndl == NULL)
+		err = -ENOENT;
+	else
+		err = hndl->dump(skb, nlh);
+	sock_diag_unlock_handler(hndl);
+
+	return err;
+}
+
+static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	int ret;
+
+	switch (nlh->nlmsg_type) {
+	case TCPDIAG_GETSOCK:
+	case DCCPDIAG_GETSOCK:
+		if (inet_rcv_compat == NULL)
+			request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
+					NETLINK_SOCK_DIAG, IPPROTO_IP);
+
+		mutex_lock(&sock_diag_table_mutex);
+		if (inet_rcv_compat != NULL)
+			ret = inet_rcv_compat(skb, nlh);
+		else
+			ret = -EOPNOTSUPP;
+		mutex_unlock(&sock_diag_table_mutex);
+
+		return ret;
+	case SOCK_DIAG_BY_FAMILY:
+		return __sock_diag_rcv_msg(skb, nlh);
+	default:
+		return -EINVAL;
+	}
+}
+
+static DEFINE_MUTEX(sock_diag_mutex);
+
+static void sock_diag_rcv(struct sk_buff *skb)
+{
+	mutex_lock(&sock_diag_mutex);
+	netlink_rcv_skb(skb, &sock_diag_rcv_msg);
+	mutex_unlock(&sock_diag_mutex);
+}
+
+struct sock *sock_diag_nlsk;
+EXPORT_SYMBOL_GPL(sock_diag_nlsk);
+
+static int __init sock_diag_init(void)
+{
+	sock_diag_nlsk = netlink_kernel_create(&init_net, NETLINK_SOCK_DIAG, 0,
+					sock_diag_rcv, NULL, THIS_MODULE);
+	return sock_diag_nlsk == NULL ? -ENOMEM : 0;
+}
+
+static void __exit sock_diag_exit(void)
+{
+	netlink_kernel_release(sock_diag_nlsk);
+}
+
+module_init(sock_diag_init);
+module_exit(sock_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index d5ca77c..b56b7ba 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -46,8 +46,6 @@ struct inet_diag_entry {
 	u16 userlocks;
 };
 
-static struct sock *sdiagnl;
-
 #define INET_DIAG_PUT(skb, attrtype, attrlen) \
 	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
 
@@ -314,7 +312,7 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
 		kfree_skb(rep);
 		goto out;
 	}
-	err = netlink_unicast(sdiagnl, rep, NETLINK_CB(in_skb).pid,
+	err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid,
 			      MSG_DONTWAIT);
 	if (err > 0)
 		err = 0;
@@ -931,7 +929,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 				return -EINVAL;
 		}
 
-		return netlink_dump_start(sdiagnl, skb, nlh,
+		return netlink_dump_start(sock_diag_nlsk, skb, nlh,
 					  inet_diag_dump_compat, NULL, 0);
 	}
 
@@ -956,7 +954,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 				return -EINVAL;
 		}
 
-		return netlink_dump_start(sdiagnl, skb, h,
+		return netlink_dump_start(sock_diag_nlsk, skb, h,
 					  inet_diag_dump, NULL, 0);
 	}
 
@@ -973,91 +971,6 @@ static struct sock_diag_handler inet6_diag_handler = {
 	.dump = inet_diag_handler_dump,
 };
 
-static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
-static DEFINE_MUTEX(sock_diag_table_mutex);
-
-int sock_diag_register(struct sock_diag_handler *hndl)
-{
-	int err = 0;
-
-	if (hndl->family > AF_MAX)
-		return -EINVAL;
-
-	mutex_lock(&sock_diag_table_mutex);
-	if (sock_diag_handlers[hndl->family])
-		err = -EBUSY;
-	else
-		sock_diag_handlers[hndl->family] = hndl;
-	mutex_unlock(&sock_diag_table_mutex);
-
-	return err;
-}
-
-void sock_diag_unregister(struct sock_diag_handler *hnld)
-{
-	int family = hnld->family;
-
-	if (family > AF_MAX)
-		return;
-
-	mutex_lock(&sock_diag_table_mutex);
-	BUG_ON(sock_diag_handlers[family] != hnld);
-	sock_diag_handlers[family] = NULL;
-	mutex_unlock(&sock_diag_table_mutex);
-}
-
-static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
-{
-	mutex_lock(&sock_diag_table_mutex);
-	return sock_diag_handlers[family];
-}
-
-static inline void sock_diag_unlock_handler(struct sock_diag_handler *h)
-{
-	mutex_unlock(&sock_diag_table_mutex);
-}
-
-static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
-{
-	int err;
-	struct sock_diag_req *req = NLMSG_DATA(nlh);
-	struct sock_diag_handler *hndl;
-
-	if (nlmsg_len(nlh) < sizeof(*req))
-		return -EINVAL;
-
-	hndl = sock_diag_lock_handler(req->sdiag_family);
-	if (hndl == NULL)
-		err = -ENOENT;
-	else
-		err = hndl->dump(skb, nlh);
-	sock_diag_unlock_handler(hndl);
-
-	return err;
-}
-
-static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
-{
-	switch (nlh->nlmsg_type) {
-	case TCPDIAG_GETSOCK:
-	case DCCPDIAG_GETSOCK:
-		return inet_diag_rcv_msg_compat(skb, nlh);
-	case SOCK_DIAG_BY_FAMILY:
-		return __sock_diag_rcv_msg(skb, nlh);
-	default:
-		return -EINVAL;
-	}
-}
-
-static DEFINE_MUTEX(sock_diag_mutex);
-
-static void sock_diag_rcv(struct sk_buff *skb)
-{
-	mutex_lock(&sock_diag_mutex);
-	netlink_rcv_skb(skb, &sock_diag_rcv_msg);
-	mutex_unlock(&sock_diag_mutex);
-}
-
 int inet_diag_register(const struct inet_diag_handler *h)
 {
 	const __u16 type = h->idiag_type;
@@ -1101,11 +1014,6 @@ static int __init inet_diag_init(void)
 	if (!inet_diag_table)
 		goto out;
 
-	sdiagnl = netlink_kernel_create(&init_net, NETLINK_SOCK_DIAG, 0,
-					sock_diag_rcv, NULL, THIS_MODULE);
-	if (sdiagnl == NULL)
-		goto out_free_table;
-
 	err = sock_diag_register(&inet_diag_handler);
 	if (err)
 		goto out_free_nl;
@@ -1114,14 +1022,13 @@ static int __init inet_diag_init(void)
 	if (err)
 		goto out_free_inet;
 
+	sock_diag_register_inet_compat(inet_diag_rcv_msg_compat);
 out:
 	return err;
 
 out_free_inet:
 	sock_diag_unregister(&inet_diag_handler);
 out_free_nl:
-	netlink_kernel_release(sdiagnl);
-out_free_table:
 	kfree(inet_diag_table);
 	goto out;
 }
@@ -1130,11 +1037,11 @@ static void __exit inet_diag_exit(void)
 {
 	sock_diag_unregister(&inet6_diag_handler);
 	sock_diag_unregister(&inet_diag_handler);
-	netlink_kernel_release(sdiagnl);
+	sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat);
 	kfree(inet_diag_table);
 }
 
 module_init(inet_diag_init);
 module_exit(inet_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 0);
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH] iproute: Use SOCK_DIAG_BY_FAMILY messages
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (9 preceding siblings ...)
  2011-12-06 17:59 ` [PATCH 11/11] sock_diag: Move the sock_ code to net/core/ Pavel Emelyanov
@ 2011-12-06 18:02 ` Pavel Emelyanov
  2012-01-20 21:05   ` Stephen Hemminger
       [not found] ` <4EDE5797.6010603@parallels.com>
  2011-12-06 18:58 ` [PATCH 0/11] Generalize the inet_diag infrastructure David Miller
  12 siblings, 1 reply; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 18:02 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Applies to cd72dcf13c8a4948ee5706794714287eeff62c90 commit of the
git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git tree

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index de6f1fc..7b6113a 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -6,6 +6,7 @@
 /* Just some random number */
 #define TCPDIAG_GETSOCK 18
 #define DCCPDIAG_GETSOCK 19
+#define SOCK_DIAG_BY_FAMILY 20
 
 #define INET_DIAG_GETSOCK_MAX 24
 
@@ -22,7 +23,7 @@ struct inet_diag_sockid {
 
 /* Request structure */
 
-struct inet_diag_req {
+struct inet_diag_req_compat {
 	__u8	idiag_family;		/* Family of addresses. */
 	__u8	idiag_src_len;
 	__u8	idiag_dst_len;
@@ -34,6 +35,15 @@ struct inet_diag_req {
 	__u32	idiag_dbs;		/* Tables to dump (NI) */
 };
 
+struct inet_diag_req {
+	__u8	sdiag_family;
+	__u8	sdiag_protocol;
+	__u8	idiag_ext;
+	__u8	pad;
+	__u32	idiag_states;
+	struct inet_diag_sockid id;
+};
+
 enum {
 	INET_DIAG_REQ_NONE,
 	INET_DIAG_REQ_BYTECODE,
diff --git a/misc/ss.c b/misc/ss.c
index 5ce40c0..49afd4a 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -1474,7 +1474,7 @@ static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
 	return 0;
 }
 
-static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
+static int __tcp_show_netlink(struct filter *f, FILE *dump_fp, int family, int socktype)
 {
 	int fd;
 	struct sockaddr_nl nladdr;
@@ -1496,12 +1496,13 @@ static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
 	nladdr.nl_family = AF_NETLINK;
 
 	req.nlh.nlmsg_len = sizeof(req);
-	req.nlh.nlmsg_type = socktype;
+	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
 	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
 	req.nlh.nlmsg_pid = 0;
 	req.nlh.nlmsg_seq = 123456;
 	memset(&req.r, 0, sizeof(req.r));
-	req.r.idiag_family = AF_INET;
+	req.r.sdiag_family = family;
+	req.r.sdiag_protocol = socktype;
 	req.r.idiag_states = f->states;
 	if (show_mem)
 		req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
@@ -1589,10 +1590,6 @@ static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
 				return 0;
 			}
 			if (!dump_fp) {
-				if (!(f->families & (1<<r->idiag_family))) {
-					h = NLMSG_NEXT(h, status);
-					continue;
-				}
 				err = tcp_show_sock(h, NULL);
 				if (err < 0)
 					return err;
@@ -1613,6 +1610,18 @@ skip_it:
 	return 0;
 }
 
+static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
+{
+	int err = 0;
+
+	if (f->families & (1 << AF_INET))
+		err |= __tcp_show_netlink(f, dump_fp, AF_INET, socktype);
+	if (f->families & (1 << AF_INET6))
+		err |= __tcp_show_netlink(f, dump_fp, AF_INET6, socktype);
+
+	return err;
+}
+
 static int tcp_show_netlink_file(struct filter *f)
 {
 	FILE	*fp;
@@ -2789,7 +2798,7 @@ int main(int argc, char *argv[])
 				exit(-1);
 			}
 		}
-		tcp_show_netlink(&current_filter, dump_fp, TCPDIAG_GETSOCK);
+		tcp_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
 		fflush(dump_fp);
 		exit(0);
 	}
@@ -2857,8 +2866,8 @@ int main(int argc, char *argv[])
 	if (current_filter.dbs & (1<<UDP_DB))
 		udp_show(&current_filter);
 	if (current_filter.dbs & (1<<TCP_DB))
-		tcp_show(&current_filter, TCPDIAG_GETSOCK);
+		tcp_show(&current_filter, IPPROTO_TCP);
 	if (current_filter.dbs & (1<<DCCP_DB))
-		tcp_show(&current_filter, DCCPDIAG_GETSOCK);
+		tcp_show(&current_filter, IPPROTO_DCCP);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/11] inet_diag: Switch from _GETSOCK to IPPROTO_ numbers
       [not found] ` <4EDE5797.6010603@parallels.com>
@ 2011-12-06 18:05   ` Pavel Emelyanov
  0 siblings, 0 replies; 17+ messages in thread
From: Pavel Emelyanov @ 2011-12-06 18:05 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Sorry, but the vger didn't let this message go to the list. Re-sending it with
less spam-filter-prone subject.



When dumping the AF_INET/AF_INET6 sockets user will also specify the protocol,
so prepare the protocol diag handlers to work with IPPROTO_ constants.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/dccp/diag.c      |    4 ++--
 net/ipv4/inet_diag.c |   34 +++++++++++++++++++++++-----------
 net/ipv4/tcp_diag.c  |    4 ++--
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/net/dccp/diag.c b/net/dccp/diag.c
index d92ba7d..424dcd8 100644
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -51,7 +51,7 @@ static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 static const struct inet_diag_handler dccp_diag_handler = {
 	.idiag_hashinfo	 = &dccp_hashinfo,
 	.idiag_get_info	 = dccp_diag_get_info,
-	.idiag_type	 = DCCPDIAG_GETSOCK,
+	.idiag_type	 = IPPROTO_DCCP,
 	.idiag_info_size = sizeof(struct tcp_info),
 };
 
@@ -71,4 +71,4 @@ module_exit(dccp_diag_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP inet_diag handler");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, DCCPDIAG_GETSOCK);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 33);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index a406caf..cf8be3e 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -50,19 +50,31 @@ static struct sock *sdiagnl;
 #define INET_DIAG_PUT(skb, attrtype, attrlen) \
 	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
 
+static inline int inet_diag_type2proto(int type)
+{
+	switch (type) {
+	case TCPDIAG_GETSOCK:
+		return IPPROTO_TCP;
+	case DCCPDIAG_GETSOCK:
+		return IPPROTO_DCCP;
+	default:
+		return 0;
+	}
+}
+
 static DEFINE_MUTEX(inet_diag_table_mutex);
 
-static const struct inet_diag_handler *inet_diag_lock_handler(int type)
+static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
 {
-	if (!inet_diag_table[type])
+	if (!inet_diag_table[proto])
 		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-			       NETLINK_SOCK_DIAG, type);
+			       NETLINK_SOCK_DIAG, proto);
 
 	mutex_lock(&inet_diag_table_mutex);
-	if (!inet_diag_table[type])
+	if (!inet_diag_table[proto])
 		return ERR_PTR(-ENOENT);
 
-	return inet_diag_table[type];
+	return inet_diag_table[proto];
 }
 
 static inline void inet_diag_unlock_handler(
@@ -85,7 +97,7 @@ static int inet_csk_diag_fill(struct sock *sk,
 	unsigned char	 *b = skb_tail_pointer(skb);
 	const struct inet_diag_handler *handler;
 
-	handler = inet_diag_table[unlh->nlmsg_type];
+	handler = inet_diag_table[inet_diag_type2proto(unlh->nlmsg_type)];
 	BUG_ON(handler == NULL);
 
 	nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
@@ -257,7 +269,7 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
 	struct inet_hashinfo *hashinfo;
 	const struct inet_diag_handler *handler;
 
-	handler = inet_diag_lock_handler(nlh->nlmsg_type);
+	handler = inet_diag_lock_handler(inet_diag_type2proto(nlh->nlmsg_type));
 	if (IS_ERR(handler)) {
 		err = PTR_ERR(handler);
 		goto unlock;
@@ -707,7 +719,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	if (nlmsg_attrlen(cb->nlh, sizeof(struct inet_diag_req)))
 		bc = nlmsg_find_attr(cb->nlh, sizeof(*r), INET_DIAG_REQ_BYTECODE);
 
-	handler = inet_diag_lock_handler(cb->nlh->nlmsg_type);
+	handler = inet_diag_lock_handler(inet_diag_type2proto(cb->nlh->nlmsg_type));
 	if (IS_ERR(handler))
 		goto unlock;
 
@@ -907,7 +919,7 @@ int inet_diag_register(const struct inet_diag_handler *h)
 	const __u16 type = h->idiag_type;
 	int err = -EINVAL;
 
-	if (type >= INET_DIAG_GETSOCK_MAX)
+	if (type >= IPPROTO_MAX)
 		goto out;
 
 	mutex_lock(&inet_diag_table_mutex);
@@ -926,7 +938,7 @@ void inet_diag_unregister(const struct inet_diag_handler *h)
 {
 	const __u16 type = h->idiag_type;
 
-	if (type >= INET_DIAG_GETSOCK_MAX)
+	if (type >= IPPROTO_MAX)
 		return;
 
 	mutex_lock(&inet_diag_table_mutex);
@@ -937,7 +949,7 @@ EXPORT_SYMBOL_GPL(inet_diag_unregister);
 
 static int __init inet_diag_init(void)
 {
-	const int inet_diag_table_size = (INET_DIAG_GETSOCK_MAX *
+	const int inet_diag_table_size = (IPPROTO_MAX *
 					  sizeof(struct inet_diag_handler *));
 	int err = -ENOMEM;
 
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 9e276b8..9814977 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -37,7 +37,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 static const struct inet_diag_handler tcp_diag_handler = {
 	.idiag_hashinfo	 = &tcp_hashinfo,
 	.idiag_get_info	 = tcp_diag_get_info,
-	.idiag_type	 = TCPDIAG_GETSOCK,
+	.idiag_type	 = IPPROTO_TCP,
 	.idiag_info_size = sizeof(struct tcp_info),
 };
 
@@ -54,4 +54,4 @@ static void __exit tcp_diag_exit(void)
 module_init(tcp_diag_init);
 module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, TCPDIAG_GETSOCK);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 6);
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 1/11] inet_diag: Partly rename inet_ to sock_
  2011-12-06 17:56 ` [PATCH 1/11] inet_diag: Partly rename inet_ to sock_ Pavel Emelyanov
@ 2011-12-06 18:24   ` Stephen Hemminger
  2011-12-06 18:42     ` David Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Stephen Hemminger @ 2011-12-06 18:24 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

On Tue, 06 Dec 2011 21:56:43 +0400
Pavel Emelyanov <xemul@parallels.com> wrote:

> diff --git a/include/linux/netlink.h b/include/linux/netlink.h
> index 8374d29..9827ebf 100644
> --- a/include/linux/netlink.h
> +++ b/include/linux/netlink.h
> @@ -8,7 +8,7 @@
>  #define NETLINK_UNUSED		1	/* Unused number				*/
>  #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
>  #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
> -#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
> +#define NETLINK_SOCK_DIAG	4	/* socket monitoring				*/
>  #define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
>  #define NETLINK_XFRM		6	/* ipsec */
>  #define NETLINK_SELINUX		7	/* SELinux event notifications */

This is a header file that is stripped and exported by other
tools. You can add new entries but need to keep existing define's
to avoid breaking source compatibility.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 1/11] inet_diag: Partly rename inet_ to sock_
  2011-12-06 18:24   ` Stephen Hemminger
@ 2011-12-06 18:42     ` David Miller
  0 siblings, 0 replies; 17+ messages in thread
From: David Miller @ 2011-12-06 18:42 UTC (permalink / raw)
  To: shemminger; +Cc: xemul, netdev

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Tue, 6 Dec 2011 10:24:47 -0800

> On Tue, 06 Dec 2011 21:56:43 +0400
> Pavel Emelyanov <xemul@parallels.com> wrote:
> 
>> diff --git a/include/linux/netlink.h b/include/linux/netlink.h
>> index 8374d29..9827ebf 100644
>> --- a/include/linux/netlink.h
>> +++ b/include/linux/netlink.h
>> @@ -8,7 +8,7 @@
>>  #define NETLINK_UNUSED		1	/* Unused number				*/
>>  #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
>>  #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
>> -#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
>> +#define NETLINK_SOCK_DIAG	4	/* socket monitoring				*/
>>  #define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
>>  #define NETLINK_XFRM		6	/* ipsec */
>>  #define NETLINK_SELINUX		7	/* SELinux event notifications */
> 
> This is a header file that is stripped and exported by other
> tools. You can add new entries but need to keep existing define's
> to avoid breaking source compatibility.

Indeed, NETLINK_INET_DIAG must be kept around forever because that's what userland
source code references.

I'll fix this up when applying Pavel's patches, by simply adding a new alias that
userland can start being coverted over to use.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/11] Generalize the inet_diag infrastructure
  2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
                   ` (11 preceding siblings ...)
       [not found] ` <4EDE5797.6010603@parallels.com>
@ 2011-12-06 18:58 ` David Miller
  12 siblings, 0 replies; 17+ messages in thread
From: David Miller @ 2011-12-06 18:58 UTC (permalink / raw)
  To: xemul; +Cc: netdev

From: Pavel Emelyanov <xemul@parallels.com>
Date: Tue, 06 Dec 2011 21:56:10 +0400

> This is an attempt to prepare the existing inet_diag infrastructure to work with
> arbitrary address family and protocol pair, not only AF_INET(6) and TCP/DCCP.
> 
> This set adds the sock_diag infrastructure, that handles the new SOCK_DIAG_BY_FAMILY
> message type by the NETLINK_INET_DIAG socket. The core API struct for this (called
> sock_diag_req) contains two fields - family and type - which specify which sockets 
> to dump. Additional information is considered to be family handler specific.
> 
> The existing inet_diag code is patched to register himself inside the sock_diag and
> provide callbacks for dumping AF_INET/AF_INET6 IPPROTO_TCP/IPPROTO_DCCP sockets. The
> existing API facilities such as state filtering and bytecode is of course preserved
> and is treated by inet_diag specific data.
> 
> Binary compatibility with existing NETLINK_INET_DIAG is also kept.
> 
> No additional stuff in this set. The support for IPPROTO_UDP protocol and AF_UNIX
> family will come later if this set is approved.
> 
> Applies to net-next, patch for iproute2's ss tool (proving that the new code ... pretends
> to work) is at the end of the thread.
> 
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

Applied, with the retention of a NETLINK_INET_DIAG define in patch #1 for
userspace compatability.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] iproute: Use SOCK_DIAG_BY_FAMILY messages
  2011-12-06 18:02 ` [PATCH] iproute: Use SOCK_DIAG_BY_FAMILY messages Pavel Emelyanov
@ 2012-01-20 21:05   ` Stephen Hemminger
  0 siblings, 0 replies; 17+ messages in thread
From: Stephen Hemminger @ 2012-01-20 21:05 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

On Tue, 06 Dec 2011 22:02:00 +0400
Pavel Emelyanov <xemul@parallels.com> wrote:

> Applies to cd72dcf13c8a4948ee5706794714287eeff62c90 commit of the
> git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git tree
> 
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
> 

Rejected since this fails binary compatiablity with older kernels:

./misc/ss -a
State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port   
TCPDIAG answers: Invalid argument
TCPDIAG answers: Invalid argument

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2012-01-20 21:05 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-06 17:56 [PATCH 0/11] Generalize the inet_diag infrastructure Pavel Emelyanov
2011-12-06 17:56 ` [PATCH 1/11] inet_diag: Partly rename inet_ to sock_ Pavel Emelyanov
2011-12-06 18:24   ` Stephen Hemminger
2011-12-06 18:42     ` David Miller
2011-12-06 17:57 ` [PATCH 2/11] sock_diag: Introduce new message type Pavel Emelyanov
2011-12-06 17:57 ` [PATCH 3/11] inet_diag: Move byte-code finding up the call-stack Pavel Emelyanov
2011-12-06 17:58 ` [PATCH 5/11] sock_diag: Initial skeleton Pavel Emelyanov
2011-12-06 17:58 ` [PATCH 6/11] inet_diag: Introduce new inet_diag_req header Pavel Emelyanov
2011-12-06 17:58 ` [PATCH 7/11] inet_diag: Switch the _get_exact to work with new header Pavel Emelyanov
2011-12-06 17:58 ` [PATCH 8/11] inet_diag: Switch the _dump " Pavel Emelyanov
2011-12-06 17:59 ` [PATCH 9/11] inet_diag: Introduce socket family checks Pavel Emelyanov
2011-12-06 17:59 ` [PATCH 10/11] inet_diag: Cleanup type2proto last user Pavel Emelyanov
2011-12-06 17:59 ` [PATCH 11/11] sock_diag: Move the sock_ code to net/core/ Pavel Emelyanov
2011-12-06 18:02 ` [PATCH] iproute: Use SOCK_DIAG_BY_FAMILY messages Pavel Emelyanov
2012-01-20 21:05   ` Stephen Hemminger
     [not found] ` <4EDE5797.6010603@parallels.com>
2011-12-06 18:05   ` [PATCH 4/11] inet_diag: Switch from _GETSOCK to IPPROTO_ numbers Pavel Emelyanov
2011-12-06 18:58 ` [PATCH 0/11] Generalize the inet_diag infrastructure David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).