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 1/1] Add new TCP and IP functions


This patch adds some basic functions to the IP and TCP tapsets. 
Mainly, it's possible to get the iphdr and tcphdr from a sk_buff structure.

As a consequence, a TCP probe called tcp.receive() was created and
is probed every time a TCP packet is received, and a lot of 
useful fields is available, as the TCP flags.

Also a small example that works like tcpdump for received TCP packets was
created.

This patch was tested on x86 and ppc machines, on 2.6.18 kernel and also on
mainline one.

Signed-off-by: Breno Leitao <leitao@linux.vnet.ibm.com>
Signed-off-by: Andre Detsch <adetsch@br.ibm.com>

---
 tapset/ip.stp                                      |   47 ++++++++++
 tapset/tcp.stp                                     |   95 ++++++++++++++++++++
 .../systemtap.examples/network/tcpdumplike.stp     |   18 ++++
 3 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100644 testsuite/systemtap.examples/network/tcpdumplike.stp

diff --git a/tapset/ip.stp b/tapset/ip.stp
index 1e2e263..dd906a2 100644
--- a/tapset/ip.stp
+++ b/tapset/ip.stp
@@ -7,6 +7,10 @@
 //
 // Based on previous work done by Arnaldo Carvalho de Melo <acme@redhat.com>
 
+%{
+#include <linux/skbuff.h>
+%}
+
 /**
  * sfunction ip_ntop - returns a string representation from an integer IP number
  * @addr: the ip represented as an integer
@@ -30,3 +34,46 @@ function __ip_sock_daddr:long (sock:long)
 {
 	return @cast(sock, "inet_sock")->daddr
 }
+
+/* Get the IP header for recent (> 2.6.21) kernels */
+function __get_skb_iphdr_new:long(skb:long) %{
+	struct sk_buff *skb;
+	skb = (struct sk_buff *)(long)THIS->skb;
+	/* as done by skb_network_header() */
+	#ifdef NET_SKBUFF_DATA_USES_OFFSET
+		THIS->__retvalue = (long)(skb->head + skb->network_header);
+	#else
+		THIS->__retvalue = (long)skb->network_header;
+	#endif
+%}
+
+/* Get the IP header from a sk_buff struct */
+function __get_skb_iphdr:long(skb:long){
+%( kernel_v < "2.6.21" %?
+	iphdr = @cast(skb, "sk_buff")->nh->raw
+	return iphdr
+%:
+	return __get_skb_iphdr_new(skb)
+%)
+}
+
+/* return the source next layer protocol for a given sk_buff structure */
+function __ip_skb_proto:long (skb:long)
+{
+	iphdr = __get_skb_iphdr(skb)
+	return @cast(iphdr, "iphdr")->protocol
+}
+
+/* return the source IP address for a given sk_buff structure */
+function __ip_skb_saddr:long (skb:long)
+{
+	iphdr = __get_skb_iphdr(skb)
+	return @cast(iphdr, "iphdr")->saddr
+}
+
+/* return the destination IP address for a given skb */
+function __ip_skb_daddr:long (skb:long)
+{
+	iphdr = __get_skb_iphdr(skb)
+	return @cast(iphdr, "iphdr")->daddr
+}
diff --git a/tapset/tcp.stp b/tapset/tcp.stp
index bb96b0c..eaf7698 100644
--- a/tapset/tcp.stp
+++ b/tapset/tcp.stp
@@ -15,6 +15,7 @@
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <net/ip.h>
+#include <linux/skbuff.h>
 %}
 
 // Get retransmission timeout in usecs. RTO is initialized from default
@@ -78,6 +79,74 @@ function __tcp_sock_dport:long (sock:long){
 	return @cast(sock, "inet_sock")->dport
 }
 
