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 v2] 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>

---
Thanks the comments, Josh. 
This new version hopefully addresses all your concerns.

---
 tapset/ip.stp                                      |   46 ++++++++++
 tapset/tcp.stp                                     |   94 ++++++++++++++++++++
 .../systemtap.examples/network/tcpdumplike.stp     |   12 +++
 3 files changed, 152 insertions(+), 0 deletions(-)
 create mode 100644 testsuite/systemtap.examples/network/tcpdumplike.stp

diff --git a/tapset/ip.stp b/tapset/ip.stp
index 1e2e263..299d88d 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,45 @@ 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)
+%{ /* pure */
+	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)(kread(&(skb->head)) + kread(&(skb->network_header)));
+	#else
+		THIS->__retvalue = (long)kread(&(skb->network_header));
+	#endif
+	CATCH_DEREF_FAULT();
+%}
+
+/* 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 (iphdr)
+{
+	return @cast(iphdr, "iphdr")->protocol
+}
+
+/* return the source IP address for a given sk_buff structure */
+function __ip_skb_saddr:long (iphdr)
+{
+	return @cast(iphdr, "iphdr")->saddr
+}
+
+/* return the destination IP address for a given skb */
+function __ip_skb_daddr:long (iphdr)
+{
+	return @cast(iphdr, "iphdr")->daddr
+}
diff --git a/tapset/tcp.stp b/tapset/tcp.stp
index bb96b0c..2c5dce7 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,70 @@ 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)
+%{ /* pure */
+	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)(kread(&(skb->head)) + kread(&(skb->transport_header)));
+	#else
+		THIS->__retvalue = (long)kread(&(skb->transport_header));
+	#endif
+	CATCH_DEREF_FAULT();
+%}
+
+/* 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 (tcphdr){
+	return @cast(tcphdr, "tcphdr")->urg
+}
+
+/* returns TCP ACK flag for a given sk_buff structure */
+function __tcp_skb_ack:long (tcphdr){
+	return @cast(tcphdr, "tcphdr")->ack
+}
+
+/* returns TCP PSH flag for a given sk_buff structure */
+function __tcp_skb_psh:long (tcphdr){
+	return @cast(tcphdr, "tcphdr")->psh
+}
+
+/* returns TCP RST flag for a given sk_buff structure */
+function __tcp_skb_rst:long (tcphdr){
+	return @cast(tcphdr, "tcphdr")->rst
+}
+
+/* returns TCP SYN flag for a given sk_buff structure */
+function __tcp_skb_syn:long (tcphdr){
+	return @cast(tcphdr, "tcphdr")->syn
+}
+
+/* returns TCP FIN flag for a given sk_buff structure */
+function __tcp_skb_fin:long (tcphdr){
+	return @cast(tcphdr, "tcphdr")->fin
+}
+
+/* returns TCP source port for a given sk_buff structure */
+function __tcp_skb_sport:long (tcphdr){
+	return ntohs(@cast(tcphdr, "tcphdr")->source)
+}
+
+/* returns TCP destination port for a given sk_buff structure */
+function __tcp_skb_dport:long (tcphdr){
+	return @cast(tcphdr, "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 +365,32 @@ 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") {
+	iphdr = __get_skb_iphdr($skb)
+	saddr = ip_ntop(__ip_skb_saddr(iphdr))
+	daddr = ip_ntop(__ip_skb_daddr(iphdr))
+	protocol = __ip_skb_proto(iphdr)
+
+	tcphdr = __get_skb_tcphdr($skb)
+	dport = __tcp_skb_dport(tcphdr)
+	sport = __tcp_skb_sport(tcphdr)
+	urg = __tcp_skb_urg(tcphdr)
+	ack = __tcp_skb_ack(tcphdr)
+	psh = __tcp_skb_psh(tcphdr)
+	rst = __tcp_skb_rst(tcphdr)
+	syn = __tcp_skb_syn(tcphdr)
+	fin = __tcp_skb_fin(tcphdr)
+}
diff --git a/testsuite/systemtap.examples/network/tcpdumplike.stp b/testsuite/systemtap.examples/network/tcpdumplike.stp
new file mode 100644
index 0000000..4026e7a
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcpdumplike.stp
@@ -0,0 +1,12 @@
+// A TCP dump like example
+
+probe begin, timer.s(1) {
+	printf("-----------------------------------------------------------------\n");
+	printf("       Source IP         Dest IP  SPort  DPort  U  A  P  R  S  F \n");
+	printf("-----------------------------------------------------------------\n");
+}
+
+probe tcp.receive {
+	printf(" %15s %15s  %5d  %5d  %d  %d  %d  %d  %d  %d\n",
+		saddr, daddr, sport, dport, urg, ack, psh, rst, syn, fin)
+}
-- 
1.5.4.3


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