{"id":73,"date":"2025-03-02T11:01:42","date_gmt":"2025-03-02T11:01:42","guid":{"rendered":"https:\/\/aiinfrahub.com\/about-us\/?p=73"},"modified":"2025-03-13T07:56:24","modified_gmt":"2025-03-13T07:56:24","slug":"linux-network-bridge","status":"publish","type":"post","link":"https:\/\/aiinfrahub.com\/about-us\/linux-network-bridge\/","title":{"rendered":"Linux Network Bridge"},"content":{"rendered":"\n<p class=\"has-small-font-size\"><\/p>\n\n\n\n<p>In the last article, we have learned about linux network namespace (<a href=\"https:\/\/aiinfrahub.com\/linux-network-namespace\/\" data-type=\"link\" data-id=\"https:\/\/aiinfrahub.com\/linux-network-namespace\/\">https:\/\/aiinfrahub.com\/linux-network-namespace\/<\/a>), Also, we understood that there is a serious scalability issue when connecting namespaces. As the no of namespaces increases we will face tremendous challenge in creating veth pair and connecting the namespaces.<\/p>\n\n\n\n<p>Rescue is done by&nbsp;Linux bridge&nbsp;which can tap these network namespaces to the bridge to get connectivity. The same concept applied to the Docker where it sets up networking between containers running on the same host.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Linux network bridge ?<\/h2>\n\n\n\n<p>A bridge works at Layer 2 of OSI model ie data link layer &nbsp;and it functions similar to a network switch. It allows multiple network interfaces to communicate with each other based on MAC addresses, which is essential for virtual networking, required for environments using containers or virtual machines.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demo<\/h2>\n\n\n\n<p>We will demo the linux bridge in a single system whose hostname is \u201chost1\u201d. Below is setup diagram which we will create using commands.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"693\" height=\"370\" src=\"https:\/\/aiinfrahub.com\/wp-content\/uploads\/2025\/03\/image-1.png\" alt=\"\" class=\"wp-image-75\" srcset=\"https:\/\/aiinfrahub.com\/wp-content\/uploads\/2025\/03\/image-1.png 693w, https:\/\/aiinfrahub.com\/wp-content\/uploads\/2025\/03\/image-1-300x160.png 300w\" sizes=\"auto, (max-width: 693px) 100vw, 693px\" \/><\/figure>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Define some macros for host1\nNS1=\"NS1\"\nNS2=\"NS2\"\nBRIDGE_SUBNET=\"10.0.0.0\/24\"\nBRIDGE_IP=\"10.0.0.1\"\nIP1=\"10.0.0.2\"\nIP2=\"10.0.0.3\"<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create the namespaces<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Create the namespaces\nsudo ip netns add $NS1\nsudo ip netns add $NS2\nhost1$ ip netns show\nNS1\nNS2<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create the veth pairs<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Create the veth pairs\nhost1$sudo ip link add vethNS1 type veth peer name vethNS1-br\nhost1$sudo ip link add vethNS2 type veth peer name vethNS2-br\nhost1$ip link show | grep veth\n22: vethNS1-br@vethNS1: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\n23: vethNS1@vethNS1-br: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\n24: vethNS2-br@vethNS2: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\n25: vethNS2@vethNS2-br: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add the veth pairs to the namespaces<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Adding the veth pairs to the namespaces\nhost1$sudo ip link set vethNS1 netns $NS1\nhost1$sudo ip link set vethNS2 netns $NS2\nhost1$sudo ip netns exec NS1 ip addr\n1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN group default qlen 1000\n    link\/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n23: vethNS1@if22: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000\n    link\/ether 9a:ab:15:34:22:f1 brd ff:ff:ff:ff:ff:ff link-netnsid 0<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Configure the veth interfaces in the network namespace with ip address<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Configure the veth interfaces in the network namespace with ip address\n\nhost1$sudo ip netns exec $NS1 ip addr add $IP1\/24 dev vethNS1\n\nhost1$sudo ip netns exec $NS2 ip addr add $IP2\/24 dev vethNS2\n\nhost1$sudo ip netns exec NS1 ip addr\n\n1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN group default qlen 1000\n\n&nbsp;&nbsp;&nbsp;&nbsp;link\/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n\n23: vethNS1@if22: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000\n\n&nbsp;&nbsp;&nbsp;&nbsp;link\/ether 9a:ab:15:34:22:f1 brd ff:ff:ff:ff:ff:ff link-netnsid 0\n\n&nbsp;&nbsp;&nbsp;&nbsp;inet 10.0.0.2\/24 scope global vethNS1\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valid_lft forever preferred_lft forever<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Enable the interfaces in the network namespace to get the IP&#8217;s<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Enable the interfaces in the network namespace\nhost1$sudo ip netns exec $NS1 ip link set dev vethNS1 up\nhost1$sudo ip netns exec $NS2 ip link set dev vethNS2 up\nhost1$sudo ip netns exec NS1 ip addr\n1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN group default qlen 1000\n    link\/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n23: vethNS1@if22: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000\n    link\/ether 9a:ab:15:34:22:f1 brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 10.0.0.2\/24 scope global vethNS1\n       valid_lft forever preferred_lft forever<\/code><\/pre>\n\n\n\n<p>Here, you can observe that the state is \u201cLOWERLAYERDOWN\u201d, its because the other end veth is yet not connected, once we connect it to bridge the state will be \u201cUP\u201d.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create the bridge<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Create the bridge\nhost1$sudo ip link add br0 type bridge\nhost1$ip link show type bridge\n26: br0: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\n    link\/ether 16:d3:08:5d:a7:55 brd ff:ff:ff:ff:ff:ff<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add the network namespaces interfaces to the bridge<\/li>\n\n\n\n<li>Assign IP address to the bridge<\/li>\n\n\n\n<li>Enable the bridge<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Adding the network namespaces interfaces to the bridge\nhost1$sudo ip link set dev vethNS1-br master br0\nhost1$sudo ip link set dev vethNS2-br master br0\n\n# Assign IP address to the bridge\nhost1$sudo ip addr add $BRIDGE_IP\/24 dev br0\n\n# Enable the bridge\nhost1$sudo ip link set dev br0 up<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Enable the interfaces connected to the bridge<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Enable the interfaces connected to the bridge\"\nhost1$sudo ip link set dev vethNS1-br up\nhost1$sudo ip link set dev vethNS2-br up\nhost1$sudo ip netns exec NS1 ip addr\n1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN group default qlen 1000\n    link\/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n23: vethNS1@if22: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000\n    link\/ether 9a:ab:15:34:22:f1 brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 10.0.0.2\/24 scope global vethNS1\n       valid_lft forever preferred_lft forever\n    inet6 fe80::98ab:15ff:fe34:22f1\/64 scope link\n       valid_lft forever preferred_lft forever<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">PING Test<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify the two network namespaces are&nbsp;connected and are reachable&nbsp;with the same host<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host1$sudo ip netns exec NS1 ping 10.0.0.3 -c 2\nPING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.\n64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.154 ms\n64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.056 ms<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify the&nbsp;network namespaces can ping itself<\/li>\n<\/ul>\n\n\n\n<p>Example, we will try to ping NS2\u2019s ip from NS2 namespace<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host1$sudo ip netns exec NS2 ping 10.0.0.3 -c 2\nPING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.\n\n--- 10.0.0.3 ping statistics ---\n2 packets transmitted, 0 received, 100% packet loss, time 1028ms<\/code><\/pre>\n\n\n\n<p>We see that its 100% packet loss, its happening because we don\u2019t have loopback interface. Enabled. Lets enable the loopback interface and see if its self pinging.<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>#Setting the loopback interfaces in the network namespaces\nhost1$sudo ip netns exec $NS1 ip link set lo up\nhost1$sudo ip netns exec $NS2 ip link set lo up\n\nhost1$sudo ip netns exec NS2 ping 10.0.0.3 -c 2\nPING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.\n64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.026 ms\n64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.103 ms\n\n--- 10.0.0.3 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1065ms\nrtt min\/avg\/max\/mdev = 0.026\/0.064\/0.103\/0.038 ms<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify the&nbsp;network namespaces connectivity with the host IP<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host1$sudo ip netns exec NS2 ping 10.20.2.4 -c 2\nping: connect: Network is unreachable<\/code><\/pre>\n\n\n\n<p>&nbsp;\u2018Network is unreachable\u2019 , this behaviour is expected because there is no route configured in the newly created namespaces. Lets set the default route in the network namespace<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code># Setting the default route in the network namespace\nhost1$sudo ip netns exec $NS1 ip route add default via $BRIDGE_IP dev vethNS1\nhost1$sudo ip netns exec $NS2 ip route add default via $BRIDGE_IP dev vethNS2\n\nhost1$sudo ip netns exec NS2 ping 10.20.2.4 -c 2\nPING 10.20.2.4 (10.20.2.4) 56(84) bytes of data.\n64 bytes from 10.20.2.4: icmp_seq=1 ttl=64 time=0.167 ms\n64 bytes from 10.20.2.4: icmp_seq=2 ttl=64 time=0.108 ms\n\n--- 10.20.2.4 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1056ms\nrtt min\/avg\/max\/mdev = 0.108\/0.137\/0.167\/0.029 ms<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify the two network namespaces on two different hosts are&nbsp;connected and are reachable.<br>Basically, we want to&nbsp;ping from HOST1-&gt;NS1 to HOST2-&gt;NS1<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"692\" height=\"204\" src=\"https:\/\/aiinfrahub.com\/wp-content\/uploads\/2025\/03\/image-2.png\" alt=\"\" class=\"wp-image-76\" style=\"width:820px;height:auto\" srcset=\"https:\/\/aiinfrahub.com\/wp-content\/uploads\/2025\/03\/image-2.png 692w, https:\/\/aiinfrahub.com\/wp-content\/uploads\/2025\/03\/image-2-300x88.png 300w\" sizes=\"auto, (max-width: 692px) 100vw, 692px\" \/><\/figure>\n\n\n\n<p>We will be following same steps in HOST2 similar to HOST1.<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>NS1=\"NS1\"\nNS2=\"NS2\"\nBRIDGE_SUBNET=\"10.0.0.0\/24\"\nBRIDGE_IP=\"10.0.1.1\"\nIP1=\"10.0.1.2\"\nIP2=\"10.0.1.3\"\n\nsudo ip netns add $NS1\nsudo ip netns add $NS2\n\nsudo ip link add vethNS1 type veth peer name vethNS1-br\nsudo ip link add vethNS2 type veth peer name vethNS2-br\n\nsudo ip link set vethNS1 netns $NS1\nsudo ip link set vethNS2 netns $NS2\n\nsudo ip netns exec $NS1 ip addr add $IP1\/24 dev vethNS1 \nsudo ip netns exec $NS2 ip addr add $IP2\/24 dev vethNS2 \n\nsudo ip netns exec $NS1 ip link set dev vethNS1 up\nsudo ip netns exec $NS2 ip link set dev vethNS2 up\n\nsudo ip link add br0 type bridge\nsudo ip link set dev vethNS1-br master br0\nsudo ip link set dev vethNS2-br master br0\n\nsudo ip addr add $BRIDGE_IP\/24 dev br0\n\nsudo ip link set dev br0 up\n\nsudo ip link set dev vethNS1-br up\nsudo ip link set dev vethNS2-br up\n\nsudo ip netns exec $NS1 ip route add default via $BRIDGE_IP dev vethNS1<\/code><\/pre>\n\n\n\n<p>Lets ping from HOST1-&gt;NS1 to HOST2-&gt;NS1<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host1$sudo ip netns exec NS1 ping 10.0.1.2 -c 2\nPING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.\n\n--- 10.0.1.2 ping statistics ---\n2 packets transmitted, 0 received, 100% packet loss, time 1061ms<\/code><\/pre>\n\n\n\n<p>We can see that there is 100 % packet loss. We need route on HOST1 to reach the network namespace of HOST2. Also we have enable IP forwarding on each node.<\/p>\n\n\n\n<p>HOST1:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host1$#sudo ip route add 10.0.1.0\/24 via 10.20.2.5 dev enp0s3\nhost1$#sudo sysctl -w net.ipv4.ip_forward=1<\/code><\/pre>\n\n\n\n<p>HOST2:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host2$#sudo ip route add 10.0.0.0\/24 via 10.20.2.4 dev enp0s3\nhost2$#sudo sysctl -w net.ipv4.ip_forward=1<\/code><\/pre>\n\n\n\n<p>PING test:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>host1$sudo ip netns exec NS1 ping 10.0.1.2 -c 2\nPING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.\n64 bytes from 10.0.1.2: icmp_seq=1 ttl=62 time=0.596 ms\n64 bytes from 10.0.1.2: icmp_seq=2 ttl=62 time=0.976 ms\n\n--- 10.0.1.2 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1036ms\nrtt min\/avg\/max\/mdev = 0.596\/0.786\/0.976\/0.190 ms<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Here, we have reached the end of our linux network bridge demo.We have covered basic connectivity between network namespaces using linux bridges. Also, all the scenarios were based on network resources residing in same subnet. When communication between network constructs is within same subnet then docker or &nbsp;Kubernetes uses native routing.<\/p>\n\n\n\n<p>However, when nodes and interfaces belong to different subnets, the concept of overlay networks comes into picture.<\/p>\n\n\n\n<p>An overlay network is a virtual network that sits on top of an existing network infrastructure. It allows devices in different subnets or even different physical locations to communicate as if they were on the same Layer 2 or Layer 3 network.<\/p>\n\n\n\n<p>In Kubernetes, all modern day CNI (Container Network Interface) &nbsp;plugin implement overlay networks to ensure seamless communication across different nodes residing on different subnet.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>We will go over the Container Network Interface&nbsp;in the next chapter.<\/p>\n\n\n\n<p>Good Bye for now.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<p><a href=\"https:\/\/man7.org\/linux\/man-pages\/man8\/bridge.8.html\">https:\/\/man7.org\/linux\/man-pages\/man8\/bridge.8.html<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Network_bridge\">https:\/\/en.wikipedia.org\/wiki\/Network_bridge<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the last article, we have learned about linux network namespace (https:\/\/aiinfrahub.com\/linux-network-namespace\/), Also, we understood that there is a serious scalability issue when connecting namespaces. As the no of namespaces increases we will face tremendous challenge in creating veth pair and connecting the namespaces. Rescue is done by&nbsp;Linux bridge&nbsp;which can tap these network namespaces to &#8230; <a title=\"Linux Network Bridge\" class=\"read-more\" href=\"https:\/\/aiinfrahub.com\/about-us\/linux-network-bridge\/\" aria-label=\"Read more about Linux Network Bridge\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":74,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4],"tags":[],"class_list":["post-73","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-kubernetes","category-networking"],"_links":{"self":[{"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/posts\/73","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/comments?post=73"}],"version-history":[{"count":5,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/posts\/73\/revisions"}],"predecessor-version":[{"id":104,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/posts\/73\/revisions\/104"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/media\/74"}],"wp:attachment":[{"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/media?parent=73"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/categories?post=73"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aiinfrahub.com\/about-us\/wp-json\/wp\/v2\/tags?post=73"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}