mirror of
https://github.com/opnsense/src.git
synced 2026-02-19 02:30:08 -05:00
bridge: allow IP addresses on members to be disabled
add a new sysctl, net.link.bridge.member_ifaddrs, which defaults to 1. if it is set to 1, bridge behaviour is unchanged. if it is set to 0: - an interface which has AF_INET6 or AF_INET addresses assigned cannot be added to a bridge. - an interface in a bridge cannot have an AF_INET6 or AF_INET address assigned to it. - the bridge will no longer consider the lladdrs on bridge members to be local addresses, i.e. frames sent to member lladdrs will not be processed by the host. update bridge.4 to document this behaviour, as well as the existing recommendation that IP addresses should not be configured on bridge members anyway, even if it currently partially works. in testing, setting this to 0 on a bridge with 50 member interfaces improved throughput by 22% (4.61Gb/s -> 5.67Gb/s) across two member epairs due to eliding the bridge member list walk in GRAB_OUR_PACKETS. Reviewed by: kp, des Approved by: des (mentor) Differential Revision: https://reviews.freebsd.org/D49995 (cherry picked from commit 0a1294f6c610948d7447ae276df74a6d5269b62e)
This commit is contained in:
parent
b69907d463
commit
cd5b92eb56
7 changed files with 162 additions and 10 deletions
|
|
@ -36,7 +36,7 @@
|
|||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 10, 2024
|
||||
.Dd May 5, 2025
|
||||
.Dt IF_BRIDGE 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -158,6 +158,19 @@ This can be used to multiplex the input of two or more interfaces into a single
|
|||
stream.
|
||||
This is useful for reconstructing the traffic for network taps
|
||||
that transmit the RX/TX signals out through two separate interfaces.
|
||||
.Pp
|
||||
To allow the host to communicate with bridge members, IP addresses
|
||||
should be assigned to the
|
||||
.Nm
|
||||
interface itself, not to the bridge's member interfaces.
|
||||
Assigning IP addresses to bridge member interfaces is unsupported, but
|
||||
for backward compatibility, it is permitted if the
|
||||
.Xr sysctl 8
|
||||
variable
|
||||
.Va net.link.bridge.member_ifaddrs
|
||||
is set to 1, which is the default.
|
||||
In a future release, this sysctl may be set to 0 by default, or may be
|
||||
removed entirely.
|
||||
.Sh IPV6 SUPPORT
|
||||
.Nm
|
||||
supports the
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
|
|||
|
||||
static void bridge_forward(struct bridge_softc *, struct bridge_iflist *,
|
||||
struct mbuf *m);
|
||||
static bool bridge_member_ifaddrs(void);
|
||||
|
||||
static void bridge_timer(void *);
|
||||
|
||||
|
|
@ -497,6 +498,19 @@ SYSCTL_BOOL(_net_link_bridge, OID_AUTO, log_mac_flap,
|
|||
CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(log_mac_flap), true,
|
||||
"Log MAC address port flapping");
|
||||
|
||||
/* allow IP addresses on bridge members */
|
||||
VNET_DEFINE_STATIC(bool, member_ifaddrs) = true;
|
||||
#define V_member_ifaddrs VNET(member_ifaddrs)
|
||||
SYSCTL_BOOL(_net_link_bridge, OID_AUTO, member_ifaddrs,
|
||||
CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(member_ifaddrs), true,
|
||||
"Allow layer 3 addresses on bridge members");
|
||||
|
||||
static bool
|
||||
bridge_member_ifaddrs(void)
|
||||
{
|
||||
return (V_member_ifaddrs);
|
||||
}
|
||||
|
||||
VNET_DEFINE_STATIC(int, log_interval) = 5;
|
||||
VNET_DEFINE_STATIC(int, log_count) = 0;
|
||||
VNET_DEFINE_STATIC(struct timeval, log_last) = { 0 };
|
||||
|
|
@ -658,6 +672,7 @@ bridge_modevent(module_t mod, int type, void *data)
|
|||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
bridge_dn_p = bridge_dummynet;
|
||||
bridge_member_ifaddrs_p = bridge_member_ifaddrs;
|
||||
bridge_detach_cookie = EVENTHANDLER_REGISTER(
|
||||
ifnet_departure_event, bridge_ifdetach, NULL,
|
||||
EVENTHANDLER_PRI_ANY);
|
||||
|
|
@ -666,6 +681,7 @@ bridge_modevent(module_t mod, int type, void *data)
|
|||
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
|
||||
bridge_detach_cookie);
|
||||
bridge_dn_p = NULL;
|
||||
bridge_member_ifaddrs_p = NULL;
|
||||
break;
|
||||
default:
|
||||
return (EOPNOTSUPP);
|
||||
|
|
@ -1273,6 +1289,25 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
|
|||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If member_ifaddrs is disabled, do not allow an interface with
|
||||
* assigned IP addresses to be added to a bridge.
|
||||
*/
|
||||
if (!V_member_ifaddrs) {
|
||||
struct ifaddr *ifa;
|
||||
|
||||
CK_STAILQ_FOREACH(ifa, &ifs->if_addrhead, ifa_link) {
|
||||
#ifdef INET
|
||||
if (ifa->ifa_addr->sa_family == AF_INET)
|
||||
return (EINVAL);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6)
|
||||
return (EINVAL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
/*
|
||||
* Two valid inet6 addresses with link-local scope must not be
|
||||
|
|
@ -2699,17 +2734,25 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
|
|||
do { GRAB_OUR_PACKETS(bifp) } while (0);
|
||||
|
||||
/*
|
||||
* Give a chance for ifp at first priority. This will help when the
|
||||
* packet comes through the interface like VLAN's with the same MACs
|
||||
* on several interfaces from the same bridge. This also will save
|
||||
* some CPU cycles in case the destination interface and the input
|
||||
* interface (eq ifp) are the same.
|
||||
* We only need to check members interfaces if member_ifaddrs is
|
||||
* enabled; otherwise we should have never traffic destined for a
|
||||
* member's lladdr.
|
||||
*/
|
||||
do { GRAB_OUR_PACKETS(ifp) } while (0);
|
||||
|
||||
/* Now check the all bridge members. */
|
||||
CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
|
||||
GRAB_OUR_PACKETS(bif2->bif_ifp)
|
||||
if (V_member_ifaddrs) {
|
||||
/*
|
||||
* Give a chance for ifp at first priority. This will help when
|
||||
* the packet comes through the interface like VLAN's with the
|
||||
* same MACs on several interfaces from the same bridge. This
|
||||
* also will save some CPU cycles in case the destination
|
||||
* interface and the input interface (eq ifp) are the same.
|
||||
*/
|
||||
do { GRAB_OUR_PACKETS(ifp) } while (0);
|
||||
|
||||
/* Now check the all bridge members. */
|
||||
CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
|
||||
GRAB_OUR_PACKETS(bif2->bif_ifp)
|
||||
}
|
||||
}
|
||||
|
||||
#undef CARP_CHECK_WE_ARE_DST
|
||||
|
|
|
|||
|
|
@ -320,5 +320,6 @@ struct ifbpstpconf {
|
|||
} while (0)
|
||||
|
||||
extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
|
||||
extern bool (*bridge_member_ifaddrs_p)(void);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ void (*vlan_input_p)(struct ifnet *, struct mbuf *);
|
|||
|
||||
/* if_bridge(4) support */
|
||||
void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
|
||||
bool (*bridge_member_ifaddrs_p)(void);
|
||||
|
||||
/* if_lagg(4) support */
|
||||
struct mbuf *(*lagg_input_ethernet_p)(struct ifnet *, struct mbuf *);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include <net/if_llatbl.h>
|
||||
#include <net/if_private.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_bridgevar.h>
|
||||
#include <net/route.h>
|
||||
#include <net/route/nhop.h>
|
||||
#include <net/route/route_ctl.h>
|
||||
|
|
@ -499,6 +500,13 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct ucred *cred
|
|||
return (error);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if bridge wants to allow adding addrs to member interfaces.
|
||||
*/
|
||||
if (ifp->if_bridge && bridge_member_ifaddrs_p &&
|
||||
!bridge_member_ifaddrs_p())
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* See whether address already exist.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#include <net/if_var.h>
|
||||
#include <net/if_private.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_bridgevar.h>
|
||||
#include <net/route.h>
|
||||
#include <net/route/route_ctl.h>
|
||||
#include <net/route/nhop.h>
|
||||
|
|
@ -1236,6 +1237,13 @@ in6_addifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra, struct in6_ifaddr *i
|
|||
int carp_attached = 0;
|
||||
int error;
|
||||
|
||||
/* Check if this interface is a bridge member */
|
||||
if (ifp->if_bridge && bridge_member_ifaddrs_p &&
|
||||
!bridge_member_ifaddrs_p()) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* first, make or update the interface address structure,
|
||||
* and link it to the list.
|
||||
|
|
|
|||
|
|
@ -703,6 +703,82 @@ many_bridge_members_cleanup()
|
|||
vnet_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "member_ifaddrs_enabled" "cleanup"
|
||||
member_ifaddrs_enabled_head()
|
||||
{
|
||||
atf_set descr 'bridge with member_ifaddrs=1'
|
||||
atf_set require.user root
|
||||
}
|
||||
|
||||
member_ifaddrs_enabled_body()
|
||||
{
|
||||
vnet_init
|
||||
vnet_init_bridge
|
||||
|
||||
ep=$(vnet_mkepair)
|
||||
ifconfig ${ep}a inet 192.0.2.1/24 up
|
||||
|
||||
vnet_mkjail one ${ep}b
|
||||
jexec one sysctl net.link.bridge.member_ifaddrs=1
|
||||
jexec one ifconfig ${ep}b inet 192.0.2.2/24 up
|
||||
jexec one ifconfig bridge0 create addm ${ep}b
|
||||
|
||||
atf_check -s exit:0 -o ignore ping -c3 -t1 192.0.2.2
|
||||
}
|
||||
|
||||
member_ifaddrs_enabled_cleanup()
|
||||
{
|
||||
vnet_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "member_ifaddrs_disabled" "cleanup"
|
||||
member_ifaddrs_disabled_head()
|
||||
{
|
||||
atf_set descr 'bridge with member_ifaddrs=0'
|
||||
atf_set require.user root
|
||||
}
|
||||
|
||||
member_ifaddrs_disabled_body()
|
||||
{
|
||||
vnet_init
|
||||
vnet_init_bridge
|
||||
|
||||
vnet_mkjail one
|
||||
jexec one sysctl net.link.bridge.member_ifaddrs=0
|
||||
|
||||
bridge=$(jexec one ifconfig bridge create)
|
||||
|
||||
# adding an interface with an IPv4 address
|
||||
ep=$(jexec one ifconfig epair create)
|
||||
jexec one ifconfig ${ep} 192.0.2.1/32
|
||||
atf_check -s exit:1 -e ignore jexec one ifconfig ${bridge} addm ${ep}
|
||||
|
||||
# adding an interface with an IPv6 address
|
||||
ep=$(jexec one ifconfig epair create)
|
||||
jexec one ifconfig ${ep} inet6 2001:db8::1/128
|
||||
atf_check -s exit:1 -e ignore jexec one ifconfig ${bridge} addm ${ep}
|
||||
|
||||
# adding an interface with an IPv6 link-local address
|
||||
ep=$(jexec one ifconfig epair create)
|
||||
jexec one ifconfig ${ep} inet6 -ifdisabled auto_linklocal up
|
||||
atf_check -s exit:1 -e ignore jexec one ifconfig ${bridge} addm ${ep}
|
||||
|
||||
# adding an IPv4 address to a member
|
||||
ep=$(jexec one ifconfig epair create)
|
||||
jexec one ifconfig ${bridge} addm ${ep}
|
||||
atf_check -s exit:1 -e ignore jexec one ifconfig ${ep} inet 192.0.2.2/32
|
||||
|
||||
# adding an IPv6 address to a member
|
||||
ep=$(jexec one ifconfig epair create)
|
||||
jexec one ifconfig ${bridge} addm ${ep}
|
||||
atf_check -s exit:1 -e ignore jexec one ifconfig ${ep} inet6 2001:db8::1/128
|
||||
}
|
||||
|
||||
member_ifaddrs_disabled_cleanup()
|
||||
{
|
||||
vnet_cleanup
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case "bridge_transmit_ipv4_unicast"
|
||||
|
|
@ -718,4 +794,6 @@ atf_init_test_cases()
|
|||
atf_add_test_case "mtu"
|
||||
atf_add_test_case "vlan"
|
||||
atf_add_test_case "many_bridge_members"
|
||||
atf_add_test_case "member_ifaddrs_enabled"
|
||||
atf_add_test_case "member_ifaddrs_disabled"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue