Search:  
Gentoo Wiki

Dual_internet_connections

Contents

Introduction

Sometimes you may have access to multiple internet connections on a single machine. It is very handy to be able to use both internet connections for various reasons:

Packages

As far as I can tell the only package you need for this is sys-apps/iproute2. To install it, simply emerge iproute2

Kernel Options

You do need to set the following kernel options to make use of dual connections. These options are for the 2.6.x kernel.

Linux Kernel Configuration: Routing options (2.6.x kernel)
Networking  --->
  Networking support  --->
    Networking options  --->
      TCP/IP networking
        [*] IP: advanced router
        [*] IP: policy routing
        [*] IP: equal cost multipath

or, if you prefer doing things manually:

CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y

Configuration

FIXME: This configuration makes use of a new init script seperate from the Gentoo networking scripts. It would be welcome if anyone would modify this to use the standard Gentoo networking init scripts.

Step 1: Check interface configuration

First of all, you need to make sure that each Internet connection you wish to use actually works. This can be achieved through the Gentoo standard network scripts by following the Gentoo guide for configuring your network on each interface. Another option is to use the ifconfig utility to create each interface:

/sbin/ifconfig ethX xxx.xxx.xxx.xxx netmask xxx.xxx.xxx.xxx

Step 2: Create the initscript

Use your favorite text editor (e.g. nano -w) to open and create /etc/init.d/dualnet

Initial empty script

First let's create an empty initscript:

File: /etc/init.d/multinet
#!/sbin/runscript

start() {
  ebegin "Configuring multinet"

  # Interface 1

  # Interface 2

  # Other interfaces...

  # Final Routing instructions

}

restart() {
  svc_stop
  svc_start
}

Device sections

Basic device section

Now we need to flesh it out. Each interface will have its own section that will follow this template:

/sbin/ip route add NETMASK dev DEVICE src IPADDRESS table #
/sbin/ip route add default via GATEWAY table #
/sbin/ip rule add from IPADDRESS table #

Variables:

DEVICE
the device used for this connection, e.g. eth0
IPADDRESS
the IP address used by this interface, e.g. 192.168.0.2
#
the table number to use. Each interface will have its own table, so for eth0 you might use 1
GATEWAY
the IP address of the gateway this interface uses, e.g. 192.168.0.1
NETMASK
the mask of the network that the interface is connected to, e.g. 192.168.0.0/24


So, what does this all do?

  1. Initial configuration for the table
  2. Specify the gateway this table should use
  3. Make sure this interface is used to respond to any connection made to it, this ensures that if someone connects to that interface, the response will go out using the same interface. We do not want a connection to come in on eth0 and have the response sent out on eth1.

You will need one section per interface.

Calculating netmask

An IP address can be represented as a 32-bit (4-byte) value, and a netmask specifies how many bits are used to identify the network, and how many are used to identify the specific machine. For instance a netmask of 255.255.255.0 has the first 3 bytes of an IP address used for the network, and the last byte for the machine. For netmasks that have only 255's and 0's as their sections it is easy to calculate the bit value at the end (/xx). Each section is 8 bits, and /xx is the total number of bits used for the network portion, so simply multiply the number of 255s by 8:

255.0.0.0        255's: 1   1 * 8 = 8   /8
255.255.0.0      255's: 2   2 * 8 = 16  /16
255.255.255.0    255's: 3   3 * 8 = 24  /24 (Fairly common)
255.255.255.255  255's: 4   4 * 8 = 32  /32 (This will never happen, as it specifies just one IP address in the subnet, and at least 4 IP addresses are needed in a standard network setup)

For more complex subnet masks, you have two choices. The first solution is to run ip route as root, which will show you the proper CIDR masks for all interfaces that are up and running.

# ip route
192.168.0.0/24 dev eth1  proto kernel  scope link  src 192.168.0.2 
127.0.0.0/8 via 127.0.0.1 dev lo  scope link

The other way to do it is with a little bit of binary conversion and a shortcut. Because of the way CIDR works, at least three of the four numbers will be 0 or 255, and the 255s will always be grouped on the left and 0s on the right. For example:

255.255.248.0 --- binary ---> 1111 1111.1111 1111.1111 1000.0000 0000

This has 2 × 8 1's from the first two bytes, then 5 from the second, giving a total of 21 bits, so if this were applied to the network 192.168.0.0, then you would have 192.168.0.0/21 (meaning that valid addresses are from 192.168.0.0 - 192.168.7.255).

Note: This is called Classless Inter-Domain Routing (CIDR pronounced 'cider') notation and allows subnets which do not start and end on byte boundaries.