+/* returns the TCP header for recent (<2.6.21) kernel */
+function __get_skb_tcphdr_new:long(skb:long) %{
+	struct sk_buff *skb;
+	skb = (struct sk_buff *)(long)THIS->skb;
+	/* as done by skb_transport_header() */
+	#ifdef NET_SKBUFF_DATA_USES_OFFSET
+		THIS->__retvalue = (long)(skb->head + skb->transport_header);
+	#else
+		THIS->__retvalue = (long)skb->transport_header;
+	#endif
+%}
+
+/* returns the TCP header for a given sk_buff structure */
+function __get_skb_tcphdr:long(skb:long){
+%( kernel_v < "2.6.21" %?
+	tcphdr = @cast(skb, "sk_buff")->h->raw
+	return tcphdr
+%:
+	return __get_skb_tcphdr_new(skb)
+%)
+}
+
+/* returns TCP URG flag for a given sk_buff structure */
+function __tcp_skb_urg:long (skb:long){
+	urg = ntohs(@cast(__get_skb_tcphdr(skb), "tcphdr")->urg) & 32
+	return urg >> 5
+}
+
+/* returns TCP ACK flag for a given sk_buff structure */
+function __tcp_skb_ack:long (skb:long){
+	ack = ntohs(@cast(__get_skb_tcphdr(skb), "tcphdr")->ack) & 16
+	return ack >> 4
+}
+
+/* returns TCP PSH flag for a given sk_buff structure */
+function __tcp_skb_psh:long (skb:long){
+	psh = ntohs(@cast(__get_skb_tcphdr(skb), "tcphdr")->psh) & 8
+	return psh >> 3
+}
+
+/* returns TCP RST flag for a given sk_buff structure */
+function __tcp_skb_rst:long (skb:long){
+	rst = ntohs(@cast(__get_skb_tcphdr(skb), "tcphdr")->rst) & 4
+	return rst >> 2
+}
+
+/* returns TCP SYN flag for a given sk_buff structure */
+function __tcp_skb_syn:long (skb:long){
+	syn = ntohs(@cast(__get_skb_tcphdr(skb), "tcphdr")->syn) & 2
+	return syn >> 1
+}
+
+/* returns TCP FIN flag for a given sk_buff structure */
+function __tcp_skb_fin:long (skb:long){
+	fin = ntohs(@cast(__get_skb_tcphdr(skb), "tcphdr")->fin) & 1
+	return fin
+}
+
+/* returns TCP source port for a given sk_buff structure */
+function __tcp_skb_sport:long (skb:long){
+	return @cast(__get_skb_tcphdr(skb), "tcphdr")->source
+}
+
+/* returns TCP destination port for a given sk_buff structure */
+function __tcp_skb_dport:long (skb:long){
+	return @cast(__get_skb_tcphdr(skb), "tcphdr")->dest
+}
+
 /* return the TCP source port for a given sock */
 function __tcp_sock_sport:long (sock:long){
 	return @cast(sock, "inet_sock")->sport
@@ -300,3 +369,29 @@ probe tcp.setsockopt.return = kernel.function("tcp_setsockopt").return {
 	ret = $return
 }
 
+/**
+ * probe tcp.receive - Called when a TCP packet is received
+ * @saddr: A string representing the source IP address
+ * @daddr: A string representing the destination IP address
+ * @sport: TCP source port
+ * @dport: TCP destination port
+ * @urg: TCP URG flag
+ * @ack: TCP ACK flag
+ * @psh: TCP PSH flag
+ * @rst: TCP RST flag
+ * @syn: TCP SYN flag
+ * @fin: TCP FIN flag
+ */
+probe tcp.receive = kernel.function("tcp_v4_rcv"){
+	saddr = ip_ntop(__ip_skb_saddr($skb))
+	daddr = ip_ntop(__ip_skb_daddr($skb))
+	protocol = __ip_skb_proto($skb)
+	dport = __tcp_skb_dport($skb)
+	sport = __tcp_skb_sport($skb)
+	urg = __tcp_skb_urg($skb)
+	ack = __tcp_skb_ack($skb)
+	psh = __tcp_skb_psh($skb)
+	rst = __tcp_skb_rst($skb)
+	syn = __tcp_skb_syn($skb)
+	fin = __tcp_skb_fin($skb)
+}
diff --git a/testsuite/systemtap.examples/network/tcpdumplike.stp b/testsuite/systemtap.examples/network/tcpdumplike.stp
new file mode 100644
index 0000000..f72a139
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcpdumplike.stp
@@ -0,0 +1,18 @@
+// A TCP dump like example
+
+function display_header(){
+	printf("---------------------------------------------------------\n");
+	printf("  Source IP     Dest IP   SPort   DPort  U  A  P  R  S  F\n");
+	printf("---------------------------------------------------------\n");
+}
+
+probe begin{
+	display_header()
+}
+probe tcp.receive{
+	printf("%s %s  %5d %5d   ", saddr, daddr, sport, dport)
+	printf(" %d  %d  %d  %d  %d  %d\n", urg, ack, psh, rst, syn, fin)
+}
+probe timer.s(1){
+	display_header()
+}
-- 
1.6.0.2


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