May the source be with you, but remember the KISS principle ;-)
Contents Bulletin Scripting in shell and Perl Network troubleshooting History Humor

Linux Policy Routing

News Routing Recommended Links Linux route command ip command martian source  
Suse static routes table Linux ifconfig netstat Static Routing Default Route RIP Daemon Making routing entries permanent
Suse network configuration Redhat Network Configuration   Horror Stories Unix History Humor Etc

Policy routing is similar to firewall: it allows to make routing decision not only based on target address (like traditional routing) but on any other component of the packet. Generally any combination of the packet header fields can be used to define a route.  There is a new Linux command called simply ip which allows to configure it. 

The most valuable is the ability to select route base of combination of source and target addresses elevates the source IP address to the same level as the destination. This allows to use multiple default routers (for example to two different ISPs see ) and helps to fight spoofing: when a router is paying attention to the source address and it is looking for a specific set of source addresses, using a faked source address (spoofing) is limited

Some Linux distributions like Suse 11 block packets as "martian packets" packets from special networks like 10.x.x.x network directed to the second interface which serves different subnet. Policy routing implemented in kernel but you need to check if it is enabled in your particular distribution.  Here is how to check kernel compatibility with policy routing feature (from Novell support document 7009083: Configure multiple default routes on linux):

1. Ensure the server is ready for the process:

A. Make sure the appropriate packages are installed (a quick zypper se will confirm this):

i. kernel-source

ii. gcc

iii. ncurses-devel iv.


B. Check for kernel compatiblity:

i. cd /usr/src/linux

ii. make menuconfig

iii. Follow: Networking -> Networking Options -> And make sure the following are selected:

TCP/IP Networking

IP: advanced router

IP: Policy Routing  

IP: use netfilter MARK value as routing key (SLES 10 only)

IP: Choose IP: FIB lookup algorithm (FIB_HASH)  (SLES 10 only)

2. Create a new policy routing table for each interface:

echo "1 corporate">> /etc/iproute2/rt_tables
3. Provide IP info / gateway to the new corporate table.
ip route add dev eth0 src table corporate
ip route add default via dev eth0 table corporate

4. Create IP rules to handle inbound / outbound traffic on this network.

ip rule add from table corporate
ip rule add to table corporate 

To check if policy routing is enabled you can view /etc/iproute2/rt_tables. For example

vi /etc/iproute2/rt_tables

A simple introduction (with a nice easy example) to source based routing

On standard Internet systems, when you receive a packet and decide where to route it to, that decision is made only based on the destination of the packet.

For example:

 crb@firewall:~$ /sbin/route -n
 Kernel IP routing table
 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface UH    0      0        0 ppp0   U     0      0        0 eth1   U     0      0        0 eth0         UG    0      0        0 ppp0

In this, a simple routing table for a firewall, all traffic for is routed out eth1; traffic for is routed out eth0; and everything else is routed out ppp0 to the Internet.

However, let's deal with the situation where we have two interfaces ppp0 and ppp1 (a dual-homed situation, with two internet providers.) We will call the IP address on ppp0 $P0 and on ppp1, $P1.

You end up with a routing table that looks like this:

 crb@firewall:~$ /sbin/route -n
 Kernel IP routing table
 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface UH    0      0        0 ppp1 UH    0      0        0 ppp0   U     0      0        0 eth1   U     0      0        0 eth0         UG    0      0        0 ppp0

If you get traffic for your machine come into ppp1 from $OUTSIDE, the machine will receive the packets, generate a reply, and the system will now have a packet from $P1, destined to $OUTSIDE. Because the system only looks at destination IP addresses, the packet will get routed out the default gateway, ppp0. Even if you disable ReversePathFiltering to allow this kind of traffic on all your interfaces, chances are high your ISP will be using it. (For example, TelstraClear does not allow any traffic on it's network that originates from another network's IP.)

So, this is where source based routing comes in. We need to take any traffic that originates from $P1 (replies to traffic that came in ppp1), and route it back out through ppp1.

To do this we need to have the iproute2 package, which provides the command /sbin/ip; giving you much finer grained control over routing. If you don't have the /sbin/ip command, install an iproute package (debian: apt-get install iproute). The command route cannot handle multiple routing tables.

You also need to have a couple of kernel options enabled: they are CONFIG_IP_ADVANCED_ROUTER (Networking/IP: Advanced Router) and CONFIG_IP_MULTIPLE_TABLES (Networking/IP: policy routing).

Then, what you do is you create another routing table by editing /etc/iproute2/rt_tables; in my example I wish to create routes for a jetstream connection, so I have called the table 'jetstream' <footnote 1> by adding the line

 100     jetstream

Now, you can create a rule that dictates what routing table to look at.

 ip rule add __from $P1__ table jetstream

Look at the rules with ip rule list to get an idea of what happens when a packet is to be routed. The important bit is the from $P1. If you forget it, depending at the priority of your table, you could send all traffic to that table by default. Now, when routing, a packet that comes from the IP address $P1 will be passed to the routing table 'jetstream' instead of the main routing table.

Populate this table with a new default route, and simple routes for the rest of your local interfaces:

 ip route add dev eth0 table jetstream
 ip route add dev eth1 table jetstream
 ip route add dev lo table jetstream
 ip route add default via table jetstream

And you're done. In my case, I'm doing this on a ppp interface, so I only need the routes to exist when the interface is up; I've therefore added scripts for this to /etc/ppp/ip-up.d/ (ip-down.d contains ip rule del; I leave the table there - it's no harm if it's not called, but you could remove it with ip route del).

Thanks to PerryLorier for explaining this all to me, and to the

Linux Advanced Routing and Traffic Control HOWTO for filling in the detail; specifically Routing for multiple uplinks/providers.


Where are the route by source address, route by packet header data, and the other selection mechanisms?

This is where the rule element comes into play. Think of the rule as a method for implementing ACLs (Access Control Lists) for routes. The rule allows you to specify the filters that match packets, and which route structure to select when the filter does match. Because the filter is part of the rule selection mechanism, you can also use rules to specify other advanced options such as destination targets and NAT functions.

Using a rule you can perform the most common Policy Routing function, route by source address. The rule can specify to select a packet based on whether or not the source address of the packet falls into a designated address scope. If it does match, the rule states which route structure to use or other destination to choose. But if you stop to think about this for a moment, you realize that on a system where you only have one routing table a rule set is usable only under limited conditions. Multiple Routing Tables

In a single routing table system, such as current network router devices, or most operating systems, all of the routes specified are in a single group called a table. This table is then read through (in network speak the route is "looked up") sequentially and the longest match of the packet destination is made. This longest match then returns the gateway to which to forward the packet.

Suppose you have three routers to the same network. Each router has a different speed connection to your network core. Which one should you use in your routing table? Even under OSPF this type of routing structure still results in a single "best" route for the condition of use.

Consider this conundrum in a different light. Most of your network clients only need limited access to a particular network. They would be fine on a slow link. A select group of your network clients needs a higher rate access to this network. If you have only one routing table, you can only put in one route to this destination network. Which one do you use? In this case even if you use rules to select the traffic, where are you going to end up sending them? To the routing table.

Thus the implementation of the rule in Policy Routing implies that for true global structure you must also implement multiple routing tables. A complete Policy Routing structure is found in the Linux kernel, version 2.1 and higher. It provides full use of Address, Multiple Independent Route Tables, and a Rule selection mechanism that can interact bidirectionally with the route tables.

3.2 RPDB - The Linux Policy Routing Implementation

Under Linux, the implementation of Policy Routing structure is carried out through the mechanism of the Routing Policy DataBase (RPDB). The RPDB is the cohesive set of routes, route tables, and rules. Since addressing is a direct function of these elements, it also is part of the system. What the RPDB primarily does is provide the internal structure and mechanism for implementing the rule element of Policy Routing. It also provides the multiple routing tables available under Linux.

Linux's RPDB and the complete rewrite of the IP addressing and routing structures in kernel 2.1 and higher sustains 255 routing tables and 2^32 rules. That is one rule per IP address under IPv4. In other words, you can specify a rule to govern every single address available in the entire IPv4 a ddress space. That works out to over 4 billion rules.

The RPDB itself operates upon the rule and route elements of the triad. In the operation of RPDB, the first element considered is the operation of the rule. The rule, as you saw, may be considered as the filter or selection agent for applying Policy Routing.

The following text about the RPDB and the definition of Policy Routing is adapted from Alexey Kuznetsov's documentation for the IPROUTE2 utility suite, with Alexey's permission. I have rewritten parts of the text to clarify some points. Any errors or omissions should be directed to me.

Classic routing algorithms used on the Internet make routing decisions based only on the destination address of packets and, in theory but not in practice, on the TOS field. In some circumstances you may want to route packets differently, depending not only on the destination addresses but also on other packet fields such as source address, IP protocol, transport protocol ports, or even packet payload. This task is called Policy Routing.

To solve this task, the conventional destination-based routing table, ordered according to the longest match rule, is replaced with the RPDB, which selects the appropriate route through execution of rules. These rules may have many keys of different natures, and therefore they have no natural order except that which is imposed by the network administrator. In Linux the RPDB is a linear list of rules ordered by a numeric priority value. The RPDB explicitly allows matching packet source address, packet destination address, TOS, incoming interface (which is packet meta data, rather than a packet field), and using fwmark values for matching IP protocols and transport ports. Fwmark is the packet filtering tag that you will use in Chapter 6 and is explained later on in this Chapter in the section "System Packet Paths -IPChains/NetFilter."

Each routing policy rule consists of a selector and an action predicate. The RPDB is scanned in the order of increasing priority, with the selector of each rule applied to the source address, destination address, incoming interface, TOS, and fwmark. If the selector matches the packet, the action is performed. The action predicate may return success, in which case the rule output provides either a route or a failure indication, and RPDB lookup is then terminated. Otherwise, the RPDB program continues on to the next rule.

What is the action semantically? The natural action is to select the nexthop and the output device. This is the way a packet path route is selected by Cisco IOS; let us call it "match & set." In Linux the approach is more flexible because the action includes lookups in destination-based routing tables and selecting a route from these tables according to the classic longest match algorithm. The "match & set" approach then becomes the simplest case of Linux route selection, realized when the second level routing table contains a single default route. Remember that Linux supports multiple routing tables managed with the ip route command.

At startup, the kernel configures a default RPDB consisting of three rules:

Priority 0: Selector = match anything  Action = lookup routing local table (ID 255)
The local table is the special routing table containing high priority control routes for local and broadcast addresses. Rule 0 is special; it cannot be deleted or overridden.

Priority 32766: Selector = match anything  Action = lookup routing main table (ID 254)
The main table is the normal routing table containing all non-policy routes. This rule may be deleted or overridden with other rules.

Priority 32767: Selector = match anything  Action = lookup routing table default (ID 253)
The table default is empty and reserved for post-processing if previous default rules did not select the packet. This rule also may be deleted.

Do not mix routing tables and rules. Rules point to routing tables, several rules may refer to one routing table, and some routing tables may have no rules pointing to them. If you delete all the rules referring to a table, then the table is not used but still exists. A routing table will disappear only after all the routes contained within it are deleted. Remember that a route is the location of the address while the rule is the location of the route.

