NanoPi R5S as a Network Switch

Hi! Thank you a ton for DietPi. It’s a wonderful piece of software! I’m having some troubles configuring it though.

I’m trying to use NanoPi R5S as a smart network switch using its 3 Ethernet ports. I was able to successfully do that on the previous OS installed on it – an OpenWRT derivative. The relevant part of /etc/config/network file looked like this:

config interface 'lan'
	option ipv6 'off'
	option device 'switch0'
	option proto 'dhcp'

config device
	option type 'bridge'
	option name 'switch0'
	list ports 'eth0'
	list ports 'eth1'
	list ports 'eth2'
	option ipv6 '0'
	option mtu '1500'
	option macaddr '86:5E:CE:F4:81:18'

So I want to link eth0, eth1 and eth2 all into a single bridge. I tried replicating this on DietPi:

/etc/network/interfaces:

auto br0
iface br0 inet dhcp
        bridge_ports eth0 eth1 eth2
        hwaddress 86:5e:ce:f4:81:18

This partially works. I’m able to make connections to and from the DietPi host, but the traffic switching part doesn’t seem to be working: From a laptop connected over a wire to the NanoPi, I’m able to ssh into DietPi, but I’m not able to reach either my network router, nor the public internet. Everything works if I bypass the wired connection by using WiFi of course.

My network topology looks like this:
OpenWRT router <=Ethernet-cable=> NanoPi <=Ethernet-cable=> laptop

The laptop is a Mac with this config:

On the DHCP server, I configure DietPi to be assigned IP address 192.168.1.100.

Can anyone recommend what else can I check to make the laptop reach the public internet (I’m not sure if I’m supposed to have 1 or 2 subnets for instance)? Any help appreciated!

When I look into examples from debian, they set up the physicals interfaces “manually” beforehand:
https://wiki.debian.org/BridgeNetworkConnections#Configuring_bridging_in_.2Fetc.2Fnetwork.2Finterfaces

 iface eth0 inet manual
 iface eth1 inet manual

 # Bridge setup
 iface br0 inet dhcp
    bridge_ports eth0 eth1

Maybe that makes a difference?

And what I don’t understand:

And in the screenshot, it shows .100 as gateway/router.
You are telling your laptop, that the gateway/ route to internet is your DietPi device, which is not the case, it’s just another client in the LAN, which is acting like a router.
I think you would need to set gateway/router also to .1 on the laptop. (Or let DHCP all handle this)

(You could establish another subnet via DHCP on your NanoPi, then it would be the gateway of the connected clients. But then you need routing rules to you other subnet, so why fiddle with all that? Let the existing DHCP server handle all that.)

No, the NanoPi is already a part of your existing LAN an also the connected devices will become part of it.

I tried that and generally had problems with picking right IP addresses for the ethX interfaces: I needed to specify either a static one or a DHCP and neither of those makes sense or is necessary for bridging AFAIU (the bridge interface it’s the only one that should have an IP address). The current configuration that I have looks right: the bridge interface is up, it’s the only one that has an IP address, all the ethX interfaces are also up yet they don’t have IP addresses. That’s how it should all looks, so I’m a bit reluctant to touch it :sweat_smile:

Good point! I changed it and a ping 192.168.1.1 from the laptop still doesn’t reach the router though, indicating that packet switching on the DietPi still isn’t functional.

Thank you, that’s good to hear because it makes the entire setup simpler!

This is expected since nothing is connected to them. It’s like a router, the router itself (bridge) has an IP. The ports do not have an IP, only the devices you connect to this ports.
If you want them as interfaces, you can’t use the bridge mode.

Can you show ip a and bridge link.

I only want for the DietPi device to act as a switch :+1:

root@NanoPi:~# 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 noprefixroute
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br0 state UP group default qlen 1000
    link/ether 7e:16:3b:26:3b:1d brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000
    link/ether 82:16:3b:26:3b:1d brd ff:ff:ff:ff:ff:ff
4: eth2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast master br0 state DOWN group default qlen 1000
    link/ether f6:67:08:83:ef:2c brd ff:ff:ff:ff:ff:ff
5: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 86:5e:ce:f4:81:18 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global dynamic br0
       valid_lft 24178sec preferred_lft 24178sec
    inet6 fe80::7c16:3bff:fe26:3b1d/64 scope link
       valid_lft forever preferred_lft forever
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:17:0c:01:c7 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:17ff:fe0c:1c7/64 scope link
       valid_lft forever preferred_lft forever
