This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] trace tcp connection parameters


This script (tcp_trace) can be used to trace tcp connection parameters
and state changes.  This work was original inspired by Stephen Hemminger's
TCP cwnd snooper (net/ipv4/tcp_probe.c). Tcp_trace is a helpful tool for
troubleshooting connection performance issues.  I would like to included
tcp_trace in the systemtap examples directory.

Signed-off-by: Varun Chandramohan <varunc@linux.vnet.ibm.com>
Signed-off-by: David Wilder <dwilder@us.ibm.com>
------------------------------------------------------
 .../systemtap.examples/network/tcp_trace.meta      |   14 +
 testsuite/systemtap.examples/network/tcp_trace.stp |  822 ++++++++++++++++++++
 testsuite/systemtap.examples/network/tcp_trace.txt |   24 +
 3 files changed, 860 insertions(+), 0 deletions(-)

diff --git a/testsuite/systemtap.examples/network/tcp_trace.meta b/testsuite/systemtap.examples/network/tcp_trace.meta
new file mode 100644
index 0000000..2783c89
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcp_trace.meta
@@ -0,0 +1,14 @@
+title: Tcp connection tracing utility.
+name: tcp_trace.stp
+version: 1.0
+author: varuncha@in.ibm.com wilder@us.ibm.com
+keywords: network trace
+subsystem: network
+status: production
+exit: user-controlled
+output: timed
+scope: per-socket
+arg_[0-9]+: tcp_trace.stp  filter=all|state|txq|rxq|srtt|snd_cwnd|snd_wnd|rexmit|pmtu|ssthresh|timer|rcvwnd [timeout=<sec>] [update=change|all] Rule
+description: This scripts traces a given tcp connection based on the filter parameters given by the user. The indexing is done by the 4 tuples local address, remote address, local port, remote port.
+test_check: stap -p4 tcp_trace.stp
+test_installcheck: stap tcp_trace.stp 127.0.0.1:*-127.0.0.1:* timeout=1
diff --git a/testsuite/systemtap.examples/network/tcp_trace.stp b/testsuite/systemtap.examples/network/tcp_trace.stp
new file mode 100755
index 0000000..04c2a63
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcp_trace.stp
@@ -0,0 +1,822 @@
+#! /usr/bin/env stap
+/*
+ *	Copyright (C) 2009 IBM Corp.
+ *	This file is part of systemtap, and is free software.  You can
+ *	redistribute it and/or modify it under the terms of the GNU General
+ *	Public License (GPL); either version 2, or (at your option) any
+ *	later version.
+ *
+ *	Version 0.1     wilder@us.ibm.com	2009-05-13
+ *	Version 0.3     varuncha@in.ibm.com	2009-05-20
+ *	Version 1.0	wilder@us.ibm.com	2009-09-24
+ *
+ *	Tcp connection tracing utility.
+ *
+ *	Description:
+ *	This scripts traces a given tcp connection based on the filter
+ *	parameters given by the user. The indexing is done by the 4 tuples
+ *	local address, remote address, local port, remote port.
+ *
+ *	Synopsis:
+ *	tcp_trace.stp	[filter=all|state|txq|rxq|srtt|snd_cwnd|snd_wnd|rexmit\
+ *			|pmtu|ssthresh|timer|rcvwnd] [timeout=<N sec>]\
+ *			[update=change|all]\
+ *	Rule format:
+ *	  <local ip-address>:<local-port>-<remote ip-address>:<remote-port>
+ *
+ *	filter  tcp_trace.stp collects connection information from various 
+ *		probe points. This gives various tcp related parameters.
+ *		However it is not all parameters are needed when debuggin
+ *		a tcp problem. Specifying only required parameters reduces
+ *		analysis time. Multiple parameters can be specified by using
+ *		','.
+ *
+ *	timeout (optional) When a timeout value (in seconds) is specified
+ *		tcpstat will automatically terminate it's run at the end of
+ *		the specified time and produce a report. When timeout is
+ *		omitted the script will run until the user terminates it by
+ *		typing a ^c.
+ *
+ *	update (optional) By default the script only displays data if there
+ *		is a change in the parameters specified in the "filter". This
+ *		can be changed by specifying "all", which will ouput parameters
+ *		of every packet that hits the probe.
+ *
+ *	Rule Format This is used to specify the particular connection being
+ *		traced. Only one connection can be specified at a time.
+ *		However, if needed the local and remote port can be a
+ *		wild-card (*). But the local & remote ip has to be a host ip.
+ *
+ *		The Rule Format is:
+ *		<local-address>:<local-port>-<remote address>:<remote-port>
+ *
+ *		-Address are specified as ipv4 dot notation address.
+ *		-Ports are specified as decimal numbers.
+ *
+ *	Examples:
+ *		Here are some examples of using tcp_trace:
+ *
+ *	Trace TCP connection from 172.16.15.160 to 172.16.15.1 on port 22 with
+ *	state,txq,rxq,pmtu filter
+ *	tcp_trace.stp filter=state,txq,rxq,pmtu timeout=100\
+ *		 172.16.15.160:*-172.16.15.1:22
+ *
+ *	Trace TCP connection from 172.16.15.1 to 172.16.15.160 on port 22 with
+ *	all parameters in filter
+ *	tcp_trace.stp filter=all 172.16.15.160:22-172.16.15.1:*
+ */
+
+global tcp_state;
+global timer_info;
+global filter;
+global key_list;
+global lastkey;
+global tcp_param;
+global timeout;
+global update;
+global count;
+global length;
+global tx_current_timer = 0;
+global rx_current_timer = 0;
+global find_timer = 0;
+global argms;
+global filter_flds = 0;
+global snd_cwnd_flg = 0;
+global snd_wnd_flg = 0;
+global srtt_flg = 0;
+global state_flg = 0;
+global txq_flg = 0;
+global rxq_flg = 0;
+global rexmit_flg = 0;
+global pmtu_flg = 0;
+global ssthresh_flg = 0;
+global timer_flg = 0;
+global rcvwnd_flg = 0;
+
+probe begin {
+	timeout = -1;
+	number_of_filters = process_cmdline()
+
+	if(number_of_filters < 1) {
+		usage("No Connection Parameters Specified")
+	} else if (number_of_filters > 1) {
+		usage("Too many Connection Parameters Specified")
+	}
+	
+	for(i =0; i < count; i++) {
+		if(tcp_param[i] == "snd_cwnd") {
+			snd_cwnd_flg = 1
+		} else if(tcp_param[i] == "snd_wnd") {
+			snd_wnd_flg = 1
+		} else if(tcp_param[i] == "srtt") {
+			srtt_flg = 1;
+		} else if(tcp_param[i] == "state") {
+			state_flg = 1;
+		} else if(tcp_param[i] == "txq") {
+			txq_flg = 1;
+		} else if(tcp_param[i] == "rxq") {
+			rxq_flg = 1;
+		} else if(tcp_param[i] == "rexmit") {
+			rexmit_flg = 1;
+		} else if(tcp_param[i] == "pmtu") {
+			pmtu_flg = 1;
+		} else if(tcp_param[i] == "ssthresh") {
+			ssthresh_flg = 1;
+		} else if(tcp_param[i] == "timer") {
+			timer_flg = 1;
+		} else if(tcp_param[i] == "rcvwnd") {
+			rcvwnd_flg = 1;
+		} else if(tcp_param[i] == "all") {
+			filter_flds = 1;
+		} else {
+			printf("Discard Unknown Filter = %s \n", tcp_param[i]);
+		}
+			
+	}
+
+	if(!(snd_cwnd_flg | snd_wnd_flg | srtt_flg | state_flg | txq_flg |
+		rxq_flg | rexmit_flg | pmtu_flg | ssthresh_flg | timer_flg |
+		rcvwnd_flg))
+		filter_flds = 1
+
+	if(state_flg || filter_flds) {
+		tcp_state[1] = "ESTABLISHED"
+		tcp_state[2] = "SYN_SENT"
+		tcp_state[3] = "SYN_RECV"
+		tcp_state[4] = "FIN_WAIT1"
+		tcp_state[5] = "FIN_WAIT2"
+		tcp_state[6] = "TIME_WAIT"
+		tcp_state[7] = "CLOSE"
+		tcp_state[8] = "CLOSE_WAIT"
+		tcp_state[9] = "LAST_ACK"
+		tcp_state[10] = "LISTEN"
+		tcp_state[11] = "CLOSING"
+	}
+
+	if(timer_flg || filter_flds) {
+		timer_info[1] = "Rxmit"
+		timer_info[2] = "Delack"
+		timer_info[3] = "Probe"
+		timer_info[4] = "Keepalv"
+	}
+		
+	printf("Start TCP Probing.....\n");
+	printf("\n");
+	printf("\nSource Address         Dest Address           State       Len    Tx-Q  Rx-Q  PMTU  SndCwnd SndWnd  A.RWnd SRTT Ssthreshold Rexmit Timer\n");
+}
+
+probe kernel.function("tcp_rcv_established"),
+      kernel.function("tcp_rcv_state_process")
+{
+	sk = $sk
+
+	laddr = tcpmib_local_addr(sk);
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+	length = $skb->len
+
+	if ( filter_key(laddr, raddr, lport, rport, 0) == 0 ) 
+		next;
+
+	if (is_packet_updated(laddr, raddr, lport, rport, 0, sk) == 0)
+		next; 
+
+	print_packet_info(laddr, raddr, lport, rport, 0)
+}
+
+probe kernel.function("tcp_transmit_skb")
+{
+	sk = $sk
+
+	laddr = tcpmib_local_addr(sk);  
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+
+	length = $skb->len
+
+	if ( filter_key(laddr, raddr, lport, rport, 1) == 0 ) 
+		next;
+
+	if (is_packet_updated(laddr, raddr, lport, rport, 1, sk) == 0)
+		next; 
+
+	print_packet_info(laddr, raddr, lport, rport, 1)
+}
+
+probe kernel.function("tcp_keepalive_timer")
+{
+	sk = $data;
+
+	laddr = tcpmib_local_addr(sk);  
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+
+	length = 0
+	tx_current_timer = 4;
+
+        if ( filter_key(laddr, raddr, lport, rport, 1) == 0 )
+                next;
+
+        if (is_packet_updated(laddr, raddr, lport, rport, 1, sk) == 0)
+                next;
+
+	print_packet_info(laddr, raddr, lport, rport, 1)
+}
+
+probe kernel.function("tcp_delack_timer")
+{
+	sk = $data;
+
+	laddr = tcpmib_local_addr(sk);  
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+
+	length = 0
+	tx_current_timer = 2;
+
+        if ( filter_key(laddr, raddr, lport, rport, 1) == 0 )
+                next;
+
+        if (is_packet_updated(laddr, raddr, lport, rport, 1, sk) == 0)
+                next;
+
+	print_packet_info(laddr, raddr, lport, rport, 1)
+}
+
+probe kernel.function("tcp_send_probe0")
+{
+	sk = $sk
+
+	if(find_timer == 3) {
+		tx_current_timer = 3
+		next;
+	}
+
+	laddr = tcpmib_local_addr(sk);  
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+
+	length = 0
+
+        if ( filter_key(laddr, raddr, lport, rport, 1) == 0 )
+                next;
+
+        if (is_packet_updated(laddr, raddr, lport, rport, 1, sk) == 0)
+                next;
+
+	print_packet_info(laddr, raddr, lport, rport, 1)
+}
+
+probe kernel.function("tcp_write_timer")
+{
+	sk = $data
+
+	laddr = tcpmib_local_addr(sk);  
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+
+        if ( filter_key(laddr, raddr, lport, rport, 1) == 0 )
+                next;
+
+	find_timer = @cast(sk, "inet_connection_sock")->icsk_pending
+}
+
+probe kernel.function("tcp_retransmit_skb")
+{
+	sk = $sk;
+
+	if(find_timer == 1) {
+		tx_current_timer = 1
+		next;
+	}
+
+	laddr = tcpmib_local_addr(sk);  
+	raddr = tcpmib_remote_addr(sk);
+	lport = tcpmib_local_port(sk);
+	rport = tcpmib_remote_port(sk);
+
+	length = $skb->len
+
+
+	if ( filter_key(laddr, raddr, lport, rport, 1) == 0 )
+		next;
+
+	if (is_packet_updated(laddr, raddr, lport, rport, 1, sk) == 0)
+		next;
+
+	print_packet_info(laddr, raddr, lport, rport, 1)
+}
+
+function print_packet_info:long (laddr:long, raddr:long, lport:long,
+				 rport:long, flag:long )
+{
+	temp_addr = ip_ntop(htonl(laddr))
+	local_addr = sprintf("%s:%d",temp_addr,lport)
+	temp_addr = ip_ntop(htonl(raddr))
+	remote_addr = sprintf("%s:%d",temp_addr,rport)
+	argms[1] = 5
+	argms[3] = length
+	
+	if(state_flg || filter_flds) {
+		state_val = key_list[laddr, raddr, lport, rport, flag, 1]
+		if(state_val < 1 || state_val > 11) {
+			prnt_state = "UNKNOWN"
+		} else {
+			prnt_state = tcp_state[state_val]
+		}
+	} else {
+		prnt_state = "-"
+	}
+
+	if(txq_flg || filter_flds) { 
+		argms[4] = key_list[laddr, raddr, lport, rport, flag, 2]
+	} else {
+		argms[4] = -1
+	}
+
+	if(rxq_flg || filter_flds) {
+		argms[5] = key_list[laddr, raddr, lport, rport, flag, 3]
+	} else {
+		argms[5] = -1
+	}
+
+	if(rexmit_flg || filter_flds) {
+		argms[12] = key_list[laddr, raddr, lport, rport, flag, 4]
+	} else {
+		argms[12] = -1
+	}
+
+	if(pmtu_flg || filter_flds) {
+		argms[6] = key_list[laddr, raddr, lport, rport, flag, 5]
+	} else {
+		argms[6] = -1
+	}
+
+	if(snd_cwnd_flg || filter_flds) {
+		argms[7] = key_list[laddr, raddr, lport, rport, flag, 6]
+	} else {
+		argms[7] = -1
+	}
+
+	if(snd_wnd_flg || filter_flds) {
+		argms[8] = key_list[laddr, raddr, lport, rport, flag, 7]
+	} else {
+		argms[8] = -1
+	}
+
+	if(srtt_flg || filter_flds) {
+		argms[10] = key_list[laddr, raddr, lport, rport, flag, 8]
+	} else {
+		argms[10] = -1
+	}
+
+	if(ssthresh_flg || filter_flds) {
+		argms[11] = key_list[laddr, raddr, lport, rport, flag, 10]
+	} else {
+		argms[11] = -1
+	}
+
+	if(timer_flg || filter_flds) {
+		timer_val = key_list[laddr, raddr, lport, rport, flag, 11]
+		if(timer_val < 1 || timer_val > 4) {
+			prnt_timer = "N/A"
+		} else {
+			prnt_timer = timer_info[timer_val]
+		}
+	} else {
+		prnt_timer = "-"
+	}
+	
+	if(rcvwnd_flg || filter_flds) {
+		argms[9] = key_list[laddr, raddr, lport, rport, flag, 12]
+	} else {
+		argms[9] = -1
+	}
+
+	if(flag) {
+                argms[0] = netmax(22,strlen(local_addr))
+                argms[2] = netmax(22,strlen(remote_addr))
+                buff = sprintf("%-*s %-*s %-*s %-*d %-*d %-*d %-*d %-*d %-*d %-*d %-*d %-*d",
+		argms[0], local_addr, argms[2],remote_addr, 11, prnt_state, 6,
+		argms[3], 5, argms[4], 5, argms[5], 5, argms[6], 7, argms[7],
+		7, argms[8], 6, argms[9], 4, argms[10], 11, argms[11]);
+                buff1 = sprintf("%-*d %-*s",6, argms[12], argms[1], prnt_timer);
+
+
+        } else {
+                argms[0] = netmax(22,strlen(remote_addr))
+                argms[2] = netmax(22,strlen(local_addr))
+                buff = sprintf("%-*s %-*s %-*s %-*d %-*d %-*d %-*d %-*d %-*d %-*d %-*d %-*d",
+		argms[0], remote_addr, argms[2],local_addr, 11, prnt_state, 6,
+		argms[3], 5, argms[4], 5, argms[5], 5, argms[6], 7, argms[7],
+		7, argms[8], 6, argms[9], 4, argms[10], 11, argms[11]);
+                buff1 = sprintf("%-*d %-*s",6, argms[12], argms[1], prnt_timer);
+        }
+
+	buff_final = str_replace(buff, "-1", " -")
+	buff_final1 = str_replace(buff1, "-1", " -")
+	printf("%s %s\n",buff_final,buff_final1)
+}
+
+function netmax:long (val1:long, val2:long)
+{
+	if(val1 > val2)
+		return val1
+	else
+		return val2
+}
+
+function is_packet_updated:long ( laddr:long, raddr:long, lport:long,
+					 rport:long, flag:long, sk:long )
+{
+	packet_updated = 0
+
+	if(state_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 1] =
+				 @cast(sk, "sock_common")->skc_state
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 1]
+			state = @cast(sk, "sock_common")->skc_state
+			if(temp != state)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 1] = state
+		}
+	}
+	if(txq_flg || filter_flds) {
+		if(update) {
+			if(@cast(sk, "sock_common")->skc_state == 10) 
+				key_list[laddr, raddr, lport, rport, flag, 2] =
+					 @cast(sk, "sock")->sk_max_ack_backlog
+			else
+				key_list[laddr, raddr, lport, rport, flag, 2] =
+					(@cast(sk, "tcp_sock")->write_seq - 
+					 @cast(sk, "tcp_sock")->snd_una)
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 2]
+			if(@cast(sk, "sock_common")->skc_state == 10)
+				tx_queue =
+					 @cast(sk, "sock")->sk_max_ack_backlog
+			else
+				tx_queue = (@cast(sk, "tcp_sock")->write_seq -
+						@cast(sk, "tcp_sock")->snd_una)
+			if(temp != tx_queue)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 2] = tx_queue
+		}
+	}
+	if(rxq_flg || filter_flds) {
+		if(update) {
+			if(@cast(sk, "sock_common")->skc_state == 10)
+				key_list[laddr, raddr, lport, rport, flag, 3] =
+					@cast(sk, "sock")->sk_ack_backlog
+			else
+				key_list[laddr, raddr, lport, rport, flag, 3] =
+					(@cast(sk, "tcp_sock")->rcv_nxt - 						@cast(sk, "tcp_sock")->copied_seq)
+			packet_updated  = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 3]
+			if(@cast(sk, "sock_common")->skc_state == 10)
+				rx_queue = @cast(sk, "sock")->sk_max_ack_backlog
+			else
+				rx_queue = (@cast(sk, "tcp_sock")->rcv_nxt -
+					@cast(sk, "tcp_sock")->copied_seq)
+			if(temp != rx_queue)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 3] = rx_queue
+		}
+	}
+	if(rexmit_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 4] =
+			 @cast(sk, "inet_connection_sock")->icsk_retransmits
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 4]
+			retxmit =
+			@cast(sk, "inet_connection_sock")->icsk_retransmits
+			if(temp != retxmit)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 4] = retxmit
+		}
+	}
+	if(pmtu_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 5] =
+			 @cast(sk, "inet_connection_sock")->icsk_pmtu_cookie
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 5]
+			pmtu =
+			@cast(sk, "inet_connection_sock")->icsk_pmtu_cookie
+			if(temp != pmtu)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 5] = pmtu
+		}
+	}
+	if(snd_cwnd_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 6] =
+			@cast(sk, "tcp_sock")->snd_cwnd
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 6]
+			snd_cwnd = @cast(sk, "tcp_sock")->snd_cwnd
+			if(temp != snd_cwnd)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 6] = snd_cwnd
+		}
+	}
+	if(snd_wnd_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 7] =
+				 @cast(sk, "tcp_sock")->snd_wnd
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 7]
+			snd_wnd = @cast(sk, "tcp_sock")->snd_wnd
+			if(temp != snd_wnd)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 7] = snd_wnd
+		}
+	}
+	if(srtt_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 8] =
+				(@cast(sk,"tcp_sock")->srtt) >> 3
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 8]
+			srtt = (@cast(sk,"tcp_sock")->srtt) >> 3
+			if(temp != srtt)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 8] = srtt
+		}
+	}
+
+	key_list[laddr, raddr, lport, rport, flag, 9] = length
+
+	if(ssthresh_flg || filter_flds) {
+		if(update) {
+			if ((1 << @cast(sk, "inet_connection_sock")->icsk_ca_state) & ((1 << 2) | (1 << 3)))
+				key_list[laddr, raddr, lport, rport, flag, 10] =
+					 @cast(sk, "tcp_sock")->snd_ssthresh
+			else
+				key_list[laddr, raddr, lport, rport, flag, 10] =
+				 netmax(@cast(sk, "tcp_sock")->snd_ssthresh,
+					((@cast(sk, "tcp_sock")->snd_cwnd >>1)+
+					(@cast(sk, "tcp_sock")->snd_cwnd >> 2)))
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 10]
+			if ((1 << @cast(sk, "inet_connection_sock")->icsk_ca_state) & ((1 << 2) | (1 << 3)))
+				ssthresh = @cast(sk, "tcp_sock")->snd_ssthresh
+			else
+				ssthresh =
+				 netmax(@cast(sk, "tcp_sock")->snd_ssthresh,
+				((@cast(sk, "tcp_sock")->snd_cwnd >> 1) +
+				(@cast(sk, "tcp_sock")->snd_cwnd >> 2)))
+			if(temp != ssthresh)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 10] =
+				 ssthresh
+		}
+	}
+
+	if(timer_flg || filter_flds) {
+		if(update) {
+			if(flag)
+				key_list[laddr, raddr, lport, rport, flag, 11] =
+					tx_current_timer
+			else
+				key_list[laddr, raddr, lport, rport, flag, 11] =
+					rx_current_timer
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 11]
+			if(flag) {
+				if(temp != tx_current_timer)
+					packet_updated = 1
+				key_list[laddr, raddr, lport, rport, flag, 11] =
+					tx_current_timer
+			} else {
+				if(temp != rx_current_timer)
+					packet_updated = 1
+				key_list[laddr, raddr, lport, rport, flag, 11] =
+					rx_current_timer
+			}
+		}
+	}
+
+	if(rcvwnd_flg || filter_flds) {
+		if(update) {
+			key_list[laddr, raddr, lport, rport, flag, 12] =
+				 @cast(sk, "tcp_sock")->rcv_wnd
+			packet_updated = 1
+		} else {
+			temp = key_list[laddr, raddr, lport, rport, flag, 12]
+			rcvwnd = @cast(sk, "tcp_sock")->rcv_wnd
+			if(temp != rcvwnd)
+				packet_updated = 1
+			key_list[laddr, raddr, lport, rport, flag, 12] = rcvwnd
+		}
+	}
+	return packet_updated		
+}
+
+/* All command line arguments other than the filters are processed
+ * first and must be placed on the command line prior to any filters.
+ */
+function process_cmdline:long ()
+{
+        filter_number = 0
+        count = 0
+        for (i=1; i <= argc; i++) {
+                argument = tokenize(argv[i], "=")
+
+                if (argument == "filter") {
+                        argv[i]=""
+                        while(strlen(byte = tokenize(argv[i], ",")) != 0) {
+                                argv[i] = ""
+                                tcp_param[count] = byte
+                                count++
+                        }
+                        continue;
+                }
+
+                if ( argument == "timeout" ){
+                        argv[i]=""
+                        timeout=strtol(tokenize(argv[i], "="),10)
+                        continue;
+                }
+
+		if ( argument == "update") {
+			argv[i]=""
+			update_disp = tokenize(argv[i], "=")
+			continue;
+		}
+
+		/* Anything on the command line after this point must
+ 		 * be a filter.
+		 */
+		source = tokenize(argv[i], "-")
+			argv[i] = ""
+		dest = tokenize(argv[i], "-")
+
+		source_addr = tokenize(source, ":")
+			source=""
+		source_port = tokenize(source, ":")
+
+		dest_addr = tokenize(dest, ":")
+			dest=""
+		dest_port = tokenize(dest, ":")
+
+		/* stap bug */
+		if ( dest_port == "fobar") i=i;
+
+		++filter_number;
+		j=filter_number*6;
+		filter[j]   = ipv4_pton(source_addr,0)  // Source address
+		filter[j+1] = ipv4_pton(source_addr,1)  // Source address mask
+		filter[j+2] = ipv4_portton(source_port) // Source port
+		filter[j+3] = ipv4_pton(dest_addr,0)    // Dest address
+		filter[j+4] = ipv4_pton(dest_addr,1)    // Dest address mask
+		filter[j+5] = ipv4_portton(dest_port)   // Dest port
+
+		if (filter[j]< -1 ||
+			filter[j+1] < -1 ||
+			filter[j+2] < -1 ||
+			filter[j+3] < -1 ||
+			filter[j+4] < -1 ||
+			filter[j+5] < -1 ) return -1;
+
+	}
+	if (update_disp == "all") {
+		update = 1;
+	} else if (update_disp == "change") {
+		update = 0;
+	} else {
+		/*We default it as "change"*/
+		update = 0;
+	}
+	return filter_number;
+}
+
+/*
+ * Convert an ascii integer values between 0 and 65534 to a u16 port number.
+ * "*" are treated as wildcards and will be converted to 0xffff.
+ */
+function ipv4_portton:long (port:string)
+{
+	if ( port == "*" ) port="65535";
+		pport=strtol(port,10);
+	if ( pport > 0xffff ){
+		printf("Bad port number %s\n",port)
+		return -22;
+	}
+	return pport
+}
+
+/*
+ * Convert ipv4 dot notation address into longs.
+ * Supports "*" in any field treating it as a wildcard by making the byte=0.
+ * If make_mask is set it creates a mask based on the "*" fields. All non='*'
+ * bytes are set to 0xff all * fields are set to 0x0;.
+ */
+function ipv4_pton:long (addr:string, make_mask:long)
+{
+	i=32;
+	ip=0;
+	ips=addr;
+	while(strlen(byte = tokenize(ips, ".")) != 0) {
+		i-=8;
+		ips="";
+
+		if ( byte == "*" ){
+			byte = "0"
+		} else {
+			if ( make_mask ) byte = "255";
+		}
+
+		j=strtol(byte,10);
+		if ( j > 255 ){
+			printf("bad address %s\n",addr)
+			return -22;
+		}
+			ip=ip+(j<<i) // left shift the byte into the address
+	}
+	if ( i != 0 ){
+		printf("bad address %s\n",addr)
+		return -22;
+	}
+	return ip;
+}
+
+/*
+ * Returns a unique value (stored in the global key_list) based on the socket
+ * address tuple and the global collection index value. A new value is created
+ * if one does not already exist.
+ */
+function build_key:long (laddr:long, raddr:long, lport:long, rport:long, flag:long)
+{
+	__index__ = 0
+
+	if ( key_list[laddr, raddr, lport, rport, flag, __index__] ) {
+		return  key_list[laddr, raddr, lport, rport, flag, __index__]
+	} else {
+		key_list[laddr, raddr, lport, rport, flag, __index__]=++lastkey
+		key = key_list[laddr, raddr, lport, rport, flag, __index__]
+		__index__ ++
+		while(__index__ != 12) {
+			key_list[laddr, raddr, lport, rport, flag, __index__]=0
+			__index__ ++
+		}
+		return key
+	}
+}
+
+		
+function filter_key:long (laddr:long, raddr:long, lport:long, rport:long, flag:long)
+{
+	j = 6;
+	local_filter = remote_filter = 0
+
+	//Local Filter
+	if ( (laddr&filter[j+1]) == filter[j] ) {
+		if ( (filter[j+2] == 0xffff) || (lport == filter[j+2]))
+			local_filter = 1;
+	}
+	// Remote filter
+	if ( (raddr&filter[j+4]) == filter[j+3] ) {
+		if ( (filter[j+5] == 0xffff) || (rport == filter[j+5]))
+			remote_filter = 1;
+	}
+
+	if(local_filter && remote_filter) {
+		return build_key(laddr, raddr, lport, rport, flag);
+	} else {
+	        return 0;
+	}
+}
+
+/* Terminates the run in timeout seconds, using global timeout value */
+probe timer.s(1) {
+	if ( timeout == -1 ) next
+	if ( !timeout-- ) exit()
+}
+
+function usage (msg:string)
+{
+	printf("\nUsage:\n");
+	printf("\ttcp_trace.stp  filter=all|state|txq|rxq|srtt|snd_cwnd|snd_wnd|rexmit|pmtu|ssthresh|timer|rcvwnd [timeout=<sec>] [update=change|all] Rule\n");
+	printf("\tRule format:  <local ip-address>:<local-port>-<remote ip-address>:<remote-port>\n\n");
+	error(msg);
+}
diff --git a/testsuite/systemtap.examples/network/tcp_trace.txt b/testsuite/systemtap.examples/network/tcp_trace.txt
new file mode 100644
index 0000000..46fe53f
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcp_trace.txt
@@ -0,0 +1,24 @@
+tcp_trace.stp filter=all 9.47.66.34:*-9.47.67.199:* 
+Start TCP Probing.....
+
+Source Address         Dest Address           State       Len    Tx-Q  Rx-Q  PMTU  SndCwnd SndWnd  A.RWnd SRTT Ssthreshold Rexmit Timer
+9.47.67.199:55587      9.47.66.34:22          SYN_RECV    20     0     0     1500  2       6144    5840   0    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 21     21    0     1500  3       6144    5840   0    2147483647  0      N/A  
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 20     21    0     1500  3       6144    5888   0    2147483647  0      N/A  
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 41     0     0     1500  4       6144    5888   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 0      0     21    1500  4       6144    5888   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 0      0     792   1500  4       6144    5888   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 784    784   792   1500  4       6144    7424   1    2147483647  0      N/A  
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 44     784   0     1500  4       6144    7424   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 152    152   0     1500  5       7680    7424   1    2147483647  0      N/A  
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 164    152   0     1500  5       7680    7424   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 0      0     0     1500  5       9216    7424   1    2147483647  0      Delack
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 720    720   0     1500  5       9216    9088   1    2147483647  0      Delack
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 36     720   0     1500  5       9216    9088   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 0      0     16    1500  5       10752   9088   1    2147483647  0      Delack
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 68     0     0     1500  5       10752   9088   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 0      0     0     1500  5       10752   9088   1    2147483647  0      Delack
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 48     48    0     1500  5       10752   9088   1    2147483647  0      Delack
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 84     48    0     1500  5       10752   9088   1    2147483647  0      N/A  
+9.47.66.34:22          9.47.67.199:55587      ESTABLISHED 64     64    0     1500  5       10752   9088   1    2147483647  0      Delack
+9.47.67.199:55587      9.47.66.34:22          ESTABLISHED 116    64    0     1500  5       10752   9088   1    2147483647  0      N/A  



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]