Enable routing between interfaces using systemd-networkd on colibi iMX6 running stock linux

Hello,

I am having trouble getting the routing function to work for my design. I have a wireless dongle (wlan0) setup as an access point / DHCP server and I can connect to the web server in the colibri from nodes on the wireless network (192.168.13.0/24). The ethernet port (eth0) is setup using dhcp and I can get to the colibri web server from nodes on that network (192.168.10.0/24).

What I can’t do that I would like to do is connect to a node on the eth0 network from a host on the wireless network. … I need a router. I don’t need much in the way of firewalling / security because I control both networks and so will the end customer.

network setup:

root@colibri-imx6:~# ip -4 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,DYNAMIC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.10.109/24 brd 192.168.10.255 scope global dynamic eth0
       valid_lft 82040sec preferred_lft 82040sec
4: wlan0: <BROADCAST,MULTICAST,DYNAMIC,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 192.168.13.1/24 brd 192.168.13.255 scope global wlan0
       valid_lft forever preferred_lft forever
5: usb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    inet 192.168.11.1/24 brd 192.168.11.255 scope global usb0
       valid_lft forever preferred_lft forever
root@colibri-imx6:~#
root@colibri-imx6:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.10.1    0.0.0.0         UG    0      0        0 eth0
0.0.0.0         192.168.10.1    0.0.0.0         UG    1024   0        0 eth0
192.168.10.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.10.1    0.0.0.0         255.255.255.255 UH    0      0        0 eth0
192.168.10.1    0.0.0.0         255.255.255.255 UH    1024   0        0 eth0
192.168.11.0    0.0.0.0         255.255.255.0   U     0      0        0 usb0
192.168.13.0    0.0.0.0         255.255.255.0   U     0      0        0 wlan0
root@colibri-imx6:~#

I can ping both subnets from the module:

root@colibri-imx6:~# ping -c3 192.168.13.155
PING 192.168.13.155 (192.168.13.155): 56 data bytes
64 bytes from 192.168.13.155: seq=0 ttl=64 time=16.176 ms
64 bytes from 192.168.13.155: seq=1 ttl=64 time=239.120 ms
64 bytes from 192.168.13.155: seq=2 ttl=64 time=192.539 ms

--- 192.168.13.155 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 16.176/149.278/239.120 ms
root@colibri-imx6:~#
root@colibri-imx6:~# ping -c3 192.168.10.110
PING 192.168.10.110 (192.168.10.110): 56 data bytes
64 bytes from 192.168.10.110: seq=0 ttl=64 time=0.497 ms
64 bytes from 192.168.10.110: seq=1 ttl=64 time=0.467 ms
64 bytes from 192.168.10.110: seq=2 ttl=64 time=0.466 ms

--- 192.168.10.110 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.466/0.476/0.497 ms
root@colibri-imx6:~#

Routing is a kernel network subsystem feature which is not particular to any device. You can enable using

 echo 1 > /proc/sys/net/ipv4/ip_forward

Or you can sysctl enable it automatically upon boot by uncommenting the following line in /etc/sysctl.conf:

net.ipv4.ip_forward=1

I’ve already verified that ipforwarding is enabled in the interface configuration(s):

root@colibri-imx6:~# sysctl -a |grep net.ipv4.conf.eth0.forwarding
net.ipv4.conf.eth0.forwarding = 1

Here is a thread on “linux questions” that has some details

Ok, with that routing should just work fine. What is it exactly what does not work?

Just make sure that your host in wlan0 has 192.168.13.1 configured as default route, as well as your host in 192.168.10.0/24 needs 192.168.10.109 set as default route. Alternatively you can add a static routes to your hosts.

I can’t ping the service router at 192.168.10.1 from any host on the .13.0/24 network.

root@colibri-imx6:~# ip route
default via 192.168.10.1 dev eth0
192.168.10.0/24 dev eth0  proto kernel  scope link  src 192.168.10.109
192.168.10.1 dev eth0  scope link
192.168.11.0/24 dev usb0  proto kernel  scope link  src 192.168.11.1
192.168.13.0/24 dev wlan0  proto kernel  scope link  src 192.168.13.1
root@colibri-imx6:~# ip rule add nat 192.168.13.1 from 192.168.10.1
RTNETLINK answers: Operation not supported
Dump terminated
root@colibri-imx6:~# ip route add nat 192.168.13.1 via 192.168.10.1
RTNETLINK answers: Invalid argument
root@colibri-imx6:~#

Also, the colibri is not routing for the .10.0/24 network. It is just a node on that subnet. (.10.109)

What I want is to get packets from the .13.0/24 subnet that are bound for outside the 13.0/24 net to hit the router at .10.1 as if they came from the .10.109 node.

Hosts on the .13.0/24 subnet have the colibri (.13.1) configured as their default gateway. Hosts on the .10.0/24 subnet have the router at .10.1 configured as their default gateway.

What I want is to get packets from the .13.0/24 subnet that are bound for outside the 13.0/24 net to hit the router at .10.1 as if they came from the .10.109 node.

Ok, what you describe here is not only routing, but also NAT (network address translation). Try the following iptables command:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Using the Arch Linux iptables.service file as template, I created the following service file: (store in /etc/systemd/system/multi-user.target.wants/iptables.service):

[Unit]
Description=Packet Filtering Framework
Before=network-pre.target
Wants=network-pre.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/iptables-restore /etc/iptables/iptables.rules
RemainAfterExit=yes                                               
                                                
[Install]          
WantedBy=multi-user.target

And create the iptables rules file (this stores the current iptables configuration to the rules file):

mkdir /etc/iptables/
iptables-save > /etc/iptables/iptables.rules

As displayed in my previous comment I was trying to add the NAT function…

ip route add nat ...
ip rule add nat ... 

I tried iptables very early on in this adventure…

root@colibri-imx6:~#  iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
modprobe: FATAL: Module ip_tables not found.
iptables v1.4.21: can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
root@colibri-imx6:~# 
root@colibri-imx6:~# mkdir /etc/iptables
root@colibri-imx6:~# iptables-save > /etc/iptables/iptables.rules
root@colibri-imx6:~# cat /etc/iptables/iptables.rules
root@colibri-imx6:~#

It looks like the i.MX 6 kernel is lacking NAT functionality. Adding the following config to your kernel configuration should fix it: CONFIG_IP_NF_IPTABLES.

So I have been trying to do the kernel modification and have run into some snags. I setup the open embedded environment and successfully built the 2.7_next angstrom image. This image runs fine on the target but has the same limitation as the production image in terms of “advanced routing”. So I thought I could easily configure the kernel / image I needed using bitbake. I did:

bitbake -c menuconfig virtual/kernel

I enabled the IP: advanced router option and the IP: policy routing option I saved the configuration to .config and exited. Then I did:

bitbake -c clean angstrom-lxde-image

followed by:

bitbake -k angstrom-lxde-image

The build fails 2 warnings and 13 errors:

WARNING: blah/linux-toradex_4.1-2.0.x.bb.do_compile is tainted from a forced run
ERROR: When reparsing ../layers/meta-toradex-demos/recepes-images/images/angstrom-lxde-image.bb.do_imagedeploy, base hash has changed. The meta data is not deterministic and this needs to be fixed.

If I do:

repo sync

then rebuild the image everything succeeds and the “stock” image runs fine on the target

After running

 bitbake -c menuconfig virtual/kernel

it is required to execute the following

bitbake -f -c compile virtual/kernel

to force recompilation of kernel and then

bitbake -k angstrom-lxde-image

repo sync is not required at all once it has been initialized and synced earlier.