This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH 1/1] Add new TCP and IP functions
- From: Breno Leitao <leitao at linux dot vnet dot ibm dot com>
- To: systemtap at sources dot redhat dot com
- Cc: Andrà Detsch <adetsch at br dot ibm dot com>
- Date: Wed, 08 Apr 2009 18:11:34 -0300
- Subject: [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