7 minutes
MAC Learning Basics
This post illustrates dynamic learning of unicast MAC addresses on
Linux MAC Bridges, and how to use the bridge fdb show
command to
view the MAC database. It expands upon an earlier
post on Bridging and VLANs.
If you wish to try this out yourself, there are hints on exploring MAC Learning with Infix and GNS3 at the bottom of this post.
Example Topology - A single bridge
The figure below shows a sample topology with a bridge (Bridge-A) and two connected hosts. H1 and H2 have IP addresses on the same 10.0.1.0/24 subnet. The MAC addresses of H1, H2 and Bridge-A have been selected for the purpose of easy illustration only. In typical scenarios, these are assigned by the hardware manufacturer.
Bridge-A BaseMAC
02:aa:aa:aa:00:00
.----------------------.
| Bridge-A |
| eth0 eth1 eth2 |
'--+-------+-------+---'
| | |
| |
| .-+--.
| | H2 |
| '----'
.--+-. IP: 10.0.1.2/24
| H1 | MAC: 02:22:22:00:00
'----'
IP: 10.0.1.1/24
MAC: 02:11:11:11:00:00
The following commands can be used to setup Bridge-A. (For more details, see Exploring MAC learning with Infix further below.)
root@bridge-a:~# ip link add br0 type bridge
root@bridge-a:~# ip link set eth0 master br0
root@bridge-a:~# ip link set eth1 master br0
root@bridge-a:~# ip link set eth2 master br0
root@bridge-a:~# ip link set br0 up
Bridges forward packets based on destination MAC …
Bridges look at the destination MAC when deciding onto what port a packet should be sent. It keeps information it its MAC database (a.k.a forwarding database, FDB, learning_cache, station cache, etc.). If the address is found, it forwards the packet onto that port. If the address is not found, it floods the packet onto all ports.
root@bridge-a:~# bridge fdb show dynamic
02:11:11:11:00:00 dev eth0 master br0
02:22:22:22:00:00 dev eth1 master br0
root@bridge-a:~#
For Bridge-A, packets to 02:11:11:11:00:00 are forwarded to eth0, packets to 02:22:22:22:00:00 to eth1, and packet to other addresses are forwarded to eth0, eth1, and all other ports of the bridge.
… and learns addresses based on source MAC
When the bridge starts, the MAC database is empty, thus all traffic is flooded. For every packet received, the bridge learns the location of the sender by inspecting the source MAC of the packet.
root@bridge-a:~# bridge fdb show dynamic
root@bridge-a:~#
Once H1, sends a packet, the bridge will learn that H1 resides on port eth0. Or more precisely, that the MAC address of H1 resides on port eth0.
root@bridge-a:~# bridge fdb show dynamic
02:11:11:11:00:00 dev eth0 master br0
root@bridge-a:~#
Learned entries are aged out
Learned MAC entries are kept in the MAC database, but will eventually be aged out if the entry is not refreshed. The aging time is typically 300 seconds (5 minutes), and entry is refreshed every time bridge receives a packet with that MAC.
Multiple Bridges
The MAC learning can be extended to multiple bridges. In the example below, we have expanded the LAN by adding a second bridge.
Bridge-A BaseMAC Bridge-B BaseMAC
02:aa:aa:aa:00:00 02:bb:bb:bb:00:00
.----------------------. .-----------------------.
| Bridge-A | | Bridge-B |
| eth0 eth1 eth2 | | eth0 eth2 eth2 |
'--+-------+-------+---' '--+-------+--------+---'
| | | | | |
| | '--------------' | |
| .-+--. .--+-. |
| | H2 | | H3 | |
| '----' '----' |
.--+-. IP: 10.0.1.2/24 IP: 10.0.1.3/24 .-+--.
| H1 | MAC: 02:22:22:00:00 MAC: 02:33:33::00:00 | H4 |
'----' '----'
IP: 10.0.1.1/24 IP: 10.0.1.1/24
MAC: 02:11:11:11:00:00 MAC: 02:44:44:44::00:00
Inspecting the MAC databases at Bridge A and B after booting up, they may show the following result
On Bridge A:
root@bridge-a:~# bridge fdb show dynamic
02:11:11:11:00:00 dev eth0 master br0
02:22:22:22:00:00 dev eth1 master br0
02:bb:bb:bb:00:00 dev eth2 master br0
root@bridge-a:~#
On Bridge B:
root@bridge-b:~# bridge fdb show dynamic
02:aa:aa:aa:00:02 dev eth0 master br0
02:33:33:33:00:00 dev eth1 master br0
02:44:44:44:00:00 dev eth2 master br0
root@bridge-b:~#
We can see that bridges know their local hosts, and have also learned about each-other. The reason MAC databases are not completely empty here is that all these nodes exchange LLDP messages. The LLDP packets only go hop-by-hop, thus Bridge-A will not learn MAC addresses of H3 and H4 this way. For example, if we listen in on port eth0 of Bridge-A, we can see the following LLDP traffic.
root@bridge-a:~# tcpdump -ee -n -i eth0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
07:56:58.915592 02:11:11:11:00:00 > 01:80:c2:00:00:0e, ethertype LLDP (0x88cc), length 208: LLDP, length 194: h1
07:57:07.452643 02:aa:aa:aa:00:00 > 01:80:c2:00:00:0e, ethertype LLDP (0x88cc), length 200: LLDP, length 186: bridge-a
^C
2 packets captured
2 packets received by filter
0 packets dropped by kernel
root@bridge-a:~#
Now, let H1 ping H2 (ping 10.0.1.2
) and inspect the MAC databases on
the bridges:
Bridge-A:
root@bridge-a:~# bridge fdb show dynamic
02:11:11:11:00:00 dev eth0 master br0
02:22:22:22:00:00 dev eth1 master br0
02:bb:bb:bb:00:00 dev eth2 master br0
root@bridge-a:~#
Bridge-B:
root@bridge-b:~# bridge fdb show dynamic
02:11:11:11:00:00 dev eth0 master br0 <====== NEW (H1)
02:aa:aa:aa:00:02 dev eth0 master br0
02:33:33:33:00:00 dev eth1 master br0
02:44:44:44:00:00 dev eth2 master br0
root@bridge-b:~#
The only thing that differs here is that Bridge-B has learned about H1
on its port eth0. It learns this from the broadcast ARP Who Has 10.0.1.2?
sent by H1 (preceding the ICMP Echo Request of the Ping);
this broadcast ARP is flooded throughout the whole LAN. The ‘ARP
Response’ by H2 is sent by unicast and never reaches Bridge-B. (More
precisely, as Bridge-A knows where MAC 02:11:11:11:00:00 resides, it
forwards the ‘ARP Response’ directly on eth0.
Now, let H1 send a broadcast ping (ping 10.0.1.255
). All hosts
respond. If we again inspect the MAC databases at the bridges, we see
they have learned the location of the MACs for all hosts.
Bridge-A:
root@bridge-a:~# bridge fdb show dynamic
02:11:11:11:00:00 dev eth0 master br0
02:22:22:22:00:00 dev eth1 master br0
02:33:33:33:00:00 dev eth2 master br0 <=== NEW (H3)
02:44:44:44:00:00 dev eth2 master br0 <=== NEW (H4)
02:bb:bb:bb:00:00 dev eth2 master br0
root@bridge-a:~#
Bridge-B:
root@bridge-b:~# bridge fdb show dynamic
02:22:22:22:00:00 dev eth0 master br0 <=== NEW (H2)
02:11:11:11:00:00 dev eth0 master br0
02:aa:aa:aa:00:02 dev eth0 master br0
02:33:33:33:00:00 dev eth1 master br0
02:44:44:44:00:00 dev eth2 master br0
root@bridge-b:~#
The figure below illustrates the MAC databases (FDBs) by using symbolic names for the MAC addresses.
Bridge-A BaseMAC Bridge-B BaseMAC
02:aa:aa:aa:00:00 02:bb:bb:bb:00:00
.----------------------. .-----------------------.
| Bridge-A | | Bridge-B |
| eth0 eth1 eth2 | | eth0 eth2 eth2 |
'--+-------+-------+---' '--+-------+--------+---'
h1| h2| br-b| |br-a |h3 |h4 <== FDB
| | h3'--------------'h1 | |
| .-+--. h4 h2 .--+-. |
| | H2 | | H3 | |
| '----' '----' |
.--+-. IP: 10.0.1.2/24 IP: 10.0.1.3/24 .-+--.
| H1 | MAC: 02:22:22:00:00 MAC: 02:33:33::00:00 | H4 |
'----' '----'
IP: 10.0.1.1/24 IP: 10.0.1.1/24
MAC: 02:11:11:11:00:00 MAC: 02:44:44:44::00:00
Exploring MAC learning with Infix
The examples above were done using a virtual setup with Infix, specifically the Classic build, on GNS3. Below are some hints if you like to explore this yourself.
To install Infix and GNS3, look at the guide in the Infix README. It is also recommended to look at the Basic Networking Training Post.
In the setup used here, all units (Bridge-A, Bridge-B, H1, H2, H3 and H4) were using Infix-Classic as GNS3 appliance.
Hints on configuring the Bridges
Bridges-A and Bridges-B were configured with multiple ports (at least 3). This is done in the GNS3 Configure window for the units.
To make Bridge-A (and Bridge-B) act like MAC bridges, the following commands where issued via the console.
root@bridge-a:~# ip link add br0 type bridge
root@bridge-a:~# ip link set eth0 master br0
root@bridge-a:~# ip link set eth1 master br0
root@bridge-a:~# ip link set eth2 master br0
root@bridge-a:~# ip link set br0 up
To make Bridge-A get hostname (and prompt) ‘bridge-a’, you can edit ‘/etc/hostname’. To avoid that Bridge-A and Bridge-B sends a lot of DHCP messages, you can comment out the associated line in ‘/etc/network/interfaces.d/ for eth0, eth1, etc.
root@bridge-a:~# cat /etc/network/interfaces.d/eth0
auto eth0
iface eth0 inet manual
#iface eth0 inet dhcp
# pre-up ip link set eth0 group iface
root@bridge-a:~#
The first line (auto eth0) could also be commented out, but then you need to bring up eth0, eth1 and eth2 manually.
root@bridge-a:~# ip link set eth0 up
root@bridge-a:~# ip link set eth1 up
root@bridge-a:~# ip link set eth2 up
Hints on configuring the Hosts
To assign static IP 10.0.1.1/24 to H1 (etc.), update the ‘/etc/network/interfaces.d/eth0’
root@h1:~# cat /etc/network/interfaces.d/eth0
auto eth0
iface eth0 inet static
address 10.0.1.1
netmask 255.255.255.0
#iface eth0 inet dhcp
# pre-up ip link set eth0 group iface
root@h1:~#
To enable hosts respond to ‘broadcast pings’, change the corresponding ‘proc’ setting
root@h1:~# sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0
net.ipv4.icmp_echo_ignore_broadcasts = 0
root@h1:~#
To make the setting permanent, the following can be used:
root@h1:~# echo 'net/ipv4/icmp_echo_ignore_broadcasts = 0' > /etc/sysctl.d/91-icmp-echo-bcast.conf
root@h1:~#