This article shows how to create a network bridge device and a TUN/TAP device, which then is added to the bridge. The CentOS 8 Stream is used along with the console NetworkManager program nmcli.
TUN/TAP devices are often used in the virtualization world as a link device between the host machine and the virtual machine.
This article is for the case when the bridge does not include the main network interface (Internet network interface and so on) of the server but is an additional device, which MAC and virtual machine MACs would not be exposed through the server’s main network interface.
If the server’s main network interface should be included in the bridge device, i.e. replace the main network interface with the bridge there is another article on the subject – Replace current interface configuration with a bridge device using nmcli (NetworkManager)
Device name are as follow:
- br0 is the name of the network bridge.
- 10.10.10.1 with mask /24 is the IP of the bridge device with name br0. Because the idea is to use the bridge only locally, a local interface is used. The IP is set manually.
- tap0 is the name of TUN/TAP device.
- enp0s3is the server’s main network connection. Not used in this howto.
Here are all the commands to create a bridge, create a TUN/TAP device and add it to the bridge, and then activate the bridge‘s link.
nmcli connection add type bridge ifname br0 con-name br0 ipv4.method manual ipv4.addresses "10.10.10.1/24" nmcli con up br0 nmcli connection add type tun ifname tap0 con-name tap0 mode tap owner 0 ip4 0.0.0.0/24 nmcli con add type bridge-slave ifname tap0 master br0
Here are the steps with much more details and information including all the command output.
The networking before any reconfiguration:
[root@srv ~]# nmcli enp0s3: connected to enp0s3 "Intel 82540EM" ethernet (e1000), 08:00:27:03:C9:2E, hw, mtu 1500 ip4 default inet4 192.168.0.20/24 route4 192.168.0.0/24 metric 100 route4 0.0.0.0/0 via 192.168.0.1 metric 100 inet6 fe80::a00:27ff:fe03:c92e/64 route6 fe80::/64 metric 100 lo: unmanaged "lo" loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536 DNS configuration: servers: 8.8.8.8 1.1.1.1 interface: enp0s3 Use "nmcli device show" to get complete information about known devices and "nmcli connection show" to get an overview on active connection profiles. Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details. [root@srv ~]# nmcli con NAME UUID TYPE DEVICE enp0s3 09497bbf-da59-42b7-a72c-d69369760b36 ethernet enp0s3
STEP 1) Create the bridge and set the IP manually.
The bridge device has name br0 and the network IP 10.10.10.1/24 should be manually set. If the IP part is skipped, the bridge would have IP configuration set to auto and it would expect to receive DHCP configuration.
[root@srv ~]# nmcli connection add type bridge ifname br0 con-name br0 ipv4.method manual ipv4.addresses "10.10.10.1/24" Connection 'br0' (89e26fba-57a8-4bb8-b46f-d85f3a1e0cd0) successfully added. [root@srv ~]# nmcli con up br0 Connection successfully activated (master waiting for slaves) (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3) [root@srv ~]# nmcli con NAME UUID TYPE DEVICE enp0s3 09497bbf-da59-42b7-a72c-d69369760b36 ethernet enp0s3 br0 89e26fba-57a8-4bb8-b46f-d85f3a1e0cd0 bridge br0 [root@srv ~]# nmcli enp0s3: connected to enp0s3 "Intel 82540EM" ethernet (e1000), 08:00:27:03:C9:2E, hw, mtu 1500 ip4 default inet4 192.168.0.20/24 route4 192.168.0.0/24 metric 100 route4 0.0.0.0/0 via 192.168.0.1 metric 100 inet6 fe80::a00:27ff:fe03:c92e/64 route6 fe80::/64 metric 100 br0: connected to br0 "br0" bridge, AA:FC:78:45:51:82, sw, mtu 1500 inet4 10.10.10.1/24 route4 10.10.10.0/24 metric 425 lo: unmanaged "lo" loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536 DNS configuration: servers: 8.8.8.8 1.1.1.1 interface: enp0s3 Use "nmcli device show" to get complete information about known devices and "nmcli connection show" to get an overview on active connection profiles. Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details. [root@srv ~]# nmcli con NAME UUID TYPE DEVICE enp0s3 09497bbf-da59-42b7-a72c-d69369760b36 ethernet enp0s3 br0 89e26fba-57a8-4bb8-b46f-d85f3a1e0cd0 bridge br0
STEP 2) Create the TUN/TAP network interface.
The TUN/TAP device name is tap0. The owner is 0, i.e. root. If the TUN/TAP device is planed to be used with different user, the UID of the user should be used instead 0.
[root@srv ~]# nmcli connection add type tun ifname tap0 con-name tap0 mode tap owner 0 ip4 0.0.0.0/24 Connection 'tap0' (9ddc1cce-7c4d-4af1-b042-d7a92a7a5084) successfully added. [root@srv ~]# nmcli enp0s3: connected to enp0s3 "Intel 82540EM" ethernet (e1000), 08:00:27:03:C9:2E, hw, mtu 1500 ip4 default inet4 192.168.0.20/24 route4 192.168.0.0/24 metric 100 route4 0.0.0.0/0 via 192.168.0.1 metric 100 inet6 fe80::a00:27ff:fe03:c92e/64 route6 fe80::/64 metric 100 tap0: connected to tap0 "tap0" tun, 26:55:7A:66:95:71, sw, mtu 1500 inet4 0.0.0.0/24 inet6 fe80::c312:f1a5:6f32:9f10/64 route6 fe80::/64 metric 450 br0: connected to br0 "br0" bridge, AA:FC:78:45:51:82, sw, mtu 1500 inet4 10.10.10.1/24 route4 10.10.10.0/24 metric 425 lo: unmanaged "lo" loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536 DNS configuration: servers: 8.8.8.8 1.1.1.1 interface: enp0s3 Use "nmcli device show" to get complete information about known devices and "nmcli connection show" to get an overview on active connection profiles. Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details. [root@srv ~]# nmcli con NAME UUID TYPE DEVICE enp0s3 09497bbf-da59-42b7-a72c-d69369760b36 ethernet enp0s3 tap0 5cb465f7-2b29-42dd-858a-ed141b0686b8 tun tap0 br0 89e26fba-57a8-4bb8-b46f-d85f3a1e0cd0 bridge br0
There are three connections the server’s main network connection through enp0s3 and two additional br0 and tap0.
STEP 3) Add the TUN/TAP device to the bridge.
Add the TUN/TAP device tap0 to the bridge br0. A new link with the name bridge-slave-tap0 is established.
[root@srv ~]# nmcli con add type bridge-slave ifname tap0 master br0 Connection 'bridge-slave-tap0' (446beb1d-af26-4e5f-9efd-9404ee23106c) successfully added. [root@srv ~]# nmcli enp0s3: connected to enp0s3 "Intel 82540EM" ethernet (e1000), 08:00:27:03:C9:2E, hw, mtu 1500 ip4 default inet4 192.168.0.20/24 route4 192.168.0.0/24 metric 100 route4 0.0.0.0/0 via 192.168.0.1 metric 100 inet6 fe80::a00:27ff:fe03:c92e/64 route6 fe80::/64 metric 100 tap0: connected to tap0 "tap0" tun, 26:55:7A:66:95:71, sw, mtu 1500 inet4 0.0.0.0/24 inet6 fe80::c312:f1a5:6f32:9f10/64 route6 fe80::/64 metric 450 br0: connected to br0 "br0" bridge, AA:FC:78:45:51:82, sw, mtu 1500 inet4 10.10.10.1/24 route4 10.10.10.0/24 metric 425 lo: unmanaged "lo" loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536 DNS configuration: servers: 8.8.8.8 1.1.1.1 interface: enp0s3 Use "nmcli device show" to get complete information about known devices and "nmcli connection show" to get an overview on active connection profiles. Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details. [root@srv ~]# nmcli con NAME UUID TYPE DEVICE enp0s3 09497bbf-da59-42b7-a72c-d69369760b36 ethernet enp0s3 tap0 5cb465f7-2b29-42dd-858a-ed141b0686b8 tun tap0 br0 89e26fba-57a8-4bb8-b46f-d85f3a1e0cd0 bridge br0 bridge-slave-tap0 446beb1d-af26-4e5f-9efd-9404ee23106c ethernet --
Now the tap0 may be used in QEMU to link the virtual machine network card with the host one, for example.
Here is the networking information using ip command form iproute2:
[root@srv ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:03:c9:2e brd ff:ff:ff:ff:ff:ff inet 192.168.0.20/24 brd 192.168.0.255 scope global noprefixroute enp0s3 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe03:c92e/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000 link/ether aa:fc:78:45:51:82 brd ff:ff:ff:ff:ff:ff inet 10.10.10.1/24 brd 10.10.10.255 scope global noprefixroute br0 valid_lft forever preferred_lft forever 4: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether 26:55:7a:66:95:71 brd ff:ff:ff:ff:ff:ff inet6 fe80::c312:f1a5:6f32:9f10/64 scope link tentative noprefixroute valid_lft forever preferred_lft forever [root@srv ~]# ping -c 4 10.10.10.1 PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data. 64 bytes from 10.10.10.1: icmp_seq=1 ttl=64 time=0.059 ms 64 bytes from 10.10.10.1: icmp_seq=2 ttl=64 time=0.052 ms 64 bytes from 10.10.10.1: icmp_seq=3 ttl=64 time=0.063 ms 64 bytes from 10.10.10.1: icmp_seq=4 ttl=64 time=0.052 ms --- 10.10.10.1 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3347ms rtt min/avg/max/mdev = 0.052/0.056/0.063/0.008 ms [root@srv ~]#
Bonus – network configuration files.
NetowrkManager created two additional network configurations under /etc/sysconfig/network-scripts/ with names ifcfg-br0 and ifcfg-bridge-slave-tap0.
[root@srv ~]# cat /etc/sysconfig/network-scripts/ifcfg-br0 STP=yes BRIDGING_OPTS=priority=32768 TYPE=Bridge PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none IPADDR=10.10.10.1 PREFIX=24 DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=br0 UUID=89e26fba-57a8-4bb8-b46f-d85f3a1e0cd0 DEVICE=br0 ONBOOT=yes [root@srv ~]# cat /etc/sysconfig/network-scripts/ifcfg-bridge-slave-tap0 TYPE=Ethernet NAME=bridge-slave-tap0 UUID=446beb1d-af26-4e5f-9efd-9404ee23106c DEVICE=tap0 ONBOOT=yes BRIDGE=br0
Bonus 2 – Internet to the bridge.
To enable the bridge to have Internet access just configure the firewall and activate masquerade mode.
[root@srv ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: br0 enp0s3 tap0 sources: services: cockpit dhcpv6-client ssh ports: protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: [root@srv ~]# firewall-cmd --permanent --add-masquerade success [root@srv ~]# firewall-cmd --reload success [root@srv ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: br0 enp0s3 tap0 sources: services: cockpit dhcpv6-client ssh ports: protocols: forward: no masquerade: yes forward-ports: source-ports: icmp-blocks: rich rules: