aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/time.c1
-rw-r--r--net/ipv4/tcp_probe.c68
2 files changed, 40 insertions, 29 deletions
diff --git a/kernel/time.c b/kernel/time.c
index a1439f421d0b..ba18ec4899bd 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -452,6 +452,7 @@ struct timespec ns_to_timespec(const s64 nsec)
452 452
453 return ts; 453 return ts;
454} 454}
455EXPORT_SYMBOL(ns_to_timespec);
455 456
456/** 457/**
457 * ns_to_timeval - Convert nanoseconds to timeval 458 * ns_to_timeval - Convert nanoseconds to timeval
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 61f406f27294..3938d5dbdf20 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -26,6 +26,8 @@
26#include <linux/proc_fs.h> 26#include <linux/proc_fs.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/kfifo.h> 28#include <linux/kfifo.h>
29#include <linux/ktime.h>
30#include <linux/time.h>
29#include <linux/vmalloc.h> 31#include <linux/vmalloc.h>
30 32
31#include <net/tcp.h> 33#include <net/tcp.h>
@@ -34,43 +36,45 @@ MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
34MODULE_DESCRIPTION("TCP cwnd snooper"); 36MODULE_DESCRIPTION("TCP cwnd snooper");
35MODULE_LICENSE("GPL"); 37MODULE_LICENSE("GPL");
36 38
37static int port = 0; 39static int port __read_mostly = 0;
38MODULE_PARM_DESC(port, "Port to match (0=all)"); 40MODULE_PARM_DESC(port, "Port to match (0=all)");
39module_param(port, int, 0); 41module_param(port, int, 0);
40 42
41static int bufsize = 64*1024; 43static int bufsize __read_mostly = 64*1024;
42MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)"); 44MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
43module_param(bufsize, int, 0); 45module_param(bufsize, int, 0);
44 46
47static int full __read_mostly;
48MODULE_PARM_DESC(full, "Full log (1=every ack packet received, 0=only cwnd changes)");
49module_param(full, int, 0);
50
45static const char procname[] = "tcpprobe"; 51static const char procname[] = "tcpprobe";
46 52
47struct { 53struct {
48 struct kfifo *fifo; 54 struct kfifo *fifo;
49 spinlock_t lock; 55 spinlock_t lock;
50 wait_queue_head_t wait; 56 wait_queue_head_t wait;
51 struct timeval tstart; 57 ktime_t start;
58 u32 lastcwnd;
52} tcpw; 59} tcpw;
53 60
61/*
62 * Print to log with timestamps.
63 * FIXME: causes an extra copy
64 */
54static void printl(const char *fmt, ...) 65static void printl(const char *fmt, ...)
55{ 66{
56 va_list args; 67 va_list args;
57 int len; 68 int len;
58 struct timeval now; 69 struct timespec tv;
59 char tbuf[256]; 70 char tbuf[256];
60 71
61 va_start(args, fmt); 72 va_start(args, fmt);
62 do_gettimeofday(&now); 73 /* want monotonic time since start of tcp_probe */
74 tv = ktime_to_timespec(ktime_sub(ktime_get(), tcpw.start));
63 75
64 now.tv_sec -= tcpw.tstart.tv_sec; 76 len = sprintf(tbuf, "%lu.%09lu ",
65 now.tv_usec -= tcpw.tstart.tv_usec; 77 (unsigned long) tv.tv_sec, (unsigned long) tv.tv_nsec);
66 if (now.tv_usec < 0) {
67 --now.tv_sec;
68 now.tv_usec += 1000000;
69 }
70
71 len = sprintf(tbuf, "%lu.%06lu ",
72 (unsigned long) now.tv_sec,
73 (unsigned long) now.tv_usec);
74 len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args); 78 len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
75 va_end(args); 79 va_end(args);
76 80
@@ -78,38 +82,44 @@ static void printl(const char *fmt, ...)
78 wake_up(&tcpw.wait); 82 wake_up(&tcpw.wait);
79} 83}
80 84
81static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk, 85/*
82 struct msghdr *msg, size_t size) 86 * Hook inserted to be called before each receive packet.
87 * Note: arguments must match tcp_rcv_established()!
88 */
89static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
90 struct tcphdr *th, unsigned len)
83{ 91{
84 const struct tcp_sock *tp = tcp_sk(sk); 92 const struct tcp_sock *tp = tcp_sk(sk);
85 const struct inet_sock *inet = inet_sk(sk); 93 const struct inet_sock *inet = inet_sk(sk);
86 94
87 if (port == 0 || ntohs(inet->dport) == port || 95 /* Only update if port matches */
88 ntohs(inet->sport) == port) { 96 if ((port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port)
97 && (full || tp->snd_cwnd != tcpw.lastcwnd)) {
89 printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %#x %#x %u %u %u\n", 98 printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %#x %#x %u %u %u\n",
90 NIPQUAD(inet->saddr), ntohs(inet->sport), 99 NIPQUAD(inet->saddr), ntohs(inet->sport),
91 NIPQUAD(inet->daddr), ntohs(inet->dport), 100 NIPQUAD(inet->daddr), ntohs(inet->dport),
92 size, tp->snd_nxt, tp->snd_una, 101 skb->len, tp->snd_nxt, tp->snd_una,
93 tp->snd_cwnd, tcp_current_ssthresh(sk), 102 tp->snd_cwnd, tcp_current_ssthresh(sk),
94 tp->snd_wnd); 103 tp->snd_wnd, tp->srtt >> 3);
104 tcpw.lastcwnd = tp->snd_cwnd;
95 } 105 }
96 106
97 jprobe_return(); 107 jprobe_return();
98 return 0; 108 return 0;
99} 109}
100 110
101static struct jprobe tcp_send_probe = { 111static struct jprobe tcp_probe = {
102 .kp = { 112 .kp = {
103 .symbol_name = "tcp_sendmsg", 113 .symbol_name = "tcp_rcv_established",
104 }, 114 },
105 .entry = JPROBE_ENTRY(jtcp_sendmsg), 115 .entry = JPROBE_ENTRY(jtcp_rcv_established),
106}; 116};
107 117
108 118
109static int tcpprobe_open(struct inode * inode, struct file * file) 119static int tcpprobe_open(struct inode * inode, struct file * file)
110{ 120{
111 kfifo_reset(tcpw.fifo); 121 kfifo_reset(tcpw.fifo);
112 do_gettimeofday(&tcpw.tstart); 122 tcpw.start = ktime_get();
113 return 0; 123 return 0;
114} 124}
115 125
@@ -162,7 +172,7 @@ static __init int tcpprobe_init(void)
162 if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops)) 172 if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops))
163 goto err0; 173 goto err0;
164 174
165 ret = register_jprobe(&tcp_send_probe); 175 ret = register_jprobe(&tcp_probe);
166 if (ret) 176 if (ret)
167 goto err1; 177 goto err1;
168 178
@@ -180,7 +190,7 @@ static __exit void tcpprobe_exit(void)
180{ 190{
181 kfifo_free(tcpw.fifo); 191 kfifo_free(tcpw.fifo);
182 proc_net_remove(procname); 192 proc_net_remove(procname);
183 unregister_jprobe(&tcp_send_probe); 193 unregister_jprobe(&tcp_probe);
184 194
185} 195}
186module_exit(tcpprobe_exit); 196module_exit(tcpprobe_exit);