The branch main has been updated by kp:

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

commit 0592a4c83d67547644763fb023abd5eb28e57f92
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2021-05-05 19:00:16 +0000
Commit:     Kristof Provost <k...@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!!!
  */
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to