Gentoo Wiki ArchivesGentoo Wiki

Bridging

This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc


Please format this article according to the guidelines and Wikification suggestions, then remove this notice {{Wikify}} from the article



Contents

Introduction

As Gentoo seems to gain more popularity as a home-brewed server platform, extending it to act like different network devices is important. In this guide, we will explore how to configure Gentoo as an IEEE 802.1d compatible bridge.

Originally, this guide rested on the Gentoo forums, and gathered some decent comments. For brevity's sake, I am not going to re-post those comments here; but if you have questions, you should check out the original posting to see if your issue has already been addressed.

Intended Audience

This document is written for users with a working knowledge of networking. Prerequisite knowledge includes those topics covered in the Gentoo Installation Guide and commands needed to edit common configuration files.

Kernel Support

Like many other things in the Layer 2 realm, 802.1d support requires an addition to the kernel. Thankfully, the 2.4 and 2.6 kernels have included this support -- we just need to make sure it gets compiled.

For simplicity, I am going to assume we start with a vanilla 2.6 kernel. Edit the /usr/src/linux/.config file with the following changes:

Linux Kernel Configuration: 802.1d Support
Networking --->
    Networking Options --->
    <*> 802.1d Ethernet Bridging

Compile the kernel and load the bridging code as necessary. If you compile into the kernel, reboot. If you opt to compile as a module, do not forget to add the module to your /etc/modules.autoload.d/kernel-2.6 file:

Code: Adding Support if compiled as a module
echo "bridge" >> /etc/modules.autoload.d/kernel-2.6
update-modules
modprobe bridge

Use the dmesg command to ensure the 802.1d code was loaded successfully. Once it is loaded without errors, continue to the next stage.

Program Support

Thanks to the magic of portage, installing the programs to control bridging is easy:

    emerge net-misc/bridge-utils

About three minutes later, depending on the speed of your machine, brctl will be installed and ready to go. The only thing left to do is figure out how to use the program.

Code: brctl overview
/sbin/brctl
     commands:
            addbr           <bridge>                add bridge
            addif           <bridge> <device>       add interface to bridge
            delbr           <bridge>                delete bridge
            delif           <bridge> <device>       delete interface from bridge
            show                                    show a list of bridges
            showmacs        <bridge>                show a list of mac addrs
            showstp         <bridge>                show bridge stp info
 
            setageing       <bridge> <time>         set ageing time
            setbridgeprio   <bridge> <prio>         set bridge priority
            setfd           <bridge> <time>         set bridge forward delay
            setgcint        <bridge> <time>         set garbage collection interval
            sethello        <bridge> <time>         set hello time
            setmaxage       <bridge> <time>         set max message age
            setpathcost     <bridge> <port> <cost>  set path cost
            setportprio     <bridge> <port> <prio>  set port priority
            stp             <bridge> <state>        turn stp on/off

Bridge Basics

A bridge is used to connect two collision domains to form a single coherent broadcast domain. Ethernet operates under a principle called CSMA/CD (Carrier Sense Multiple Access / Collision Detection). In simplistic terms, any Ethernet host "listens" to the network when it wants to transmit. It waits until it believes the network is unused (Carrier Sense Multiple Access) and then sends the data.

Because data is not transmitted instantaneously (there is actually a small amount of delay), there exists the potential that two Ethernet hosts send data at the same time. When that happens, it is as if two people talk at once: neither can really understand what the other is saying. This is called a collision in the domain of networking technology. So an Ethernet host continues to listen to the network while it transmits its data. If it doesn't hear what it originally sent, it assumes a collision occured (Collision Detection). It will stop transmitting for some variable amount of time and then start the whole process over again.

The more hosts you have on a given network segment, the greater the chance of a collision occuring. A network segment can be subdivided to decrease the number of hosts that are on a segment together. That is, I can have a LAN that looks like either of the following diagrams. Both operate the same, but the first is a single collision domain, the second has two collision domains.

         ----------------------------------------------------
              |                    |                  |
            Host A               Host B             Host C


         ----------[BRIDGE]----------------------------------
              |                    |                  |
            Host A               Host B             Host C

In the first example, if A and C talk at the same time, a collision occurs. In the second, A and C can talk at the same time without having to worry about their data colliding -- the bridge assumes the role of minimizing collisions! (Note that in the second example, B and C can still create collisions together.)

Ethernet also has this property called a "broadcast." If you know you want to talk to a host on the network, but you're not quite sure WHICH host you want to talk to -- or maybe you want to talk to all of them with the same message -- then you broadcast the message on the network. Broadcasts must be transmitted across collision domains. In the second example from above, if A sends a broadcast, both B and C hear it. Also, if B sends a broadcast, both A and C hear it. But if B sends a message to C, A will not hear it. That is the difference between a broadcast domain (the logical network) and a collision domain (the physical network).


