Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Oct 2020 15:01:33 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r366908 - in head: share/dtrace sys/netpfil/ipfw
Message-ID:  <202010211501.09LF1XBr041764@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Wed Oct 21 15:01:33 2020
New Revision: 366908
URL: https://svnweb.freebsd.org/changeset/base/366908

Log:
  Add dtrace SDT probe ipfw:::rule-matched.
  
  It helps to reduce complexity with debugging of large ipfw rulesets.
  Also define several constants and translators, that can by used by
  dtrace scripts with this probe.
  
  Reviewed by:	gnn
  Obtained from:	Yandex LLC
  MFC after:	2 weeks
  Sponsored by:	Yandex LLC
  Differential Revision:	https://reviews.freebsd.org/D26879

Added:
  head/share/dtrace/ipfw.d   (contents, props changed)
Modified:
  head/share/dtrace/Makefile
  head/sys/netpfil/ipfw/ip_fw2.c

Modified: head/share/dtrace/Makefile
==============================================================================
--- head/share/dtrace/Makefile	Wed Oct 21 05:57:25 2020	(r366907)
+++ head/share/dtrace/Makefile	Wed Oct 21 15:01:33 2020	(r366908)
@@ -21,7 +21,7 @@ SCRIPTS=	blocking \
 
 SCRIPTSDIR= ${SHAREDIR}/dtrace
 
-DSRCS=		mbuf.d
+DSRCS=		mbuf.d ipfw.d
 
 FILES=		${DSRCS}
 FILESDIR=	/usr/lib/dtrace

