[DTrace-devel] [PATCH v3] Implement the ip provider

Kris Van Hees kris.van.hees at oracle.com
Fri Sep 22 13:30:41 UTC 2023


This patch also resolves the issue of ipaddr_t not being a known type
because ip.d provides a definition for it.

Orabug: 34855291
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/Build                     |   4 +-
 libdtrace/dt_open.c                 |   3 +-
 libdtrace/dt_prov_ip.c              | 184 ++++++++++++++++++++++++++++
 libdtrace/dt_provider.h             |   1 +
 libdtrace/ip.d                      |   6 +-
 test/demo/ip/ipproto.d              |   3 +-
 test/unittest/funcs/tst.inet_ntoa.d |   4 +-
 test/unittest/ip/tst.lv-receive.r   |  20 +++
 test/unittest/ip/tst.lv-receive.r.p |   1 +
 test/unittest/ip/tst.lv-receive.sh  |  11 ++
 test/unittest/ip/tst.lv-send.r      |  20 +++
 test/unittest/ip/tst.lv-send.r.p    |   1 +
 test/unittest/ip/tst.lv-send.sh     |  11 ++
 13 files changed, 260 insertions(+), 9 deletions(-)
 create mode 100644 libdtrace/dt_prov_ip.c
 create mode 100644 test/unittest/ip/tst.lv-receive.r
 create mode 120000 test/unittest/ip/tst.lv-receive.r.p
 create mode 100755 test/unittest/ip/tst.lv-receive.sh
 create mode 100644 test/unittest/ip/tst.lv-send.r
 create mode 120000 test/unittest/ip/tst.lv-send.r.p
 create mode 100755 test/unittest/ip/tst.lv-send.sh

diff --git a/libdtrace/Build b/libdtrace/Build
index d1b00933..7dc2d5d6 100644
--- a/libdtrace/Build
+++ b/libdtrace/Build
@@ -49,6 +49,7 @@ libdtrace-build_SOURCES = dt_aggregate.c \
                    dt_prov_cpc.c \
                    dt_prov_dtrace.c \
                    dt_prov_fbt.c \
+                   dt_prov_ip.c \
                    dt_prov_lockstat.c \
                    dt_prov_proc.c \
                    dt_prov_profile.c \
@@ -96,8 +97,9 @@ dt_proc.c_CFLAGS := -Wno-pedantic
 dt_prov_cpc.c_CFLAGS := -Wno-pedantic
 dt_prov_dtrace.c_CFLAGS := -Wno-pedantic
 dt_prov_fbt.c_CFLAGS := -Wno-pedantic
-dt_prov_proc.c_CFLAGS := -Wno-pedantic
+dt_prov_ip.c_CFLAGS := -Wno-pedantic
 dt_prov_lockstat.c_CFLAGS := -Wno-pedantic
+dt_prov_proc.c_CFLAGS := -Wno-pedantic
 dt_prov_profile.c_CFLAGS := -Wno-pedantic
 dt_prov_rawtp.c_CFLAGS := -Wno-pedantic
 dt_prov_sched.c_CFLAGS := -Wno-pedantic
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 1eca6079..7050b625 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -68,6 +68,7 @@ static const dt_provimpl_t *dt_providers[] = {
      &dt_dtrace,       /* list dt_dtrace first */
      &dt_cpc,
      &dt_fbt,
+     &dt_ip,
      &dt_lockstat,
      &dt_proc,
      &dt_profile,
@@ -199,7 +200,7 @@ static const dt_ident_t _dtrace_globals[] = {
 { "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
      &dt_idops_func, "int(const char *, const char *, [int])" },
 { "inet_ntoa", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN,
-     DT_VERS_1_5, &dt_idops_func, "string(void *)" }, /* FIXME should be ipaddr_t* */
+     DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" },
 { "inet_ntoa6", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN,
      DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" },
 { "inet_ntop", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_INET_NTOP, DT_ATTR_STABCMN,
diff --git a/libdtrace/dt_prov_ip.c b/libdtrace/dt_prov_ip.c
new file mode 100644
index 00000000..03e929b6
--- /dev/null
+++ b/libdtrace/dt_prov_ip.c
@@ -0,0 +1,184 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ *
+ * The 'ip' SDT provider for DTrace-specific probes.
+ */
+#include <assert.h>
+#include <errno.h>
+
+#include "dt_dctx.h"
+#include "dt_cg.h"
+#include "dt_provider_sdt.h"
+#include "dt_probe.h"
+
+static const char            prvname[] = "ip";
+static const char            modname[] = "vmlinux";
+
+static probe_dep_t     probes[] = {
+     { "receive",
+       DTRACE_PROBESPEC_NAME,      "fbt::ip_local_deliver:entry" },
+     { "receive",
+       DTRACE_PROBESPEC_NAME,      "fbt::ip6_input:entry" },
+     { "send",
+       DTRACE_PROBESPEC_NAME,      "fbt::ip_finish_output:entry" },
+     { "send",
+       DTRACE_PROBESPEC_NAME,      "fbt::ip6_finish_output:entry" },
+     { NULL, }
+};
+
+static probe_arg_t probe_args[] = {
+     { "receive", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } },
+     { "receive", 1, { 1, 0, "struct sock *", "csinfo_t *" } },
+     { "receive", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } },
+     { "receive", 3, { 3, 0, "struct net_device *", "ifinfo_t *" } },
+     { "receive", 4, { 4, 0, "struct iphdr *", "ipv4info_t *" } },
+     { "receive", 5, { 5, 0, "struct ipv6hdr *", "ipv6info_t *"} },
+     { "send", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } },
+     { "send", 1, { 1, 0, "struct sock *", "csinfo_t *" } },
+     { "send", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } },
+     { "send", 3, { 3, 0, "struct net_device *", "ifinfo_t *" } },
+     { "send", 4, { 4, 0, "struct iphdr *", "ipv4info_t *" } },
+     { "send", 5, { 5, 0, "struct ipv6hdr *", "ipv6info_t *"} },
+     { NULL, }
+};
+
+static const dtrace_pattr_t  pattr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+};
+
+/*
+ * Provide all the "ip" SDT probes.
+ */
+static int populate(dtrace_hdl_t *dtp)
+{
+     return dt_sdt_populate(dtp, prvname, modname, &dt_ip, &pattr,
+                        probe_args, probes);
+}
+
+/*
+ * Retrieve the value of a member in a given struct.
+ *
+ * Entry:
+ *   reg = TYPE *ptr
+ *
+ * Return:
+ *   %r0 = ptr->member
+ * Clobbers:
+ *   %r1 .. %r5
+ */
+static int get_member(dt_pcb_t *pcb, const char *name, int reg,
+                 const char *member) {
+     dtrace_hdl_t            *dtp = pcb->pcb_hdl;
+     dt_irlist_t       *dlp = &pcb->pcb_ir;
+     dtrace_typeinfo_t tt;
+     ctf_membinfo_t          ctm;
+     size_t                  size;
+     uint_t                  ldop;
+
+     if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_KMODS, name, &tt) == -1 ||
+         ctf_member_info(tt.dtt_ctfp, tt.dtt_type, member, &ctm) == CTF_ERR)
+           return -1;
+
+     ldop = dt_cg_ldsize(NULL, tt.dtt_ctfp, ctm.ctm_type, &size);
+
+     emit(dlp, BPF_MOV_REG(BPF_REG_3, reg));
+     emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY));
+     emit(dlp, BPF_MOV_IMM(BPF_REG_2, size));
+     emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP));
+     emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_BASE));
+     emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel]));
+     emit(dlp, BPF_LOAD(ldop, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_BASE));
+
+     return 0;
+}
+
+/*
+ * Generate a BPF trampoline for a SDT probe.
+ *
+ * The trampoline function is called when a SDT probe triggers, and it must
+ * satisfy the following prototype:
+ *
+ *   int dt_ip(void *data)
+ *
+ * The trampoline will populate a dt_dctx_t struct and then call the function
+ * that implements the compiled D clause.  It returns the value that it gets
+ * back from that function.
+ */
+static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
+{
+     dt_irlist_t *dlp = &pcb->pcb_ir;
+     dt_probe_t  *prp = pcb->pcb_probe;
+     dt_probe_t  *uprp = pcb->pcb_parent_probe;
+     uint_t            skbreg;
+
+     /*
+      * Determine the register that holds a pointer to the skb passed from
+      * the underlying probe.
+      */
+     if (strcmp(prp->desc->prb, "receive") == 0)
+           skbreg = 0;
+     else
+           skbreg = 2;
+
+     /*
+      * We construct the ip:::(receive,send) probe arguments as
+      * follows:
+      *    args[0] = skb
+      *    args[1] = skb->sk
+      *    args[2] = ip_hdr(skb)
+      *    args[3] = skb->dev
+      *    args[4] = [IPv4] ip_hdr(skb)  -or- [IPv6] NULL
+      *    args[5] = [IPv4] NULL         -or- [IPv6] ipv6_hdr(skb)
+      */
+     emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skbreg)));
+     emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl));
+
+     emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6));
+
+     get_member(pcb, "struct sk_buff", BPF_REG_6, "sk");
+     emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_0));
+
+     /*
+      * ip_hdr(skb) =
+      *    skb_network_header(skb) =     (include/linux/ip.h)
+      *    skb->head + skb->network_header     (include/linux/skbuff.h)
+      */
+     get_member(pcb, "struct sk_buff", BPF_REG_6, "head");
+     emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0));
+     emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0));
+     emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(5), BPF_REG_0));
+     get_member(pcb, "struct sk_buff", BPF_REG_6, "network_header");
+     emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0));
+     emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0));
+     emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(5), BPF_REG_0));
+
+     /*
+      * We can use the name of the underlying probe to determine whether we
+      * are dealing with IPv4 (ip_*) or IPv6 (ip6_*).
+      */
+     if (uprp->desc->fun[2] == '6')
+           emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(4), 0));
+     else
+           emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(5), 0));
+
+     get_member(pcb, "struct sk_buff", BPF_REG_6, "dev");
+     emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(3), BPF_REG_0));
+
+     return 0;
+}
+
+dt_provimpl_t    dt_ip = {
+     .name       = prvname,
+     .prog_type  = BPF_PROG_TYPE_UNSPEC,
+     .populate   = &populate,
+     .enable           = &dt_sdt_enable,
+     .trampoline = &trampoline,
+     .probe_info = &dt_sdt_probe_info,
+};
diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
index 8face769..31ad028d 100644
--- a/libdtrace/dt_provider.h
+++ b/libdtrace/dt_provider.h
@@ -70,6 +70,7 @@ typedef struct dt_provimpl {
 extern dt_provimpl_t dt_dtrace;
 extern dt_provimpl_t dt_cpc;
 extern dt_provimpl_t dt_fbt;
+extern dt_provimpl_t dt_ip;
 extern dt_provimpl_t dt_lockstat;
 extern dt_provimpl_t dt_proc;
 extern dt_provimpl_t dt_profile;
diff --git a/libdtrace/ip.d b/libdtrace/ip.d
index f66316c3..f8b77f12 100644
--- a/libdtrace/ip.d
+++ b/libdtrace/ip.d
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -51,6 +51,8 @@ inline int TCP_MIN_HEADER_LENGTH =  20;
  * to the net namespace (nd_net in struct net_device).
  */
 typedef uint64_t netstackid_t;
+typedef __be32         ipaddr_t;
+typedef struct in6_addr      in6_addr_t;

 /*
  * pktinfo is where packet ID info can be made available for deeper
@@ -159,7 +161,7 @@ translator csinfo_t < struct sock *s > {
 #pragma D binding "1.5" translator
 translator ipinfo_t < struct iphdr *I > {
      ip_ver = 4;
-        ip_plength = I != NULL ? (ntohs(I->tot_len) - (*(uint8_t *)I & 0xf) << 2) : 0;
+        ip_plength = I != NULL ? (ntohs(I->tot_len) - I->ihl << 2) : 0;
      ip_saddr = I != NULL ? inet_ntoa(&I->saddr) : "<unknown>";
      ip_daddr = I != NULL ? inet_ntoa(&I->daddr) : "<unknown>";
 };
diff --git a/test/demo/ip/ipproto.d b/test/demo/ip/ipproto.d
index 0538abe3..da499f74 100644
--- a/test/demo/ip/ipproto.d
+++ b/test/demo/ip/ipproto.d
@@ -1,10 +1,9 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */

 #pragma D option quiet

diff --git a/test/unittest/funcs/tst.inet_ntoa.d b/test/unittest/funcs/tst.inet_ntoa.d
index 42ea7107..3b7b7556 100644
--- a/test/unittest/funcs/tst.inet_ntoa.d
+++ b/test/unittest/funcs/tst.inet_ntoa.d
@@ -1,14 +1,12 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */

 #pragma D option quiet

-typedef vmlinux`__be32 ipaddr_t;                  /* FIXME: how should this really be handled? */
-
 ipaddr_t *ip4a;
 ipaddr_t *ip4b;
 ipaddr_t *ip4c;
diff --git a/test/unittest/ip/tst.lv-receive.r b/test/unittest/ip/tst.lv-receive.r
new file mode 100644
index 00000000..bf81d0e1
--- /dev/null
+++ b/test/unittest/ip/tst.lv-receive.r
@@ -0,0 +1,20 @@
+PROBE ip vmlinux receive
+
+     Probe Description Attributes
+           Identifier Names: Private
+           Data Semantics:   Private
+           Dependency Class: Unknown
+
+     Argument Attributes
+           Identifier Names: Evolving
+           Data Semantics:   Evolving
+           Dependency Class: ISA
+
+     Argument Types
+           args[0]: pktinfo_t *
+           args[1]: csinfo_t *
+           args[2]: ipinfo_t *
+           args[3]: ifinfo_t *
+           args[4]: ipv4info_t *
+           args[5]: ipv6info_t *
+
diff --git a/test/unittest/ip/tst.lv-receive.r.p b/test/unittest/ip/tst.lv-receive.r.p
new file mode 120000
index 00000000..d9c51ca5
--- /dev/null
+++ b/test/unittest/ip/tst.lv-receive.r.p
@@ -0,0 +1 @@
+../lockstat/tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/ip/tst.lv-receive.sh b/test/unittest/ip/tst.lv-receive.sh
new file mode 100755
index 00000000..0bb06caf
--- /dev/null
+++ b/test/unittest/ip/tst.lv-receive.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+
+dtrace=$1
+
+$dtrace $dt_flags -lvn ip:::receive
+exit $?
diff --git a/test/unittest/ip/tst.lv-send.r b/test/unittest/ip/tst.lv-send.r
new file mode 100644
index 00000000..66b5efd3
--- /dev/null
+++ b/test/unittest/ip/tst.lv-send.r
@@ -0,0 +1,20 @@
+PROBE ip vmlinux send
+
+     Probe Description Attributes
+           Identifier Names: Private
+           Data Semantics:   Private
+           Dependency Class: Unknown
+
+     Argument Attributes
+           Identifier Names: Evolving
+           Data Semantics:   Evolving
+           Dependency Class: ISA
+
+     Argument Types
+           args[0]: pktinfo_t *
+           args[1]: csinfo_t *
+           args[2]: ipinfo_t *
+           args[3]: ifinfo_t *
+           args[4]: ipv4info_t *
+           args[5]: ipv6info_t *
+
diff --git a/test/unittest/ip/tst.lv-send.r.p b/test/unittest/ip/tst.lv-send.r.p
new file mode 120000
index 00000000..d9c51ca5
--- /dev/null
+++ b/test/unittest/ip/tst.lv-send.r.p
@@ -0,0 +1 @@
+../lockstat/tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/ip/tst.lv-send.sh b/test/unittest/ip/tst.lv-send.sh
new file mode 100755
index 00000000..46dba5cf
--- /dev/null
+++ b/test/unittest/ip/tst.lv-send.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+
+dtrace=$1
+
+$dtrace $dt_flags -lvn ip:::send
+exit $?
--
2.40.1


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://oss.oracle.com/pipermail/dtrace-devel/attachments/20230922/26e4c8e2/attachment-0001.html>


More information about the DTrace-devel mailing list