Advanced Bridging

Now that we understand the basics about bridging, let's look at a more complex example:

         Host A ------+-------------------+----- Host B
                      |                   |
                      |                   |       Interface 0
                 +--------+          +--------+
                 |  Br 1  |          |  Br 2  |
                 +--------+          +--------+
                      |                   |       Interface 1
                      |                   |
         Host C ------+-------------------+----- Host D

Hosts A and B are on one network segment, and Hosts C and D are on a different segment. The two segments are connected via two bridges, Br1 and Br2, via Interfaces 0 and 1, respectively. (That is, Interface 0 on Br1 and Br2 points to the Host A/B segment, and Interface 1 points to the Host C/D segment.)

Let's say Host A sends a Layer 2 ARP packet (a broadcast) looking for the address of Host D. Both Br1 and Br2 receive the broadcast packet via Interface 0. Since it is a broadcast, the bridges flood it out every other interface, so Host D receives two copies of the packet from the bridges. It responds using a unicast packet, and the bridges forward the data properly. But something bad has just happened.

When Br1 flooded the broadcast to the wire, Br2 received the packet on Interface 1. (And likewise for Br1 receiving it from Br2.) Since the bridges interpret the packet as "new," they forward the packets out to Interface 0. Wait a second ... the broadcast was already heard on that segment when Host A originally sent it! This loop continues again, where Br1 and Br2 keep forwarding the broadcast from interface to interface like a giant perpetual motion machine. The broadcast packets start eating up all of the available time slices when a host can transmit, causing a denial of service attack. This is not a good thing and is called a "broadcast storm."

When Host D responds with that unicast packet, another troublesome event takes place. Br1 and Br2 know Host A can be found on Interface 0. They learn from the response that Host D can be found on Interface 1. Both bridges receive the response, and both forward it back out Interface 0 to Host A. When Br1 sends it, Br2 receives it; and vice versa.

Since a bridge learns which port a host is on by the source MAC address, they can get confused when they hear the same source MAC on two different interfaces. Br1 and Br2 learned that Host D is on Interface 1 from the response ... but now they think that Host D is on Interface 0 instead because their forwards got confused! Just like in the broadcast storm example that got us started, the bridges continue forwarding these packets ad infinitum, relearning their bridge forwarding tables on every packet. And thus the "unicast flood" is born.

Now, these problems do not exist when a single bridge is involved. It is only when two or more segments are interconnected by two or more bridges. But as we can see, they are very important to discuss. Broadcast storms are infamously known for crashing entire networks. So how do we combat this?

The answer is known as the Spanning Tree Protocol (STP). It acts as a type of routing protocol for bridges, telling them to turn off certain ports that may cause potential loops. The details of STP are well beyond the scope of this document, but I highly suggest reading Michael Norton's article Understanding Spanning Tree Protocol - the Fundamental Bridging Algorithm as an introduction to STP.

Now we are ready to begin building our bridge.

Manually Creating a Bridge Interface

Let's say I want to create Br1 from our previous example. eth0 and eth1 will be the interfaces used. Linux requires that we create a new bridge interface that is a summation of the two real interfaces, so let's go ahead and do that:

Warning: If you are adding a bridge to a machine you are administering through ssh, and, are currently connected to one of the interfaces you would like to bridge, you should read this section before issuing any commands so that you understand what you are doing. Then go back and combine all of the commands into one, seperated by '&&' or you may have to get physical access in order to finish creating the bridge/regain remote access.
Code: Manual Bridge Creation
/sbin/ifconfig eth0 up
/sbin/ifconfig eth1 up
 
/sbin/brctl addbr br0
 
/sbin/brctl addif br0 eth0
/sbin/brctl addif br0 eth1
 
/sbin/ifconfig br0 up

This tells brctl to create an interface br0 and then to assign eth0 and eth1 to it. And with those three commands, we have a fully functional bridge. The rest is just tweaking.

By default, STP is disabled under Linux bridging. Let's go ahead and enable this for safe measure:

Code: Enable STP
/sbin/brctl stp br0 on

Ah, now Br1 is really working well. We don't need to worry about broadcast storms or unicast floods on this bridge anymore.

The only thing lacking is remote administration of the Linux box. eth0 and eth1 are in promiscuous mode to be part of the bridge, so how do we SSH into it? The answer: we assign the bridge interface itself an IP address.

Code: Assign the Bridge Interface
/sbin/ifconfig br0 192.168.1.2 netmask 255.255.255.0 up

The only thing more perfect would be if we could somehow script all this into an init script.


Gentoo Init Scripts