Each RPDB entry has additional attributes attached. Each rule has a pointer to some routing table. NAT and masquerading rules have the attribute to select a new IP address to translate/masquerade. Additionally, rules have some of the optional attributes that routes have, such as realms. These values do not override those contained in routing tables; they are used only if the route did not select any of those attributes.

The RPDB may contain rules of the following types:

unicast The rule prescribes returning the route found in the routing table referenced by the rule.
blackhole The rule prescribes dropping a packet silently.
unreachable The rule prescribes generating the error Network is unreachable.
prohibit The rule prescribes generating the error Communication is administratively prohibited.
nat The rule prescribes translating the source address of the IP packet to some other value.

You will see how these rule actions operate primarily in Chapter 5 and Chapter 6. There you will make hands-on use of the command set and implement several Policy Routing structures.

The RPDB was the first implementation of and first mention within the Linux community of the concept of Policy Routing. When you consider that the ip utility was first released in late spring of 1997, and that Alexey's documentation was released in April of 1999 coinciding with the official Linux 2.2 kernel release in May of 1999, then you realize that the Linux Policy Routing structure is already over five years old. In Internet time that is considered almost ancient. But as with most new network subjects, such as IPv6 and Policy Routing, Linux leads the way.

The RPDB itself was an integral part of the rewrite of the networking stack in Linux kernel 2.2. The Policy Routing extensions are accessed through a defined set of additional control structures within the Linux kernel. These extensions are the NETLINK and RT_NETLINK objects and related constructs. If you are curious about the programmatic details you can look through the source to the ip utility itself. The call structure and reference to the kernel internals is laid out quite well.

One of the important features that makes the RPDB implementation so special is that it is completely backward-compatible with the standard network utilities. You do not need to use the ip utility to perform standard networking tasks on your system. You can use ifconfig and route and get along quite fine. In fact, you can even compile the kernel without the NETLINK family objects and still use standard networking tools. It is only when you need to use the full features of the RPDB that you need to use the appropriate utility.

This backward compatibility is due to the RPDB being a complete replacement of the Linux networking structure, especially as it relates to routing. The addressing modalities for Policy Routing, as discussed in the "Address" section earlier in this chapter (and illustrated in depth in Chapter 5), were also implemented as part of this change. But the main changes, besides the addition of the rule element, were the changes to the route element. Drawing upon Alexey's documentation again I provide the following information on the route element construct.

In the RPDB, each route entry has a key consisting of the protocol prefix, which is the pairing of the network address and network mask length, and optionally the TOS value. An IP packet matches the route if the highest bits of the packet's destination address are equal to the route prefix, at least up to the prefix length, and if the TOS of the route is zero or equal to the TOS of the packet.

If several routes match the packet, the following pruning rules are used to select the best one:

  1. The longest matching prefix is selected; all shorter ones are dropped.
  2. If the TOS of some route with the longest prefix is equal to the TOS of the packet, routes with different TOS are dropped.
  3. If no exact TOS match is found and routes with TOS=0 exist, the rest of the routes are pruned. Otherwise the route lookup fails.
  4. If several routes remain after steps 1-3 have been tried, then routes with the best preference value are selected.
  5. If several routes still exist, then the first of them is selected.

Note the ambiguity of action 5. Unfortunately, Linux historically allowed such a bizarre situation. The sense of the word "the first" depends on the literal order in which the routes were added to the routing table, and it is practically impossible to maintain a bundle of such routes in any such order.

For simplicity we will limit ourselves to the case wherein such a situation is impossible, and routes are uniquely identified by the triplet of prefix, TOS, and preference. Using the ip command for route creation and manipulation makes it impossible to create non-unique routes.

One useful exception to this rule is the default route on non-forwarding hosts. It is "officially" allowed to have several fallback routes in cases when several routers are present on directly connected networks. In this case, Linux performs "dead gateway detection" as controlled by Neighbor Unreachability Detection (nud) and references from the transport protocols to select the working router. Thus the ordering of the routes is not essential. However, in this specific case it is not recommended that you manually fiddle with default routes but instead use the Router Discovery protocol. Actually, Linux IPv6 does not even allow user-level applications access to default routes.

Of course, the preceding route selection steps are not performed in exactly this sequence. The routing table in the kernel is kept in a data structure that allows the final result to be achieved with minimal cost. Without depending on any particular routing algorithm implemented in the kernel, we can summarize the sequence as this: Route is identified by the triplet {prefix,tos,preference} key, which uniquely locates the route in the routing table.

Each route key refers to a routing information record. The routing information record contains the data required to deliver IP packets, such as output device and next hop router, and additional optional attributes, such as path MTU (Maximum Transmission Unit) or the preferred source address for communicating to that destination.

It is important that the set of required and optional attributes depends on the route type. The most important route type is a unicast route, which describes real paths to other hosts. As a general rule, common routing tables contain only unicast routes. However, other route types with different semantics do exist. The full list of types understood by the Linux kernel is as follows:

unicast The route entry describes real paths to the destinations covered by the route prefix.
unreachable  These destinations are unreachable; packets are discarded and the ICMP message host unreachable (ICMP Type 3 Code 1) is generated. The local senders get error EHOSTUNREACH.
blackhole These destinations are unreachable; packets are silently discarded. The local senders get error EINVAL.
prohibit These destinations are unreachable; packets are discarded and the ICMP message communication administratively prohibited (ICMP Type 3 Code 13) is generated. The local senders get error EACCES.
local The destinations are assigned to this host, the packets are looped back and delivered locally.
broadcast The destinations are broadcast addresses, the packets are sent as link broadcasts.
throw Special control route used together with policy rules. If a throw route is selected, then lookup in this particular table is terminated, pretending that no route was found. Without any Policy Routing, it is equivalent to the absence of the route in the routing table, the packets are dropped, and ICMP message net unreachable (ICMP Type 3 Code 0) is generated. The local senders get error ENETUNREACH.
nat Special NAT route. Destinations covered by the prefix are considered as dummy (or external) addresses, which require translation to real (or internal) ones before forwarding. The addresses to translate to are selected with the attribute via.
anycast not implemented The destinations are anycast addresses assigned to this host. They are mainly equivalent to local addresses, with the difference that such addresses are invalid to be used as the source address of any packet.
multicast Special type, used for multicast routing. It is not present in normal routing tables.

Linux can place routes within multiple routing tables identified by a number in the range from 1 to 255 or by a name taken from the file /etc/iproute2/rt_tables. By default all normal routes are inserted to the table main (ID 254), and the kernel uses only this table when calculating routes.

Actually, another routing table always exists that is invisible but even more important. It is the local table (ID 255). This table consists of routes for local and broadcast addresses. The kernel maintains this table automatically, and administrators should not ever modify it and do not even need to look at it in normal operation.

In Policy Routing, the routing table identifier becomes effectively one more parameter added to the key triplet {prefix,tos,preference}. Thus, under Policy Routing the route is obtained by {tableid,key triplet}, identifying the route uniquely. So you can have several identical routes in different tables that will not conflict, as was mentioned earlier in the description of action 5 and "the first" mechanism associated with action 5.

These changes to the route element provide one of the core strengths of the RPDB, multiple independent route tables. As you will see in Chapter 5, the rule element alone can only perform a selection or filter operation. It is still up to the route to indicate where the packet needs to go next. Adding on top of these elements the QoS mechanisms to determine and set the TOS field and the ability to route by the TOS field provides you with the most powerful and flexible routing structure available under IPv4 and IPv6.

In summary, the RPDB is the core facility for implementing Policy Routing under Linux. The RPDB streamlines the mechanism of dealing with rules and multiple route tables. All operations of the rule and route structure are centralized into a single point of access and control. The addition of various alternate actions and destinations for routes and rules through the RPDB allows you to fine tune the mechanism of Policy Routing without needing to hack sections of the networking code.

3.3 System Packet Paths - IPChains/NetFilter

Understanding the RPDB brings up the question of at what point within the system the RPDB operates. To understand this within the context of the system you need to first see the logic of packet traversal within the system. The best way to approach this traversal is to consider how the packet filtering mechanisms treat this flow.

The various packet filtering mechanisms within the Linux kernel structures deal directly with the conceptualization of the packet flow as a means to identify the control points. They do this so that they may apply their security mechanisms at the control points. These control points are also of interest to the Policy Routing structure because these are the same control points that you would think to operate upon with Policy Routing structures.

... ... ...

3.3.2 NetFilter - Kernel 2.3/2.4

This contention of packet path location brings up the latest iteration of packet filtering in Linux. NetFilter is the extension of the traditional IPChains to cover state tracking functions. The new concept is to consider pure packet selection mechanisms as defining packet filtering in contrast to defining any packet selection mechanisms that change the packet information as packet mangling. This makes sense from many standpoints. It even casts a good light on the traditional split of consideration between routing and TOS/QoS structures as you will see in Chapter 6.

What NetFilter does is make this division of function obvious. Consider the packet paths in Figure 3.3.2.

Note that the dotted line tying together the two routing diamonds indicates that these are the same function, the RPDB. The reason for the split is that the routing function is entered in different places in the packet path.

This is due to another change in the packet path policy within NetFilter. The Input(2) and Output(4) chains now only refer to the Local Machine. When you consider that the primary function of a firewall is to protect machines behind it, and that implies transverse packets, then the packet path for NetFilter is much cleaner. Additionally, by placing the INPUT and OUTPUT chains as operating only upon the Local Machine you can create secured server machines.

Consider the path for a transverse packet. It enters the system and is processed by the entrance packet mangling and tagging stage, Pre-Route(1). This stage is where you would apply packet mangling operations such as fwmark and TOS/QoS tagging. The packet then enters the RPDB to obtain routing. From the RPDB it enters the primary firewall chain, Forward(3). The Forward chain is where the firewalling decisions are made. After the Forward chain it enters the exit packet mangling and tagging stage, Post-Route(5). The Pre-Route and Post-Route locations are where you would also apply NAT and IP MASQUERADING functions. Note that these NAT functions are not the same as the RPDB NAT. Indeed you will see the differences between RPDB NAT and NetFilter NAT in Chapter 8.

This transverse packet path, assuming you do not do any packet mangling, only then needs to be inspected by two entities, the RPDB and the Forward firewall chain. This is a great improvement in speed and logic when you start considering the interactions of Policy Routing and firewalling. For the purposes of a secured service machine, things are also more logically handled.

Consider the path for an externally sourced packet destined for an internal service. It enters the system and is processed by the entrance packet mangling and tagging stage, Pre-Route(1). This stage is where you would apply packet mangling operations such as fwmark and TOS/QoS tagging or perhaps the NetFilter NAT. The packet then enters the RPDB to obtain routing and is routed to the Input(2) chain. The Input chain provides the firewalling functions for packets destined to the Local Machine services.

The reverse scenario is the packet path for an internal service sourced packet destined for an external system, such as the reply packet to the one described in the previous paragraph. It exits the Local Machine and enters the Output(4) chains, which provides the firewalling functions. It then enters the RPDB for route processing and exits the system via the exit packet mangling and tagging stage, Post-Route(5).

