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
This commit is contained in:
parent
955460d41e
commit
5062afff9d
@ -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;
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user