Thanks to the kind developers over the baselayout scripts, we no longer have to patch the init scripts. Also, it seems you no longer have to start the bridging software (/etc/init.d/bridge) as a separate process. It gets fairly simple from here.

Our first step is to modify /etc/conf.d/net to add the bridge configuration. If you look at /etc/conf.d/net.example you'll notice a sample configuration you can use as a template. You'll notice the syntax is similar to the syntax for configuing individual interfaces specifically.

File: /etc/conf.d/net
# Bridging (802.1d)
# For bridging support emerge net-misc/bridge-utils

# To add ports to bridge br0
bridge_br0="eth0 eth1"

# Finally give the bridge an address - dhcp or a static IP
#config_br0=( "dhcp" )
config_br0=( "192.168.1.1 netmask 255.255.255.0" )
 

Note that for any interfaces that are to be in the bridge, they need to be set to "null." Unexpected results may occur if these ports get configured with an IP. Hence, configure the individual ethernet ports like so:

File: /etc/conf.d/net
# You need to configure the ports to null values so dhcp does not get started
config_eth0=( "null" )
config_eth1=( "null" )

If you have multiple bridges on the network, you'll probably want to turn on STP (discussed above; shown below). You can use similar syntax for other brctl commands:

File: /etc/conf.d/net
# Try to prevent "storms"
brctl_br0=( "stp on" )


To access the network through eth0 add to /etc/conf.d/net

File: /etc/conf.d/net
# To be able to access internet on current machine
depend_br0() {
         need net.eth0
 }


Next, create the symbolic links for the extra interface and for br0 init scripts and add them to the default runlevel:

Code: Symbolic Links & Default Run Runlevel
ln -sf /etc/init.d/net.lo /etc/init.d/net.eth1
rc-update add net.eth0 default
rc-update add net.eth1 default
 
ln -sf /etc/init.d/net.lo /etc/init.d/net.br0
rc-update add net.br0 default
/etc/init.d/net.br0 start

Bridging With VLANs

802.1d and 802.1Q can combine seamlessly under a Linux system. Unfortunately, Gentoo does not make configuration easy on us. Using Bash variables, we cannot easily create a device-specific VLAN and specify configuration parameters. To do this, we would need to be able to create a "config_eth0.2" directive in /etc/conf.d/net, which violates the variable rules for Bash. We can, however, circumvent the problem entirely using the vconfig name-type parameter 'VLAN_PLUS_VID_NO_PAD'. Unfortunately, if the same VLAN is used on two interfaces, this method will not work without a helper function to rename the VLAN to something unique on a per-interface basis. Using the preup() function provided by Gentoo, we can issue a series of commands that performs this renaming for us.

File: /etc/conf.d/net
# Bridging (802.1d) with VLANs (802.1q)
# For bridging support emerge net-misc/bridge-utils
# For VLAN support emerge vconfig

preup() {
        VLAN=$(echo "${IFACE}" | grep v)
        if [[ "${VLAN}" ]]; then
                VNUM=$(echo "${IFACE}" | awk -F'v' '{print $2;}')

                # We need to bring the newly created vlan2 device down to rename it
                CMDTMP="CMD=\"ip link set vlan${VNUM} down\""
                eval $CMDTMP && ebegin "$CMD" && $CMD  &>/tmp/error
                ewend $? $(cat /tmp/error && rm -f /tmp/error)

                # Then we rename it to our real interface-specific name
                CMDTMP="CMD=\"ip link set vlan${VNUM} name ${IFACE}\""
                eval $CMDTMP && ebegin "$CMD" && $CMD  &>/tmp/error
                ewend $? $(cat /tmp/error && rm -f /tmp/error)

                # Then we bring the interface back up
                CMDTMP="CMD=\"ip link set ${IFACE} up\""
                eval $CMDTMP && ebegin "$CMD" && $CMD  &>/tmp/error
                ewend $? $(cat /tmp/error && rm -f /tmp/error)
        fi
}


# These depend functions tell Gentoo which order interfaces need to be started
depend_br0() {
        # We need to start _all_ VLAN interfaces before we start a bridged interface!
        need net.e0v2 net.e1v2
}
depend_br1() {
        # We need to start _all_ VLAN interfaces before we start a bridged interface!
        need net.e0v2 net.e1v2
}
depend_e0v2() {
        need net.eth0
}
depend_e1v2() {
        need net.eth1
}


# Add VLAN 2 to both interfaces
vlans_eth0=( "2" )
vlans_eth1=( "2" )

# When we create the VLAN, call it "vlan" followed by the VLAN ID
vconfig_eth0=( "set_name_type VLAN_PLUS_VID_NO_PAD" )
vconfig_eth1=( "set_name_type VLAN_PLUS_VID_NO_PAD" )

# We need this so that the VLAN tagged packets are interpreted properly by our software
vconfig_e0v2=( "set_flag 1" )
vconfig_e1v2=( "set_flag 1" )

# Bridge 0 is VLAN 1 (the default VLAN)
bridge_br0=( "eth0 eth1" )

# Bridge 1 is VLAN 2
bridge_br1=( "e0v2 e1v2" )

# Turn on STP for both VLANs
brctl_br0=( "stp on" )
brctl_br1=( "stp on" )

# We need to set all interfaces to NO IP address
###################################################
# These are our physical interfaces
config_eth0=( "null" )
config_eth1=( "null" )

# This interface is for the temporary vlan2 interface so DHCPCD does not fire
config_vlan2=( "null" )

# These are the final interface-specific names for vlan2
config_e0v2=( "null" )
config_e1v2=( "null" )
###################################################

# We set the actual IP addresses on the bridge interfaces
config_br0=( "192.168.1.2 netmask 255.255.255.0" )
config_br1=( "192.168.2.2 netmask 255.255.255.0" )

routes_br0=( "default via 192.168.1.1" )
 

As you can see, the basics of bridging with VLAN support is already present. The only problem we have to circumvent is the Bash variable naming problem. Gentoo provides adequate capabilities to do this. Our last step is to create the init.d scripts and add them to the default runlevel:

# cd /etc/init.d
# ln -s net.eth0 net.e0v2
# ln -s net.eth0 net.e1v2
# ln -s net.eth0 net.br0
# ln -s net.eth0 net.br1
# rc-update add net.eth0 default
# rc-update add net.eth1 default
# rc-update add net.e0v2 default
# rc-update add net.e1v2 default
# rc-update add net.br0 default
# rc-update add net.br1 default

Now we can start our bridged interfaces:

Code: Start the Bridged Interfaces
/etc/init.d/net.br0 start
/etc/init.d/net.br1 start

The bridged interfaces require all VLAN interfaces to start first. If you fail to start your VLAN interfaces before starting a bridged interface, the VLAN interfaces will fail to start. You can start your bridged interfaces in any order, just so long as all VLAN interfaces (e0v2, e1v2, etc) have been started prior to starting a bridged interface.

Creating 802.11/802.3 Bridges

Quite simply, Linux does not support this easily. From Jean Tourrilhes' site:

The conventional Ethernet bridging method (promiscuous sniffing) doesn't work with most wireless LAN standard, because of the header encapsulation and the interactions with link layer retransmissions. In other word, most often, when you use a software bridge on a wireless LAN (such as the Linux bridge on a 802.11 card), it doesn't work (moreover, quite often promiscuous is broken as well).
The driver could work around this restriction by creating its own MAC headers (802.11 headers instead of 802.3, and putting the right bits in the right place), but in fact most vendors don't provide the specification on how to this with their hardware (when they don't explicitly prevent it in hardware, to force you to buy their Access Points). (http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Linux.Wireless.usage.html)

The eventual goal is to bridge a wireless network to a wired network. This is what an access point provides so if you can, buy an access point instead of trying to build your own. If you need it to bridge a virtual machine to your wireless network, you are going to be pretty out of luck for the time being.

Bridge & iptables

You can filter bridged traffic with iptables, to do that you have to enable following kernel option:

CONFIG_BRIDGE_NETFILTER=y

Networking  --->
  Networking support  --->
    Networking options  --->
      Network packet filtering (replaces ipchains) --->
       [*] Bridged IP/ARP packets filtering

If you want to disable this feature on-the-fly without recompiling the kernel, you can tune the behavior with sysctl:

File: /etc/sysctl.conf
# Disable bridge filtering
net.bridge.bridge-nf-call-arptables = 0
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-filter-vlan-tagged = 0

Conclusion

While Gentoo has enjoyed lots of attention in the matters of 802.1q VLANs and Layer 3 routers/firewalls, bridging support is has been relatively ignored. Hopefully, this document has remedied some of that.

I recommend using a Linux bridge in the special case of a transparent proxy server. Read Chapter 7 in the Transparent Proxy with Linux and Squid mini-HOWTO by Daniel Kiracofe. Otherwise, I generally prefer specialized hardware. My flavor of choice is the Cisco Catalyst 2950, though just about any Layer 2 switch would handle the job. (The Catalyst supports STP and VLANs along with remote management features.)

You can use 802.1d in combination with other features like Linux 802.1q VLANs, firewalling, Linux Channel Bonding, and Squid for a flexible and complete solution in any network. Start with the basics and expand outwards.

Retrieved from "http://www.gentoo-wiki.info/Bridging"

Last modified: Sat, 30 Aug 2008 15:23:00 +1000 Hits: 76,512

Created by NickStallman.net, Luxury Homes Australia
Real estate agents should list their apartments, townhouses and units in Australia.