[PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)

Robin Hack rhack@redhat.com
Sun Nov 17 10:18:00 GMT 2013


On Wed, Nov 13, 2013 at 05:18:35PM -0500, Frank Ch. Eigler wrote:

Hi Frank.

Thanks again for comments. I did some changes, but comments and changes
are still needed.
> 
> Hi, Robin -
> 
> rhack wrote:
> 
> > [...]  Then I decided to write this patch. Patch is only draft now
> > and comments are very welcome.
> 
> Nice.  A few code comments:
> 
> The use of TMP_STAP_RETVALUE / MAXLEN in the embedded-c function is a
> little clumsy.  Have you considered using ordinarily named variables
> to track the remainder base/length of STAP_RETVALUE,
It's fixed.
> and doing the
> RETVALUE_INC_SKIP dance inlined instead of as a macro?
I apologize here, but this part is not clear enought for me.

> What about delimiters between the data corresponding to multiple SA_* selections?
I changed approach. Now I export values direct to probes.
Delimiters will be good in tapset library.
> 
> 
> > Very easy example are attached too.
> 
> It might be even simpler if the related tapset functions all get this
> kind of stuff, but perhaps plopped into a macro for easier handling:
> 
> probe syscall.bind = ... {
> %( systemtap_v >= "2.5" %? 
>     if (_struct_sockaddr_u_sa_family(my_addr_uaddr, addrlen) =~ "AF_INET.*") {
>        uaddr_ip = _struct_sockaddr_u_ip_addr(my_addr_uaddr, addrlen)
>        uaddr_ip_port = ... 
>     }
> %)
> 
> where the whole %(  %)  block could be @defined in a macro, kind of like
> _nfs_data_timestamp in tapset/linux/nfs_proc.stpm.
> 
> 
> > What is not solved in this patch:
> >     * Error handling if wrong struct is passed - now it's just return empty ("") string. Maybe throw exception will be better.
I hope, that this will be part of tapset.
> >     * Expansion to syscall.connect probe.
Done :).
> >     * Write tapset shell for new internal functions.
In progress.
> 
> Yup, plus a test case (e.g., a testsuite/buildok file).
I added some tests.
> 
> Thanks!
> 
> - FChE
-------------- next part --------------
diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
index 0f9c9e4..1513150 100644
--- a/tapset/linux/aux_syscalls.stp
+++ b/tapset/linux/aux_syscalls.stp
@@ -280,7 +280,7 @@ function _struct_compat_itimerval_u:string(uaddr:long)
 %}
 
 %{
-// Needed for function _struct_sockaddr_u. Unfortunately cannot be
+// Needed for function _struct_sockaddr_u_impl. Unfortunately cannot be
 // inlined into the function since these header files define static
 // functions themselves.
 #include <linux/socket.h>
@@ -288,18 +288,75 @@ function _struct_compat_itimerval_u:string(uaddr:long)
 #include <linux/netlink.h>
 %}
 
+%{
+// Enum for _struct_sockaddr_u_* functions.
+typedef enum {
+    SA_PRETTY           = 1,
+    SA_IP_ADDR          = 2,
+    SA_TCP_PORT         = 4,
+    SA_FAMILY           = 8,
+    SA_IPV6_FLOWINFO    = 16,
+    SA_IPV6_SCOPE_ID    = 32,
+} sa_dispatch;
+%}
+
+function _struct_sockaddr_u_ip_addr:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR %});
+}
+
+function _struct_sockaddr_u_tcp_port:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_TCP_PORT %});
+}
+
+function _struct_sockaddr_u_ip_addr_tcp_port:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR | SA_TCP_PORT %});
+}
+
+function _struct_sockaddr_u_sa_family:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_FAMILY %});
+}
+
+function _struct_sockaddr_u_ipv6_flowinfo:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_FLOWINFO %});
+}
+
+function _struct_sockaddr_u_ipv6_scope_id:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_SCOPE_ID %});
+}
+
 function _struct_sockaddr_u:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_PRETTY %});
