16.13. Forwarding Database
Each bridge instance has it own forwarding database , which is used regardless of whether STP is enabled or disabled. We will see later in this chapter exactly when the database is consulted and updated. Let's first see its implementation and the core functions for manipulating it. All of the routines used to manage forwarding databases are located in net/bridge/br_fdb.c.
The database is embedded in the net_bridge data structure and is defined as a hash table (see Figure 16-6). An instance of a net_bridge_fdb_entry data structure is added to the database for each MAC address that is learned on any of the bridge's ports.
The bridge forwarding database subsystem is initialized with br_fdb_init, which simply creates the br_fdb_cache cache that will be used for the allocation of net_bridge_fdb_entry instances.
Allocations are done with fdb_create, which also initializes a few fields of net_bridge_fdb_entry according to its input parameters.
Elements of the forwarding database are identified by their MAC addresses. A lookup in the table consists of selecting the right hash table bucket with br_mac_hash and browsing the bucket's list of net_bridge_fdb_entry instances to find one that matches a given MAC address.
There are two main lookup routines:
For both routines, proper locking is ensured by the caller.
An external subsystem that wishes to make a lookup on the forwarding database can use the br_fdb_get routine, a wrapper that takes care of locking and reference counts and calls _ _br_fdb_get. br_fdb_get is not called directly, but via br_fdb_get_hook, which is initialized in br_init to be a pointer to br_fdb_get.
16.13.2. Reference Counts
Because external subsystems that query the forwarding database with br_fdb_get are likely to cache the result, a reference count is used to keep track of when entries in the forwarding database are still needed and when they can be freed. Each entry is assigned a reference count. br_fdb_get always increments the reference count when the lookup succeeds. The caller is supposed to decrement it with br_fdb_put when it no longer needs the reference to the lookup result. When the reference count drops to 0, br_fdb_put frees net_bridge_fdb_entry.
16.13.3. Adding, Updating, and Removing Entries
The forwarding database is populated and updated by a different set of routines, depending on whether the MAC addresses are associated with local interfaces or ingress frames.
When you create a bridge port, br_add_if adds the enslaved device's MAC address to the forwarding database with br_fdb_insert. The latter function ignores MAC addresses that are not supposed to be added to the database, such as multicast and broadcast addresses. When the new address happens to be in the database already, it is replaced unless it is associated with another local interface, in which case there is no need for any update. Note that local MAC addresses in the forwarding database allow the bridging code to deliver ingress frames addressed to a local interface locally. So it does not matter what interface the local MAC address is associated with. All that matters is that at least one entry in the database tells the bridging code what traffic to deliver locally.
There is no hard limit on the number of entries that can be added to the forwarding database. This can expose the system to a DOS attack, so we can expect developers to add a hard limit in the near future.
When a local device that is associated with a bridge portand that therefore has its MAC address in the forwarding databasechanges its MAC address,[*] its entry in the database is updated with br_fdb_change_addr (see the section "netdevice Notification Chain"). Because it is possible for multiple local interfaces to be configured with the same MAC address (even though it is not common), bf_fdb_change_addr checks whether another bridge port for the same bridge has the same MAC address before removing the net_bridge_fdb_entry instance: if it finds another bridge port with the same MAC address, it binds the database entry to the interface for the remaining port.
The MAC addresses learned with ingress frames (as described in Chapter 14) are added to the database with br_fdb_update. When the address is already in the database, the reference to the ingress port (dst) is updated if needed and the timestamp of the last update (ageing_timer) is updated.
net_bridge_fdb_entry instances are removed with fdb_delete. That function is never called directly, but always through wrappers like br_fdb_cleanup (described in the next section) and br_fdb_delete_by_port.
For each bridge instance there is a garbage collection timer (gc_timer) that periodically scans the forwarding database and deletes expired entries. The timer is initialized in br_stp_timer_init when the bridge instance is initialized, and is started when the bridge is enabled with br_stp_enable_bridge.
The timer expires every one-tenth of second and calls br_fdb_cleanup to do the cleanup. That function scans the database and deletes expired entries with fdb_delete.
An entry normally expires if it has not been used for at least 5 minutes. However, when a bridge runs the STP, a shorter aging time of forward_delay seconds is used when a topology change has been detected (see the section "Short Aging Timer" in Chapter 15). The right aging time is used transparently by calling the hold_time routine, which returns the right one to use based on the logic described here.