Example: two interfaces
# Interface 1:
/sbin/ip route add 192.168.0.0/24 dev eth0 src 192.168.0.2 table 1
/sbin/ip route add default via 192.168.0.1 table 1
/sbin/ip rule add from 192.168.0.2 table 1

# Interface 2:
/sbin/ip route add 192.168.1.0/24 dev eth1 src 192.168.1.2 table 2
/sbin/ip route add default via 192.168.1.1 table 2
/sbin/ip rule add from 192.168.1.2 table 2

Final Routing Instructions

Single Outbound Route

Normally a system will have a single default gateway. This gateway is used for any connection where no pre-defined routing path can be found. If you simply want each interface to respond to its own connections, but only have one connection used for outbound traffic then you simply need to specify the default gateway:

# route add default gw GATEWAY DEVICE

If, however, you want to utilise the bandwidth of more than one connection then you must specify the route differently.

Load Balancing

Before you start load balancing, you will want to know what your current default gateways are. If you don't know what these are, then they are probably automatically set up for you. Gateways appear in your routing table with a "G" flag, as shown below:

# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.0.0     *               255.255.255.0   U     0      0        0 eth1
loopback        Abydos.open-exo 255.0.0.0       UG    0      0        0 lo
default         xxx.xxx.xxx.xxx   0.0.0.0       UG    0      0        0 eth0
default         xxx.xxx.xxx.xxx   0.0.0.0       UG    0      0        0 eth1

The columns in the routing table above are, in order, target address type, gateway address (or * if none required), network mask (described above), flags, some advanced information, and then the interface to which the line refers.

First you want to make sure there are no existing default gateway routes. This means that you have to edit your startup scripts and make sure you never specify a gateway for the interfaces you have configured. This information can be found in /etc/conf.d/net and will usually be a line similar to:

File: /etc/conf.d/net
routes_eth0=( "default via xxx.xxx.xxx.xxx" )

and it may or may not have "dev eth0" at the end. This line should be commented for all interfaces that you wish to use in this way.