+}
+
+function _struct_sockaddr_u_impl:string(uaddr:long, len:long, what:long)
 %{ /* pure */
 #include <linux/version.h>
 #include <linux/in6.h>
 #include <linux/un.h>
 #include <linux/if_packet.h>
 
+	sa_dispatch what = (sa_dispatch)STAP_ARG_what;
+
 	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
 	char buf[128];
 	size_t len = STAP_ARG_len < 128 ? STAP_ARG_len : 128;
 	struct sockaddr *sa = (struct sockaddr *)buf;
 
+// Don't use this macro outside of if (what & ... ) statement!
+// (n - 1) mean: cut of null char
+#define RETVALUE_INC_SKIP() do {stap_retvalue += (n); maxstringlen -= (n - 1);} while (0)
+    char *stap_retvalue = (char *)(unsigned long)STAP_RETVALUE;
+    int maxstringlen = MAXSTRINGLEN;
+    size_t n;
+
+
 	if (ptr == NULL)
 	{
 		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
@@ -320,60 +377,163 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
 #define DADDR   (&inet->daddr)
 #endif
 
+
 // Use kernel builtin instead of picking up user space ntohs (function).
 #define _stp_ntohs be16_to_cpu
 
 	if ((sa->sa_family == AF_INET) && (len == sizeof(struct sockaddr_in)))
 	{
 		struct sockaddr_in *sin = (struct sockaddr_in *)buf;
-#ifndef NIPQUAD_FMT			// kver >= 2.6.36
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
-			 &sin->sin_addr, _stp_ntohs(sin->sin_port));
+
+        if (what & SA_PRETTY)
+        {
+#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
+                     &sin->sin_addr, _stp_ntohs(sin->sin_port));
 #else
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_INET, " NIPQUAD_FMT ", %d}",
-			 NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
-#endif
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                     "{AF_INET, " NIPQUAD_FMT ", %d}",
+                     NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
+#endif
+            return;
+        }
+
+        if (what & SA_FAMILY)
+        {
+            n = strlcpy(stap_retvalue, "AF_INET", maxstringlen);
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IP_ADDR)
+        {
+#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
+            n = snprintf(stap_retvalue, maxstringlen, "%pI4", &sin->sin_addr);
+#else
+            n = snprintf(stap_retvalue, maxstringlen, NIPQUAD_FMT,
+                    NIPQUAD(sin->sin_addr));
+#endif
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_TCP_PORT)
+        {
+            n = snprintf(stap_retvalue, maxstringlen, "%d",
+                    _stp_ntohs(sin->sin_port));
+            RETVALUE_INC_SKIP();
+        }
 	}
 	else if ((sa->sa_family == AF_UNIX)
 		 && (len == sizeof(struct sockaddr_un)))
-	{	
-		struct sockaddr_un *sun = (struct sockaddr_un *)buf;	
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
-			 sun->sun_path); 
+	{
+		struct sockaddr_un *sun = (struct sockaddr_un *)buf;
+
+        if (what & SA_PRETTY)
+        {
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
+                 sun->sun_path);
+        } else if (what & SA_FAMILY)
+        {
+            strlcpy(STAP_RETVALUE, "AF_UNIX", MAXSTRINGLEN);
+        } else
+        {
+            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+        }
 	}
 	else if ((sa->sa_family == AF_NETLINK)
 		 && (len == sizeof(struct sockaddr_nl)))
 	{
 		struct sockaddr_nl *nl = (struct sockaddr_nl *)buf;
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_NETLINK, pid=%d, groups=%08x}",
-			 nl->nl_pid, nl->nl_groups);
+
+        if (what & SA_PRETTY) {
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_NETLINK, pid=%d, groups=%08x}",
+                 nl->nl_pid, nl->nl_groups);
+        } else if (what & SA_FAMILY)
+        {
+            strlcpy(STAP_RETVALUE, "AF_NETLINK", MAXSTRINGLEN);
+        } else
+        {
+            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+        }
 	}
 	else if ((sa->sa_family == AF_INET6)
 		 && (len == sizeof(struct sockaddr_in6)))
 	{
 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)buf;
