2

I have a raspberry pi with three interfaces connected, eth0, wlan0 and ppp0, what i'm looking to achieve is having routes to the internet through all interfaces, but so far only eth0 and ppp0 gets a route.

here's outputs of route -n and ip route show (don't have a working ppp0 interface now but i know that one works)

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 wlan0

default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.39
192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.243

I wrote a script that is triggered from /etc/dhcp/dhclient-exit-hooks.d/ so once the interface gets an offer from dhcp.

#!/bin/bash

calculateCIDR() {
    nbits=0
    IFS=.
    for dec in $1 ; do
        case $dec in
            255) let nbits+=8;;
            254) let nbits+=7;;
            252) let nbits+=6;;
            248) let nbits+=5;;
            240) let nbits+=4;;
            224) let nbits+=3;;
            192) let nbits+=2;;
            128) let nbits+=1;;
            0);;
            *) 
                echo "Error calulating CIDR exiting."; 
                exit 1
            ;;
        esac
    done
    echo $nbits
}

calculateSubnet() {
    IFS=. read -r i1 i2 i3 i4 <<< $1
    IFS=. read -r m1 m2 m3 m4 <<< $2
    echo "$((i1 & m1)).$((i2 & m2)).$((i3 & m3)).$((i4 & m4))"
}

# check if all parameters are there
# expected parameters 
# $1 = iface
# $2 = ip
# $3 = mask
# $4 = gateway
if [ $# -ne 4 ]
  then
    echo "Illegal number of arguments"
    exit 2
fi

# assign variables
IFACE=$1
IP=$2
MASK=$3
GATEWAY=$4

# extract inface number and calculate table number 
case $IFACE in
    eth*)
        TABLEID=$(( 10 + `echo $IFACE | grep -o -E '[0-9]+'`))
        METRIC=0
    ;;
    wlan*)
        TABLEID=$(( 30 + `echo $IFACE | grep -o -E '[0-9]+'`))
        METRIC=$(( 50 + `echo $IFACE | grep -o -E '[0-9]+'`))
    ;;
    ppp*)
        TABLEID=$(( 90 + `echo $IFACE | grep -o -E '[0-9]+'`))
        METRIC=$(( 100 + `echo $IFACE | grep -o -E '[0-9]+'`))
    ;;
    *)
        echo "Bad interface exiting"
        exit 1
    ;;
esac

# create new table for interface only if not existing there already
grep -q -F "$TABLEID $IFACE" /etc/iproute2/rt_tables || echo "$TABLEID $IFACE" >> /etc/iproute2/rt_tables

# remove previous rules
while ip rule delete table $IFACE 2>/dev/null; do true; done

# flush previous table
ip route flush table $IFACE

# calculate CIDR from
CIDR=$(calculateCIDR $MASK)

# calculate subnet address
SUBNET=$(calculateSubnet $IP $MASK)

# create route for local network
ip route add $SUBNET/$CIDR dev $IFACE src $IP metric $METRIC table $IFACE

# create route for internet
ip route add default via $GATEWAY dev $IFACE metric $METRIC table $IFACE

# set rules for the interface
ip rule add from $IP/32 table $IFACE
ip rule add to $IP/32 table $IFACE

# done 
exit 0

this same script is used for all interfaces provided with network setup, wlan0 never gets a route to internet meaning i can't use it to ping anything outside the local network. anyone knows why ? i'm running out of ideas.

  • In general, you can't. Multiple routes to the same destination for load balancing via different interfaces don't work. Bonding only works if both sides bond. The best you can do is to use some kind of fallback mechanism (e.g., use WLAN if the LAN goes down). – dirkt Mar 1 '18 at 13:01
  • Bond 1 works with quick mac address expiration of the inactive member so, there is no need that both network equipments implement it. Stop spreading missinformation. Take a look at my comment at my answer and official documentation - kernel.org/doc/Documentation/networking/bonding.txt - Bond does not require LACP – user34720 Mar 1 '18 at 17:57
  • 1
    Look at this (outdated) documentation about having multiple links to internet: lartc.org/howto/lartc.rpdb.multiple-links.html . Parts 4.2 and 4.2.1 are mostly fine, part 4.2.2 doesn't work anymore (but using iptables' statistic --mode nth + MARK along with ip rule's fwmark does work). Anyway the solution proposed does indeed use this kind of setting: using additional routing tables – A.B Mar 4 '18 at 15:53
