The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5062afff9de7e67da96e3f0dcb9d8bbd5a4e1c5b

commit 5062afff9de7e67da96e3f0dcb9d8bbd5a4e1c5b
Author:     Kristof Provost <[email protected]>
AuthorDate: 2021-08-13 11:42:59 +0000
Commit:     Kristof Provost <[email protected]>
CommitDate: 2021-09-29 13:11:54 +0000

    pfctl: userspace adaptive syncookies configration
    
    Hook up the userspace bits to configure syncookies in adaptive mode.
    
    MFC after:      1 week
    Sponsored by:   Modirum MDPay
    Differential Revision:  https://reviews.freebsd.org/D32136
---
 lib/libpfctl/libpfctl.c   | 55 ++++++++++++++++++++++++++++++++++++++++++-----
 lib/libpfctl/libpfctl.h   |  6 +++++-
 sbin/pfctl/parse.y        | 43 ++++++++++++++++++++++++++++++++++--
 sbin/pfctl/pfctl.c        | 51 ++++++++++++++++++++++++++++++++++++++++++-
 sbin/pfctl/pfctl_parser.c |  5 +++--
 sbin/pfctl/pfctl_parser.h |  8 +++++++
 sys/net/pfvar.h           |  3 +++
 7 files changed, 160 insertions(+), 11 deletions(-)

diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 576b256155fb..aaf5998ed0d6 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -50,6 +50,12 @@
 
 #include "libpfctl.h"
 
+const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = {
+       "never",
+       "always",
+       "adaptive"
+};
+
 static int     _pfctl_clear_states(int , const struct pfctl_kill *,
                    unsigned int *, uint64_t);
 
@@ -938,17 +944,40 @@ pfctl_kill_states(int dev, const struct pfctl_kill *kill, 
unsigned int *killed)
        return (_pfctl_clear_states(dev, kill, killed, DIOCKILLSTATESNV));
 }
 
+static int
+pfctl_get_limit(int dev, const int index, u_int *limit)
+{
+       struct pfioc_limit pl;
+
+       bzero(&pl, sizeof(pl));
+       pl.index = index;
+
+       if (ioctl(dev, DIOCGETLIMIT, &pl) == -1)
+               return (errno);
+
+       *limit = pl.limit;
+
+       return (0);
+}
+
 int
 pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s)
 {
        struct pfioc_nv  nv;
        nvlist_t        *nvl;
        int              ret;
+       u_int            state_limit;
+
+       ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
+       if (ret != 0)
+               return (ret);
 
        nvl = nvlist_create(0);
 
        nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER);
-       nvlist_add_bool(nvl, "adaptive", false); /* XXX TODO */
+       nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE);
+       nvlist_add_number(nvl, "highwater", state_limit * s->highwater / 100);
+       nvlist_add_number(nvl, "lowwater", state_limit * s->lowwater / 100);
 
        nv.data = nvlist_pack(nvl, &nv.len);
        nv.size = nv.len;
