0

Hello I have a simple setup for explanation purposes created with following scripts:`

env.sh

CON1="con1" CON2="con2" NODE_IP="10.0.0.20" TUNNEL_IP="172.16.1.100" BRIDGE_IP="172.16.1.1" IP1="172.16.1.2" IP2="172.16.1.3" 

setup.sh

#!/bin/bash -e . env.sh echo "Creating the namespaces" sudo ip netns add $CON1 sudo ip netns add $CON2 echo "Creating the veth pairs" sudo ip link add veth10 type veth peer name veth11 sudo ip link add veth20 type veth peer name veth21 echo "Adding the veth pairs to the namespaces" sudo ip link set veth11 netns $CON1 sudo ip link set veth21 netns $CON2 echo "Configuring the interfaces in the network namespaces with IP address" sudo ip netns exec $CON1 ip addr add $IP1/24 dev veth11 sudo ip netns exec $CON2 ip addr add $IP2/24 dev veth21 echo "Enabling the interfaces inside the network namespaces" sudo ip netns exec $CON1 ip link set dev veth11 up sudo ip netns exec $CON2 ip link set dev veth21 up echo "Creating the bridge" sudo ip link add name br0 type bridge echo "Adding the network namespaces interfaces to the bridge" sudo ip link set dev veth10 master br0 sudo ip link set dev veth20 master br0 echo "Assigning the IP address to the bridge" sudo ip addr add $BRIDGE_IP/24 dev br0 echo "Enabling the bridge" sudo ip link set dev br0 up echo "Enabling the interfaces connected to the bridge" sudo ip link set dev veth10 up sudo ip link set dev veth20 up echo "Setting the loopback interfaces in the network namespaces" sudo ip netns exec $CON1 ip link set lo up sudo ip netns exec $CON2 ip link set lo up echo "Setting the default route in the network namespaces" sudo ip netns exec $CON1 ip route add default via $BRIDGE_IP dev veth11 sudo ip netns exec $CON2 ip route add default via $BRIDGE_IP dev veth21 

When I run sudo ip netns exec con1 ping <ip address of my eth0 on host>, then ping simply works, but inspection by wireshark indicates that traffic arrives at bridge with destination MAC address set to MAC address of the bridge(which makes sense given the routes in namespaces), but there are no subsequent ARPs to find out the MAC address of eth0 and the MAC address of eth0 is not listed in bridge br0 forwarding table.

So my question is, how come that ping still works with IP address assigned to eth0, when neither the namespace nor bridge are aware of anything about eth0?

What happens with frames and packets once they reach the bridge?

0

1 Answer 1

2

So my question is, how come that ping still works with IP address assigned to eth0, when neither the namespace nor bridge are aware of anything about eth0?

It has nothing to do with the bridge. IP addresses configured on interfaces only "loosely" bind to the respective interfaces. And by default Linux would response to ARP requests that attempt to resolve any of the addresses configured in a host (although there's sysctl like arp_ignore for you to change the behavior). (IIRC it's more of a matter of local routes in the local route table. You may even add one with ip route. May be worth mentioning that the ip rule that looks up the local route table is set with the highest precedence.)

In fact, AFAIK, there is no way other than firewall rules that allows you to more or less "mimick" a "strongly bound" behavior in the case where ARP isn't used (e.g. an L3 tunnel). fib in nftables does offer a way to have a "non-hardcoding" check (fib daddr . iif type != { local, broadcast, multicast }, as given in nft(8)). (Basically that means check the destination address in the route tables, and see if the route type is local, broadcast or multicast. . iif means consider only routes with route interface being the interface that the traffics ingress the host via, I think.)

What happens with frames and packets once they reach the bridge?

It may be worth mentioning that what you were talking about isn't exactly what happen "once they reach the bridge", but really "when they egress the bridge and reach the 'default' netns" (or "the host side", if you want to see it in the VM/container way). The bridge interface is like a virtual switch plus a switch port that the host is attached to. (The traffics "reaches" / ingress the bridge once it "get out of" the other end of the veth pair.) As you enslave (set master) more interfaces to the bridge, the number of switch ports increases.

Because you have a default route in the netns with the gateway address / nexthop being the IP address on the bridge, and the route is the only / "best" route that covers the IP on eth0, the netns would first send ARP requests out in attempt to resolve the nexthop. Then it uses the MAC address in the response to encapsulate the packet destined at IP address on eth0, which is why the frame would egress to the "host side" instead of to another connected netns or going nowhere. After the the the frame being de-encapsulated by the "host side", it recognizes the destination IP of the packet is one of its IP, so it "takes" the packet (instead of L3 forwarding it to another host or dropping it if that is disabled).

If you add a direct route (i.e., no nexthop, but e.g. ip route add $eth0_addr dev veth11) for the IP address on eth0 in the netns, the netns would send ARP request for that IP address instead, the "host side" would still response to the request as mentioned before, unless the behavior is changed / suppressed with e.g. arp_ignore. The response will still have the MAC address of the bridge (instead of eth0), because it is the interface the request ingress via, so the frame / packet will still egress to the "host side".

4
  • So basically once the packet arrives in root network namespace, it does not get "forwarded", or "handled by" eth0 anymore? I am asking because when I wireshark on eth0 I see no ICMP messages arriving. Commented Jul 14, 2024 at 7:48
  • @TheCoolDrop You can think of a host (and "network-wise" each netns is a host) as a room with different doors (its network interfaces), and as mentioned the room "knows" all its IP addresses, so when a packet get in from one door, it doesn't need to "reach" / be "handled by" another door, even if its destination address is the IP configured on the other door. L3/IP forwarding (going to another room through a different or the same door) occurs only when the destination IP is not one of the IPs of the room. Which door it will go through depends on the routes and etc. configured on in the room. Commented Jul 14, 2024 at 15:21
  • @TheCoolDrop And in case you'd be confused, local routes mentioned in the answer are essentially routes for making certain traffics "go no further and stay in the room", even when those routes also consists of a "door label" (route interface). In their case the "door label" is only for relating / binding the route destination to an interface and used for stuff like fib queries mentioned in the answer, or for making ping -I interface work "expectedly" when the destination is an IP of the host itself. Commented Jul 14, 2024 at 15:43
  • Well, if curiosity did not kill the cat, then Linux kernel may. I could not get peace of mind, so looked into the kernels bridge code. Turns out that when simple bridge, without LAN and STP, receives a packet for local route, then the behavior is basically the same as if machine received the packet from anywhere else. Basically net_if_receive_skb gets eventually called, kicking off the "regular" packet receival process of the kernel. Turns out it is as simple as possible. Occam's razor slices yet again. Commented Jul 18, 2024 at 6:45

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.