Alternatively (although it's not recommended) you can manually remove existing gateway routes. To manually remove default gateways, you need to find them first, as described above.

To remove a gateway:

# route del default DEVICE

Make sure they are all removed.

Warning: This will not be permanent, and this is one of the reasons this method is not recommended. If your default gateway is specified in your startup scripts it will be restored on reboot. If you do not know how to remove the default gateway from your startup script you can force the issue, as demonstrated above, but it is a dirty workaround.

If you still wish to do this, edit your multinet init script that we wrote above, and above each interface section insert this line:

/sbin/route del default DEVICE &> /dev/null

This will do the job, but it is not recommended. If the default route exists it will be deleted, but if not the command will generate an error.

Now we have removed our gateways, we must specify our default route.

/sbin/ip route add default scope global\
           nexthop via GATEWAY1 dev DEVICE1 weight W1\
           nexthop via GATEWAY2 dev DEVICE2 weight W2

Variables:

All previously defined terms are still used, with the same meanings.
W
Weight, numerical value 1 or greater. A higher weight will result in that connection being used more often. If both of your connections are the same speed, use 1 for each. If one connection is twice as fast as the other use 2 for its weight, and it will be used more often.

Each device will have its own line:

nexthop via GATEWAY dev DEVICE weight W

Each line except the last should have the "\" escape character to tell the script that the next line is still part of the same command.

Warning: Make sure you use the correct device/gateway pairings.

The last piece of information the system needs is the nameserver to use when resolving hostnames to IP addresses. The nameserver address is stored in /etc/resolv.conf and should have an entry like this:

File: /etc/resolv.conf
nameserver 192.168.0.1

To specify the nameserver simply run the following:

# echo "nameserver GATEWAY" >> /etc/resolv.conf
FIXME: I know there is a way to stop this, but I can't remember it offhand. One way is to edit /etc/conf.d/net and add/edit the dhcpcd_iface lines to include the -R option, which stops dhcpcd replacing /etc/resolv.conf. phyreskull 22:25, 25 March 2007 (UTC)


If you do not have anything that creates this line in the file that is all you need. However if you already have the nameserver line in there for some reason on reboot, I recommend you find out why and prevent it from happening. An alternative way to do this is to execute the following command before the echo given above:

# sed -i -e '/^nameserver/d'

This will remove all "nameserver" lines from /etc/resolv.conf while preserving the other important lines.

Warning: You must have at least one nameserver specified in order to resolve internet addresses.


Most gateways will run a DNS server of some kind, so you can probably use the IP address of any of your Internet gateways, but it is best to check. Optionally you can specify all of them:

# echo "nameserver GATEWAY1" >> /etc/resolv.conf
# echo "nameserver GATEWAY2" >> /etc/resolv.conf
# echo "nameserver GATEWAY3" >> /etc/resolv.conf

Example of final script

Here is a script as an example. It uses both DSL and cable modem connections. Note that IP addresses have been stripped for security.

FIXME: I'll come up with a more general script with better integration to the Gentoo net scripts and more progress information when I have some time later. phyreskull 22:53, 25 March 2007 (UTC)
File: /etc/init.d/multinet
#!/sbin/runscript

start() {
  ebegin "Configuring multinet"

  # I do not use the Gentoo net scripts, so I start the interface here
  /sbin/ifconfig eth0 aaa.aaa.aaa.aaa netmask 255.255.255.248
  /sbin/ip route add aaa.aaa.aaa.aaa/29 dev eth0 src aaa.aaa.aaa.aaa table 1
  /sbin/ip route add default via bbb.bbb.bbb.bbb table 1
  /sbin/ip rule add from aaa.aaa.aaa.aaa table 1

  # I do not use the Gentoo net scripts, so I start the interface here
  /sbin/ifconfig eth1 192.168.0.2 netmask 255.255.255.0
  /sbin/ip route add 192.168.0.0/24 dev eth1 src 192.168.0.2 table 2
  /sbin/ip route add default via 192.168.0.1 table 2
  /sbin/ip rule add from 192.168.0.2 table 2

  /sbin/ip route add default scope global\
                       nexthop via bbb.bbb.bbb.bbb dev eth0 weight 1\
                       nexthop via 192.168.0.1     dev eth1 weight 3
                       # cable modem is 3 times faster than my dsl

  ##################################
  # This method is not recommended #
  ##################################
  # Wipe out the file and give it the first nameserver
  echo "nameserver 192.168.0.1" > /etc/resolv.conf
  # Add the second nameserver afterwards
  echo "nameserver bbb.bbb.bbb.bbb" >> /etc/resolv.conf

  eend $?
}

restart() {
  svc_stop
  svc_start
}

Note on DHCP and dynamic IPs

The Note

FIXME: TODO: work out how this should all fit together with dynamic IPs. phyreskull 11:31, 29 March 2007 (UTC)

If any of your connections are dynamically assigned via DHCP, you have a problem. Basically everything laid out above is for static IP addresses. One solution is to have your dynamically assigned interfaces initialise before the script, then grab the info from the system and use it in the script. The original author did not have this issue and has not worked out all the fine details of doing this. Basically you need to follow these steps though:

  1. Establish the dynamic connections
  2. Grab the information (IP, Network, and gateway)
  3. Remove the default route created by the connection
  4. Run the script using the information that has been grabbed

Helpful script

FIXME: Note to self: Carry on from here. phyreskull 11:31, 29 March 2007 (UTC)

I am a nice guy, while I have not gone through and written the script for dynamic addresses I have created a utility to help anyone that wants to try.

The perl script below allows you to grab the IP and gateway of an established interface.

#!/usr/bin/perl

use strict;

my $IP;
my $GW;
my $IF = $ARGV[0];
my $Data;

exit(1) if ((!($ARGV[0])) || (!($ARGV[1])));

if ($ARGV[1] eq 'ip')
{
        $Data = `/sbin/ifconfig $IF`;
        $Data =~ m/inet addr:[0-9\.]+/i;
        my $IP = $&;
        $IP =~ s/inet addr://ig;
        print("$IP");
} elsif ($ARGV[1] eq 'gw')
{
        $Data = `/sbin/route`;
        $Data =~ m/default.*$IF/ig;
        $GW = $&;
        $GW =~ s/default\s*//ig;
        $GW =~ s/\s+.*//ig;
        print("$GW");
}

Simply save the script to a file such as info.pl, and give it the proper permissions using chmod.

[Camel] The above script returns the FQDN of my gateway; this is a simple fix:

   $Data = `/sbin/ip route | grep $IF`;
   $Data =~ m/default.*via.*/ig;
   $GW = $&;
   $GW =~ s/default via\s*//ig;
   $GW =~ s/\s+.*//ig;
   print("$GW");

Syntax:

./Script.pl <DEVICE> <Info to get>

Example: Getting IP of eth0

./Script.pl eth0 ip

Example: Getting Gateway of eth0

./Script.pl eth0 GW

To use this in a script:

$IP = `/path/to/script.pl eth0 ip`

the ip address of eth0 will now be inside the $IP variable, you can then use that wherever you need it. The script does not return a newline, so the variable should be uncluttered.

Hope that helps.

Sources/Links

[1] - 4.2 Routing for multiple uplinks/providers section of Linux Advanced Routing & Traffic Control HOWTO

Retrieved from "http://www.gentoo-wiki.info/Dual_internet_connections"

Last modified: Fri, 10 Oct 2008 07:03:00 +0000 Hits: 14,657