The Hoof & Paw
DocsCategoriesTagsView the current conditions from the WolfspyreLabs WeatherstationToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Policy based routing Micro Howto

title: Policy based routing Micro Howto slug: /Networking/Policy-Based-Routing-Howto

Policy Based Routing MicroHowto

This originally resided here

Scraped from the waybackmachine by Yours Truly.

Horacio J. Peña, v0.03 05/Apr/2000

  1. Preface, disclaimer and help request.

This is my attempt to recopilate some info on how to use the advanced routing capabilities of the 2.1.x Linux kernels. As each time i’ve asked for help in linux-(kernel|net|router|es) instead of getting answers i received lots of mail saying “You seem to know how to use iproute, could you explain me it?” i’m writing that so i can send them an URL :-)

I DON’T KNOW NOTHING OF POLICY ROUTING FOR SURE. All of these notes are based on my guesses about how that works. I HAVEN’T READ THE CODE (i tried, but i got lost very quickly, i promise retry when i wake up) ALL OF WHAT YOU DO BASED ON THIS DOCUMENT IS YOUR AND ONLY YOUR RESPONSABILITY. I wasn’t. You haven’t seen me. You cannot prove it. And i apologize for my english, i’m hard enough to understand writing in Spanish (too confuse), so i imagine it will be real hard reading me in English.

I’m not maintaining actively this document (i’m updating it now, in Apr/2000, and last mod was from Nov/1998)

This micro HOWTO will probably vanish with somebody that knows really about this issue writing the corresponding section of the NET-3 (NET-4?) HOWTO.

I’ll assume you know enough of tcp/ip and the standard routing principles. If you don’t please read before the NET-3 HOWTO and the NAG.

1.1. History.

v0.1 and v0.2. Original and grammatical corrections. (End of 1998)

v0.3 added “Routing

  1. Required software.

You’ll need a recent 2.1.x kernel (i’ve a pair of production machines running 2.1.119 from some weeks ago and my work devel machine runs 2.1.129) compiled with policy routing. (depends on Networking Options/ IP: advanced router)

You will need too the iproute2 package. You can get it from (there are lots of interesting things there), but it can be hairy to compile, so if your distro has it as package use it. (i know for sure that Debian has it)

You probably will want to use ipchains. And read its wonderful HOWTO (at least for the ASCII art ;). You can find ipchains in

  1. Basics.

In the traditional (2.0) routing you had a routing table. Now you have a rules table that point to multiple routing tables. The rules let you select the routes based not only on the destination address, but in the source address, TOS, and incoming device.

Added to that, you can use the very expressive ipchains rules to route using more details (transport protocol headers)

  1. Rules.

Rules are defined by the “ip rule” command. Let’s see its syntax:

Usage: ip rule [ list | add | del ] SELECTOR ACTION SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ dev STRING ] [ pref NUMBER ] ACTION := [ table TABLE_ID ] [ nat ADDRESS ] [ prohibit | reject | unreachable ] TABLE_ID := [ local | main | default | NUMBER ]

(I haven’t played yet with NAT, and don’t understand what “[ prohibit | reject | unreachable ]” does here (isn’t it an ipchains work?), so, by now, the only ACTION we’ll be using is table.)

4.1. Listing rules.

The command to list the rules table is “ip rule list”, more often abbreviate as “ip ru ls”.

Look at its output:

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

(default output)

0: from all lookup local 2000: from all lookup 2 3000: from all lookup 3 3500: from all tos 04 lookup 32 4000: from lookup 4 4000: from lookup 4 4000: from lookup 4 4000: from lookup 4 32000: from all lookup 32 32766: from all lookup main 32767: from all lookup default

(output in my main router)

The number at the left of the colon is the preference. When a packet arrives to the system it gets compared with the SELECTOR of each rule in preference order, (don’t know what happens with equal preference rules), if it matches then the ACTION is done.

4.2. Adding a rule.

The command to add a rule is “ip ru add SELECTOR ACTION”. Some examples:

4.2.1. Routing by TOS.

ip ru add tos 4 pref 3500 table 32

generates the rule

3500: from all tos 04 lookup 32

That means: For all packets with the IP header TOS field == 4 use the routing table 32.