Note that in all of these packet paths, ignoring the Mangle functions of the Pre/Post ROUTING chains, the packet never crosses through more than one packet filter chain and in all cases the packet gets processed by the RPDB. So all of the functions associated with the Policy Routing structures under the RPDB may be applied to the packet.

3.4 Summary

You have seen the fundamental triad of Policy Routing and how these elements are implemented within the Linux kernel through the RPDB. You then traced through the logic of the packet paths for the packet filters and the RPDB action locations. Now you understand the logic of the traffic flow for Policy Routing in Linux.

Chapter 4 will cover the usage and operation of the ip utility from Alexey Kuznetsov. This is the main utility implementing all of Policy Routing with the exception of TOS/QoS. Within the utility suite, however, is the tc utility, which performs all of the TOS/QoS functions of Policy Routing. After you have learned about the ip utility you will start to delve into hands-on experiences with Policy Routing by implementing a series of increasingly complex examples.

As you go through the examples and usages of the utilities try to see how the Triad operates in those situations. Remember:

Address  defines the location of a service.
Route  defines the location of the address.
Rule  defines the location of the route.
Return to Table of Contents

Top Visited
Past week
Past month


Old News ;-)

Multihomed Linux server just like my old NetWare...

I have no idea how to explain my environment... It's multi-homed it works in NetWare, breaks in Linux.

Similar to this:

What I did.
1. vi /etc/iproute2/rt_tables
added: 250 eth0
added: 251 eth1

2. vi /etc/sysconfig/network/my-routes

3. added the following lines in the my-routes file
#| /bin/bash
ip route add dev eth0 src table eth0
ip route add dev eth1 src table eth1
ip route add default via table eth0
ip route add default via table eth1
ip route add dev eth0 src
ip route add dev eth1 src
ip route add default via
ip rule add from table eth0
ip rule add from table eth1

4. chmod 740 /etc/sysconfig/network/my-routes

5. the last thing I did was add this line to my /etc/crontab file, I'm sure there is a better way but I'm tired:
@boot root /etc/sysconfig/network/my-routes

6. rebooted the box and tested...

Reply packets are sent over an unexpected interface

This document (7000318) is provided subject to the disclaimer at the end of this document.

Novell SUSE Linux Enterprise Server 10
Novell SUSE Linux Enterprise Desktop 10
Novell Open Enterprise Server 2 (OES)

Multiple network interfaces




Set up split access routing

To route response/reply packets out over the same interface that the packets that they are a response to came in on, separate routing tables (based on the incoming interface) can be set up. For a detailed explanation, refer to the "Split Access" section of the "Rules - routing policy database" chapter in the Linux Advanced Routing & Traffic Control HOWTO (LARTC).

Additional Information

Background information: how Linux routes by default

In Linux, by default, packets are considered individually for routing purposes. Thus, all the routing algorithm considers is where to send a packet based on that packet itself, without taking into consideration that the packet may be a response packet of sorts. In a typical setup, this means that all outgoing traffic is going out over one interface, eth0.

If multiple NICs in Linux are configured with addresses in the same subnet, by default communication into that subnet will always be done by the first NIC in that subnet that is started.

Example setup

To obtain the expected behaviour (as stated under "goal" above), split routing needs to be set up.

Assume a single server with two NICs, one configured for the address; the other for

First, create two routing tables, T1 and T2 to be used for packets sent to or from these NICs by adding the lines

252 T1
251 T2

to /etc/iproute2/rt_tables.

Next, set up the routing rules to route incoming and outgoing packets via these tables:

ip route add dev eth0 src table T1
ip route add default via dev eth0 src table T1
ip rule add from table T1

ip route add dev eth1 src table T2
ip route add default via dev eth1 src table T2
ip rule add from table T2

Note that these rules do not cover the routing of outgoing packets which are not response packets (e.g. outgoing ICMP ECHO ("ping") packets). These packets are still governed by the default route. In some setups, there may be a requirement to use both interfaces for such packets as well (e.g. for load balancing). Refer to the "load balancing" section of LARTC for details on how to implement such requirements.

[Apr 05, 2012] Configuring Multiple Default Routes in Linux

Nov 19, 2007 | Darien Kindlund's Blog

Assume you have a Linux system with more than one network interface card (NIC) — say eth0 and eth1. By default, administrators can define a single, default route (on eth0). However, if you receive traffic (i.e., ICMP pings) on eth1, the return traffic will go out eth0 by default.

This can be a bit of a problem — especially when the two NICs share the same parent network and you’re trying to preserve sane traffic flows. In a nutshell, this post will explain how you can ensure traffic going into eth0 goes out only on eth0, as well as enforce all traffic going into eth1 goes out only on eth1.

You’ve found the one post that actually explains this issue; your googling has paid off. You wouldn’t believe how many advanced Linux routing websites out there explain how to route everything including your kitchen sink — yet fail to clearly explain something as simple as this.

As always, we’ll explain by example. Assume the following:

First, you’ll need to make sure your Linux kernel has support for “policy routing” enabled. (As a reference, I’m using a v2.6.13-gentoo-r5 kernel.)

During the kernel compilation process, you’ll want to:

cd /usr/src/linux
make menuconfig
Select "Networking --->"
Select "Networking options --->"
[*] TCP/IP networking
[*] IP: advanced router
Choose IP: FIB lookup algorithm (FIB_HASH)
[*] IP: policy routing
[*] IP: use netfilter MARK value as routing key

Next, you’ll want to download, compile, and install the iproute2 [1] utilities. (Most Linux distributions have binary packages for this utility.) Once installed, typing ip route show should bring up your system’s routing table. Type man ip for more information about this utility, in general.

Speaking of which, assume the system’s initial route configuration looks like this:

# netstat -anr
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface U 0 0 0 eth1 U 0 0 0 eth0 UG 0 0 0 eth1

So, basically, the system is using eth1 as the default route. If anyone pings, then the response packets will properly go out eth1 to the upstream gateway of But what about pinging Sure, the incoming ICMP packets will properly arrive on eth0, but the outgoing response packets will be sent out via eth1! That’s bad.

Here’s how to fix this issue. Borrowing the method from a really sketchy website [2], you’ll first need to create a new policy routing table entry within the /etc/iproute2/rt_tables. Let’s call it table #1, named “admin” (for routing administrative traffic onto eth0).

# echo "1 admin" >> /etc/iproute2/rt_tables

Next, we’re going to set a couple of new entries within this “admin” table. Specifically, we’ll provide information about eth0‘s local /24 subnet, along with eth0‘s default gateway.

ip route add dev eth0 src table admin
ip route add default via dev eth0 table admin

At this point, you’ve created a new, isolated routing table named “admin” that really isn’t used by the OS just yet. Why? Because we still need to create a rule referencing how the OS should use this table. For starters, type ip rule show to see your current policy routing ruleset. Here’s what an empty ruleset looks like:

0: from all lookup local
32766: from all lookup main
32767: from all lookup default

Without going into all the boring details, each rule entry is evaluated in ascending order. The main gist is that your normal main routing table appears as entry 32766 in this list. (This would be the normal route table you’d see when you type netstat -anr.)

We’re now going to create two new rule entries, that will be evaluated before the main rule entry.

ip rule add from table admin
ip rule add to table admin

Typing ip rule show now shows the following policy routing rulesets:

0: from all lookup local
32764: from all to lookup admin
32765: from lookup admin
32766: from all lookup main
32767: from all lookup default

Rule 32764 specifies that for all traffic going to eth0‘s IP, make sure to use the “admin” routing table, instead of the “main” one. Likewise, rule 32765 indicates that for all traffic originating from eth0‘s IP, make sure to use the “admin” routing table as well. For all other packets, use the “main” routing table. In order to commit these changes, it’s a good idea to type ip route flush cache.

Congratulations! You’re system should now properly route traffic to these two different default gateways. For more than 2 NICs, repeat the table/rule creation process as necessary.

Please provide comments, if you find any errors or have corrections to this post. I don’t claim that this method will work for everyone; this information is designed primarily to preserve my sanity, when configuring routing on future multi-NIC Linux systems.



Update: Here are some additional resources, that I have found useful.

