kern/116051: add local packet filtering on the physical interfaces of if_bridge

Eygene Ryabinkin rea-fbsd at
Mon Sep 3 06:30:02 PDT 2007

>Number:         116051
>Category:       kern
>Synopsis:       add local packet filtering on the physical interfaces of if_bridge
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Sep 03 13:30:01 GMT 2007
>Originator:     Eygene Ryabinkin
>Release:        FreeBSD 7.0-CURRENT i386
Code Labs

System: FreeBSD XXX 7.0-CURRENT FreeBSD 7.0-CURRENT #9: Wed Aug 8 10:56:57 MSD 2007 root at XXX:/usr/src/sys/i386/compile/XXX i386


Currently, if we are running filtering L2-bridge with if_bridge it
is not possible to filter the packets that are destined to the
bridge itself (on the L2) basing on the physical incoming interface.
Such packets are seen by pfil(9) only at the bridge interface itself.

The common setup where such feature is desirable is the bridge that
does simple IP-gatewaying or NAT for the number of the links bundled
together on the L2.  One can distinguish the packets only using its
IP address, but it is sometimes desirable to add the incoming
interface check to differentiate between network segments using
physical network characteristics (switches and their ports or VLANs)
and not only logical ones (MAC or IP in the packet header).


Setup if_bridge, make it the default gateway for the network with
the gateway's IP sitting on the bridge interface itself and set up
IP forwarding.  Try to filter the packets that are destined on the
L2 to the gateway, but are the transit ones on the L3: you will see
that such packets are seen by pfil(9) only at the bridge interface,
but not at the physical incoming interface.

One can inspect the /sys/net/if_bridge.c, rev. 1.102, starting from
the line 2070 to see why filters see only the bridge interface.


The following patches implements additional filtering on the physical
incoming interface and changing the manual page, describing the
added option.  This patch was tested for about half a year on the
rather busy NAT box serving half hundred clients (on the 6.2, but
now it was ported to the 7-CURRENT).

Source patch:
--- pfil-local-phys.patch begins here ---
--- if_bridge.c.orig	2007-09-03 15:16:40.000000000 +0400
+++ if_bridge.c	2007-09-03 16:53:31.000000000 +0400
@@ -340,6 +340,8 @@
 static int pfil_member = 1; /* run pfil hooks on the member interface */
 static int pfil_ipfw = 0;   /* layer2 filter with ipfw */
 static int pfil_ipfw_arp = 0;   /* layer2 filter with ipfw */
+static int pfil_local_phys = 0; /* show physical interface for the
+                                   bridge-destined packets */
 static int log_stp   = 0;   /* log STP state changes */
 SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW,
     &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled");
@@ -349,6 +351,8 @@
     &pfil_bridge, 0, "Packet filter on the bridge interface");
 SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW,
     &pfil_member, 0, "Packet filter on the member interface");
+SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW,
+    &pfil_local_phys, 0, "Show physical interface for bridge-destined packets");
 SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW,
     &log_stp, 0, "Log STP state changes");
@@ -2070,6 +2074,21 @@
 	if (memcmp(eh->ether_dhost, IF_LLADDR(bifp),
 	    ETHER_ADDR_LEN) == 0) {
+		 * Try to filter on the physical interface.
+		 */
+		if (pfil_local_phys && (PFIL_HOOKED(&inet_pfil_hook)
+#ifdef INET6
+		    || PFIL_HOOKED(&inet6_pfil_hook)
+		    )) {
+			if (bridge_pfil(&m, ifp, NULL, PFIL_IN) != 0 ||
+			    m == NULL) {
+				return NULL;
+			}
+		}
+		/*
 		 * If the packet is for us, set the packets source as the
 		 * bridge, and return the packet back to ether_input for
 		 * local processing.
--- pfil-local-phys.patch ends here ---

Manpage patch:
--- begins here ---
--- if_bridge.4.orig	2007-09-03 15:29:16.000000000 +0400
+++ if_bridge.4	2007-09-03 17:00:05.000000000 +0400
@@ -185,6 +185,20 @@
 .Li 0
 to disable it.
+.It Va
+Set to
+.Li 1
+to enable additional filtering on the physical incoming interface
+using the
+.Xr pfil 9
+framework when the packet is destined (on the layer 2) to the
+bridge interface itself.
+The filtering is done before the usual
+.Xr pfil 9
+processing on the bridge interface.
+Set to
+.Li 0
+to disable this feature.
 .It Va
 Set to
 .Li 1
@@ -310,7 +324,9 @@
 to assign the IP address only to the
 interface and not to the bridge members.
-But your mileage may vary.
+will let you do the additional filtering using the physical interface name.
 The following when placed in the file
 .Pa /etc/rc.conf
--- ends here ---

More information about the freebsd-bugs mailing list