diff options
author | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2002-02-26 07:25:34 +0000 |
---|---|---|
committer | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2002-02-26 07:25:34 +0000 |
commit | 14608d25f576fa09b5a6e105a9e94fb2b85347ec (patch) | |
tree | 2cfbf71ce629b6f97df9ab26284a0b784451cbd2 | |
parent | 65583a8e59b50c7e450aef00218173b3ff749335 (diff) |
Add optional pool memory hard limits, mainly as temporary solution
until pool exhaustion causes problems no more.
-rw-r--r-- | sbin/pfctl/pfctl.8 | 21 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 121 | ||||
-rw-r--r-- | sys/net/pf.c | 42 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 5 | ||||
-rw-r--r-- | sys/net/pfvar.h | 15 |
5 files changed, 193 insertions, 11 deletions
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8 index 74c1ef2e1b8..9e74d62a194 100644 --- a/sbin/pfctl/pfctl.8 +++ b/sbin/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.40 2002/02/11 18:43:51 mpech Exp $ +.\" $OpenBSD: pfctl.8,v 1.41 2002/02/26 07:25:33 dhartmei Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -35,6 +35,7 @@ .Op Fl dehnqvz .Op Fl F Ar modifier .Op Fl l Ar interface +.Op Fl m Ar modifier .Op Fl N Ar file .Op Fl O Ar level .Op Fl R Ar file @@ -114,6 +115,24 @@ Enable collection of packet and byte count statistics for interface named These statistics can be viewed with the .Fl s Ar info option. +.It Fl m Ar modifier +Gets or sets hard limits on the memory pools used by the packet filter. +See +.Xr pool 9 +for an explanation of memory pools. +The modifier has the form name[=limit], where name specifies one of the +following pools and limit is either a positive integer (maximum number +of pool entries) or the string "inf" (removes the limit): +.Bl -tag -width "m states[=limit] " -compact +.It Fl m Ar states[=limit] +Maximum number of entries in the memory pool used by state table +entries (generated by 'keep state' rules). +.It Fl m Ar frags[=limit] +Maximum number of entries in the memory pool used for fragment +caching (generated by 'scrub' rules). +.It Fl m Ar all +Display all maxima, cannot be set. +.El .It Fl n Do not actually load rules, just parse them. .It Fl N Ar file diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 367a78dcd16..f04c4898bc7 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.51 2002/01/09 11:30:53 dhartmei Exp $ */ +/* $OpenBSD: pfctl.c,v 1.52 2002/02/26 07:25:33 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -44,6 +44,7 @@ #include <fcntl.h> #include <errno.h> #include <err.h> +#include <limits.h> #include "pfctl_parser.h" @@ -65,6 +66,9 @@ int pfctl_log(int, char *, int); int pfctl_timeout(int, char *, int); int pfctl_gettimeout(int, const char *); int pfctl_settimeout(int, const char *, int); +int pfctl_limit(int, char *, int); +int pfctl_getlimit(int, const char *); +int pfctl_setlimit(int, const char *, unsigned); int pfctl_debug(int, u_int32_t, int); int pfctl_clear_rule_counters(int, int); @@ -76,6 +80,7 @@ char *natopt; char *rulesopt; char *showopt; char *timeoutopt; +char *limitopt; char *debugopt; char *infile; @@ -102,6 +107,14 @@ static const struct { { "interval", PFTM_INTERVAL }, { NULL, 0 }}; +static const struct { + const char *name; + int index; +} pf_limits[] = { + { "states", PF_LIMIT_STATES }, + { "frags", PF_LIMIT_FRAGS }, + { NULL, 0 }}; + struct pf_hint { const char *name; int timeout; @@ -578,6 +591,100 @@ pfctl_hint(int dev, const char *opt, int opts) } int +pfctl_limit(int dev, char *opt, int opts) +{ + char *arg, *serr = NULL; + unsigned limit; + + arg = index(opt, '='); + if (arg == NULL) + return pfctl_getlimit(dev, opt); + else { + if (*arg) + *arg++ = 0; + if (strcasecmp(arg, "inf") == 0) + limit = UINT_MAX; + else { + limit = strtol(arg, &serr, 10); + if (*serr || !*arg) { + warnx("Bad limit argument. " + "Format -m name=limit"); + return (1); + } + } + return pfctl_setlimit(dev, opt, limit); + } +} + +int +pfctl_getlimit(int dev, const char *opt) +{ + struct pfioc_limit pl; + int i, found = 0; + + for (i = 0; pf_limits[i].name; i++) { + if (strcmp(opt, "all") == 0 || + strcasecmp(opt, pf_limits[i].name) == 0) { + found = 1; + pl.index = i; + if (ioctl(dev, DIOCGETLIMIT, &pl)) + err(1, "DIOCGETLIMIT"); + printf("%-10s ", pf_limits[i].name); + if (pl.limit == UINT_MAX) + printf("unlimited\n"); + else + printf("hard limit %6u\n", pl.limit); + } + } + if (found == 0) { + warnx("Bad pool name. Format -m name[=<limit>]"); + return (1); + } + return (0); +} + +int +pfctl_setlimit(int dev, const char *opt, unsigned limit) +{ + struct pfioc_limit pl; + int i; + + for (i = 0; pf_limits[i].name; i++) { + if (strcasecmp(opt, pf_limits[i].name) == 0) { + pl.index = i; + pl.limit = limit; + if (ioctl(dev, DIOCSETLIMIT, &pl)) { + if (errno == EBUSY) { + warnx("Current pool size exceeds " + "requested hard limit"); + return (1); + } else + err(1, "DIOCSETLIMIT"); + } + if ((opts & PF_OPT_QUIET) == 0) { + printf("%s ", pf_limits[i].name); + if (pl.limit == UINT_MAX) + printf("unlimited"); + else + printf("hard limit %u", pl.limit); + printf(" -> "); + if (limit == UINT_MAX) + printf("unlimited"); + else + printf("hard limit %u", limit); + printf("\n"); + } + break; + } + } + if (pf_limits[i].name == NULL) { + warnx("Bad pool name. Format -m name[=<limit>]"); + return (1); + } + return (0); +} + +int pfctl_timeout(int dev, char *opt, int opts) { char *seconds, *serr = NULL; @@ -592,7 +699,7 @@ pfctl_timeout(int dev, char *opt, int opts) *seconds++ = '\0'; /* Eat '=' */ setval = strtol(seconds, &serr, 10); if (*serr != '\0' || *seconds == '\0' || setval < 0) { - warnx("Bad timeout arguement. Format -t name=seconds"); + warnx("Bad timeout argument. Format -t name=seconds"); return 1; } return pfctl_settimeout(dev, opt, setval); @@ -709,7 +816,7 @@ main(int argc, char *argv[]) if (argc < 2) usage(); - while ((ch = getopt(argc, argv, "deqF:hl:nN:O:R:s:t:vx:z")) != -1) { + while ((ch = getopt(argc, argv, "deqF:hl:m:nN:O:R:s:t:vx:z")) != -1) { switch (ch) { case 'd': opts |= PF_OPT_DISABLE; @@ -730,6 +837,10 @@ main(int argc, char *argv[]) logopt = optarg; mode = O_RDWR; break; + case 'm': + limitopt = optarg; + mode = O_RDWR; + break; case 'n': opts |= PF_OPT_NOACTION; break; @@ -867,6 +978,10 @@ main(int argc, char *argv[]) if (pfctl_timeout(dev, timeoutopt, opts)) error = 1; + if (limitopt != NULL) + if (pfctl_limit(dev, limitopt, opts)) + error = 1; + if (opts & PF_OPT_ENABLE) if (pfctl_enable(dev, opts)) error = 1; diff --git a/sys/net/pf.c b/sys/net/pf.c index ccc40b64335..4cd075e965f 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.192 2002/02/23 00:03:58 art Exp $ */ +/* $OpenBSD: pf.c,v 1.193 2002/02/26 07:25:33 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -173,6 +173,12 @@ int *pftm_timeouts[PFTM_MAX] = { &pftm_tcp_first_packet, struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl, pf_sport_pl; struct pool pf_rdr_pl, pf_state_pl, pf_binat_pl; +struct pf_pool_limit { + void *pp; + unsigned limit; +} pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, UINT_MAX }, + { &pf_frent_pl, PFFRAG_FRENT_HIWAT } }; + int pf_tree_key_compare(struct pf_tree_key *, struct pf_tree_key *); void pf_addrcpy(struct pf_addr *, struct pf_addr *, @@ -1060,9 +1066,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATES: case DIOCGETTIMEOUT: case DIOCCLRRULECTRS: + case DIOCGETLIMIT: break; default: - return EPERM; + return (EPERM); } if (!(flags & FWRITE)) @@ -1079,6 +1086,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETTIMEOUT: case DIOCGETBINATS: case DIOCGETBINAT: + case DIOCGETLIMIT: break; default: return (EACCES); @@ -2164,6 +2172,36 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } + case DIOCGETLIMIT: { + struct pfioc_limit *pl = (struct pfioc_limit *)addr; + + if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { + error = EINVAL; + goto fail; + } + pl->limit = pf_pool_limits[pl->index].limit; + break; + } + + case DIOCSETLIMIT: { + struct pfioc_limit *pl = (struct pfioc_limit *)addr; + int old_limit; + + if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { + error = EINVAL; + goto fail; + } + if (pool_sethardlimit(pf_pool_limits[pl->index].pp, + pl->limit, NULL, 0) != 0) { + error = EBUSY; + goto fail; + } + old_limit = pf_pool_limits[pl->index].limit; + pf_pool_limits[pl->index].limit = pl->limit; + pl->limit = old_limit; + break; + } + case DIOCSETDEBUG: { u_int32_t *level = (u_int32_t *)addr; pf_status.debug = *level; diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 2d256538670..38de048815f 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.19 2002/02/25 00:29:07 dhartmei Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.20 2002/02/26 07:25:33 dhartmei Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -90,9 +90,6 @@ u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t); int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); -#define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ -#define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */ - #define DPFPRINTF(x) if (pf_status.debug) printf x #if NPFLOG > 0 diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 2e76d0792bd..9cb88d8538a 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.63 2002/02/14 23:53:32 dhartmei Exp $ */ +/* $OpenBSD: pfvar.h,v 1.64 2002/02/26 07:25:33 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -51,6 +51,7 @@ enum { PFTM_TCP_FIRST_PACKET=0, PFTM_TCP_OPENING=1, PFTM_TCP_ESTABLISHED=2, PFTM_OTHER_FIRST_PACKET=11, PFTM_OTHER_SINGLE=12, PFTM_OTHER_MULTIPLE=13, PFTM_FRAG=14, PFTM_INTERVAL=15, PFTM_MAX=16 }; enum { PF_FASTROUTE=1, PF_ROUTETO=2, PF_DUPTO=3 }; +enum { PF_LIMIT_STATES=0, PF_LIMIT_FRAGS=1, PF_LIMIT_MAX=2 }; struct pf_addr { union { @@ -420,6 +421,9 @@ struct pf_status { u_int32_t debug; }; +#define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ +#define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */ + /* * ioctl parameter structures */ @@ -510,6 +514,11 @@ struct pfioc_tm { int seconds; }; +struct pfioc_limit { + int index; + unsigned limit; +}; + /* * ioctl operations */ @@ -552,6 +561,8 @@ struct pfioc_tm { #define DIOCCHANGEBINAT _IOWR('D', 36, struct pfioc_changebinat) #define DIOCADDSTATE _IOWR('D', 37, struct pfioc_state) #define DIOCCLRRULECTRS _IO ('D', 38) +#define DIOCGETLIMIT _IOWR('D', 39, struct pfioc_limit) +#define DIOCSETLIMIT _IOWR('D', 40, struct pfioc_limit) #ifdef _KERNEL @@ -583,6 +594,8 @@ void pf_purge_expired_fragments(void); extern struct pf_rulequeue *pf_rules_active; extern struct pf_status pf_status; +extern struct pool pf_frent_pl, pf_frag_pl; + #endif /* _KERNEL */ #endif /* _NET_PFVAR_H_ */ |