Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 May 2021 11:54:50 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0592a4c83d67 - main - pf: Add DIOCGETSTATESNV
Message-ID:  <202105201154.14KBsocI056842@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=0592a4c83d67547644763fb023abd5eb28e57f92

commit 0592a4c83d67547644763fb023abd5eb28e57f92
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-05-05 19:00:16 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-05-20 10:49:27 +0000

    pf: Add DIOCGETSTATESNV
    
    Add DIOCGETSTATESNV, an nvlist-based alternative to DIOCGETSTATES.
    
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D30243
---
 share/man/man4/pf.4       | 71 ++++++++++++++++++++++++++++++++-----------
 sys/net/pfvar.h           |  1 +
 sys/netpfil/pf/pf_ioctl.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+), 18 deletions(-)

diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4
index 24843535c924..133e4d300043 100644
--- a/share/man/man4/pf.4
+++ b/share/man/man4/pf.4
@@ -415,30 +415,65 @@ Set the debug level.
 enum	{ PF_DEBUG_NONE, PF_DEBUG_URGENT, PF_DEBUG_MISC,
 	  PF_DEBUG_NOISY };
 .Ed
-.It Dv DIOCGETSTATES Fa "struct pfioc_states *ps"
+.It Dv DIOCGETSTATESNV Fa "struct pfioc_nv *nv"
 Get state table entries.
 .Bd -literal