4.2.2. Routing by source

This is probably the most used feature of policy routing.

ip ru add from table 5

generates the rule

1: from lookup 5

(preference can differ, it assigns the first unused one)

That means: for all packets originated from the IP use routing table 5.

4.3. Deleting a rule.

Same syntax than for add but using “ip ru del”

  1. Routing tables.

These are handled by “ip route” (“ip ro” for the friends)

The syntax is very similar to the good old route’s one:

Usage: ip route list SELECTOR ip route { change | del | add | append | replace | monitor } ROUTE SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ] [ table TABLE_ID ] [ proto RTPROTO ] [ type TYPE ] [ scope SCOPE ] ROUTE := NODE_SPEC [ INFO_SPEC ] NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ] [ table TABLE_ID ] [ proto RTPROTO ] [ type TYPE ] [ scope SCOPE ] INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]… NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS OPTIONS := FLAGS [ mtu NUMBER ] [ rtt NUMBER ] [ window NUMBER ] TYPE := [ unicast | local | broadcast | multicast | throw | unreachable | prohibit | blackhole | nat ] TABLE_ID := [ local | main | default | all | NUMBER ] SCOPE := [ host | link | global | NUMBER ] NHFLAGS := [ onlink | pervasive ] RTPROTO := [ kernel | boot | static | NUMBER ]

Oops, it seems a bit more complex than route’s one… :-)

But, for now, just use it as route.

5.1 Listing routing tables.

ip ro ls [table N]

The output will be similar to: dev eth1 scope link via dev eth1 default via dev eth1

5.2. Adding routes.

ip ro add destination/dstmsk [dev DEV] [via GATEWAY] [table TABLE]


ip ro add dev eth1 table 3 ip ro add via table 32

5.3. Deleting routes.

ip ro del destination/dstmsk [dev DEV] [via GATEWAY] [table TABLE]

ip ro del dev eth1 table 3 ip ro del table 32

  1. Routing by firewall mark.

The most common scenary i receive questions about is a router with two connections to the internet. The good and expensive and the cheap and bad… So we would like to send the priority traffic for the good one, and the standard routing system doesn’t give us enough flexibility.

Here comes ipchains to the rescue! It provides us the added flexibility and let us to route based in transport protocol headers.

The way to do it is by adding a firewall rule to the input chain, that marks the packet and adding a routing rule to process it.

Remember to compile your kernel with CONFIG_IP_ROUTE_FWMARK.

6.1. Marking packets.

The marking of packets must be done in the input chain (or on a chain called from the input one) to be useful. That’s because the routing decissions are taken before the packet hits the forward rule (that’s a assumption, i haven’t read the code yet O:-) and of course before the output chain…

An interesting note about this is that you can only route with this added flexibility packets generated non locally. It would be interesting to add a “local” chain…

To mark a packet add a rule like that: (check the ipchains HOWTO for the syntax)

ipchains -A input -p tcp -s -d 0/0 22 -m 2

(This means, mark all the ssh -tcp port 22- traffic with 2 as mark value)

6.2. Using the mark.

Use fwmark in the routing rule definition.

ip ru add fwmark 2 table 4 pref 2500 ip ro add 0/0 dev ppp0 table 4

6.3. Masquerading.

With this, you can determine what connection will be used for sending out the packets, but if you want to decide where will the answer come by, you’ll need to do masquerading…

ipchains -A forward -p tcp -s -d 0/0 22 -j MASQ

(in this example, you’d need to do masquerade the same, because we’re using private IPs)

  1. More info.

    There is now documentation for iproute2! Look for ip-cref in the iproute files.

  2. Credits and legalities.

8.1. Thanks.

To Linus, _Anarchy_, Alexey, Paul, David, etc. for his great

work on my preferred TCP/IP stack. :-)

To Arne Kuhlmann, JOshua, Enrique I.R. and Lindsay Allen, that

have convinced me to write that.

To the UniNet crowd, MJ, Mapi, pukka, pask, ciberio, etc. for their


To the PuntoAr people that let me work on thinks i enjoy, without

bothering with stupid burocratic things.

8.2 Legalities.

This document is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This document is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the:

Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.