A virtual bridge connects multiple network interfaces together, allowing them to communicate with each other as if they were on the same network.
A virtual bridge can simulate following things:
- A switch.
- A bridge.
Create a virtual bridge.
$ ip link add <bridge_name> type bridge
Set the bridge as the master devive of another one.
$ ip link set <another_device> master <bridge_device>
Example:
# Create a virtual bridge: virbr0
$ ip link add virbr0 type bridge
# Create veth devices: veth0, veth1, veth2
$ ip link add veth0 type veth
$ ip link add veth1 type veth peer name veth2
# Connect veth0, veth1 to virbr0
$ ip link set veth0 master virbr0
$ ip link set veth1 master virbr0
flowchart TD veth0 <---> virbr0 veth2 <---> veth1 veth1 <---> virbr0
flowchart TD subgraph ns1 veth1 end subgraph ns2 veth2 end veth1 <---> vethbr1 veth2 <---> vethbr2 vethbr1 <---> virbr0 vethbr2 <---> virbr0
# create namepsaces
$ ip netns add ns1
$ ip netns add ns2
# create veth pairs
$ ip link add veth1 type veth peer name vethbr1
$ ip link add veth2 type veth peer name vethbr2
# move veth endpoints to namespaces
$ ip link set veth1 netns ns1
$ ip link set veth2 netns ns2
# create virtual bridge
$ ip link add virbr0 type bridge
# connect veth endpoints to bridge
$ ip link set vethbr1 master virbr0
$ ip link set vethbr2 master virbr0
# assign IP
$ ip netns exec ns1 ip addr add 192.168.0.10/24 dev veth1
$ ip netns exec ns2 ip addr add 192.168.0.20/24 dev veth2
# turn on devices
$ ip netns exec ns1 ip link set veth1 up
$ ip netns exec ns2 ip link set veth2 up
$ ip link set vethbr1 up
$ ip link set vethbr2 up
$ ip link set virbr0 up
# show learned mac addressed of the bridge
$ brctl showmacs virbr0
# check connection with ping
$ ip netns exec ns1 ping 192.168.0.20
$ ip netns exec ns2 ping 192.168.0.10
flowchart TD subgraph container1 veth1 end subgraph container2 veth2 end veth1 <---> vethbr1 veth2 <---> vethbr2 vethbr1 <---> virbr0 vethbr2 <---> virbr0
# create containers
$ docker run -id --cap-add=NET_ADMIN --name container1 alpine sh
$ docker run -id --cap-add=NET_ADMIN --name container2 alpine sh
# create veth pairs
$ ip link add veth1 type veth peer name vethbr1
$ ip link add veth2 type veth peer name vethbr2
# move veth1 to namespace of container1
$ pid_of_container1=$(docker inspect --format '{{.State.Pid}}' container1)
$ ip link set veth1 netns ${pid_of_container1}
# move veth2 to namespace of container2
$ pid_of_container2=$(docker inspect --format '{{.State.Pid}}' container2)
$ ip link set veth2 netns ${pid_of_container2}
# create virtual bridge
$ ip link add virbr0 type bridge
# connect veth endpoints to bridge
$ ip link set vethbr1 master virbr0
$ ip link set vethbr2 master virbr0
# assign IP
$ docker exec container1 ip addr add 192.168.0.10/24 dev veth1
$ docker exec container2 ip addr add 192.168.0.20/24 dev veth2
# turn on devices
$ docker exec container1 ip link set veth1 up
$ docker exec container2 ip link set veth2 up
$ ip link set vethbr1 up
$ ip link set vethbr2 up
$ ip link set virbr0 up
# check connection with ping
$ docker exec container1 ping 192.168.0.20
$ docker exec container2 ping 192.168.0.10
# create namepsaces
$ ip netns add ns1
$ ip netns add ns2
$ ip netns add ns3
# create veth pairs
$ ip link add veth1 type veth peer name vethbr1
$ ip link add veth2 type veth peer name vethbr2
$ ip link add veth3 type veth peer name vethbr3
# move veth endpoints to namespaces
$ ip link set veth1 netns ns1
$ ip link set veth2 netns ns2
$ ip link set veth3 netns ns3
# create virtual bridge
$ ip link add br0 type bridge
# connect veth endpoints to bridge
$ ip link set vethbr1 master br0
$ ip link set vethbr2 master br0
$ ip link set vethbr3 master br0
# assign IP
$ ip netns exec ns1 ip addr add 192.168.0.10/24 dev veth1
$ ip netns exec ns2 ip addr add 192.168.0.20/24 dev veth2
$ ip netns exec ns3 ip addr add 192.168.0.30/24 dev veth3
# turn on devices
$ ip netns exec ns1 ip link set veth1 up
$ ip netns exec ns2 ip link set veth2 up
$ ip netns exec ns3 ip link set veth3 up
$ ip link set vethbr1 up
$ ip link set vethbr2 up
$ ip link set vethbr3 up
$ ip link set br0 up
# show interfaces of br0
$ brctl show br0
bridge name bridge id STP enabled interfaces
br0 8000.9e4287f72992 no vethbr1
vethbr2
vethbr3
Show vlan configuration.
$ bridge vlan show
port vlan-id
vethbr1 1 PVID Egress Untagged
vethbr2 1 PVID Egress Untagged
vethbr3 1 PVID Egress Untagged
br0 1 PVID Egress Untagged
flowchart TD subgraph ns1 veth1 end subgraph ns2 veth2 end subgraph ns3 veth3 end veth1 <---> vethbr1 veth2 <---> vethbr2 veth3 <---> vethbr3 vethbr1 <--->|vlan 1| br0 vethbr2 <--->|vlan 1| br0 vethbr3 <--->|vlan 1| br0
# ns1 -> ns2
$ ip netns exec ns1 ping -c 1 192.168.0.20
64 bytes from 192.168.0.20: icmp_seq=1 ttl=64 time=0.058 ms
# ns1 -> ns3
$ ip netns exec ns1 ping -c 1 192.168.0.30
64 bytes from 192.168.0.30: icmp_seq=1 ttl=64 time=0.119 ms
flowchart TD subgraph ns1 veth1 end subgraph ns2 veth2 end subgraph ns3 veth3 end veth1 <---> vethbr1 veth2 <---> vethbr2 veth3 <---> vethbr3 vethbr1 <--->|vlan 10| br0 vethbr2 <--->|vlan 10| br0 vethbr3 <--->|vlan 20| br0
# enable vlan filtering
$ ip link set dev br0 type bridge vlan_filtering 1
# check vlan filtering
$ ip -details link show br0
br0:
vlan_filtering 1
# move vethbr1, vethbr2 to vlan 10
$ bridge vlan add vid 10 dev vethbr1 pvid untagged
$ bridge vlan add vid 10 dev vethbr2 pvid untagged
# move vethbr1 to vlan 20
$ bridge vlan add vid 20 dev vethbr3 pvid untagged
# show vlan config
$ bridge vlan show
port vlan-id
vethbr1 1 Egress Untagged
10 PVID Egress Untagged
vethbr2 1 Egress Untagged
10 PVID Egress Untagged
vethbr3 1 Egress Untagged
20 PVID Egress Untagged
br0 1 PVID Egress Untagged
# remove vlan 1
$ bridge vlan del vid 1 dev vethbr1
$ bridge vlan del vid 1 dev vethbr2
$ bridge vlan del vid 1 dev vethbr3
# show vlan config
$ bridge vlan show
vethbr1 10 PVID Egress Untagged
vethbr2 10 PVID Egress Untagged
vethbr3 20 PVID Egress Untagged
# ns1 -> ns2: ping ok
$ ip netns exec ns1 ping -c 1 192.168.0.20
64 bytes from 192.168.0.20: icmp_seq=1 ttl=64 time=0.062 ms
# ns1 -> ns3: cannot ping
$ ip netns exec ns1 ping -c 1 192.168.0.30
1 packets transmitted, 0 received, 100% packet loss, time 0ms