-struct pfioc_states {
-	int	ps_len;
-	union {
-		caddr_t		 psu_buf;
-		struct pf_state *psu_states;
-	} ps_u;
-#define ps_buf		ps_u.psu_buf
-#define ps_states	ps_u.psu_states
+nvlist pf_state_key {
+	nvlist pf_addr	addr[2];
+	number		port[2];
+	number		af;
+	number		proto;
+};
+
+nvlist pf_state_scrub {
+	bool	timestamp;
+	number	ttl;
+	number	ts_mod;
+};
+
+nvlist pf_state_peer {
+	nvlist pf_state_scrub	scrub;
+	number			seqlo;
+	number			seqhi;
+	number			seqdiff;
+	number			max_win;
+	number			mss;
+	number			state;
+	number			wscale;
+};
+
+nvlist pf_state {
+	number			id;
+	string			ifname;
+	nvlist pf_state_key	stack_key;
+	nvlist pf_state_key	wire_key;
+	nvlist pf_state_peer	src;
+	nvlist pf_state_peer	dst;
+	nvlist pf_addr		rt_addr;
+	number			rule;
+	number			anchor;
+	number			nat_rule;
+	number			expire;
+	number			packets[2];
+	number			bytes[2];
+	number			creatorid;
+	number			direction;
+	number			log;
+	number			state_flags;
+	number			timeout;
+	number			sync_flags;
+};
+
+nvlist pf_states {
+	number		count;
+	nvlist pf_state	states[];
 };
 .Ed
 .Pp
 If
-.Va ps_len
-is non-zero on entry, as many states as possible that can fit into this
-size will be copied into the supplied buffer
-.Va ps_states .
-On exit,
-.Va ps_len
-is always set to the total size required to hold all state table entries
-(i.e., it is set to
-.Li sizeof(struct pf_state) * nr ) .
+.Va pfioc_nv.size
+is insufficiently large, as many states as possible that can fit into this
+size will be copied into the supplied buffer.
 .It Dv DIOCCHANGERULE Fa "struct pfioc_rule *pcr"
 Add or remove the
 .Va rule
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 1bd1ebd27449..d9e35dae753a 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1264,6 +1264,7 @@ struct pfioc_iface {
 #define DIOCNATLOOK	_IOWR('D', 23, struct pfioc_natlook)
 #define DIOCSETDEBUG	_IOWR('D', 24, u_int32_t)
 #define DIOCGETSTATES	_IOWR('D', 25, struct pfioc_states)
+#define DIOCGETSTATESNV	_IOWR('D', 25, struct pfioc_nv)
 #define DIOCCHANGERULE	_IOWR('D', 26, struct pfioc_rule)
 /* XXX cut 26 - 28 */
 #define DIOCSETTIMEOUT	_IOWR('D', 29, struct pfioc_tm)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 1ea7310ebebb..8424e0ce5689 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -209,6 +209,7 @@ static int		 pf_killstates_row(struct pf_kstate_kill *,
 static int		 pf_killstates_nv(struct pfioc_nv *);
 static int		 pf_clearstates_nv(struct pfioc_nv *);
 static int		 pf_getstate(struct pfioc_nv *);
+static int		 pf_getstates(struct pfioc_nv *);
 static int		 pf_clear_tables(void);
 static void		 pf_clear_srcnodes(struct pf_ksrc_node *);
 static void		 pf_kill_srcnodes(struct pfioc_src_node_kill *);
@@ -2948,6 +2949,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		case DIOCNATLOOK:
 		case DIOCSETDEBUG:
 		case DIOCGETSTATES:
+		case DIOCGETSTATESNV:
 		case DIOCGETTIMEOUT:
 		case DIOCCLRRULECTRS:
 		case DIOCGETLIMIT:
@@ -3000,6 +3002,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		case DIOCGETSTATENV:
 		case DIOCGETSTATUS:
 		case DIOCGETSTATES:
+		case DIOCGETSTATESNV:
 		case DIOCGETTIMEOUT:
 		case DIOCGETLIMIT:
 		case DIOCGETALTQSV0:
@@ -3709,6 +3712,11 @@ DIOCGETSTATES_full:
 		break;
 	}
 
+	case DIOCGETSTATESNV: {
+		error = pf_getstates((struct pfioc_nv *)addr);
+		break;
+	}
+
 	case DIOCGETSTATUS: {
 		struct pf_status *s = (struct pf_status *)addr;
 
@@ -5916,6 +5924,74 @@ errout:
 	return (error);
 }
 
+static int
+pf_getstates(struct pfioc_nv *nv)
+{
+	nvlist_t	*nvl = NULL, *nvls;
+	void		*nvlpacked = NULL;
+	struct pf_state	*s = NULL;
+	int		 error = 0;
+	uint64_t	 count = 0;
+
+#define ERROUT(x)	ERROUT_FUNCTION(errout, x)
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		ERROUT(ENOMEM);
+
+	nvlist_add_number(nvl, "count", uma_zone_get_cur(V_pf_state_z));
+
+	for (int i = 0; i < pf_hashmask; i++) {
+		struct pf_idhash *ih = &V_pf_idhash[i];
+
+		PF_HASHROW_LOCK(ih);
+		LIST_FOREACH(s, &ih->states, entry) {
+			if (s->timeout == PFTM_UNLINKED)
+				continue;
+
+			nvls = pf_state_to_nvstate(s);
+			if (nvls == NULL) {
+				PF_HASHROW_UNLOCK(ih);
+				ERROUT(ENOMEM);
+			}
+			if ((nvlist_size(nvl) + nvlist_size(nvls)) > nv->size) {
+				/* We've run out of room for more states. */
+				nvlist_destroy(nvls);
+				PF_HASHROW_UNLOCK(ih);
+				goto DIOCGETSTATESNV_full;
+			}
+			nvlist_append_nvlist_array(nvl, "states", nvls);
+			count++;
+		}
+		PF_HASHROW_UNLOCK(ih);
+	}
+
+	/* We've managed to put them all the available space. Let's make sure
+	 * 'count' matches our array (that's racy, because we don't hold a lock
+	 * over all states, only over each row individually. */
+	(void)nvlist_take_number(nvl, "count");
+	nvlist_add_number(nvl, "count", count);
+
+DIOCGETSTATESNV_full:
+
+	nvlpacked = nvlist_pack(nvl, &nv->len);
+	if (nvlpacked == NULL)
+		ERROUT(ENOMEM);
+
+	if (nv->size == 0)
+		ERROUT(0);
+	else if (nv->size < nv->len)
+		ERROUT(ENOSPC);
+
+	error = copyout(nvlpacked, nv->data, nv->len);
+
+#undef ERROUT
+errout:
+	free(nvlpacked, M_TEMP);
+	nvlist_destroy(nvl);
+	return (error);
+}
+
 /*
  * XXX - Check for version missmatch!!!
  */



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