aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/Kconfig12
-rw-r--r--net/sctp/Makefile3
-rw-r--r--net/sctp/probe.c213
3 files changed, 228 insertions, 0 deletions
diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig
index 58b3e882a187..126b014eb79b 100644
--- a/net/sctp/Kconfig
+++ b/net/sctp/Kconfig
@@ -37,6 +37,18 @@ menuconfig IP_SCTP
37 37
38if IP_SCTP 38if IP_SCTP
39 39
40config NET_SCTPPROBE
41 tristate "SCTP: Association probing"
42 depends on PROC_FS && KPROBES
43 ---help---
44 This module allows for capturing the changes to SCTP association
45 state in response to incoming packets. It is used for debugging
46 SCTP congestion control algorithms. If you don't understand
47 what was just said, you don't need it: say N.
48
49 To compile this code as a module, choose M here: the
50 module will be called sctp_probe.
51
40config SCTP_DBG_MSG 52config SCTP_DBG_MSG
41 bool "SCTP: Debug messages" 53 bool "SCTP: Debug messages"
42 help 54 help
diff --git a/net/sctp/Makefile b/net/sctp/Makefile
index 6b794734380a..5c30b7a873df 100644
--- a/net/sctp/Makefile
+++ b/net/sctp/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_IP_SCTP) += sctp.o 5obj-$(CONFIG_IP_SCTP) += sctp.o
6obj-$(CONFIG_NET_SCTPPROBE) += sctp_probe.o
6 7
7sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ 8sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
8 protocol.o endpointola.o associola.o \ 9 protocol.o endpointola.o associola.o \
@@ -11,6 +12,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
11 tsnmap.o bind_addr.o socket.o primitive.o \ 12 tsnmap.o bind_addr.o socket.o primitive.o \
12 output.o input.o debug.o ssnmap.o auth.o 13 output.o input.o debug.o ssnmap.o auth.o
13 14
15sctp_probe-y := probe.o
16
14sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o 17sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o
15sctp-$(CONFIG_PROC_FS) += proc.o 18sctp-$(CONFIG_PROC_FS) += proc.o
16sctp-$(CONFIG_SYSCTL) += sysctl.o 19sctp-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/sctp/probe.c b/net/sctp/probe.c
new file mode 100644
index 000000000000..8f025d5831aa
--- /dev/null
+++ b/net/sctp/probe.c
@@ -0,0 +1,213 @@
1/*
2 * sctp_probe - Observe the SCTP flow with kprobes.
3 *
4 * The idea for this came from Werner Almesberger's umlsim
5 * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
6 *
7 * Modified for SCTP from Stephen Hemminger's code
8 * Copyright (C) 2010, Wei Yongjun <yjwei@cn.fujitsu.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#include <linux/kernel.h>
26#include <linux/kprobes.h>
27#include <linux/socket.h>
28#include <linux/sctp.h>
29#include <linux/proc_fs.h>
30#include <linux/module.h>
31#include <linux/kfifo.h>
32#include <linux/time.h>
33#include <net/net_namespace.h>
34
35#include <net/sctp/sctp.h>
36#include <net/sctp/sm.h>
37
38MODULE_AUTHOR("Wei Yongjun <yjwei@cn.fujitsu.com>");
39MODULE_DESCRIPTION("SCTP snooper");
40MODULE_LICENSE("GPL");
41
42static int port __read_mostly = 0;
43MODULE_PARM_DESC(port, "Port to match (0=all)");
44module_param(port, int, 0);
45
46static int bufsize __read_mostly = 64 * 1024;
47MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
48module_param(bufsize, int, 0);
49
50static int full __read_mostly = 1;
51MODULE_PARM_DESC(full, "Full log (1=every ack packet received, 0=only cwnd changes)");
52module_param(full, int, 0);
53
54static const char procname[] = "sctpprobe";
55
56static struct {
57 struct kfifo fifo;
58 spinlock_t lock;
59 wait_queue_head_t wait;
60 struct timespec tstart;
61} sctpw;
62
63static void printl(const char *fmt, ...)
64{
65 va_list args;
66 int len;
67 char tbuf[256];
68
69 va_start(args, fmt);
70 len = vscnprintf(tbuf, sizeof(tbuf), fmt, args);
71 va_end(args);
72
73 kfifo_in_locked(&sctpw.fifo, tbuf, len, &sctpw.lock);
74 wake_up(&sctpw.wait);
75}
76
77static int sctpprobe_open(struct inode *inode, struct file *file)
78{
79 kfifo_reset(&sctpw.fifo);
80 getnstimeofday(&sctpw.tstart);
81
82 return 0;
83}
84
85static ssize_t sctpprobe_read(struct file *file, char __user *buf,
86 size_t len, loff_t *ppos)
87{
88 int error = 0, cnt = 0;
89 unsigned char *tbuf;
90
91 if (!buf)
92 return -EINVAL;
93
94 if (len == 0)
95 return 0;
96
97 tbuf = vmalloc(len);
98 if (!tbuf)
99 return -ENOMEM;
100
101 error = wait_event_interruptible(sctpw.wait,
102 kfifo_len(&sctpw.fifo) != 0);
103 if (error)
104 goto out_free;
105
106 cnt = kfifo_out_locked(&sctpw.fifo, tbuf, len, &sctpw.lock);
107 error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0;
108
109out_free:
110 vfree(tbuf);
111
112 return error ? error : cnt;
113}
114
115static const struct file_operations sctpprobe_fops = {
116 .owner = THIS_MODULE,
117 .open = sctpprobe_open,
118 .read = sctpprobe_read,
119};
120
121sctp_disposition_t jsctp_sf_eat_sack(const struct sctp_endpoint *ep,
122 const struct sctp_association *asoc,
123 const sctp_subtype_t type,
124 void *arg,
125 sctp_cmd_seq_t *commands)
126{
127 struct sctp_transport *sp;
128 static __u32 lcwnd = 0;
129 struct timespec now;
130
131 sp = asoc->peer.primary_path;
132
133 if ((full || sp->cwnd != lcwnd) &&
134 (!port || asoc->peer.port == port ||
135 ep->base.bind_addr.port == port)) {
136 lcwnd = sp->cwnd;
137
138 getnstimeofday(&now);
139 now = timespec_sub(now, sctpw.tstart);
140
141 printl("%lu.%06lu ", (unsigned long) now.tv_sec,
142 (unsigned long) now.tv_nsec / NSEC_PER_USEC);
143
144 printl("%p %5d %5d %5d %8d %5d ", asoc,
145 ep->base.bind_addr.port, asoc->peer.port,
146 asoc->pathmtu, asoc->peer.rwnd, asoc->unack_data);
147
148 list_for_each_entry(sp, &asoc->peer.transport_addr_list,
149 transports) {
150 if (sp == asoc->peer.primary_path)
151 printl("*");
152
153 if (sp->ipaddr.sa.sa_family == AF_INET)
154 printl("%pI4 ", &sp->ipaddr.v4.sin_addr);
155 else
156 printl("%pI6 ", &sp->ipaddr.v6.sin6_addr);
157
158 printl("%2u %8u %8u %8u %8u %8u ",
159 sp->state, sp->cwnd, sp->ssthresh,
160 sp->flight_size, sp->partial_bytes_acked,
161 sp->pathmtu);
162 }
163 printl("\n");
164 }
165
166 jprobe_return();
167 return 0;
168}
169
170static struct jprobe sctp_recv_probe = {
171 .kp = {
172 .symbol_name = "sctp_sf_eat_sack_6_2",
173 },
174 .entry = jsctp_sf_eat_sack,
175};
176
177static __init int sctpprobe_init(void)
178{
179 int ret = -ENOMEM;
180
181 init_waitqueue_head(&sctpw.wait);
182 spin_lock_init(&sctpw.lock);
183 if (kfifo_alloc(&sctpw.fifo, bufsize, GFP_KERNEL))
184 return ret;
185
186 if (!proc_net_fops_create(&init_net, procname, S_IRUSR,
187 &sctpprobe_fops))
188 goto free_kfifo;
189
190 ret = register_jprobe(&sctp_recv_probe);
191 if (ret)
192 goto remove_proc;
193
194 pr_info("SCTP probe registered (port=%d)\n", port);
195
196 return 0;
197
198remove_proc:
199 proc_net_remove(&init_net, procname);
200free_kfifo:
201 kfifo_free(&sctpw.fifo);
202 return ret;
203}
204
205static __exit void sctpprobe_exit(void)
206{
207 kfifo_free(&sctpw.fifo);
208 proc_net_remove(&init_net, procname);
209 unregister_jprobe(&sctp_recv_probe);
210}
211
212module_init(sctpprobe_init);
213module_exit(sctpprobe_exit);