+
+        if (what & SA_PRETTY)
+        {
 #ifndef NIP6_FMT			// kver >= 2.6.36
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
-			 _stp_ntohs(sin->sin6_port));
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
+                 _stp_ntohs(sin->sin6_port));
 #else
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
-			 _stp_ntohs(sin->sin6_port));
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
+                 _stp_ntohs(sin->sin6_port));
 #endif
+            return;
+        }
+
+        if (what & SA_FAMILY)
+        {
+            n = strlcpy(stap_retvalue, "AF_INET6", maxstringlen);
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IP_ADDR)
+        {
+#ifndef NIP6_FMT			// kver >= 2.6.36
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%pI6", &sin->sin6_addr);
+#else
+            n = snprintf(stap_retvalue, maxstringlen,
+                 NIP6_FMT, NIP6(sin->sin6_addr));
+#endif
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_TCP_PORT)
+        {
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%d", _stp_ntohs(sin->sin6_port));
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IPV6_FLOWINFO)
+        {
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%d", sin->sin6_flowinfo);
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IPV6_SCOPE_ID)
+        {
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%d", sin->sin6_flowinfo);
+            RETVALUE_INC_SKIP();
+        }
 	}
 	else if ((sa->sa_family == AF_PACKET)
-		 && (len == sizeof(struct sockaddr_ll))) 
+		 && (len == sizeof(struct sockaddr_ll)))
 	{
 		struct sockaddr_ll *sll = (struct sockaddr_ll *)buf;
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
-			 (int)sll->sll_protocol, sll->sll_ifindex,
-			 (int)sll->sll_hatype, (int)sll->sll_pkttype,
-			 (int)sll->sll_halen,
-			 (long long)(*(uint64_t *)sll->sll_addr));
+
+        if (what & SA_PRETTY)
+        {
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
+                 (int)sll->sll_protocol, sll->sll_ifindex,
+                 (int)sll->sll_hatype, (int)sll->sll_pkttype,
+                 (int)sll->sll_halen,
+                 (long long)(*(uint64_t *)sll->sll_addr));
+        } else if (what & SA_FAMILY)
+        { 
+            strlcpy(STAP_RETVALUE, "AF_PACKET", MAXSTRINGLEN);
+        } else
+        {
+            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+        }
 	}
 	else
 	{
@@ -389,6 +549,8 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
 				 "{unknown sockaddr with salen=%d}", (int)len);
 		}
 	}
+
+#undef RETVALUE_INC_SKIP
 %}
 
 function _struct_rlimit_u:string(uaddr:long)
diff --git a/tapset/linux/nd_syscalls.stp b/tapset/linux/nd_syscalls.stp
index f2daa01..5121751 100644
--- a/tapset/linux/nd_syscalls.stp
+++ b/tapset/linux/nd_syscalls.stp
@@ -247,6 +247,7 @@ probe nd_syscall.bind = kprobe.function("sys_bind") ?
 	sockfd = int_arg(1)
 	my_addr_uaddr = pointer_arg(2)
 	addrlen = int_arg(3)
+	@_af_inet_info_u(my_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(my_addr_uaddr, addrlen), addrlen)
 }
 probe nd_syscall.bind.return = kprobe.function("sys_bind").return ?
@@ -586,6 +587,7 @@ probe nd_syscall.connect = kprobe.function("sys_connect") ?
 	sockfd = int_arg(1)
 	serv_addr_uaddr = pointer_arg(2)
 	addrlen = int_arg(3)
+	@_af_inet_info_u(serv_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(serv_addr_uaddr, addrlen), addrlen)
 }
 probe nd_syscall.connect.return = kprobe.function("sys_connect").return ?
diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp
index 13fb92f..d8e1d05 100644
--- a/tapset/linux/syscalls.stp
+++ b/tapset/linux/syscalls.stp
@@ -199,6 +199,7 @@ probe syscall.bind = kernel.function("sys_bind").call ?
 	sockfd = $fd
 	my_addr_uaddr = $umyaddr
 	addrlen = $addrlen
+	@_af_inet_info_u(my_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($umyaddr, $addrlen), $addrlen)
 }
 probe syscall.bind.return = kernel.function("sys_bind").return ?
@@ -472,6 +473,7 @@ probe syscall.connect = kernel.function("sys_connect").call ?
 	sockfd = $fd
 	serv_addr_uaddr = $uservaddr
 	addrlen = $addrlen