7: br-8b62b0970274: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:69:45:6d:f8 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-8b62b0970274
       valid_lft forever preferred_lft forever
    inet6 fe80::42:69ff:fe45:6df8/64 scope link
       valid_lft forever preferred_lft forever
33: veth549e5f8@if32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether ca:bb:c0:df:e3:65 brd ff:ff:ff:ff:ff:ff link-netnsid 4
    inet6 fe80::c8bb:c0ff:fedf:e365/64 scope link
       valid_lft forever preferred_lft forever
35: veth8c71c4f@if34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-8b62b0970274 state UP group default
    link/ether a2:91:6b:58:de:aa brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::a091:6bff:fe58:deaa/64 scope link
       valid_lft forever preferred_lft forever
37: veth2efd70c@if36: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 5e:4f:80:33:fb:16 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::5c4f:80ff:fe33:fb16/64 scope link
       valid_lft forever preferred_lft forever
39: vethbea00bc@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-8b62b0970274 state UP group default
    link/ether ee:55:26:4d:40:7a brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::ec55:26ff:fe4d:407a/64 scope link
       valid_lft forever preferred_lft forever
41: vethacb6e80@if40: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-8b62b0970274 state UP group default
    link/ether ba:c7:af:ac:e5:12 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::b8c7:afff:feac:e512/64 scope link
       valid_lft forever preferred_lft forever
43: veth1fcf11a@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-8b62b0970274 state UP group default
    link/ether 12:48:3e:2a:fc:0c brd ff:ff:ff:ff:ff:ff link-netnsid 5
    inet6 fe80::1048:3eff:fe2a:fc0c/64 scope link
       valid_lft forever preferred_lft forever
root@NanoPi:~# bridge link
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
4: eth2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 master br0 state disabled priority 32 cost 100
33: veth549e5f8@if32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
35: veth8c71c4f@if34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-8b62b0970274 state forwarding priority 32 cost 2
37: veth2efd70c@if36: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
39: vethbea00bc@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-8b62b0970274 state forwarding priority 32 cost 2
41: vethacb6e80@if40: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-8b62b0970274 state forwarding priority 32 cost 2
43: veth1fcf11a@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-8b62b0970274 state forwarding priority 32 cost 2

Did you try to add this to the config?

auto eth0
iface eth0 inet manual # Set to "manual" to prevent automatic configuration
auto eth1
iface eth1 inet manual # Set to "manual" to prevent automatic configuration
auto eth2
iface eth2 inet manual  # Set to "manual" to prevent automatic configuration

And you can also try to use DHCP on the laptop and check on the router if it assigned an IP to it.

I changed that, did ifdown -a && if up -a, systemctl restart networking.service (for good measure) and there’s no difference – still can’t ping router from the laptop.

Just tried that – It doesn’t.

This may be interesting:

If I do tcpdump -i eth1 port 67 or port 68 -e -n -vv on the DietPi, I can see the DHCP requests coming from the laptop.

I have an analogous tcpdump command opened at the same time, but for the eth1 interface on DietPi and it doesn’t show any DHCP requests being forwarded from the laptop to the router.

That leads me to believe the DHCP requests are getting swallowed/not forwarded by NanoPi for some reason.

Found it! Turns out it’s an iptables issue! This one exactly: networking - why linux bridge doesn't work - Super User
After echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables, the laptop got its IP address via DHCP finally and pinging the router started working!

Now the problem is that the setting get reset on reboot even if I put it into /etc/sysctl.conf.

1 Like

Since setting the requisite kernel parameters at boot time seems to be buggy, I had to resort to create a workaround. I created this systemd init file (/etc/systemd/system/bridge-config.service):

[Unit]
Description=Bridge configuration
After=network.target

[Service]
User=root
LogsDirectory=bridge-config
WorkingDirectory=/root
Type=oneshot
ExecStart=/bin/bash -c "while [[ ! -f /proc/sys/net/bridge/bridge-nf-call-iptables ]]; do sleep 1; done; echo 0 >/proc/sys/net/bridge/bridge-nf-call-iptables"

[Install]
WantedBy=multi-user.target

then

$ systemctl enable bridge-config.service

and after a reboot, it should be working.

I think you can just add this to /etc/sysctl.conf to make it permanent

echo 'net.bridge.bridge-nf-call-iptables = 0' >> /etc/sysctl.conf

which means, the traffic which passes the bridge ignores any iptables rules?

Or you create an iptables rule to allow all traffic from and to the bridge. :smiley:
iptables -A FORWARD -i br0 -o br0 -j ACCEPT

This has no effect unfortunately for those particular kernel parameters. See the linked bug above.

That’s right.

Yep, that should also work :smiley: