|
Ethernet Bridges under LinuxSaturday, May 13. 2006
Ten years ago, shortly after I started my first job as a network programmer at an Australian university, I received a call from a person working in one faculty who was having some network difficulties. All of their computers were connected together by 50-ohm coaxial cable ethernet, and two of the computers on this network sent a considerable amount of data to each other.
This data, naturally, was echoed along the entire network cable and was the primary cause of delays and packet loss to other users of the network. The caller wanted to know of a way to solve this problem. My manager suggested the use of a bridge; the two noisy computers could be placed behind this device and their traffic to each other would be confined to their segment. This solution was particularly attractive as it would not require any other changes to the network or the network numbering; it could be inserted and would work immediately. For a number of years now, the Linux kernel has had the ability to turn any host with more than one network interface into a bridge. This article explains how it works. What is bridging?Bridging is the process of transparently connecting two networks segments together, so that packets can pass between the two as if they were a single logical network. Bridging is performed on the data link layer; hence it is independent of the network protocol being used - it doesn't matter if you use IP, Appletalk, Netware or any other protocol, as the bridge operates upon the raw ethernet packets. Typically, in a non-bridged situation, a computer with two network cards would be connected to a separate network on each; while the computer itself may or may not route packets between the two, in the IP realm, each network interface would have a different address and different network number. When bridging is used, however, each network segment is effectively part of the same logical network, the two network cards are logically merged into a single bridge device and devices connected to both network segments are assigned addresses from the same network address range. Only those packets that need to cross from one segment of the network to another are passed from one physical interface to the other; a bridge will learn the MAC addresses of the equipment attached to each of its segments, so that it can determine which packets need to be retransmitted. This makes bridges ideal for reducing traffic on heavy networks, by segmenting off any devices that talk to each other frequently. These days almost all newly deployed networks would use a dedicated bridging device called a switch. This device is effectively a network hub with a bridge segment on every port. All segments are considered to be on the same network, but traffic between two segments is not broadcast to every segment; rather, it is confined only to those two segments themselves. Why use bridging?There's probably not much point using a Linux box as a dedicated bridge or switch; switches are now available very cheaply and are much quieter and considerably more power efficient than your average PC. Additionally, any interface that is part of a bridge must be in promiscuous mode so that it will receive packets that aren't specifically destined for it; this will increase the load on the machine. For this reason, it is better to use a dedicated machine for bridging rather than one that has other important functions. That said, there are many things that the Linux bridging code can do which isn't possible with commodity switches - bridging one of your ethernet networks with a ppp interface, for example, or bridging together a number of virtual private networks. Just recently, I had a need to be able to snoop the traffic between an ADSL router and a small embedded VOIP device. The router's functionality was quite limited, so it wasn't able to do this itself; instead, I grabbed a PC with Linux on it, put an extra ethernet card in it, and bridged the network between the router and the VOIP device. This let traffic flow unimpeded, and I was able to see what was passing by running tcpdump on the Linux box. Linux Bridging SupportSupport for bridging has been available in stable Linux kernels from version 2.4.0 onwards. Previously, patches were available for versions 2.2, however these are no longer maintained for newer 2.2.x releases. Kernel configurationIf you're using a distribution supplied kernel, chances are that you already have support for Ethernet bridges on your system. Most likely it will be compiled as a module, in which case you will need to load it before you can use it:
If you need to recompile your kernel, you will need to set the 'CONFIG_BRIDGE' option to 'y' or 'm' during the configuration stage. Userspace ToolsAll the popular distributions have the bridging userspace tools already packaged for easy installation; under Debian, Ubuntu, Fedora, Redhat Enterprise and SuSE Linux, this package is called 'bridge-utils'. The package provides the 'brctl' command, which is used to control all of the Linux bridging capabilities discussed here. If your system doesn't have a precompiled package available, you will need to download the source from the Linux ethernet bridging sourceforge page. At the time of writing, the latest stable version available of the bridge utils package was 1.1. Compilation and installation is quite straightforward:
Other than the standard GNU autoconf options, there are no special compile time directives to alter the behaviour of the bridge-utils package. Creating and using bridgesFor simplicity's sake, we will assume that we want to bridge together two ethernet networks, interfaces eth0 and eth1. Figure 1 shows a fairly basic network: our bridging linux box (bridge01) with two network segments, which have two Linux machines on each (linux01 and linux02 on the first, and linux03 and linux04 on the second). Before we create the bridge, we should ensure that both interfaces are down, and have no IP address assigned to them:
Now, we can create the bridge interface. Here we see the use of the brctl 'addbr' command, which adds a bridge interface named 'br0'.
There are no restrictions on the interface name used for the bridge; any name can be used, as long as the system does not already have an interface with that name. The convention, however, is to name bridges br0, br1 and so forth. Once the bridge interface has been created, we can add the real ethernet interfaces to it as ports:
That's all there is to it. At this point, we can now treat the bridge interface as we would any other network interface on a Linux box; so the first thing we can do is give it an interface and bring it up on the network:
The brctl command provides a 'show' function, so that it is possible to see the state of bridges on the machine:
Of note is the "bridge id". This number is used with Spanning Tree Protocol, which will be discussed later on. At this point, it should be possible to ping the client machines on each of the network segments, from the bridge:
It will also be possible to send traffic from one of the machines on one segment to a machine on the other segment:
More importantly, it can be seen that for traffic between two devices on a single network segment, the bridge will confine the traffic to that segment. This can be seen by running tcpdump on, say, linux03, while sending ICMP packets from linux01 to linux02.
If the bridge is working correctly, linux03 should not see any of the traffic between linux01 and linux02, even though they are part of the same logical network. On the other hand, if we were to send an ICMP packet to the broadcast address on the network, the bridge will pass this packet across to the second network segment:
This tcpdump output shows the broadcast ICMP request from linux01, and two replies, one from linux03 and one from linux04. linux01 and linux02 would also have sent ICMP responses, as indeed would the bridge itself, since we configured it to have a broadcast address on this network. It is worth mentioning at this point that it is perfectly possible for the bridge to be able to operate without having an IP address assigned to it. If this were the case, it would bridge packets between the two segments as shown above, but would not actually take part in any network exchanges on an IP level. Using the 'showmacs' command, we can see a list of the devices on the network, along with the port to which they are connected:
This list displays the MAC addresses of the six ethernet cards connected to our bridged network; firstly the ethernet cards in each of our four client PCs (listed as not local) and then the two ethernet cards in our bridge itself (and hence, local). The Ageing Time represents the period of time since the bridge last saw a packet from a device with a particular MAC address. After a certain amount of time has passed, the bridge will purge an address from its database. This is done to handle machines that might change ports over a period of time (for example, a laptop computer which is physically moved from one location to another). The ageing timeout for a bridge can be changed with the 'setageingtime' command:
The above command would set a bridge to purge addresses after 40 seconds. Removing bridge ports and bridge interfaces.If you need to remove a port from a bridge, brctl provides the 'delif' command:
Should you want to delete a bridge completely, then use 'delbr'. You must shut the interface down before you can do this, however.
Spanning Tree ProtocolSpanning Tree Protocol (STP) is used by switches to handle multiple bridge paths on a network. The ability to have multiple paths within a network handles, amongst other things, one serious flaw with our network as show above: the bridge has become a single point of failure. Should it fail, the two sides of the network will be unable to talk to one another. We can fix this easily by adding a second bridge, as shown in Figure 2. STP allows these two bridges to negotiate which will be active and which will be passive. The active bridge will take part in all packet transmission between the two segments, while the passive bridge will do nothing until its partner fails. STP is considerably more complex than can be covered in an introductory article such as this, so we will cover only the basics. As we saw earlier, every bridge has an id associated with it; this is an eight-byte number, the first two bytes being the bridge priority, which we can set manually, and the next six bytes are the MAC address of the bridge. Under Linux, the default bridge priority is 32768. The bridge's MAC address is that of the lowest numbered MAC address of all the bridge's ports. We generally represent the bridge ID as a two part hexadecimal number, the bridge ID followed by the MAC address as the fractional part. For example, 8000.100001037303 is the ID of a bridge with a priority of 32768 (8000 hex) and a MAC address of 10:00:01:03:73:03. In a network with multiple bridges, the bridge with the lowest bridge id will be "elected" to be the root bridge. The root bridge then determines a path cost for every redundant path in the network, and where path loops are discovered, certain bridge ports are placed in a "blocking" state, and these ports will no longer forward packets. STP is off by default, under Linux. You can determine whether it has been turned on or off using "brctl show br0", as outlined above. The state can be changed using:
or
To see further information about STP settings on a bridge, use the "showstp" command:
We can see from the above that this bridge is the root bridge for its network (see "bridge id" and "designated root") and hence, both of its interfaces are in a forwarding state. If we run the same command on the second bridge, we will see a few differences:
This bridge has an ID of 8000.100001087423, but its designated root value shows the id of the other bridge. This makes sense, since only one bridge can be the master on a network. We also see that one of its ports is listed as blocking. This is the whole point of STP: it removes loops on the network. If this bridge receives any packets that need to be sent across to a different network segment, it will ignore them, since the other bridge will handle it. If, for some reason, you don't like the choice of a root master that your system has elected for itself, it is possible to alter the priority of one or more bridges using the 'setbridgeprio' command. Here, we set a bridge priority of 4096 (1000 hex).
Looking at our bridges now, we will see that the bridge id has changed.
It's also possible to set a specific cost to a port. This may be required where, for example, a slower link has been automatically selected to be the designated port instead of a faster one and the operator wishes to override this. Links with lower costs will be selected for use, in preference to those with higher costs.
Depending on the topology of the bridge network, this may cause some of the bridge ports to change their status, from "forwarding" to "blocking". While this happens, part of the network may become unreachable for a short period of time, but it should stabilise and become available again within a minute. For further information on Spanning Tree Protocol, please see the IEEE 802.1D specification. ConclusionHopefully now you have a good grounding in the basics of Linux bridging and can now experiment with more complex arrangements on your own. You may find it handy to build a large number of virtual machines (eg, with User Mode Linux or QEMU), and bridge together their networks. This makes it very easy to create very involved topologies to investigate the concepts outlined above. If you found this article helpful, consider making a donation to offset the costs of running this server, to one of these addresses: Trackbacks
Trackback specific URI for this entry
No Trackbacks
Comments
Display comments as
(Linear | Threaded)
Are there ways to bridge bridges together? Primarily, because there would be bridges used for certain networks without any attached interfaces. Sometimes those bridges need to communicate with other separate bridges.
The figure 2 image-url at the "Spanning Tree Protocol" paragraph is:
http://www.iomem.com/uploads/figures/bridges-figure1.png but it should be: http://www.iomem.com/uploads/figures/bridges-figure2.png |