diff options
author | GhantaKrishnamurthy MohanKrishna <mohan.krishna.ghanta.krishnamurthy@ericsson.com> | 2018-03-21 09:37:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-03-22 14:43:35 -0400 |
commit | c30b70deb5f4861f590031c33fd3ec6cc63f1df1 (patch) | |
tree | e2c0d01bb5f748d9674e962f71c536c1ae03f0e5 /net/tipc | |
parent | dfde331e757fd792e1c9579b72a8370ca665e5ed (diff) |
tipc: implement socket diagnostics for AF_TIPC
This commit adds socket diagnostics capability for AF_TIPC in netlink
family NETLINK_SOCK_DIAG in a new kernel module (diag.ko).
The following are key design considerations:
- config TIPC_DIAG has default y, like INET_DIAG.
- only requests with flag NLM_F_DUMP is supported (dump all).
- tipc_sock_diag_req message is introduced to send filter parameters.
- the response attributes are of TLV, some nested.
To avoid exposing data structures between diag and tipc modules and
avoid code duplication, the following additions are required:
- export tipc_nl_sk_walk function to reuse socket iterator.
- export tipc_sk_fill_sock_diag to fill the tipc diag attributes.
- create a sock_diag response message in __tipc_add_sock_diag defined
in diag.c and use the above exported tipc_sk_fill_sock_diag
to fill response.
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: GhantaKrishnamurthy MohanKrishna <mohan.krishna.ghanta.krishnamurthy@ericsson.com>
Signed-off-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/Kconfig | 8 | ||||
-rw-r--r-- | net/tipc/Makefile | 5 | ||||
-rw-r--r-- | net/tipc/diag.c | 114 | ||||
-rw-r--r-- | net/tipc/socket.c | 72 | ||||
-rw-r--r-- | net/tipc/socket.h | 10 |
5 files changed, 203 insertions, 6 deletions
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index c25a3a149dc4..e450212121d2 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig | |||
@@ -34,3 +34,11 @@ config TIPC_MEDIA_UDP | |||
34 | Saying Y here will enable support for running TIPC over IP/UDP | 34 | Saying Y here will enable support for running TIPC over IP/UDP |
35 | bool | 35 | bool |
36 | default y | 36 | default y |
37 | |||
38 | config TIPC_DIAG | ||
39 | tristate "TIPC: socket monitoring interface" | ||
40 | depends on TIPC | ||
41 | default y | ||
42 | ---help--- | ||
43 | Support for TIPC socket monitoring interface used by ss tool. | ||
44 | If unsure, say Y. | ||
diff --git a/net/tipc/Makefile b/net/tipc/Makefile index 1edb7192aa2f..aca168f2abb1 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile | |||
@@ -14,3 +14,8 @@ tipc-y += addr.o bcast.o bearer.o \ | |||
14 | tipc-$(CONFIG_TIPC_MEDIA_UDP) += udp_media.o | 14 | tipc-$(CONFIG_TIPC_MEDIA_UDP) += udp_media.o |
15 | tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o | 15 | tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o |
16 | tipc-$(CONFIG_SYSCTL) += sysctl.o | 16 | tipc-$(CONFIG_SYSCTL) += sysctl.o |
17 | |||
18 | |||
19 | obj-$(CONFIG_TIPC_DIAG) += diag.o | ||
20 | |||
21 | tipc_diag-y := diag.o | ||
diff --git a/net/tipc/diag.c b/net/tipc/diag.c new file mode 100644 index 000000000000..46d9cd62f781 --- /dev/null +++ b/net/tipc/diag.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * net/tipc/diag.c: TIPC socket diag | ||
3 | * | ||
4 | * Copyright (c) 2018, Ericsson AB | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * 3. Neither the names of the copyright holders nor the names of its | ||
16 | * contributors may be used to endorse or promote products derived from | ||
17 | * this software without specific prior written permission. | ||
18 | * | ||
19 | * Alternatively, this software may be distributed under the terms of the | ||
20 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
21 | * Software Foundation. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "ASIS" | ||
24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE | ||
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
33 | * POSSIBILITY OF SUCH DAMAGE. | ||
34 | */ | ||
35 | |||
36 | #include "core.h" | ||
37 | #include "socket.h" | ||
38 | #include <linux/sock_diag.h> | ||
39 | #include <linux/tipc_sockets_diag.h> | ||
40 | |||
41 | static u64 __tipc_diag_gen_cookie(struct sock *sk) | ||
42 | { | ||
43 | u32 res[2]; | ||
44 | |||
45 | sock_diag_save_cookie(sk, res); | ||
46 | return *((u64 *)res); | ||
47 | } | ||
48 | |||
49 | static int __tipc_add_sock_diag(struct sk_buff *skb, | ||
50 | struct netlink_callback *cb, | ||
51 | struct tipc_sock *tsk) | ||
52 | { | ||
53 | struct tipc_sock_diag_req *req = nlmsg_data(cb->nlh); | ||
54 | struct nlmsghdr *nlh; | ||
55 | int err; | ||
56 | |||
57 | nlh = nlmsg_put_answer(skb, cb, SOCK_DIAG_BY_FAMILY, 0, | ||
58 | NLM_F_MULTI); | ||
59 | if (!nlh) | ||
60 | return -EMSGSIZE; | ||
61 | |||
62 | err = tipc_sk_fill_sock_diag(skb, tsk, req->tidiag_states, | ||
63 | __tipc_diag_gen_cookie); | ||
64 | if (err) | ||
65 | return err; | ||
66 | |||
67 | nlmsg_end(skb, nlh); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int tipc_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
72 | { | ||
73 | return tipc_nl_sk_walk(skb, cb, __tipc_add_sock_diag); | ||
74 | } | ||
75 | |||
76 | static int tipc_sock_diag_handler_dump(struct sk_buff *skb, | ||
77 | struct nlmsghdr *h) | ||
78 | { | ||
79 | int hdrlen = sizeof(struct tipc_sock_diag_req); | ||
80 | struct net *net = sock_net(skb->sk); | ||
81 | |||
82 | if (nlmsg_len(h) < hdrlen) | ||
83 | return -EINVAL; | ||
84 | |||
85 | if (h->nlmsg_flags & NLM_F_DUMP) { | ||
86 | struct netlink_dump_control c = { | ||
87 | .dump = tipc_diag_dump, | ||
88 | }; | ||
89 | netlink_dump_start(net->diag_nlsk, skb, h, &c); | ||
90 | return 0; | ||
91 | } | ||
92 | return -EOPNOTSUPP; | ||
93 | } | ||
94 | |||
95 | static const struct sock_diag_handler tipc_sock_diag_handler = { | ||
96 | .family = AF_TIPC, | ||
97 | .dump = tipc_sock_diag_handler_dump, | ||
98 | }; | ||
99 | |||
100 | static int __init tipc_diag_init(void) | ||
101 | { | ||
102 | return sock_diag_register(&tipc_sock_diag_handler); | ||
103 | } | ||
104 | |||
105 | static void __exit tipc_diag_exit(void) | ||
106 | { | ||
107 | sock_diag_unregister(&tipc_sock_diag_handler); | ||
108 | } | ||
109 | |||
110 | module_init(tipc_diag_init); | ||
111 | module_exit(tipc_diag_exit); | ||
112 | |||
113 | MODULE_LICENSE("Dual BSD/GPL"); | ||
114 | MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, AF_TIPC); | ||
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 35ac0f5b9529..07559ce4b8ba 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -3213,10 +3213,10 @@ msg_cancel: | |||
3213 | return -EMSGSIZE; | 3213 | return -EMSGSIZE; |
3214 | } | 3214 | } |
3215 | 3215 | ||
3216 | static int __tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb, | 3216 | int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb, |
3217 | int (*skb_handler)(struct sk_buff *skb, | 3217 | int (*skb_handler)(struct sk_buff *skb, |
3218 | struct netlink_callback *cb, | 3218 | struct netlink_callback *cb, |
3219 | struct tipc_sock *tsk)) | 3219 | struct tipc_sock *tsk)) |
3220 | { | 3220 | { |
3221 | struct net *net = sock_net(skb->sk); | 3221 | struct net *net = sock_net(skb->sk); |
3222 | struct tipc_net *tn = tipc_net(net); | 3222 | struct tipc_net *tn = tipc_net(net); |
@@ -3255,10 +3255,72 @@ out: | |||
3255 | 3255 | ||
3256 | return skb->len; | 3256 | return skb->len; |
3257 | } | 3257 | } |
3258 | EXPORT_SYMBOL(tipc_nl_sk_walk); | ||
3259 | |||
3260 | int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct tipc_sock *tsk, | ||
3261 | u32 sk_filter_state, | ||
3262 | u64 (*tipc_diag_gen_cookie)(struct sock *sk)) | ||
3263 | { | ||
3264 | struct sock *sk = &tsk->sk; | ||
3265 | struct nlattr *attrs; | ||
3266 | struct nlattr *stat; | ||
3267 | |||
3268 | /*filter response w.r.t sk_state*/ | ||
3269 | if (!(sk_filter_state & (1 << sk->sk_state))) | ||
3270 | return 0; | ||
3271 | |||
3272 | attrs = nla_nest_start(skb, TIPC_NLA_SOCK); | ||
3273 | if (!attrs) | ||
3274 | goto msg_cancel; | ||
3275 | |||
3276 | if (__tipc_nl_add_sk_info(skb, tsk)) | ||
3277 | goto attr_msg_cancel; | ||
3278 | |||
3279 | if (nla_put_u32(skb, TIPC_NLA_SOCK_TYPE, (u32)sk->sk_type) || | ||
3280 | nla_put_u32(skb, TIPC_NLA_SOCK_TIPC_STATE, (u32)sk->sk_state) || | ||
3281 | nla_put_u32(skb, TIPC_NLA_SOCK_INO, sock_i_ino(sk)) || | ||
3282 | nla_put_u32(skb, TIPC_NLA_SOCK_UID, | ||
3283 | from_kuid_munged(sk_user_ns(sk), sock_i_uid(sk))) || | ||
3284 | nla_put_u64_64bit(skb, TIPC_NLA_SOCK_COOKIE, | ||
3285 | tipc_diag_gen_cookie(sk), | ||
3286 | TIPC_NLA_SOCK_PAD)) | ||
3287 | goto attr_msg_cancel; | ||
3288 | |||
3289 | stat = nla_nest_start(skb, TIPC_NLA_SOCK_STAT); | ||
3290 | if (!stat) | ||
3291 | goto attr_msg_cancel; | ||
3292 | |||
3293 | if (nla_put_u32(skb, TIPC_NLA_SOCK_STAT_RCVQ, | ||
3294 | skb_queue_len(&sk->sk_receive_queue)) || | ||
3295 | nla_put_u32(skb, TIPC_NLA_SOCK_STAT_SENDQ, | ||
3296 | skb_queue_len(&sk->sk_write_queue))) | ||
3297 | goto stat_msg_cancel; | ||
3298 | |||
3299 | if (tsk->cong_link_cnt && | ||
3300 | nla_put_flag(skb, TIPC_NLA_SOCK_STAT_LINK_CONG)) | ||
3301 | goto stat_msg_cancel; | ||
3302 | |||
3303 | if (tsk_conn_cong(tsk) && | ||
3304 | nla_put_flag(skb, TIPC_NLA_SOCK_STAT_CONN_CONG)) | ||
3305 | goto stat_msg_cancel; | ||
3306 | |||
3307 | nla_nest_end(skb, stat); | ||
3308 | nla_nest_end(skb, attrs); | ||
3309 | |||
3310 | return 0; | ||
3311 | |||
3312 | stat_msg_cancel: | ||
3313 | nla_nest_cancel(skb, stat); | ||
3314 | attr_msg_cancel: | ||
3315 | nla_nest_cancel(skb, attrs); | ||
3316 | msg_cancel: | ||
3317 | return -EMSGSIZE; | ||
3318 | } | ||
3319 | EXPORT_SYMBOL(tipc_sk_fill_sock_diag); | ||
3258 | 3320 | ||
3259 | int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb) | 3321 | int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb) |
3260 | { | 3322 | { |
3261 | return __tipc_nl_sk_walk(skb, cb, __tipc_nl_add_sk); | 3323 | return tipc_nl_sk_walk(skb, cb, __tipc_nl_add_sk); |
3262 | } | 3324 | } |
3263 | 3325 | ||
3264 | /* Caller should hold socket lock for the passed tipc socket. */ | 3326 | /* Caller should hold socket lock for the passed tipc socket. */ |
diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 06fb5944cf76..aae3fd4cd06c 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h | |||
@@ -49,6 +49,8 @@ | |||
49 | #define RCVBUF_DEF (FLOWCTL_BLK_SZ * 1024 * 2) | 49 | #define RCVBUF_DEF (FLOWCTL_BLK_SZ * 1024 * 2) |
50 | #define RCVBUF_MAX (FLOWCTL_BLK_SZ * 1024 * 16) | 50 | #define RCVBUF_MAX (FLOWCTL_BLK_SZ * 1024 * 16) |
51 | 51 | ||
52 | struct tipc_sock; | ||
53 | |||
52 | int tipc_socket_init(void); | 54 | int tipc_socket_init(void); |
53 | void tipc_socket_stop(void); | 55 | void tipc_socket_stop(void); |
54 | void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); | 56 | void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); |
@@ -59,5 +61,11 @@ int tipc_sk_rht_init(struct net *net); | |||
59 | void tipc_sk_rht_destroy(struct net *net); | 61 | void tipc_sk_rht_destroy(struct net *net); |
60 | int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb); | 62 | int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb); |
61 | int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb); | 63 | int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb); |
62 | 64 | int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct tipc_sock *tsk, | |
65 | u32 sk_filter_state, | ||
66 | u64 (*tipc_diag_gen_cookie)(struct sock *sk)); | ||
67 | int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb, | ||
68 | int (*skb_handler)(struct sk_buff *skb, | ||
69 | struct netlink_callback *cb, | ||
70 | struct tipc_sock *tsk)); | ||
63 | #endif | 71 | #endif |