summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2002-02-26 07:25:34 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2002-02-26 07:25:34 +0000
commit14608d25f576fa09b5a6e105a9e94fb2b85347ec (patch)
tree2cfbf71ce629b6f97df9ab26284a0b784451cbd2
parent65583a8e59b50c7e450aef00218173b3ff749335 (diff)
Add optional pool memory hard limits, mainly as temporary solution
until pool exhaustion causes problems no more.
-rw-r--r--sbin/pfctl/pfctl.821
-rw-r--r--sbin/pfctl/pfctl.c121
-rw-r--r--sys/net/pf.c42
-rw-r--r--sys/net/pf_norm.c5
-rw-r--r--sys/net/pfvar.h15
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_ */