Added: head/share/dtrace/ipfw.d
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/share/dtrace/ipfw.d	Wed Oct 21 15:01:33 2020	(r366908)
@@ -0,0 +1,219 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Yandex LLC
+ * Copyright (c) 2020 Andrey V. Elsukov <ae@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#pragma D depends_on provider ipfw
+
+/* ipfw_chk() return values */
+#pragma D binding "1.0" IP_FW_PASS
+inline int IP_FW_PASS = 	0;
+#pragma D binding "1.0" IP_FW_DENY
+inline int IP_FW_DENY = 	1;
+#pragma D binding "1.0" IP_FW_DIVERT
+inline int IP_FW_DIVERT =	2;
+#pragma D binding "1.0" IP_FW_TEE
+inline int IP_FW_TEE =		3;
+#pragma D binding "1.0" IP_FW_DUMMYNET
+inline int IP_FW_DUMMYNET =	4;
+#pragma D binding "1.0" IP_FW_NETGRAPH
+inline int IP_FW_NETGRAPH =	5;
+#pragma D binding "1.0" IP_FW_NGTEE
+inline int IP_FW_NGTEE =	6;
+#pragma D binding "1.0" IP_FW_NAT
+inline int IP_FW_NAT =		7;
+#pragma D binding "1.0" IP_FW_REASS
+inline int IP_FW_REASS =	8;
+#pragma D binding "1.0" IP_FW_NAT64
+inline int IP_FW_NAT64 =	9;
+
+#pragma D binding "1.0" ipfw_retcodes
+inline string ipfw_retcodes[int ret] =
+	ret == IP_FW_PASS ? "PASS" :
+	ret == IP_FW_DENY ? "DENY" :
+	ret == IP_FW_DIVERT ? "DIVERT" :
+	ret == IP_FW_TEE ? "TEE" :
+	ret == IP_FW_DUMMYNET ? "DUMMYNET" :
+	ret == IP_FW_NETGRAPH ? "NETGRAPH" :
+	ret == IP_FW_NGTEE ? "NGTEE" :
+	ret == IP_FW_NAT ? "NAT" :
+	ret == IP_FW_REASS ? "REASS" :
+	ret == IP_FW_NAT64 ? "NAT64" :
+	"<unknown>";
+
+/* ip_fw_args flags */
+#pragma D binding "1.0" IPFW_ARGS_ETHER
+inline int IPFW_ARGS_ETHER =	0x00010000; /* valid ethernet header */
+#pragma D binding "1.0" IPFW_ARGS_NH4
+inline int IPFW_ARGS_NH4 =	0x00020000; /* IPv4 next hop in hopstore */
+#pragma D binding "1.0" IPFW_ARGS_NH6
+inline int IPFW_ARGS_NH6 =	0x00040000; /* IPv6 next hop in hopstore */
+#pragma D binding "1.0" IPFW_ARGS_NH4PTR
+inline int IPFW_ARGS_NH4PTR =	0x00080000; /* IPv4 next hop in next_hop */
+#pragma D binding "1.0" IPFW_ARGS_NH6PTR
+inline int IPFW_ARGS_NH6PTR =	0x00100000; /* IPv6 next hop in next_hop6 */
+#pragma D binding "1.0" IPFW_ARGS_REF
+inline int IPFW_ARGS_REF =	0x00200000; /* valid ipfw_rule_ref	*/
+#pragma D binding "1.0" IPFW_ARGS_IN
+inline int IPFW_ARGS_IN =	0x00400000; /* called on input */
+#pragma D binding "1.0" IPFW_ARGS_OUT	
+inline int IPFW_ARGS_OUT =	0x00800000; /* called on output */
+#pragma D binding "1.0" IPFW_ARGS_IP4
+inline int IPFW_ARGS_IP4 =	0x01000000; /* belongs to v4 ISR */
+#pragma D binding "1.0" IPFW_ARGS_IP6
+inline int IPFW_ARGS_IP6 =	0x02000000; /* belongs to v6 ISR */
+#pragma D binding "1.0" IPFW_ARGS_DROP
+inline int IPFW_ARGS_DROP =	0x04000000; /* drop it (dummynet) */
+#pragma D binding "1.0" IPFW_ARGS_LENMASK
+inline int IPFW_ARGS_LENMASK =	0x0000ffff; /* length of data in *mem */
+
+/* ipfw_rule_ref.info */
+#pragma D binding "1.0" IPFW_INFO_MASK
+inline int IPFW_INFO_MASK =	0x0000ffff;
+#pragma D binding "1.0" IPFW_INFO_OUT
+inline int IPFW_INFO_OUT =	0x00000000;
+#pragma D binding "1.0" IPFW_INFO_IN
+inline int IPFW_INFO_IN =	0x80000000;
+#pragma D binding "1.0" IPFW_ONEPASS
+inline int IPFW_ONEPASS =	0x40000000;
+#pragma D binding "1.0" IPFW_IS_MASK
+inline int IPFW_IS_MASK =	0x30000000;
+#pragma D binding "1.0" IPFW_IS_DIVERT
+inline int IPFW_IS_DIVERT =	0x20000000;
+#pragma D binding "1.0" IPFW_IS_DUMMYNET
+inline int IPFW_IS_DUMMYNET =	0x10000000;
+#pragma D binding "1.0" IPFW_IS_PIPE
+inline int IPFW_IS_PIPE =	0x08000000;
+
+typedef struct ipfw_match_info {
+	uint32_t	flags;
+
+	struct mbuf	*m;
+	void		*mem;
+	struct inpcb	*inp;
+	struct ifnet	*ifp;
+	struct ip	*ipp;
+	struct ip6_hdr	*ip6p;
+
+	/* flow id */
+	uint8_t		addr_type;
+	uint8_t		proto;
+	uint8_t		proto_flags;
+	uint16_t	fib;	/* XXX */
+	in_addr_t	dst_ip;	/* in network byte order */
+	in_addr_t	src_ip;	/* in network byte order */
+	struct in6_addr	dst_ip6;
+	struct in6_addr	src_ip6;
+
+	uint16_t	dst_port; /* in host byte order */
+	uint16_t	src_port; /* in host byte order */
+
+	uint32_t	flowid;	/* IPv6 flowid */
+	uint32_t	extra;
+
+	/* ipfw_rule_ref */
+	uint32_t	slot;
+	uint32_t	rulenum;
+	uint32_t	rule_id;
+	uint32_t	chain_id;
+	uint32_t	match_info;
+} ipfw_match_info_t;
+
+#pragma D binding "1.0" translator
+translator ipfw_match_info_t < struct ip_fw_args *p > {
+	flags =		p->flags;
+	m =		(p->flags & IPFW_ARGS_LENMASK) ? NULL : p->m;
+	mem =		(p->flags & IPFW_ARGS_LENMASK) ? p->mem : NULL;
+	inp =		p->inp;
+	ifp =		p->ifp;
+	/* Initialize IP pointer corresponding to addr_type */
+	ipp =		(p->flags & IPFW_ARGS_IP4) ?
+	    (p->flags & IPFW_ARGS_LENMASK) ? (struct ip *)p->mem :
+	    (p->m != NULL) ? (struct ip *)p->m->m_data : NULL : NULL;
+	ip6p =		(p->flags & IPFW_ARGS_IP6) ?
+	    (p->flags & IPFW_ARGS_LENMASK) ? (struct ip6_hdr *)p->mem :
+	    (p->m != NULL) ? (struct ip6_hdr *)p->m->m_data : NULL : NULL;
+
+	/* fill f_id fields */
+	addr_type =	p->f_id.addr_type;
+	proto =		p->f_id.proto;
+	proto_flags =	p->f_id._flags;
+
+	/* f_id.fib keeps truncated fibnum, use mbuf's fibnum if possible */
+	fib =		p->m != NULL ? p->m->m_pkthdr.fibnum : p->f_id.fib;
+
+	/*
+	 * ipfw_chk() keeps IPv4 addresses in host byte order. But for
+	 * dtrace script it is useful to have them in network byte order,
+	 * because inet_ntoa() uses address in network byte order.
+	 */
+	dst_ip =	htonl(p->f_id.dst_ip);
+	src_ip =	htonl(p->f_id.src_ip);
+
+	dst_ip6 =	p->f_id.dst_ip6;
+	src_ip6 =	p->f_id.src_ip6;
+
+	dst_port =	p->f_id.dst_port;
+	src_port =	p->f_id.src_port;
+
+	flowid =	p->f_id.flow_id6;
+	extra = 	p->f_id.extra;
+
+	/* ipfw_rule_ref */
+	slot =		(p->flags & IPFW_ARGS_REF) ? p->rule.slot : 0;
+	rulenum =	(p->flags & IPFW_ARGS_REF) ? p->rule.rulenum : 0;
+	rule_id =	(p->flags & IPFW_ARGS_REF) ? p->rule.rule_id : 0;
+	chain_id =	(p->flags & IPFW_ARGS_REF) ? p->rule.chain_id : 0;
+	match_info =	(p->flags & IPFW_ARGS_REF) ? p->rule.info : 0;
+};
+
+typedef struct ipfw_rule_info {
+	uint16_t	act_ofs;
+	uint16_t	cmd_len;
+	uint32_t	rulenum;
+	uint8_t		flags;
+	uint8_t		set;
+	uint32_t	rule_id;
+	uint32_t	cached_id;
+	uint32_t	cached_pos;
+	uint32_t	refcnt;
+} ipfw_rule_info_t;
+
+#pragma D binding "1.0" translator
+translator ipfw_rule_info_t < struct ip_fw *r > {
+	act_ofs =	r->act_ofs;
+	cmd_len =	r->cmd_len;
+	rulenum =	r->rulenum;
+	flags =		r->flags;
+	set =		r->set;
+	rule_id =	r->id;
+	cached_id =	r->cached_id;
+	cached_pos =	r->cached_pos;
+	refcnt =	r->refcnt;
+};
+