Update: Apparently, OpenBSD also now supports multiple default routes through a new feature called the Virtual Routing Table:

  1. RE: Failover Default Routes

    Here are some articles that describe what you’re looking for:

    OpenBSD also has a daemon called “hoststated” that provides this type of capability:

  2. Thank you very much for the links…

    gc_timeout did the trick for me as the default is 5 min which is too long for a route to fail over.

  3. RE: ARP Cache Timeout

    Try this link, for information about how to control how long entries stay in the ARP cache:

  4. i’m actually kind of curious – the most common, default situation is where eth0 is the interface that packets are routed through — heck, that’s noted in the first sentence — so i’m wondering why you constructed your example with the reverse configuration – with eth1 as the default? i found it kind of confusing, in an otherwise most excellent article….
  5. Sorry about the confusion; in my example, the Linux distribution I used in my example (Gentoo) seemed to always specify eth1 as the default route — when both eth0 and eth1 were present and active (and when automatic configurations were used).

    Let me ask you this, in your Linux distribution, when you have both an eth0 and an eth1 on the system with active links for both — does your distribution automatically select eth0 as the default route? I’m guessing it’s pretty much random, as the standard defaults are to use DHCP for both eth0 and eth1, in which case, whichever interface gets the DHCP lease (first? or last?) will ultimately decide which default route actually gets used by the system.

    I hope this explains where I was coming from.

  6. oh, okay, that makes sense. i’m always running servers with fixed IP’s, so DHCP never enters into the picture.

    for what i’m attempting, i actually found that going with bonded interfaces worked best – using a bond0 device and making both interfaces capable of “believing” that they’re the server’s IP, and the only path out. thus if one interface goes offline, traffic can still pass.

  7. I have a slightly different requirement.
    I have internet access both over WLAN and over DSL. I use the DSL for VoIP setup and WLAN for internet. But sometimes the WLAN or the DSL goes out of service. In this caseI want to use both the services – Internet and my VoIP setup over the either WLAN or DSL whichever is active.
    How could I do this?


  8. Hi Amit,

    See my earlier comment about “Failover Default Routes”:

    – Darien

  9. Each Linux distribution is slightly different. Some distributions offer a way to save these configurations within a configuration file under /etc to be used upon reboot.

    Other distributions require you to add the “echo” and “ip rule” commands into a script file that gets called as one of the last commands when the system boots up.

    For example, on Ubuntu Linux, there is a script file called “/etc/rc.local” that you can add all the “echo” and “ip rule” commands into, that will apply these configurations upon complete server bootup.

    However, please be aware that if you have other network services that require the multiple default routes to be set up BEFORE those services can successfully load (e.g., an automatic VPN/IPSec tunnel), then you’ll have to create an rc.d init script, similar to those found in the “/etc/init.d” directory.

    The short answer:
    - Try adding the commands to “/etc/rc.local”.
    - If other services fail, then make a copy of a simple script in “/etc/init.d”; then edit that script to reflect the commands needed to be run at boot time; then register that script to be started upon bootup (“man update-rc.d”, for Ubuntu/Debian Linux).

    Hope this helps,
    – Darien

  10. Hello,
    This is a good article, but when you say : “However, if you receive traffic (i.e., ICMP pings) on eth1, the return traffic will go out eth0 by default.”, car you please explain or give examples where we will or can receive traffic on eth1 if we have eth0 as a gateway.


  11. Sure,

    Lasy, when you set a single default route, then that route is relevant for *all traffic outside your local subnet*.

    Let’s say you have a public class-C subnet of and eth0 is while eth1 is and your default route is through eth0.

    Then, let’s say someone from a completely different subnet (from, for example) pings your ETH1 IP address ( The ICMP request packets will arrive on eth1; however, when your system sends out the ICMP response packets, *because the destination is outside your local subnet*, these packets will go out on eth0, since that is your default route.

    The point of the article is that if you have two or more network interfaces and have only one default *route* set on the OS, then *for all non-local-subnet traffic*, all outgoing packets will go out on the interface marked as the default route — unless you follow the steps listed in this article.

    – Darien

  12. GB

    • Hi Ghostbuster,

      Yes, IP_ROUTE_FWMARK was removed from linux v2.6.20 and later releases. See this link for details:

      Presumably, the feature still exists, but it’s probably named something else (or perhaps merged with some other feature).

      Hope this helps,
      – Darien

  13. Hi Darien,

    Thanks for that pointer.

    I’m thinking it’s the MARK command in Netfilter these days.

    I’ve done some qdisc stuff so hopefully it won’t be too alien.


  14. Okay, scrap that last comment :-)

    I’ll try this instead hoping the support is all handled by iproute2 these days:


  15. Hi Anderson,

    There is no specific file, as all the commands I’ve listed are performed from the command line. If you’re looking to run these commands every time your OS boots, then you can put them all in /etc/rc.local (for Ubuntu Linux).

    Second, ‘netstat -rn’ can’t show you “policy routes” properly. So even after you run the policy routing commands, it’s likely ‘netstat -rn’ will still show you the same thing before and after the policy routes are in place.

    If you’re looking to verify that policy routes are working properly, run the “ip rule show” before and after setting up policy routes. If you want more detailed information, see the man pages for the “ip” command, by typing “man ip”.

    – Darien

  16. Hi Anderson,
    You can define your eth1 gateway in the set of commands you enter into /etc/rc.local

    The “ip rule” commands Listed in the article will properly configure your eth1 gateway, so you won’t need to define it within /etc/sysconfig/network

    – Darien

  17. What do you change if both NICs are on the same network segment, using the same gateway IP? I tried following the steps above but I was left with all traffic going out eth0 while some went in eth1.
    • Hi nobodyfamous,
      If both NICs are on the same network segment, the policy routing isn’t going to help you. The problem has to do with Linux kernel’s TCP/IP stack employing short-circuit routing.

      Specifically, this problem is solved at a different layer than routing. What you’re looking for is “Link Aggregation” (aka. making multiple NICs in your server act as one large NIC). There is an entire page dedicated to the concept, available here:

      In order to get it to work, though, you’ll need to make sure your upstream switch/router supports the 802.3ad protocol (most recent managed switches do support it; however, if you have an unmanaged switch, probably not).

      – Darien

      • Yeah, bonding was the initial goal, but we don’t have access to the switches in this case, so it had to be solved at the host level.

        We were able to make it work following a modified form of your instructions, FWIW:

        In this example, the gateway is and the server’s IPs are and on eth0 and eth1 respectively:

        printf “1\tuplink0\n” >> /etc/iproute2/rt_tables
        printf “2\tuplink1\n” >> /etc/iproute2/rt_tables

        ip route add dev eth0 src table uplink0
        ip route add default via dev eth0 table uplink0
        ip rule add from table uplink0
        ip rule add to table uplink0

        ip route add dev eth1 src table uplink1
        ip route add default via dev eth1 table uplink1
        ip rule add from table uplink1
        ip rule add to table uplink1

        By the way, in the second paragraph you say that the solution is applicable to cases where the two NICs are on the same network, that’s why I followed your lead on this.

  18. This is extremely helpful. Thank you.

    One question about routing in general, is there a way to have subnets share a common default gateway?

    • Hi Tekknogenius,
      If we’re talking about two subnets sharing a common, physical gateway (such as a router), then yes, but that common gateway must have a valid IP address on each subnet. For example, assume you have two subnets:

      You can then configure your router to have the IPs of: and for use by members of their respective subnets.

      Bottom line is that the gateway must have an address in each subnet; otherwise, you would have to figure out some other way to reach the gateway’s IP address (e.g. static ARP entry if on the local LAN)

      – Darien

  19. Hi – i have another slightly different goal. My Linux box has an eth0 (connected via a default gw to the internet) and a on-demand ppp0 (gprs) connection. My goal is to programmatically create sockets via both interface at the same time. I think i am stuck setting up the correct routes for this – do you know how to handle this issue?
    • Hi Johnny,
      See my earlier comment as I’ve already addressed this issue:

      – Darien

      • Thanks for your quick reply. I’m not sure failover routing is the correct issue here, as both routes should be up all the time. My app decides on various criteria which connection should be used. I had read som article, whiches in short says: What goes out on one device, should comme in on that again. Is this the right idea? And how can I realize that?
        • Hi Johnny,
          Okay, thanks for the clarification. I had assumed when you mentioned ‘on-demand’, that you somehow wanted to switch from eth0 to ppp0 when eth0 failed. Instead, you want both eth0 and ppp0 alive all the time.

          In that case, just replaced ‘eth1′ with ‘ppp0′ in the example and you can still use policy routing to accomplish what you’re looking for.

          The real challenge, is if ppp0′s network configuration changes constantly. If the IP address, subnet, and route of ppp0 constantly changes, then you need to somehow have logic to detect when these changes occur and update your policy routes accordingly.

          In that case, you’ll probably want to research DHCP notification code. Depending on your Linux distribution, there are scripts which execute when your network changes, which you could use to also update your corresponding policy routes.

          – Darien

  20. Hey,

    Great article, helped me loads compared to the other sites were they just skimm abit on the top.

    Thou, having problem adapting it to my setup.

    I currently have 2 nic’s on my server that is acting as router/gateway.

    1 of the physical nic’s has 5 virtuell interfaces (g1-5), g1 goes to the router itself as it also goes as a webserver. The rest are nated straight to nic2(which has no virtuell interfaces). As i have 4 computer, g2-5 are nated 1:1 towards the inside local ip:s 10.10.1.X.

    I have a simple iptables rule to fix the NAT part, and i had it working “sortoff” since everything was working except that i could not reach the servers/pc’s from the outside, they could only talk from the inside->out (torrents etc works flawlessly thou).

    Any hints? If you got a mail or something it would be great to get some advice..

    • Hi DevizioN,

      It sounds like you have one-way NAT working and you want bi-directional NAT. From your post, it sounds like g1 goes to the router, as well as nic2 goes directly to the router … is that correct?

      Regardless, it sounds like setting up multiple default routes correctly will NOT fix your NAT problem… I would recommend you try and fix your NAT problem first, and then setup the multiple default routes.

      To be very specific, with your current NAT configuration, try configuring your server with only ONE upstream gateway and fix your NAT so that it’s working in both directions (insideout).

      Once you get a single route working, then add your second upstream gateway. If your bi-directional NAT breaks and no longer works correctly, then let me know and we can troubleshoot further (as configuring multiple default routes may help you).

      The general approach is: reduce the complexity of your configuration, verify each piece works first (e.g., NATing, virtual interfaces), and THEN verify the total configuration works. Otherwise, it can be a nightmare to troubleshoot multiple unknown pieces at the same time.

      – Darien

  21. example

    ip rules add and from are with /32 or /24?


    ip rule add from table admin
    ip rule add to table admin
    ip rule add from table admin2
    ip rule add to table admin2


    ip rule add from table admin
    ip rule add to table admin
    ip rule add from table admin2
    ip rule add to table admin2

    I don’t hunderstand why you use all 32 bits.


  22. Thanks for a great article. This looks like kinda what I need. However, my situation is a bit different (aren’t they all :) ). Anyway, I am basically, trying to setup openVPN on my Ubuntu 8.10 server. I got 2 NICs in my server. eth0 and eth1. eth0 is the external NIC while eth1 is the internal one (the LAN. eth0 is the default route. VPN connects through eth0 and I can ping my server and I can ping eth1, however I can’t ping anything behind eth1 (which is my local LAN). From the server console itself I can ping my internal LAN. I think the problem lies with traffice coming via eth0 and since the default route is eth0 it only goes through eth0. So if I ping anything which is behind eth1 it is routed via eth0 and not eth1. Is it possible to route all VPN traffic meant for eth1 through eth1 even though it’s not the default route?

    Does this make any sense or am I making you guys as confused as myself?

    Thanks for your help in advance.

    • Hi Mazzer,

      1) As a sanity check, are you able to ping your eth1 network if you TURN OFF your VPN? I just want to make sure that the problem isn’t more fundamental.

      2) On your server, once you have your VPN setup, you actually have THREE different interfaces: eth0, eth1, and (probably something like vpn0 — check your ‘ifconfig -a’ for details). Essentially, you have a third ‘virtual’ interface, representing the effective IP address of your server, once connected on the *inside* of your VPN network.

      Here’s what I need to know:
      - The IP address and netmask of your eth1 network.
      - The IP address and netmask of your *vpn0* network (see above for what I mean).

      Specifically, I believe that perhaps your eth1 network and your vpn0 network may have conflicting IP addressing, which is causing you to lose connectivity to your eth1 network once a VPN is established. However, I need more information in order to accurately say that this is the problem.

      – Darien

  23. I used the same kinda configuring (but created two tables instead of one) one per interface. This makes sure i get the response to through the right interface.

    # Assign IP address on the interfaces eth0 and eth1
    ip route add dev eth0 src
    ip route add dev eth1 src

    # IP route and default gateway for eth0 in the table 100
    ip route add dev eth0 src table 100
    ip route add default via table 100
    # IP route and default gateway for eth1 in the table 101
    ip route add dev eth1 src table 101
    ip route add default via table 101

    # Assign the rule to corresponding particular table
    ip rule add from table 100
    ip rule add from table 101
    ip route flush cache

    Now, i can ping the box to the corresponding box from behind the
    gateway. Everything works fine according to my requirement.

    Now if i use the ping utility (from the box) with a destination address not in 10.1.X.X or in 10.0.X.X network using both the interfaces (or the
    ip-address) it works
    ping -I eth0 some-address (works)
    ping -I eth1 some-address (works)
    ping some-address (not working) with “network is unreachable” as the error

    Now this force me to use the default route on the main table which i
    thought was not neccessary using below command
    ip route add default via

    Since with out any interface or ip-address explicity given, ping
    should have chosen the source ip-address as either or If so , rule should have hit in routing table 100 or table
    101. But just wondering why it is hiting the main routing table. This
    forces me to have a two gateway programming option for each interface
    and another default gateway to select among two. Not sure why..

    • Also how do we use the same concept in the DHCP enabled network. DHCP client running on both the interfaces. DHCP clients always deals with the main routing table (instead of the custom created routing table).
      • Handling DHCP leases is tough. You’ll need to use a DHCP client that supports custom extensions, so that you can call a script (which you create) that will setup the appropriate policy routes.
    • What does your ‘netstat -anr’ and ‘ip rule show’ look like?
  24. Hi Darien,

    Thank you for your quick reply. I was away from my computer for a while so couldn’t reply.

    As per your questions, I’ll answer the ones I can right now.

    1) I can ping eth1.

    2) I know what you mean about the 3rd virtual interface. Sorry for not providing more information. I do have one and it’s a tun interface (tun0). I’m using routing and not bridging.

    The IP address of eth1 is, netmask is so thats the subnet.

    The details about tun0 I’ll get for you when I go home tonight.

    I think the problem lies between the virtual Interface and eth1. From the VPN server I can ping both eth1 and eth0 and everything behind those interface. I can ping everything behind the eth1 subnet (internal network) and I can ping everyhting behind the eth0 subnet (the internet). When I’m connect via VPN to the server. I can ping both eth0 and eth1 but can’t ping anything behind eth1. Once connected via VPN, I can SSH into the VPN server (through the VPN connection) and one connected to the server console. I can ping everything behind eth1. I guess thats no surprise as I’m am then doing the pinging from the console. So as I said, I think the problem lies with the virtual interface having the default route of eth0 and so the pings arte going through eth0 even though they meant for eth1.

    Phew, I can’t believe I wrote all that down :) . Thanks for your help though.

  25. Also Just so you know, I’m using OpenVPN as my VPN server and I’ve setup the redirect gateway option as well.
  26. Got the details for the tun0 interface.

    IP Address:
    Subnet Mask:
    Default Gateway:
    DHCP Server:
    DNS Servers:

    The subnet is the internal eth1 network so looks like the VPN server is pushing the DNS server to the client correctly.

  27. Good article.
    Forgive my ignorance, but what’s the purpose of the “to” rule, ie

    ip rule add to table admin

    that would be used only from incoming packets, and even in that case it doesn’t seem very useful. But I’m sure I’m missing something obvious.

    Thank you.

    • madinc,

      The “to” rule is to tell the tcp/ip stack that for all packets where the destination is, then route those packets to the “admin” interface. This is important for STATEFUL flow processing. When Linux constructs the appropriate reply (e.g., a TCP ACK), it will know which policy route to use, when sending the reply. Otherwise, without this rule, you’ll find that your ACKs will get sent using the default route in the main table.

      • Sorry for being slow to understand, but for ACK reply packets the “to” (destination IP) will NOT be, but rahter the IP of the host the ACK is directed to.
        So if you want to use a specific rule to route those packets out, you probably want a rule that matches on *from*, rather than “to”.

        I still fail to see how that “to” rule can match anything other than incoming packets.

        Thank you!

        • Hi madinc,

          The “to” rule is primarily important when BOTH of your ethernet interfaces are on the SAME SUBNET. If both interfaces are on separate subnets with NO possibility of getting overlapping traffic, then the “to” rule is less of an issue.

          However, when both interfaces are on the same subnet, then the “to” rule tells Linux which packets to ignore or listen to if each interface is getting duplicate traffic.

            • Darien

            • Posted November 10, 2009 at 6:14 pm
            • Permalink
            Just to clarify, when I mean SAME SUBNET, I mean that both ethernet interfaces are connected to the same upstream hub/switch/router, where both ethernet interfaces receive copies of all network traffic destined to any of the interfaces.
  28. When both ethernet interfaces are on the same subnet, only the one whose IP address is the destination IP address of the incoming packet will get it.
    It’s like having many hosts in a LAN: only the destination host will reply to ARP and thus get the packet, despite all other hosts being in the same subnet.

    Forgive me, but I still don’t see where the “to” rule comes into play :)

    Thank you.

    • Hm, on second thought…with Linux’s weak host model, both interfaces will reply. So yeah, now I see where the “to” can be useful.

      Thank you and sorry for the noise.

      • No problem; glad to help. In general, when getting real answers, I’d recommend actually testing against an actual Linux system, since a lot of these nuances could change, depending on which kernel patches (from which Linux distributions) are loaded on your test machine.

        On numerous occasions, I’ve found that “what should happen” is largely different than “what really happens”.

  29. I tried using the steps that you used to configure Multiple Routes and I ran into an error when I ran the command “ip route add default vi dev eth2 table ccsadmin”. The error that I received was “error: either “to” is duplicate, or “″ is a garbage. I’m not sure what steps do I need to take to solve this problem that I’m having. I’m running CentOS 4.7 kernel version 2.6.9-78
    • Umm, I think you mis-typed the command:

      “ip route add default vi dev eth2 table ccsadmin”

      Should be:

      “ip route add default via dev eth2 table ccsadmin”

      Specifically, the “vi” should be “via”.

  30. Hmmm…

    I keep getting:

    [root@bjwww001 ~]# ip route add dev eth1 src table hkvpn
    RTNETLINK answers: Invalid argument

    All my ifcfgXX files are correct and have broadcast and network IP’s defined too….

    • Did you enable “policy routing” in the Linux kernel and install the iproute2 utilities? (Both were mentioned above in the article.)
      • iproute yes… policy routing – will have to check. This is a stock CentOS 5.4 64 bit. WIll I need to recompile the kernel or is there a kernel flag I can set in sysctl?
        • Policy routing requires a kernel recompilation, if it’s not enabled by default. There’s no way to dynamically enable/disable it via sysctl.

          Not sure about CentOS, but many Linux distributions will store a copy of the actual Linux kernel config in /proc/config.gz, so you could try inspecting that kernel config (if it exists) to see if Policy Routing has been defined. Otherwise, you’ll have to do a recompile.

  31. Worked great for ssh, but borked my apache server. I don’t know why but requests arriving on one device to the apache server will be sent out on the other one. And with the ip rule will try to go the wrong way. Maybe its an apache bug (or feature?)
  32. Since you were using Gentoo:

    How do you setup the IP address in the “admin” routing table during boot? How did your modify your “/etc/conf.d/net.eth0″-file?

    The default gateway can be added with “routes_eth0=( “default via table admin” )

    The rules can be added in the “postup” section of the /etc/conf.d/net; but I simply cannot bring Gentoo to add the IP address in the other table. It either adds it in the default table; or throws a syntax error.

    • Instead of trying to figure out the proper way to add the routing table commands to the network startup scripts, just add them to your /etc/rc.local script (or equivalent). Essentially, you want to use the same absolute commands as listed in the examples (in the article) and write them to a script that will run after *all* automatic networking scripts are ran. On most systems, commands written to /etc/rc.local are literally the last commands executed before the system finished bootup and presents a login prompt to the user.
      • That would be “/etc/conf.d/local.start” on a Gentoo system.

        While it does work, of course, there is a problem if you restart the interface with an “/etc/init.d/net.eth0 restart”, since the routing table will be empty afterwards.

        Alas, at least it works now. Thanks for pointing me in the right direction.

        • Replying to my own comment:

          Using OpenRC with baselayout2 the /etc/conf.d/net.eth0 script would look like this:

          config_eth0=” netmask broadcast″
          routes_eth0=”default via
 dev eth0 proto kernel scope link src table dmz
          default via dev eth0 table dmz”
          dns_servers_eth0=”dns.ip.1 dns.ip.2″

          Modify to your own pleasure.

  33. Thanks so much for this! I had no idea, until I watched it with tcpdump, that a packet coming in on one interface would get an (attempted) response on another.

    The fix you give worked like a charm.

    –Al Evans

  34. Wow, this worked great! Really cool. Does anybody know if something like this can be done under Windows?
  35. Hi,
    Thanks for the tutorial, it helped a lot! One thing, is there a way to make the routing tables persistent? Or will the newly configured tables still be there after a system reboot?


    • Hi mdewet,

      The policy routing settings should persist across reboots. If, for whatever reason, they do not, you can usually add these settings to /etc/rc.local (or equivalent), so that these settings are applied at the very end of system boot.

      – Darien

  36. Great article. Much appreciated!!!
  37. Hi Darien,

    First of all great post.
    I just have one question. Is it possible to do something similar but with two interfaces connected to the same network? For instance two wireless cards connected to the same access point.

    • Hi rodmar,

      Yes, the same technique can be used on 2 wireless NICs connected to the same access point — Linux treats those interfaces the same when performing policy routing.

      – Darien

  38. Thanks for the tutorial. Does this also work with configuring multiple default routes on vlan interfaces?
    • Hi,
      Yes, this technique can be applied to vlan interfaces as well, because Linux treats those interfaces exactly the same as physical interfaces — just substitute eth0/eth1 with the corresponding vlan interfaces you want to perform policy routing on.
      – Darien
  39. Bless you, O Darien, for this gem on a subject which has stumped not only me but all who I have hit up for the solution, til now!
  40. Bless you, O Darien, for this gem on a subject which has stumped not only me but many who I have hit up for the solution!
  41. Classful routing hasn’t been used since 1994. The fact that the mask is included means it is a classless network. So stop saying ‘class C’, just because the Class C default mask was It is simply a /24 subnet.
  42. Darien, Thnak you for this info..

    Do i have to remove the gateway in the interface file for this to work???

    • Hi Will,
      No, you don’t need to remove the gateway in the interface file for this to work. Essentially, you want to perform the policy route configuration *after* basic networking (including setting the default gateway) has been done. This is why I recommend setting the policy route in /etc/rc.local, so that it is the *last* thing initialized, which guarantees the settings will not conflict with another daemon upon boot up.
      – Darien
      • Can you look at this and see what I’m doing wrong??? I would gladly pay you for your time.
        We have 2 NIC cards and when I try to set the eth1 gatway we lose SHH to the server.
        ETH0 is for (SSH<WEB<ECT.)
        ETH1 is for SIP traffic only
        ifconfig –a
        eth0 Link encap:Ethernet HWaddr 00:1c:23:d0:0b:2c
        inet addr: Bcast: Mask:
        inet6 addr: fe80::21c:23ff:fed0:b2c/64 Scope:Link
        RX packets:6215 errors:0 dropped:0 overruns:0 frame:0
        TX packets:59877 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000
        RX bytes:908397 (887.1 KiB) TX bytes:13233015 (12.6 MiB)
        Interrupt:16 Memory:f8000000-f8012100

        eth1 Link encap:Ethernet HWaddr 00:1c:23:d0:0b:2e
        inet addr: Bcast: Mask:
        inet6 addr: fe80::21c:23ff:fed0:b2e/64 Scope:Link
        RX packets:271 errors:0 dropped:0 overruns:0 frame:0
        TX packets:123 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000
        RX bytes:181558 (177.3 KiB) TX bytes:13875 (13.5 KiB)
        Interrupt:16 Memory:f4000000-f4012100

        lo Link encap:Local Loopback
        inet addr: Mask:
        inet6 addr: ::1/128 Scope:Host
        UP LOOPBACK RUNNING MTU:16436 Metric:1
        RX packets:197 errors:0 dropped:0 overruns:0 frame:0
        TX packets:197 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0
        RX bytes:68135 (66.5 KiB) TX bytes:68135 (66.5 KiB)

        vi interfaces
        auto lo
        iface lo inet loopback
        # The primary network interface[m
        auto eth0
        iface eth0 inet static

        auto eth1
        iface eth1 inet static
        #gateway ß—-When I try to use this line it locks me out oh SSH

        ip rule show
        0: from all lookup local
        32759: from lookup sip
        32760: from all to lookup sip
        32763: from all to lookup admin
        32764: from lookup admin
        32766: from all lookup main
        32767: from all lookup default

        ip route show dev eth1 proto kernel scope link src dev eth0 proto kernel scope link src

        • Hi Will,
          Your last post looks like some information was cut off, but I think I have enough information to help you.

          1) In /etc/interfaces, do NOT define the gateway for eth1. You are correct that this declaration will cause problems. So, remove the line:
          “gateway″ completely from /etc/interfaces.

          2) It looks like you’re trying to define TWO (2) policy tables: “sip” and “admin”. You do NOT need to do this. Please remove *both* “sip” and “admin” tables, and clear out all the custom “ip rule” and “ip route” commands you have defined.

          3) Once you’ve down that, reboot your system and verify that there are NO custom “ip rule show” and “ip route show” commands listed, and that only the eth0 default gateway is showing up in “netstat -anr”.

          4) THEN, type the following commands:

          echo “1 admin” >> /etc/iproute2/rt_tables

          ip route add dev eth1 src table admin
          ip route add default via dev eth0 table admin

          ip rule add from table admin
          ip rule add to table admin

          ip route flush cache

          Hope this helps,
          – Darien

  43. Great article – worked like a charm.
    Thanks very much!
  44. Thanks very much for the excellent info!

    However there was an error for me for the route setting for the default gateway, which I tried to set to same as in the /etc/network/interfaces file, but from an online IP-calculator I found that the gateway should be the first usable host address from the range of machines on the sub network. After changing to that IP, it worked like a charm.

  45. Many thanks for this I have been trying to consolidate some servers and I was combining our Proxy box with our openvpn box for a different subnet. I decided to use Untangle for the proxy as it was a quick easy set up. However, I knew that I would have to run my own instance of openVPN as Untangle only does routed VPNs and I needed a bridged VPN. All setup fine, but then when I pinged to the openVPN bridged interface through a second router from a PC on my LAN which is the one subnet being proxied I was getting no response, because it was killing them, I looked for a way to route the traffic back out the same interface it came in one for a couple of weeks and even posted questions about this at some forums, but your web page here finally provided me the information I needed to do it. I hope you don’t mind I have resolved the questions I asked on the forums and linked back to your article. Many thanks.
  46. Darien – thanks this is very helpful!
    nobodyfamous and howard refer to same subnet and same gatway with 2 (or multiple) NICs. But would anything change in your precription if I want 2 gateways ( and with 2 NICS ( and on the same subnet. (This is different from link aggregation).

    To stay with your example – what if eth0 has ip
    and gateway

    • oops I shouls have said:

      To stay with your example – what if eth0 has ip
      and gateway

      • Hi Dave,
        Take a look at the comments posted right after nobodyfamous:

        So, let’s assume:
        eth0 – netmask
        eth0′s gateway is:
        eth1 – netmask
        eth1′s gateway is:

        Here are the corresponding commands:
        printf “1\tuplink0\n” >> /etc/iproute2/rt_tables
        printf “2\tuplink1\n” >> /etc/iproute2/rt_tables

        ip route add dev eth0 src table uplink0
        ip route add default via dev eth0 table uplink0
        ip rule add from table uplink0
        ip rule add to table uplink0

        ip route add dev eth1 src table uplink1
        ip route add default via dev eth1 table uplink1
        ip rule add from table uplink1
        ip rule add to table uplink1

        • I have set it up as stated. It boots fine but I am unable to ping (eth1) from another machine on the subnet – but I can ping (eth0). From the machine itself I can ping Here is some output:
          oft201:~# ip rule
          0: from all lookup local
          32766: from all lookup main
          32767: from all lookup default
          oft201:~# vi /etc/rc.local
          oft201:~# /etc/rc.local
          oft201:~# ip rule
          0: from all lookup local
          32762: from all to lookup uplink1
          32763: from lookup uplink1
          32764: from all to lookup uplink0
          32765: from lookup uplink0
          32766: from all lookup main
          32767: from all lookup default
          oft201:~# netstat -nra
          Kernel IP routing table
          Destination Gateway Genmask Flags MSS Window irtt Iface
 U 0 0 0 eth1
 U 0 0 0 eth0
 UG 0 0 0 eth0

          What gives? [I am assuming that policy routing must be enabled in the latest stable debian kernel:
          Linux oft201 2.6.26-2-686-bigmem #1 SMP Thu Sep 16 20:29:07 UTC 2010 i686 GNU/Linux]

            • Darien

            • Posted November 24, 2010 at 6:58 pm
            • Permalink
            Okay, can you paste the contents of your /etc/rc.local file?
            • Darien

            • Posted November 24, 2010 at 7:00 pm
            • Permalink
            Also, I assume you entered “ip route flush cache” and still ran into problems?
            • Dave

            • Posted November 24, 2010 at 7:03 pm
            • Permalink
            I am able to get it to work if the line:
            ip route add dev eth0 src table uplink0
            is changed to
            ip route add dev eth0 src table uplink0
            and the line
            ip route add dev eth1 src table uplink1
            is changed to
            ip route add dev eth1 src table uplink1
            • Darien

            • Posted November 24, 2010 at 7:05 pm
            • Permalink
            Okay, glad it’s working for you.
  47. My rc.local with what I beleive to be the incorrect lines commented out:
    #!/bin/sh -e
    # rc.local
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will “exit 0″ on success or any other
    # value on error.
    # In order to enable or disable this script just change the execution
    # bits.
    # By default this script does nothing.

    #ip route add dev eth0 src table uplink0
    ip route add dev eth0 src table uplink0
    ip route add default via dev eth0 table uplink0
    ip rule add from table uplink0
    ip rule add to table uplink0

    #ip route add dev eth1 src table uplink1
    ip route add dev eth1 src table uplink1
    ip route add default via dev eth1 table uplink1
    ip rule add from table uplink1
    ip rule add to table uplink1

    exit 0

    • Turns out that the above settings work but not as expected.
      If I run ‘ifdown eth1′ and then try
      ping or ssh (the interface associated with eth1) – I can still get through (and vice versa). This may be seen as a feature rather than a bug – but I am spooked by it because I dont understand it. I have abandoned the quest of dual gateway on same subnet. There is no compelling reason for having this anyway. I can live with the original prescription of Darien – which works as expected. (I used the latest debian lenny kernel and did not need to make any special kernel compile to get Dariens prescription working). Thanks again.
  48. Would have been a great article if it had explained where one wrote the admin routing information:

    ip route add dev eth0 src table admin
    ip route add default via dev eth0 table admin

    Which file is this placed into? I don’t know. The article does not say.

    Therefore, I am back to googgeling once more for another site. But at least I know I should Google for policy routing. Thus a partial thank-you.

  49. Hi,
    I have had a hard time following the post, and am unsure its what I have to do. Would you be able to have a look at this scenario and add some helpers for it?

    Both interfaces are on different VLANs (Should not make an once of difference). The default route is the one that goes to the commodity Internet, while the 10/8 destinations are for the internal network.

    eth0 IP
    default eth0 eth0

    eth1 IP
    default eth1 eth1

    • I’ll take a look, but why are you defining two different netmasks for each interface? That makes no sense.

      If you’re going to define a full Class-A /8, then you don’t need to explicitly define a /22 for the upstream Internet gateway. The /22 serves no purpose in this context.

      I’ll generate some rules that show you what I mean…

      • I think I see what you’re trying to do… each interface has two _virtual_ IPs assigned to it:


        I’ll adjust accordingly…

        • Actually, can you confirm each interface has two virtual IPs? The way you wrote the initial IP information is confusing…
            • whynot

            • Posted December 21, 2010 at 4:08 pm
            • Permalink
            These are both IPs plumbs on real NICs, not virtual NIC (not eth0:1 etc), and neither are these bonded in anyway.
      • Hi Darie,

        Apologies for the confusion.

        The 10/8 reference was only mean to refer to the second route below for all traffic to the network, and this understandingly caused confusion.

        All networks use /22. The default route is for all traffic other than the network, (which is really the public Internet and other private nets 192.168.n.n. and 172.16.n.n networks).

        The current system has one NIC eth0. Its routing table as defined is :
        default - -

        I have to plumb a new eth1 onto it on another VLAN and keep the traffic separate. (I had never heard of priority routing until now.) The eth1 has to send the default Internet traffic via the router on eth1, and the rest back to the internal LAN via on eth1.

        • ^Hi Darie,^Hi Darien,
        • Okay, ignore my previous post… will provide documentation based on this new information, shortly.
            • whynot

            • Posted December 21, 2010 at 4:13 pm
            • Permalink
            These are all routers somewhere on the network:
        • Okay, the real issue is that you have a single IP address defined for each physical interface (eth0 and eth1), and yet you have multiple _overlapping_ netmasks defined for the routes in each interface.

          For example, eth0:
          Class-A /8 – respond directly
          /22 – out to gateway

          This makes the issue not as easy to solve, because normally you would assign the same netmask for each interface — or you could define multiple virtual interfaces with different IP addresses and netmask combinations.

          In any event, I believe the following commands will work without having to define any virtual interfaces, but I have never tested this scenario, so you’ll have to try it out and see for yourself:

          Here are the corresponding commands:
          printf “1\tuplink0\n” >> /etc/iproute2/rt_tables
          printf “2\tuplink1\n” >> /etc/iproute2/rt_tables
          printf “3\tuplink2\n” >> /etc/iproute2/rt_tables
          printf “4\tuplink3\n” >> /etc/iproute2/rt_tables

          ip route add dev eth0 src table uplink0
          ip route add default via dev eth0 table uplink0
          ip rule add from table uplink0
          ip rule add to table uplink0

          ip route add dev eth0 src table uplink1
          ip rule add from table uplink1
          ip rule add to table uplink1

          ip route add dev eth1 src table uplink2
          ip route add default via dev eth1 table uplink2
          ip rule add from table uplink2
          ip rule add to table uplink2

          ip route add dev eth1 src table uplink3
          ip rule add from table uplink3
          ip rule add to table uplink3

            • whynot

            • Posted December 21, 2010 at 11:28 am
            • Permalink
            For example, eth0:
            Class-A /8 – respond directly
            /22 – out to gateway

            Yes, this is exactly this. There is a multitude of overlapping netmasks here.

            I shall try all this on a test server, and then report back here. This’ll be later tomorrow, as its nearly home time here.

    • Okay, here’s the set of rules for this scenario. I assume that each interface actually has _two_ virtual IP addresses. In this case, you would be defining “eth0:0 and eth0:1″ as the virtual interfaces for eth0 and “eth1:0 and eth1:1″ for the virtual interfaces for eth1. If you’re not sure what this means or how to set it up, the SLES documentation about virtual interfaces should help.

      Regardless, instead of thinking about two interfaces, think about this problem in terms of _four_ virtual interfaces. If you split the problem based upon each virtual interface, it’s much easier to solve. See below for details.

      eth0:0 – netmask
      eth0:0′s gateway is:

      eth0:1 – netmask

      eth1:0 – netmask
      eth1:0′s gateway is:

      eth1:1 – netmask

      Here are the corresponding commands:
      printf “1\tuplink0\n” >> /etc/iproute2/rt_tables
      printf “2\tuplink1\n” >> /etc/iproute2/rt_tables
      printf “3\tuplink2\n” >> /etc/iproute2/rt_tables
      printf “4\tuplink3\n” >> /etc/iproute2/rt_tables

      ip route add dev eth0:0 src table uplink0
      ip route add default via dev eth0:0 table uplink0
      ip rule add from table uplink0
      ip rule add to table uplink0

      ip route add dev eth0:1 src table uplink1
      ip rule add from table uplink1
      ip rule add to table uplink1

      ip route add dev eth1:0 src table uplink2
      ip route add default via dev eth1:0 table uplink2
      ip rule add from table uplink2
      ip rule add to table uplink2

      ip route add dev eth1:1 src table uplink3
      ip rule add from table uplink3
      ip rule add to table uplink3

  50. Apologies. I;m confused.

    Actually, your original thread was so close what I want to do, yet the ip rules you defined only ever mentioned eth0:
    # eth0 – netmask
    # eth0′s gateway is:
    But never mentioned eth1:
    # eth1 – netmask
    # eth1′s gateway is:

    Since the eth1 is not mentioned, then I presume that it has to be indirectly decided upon by iproute, but this is where I lost the plot. There are only these entries:
    ip route add dev eth0 src table admin
    ip route add default via dev eth0 table admin
    ip rule add from table admin
    ip rule add to table admin
    Nor does it say what to add or remove for the /etc/sysconfig/network/routes table, which currently has some routing information in it

    Anyway, cheers for your time.

    • The default route for anything other than that subnet specified in the table is that which is set for the network. In other words: if those rules don’t apply to the packets, they head on out eth1 towards (unless the packets came from the 7.x network, in which case they would head on over to the machine that made the request.)
  51. This may be an old post, but wonderfully explains how to properly set up the routes. I’m running Ubuntu 10.04. One note, if it’s not clear, I defined a gateway ( for eth0 as my default in the /etc/network/interfaces file. For eth1, I did not define a gateway, but rather set up the route as noted above. Again, many thanks.
  52. Excellent article. It served most of my problem, specially where multiple vlan interfaces setup for different network.
  53. Splendid post!! Thanks =))
  54. Thanks.
  55. This is really great. Finally got my bridged virtual VBOX server environment connected to the internet through a separate nic, leaving my primary nic for the physical ubuntu server access only.

    This makes my virtual business environment finally completely safe and separate from my physical private environment.

    Thanks a lot !

    (If someone wants the setup details, leave a reply and I will post them.)

  57. Two years later, and this is the best post i found to accomplish the job without need to learn all about iptables, routes, rules, etc of a linux box (but still is necesary ;) ).
    Thank you very much. You make my day a happy day ;)
  58. Thank you Thank you Thank you,
    I’ve been trying to shovel several vlans across as many openvpn tunnels on a virtual server without success for what felt like eternity, now in 2 minutes flat it actually does stuff.

    Thanks again

  59. Man, Thank You !!!!!!

    I spent days trying to solve this. This worked right away.

  60. Darien,
    Thanks to you for great article and thanks to everyone else for some great reading.

    Set this up on BackTrack 5 – 32 bit and it worked fine. Now trying the same thing on BT5 R1 – 64 bit and it’s not playing

    I have two distinct networks and never the twain shall meet.

    My home network (eth0) is a with the gateway as and this connects to the internet
    My ‘special’ network (eth1) is a with the gateway as and this connects nowhere due to some of the software sitting on the VM’s that live on this network (vm’s are fixed to eth1 only using VMWare Virtual Network Editor). Both nics have static ip’s though it did work with DHCP when I had it running pre 64 bit install.

    Here is what i’m getting
    have added following to rc.local
    ip route add dev oth0 src table admin
    ip route add default via dev eth0 table admin
    ip rule add from table admin
    ip rule add to table admin
    ip route flush cache

    ip rule show
    0: from all lookup local
    32764: from all to lookup admin
    32765: from lookup admin
    32766: from all lookup main
    32767: from all lookup default

    ip route show
    default via dev eth0 metric 100
    default via dev eth1 metric 100 dev eth1 proto kernel scope link src dev eth0 proto kernel scope link src

    netstat -anr
    Kernel IP routing table
    Destination Gateway Genmask Flags MSS Window irtt Iface UG 0 0 0 eth0 UG 0 0 0 eth1 U 0 0 0 eth1 U 0 0 0 eth0

    With eth1 enabled, I can’t access the internet or if I use ‘route del default gw′ it will let me connect to the internet until next time I reboot. I had it working before and am now baffled as to why it’s playing silly buggers. Have I missed something obvious above or can you think of something else I can try?

    This system is a training rig and I need to be able to access the internet from the main machine whilst using the VM’s on their special network.

    • Here’s your problem:

      “netstat -anr UG 0 0 0 eth0

      You’ve _already_ specified a default route in the _admin_ table for eth0; as such, you should NOT specify a default route for eth0 in the _main_ table.

      To correct this, remove the following command [FLAGGED] from your list:
      “ip route show
      default via dev eth0 metric 100 <— [REMOVE THIS ONE]
      default via dev eth1 metric 100 dev eth1 proto kernel scope link src dev eth0 proto kernel scope link src"

  61. Thanks! This article really helped me.
  62. Thanks man ! you saved my life :) i was looking this information from a long time ago.


  63. hi, and thank you for your post! i have a question….

    eth0 – ip 10,60,90,45 gw 10,60,90,1
    eth1 – ip 10,60,91,45 gw 10,60,91,1
    Kernel IP routing table
    Destination Gateway Genmask Flags Metric Ref Use Iface * U 0 0 0 eth0 * U 0 0 0 eth1
    link-local * U 0 0 0 eth0
    loopback * U 0 0 0 lo
    default UG 0 0 0 eth0

    if i need that a machine on 69,50,20,xx subnet can connect to 10,60,91,45 i add a new route

    69,51,20,0 10,60,91,1 255,255,255,0 UG 0 0 0 eth1

    but if i don’t know all the subnets or more easy, how can i do to all traffic that goes through an interface is returned by the same interface.

    • Hi sun,
      Take a look at the comments posted right after nobodyfamous:

      So, let’s assume:
      eth0 – netmask
      eth0′s gateway is:

      eth1 – netmask
      eth1′s gateway is:

      Here are the corresponding commands:

      printf “1\tuplink0\n” >> /etc/iproute2/rt_tables
      printf “2\tuplink1\n” >> /etc/iproute2/rt_tables

      ip route add dev eth0 src table uplink0
      ip route add default via dev eth0 table uplink0
      ip rule add from table uplink0
      ip rule add to table uplink0

      ip route add dev eth1 src table uplink1
      ip route add default via dev eth1 table uplink1
      ip rule add from table uplink1
      ip rule add to table uplink1

      ip route flush

  65. Thank you! Your page made it so simple to fix my routing dilemma! I had two NICs on two separate dmz networks and needed to keep traffic on the the same NIC it started on. And have a default gateway for each NIC. This helped! Great Work!
  66. Four years on, this is still the clearest guide to this. It just works.


  67. Thanks for the article.

    Unfortunately it does not work in my setup.
    How can I make sure my kernel has support for policy routing?
    I use Proxmox Virtualization Environment ( with kernel 2.6.32-6-pve.

    My setup shows:

    vserver3:~# ip rule show
    0: from all lookup local
    32764: from all to lookup vmbr1
    32765: from lookup vmbr1
    32766: from all lookup main
    32767: from all lookup default

    vserver3:~# ip route show dev vmbr101 proto kernel scope link src dev vmbr1 proto kernel scope link src dev vmbr100 proto kernel scope link src dev vmbr0 proto kernel scope link src
    default via dev vmbr0

    vserver3:~# ip route show table vmbr1 dev vmbr1 scope link src
    default via dev vmbr1

    I have vmbr100 connected via iptables NAT rules to vmbr0
    and vmbr101 via iptables NAT rules to vmbr1.

    Connectivity of vmbr0 and vmbr100 works.
    Connectivity of vmbr1 and vmbr101 is limited to network

    Any ideas? Thanks.

    • Hi Birger,

      “vmbr*” interfaces are not standard network interfaces ( — they are bridging interfaces, which is why policy routing does NOT work properly.

      In order to use policy routing, you need to assign one or more NICs (eth*) interfaces to a bridging interface (vmbr*), and then assign the routing to the attached eth* interface, accordingly.

  68. Hi Darien,

    With respect to multiple default routes on OpenBSD: the virtual tables are primarily meant to create separate logical networks over top of a common base network. For instance you could create a private network for contractors which would keep them logically separated from your employees.

    However within a routing table, OpenBSD actually supports equal-cost multipath route entries. The kernel will choose a path based on the result of a hash and send the packets on their way. It’s really easy to setup and does not require the complexity of virtual tables. Details are in the OpenBSD FAQ (

  69. Thanks for the feedback.

    Special Thanks to Darien for the very valuable blog post.

    Everything works as expected. We tested the configuration with the command “ping -I vmbr1 …”, which gave an error “Destination host unreachable”. Now we found that ping is buggy.

    “ping -I …” works as expected. “wget -q -O – -bind-address=” works also.

    It does work with bridging interfaces and it does work in combination with NAT.

    • Okay, glad to hear it works with bridging interfaces… I wasn’t 100% sure of this, as I had never tested it before.
  70. thx for this. you made my day. if you got 2 nics make sure you add two route tables

    # echo “1 uplink0″ >> /etc/iproute2/rt_tables
    # echo “2 uplink1″ >> /etc/iproute2/rt_tables

    # ip route add dev eth0 src table uplink0
    # ip route add default via dev eth0 table uplink0
    # ip rule add from table uplink0
    # ip rule add to table uplink0

    # ip route add dev eth3 src table uplink1
    # ip route add default via dev eth3 table uplink1
    # ip rule add from table uplink1
    # ip rule add to table uplink1
    ( replace with your settings :P )

    to make it permanent under gentoo you can use

    # nano /etc/local.d/network.start (
    (add #!/bin/sh & the ip xxx commandos; check with rc-update show if the local is added to the default level)
    # chmod +x /etc/local.d/network.start

    have fun and enjoy!

  71. Hi. Great post and the comment stream is going strong…

    I used your post to set up my system.

    I have a gateway box with 2 NICs.
    One nic sits on the internal network (eth1;, the other nic (eth0; connected to a 10 MBit pipe used for incoming VPN.
    There is an ADSL router ( sitting on the network as well…
    Everyone on the network uses as their gateway.
    I want people to be able to set as their gateway if they have special speed needs.
    So what happens is that when the user’s (say user gateway is set to the traffic still goes via… whereas I want it to go through…

    Host Loss% Snt Last Avg Best Wrst StDev
    1. gateway1.e3( 0.0% 4 0.1 0.2 0.1 0.2 0.0
    2. firewall.e3( 0.0% 4 0.4 0.5 0.4 0.5 0.0
    3. 0.0% 3 30.0 146.9 30.0 263.7 165.2
    4. 0.0% 3 280.6 229.0 140.8 280.6 76.8
    5. 50.0% 3 155.1 155.1 155.1 155.1 0.0

    here are my configs:


    2 gatewayeth1
    3 gatewayeth0

    # The primary network interface
    auto eth1
    iface eth1 inet static

    # 10Mbit interface
    auto eth0
    iface eth0 inet static

    ip route add dev eth0 src table gatewayeth0
    ip route add default via dev eth0 table gatewayeth0
    ip route add dev eth1 src table gatewayeth1
    ip route add default via dev eth1 table gatewayeth1

    ip rule add from table gatewayeth0
    ip rule add to table gatewayeth0
    ip rule add from table gatewayeth1
    ip rule add to table gatewayeth1

    iptables rules:
    #! /bin/bash

    iptables –flush

    iptables -t nat –policy PREROUTING ACCEPT
    iptables -t nat –policy POSTROUTING ACCEPT
    iptables -t nat –policy OUTPUT ACCEPT
    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

    iptables –policy INPUT DROP
    iptables –policy OUTPUT DROP
    iptables –policy FORWARD DROP

    # localhost rules
    iptables -A INPUT -i lo -j ACCEPT
    iptables -A OUTPUT -o lo -j ACCEPT

    # in chain for eth0 (outward facing telstra port on network

    iptables -X IN_RULES_ETH0
    iptables -N IN_RULES_ETH0
    iptables -A INPUT -i eth0 -j IN_RULES_ETH0

    # in chain for eth1 (inward facing internal network

    iptables -X IN_RULES_ETH1
    iptables -N IN_RULES_ETH1
    iptables -A INPUT -i eth1 -j IN_RULES_ETH1

    # out chain

    iptables -X OUT_RULES
    iptables -N OUT_RULES
    iptables -A OUTPUT -j OUT_RULES

    # forward chain for eth1

    iptables -X FORWARD_ETH1
    iptables -N FORWARD_ETH1
    iptables -A FORWARD -j FORWARD_ETH1

    # drop stuff for eth0
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP
    iptables -A IN_RULES_ETH0 -d -j DROP
    iptables -A IN_RULES_ETH0 -s -j DROP

    # drop stuff for eth1 allow only a few addresses
    iptables -A IN_RULES_ETH1 -m iprange –src-range -j DROP
    iptables -A IN_RULES_ETH1 -m iprange –src-range -j DROP
    iptables -A IN_RULES_ETH1 -m iprange –src-range -j DROP
    iptables -A IN_RULES_ETH1 -m iprange –src-range -j DROP
    iptables -A IN_RULES_ETH1 -s -j DROP

    # drop stuff out rules
    iptables -A OUT_RULES -d -j DROP

    # allow previously established / related connections
    iptables -A OUT_RULES -m state –state ESTABLISHED,RELATED -j ACCEPT
    iptables -A IN_RULES_ETH0 -m state –state ESTABLISHED,RELATED -j ACCEPT
    iptables -A IN_RULES_ETH1 -m state –state ESTABLISHED,RELATED -j ACCEPT

    # forward all on eth1
    iptables -A FORWARD_ETH1 -i eth1 -j ACCEPT
    iptables -A FORWARD_ETH1 -o eth1 -j ACCEPT

    # out services / ports

    # ICMP
    iptables -A OUT_RULES -p icmp -j ACCEPT
    # Port 22 (SSH)
    iptables -A OUT_RULES -p tcp –dport 22 -j ACCEPT
    # Port 1723 (VPN)
    iptables -A OUT_RULES -p tcp –dport 1723 -j ACCEPT

    # Port 123 (NTP)
    iptables -A OUT_RULES -p udp –dport 123 -j ACCEPT
    iptables -A OUT_RULES -p tcp –dport 123 -j ACCEPT

    iptables -A OUT_RULES -j LOG –log-prefix “BLOCKED OUTPUT ”
    iptables -A OUT_RULES -j REJECT

    # input services / ports

    # ICMP
    iptables -A IN_RULES_ETH0 -p icmp -j ACCEPT
    iptables -A IN_RULES_ETH1 -p icmp -j ACCEPT

    # Port 22 (SSH)
    iptables -A IN_RULES_ETH0 -p tcp –dport 22 -m state –state NEW -j ACCEPT
    iptables -A IN_RULES_ETH1 -p tcp –dport 22 -m state –state NEW -j ACCEPT

    # Port 1723 (VPN)
    iptables -A IN_RULES_ETH0 -p tcp -m tcp –dport 1723 -j ACCEPT
    iptables -A IN_RULES_ETH0 -p gre -j ACCEPT


    # Drop MS NetBIOS scanning early (it spams the log)
    iptables -A IN_RULES_ETH0 -p tcp –dport 137 -j DROP
    iptables -A IN_RULES_ETH1 -p tcp –dport 137 -j DROP
    iptables -A IN_RULES_ETH0 -p udp –dport 137 -j DROP
    iptables -A IN_RULES_ETH1 -p udp –dport 137 -j DROP
    iptables -A IN_RULES_ETH0 -p tcp –dport 138 -j DROP
    iptables -A IN_RULES_ETH1 -p udp –dport 138 -j DROP

    # Log and reject
    iptables -A IN_RULES_ETH0 -j LOG –log-prefix “BLOCKED INPUT ”
    iptables -A IN_RULES_ETH1 -j LOG –log-prefix “BLOCKED INPUT ”
    iptables -A IN_RULES_ETH0 -j REJECT
    iptables -A IN_RULES_ETH1 -j REJECT

    Hopefully you can help me…


    • > Hopefully you can help me…

      Luke, I need some additional clarification… I assume you posted this information because multiple default routing for you isn’t working correctly — is that correct? If so, can you clarify as to what is and is not working correctly? (e.g. which route works properly?)

      Also, remove _all_ the firewall rules and just test to make sure multiple default routing works from the system, first (without any further NAT’ing). If multiple default routes for that host _fail_ to work, then the problem isn’t with your iptables rules — however, if multiple default routing _works_ from (just) the host without the iptable rules, then you’ve isolated the problem to your iptables rules.

      The overall idea here, is to reduce the number variables in your configuration, in order to identify the root cause.

      – Darien

      • Hi Darien. Thanks for your reply.
        The problem is that users on the network who set their gateway to should have their traffic go straight out through the interface, but it goes first to the interface…
        I will try what you suggest and get back here…
      • Ive removed the gateway statement from the local NIC for and it seems to have fixed the problem.
        I thought that having routes added later (as in /etc/rc.local) would have overridden the default gateway set in /etc/network/interfaces but apparently not…
      • Hi Darien. Lastly is there a way I can edit my posts … I seem to have mentioned my ip address in my original post, although I thought I had edited them all, one still remains, could you replace with xxx… thanks
        • Okay, this is fixed..
    I nee a help, I m delete device from ‘network configuration’ and again add it. It may be wrong so I unable to ping eventhough default gateway of my router. so plz guide me to configure properly to access internet via netgare 150 adsl router. plz replay in mail id :
  72. Thanks Darien, this has moved things forward for me. I hope that someone can help with the 1 (!) remainng problem.

    I have eth0 on the 10.10.170 subnet and eth1 on the 10.10.177 subnet. There is more than 1 gateway on each subnet, for reasons I won’t go into. The suggestion in the initial post, modified for my circumstances, allowed me to ssh and ping into either interface. So far, so good. I wasn’t able to do that before. Now however, I’m having trouble transitting from one subnet to the other. I wanted to use the gateway, and that is how I set it up. However, a tracert tries to send me through the gateway. I’ve searched the system and there is no mention of that ip address anywhere to be found.

    Here’s the commands I used.

    ip route add dev eth1 src table voice
    ip route add default via dev eth1 table voice
    ip rule add from table voice
    ip rule add to table voice

    This is under Centos 6


    • Hi Chris,

      I’ll need more information about your network setup, including the configuration used to setup eth0.

      – Darien

  73. Hi, i’ve follow your step, but when i run /etc/init.d/networking restart , the ip table admin is gone, how to save it?
    • sandm3n: See this earlier comment:
      • Thanks for the ansewer, but i still confuse about this (i’m new in ubuntu) , i’ve problem about connection, you can see here (please)

        in that case, i want computer on lan, can connect through squid proxy to the internet, when i setting up without client connect, it can’t ping to LAN because of default route (that connect to internet)
        when i disable that default route, i can successfully ping to lan, But link to internet is off.

        How could i make two connection, so i can connect to LAN and the internet, i refer to your site but still not work.

        Many thanks

        • Hi sandm3n,

          The problem is that your Squid proxy is running inside VMware. I assume you are running VMware Workstation. The problem you are running into is specific to VMware’s network configuration.

          1) You need to change eth0 to use a vmnet that is _bridged_ with a physical network interface card (NIC).
          2) You need to change eth1 to use a vmnet that is _bridged_ with a _different_ physical network interface card (NIC).

          Because you are using (host-only) and (NAT) for these interfaces, VMware is not letting the policy routing settings work correctly.

          • i will let you know my whole simulated network, see here , using GNS3 virtual box edition with cisco router and inter vlan on it, i use Virtual Box as client, you can see cloud on the right that is connect to vmware (ubuntu server), client to client between vlan can connect .
            first question is my topology correct? on the cloud (server) i run Samba file sharing and Squid (not running)
            Do i must running samba and squid separately ?
            many thanks!
            • Darien

            • Posted January 20, 2012 at 11:41 am
            • Permalink
            Hi sandm3n,

            You have enough complex components that I’d recommend testing the multiple default route settings on the Ubuntu server in _isolation_ from the rest of your network. The samba and squid services running on the Ubuntu server do not matter.

            Specifically, if you have two separate clients connected directly to the two interfaces on the Ubuntu server, and you can ping each interface separately from each client, then your multiple default route settings should be working properly.

            Once you have established that this works, you can slowly increase the complexity of your network architecture and re-test these basic checks at each step (e.g., pinging each interface). That way, when the test fails, you will be able to isolate which component is responsible for the problem.

          • Thanks for your nice advice, want to test your suggest first, i’ve to learn more about this, sorry if i bothering you Darien.

Recommended Links

Softpanorama hot topic of the month

Softpanorama Recommended


FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available in our efforts to advance understanding of environmental, political, human rights, economic, democracy, scientific, and social justice issues, etc. We believe this constitutes a 'fair use' of any such copyrighted material as provided for in section 107 of the US Copyright Law. In accordance with Title 17 U.S.C. Section 107, the material on this site is distributed without profit exclusivly for research and educational purposes.   If you wish to use copyrighted material from this site for purposes of your own that go beyond 'fair use', you must obtain permission from the copyright owner. 

ABUSE: IPs or network segments from which we detect a stream of probes might be blocked for no less then 90 days. Multiple types of probes increase this period.  


Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy


War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes


Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law


Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least

Copyright © 1996-2016 by Dr. Nikolai Bezroukov. was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License.

The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to make a contribution, supporting development of this site and speed up access. In case is down you can use the at


The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the author present and former employers, SDNP or any other organization the author may be associated with. We do not warrant the correctness of the information provided or its fitness for any purpose.

Last modified: June 04, 2016