+	@_af_inet_info_u(serv_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($uservaddr, $addrlen), $addrlen)
 }
 probe syscall.connect.return = kernel.function("sys_connect").return ?
diff --git a/tapset/linux/syscalls.stpm b/tapset/linux/syscalls.stpm
new file mode 100644
index 0000000..0ab18ab
--- /dev/null
+++ b/tapset/linux/syscalls.stpm
@@ -0,0 +1,24 @@
+// Macros for syscalls.stp and nd_syscalls.stp
+// Copyright (C) 2013 Red Hat
+//
+// Author : Robin Hack <rhack@redhat.com>
+//
+// 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.
+
+@define _af_inet_info_u(my_addr_uaddr, addrlen)
+%(
+	%( systemtap_v >= "2.5" %?
+		uaddr_af = _struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen)
+		if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) =~ "AF_INET.*") {
+			uaddr_ip = _struct_sockaddr_u_ip_addr(@my_addr_uaddr, @addrlen)
+			uaddr_ip_port = _struct_sockaddr_u_tcp_port(@my_addr_uaddr, @addrlen)
+			if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) == "AF_INET6") {
+				uaddr_ipv6_flowinfo =  _struct_sockaddr_u_ipv6_flowinfo(@my_addr_uaddr, @addrlen)
+				uaddr_ipv6_scope_id =  _struct_sockaddr_u_ipv6_scope_id(@my_addr_uaddr, @addrlen)
+			}
+		}
+	%)
+%)
diff --git a/testsuite/buildok/aux_syscalls-embedded.stp b/testsuite/buildok/aux_syscalls-embedded.stp
index 1fb5114..51b02c1 100755
--- a/testsuite/buildok/aux_syscalls-embedded.stp
+++ b/testsuite/buildok/aux_syscalls-embedded.stp
@@ -14,6 +14,14 @@ probe begin {
 	print (_struct_itimerval_u(0))
 	print (_struct_compat_itimerval_u(0))
 	print (_struct_sockaddr_u(0,0))
+%( systemtap_v >= "2.5" %?
+	print (_struct_sockaddr_u_ip_addr(0,0))
+	print (_struct_sockaddr_u_tcp_port(0,0))
+	print (_struct_sockaddr_u_sa_family(0,0))
+	print (_struct_sockaddr_u_ipv6_flowinfo(0,0))
+	print (_struct_sockaddr_u_ipv6_scope_id(0,0))
+	print (_struct_sockaddr_u_impl(0,0,0))
+%)
 	print (_struct_rlimit_u(0))
 	print (_fildes_index_u(0, 0))
 
diff --git a/testsuite/buildok/nd_syscalls-detailed.stp b/testsuite/buildok/nd_syscalls-detailed.stp
index 8152f8d..4c9e0ed 100755
--- a/testsuite/buildok/nd_syscalls-detailed.stp
+++ b/testsuite/buildok/nd_syscalls-detailed.stp
@@ -74,8 +74,13 @@ probe nd_syscall.bdflush.return ?
 probe nd_syscall.bind
 {
 	printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
+%)
 }
+
 probe nd_syscall.bind.return
 {
 	printf("%s, %s\n", name, retstr)
@@ -194,7 +199,11 @@ probe nd_syscall.close.return
 probe nd_syscall.connect
 {
 	printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
+%)
 }
 probe nd_syscall.connect.return
 {
diff --git a/testsuite/buildok/syscalls-detailed.stp b/testsuite/buildok/syscalls-detailed.stp
index e1c626c..17544f7 100755
--- a/testsuite/buildok/syscalls-detailed.stp
+++ b/testsuite/buildok/syscalls-detailed.stp
@@ -74,7 +74,12 @@ probe syscall.bdflush.return ?
 probe syscall.bind
 {
 	printf("%s, %s\n", name, argstr)
+
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
+%)
 }
 probe syscall.bind.return
 {
@@ -194,7 +199,11 @@ probe syscall.close.return
 probe syscall.connect
 {
 	printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
+%)
 }
 probe syscall.connect.return
 {


More information about the Systemtap mailing list