Modified: head/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw2.c	Wed Oct 21 05:57:25 2020	(r366907)
+++ head/sys/netpfil/ipfw/ip_fw2.c	Wed Oct 21 15:01:33 2020	(r366908)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/proc.h>
 #include <sys/rwlock.h>
 #include <sys/rmlock.h>
+#include <sys/sdt.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
@@ -106,6 +107,18 @@ __FBSDID("$FreeBSD$");
 #include <security/mac/mac_framework.h>
 #endif
 
+#define	IPFW_PROBE(probe, arg0, arg1, arg2, arg3, arg4, arg5)		\
+    SDT_PROBE6(ipfw, , , probe, arg0, arg1, arg2, arg3, arg4, arg5)
+
+SDT_PROVIDER_DEFINE(ipfw);
+SDT_PROBE_DEFINE6(ipfw, , , rule__matched,
+    "int",			/* retval */
+    "int",			/* af */
+    "void *",			/* src addr */
+    "void *",			/* dst addr */
+    "struct ip_fw_args *",	/* args */
+    "struct ip_fw *"		/* rule */);
+
 /*
  * static variables followed by global ones.
  * All ipfw global variables are here.
@@ -3237,6 +3250,13 @@ do {								\
 		struct ip_fw *rule = chain->map[f_pos];
 		/* Update statistics */
 		IPFW_INC_RULE_COUNTER(rule, pktlen);
+		IPFW_PROBE(rule__matched, retval,
+		    is_ipv4 ? AF_INET : AF_INET6,
+		    is_ipv4 ? (uintptr_t)&src_ip :
+		        (uintptr_t)&args->f_id.src_ip6,
+		    is_ipv4 ? (uintptr_t)&dst_ip :
+		        (uintptr_t)&args->f_id.dst_ip6,
+		    args, rule);
 	} else {
 		retval = IP_FW_DENY;
 		printf("ipfw: ouch!, skip past end of rules, denying packet\n");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202010211501.09LF1XBr041764>