<commit_before>---
layout: post
title: "Linux Bridge - how it works"
date: 2017-05-07 21:07
comments: true
published: true
categories: bridge networks
---


Linux bridge is a layer 2 virtual device that on its own cannot receive or transmit anything unless you bind one or more real devices to it. [source](http://shop.oreilly.com/product/9780596002558.do).

As [Anatomy of a Linux bridge](https://wiki.aalto.fi/download/attachments/70789083/linux_bridging_final.pdf) puts it, bridge mainly consists of four major components:

- **Set of network ports (or interfaces)**: used to forward traffic between end switches to other hosts in the network.
- **A control plane**: used to run Spanning Tree Protocol (STP) that calculates minimum spanning tree, preventing loops from crashing the network.
- **A forwarding plane**: used to process incoming input frames from the ports, forward them to the network port by making a forwarding decision based on the MAC learning database.
- **MAC learning database**: used to keep track of the host locations in the LAN.

For each unicast mac address, bridge maintains a mac learning database to decide which ports to forward based on MAC addresses, and if it can't find an entry for a given mac address, it will broadcast the frame to all ports except the one where it received the frame from.

There are two main configuration subsystems to do bridges:
- **ioctl**: This interface is used to create/destroy bridges and add/remove interfaces to/from a bridge.
- **sysfs**: Management of bridge and port specific parameters.

## Creating a bridge

Bridge can be created using `ioctl` command `SIOCBRADDBR`; as can be seen by `brctl` utiligy provided by bridge-utils.

{% highlight sh %}
vagrant@precise64:~$ sudo strace brctl addbr br1
execve("/sbin/brctl", ["brctl", "addbr", "br1"], [/* 16 vars */]) = 0
...
ioctl(3, SIOCBRADDBR, 0x7fff2eae9966)   = 0
...
{% endhighlight %}

Note that there is no device at this point to handle the ioctl command, so the ioctl command is handled by a stub method: [`br_ioctl_deviceless_stub`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_ioctl.c#L351), which in turn calls [`br_add_bridge`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_if.c#L235). This method calls `alloc_netdev`, which is a macro that eventually calls [`alloc_netdev_mqs`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/core/dev.c#L5660).

{% highlight c %}
br_ioctl_deviceless_stub
  |- br_add_bridge
      |- alloc_netdev
           |- alloc_netdev_mqs  // creates the network device
              |- br_dev_setup // sets br_dev_ioctl handler               
{% endhighlight %}
`alloc_netdev` also initializes the new netdevice using the [`br_dev_setup`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_device.c#L335). This also includes setting up the bridge specific [`ioctl handler`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_ioctl.c#L379). If you look at the handler code, it handles ioctl command to add/delete interfaces.

{% highlight c %}
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
    ...
    switch(cmd) {
	case SIOCBRADDIF:
	case SIOCBRDELIF:
		return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
    ...
    }
    ..
}<commit_msg>Update 2017-04-30-linux-bridge.markdown<commit_after>---
layout: post
title: "Linux Bridge - how it works"
date: 2017-05-07 21:07
comments: true
published: true
categories: bridge networks
---


Linux bridge is a layer 2 virtual device that on its own cannot receive or transmit anything unless you bind one or more real devices to it. [source](http://shop.oreilly.com/product/9780596002558.do).

As [Anatomy of a Linux bridge](https://wiki.aalto.fi/download/attachments/70789083/linux_bridging_final.pdf) puts it, bridge mainly consists of four major components:

- **Set of network ports (or interfaces)**: used to forward traffic between end switches to other hosts in the network.
- **A control plane**: used to run Spanning Tree Protocol (STP) that calculates minimum spanning tree, preventing loops from crashing the network.
- **A forwarding plane**: used to process incoming input frames from the ports, forward them to the network port by making a forwarding decision based on the MAC learning database.
- **MAC learning database**: used to keep track of the host locations in the LAN.

For each unicast mac address, bridge maintains a mac learning database to decide which ports to forward based on MAC addresses, and if it can't find an entry for a given mac address, it will broadcast the frame to all ports except the one where it received the frame from.

There are two main configuration subsystems to do bridges:
- **ioctl**: This interface is used to create/destroy bridges and add/remove interfaces to/from a bridge.
- **sysfs**: Management of bridge and port specific parameters.

## Creating a bridge

Bridge can be created using `ioctl` command `SIOCBRADDBR`; as can be seen by `brctl` utility provided by bridge-utils.

{% highlight sh %}
vagrant@precise64:~$ sudo strace brctl addbr br1
execve("/sbin/brctl", ["brctl", "addbr", "br1"], [/* 16 vars */]) = 0
...
ioctl(3, SIOCBRADDBR, 0x7fff2eae9966)   = 0
...
{% endhighlight %}

Note that there is no device at this point to handle the ioctl command, so the ioctl command is handled by a stub method: [`br_ioctl_deviceless_stub`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_ioctl.c#L351), which in turn calls [`br_add_bridge`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_if.c#L235). This method calls `alloc_netdev`, which is a macro that eventually calls [`alloc_netdev_mqs`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/core/dev.c#L5660).

{% highlight c %}
br_ioctl_deviceless_stub
  |- br_add_bridge
      |- alloc_netdev
           |- alloc_netdev_mqs  // creates the network device
              |- br_dev_setup // sets br_dev_ioctl handler               
{% endhighlight %}
`alloc_netdev` also initializes the new netdevice using the [`br_dev_setup`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_device.c#L335). This also includes setting up the bridge specific [`ioctl handler`](http://elixir.free-electrons.com/linux/v3.10.105/source/net/bridge/br_ioctl.c#L379). If you look at the handler code, it handles ioctl command to add/delete interfaces.

{% highlight c %}
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
    ...
    switch(cmd) {
	case SIOCBRADDIF:
	case SIOCBRDELIF:
		return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
    ...
    }
    ..
}
{'fraction_non_alphanumeric': 0.10448430493273543, 'fraction_numerical': 0.029895366218236172, 'mean_word_length': 4.111535523300229, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '925023', 'n_tokens_mistral': 2201, 'n_tokens_neox': 2022, 'n_words': 759}