1

First: Always use ip(8) command instead. route is one of those Linux commands on it's way to deprecation. Basically, Linux route was ported from other OS and does not work with Linux routing table scheme(it only shows main table).

main route table is always implicit. Before matching what needs to be routed through main, table local is also looked by the Kernel(basically all broadcast, local address and loopback is there). That's why you can't have a default route on each interface, cause when routing on table main only one of the default will have precedence over others. Look what tables you have with ip rule list.

What you will have to do to configure basic redundancy is:

  • Create 2 rules(say, link01 and `link02) and its routing tables
  • Keep default route empty on main table.
  • Create one default route to table link01 and other to link02.
  • Create rules to those tables or iptables rules when you will match each table
  • Create separated network ip ranges to Wifi and Cable connections.

You face a problem on your current setup: You are repeating a default route on the same gateway and on the same table(main) to different interfaces(probably facing the "route already exists" error when trying to add the default route the second time). This is never going to happen. How arp is supposed to deal with the same IP being published on 2 interfaces at the same time?

Alternative solution:

If you want some redundancy like an active-backup solution without having to change the items i've enlisted above, you could use a bonding interface configured on mode 1, put eth0 and wlan0 as slaves. This is a Debian example of /etc/network/interfaces so you will have to adapt to your distribution:

# Slaves   
auto eth0
iface eth0 inet manual
    bond-master bond0
    bond-primary eth0
    bond-mode active-backup

auto wlan0
iface wlan0 inet manual
    wpa-conf /etc/network/wpa.conf
    bond-master bond0
    bond-primary eth0
    bond-mode active-backup

# Master
auto bond0
iface bond0 inet dhcp
    bond-slaves none
    bond-primary eth0
    bond-mode active-backup
    bond-miimon 100

This way you will connect on cable and wifi, and have an "unified" ip address to both.

If you have a mid/high end network switch that is able to do LACP(IEEE 802.3ad) you can do a link aggregation that will use both cables/connections at the same time(and bond mode of Linux will be 4).

  • Note that bonding interfaces only works if the communication partner (e.g. the home router) also bonds the interfaces in the same way. In particular, this setup will force all other clients to be both on LAN and WLAN, and have configured it the same way. – dirkt Mar 1 '18 at 12:59
  • Your statement is not completly right. If you use LACP(bond mode 4) yes, you will need a network asset that is IEEE 802.3ad readly, a protocol that is comonly known as "port-channel" on Dell and Cisco Switches. If you use bond mode 1, there is no need of a special protocol to negotiate link failover. Bond 1 will deal with Mac changes - wiki.centos.org/TipsAndTricks/BondingInterfaces - I'm also assuming here based on the IP addressing used by OP, that he/she has a AccessPoint that uses the same network(192.168.0.0/24) to both wired and wireless, making this setup with bond 1 possible – user34720 Mar 1 '18 at 17:44
  • Bond 1 (failover mode) will only use one network adapter, or in other words, "the best you can do is to use some kind of fallback mechanism", as I said in the comment above. It's not the same as "having routing to the internet with multiple interfaces". – dirkt Mar 1 '18 at 17:55
  • I gave one OPTION to one who is asking that will not require changing ip address to wireless neither messing with ip rules, ip route tables an iptables, the same way it seems that he/she is using an home router and not an equipment that is prepared for dealing with LACP... – user34720 Mar 1 '18 at 17:59
  • Sometimes if you keep the default route empty, there's nothing allowing a packet to reach the correct iptables entry that will alter this default route. It's still best to have a default route (even a never working route), even if it will be overriden with some rules, just to have those rule be actually working – A.B Mar 4 '18 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.