Hi,
in an earlier thread Daniel suggested that it might be a good idea to skip pf
processing on lo0:
http://www.monkey.org/openbsd/archive/tech/0407/msg00061.html
Another thread on freebsd-net:
http://lists.freebsd.org/pipermail/freebsd-net/2004-December/005906.html
is discussing the possible overhead with filtering interfaces that do not
transport any IP-level data or in setups with huge LAN pipes that you don't
want to filter on.
As a solution I'd like to propose a new option "skip on <interface>" that
disables filtering on the listed interface(s). I realize this as a flag in
the already existing pf internal interface list. See attachment. The cost is
a simple compare and the gain should be obvious.
To give some more motivation think of a setup where you have some GigE
interfaces facing your LAN/DMZ and you don't want to filter them (which is
very common). You will write a ruleset like:
block all
pass on { $if0, $if1, ... $ifN }
#ruleset goes here
The optimizer will also put these rules in front of the processing as there
are a lot of matches. Still every packet on $ifN will have to go through N
rules (skip-steps don't help) and every packet that really is filtered has
that O(N) overhead in front as well.
It might be worthwhile to extend this to be able to skip only certain
processing. e.g.:
set skip all on <interface>
Will skip all (surprise)
set skip from scrub on <interface>
Will evaluate scrub rules and end processing afterwards.
set skip from nat on <interface>
Will evaluate scrub and nat rules and stop afterwards.
I am open to changes regarding syntax and implementation, but think that the
idea itself is good.
Comments?
--
/"\ Best regards, | mlaier_(_at_)_freebsd_(_dot_)_org
\ / Max Laier | ICQ #67774661
X http://pf4freebsd.love2party.net/ | mlaier_(_at_)_EFnet
/ \ ASCII Ribbon Campaign | Against HTML Mail and News
Index: sbin/pfctl/parse.y
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.469
diff -u -r1.469 parse.y
--- sbin/pfctl/parse.y 10 Dec 2004 22:13:26 -0000 1.469
+++ sbin/pfctl/parse.y 14 Dec 2004 17:37:42 -0000
@@ -281,6 +281,7 @@
struct node_queue_bw bwspec, struct node_queue_opt *);
int expand_queue(struct pf_altq *, struct node_if *, struct node_queue *,
struct node_queue_bw, struct node_queue_opt *);
+int expand_skip_interface(struct node_if *);
int check_rulestate(int);
int kw_cmp(const void *, const void *);
@@ -398,7 +399,7 @@
%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
-%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG HOSTID
+%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
%token ANTISPOOF FOR
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
@@ -570,6 +571,12 @@
}
free($3);
}
+ | SET SKIP interface {
+ if (expand_skip_interface($3) != 0) {
+ yyerror("error setting skip interface(s)");
+ YYERROR;
+ }
+ }
;
string : string STRING {
@@ -4446,6 +4453,35 @@
yyerror("rule expands to no valid combination");
}
+int
+expand_skip_interface(struct node_if *interfaces)
+{
+ int errs = 0;
+
+ if ((!interfaces) ||
+ ((!interfaces->next) && (!interfaces->not) &&
+ (strcmp(interfaces->ifname, "none") == 0))) {
+ errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
+ return (errs);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ if (interface->not) {
+ yyerror("skip on ! <interface> is not supported");
+ errs++;
+ } else
+ errs += pfctl_set_interface_flags(pf,
+ interface->ifname, PFI_IFLAG_SKIP, 1);
+ );
+
+ FREE_LIST(struct node_if, interfaces);
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
#undef FREE_LIST
#undef LOOP_THROUGH
@@ -4565,6 +4601,7 @@
{ "rule", RULE},
{ "scrub", SCRUB},
{ "set", SET},
+ { "skip", SKIP},
{ "source-hash", SOURCEHASH},
{ "source-track", SOURCETRACK},
{ "state", STATE},
Index: sbin/pfctl/pfctl.c
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sbin/pfctl/pfctl.c,v
retrieving revision 1.223
diff -u -r1.223 pfctl.c
--- sbin/pfctl/pfctl.c 21 Sep 2004 16:59:11 -0000 1.223
+++ sbin/pfctl/pfctl.c 14 Dec 2004 17:37:42 -0000
@@ -1270,6 +1270,39 @@
}
int
+pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
+{
+ struct pfioc_iface pi;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ bzero(&pi, sizeof(pi));
+
+ pi.pfiio_flags = flags;
+
+ if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
+ sizeof(pi.pfiio_name))
+ errx(1, "pfctl_set_interface_flags: strlcpy");
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (how == 0) {
+ if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
+ err(1, "DIOCCLRIFFLAG");
+ } else {
+ if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
+ err(1, "DIOCSETIFFLAG");
+ }
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("%s %s:0x%x flags\n", how?"set":"clear", pi.pfiio_name,
+ pi.pfiio_flags);
+
+ return (0);
+}
+
+int
pfctl_debug(int dev, u_int32_t level, int opts)
{
if (ioctl(dev, DIOCSETDEBUG, &level))
Index: sbin/pfctl/pfctl_parser.h
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sbin/pfctl/pfctl_parser.h,v
retrieving revision 1.77
diff -u -r1.77 pfctl_parser.h
--- sbin/pfctl/pfctl_parser.h 16 Jul 2004 23:44:25 -0000 1.77
+++ sbin/pfctl/pfctl_parser.h 14 Dec 2004 17:37:42 -0000
@@ -187,6 +187,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 parse_rules(FILE *, struct pfctl *);
int parse_flags(char *);
Index: sbin/pfctl/pfctl_table.c
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sbin/pfctl/pfctl_table.c,v
retrieving revision 1.61
diff -u -r1.61 pfctl_table.c
--- sbin/pfctl/pfctl_table.c 12 Jun 2004 22:22:44 -0000 1.61
+++ sbin/pfctl/pfctl_table.c 14 Dec 2004 17:37:42 -0000
@@ -577,7 +577,8 @@
oprintf(flags, PFI_IFLAG_GROUP, "group", &first, 0);
oprintf(flags, PFI_IFLAG_CLONABLE, "clonable", &first, 0);
oprintf(flags, PFI_IFLAG_DYNAMIC, "dynamic", &first, 0);
- oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 1);
+ oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 0);
+ oprintf(flags, PFI_IFLAG_SKIP, "skipped", &first, 1);
printf("\n");
if (!(opts & PF_OPT_VERBOSE2))
Index: share/man/man4/pf.4
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/share/man/man4/pf.4,v
retrieving revision 1.53
diff -u -r1.53 pf.4
--- share/man/man4/pf.4 10 Dec 2004 03:29:02 -0000 1.53
+++ share/man/man4/pf.4 14 Dec 2004 17:48:38 -0000
@@ -1013,6 +1013,19 @@
.Va pfiio_nzero
will be set by the kernel to the number of interfaces and drivers
that have been cleared.
+.It Dv DIOCSETIFFLAG Fa "struct pfioc_iface *io"
+Set the user setable flags (described below) of the pf internal interface
+description.
+The filtering process is the same as for
+.Dv DIOCIGETIFACES .
+.Bd -literal
+#define PFI_IFLAG_SKIP 0x0100 /* skip progressing */
+#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */
+.Ed
+.It Dv DIOCCLRIFFLAG Fa "struct pfioc_iface *io"
+works as
+.DV DIOCSETIFFLAG
+above but clears the flags.
.El
.Sh FILES
.Bl -tag -width /dev/pf -compact
Index: share/man/man5/pf.conf.5
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/share/man/man5/pf.conf.5,v
retrieving revision 1.314
diff -u -r1.314 pf.conf.5
--- share/man/man5/pf.conf.5 12 Dec 2004 17:41:55 -0000 1.314
+++ share/man/man5/pf.conf.5 14 Dec 2004 17:33:04 -0000
@@ -483,6 +483,16 @@
.Pp
.Dl set fingerprints \&"/etc/pf.os.devel\&"
.Pp
+.It Ar set skip on <interface>
+List interfaces that should not be included in the ruleset progressing.
+This can be helpful for lo0 and interfaces that only see encapsulated
+traffic (e.g. pppoe).
+If skipping is enabled on a given interface can be determined with
+.Xr pfctl 8 .
+To disable skipping on all interfaces (default) use:
+.Pp
+.Dl set skip on none
+.Pp
.It Ar set debug
Set the debug
.Ar level
Index: sys/net/pf.c
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sys/net/pf.c,v
retrieving revision 1.474
diff -u -r1.474 pf.c
--- sys/net/pf.c 14 Dec 2004 03:49:06 -0000 1.474
+++ sys/net/pf.c 14 Dec 2004 16:27:10 -0000
@@ -5627,6 +5627,8 @@
kif = pfi_index2kif[ifp->if_index];
if (kif == NULL)
return (PF_DROP);
+ else if (kif->pfik_flags & PFI_IFLAG_SKIP) /* later? */
+ return (PF_PASS);
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
@@ -5934,6 +5936,8 @@
kif = pfi_index2kif[ifp->if_index];
if (kif == NULL)
return (PF_DROP);
+ else if (kif->pfik_flags & PFI_IFLAG_SKIP) /* later? */
+ return (PF_PASS);
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
Index: sys/net/pf_if.c
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sys/net/pf_if.c,v
retrieving revision 1.22
diff -u -r1.22 pf_if.c
--- sys/net/pf_if.c 13 Dec 2004 23:51:22 -0000 1.22
+++ sys/net/pf_if.c 14 Dec 2004 16:25:31 -0000
@@ -689,6 +689,44 @@
}
int
+pfi_set_flags(const char *name, int flags)
+{
+ struct pfi_kif *p;
+
+ if (flags & ~PFI_IFLAG_SETABLE_MASK)
+ return (EINVAL);
+
+ s = splsoftnet();
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
+ continue;
+ p->pfik_flags |= flags;
+ }
+ splx(s);
+
+ return (0);
+}
+
+int
+pfi_clear_flags(const char *name, int flags)
+{
+ struct pfi_kif *p;
+
+ if (flags & ~PFI_IFLAG_SETABLE_MASK)
+ return (EINVAL);
+
+ s = splsoftnet();
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
+ continue;
+ p->pfik_flags &= ~flags;
+ }
+ splx(s);
+
+ return (0);
+}
+
+int
pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
{
struct pfi_kif *p;
Index: sys/net/pf_ioctl.c
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.136
diff -u -r1.136 pf_ioctl.c
--- sys/net/pf_ioctl.c 10 Dec 2004 22:13:26 -0000 1.136
+++ sys/net/pf_ioctl.c 14 Dec 2004 16:26:17 -0000
@@ -1028,6 +1028,8 @@
case DIOCCLRSRCNODES:
case DIOCIGETIFACES:
case DIOCICLRISTATS:
+ case DIOCSETIFFLAG:
+ case DIOCCLRIFFLAG:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -2767,6 +2769,20 @@
break;
}
+ case DIOCSETIFFLAG: {
+ struct pfioc_iface *io = (struct pfioc_iface *)addr;
+
+ error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
+ break;
+ }
+
+ case DIOCCLRIFFLAG: {
+ struct pfioc_iface *io = (struct pfioc_iface *)addr;
+
+ error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
+ break;
+ }
+
default:
error = ENODEV;
break;
Index: sys/net/pfvar.h
===================================================================
RCS file: /usr/store/mlaier/ocvs/src/sys/net/pfvar.h,v
retrieving revision 1.209
diff -u -r1.209 pfvar.h
--- sys/net/pfvar.h 10 Dec 2004 22:13:26 -0000 1.209
+++ sys/net/pfvar.h 14 Dec 2004 16:24:18 -0000
@@ -869,6 +869,8 @@
#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */
#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */
#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */
+#define PFI_IFLAG_SKIP 0x0100 /* skip progressing */
+#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */
struct pf_pdesc {
u_int64_t tot_len; /* Make Mickey money */
@@ -1326,6 +1328,8 @@
#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t)
#define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface)
#define DIOCICLRISTATS _IOWR('D', 88, struct pfioc_iface)
+#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
+#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
#ifdef _KERNEL
RB_HEAD(pf_src_tree, pf_src_node);
@@ -1488,6 +1492,8 @@
void pfi_fill_oldstatus(struct pf_status *);
int pfi_clr_istats(const char *, int *, int);
int pfi_get_ifaces(const char *, struct pfi_if *, int *, int);
+int pfi_set_flags(const char *, int);
+int pfi_clear_flags(const char *, int);
int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
sa_family_t);
Attachment:
pgp8qnql0WF2m.pgp
Description: PGP signature