From owner-svn-src-head@freebsd.org Wed Oct 21 15:01:34 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 3010D44DB6B; Wed, 21 Oct 2020 15:01:34 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4CGYby0Py8z4PK8; Wed, 21 Oct 2020 15:01:34 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id E5B6E276FE; Wed, 21 Oct 2020 15:01:33 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 09LF1XHZ041767; Wed, 21 Oct 2020 15:01:33 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 09LF1XBr041764; Wed, 21 Oct 2020 15:01:33 GMT (envelope-from ae@FreeBSD.org) Message-Id: <202010211501.09LF1XBr041764@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Wed, 21 Oct 2020 15:01:33 +0000 (UTC) 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 X-SVN-Group: head X-SVN-Commit-Author: ae X-SVN-Commit-Paths: in head: share/dtrace sys/netpfil/ipfw X-SVN-Commit-Revision: 366908 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Oct 2020 15:01:34 -0000 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 + * + * 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" : + ""; + +/* 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 #include #include +#include #include #include #include @@ -106,6 +107,18 @@ __FBSDID("$FreeBSD$"); #include #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");