OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [tags/] [linux-2.6/] [linux-2.6.24_or32_unified_v2.3/] [net/] [ipv4/] [tcp_probe.c] - Blame information for rev 8

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * tcpprobe - Observe the TCP 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
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 */
20
 
21
#include <linux/kernel.h>
22
#include <linux/kprobes.h>
23
#include <linux/socket.h>
24
#include <linux/tcp.h>
25
#include <linux/proc_fs.h>
26
#include <linux/module.h>
27
#include <linux/ktime.h>
28
#include <linux/time.h>
29
#include <net/net_namespace.h>
30
 
31
#include <net/tcp.h>
32
 
33
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
34
MODULE_DESCRIPTION("TCP cwnd snooper");
35
MODULE_LICENSE("GPL");
36
MODULE_VERSION("1.1");
37
 
38
static int port __read_mostly = 0;
39
MODULE_PARM_DESC(port, "Port to match (0=all)");
40
module_param(port, int, 0);
41
 
42
static int bufsize __read_mostly = 4096;
43
MODULE_PARM_DESC(bufsize, "Log buffer size in packets (4096)");
44
module_param(bufsize, int, 0);
45
 
46
static int full __read_mostly;
47
MODULE_PARM_DESC(full, "Full log (1=every ack packet received,  0=only cwnd changes)");
48
module_param(full, int, 0);
49
 
50
static const char procname[] = "tcpprobe";
51
 
52
struct tcp_log {
53
        ktime_t tstamp;
54
        __be32  saddr, daddr;
55
        __be16  sport, dport;
56
        u16     length;
57
        u32     snd_nxt;
58
        u32     snd_una;
59
        u32     snd_wnd;
60
        u32     snd_cwnd;
61
        u32     ssthresh;
62
        u32     srtt;
63
};
64
 
65
static struct {
66
        spinlock_t      lock;
67
        wait_queue_head_t wait;
68
        ktime_t         start;
69
        u32             lastcwnd;
70
 
71
        unsigned long   head, tail;
72
        struct tcp_log  *log;
73
} tcp_probe;
74
 
75
 
76
static inline int tcp_probe_used(void)
77
{
78
        return (tcp_probe.head - tcp_probe.tail) % bufsize;
79
}
80
 
81
static inline int tcp_probe_avail(void)
82
{
83
        return bufsize - tcp_probe_used();
84
}
85
 
86
/*
87
 * Hook inserted to be called before each receive packet.
88
 * Note: arguments must match tcp_rcv_established()!
89
 */
90
static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
91
                               struct tcphdr *th, unsigned len)
92
{
93
        const struct tcp_sock *tp = tcp_sk(sk);
94
        const struct inet_sock *inet = inet_sk(sk);
95
 
96
        /* Only update if port matches */
97
        if ((port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port)
98
            && (full || tp->snd_cwnd != tcp_probe.lastcwnd)) {
99
 
100
                spin_lock(&tcp_probe.lock);
101
                /* If log fills, just silently drop */
102
                if (tcp_probe_avail() > 1) {
103
                        struct tcp_log *p = tcp_probe.log + tcp_probe.head;
104
 
105
                        p->tstamp = ktime_get();
106
                        p->saddr = inet->saddr;
107
                        p->sport = inet->sport;
108
                        p->daddr = inet->daddr;
109
                        p->dport = inet->dport;
110
                        p->length = skb->len;
111
                        p->snd_nxt = tp->snd_nxt;
112
                        p->snd_una = tp->snd_una;
113
                        p->snd_cwnd = tp->snd_cwnd;
114
                        p->snd_wnd = tp->snd_wnd;
115
                        p->ssthresh = tcp_current_ssthresh(sk);
116
                        p->srtt = tp->srtt >> 3;
117
 
118
                        tcp_probe.head = (tcp_probe.head + 1) % bufsize;
119
                }
120
                tcp_probe.lastcwnd = tp->snd_cwnd;
121
                spin_unlock(&tcp_probe.lock);
122
 
123
                wake_up(&tcp_probe.wait);
124
        }
125
 
126
        jprobe_return();
127
        return 0;
128
}
129
 
130
static struct jprobe tcp_jprobe = {
131
        .kp = {
132
                .symbol_name    = "tcp_rcv_established",
133
        },
134
        .entry  = jtcp_rcv_established,
135
};
136
 