@@ -966,12 +995,18 @@ pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
 {
        struct pfioc_nv  nv;
        nvlist_t        *nvl;
-       bool            enabled, adaptive;
+       int              ret;
+       u_int            state_limit;
+       bool             enabled, adaptive;
+
+       ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
+       if (ret != 0)
+               return (ret);
 
        bzero(s, sizeof(*s));
 
-       nv.data = malloc(128);
-       nv.len = nv.size = 128;
+       nv.data = malloc(256);
+       nv.len = nv.size = 256;
 
        if (ioctl(dev, DIOCGETSYNCOOKIES, &nv)) {
                free(nv.data);
@@ -987,7 +1022,17 @@ pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
        enabled = nvlist_get_bool(nvl, "enabled");
        adaptive = nvlist_get_bool(nvl, "adaptive");
 
-       s->mode = enabled ? PFCTL_SYNCOOKIES_ALWAYS : PFCTL_SYNCOOKIES_NEVER;
+       if (enabled) {
+               if (adaptive)
+                       s->mode = PFCTL_SYNCOOKIES_ADAPTIVE;
+               else
+                       s->mode = PFCTL_SYNCOOKIES_ALWAYS;
+       } else {
+               s->mode = PFCTL_SYNCOOKIES_NEVER;
+       }
+
+       s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit;
+       s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit;
 
        nvlist_destroy(nvl);
 
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index f57497b4a88a..1f7259ee8d32 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -276,11 +276,15 @@ struct pfctl_states {
 
 enum pfctl_syncookies_mode {
        PFCTL_SYNCOOKIES_NEVER,
-       PFCTL_SYNCOOKIES_ALWAYS
+       PFCTL_SYNCOOKIES_ALWAYS,
+       PFCTL_SYNCOOKIES_ADAPTIVE
 };
+extern const char* PFCTL_SYNCOOKIES_MODE_NAMES[];
 
 struct pfctl_syncookies {
        enum pfctl_syncookies_mode      mode;
+       uint8_t                         highwater;      /* Percent */
+       uint8_t                         lowwater;       /* Percent */
 };
 
 struct pfctl_status* pfctl_get_status(int dev);
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 6bcf5a0bc397..89d5f330da47 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -320,6 +320,7 @@ static struct codel_opts     codel_opts;
 static struct node_hfsc_opts    hfsc_opts;
 static struct node_fairq_opts   fairq_opts;
 static struct node_state_opt   *keep_state_defaults = NULL;
+static struct pfctl_watermarks  syncookie_opts;
 
 int             disallow_table(struct node_host *, const char *);
 int             disallow_urpf_failed(struct node_host *, const char *);
@@ -445,6 +446,7 @@ typedef struct {
                struct node_hfsc_opts    hfsc_opts;
                struct node_fairq_opts   fairq_opts;
                struct codel_opts        codel_opts;
+               struct pfctl_watermarks *watermarks;
        } v;
        int lineno;
 } YYSTYPE;
@@ -531,6 +533,7 @@ int parseport(char *, struct range *r, int);
 %type  <v.pool_opts>           pool_opts pool_opt pool_opts_l
 %type  <v.tagged>              tagged
 %type  <v.rtableid>            rtable
+%type  <v.watermarks>          syncookie_opts
 %%
 
 ruleset                : /* empty */
@@ -729,14 +732,19 @@ option            : SET OPTIMIZATION STRING               
{
                | SET KEEPCOUNTERS {
                        pf->keep_counters = true;
                }
-               | SET SYNCOOKIES syncookie_val {
-                       pf->syncookies = $3;
+               | SET SYNCOOKIES syncookie_val syncookie_opts {
+                       if (pfctl_cfg_syncookies(pf, $3, $4)) {
+                               yyerror("error setting syncookies");
+                               YYERROR;
+                       }
                }
                ;
 
 syncookie_val  : STRING        {
                        if (!strcmp($1, "never"))
                                $$ = PFCTL_SYNCOOKIES_NEVER;
+                       else if (!strcmp($1, "adaptive"))
+                               $$ = PFCTL_SYNCOOKIES_ADAPTIVE;
                        else if (!strcmp($1, "always"))
                                $$ = PFCTL_SYNCOOKIES_ALWAYS;
                        else {
@@ -745,6 +753,37 @@ syncookie_val  : STRING        {
                        }
                }
                ;
+syncookie_opts  : /* empty */                   { $$ = NULL; }
+               | {
+                       memset(&syncookie_opts, 0, sizeof(syncookie_opts));
+                 } '(' syncookie_opt_l ')'     { $$ = &syncookie_opts; }
+               ;
+
+syncookie_opt_l : syncookie_opt_l comma syncookie_opt
+               | syncookie_opt
+               ;
+
+syncookie_opt   : STRING STRING {
+                       double   val;
+                       char    *cp;
+
+                       val = strtod($2, &cp);
+                       if (cp == NULL || strcmp(cp, "%"))
+                               YYERROR;
+                       if (val <= 0 || val > 100) {
+                               yyerror("illegal percentage value");
+                               YYERROR;
+                       }
+                       if (!strcmp($1, "start")) {
+                               syncookie_opts.hi = val;
+                       } else if (!strcmp($1, "end")) {
+                               syncookie_opts.lo = val;
+                       } else {
+                               yyerror("illegal syncookie option");
+                               YYERROR;
+                       }
+               }
+               ;
 
 stringall      : STRING        { $$ = $1; }
                | ALL           {
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 8f3698e398f6..d7bde0012e9b 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1812,6 +1812,10 @@ pfctl_init_options(struct pfctl *pf)
        pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
 
        pf->debug = PF_DEBUG_URGENT;
+
+       pf->syncookies = false;
+       pf->syncookieswat[0] = PF_SYNCOOKIES_LOWATPCT;
+       pf->syncookieswat[1] = PF_SYNCOOKIES_HIWATPCT;
 }
 
 int
@@ -2069,7 +2073,9 @@ pfctl_load_syncookies(struct pfctl *pf, u_int8_t val)
 
        bzero(&cookies, sizeof(cookies));
 
-       cookies.mode = val ? PFCTL_SYNCOOKIES_ALWAYS : PFCTL_SYNCOOKIES_NEVER;
+       cookies.mode = val;
+       cookies.lowwater = pf->syncookieswat[0];
+       cookies.highwater = pf->syncookieswat[1];
 
        if (pfctl_set_syncookies(dev, &cookies)) {
                warnx("DIOCSETSYNCOOKIES");
@@ -2078,6 +2084,49 @@ pfctl_load_syncookies(struct pfctl *pf, u_int8_t val)
        return (0);
 }
 
+int
+pfctl_cfg_syncookies(struct pfctl *pf, uint8_t val, struct pfctl_watermarks *w)
+{
+       if (val != PF_SYNCOOKIES_ADAPTIVE && w != NULL) {
+               warnx("syncookies start/end only apply to adaptive");
+               return (1);
+       }
+       if (val == PF_SYNCOOKIES_ADAPTIVE && w != NULL) {
+               if (!w->hi)
+                       w->hi = PF_SYNCOOKIES_HIWATPCT;
+               if (!w->lo)
+                       w->lo = w->hi / 2;
+               if (w->lo >= w->hi) {
+                       warnx("start must be higher than end");
+                       return (1);
+               }
+               pf->syncookieswat[0] = w->lo;
+               pf->syncookieswat[1] = w->hi;
+               pf->syncookieswat_set = 1;
+       }
+
+       if (pf->opts & PF_OPT_VERBOSE) {
+               if (val == PF_SYNCOOKIES_NEVER)
+                       printf("set syncookies never\n");
+               else if (val == PF_SYNCOOKIES_ALWAYS)
+                       printf("set syncookies always\n");
+               else if (val == PF_SYNCOOKIES_ADAPTIVE) {
+                       if (pf->syncookieswat_set)
+                               printf("set syncookies adaptive (start %u%%, "
+                                   "end %u%%)\n", pf->syncookieswat[1],
+                                   pf->syncookieswat[0]);
+                       else
+                               printf("set syncookies adaptive\n");
+               } else {        /* cannot happen */
+                       warnx("king bula ate all syncookies");
+                       return (1);
+               }
+       }
+
+       pf->syncookies = val;
+       return (0);
+}
+
 int
 pfctl_set_debug(struct pfctl *pf, char *d)
 {
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 131ad22123e2..91a3a38ef016 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
 #include <net/pfvar.h>
 #include <arpa/inet.h>
 
+#include <assert.h>
 #include <search.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -618,9 +619,9 @@ print_status(struct pfctl_status *s, struct 
pfctl_syncookies *cookies, int opts)
                }
 
                printf("Syncookies\n");
+               assert(cookies->mode <= PFCTL_SYNCOOKIES_ADAPTIVE);
                printf("  %-25s %s\n", "mode",
-                   cookies->mode == PFCTL_SYNCOOKIES_NEVER ?
-                   "never" : "always");
+                   PFCTL_SYNCOOKIES_MODE_NAMES[cookies->mode]);
        }
 }
 
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 12a66e1ae710..484830c61791 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -101,6 +101,8 @@ struct pfctl {
        char            *ifname;
        bool             keep_counters;
        u_int8_t         syncookies;
+       u_int8_t         syncookieswat[2];      /* lowat, highwat, in % */
+       u_int8_t         syncookieswat_set;
 
        u_int8_t         timeout_set[PFTM_MAX];
        u_int8_t         limit_set[PF_LIMIT_MAX];
@@ -200,6 +202,11 @@ struct pfctl_altq {
        } meta;
 };
 
+struct pfctl_watermarks {
+       uint32_t        hi;
+       uint32_t        lo;
+};
+
 #ifdef __FreeBSD__
 /*
  * XXX
@@ -270,6 +277,7 @@ int pfctl_set_logif(struct pfctl *, char *);
 int    pfctl_set_hostid(struct pfctl *, u_int32_t);
 int    pfctl_set_debug(struct pfctl *, char *);
 int    pfctl_set_interface_flags(struct pfctl *, char *, int, int);
+int    pfctl_cfg_syncookies(struct pfctl *, uint8_t, struct pfctl_watermarks 
*);
 
 int    parse_config(char *, struct pfctl *);
 int    parse_flags(char *);
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 90ef19c59172..ba5a2d341172 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1386,6 +1386,9 @@ enum pf_syncookies_mode {
        PF_SYNCOOKIES_MODE_MAX = PF_SYNCOOKIES_ADAPTIVE
 };
 
+#define        PF_SYNCOOKIES_HIWATPCT  25
+#define        PF_SYNCOOKIES_LOWATPCT  (PF_SYNCOOKIES_HIWATPCT / 2)
+
 #ifdef _KERNEL
 struct pf_kstatus {
        counter_u64_t   counters[PFRES_MAX]; /* reason for passing/dropping */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to