diff options
author | Andrey Vagin <avagin@openvz.org> | 2012-07-16 00:28:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-17 01:31:34 -0400 |
commit | 51d7cccf07238f5236c5b9269231a30dd5f8e714 (patch) | |
tree | 1155d43b810d0f163276182be610d69c50e862d9 /net/ipv4/inet_diag.c | |
parent | cbc89c8cf279b85edc95b4ae40a9e7e1edf2dfae (diff) |
net: make sock diag per-namespace
Before this patch sock_diag works for init_net only and dumps
information about sockets from all namespaces.
This patch expands sock_diag for all name-spaces.
It creates a netlink kernel socket for each netns and filters
data during dumping.
v2: filter accoding with netns in all places
remove an unused variable.
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Pavel Emelyanov <xemul@parallels.com>
CC: Eric Dumazet <eric.dumazet@gmail.com>
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Andrew Vagin <avagin@openvz.org>
Acked-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/inet_diag.c')
-rw-r--r-- | net/ipv4/inet_diag.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 38064a285cca..570e61f9611f 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
@@ -272,16 +272,17 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s | |||
272 | int err; | 272 | int err; |
273 | struct sock *sk; | 273 | struct sock *sk; |
274 | struct sk_buff *rep; | 274 | struct sk_buff *rep; |
275 | struct net *net = sock_net(in_skb->sk); | ||
275 | 276 | ||
276 | err = -EINVAL; | 277 | err = -EINVAL; |
277 | if (req->sdiag_family == AF_INET) { | 278 | if (req->sdiag_family == AF_INET) { |
278 | sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0], | 279 | sk = inet_lookup(net, hashinfo, req->id.idiag_dst[0], |
279 | req->id.idiag_dport, req->id.idiag_src[0], | 280 | req->id.idiag_dport, req->id.idiag_src[0], |
280 | req->id.idiag_sport, req->id.idiag_if); | 281 | req->id.idiag_sport, req->id.idiag_if); |
281 | } | 282 | } |
282 | #if IS_ENABLED(CONFIG_IPV6) | 283 | #if IS_ENABLED(CONFIG_IPV6) |
283 | else if (req->sdiag_family == AF_INET6) { | 284 | else if (req->sdiag_family == AF_INET6) { |
284 | sk = inet6_lookup(&init_net, hashinfo, | 285 | sk = inet6_lookup(net, hashinfo, |
285 | (struct in6_addr *)req->id.idiag_dst, | 286 | (struct in6_addr *)req->id.idiag_dst, |
286 | req->id.idiag_dport, | 287 | req->id.idiag_dport, |
287 | (struct in6_addr *)req->id.idiag_src, | 288 | (struct in6_addr *)req->id.idiag_src, |
@@ -317,7 +318,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s | |||
317 | nlmsg_free(rep); | 318 | nlmsg_free(rep); |
318 | goto out; | 319 | goto out; |
319 | } | 320 | } |
320 | err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid, | 321 | err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).pid, |
321 | MSG_DONTWAIT); | 322 | MSG_DONTWAIT); |
322 | if (err > 0) | 323 | if (err > 0) |
323 | err = 0; | 324 | err = 0; |
@@ -724,6 +725,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, | |||
724 | { | 725 | { |
725 | int i, num; | 726 | int i, num; |
726 | int s_i, s_num; | 727 | int s_i, s_num; |
728 | struct net *net = sock_net(skb->sk); | ||
727 | 729 | ||
728 | s_i = cb->args[1]; | 730 | s_i = cb->args[1]; |
729 | s_num = num = cb->args[2]; | 731 | s_num = num = cb->args[2]; |
@@ -743,6 +745,9 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, | |||
743 | sk_nulls_for_each(sk, node, &ilb->head) { | 745 | sk_nulls_for_each(sk, node, &ilb->head) { |
744 | struct inet_sock *inet = inet_sk(sk); | 746 | struct inet_sock *inet = inet_sk(sk); |
745 | 747 | ||
748 | if (!net_eq(sock_net(sk), net)) | ||
749 | continue; | ||
750 | |||
746 | if (num < s_num) { | 751 | if (num < s_num) { |
747 | num++; | 752 | num++; |
748 | continue; | 753 | continue; |
@@ -813,6 +818,8 @@ skip_listen_ht: | |||
813 | sk_nulls_for_each(sk, node, &head->chain) { | 818 | sk_nulls_for_each(sk, node, &head->chain) { |
814 | struct inet_sock *inet = inet_sk(sk); | 819 | struct inet_sock *inet = inet_sk(sk); |
815 | 820 | ||
821 | if (!net_eq(sock_net(sk), net)) | ||
822 | continue; | ||
816 | if (num < s_num) | 823 | if (num < s_num) |
817 | goto next_normal; | 824 | goto next_normal; |
818 | if (!(r->idiag_states & (1 << sk->sk_state))) | 825 | if (!(r->idiag_states & (1 << sk->sk_state))) |
@@ -839,6 +846,8 @@ next_normal: | |||
839 | 846 | ||
840 | inet_twsk_for_each(tw, node, | 847 | inet_twsk_for_each(tw, node, |
841 | &head->twchain) { | 848 | &head->twchain) { |
849 | if (!net_eq(twsk_net(tw), net)) | ||
850 | continue; | ||
842 | 851 | ||
843 | if (num < s_num) | 852 | if (num < s_num) |
844 | goto next_dying; | 853 | goto next_dying; |
@@ -943,6 +952,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb, | |||
943 | static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) | 952 | static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) |
944 | { | 953 | { |
945 | int hdrlen = sizeof(struct inet_diag_req); | 954 | int hdrlen = sizeof(struct inet_diag_req); |
955 | struct net *net = sock_net(skb->sk); | ||
946 | 956 | ||
947 | if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX || | 957 | if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX || |
948 | nlmsg_len(nlh) < hdrlen) | 958 | nlmsg_len(nlh) < hdrlen) |
@@ -963,7 +973,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
963 | struct netlink_dump_control c = { | 973 | struct netlink_dump_control c = { |
964 | .dump = inet_diag_dump_compat, | 974 | .dump = inet_diag_dump_compat, |
965 | }; | 975 | }; |
966 | return netlink_dump_start(sock_diag_nlsk, skb, nlh, &c); | 976 | return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); |
967 | } | 977 | } |
968 | } | 978 | } |
969 | 979 | ||
@@ -973,6 +983,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
973 | static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) | 983 | static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) |
974 | { | 984 | { |
975 | int hdrlen = sizeof(struct inet_diag_req_v2); | 985 | int hdrlen = sizeof(struct inet_diag_req_v2); |
986 | struct net *net = sock_net(skb->sk); | ||
976 | 987 | ||
977 | if (nlmsg_len(h) < hdrlen) | 988 | if (nlmsg_len(h) < hdrlen) |
978 | return -EINVAL; | 989 | return -EINVAL; |
@@ -991,7 +1002,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) | |||
991 | struct netlink_dump_control c = { | 1002 | struct netlink_dump_control c = { |
992 | .dump = inet_diag_dump, | 1003 | .dump = inet_diag_dump, |
993 | }; | 1004 | }; |
994 | return netlink_dump_start(sock_diag_nlsk, skb, h, &c); | 1005 | return netlink_dump_start(net->diag_nlsk, skb, h, &c); |
995 | } | 1006 | } |
996 | } | 1007 | } |
997 | 1008 | ||