137
static int tcpprobe_open(struct inode * inode, struct file * file)
138
{
139
        /* Reset (empty) log */
140
        spin_lock_bh(&tcp_probe.lock);
141
        tcp_probe.head = tcp_probe.tail = 0;
142
        tcp_probe.start = ktime_get();
143
        spin_unlock_bh(&tcp_probe.lock);
144
 
145
        return 0;
146
}
147
 
148
static int tcpprobe_sprint(char *tbuf, int n)
149
{
150
        const struct tcp_log *p
151
                = tcp_probe.log + tcp_probe.tail % bufsize;
152
        struct timespec tv
153
                = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start));
154
 
155
        return snprintf(tbuf, n,
156
                        "%lu.%09lu %d.%d.%d.%d:%u %d.%d.%d.%d:%u"
157
                        " %d %#x %#x %u %u %u %u\n",
158
                        (unsigned long) tv.tv_sec,
159
                        (unsigned long) tv.tv_nsec,
160
                        NIPQUAD(p->saddr), ntohs(p->sport),
161
                        NIPQUAD(p->daddr), ntohs(p->dport),
162
                        p->length, p->snd_nxt, p->snd_una,
163
                        p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt);
164
}
165
 
166
static ssize_t tcpprobe_read(struct file *file, char __user *buf,
167
                             size_t len, loff_t *ppos)
168
{
169
        int error = 0, cnt = 0;
170
 
171
        if (!buf || len < 0)
172
                return -EINVAL;
173
 
174
        while (cnt < len) {
175
                char tbuf[128];
176
                int width;
177
 
178
                /* Wait for data in buffer */
179
                error = wait_event_interruptible(tcp_probe.wait,
180
                                                 tcp_probe_used() > 0);
181
                if (error)
182
                        break;
183
 
184
                spin_lock_bh(&tcp_probe.lock);
185
                if (tcp_probe.head == tcp_probe.tail) {
186
                        /* multiple readers race? */
187
                        spin_unlock_bh(&tcp_probe.lock);
188
                        continue;
189
                }
190
 
191
                width = tcpprobe_sprint(tbuf, sizeof(tbuf));
192
 
193
                if (width < len)
194
                        tcp_probe.tail = (tcp_probe.tail + 1) % bufsize;
195
 
196
                spin_unlock_bh(&tcp_probe.lock);
197
 
198
                /* if record greater than space available
199
                   return partial buffer (so far) */
200
                if (width >= len)
201
                        break;
202
 
203
                error = copy_to_user(buf + cnt, tbuf, width);
204
                if (error)
205
                        break;
206
                cnt += width;
207
        }
208
 
209
        return cnt == 0 ? error : cnt;
210
}
211
 
212
static const struct file_operations tcpprobe_fops = {
213
        .owner   = THIS_MODULE,
214
        .open    = tcpprobe_open,
215
        .read    = tcpprobe_read,
216
};
217
 
218
static __init int tcpprobe_init(void)
219
{
220
        int ret = -ENOMEM;
221
 
222
        init_waitqueue_head(&tcp_probe.wait);
223
        spin_lock_init(&tcp_probe.lock);
224
 
225
        if (bufsize < 0)
226
                return -EINVAL;
227
 
228
        tcp_probe.log = kcalloc(sizeof(struct tcp_log), bufsize, GFP_KERNEL);
229
        if (!tcp_probe.log)
230
                goto err0;
231
 
232
        if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &tcpprobe_fops))
233
                goto err0;
234
 
235
        ret = register_jprobe(&tcp_jprobe);
236
        if (ret)
237
                goto err1;
238
 
239
        pr_info("TCP probe registered (port=%d)\n", port);
240
        return 0;
241
 err1:
242
        proc_net_remove(&init_net, procname);
243
 err0:
244
        kfree(tcp_probe.log);
245
        return ret;
246
}
247
module_init(tcpprobe_init);
248
 
249
static __exit void tcpprobe_exit(void)
250
{
251
        proc_net_remove(&init_net, procname);
252
        unregister_jprobe(&tcp_jprobe);
253
        kfree(tcp_probe.log);
254
}
255
module_exit(tcpprobe_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.