git: 5062afff9de7 - main - pfctl: userspace adaptive syncookies configration
Kristof Provost
kp at FreeBSD.org
Wed Sep 29 13:42:32 UTC 2021
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=5062afff9de7e67da96e3f0dcb9d8bbd5a4e1c5b
commit 5062afff9de7e67da96e3f0dcb9d8bbd5a4e1c5b
Author: Kristof Provost <kp at FreeBSD.org>
AuthorDate: 2021-08-13 11:42:59 +0000
Commit: Kristof Provost <kp at FreeBSD.org>
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 */
More information about the dev-commits-src-main
mailing list