From e07f0ef41707863dac2a371e631a2594c276eb45 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Sat, 11 Dec 2010 13:43:52 -0800 Subject: Merge support for Routing Policy Database (RPDB) This can be used for multi-homed connections and other advanced routing in Linux. See the documentation links for more information about doing this in linux. The code was a originally pure addon into the conf.d/net files, written in mid-2004 for doing multi-homing between two internet connections. I have finally cleaned this up and integrated it. Thanks to Jonathan Kwan for giving me the original impetus to develop this for Gentoo (it was his dual internet connections...). In the intervening years, it was a example of postup/postdown in the net.example file, however that suffered from a few corner case issues. If you were using the code from net.example, please see the updated section 'Advanced Routing' on syntax, and drop your old function blocks. Additionally, note that the rules added are now directly saved for removal when the interface is taken down. --- doc/net.example.Linux.in | 88 +++++++++++++++++++++++++----------------------- net/iproute2.sh | 44 +++++++++++++++++++++++- 2 files changed, 89 insertions(+), 43 deletions(-) diff --git a/doc/net.example.Linux.in b/doc/net.example.Linux.in index 582c1618..7955fe3d 100644 --- a/doc/net.example.Linux.in +++ b/doc/net.example.Linux.in @@ -864,6 +864,52 @@ #relay_6to4="192.168.3.2" #suffix_6to4=":ff" +#----------------------------------------------------------------------------- +# Advanced Routing +# WARNING: For advanced routing you MUST be using sys-apps/iproute2 +# +# This provides a means to do multi-homing and more using the Routing Policy +# Database (RPDB). +# +# See the following links for background and more information. +# http://linux-ip.net/html/ch-routing.html +# http://linux-ip.net/html/ch-advanced-routing.html + +# The rules listed will be added with 'ip rule add LINE' when the interface is +# being brought up. They will also be removed with 'ip rule delete LINE'. +# The rules added are also stored for later removal, so if you alter your rules +# directly before stopping, you should review your rules again after stopping. + +# Note in earlier versions of openrc, this was provided as an example in +# postup/postdown, however that implementation suffered some bugs in corner +# cases, which are now fixed with this merger. If you used the previous +# example, you should only need to drop the relevent portions of your +# postup/postdown functions, and review the quoting in your rules_IFACE +# variables. + +# Below is a trivial example for a dual-homed connection where there is an OOB +# management network. Only packets explicitly with an address from or to the +# OOB are sent via eth0. All others go via eth1 as the eth1 rules have a lower +# priority. + +# If you want to use names for your tables, you should put lines into +# /etc/iproute2/rt_tables, an example follows: +# 2 oob +# 3 external + +#rules_eth0=" +#from ZZZ.ZZZ.200.128/27 table oob priority 500 +#to ZZZ.ZZZ.200.128/27 table oob priority 550" +#rules_eth1=" +#from XXX.XXX.112.0/24 table external priority 400 +#to XXX.XXX.112.0/24 table external priority 450" +#routes_eth0=" +#ZZZ.ZZZ.200.128/27 dev eth0 table oob scope link +#default via ZZZ.ZZZ.200.129 table oob" +#routes_eth1=" +#XXX.XXX.112.0/24 dev eth1 table external scope link +#default via XXX.XXX.112.1 dev eth1" + #----------------------------------------------------------------------------- # System @@ -992,33 +1038,6 @@ # # This function could be used, for example, to register with a # # dynamic DNS service. Another possibility would be to # # send/receive mail once the interface is brought up. - -# # Here is an example that allows the use of iproute rules -# # which have been configured using the rules_eth0 variable. -# #rules_eth0=" \ -# # 'from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100' \ -# # 'from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100' \ -# #" -# eval set -- \$rules_${IFVAR} -# if [ $# != 0 ]; then -# einfo "Adding IP policy routing rules" -# eindent -# # Ensure that the kernel supports policy routing -# if ! ip rule list | grep -q "^"; then -# eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)" -# eerror "in your kernel to use ip rules" -# else -# for x; do -# ebegin "${x}" -# ip rule add ${x} -# eend $? -# done -# fi -# eoutdent -# # Flush the cache -# ip route flush cache dev "${IFACE}" -# fi - #} #postdown() { @@ -1026,21 +1045,6 @@ # # Probably a good idea to set ifdown="no" in /etc/conf.d/net # # as well ;) # [ "${IFACE}" != "lo" ] && ethtool -s "${IFACE}" wol g - -# Automatically erase any ip rules created in the example postup above -# if interface_exists "${IFACE}"; then -# # Remove any rules for this interface -# local rule -# ip rule list | grep " iif ${IFACE}[ ]*" | { -# while read rule; do -# rule="${rule#*:}" -# ip rule del ${rule} -# done -# } -# # Flush the route cache -# ip route flush cache dev "${IFACE}" -# fi - # # Return 0 always # return 0 #} diff --git a/net/iproute2.sh b/net/iproute2.sh index 09a72d73..e89e33b6 100644 --- a/net/iproute2.sh +++ b/net/iproute2.sh @@ -199,6 +199,32 @@ _tunnel() ip tunnel "$@" } +# This is just to trim whitespace, do not add any quoting! +_trim() { + echo $* +} + +# This is our interface to Routing Policy Database RPDB +# This allows for advanced routing tricks +_ip_rule_runner() { + local cmd rules OIFS="${IFS}" + cmd="$1" + rules="$2" + eindent + local IFS="$__IFS" + for ru in $rules ; do + unset IFS + ruN="$(trim "${ru}")" + [ -z "${ruN}" ] && continue + ebegin "${cmd} ${ruN}" + ip rule ${cmd} ${ru} + eend $? + local IFS="$__IFS" + done + IFS="${OIFS}" + eoutdent +} + iproute2_pre_start() { local tunnel= @@ -210,7 +236,7 @@ iproute2_pre_start() ebegin "Creating tunnel ${IFVAR}" ip tunnel add ${tunnel} name "${IFACE}" eend $? || return 1 - _up + _up fi # MTU support @@ -240,6 +266,15 @@ iproute2_post_start() # Kernel may not have IP built in if [ -e /proc/net/route ]; then + local rules="$(_get_array "rules_${IFVAR}")" + if [ -n "${rules}" ]; then + if ! ip rule list | grep -q "^"; then + eerror "IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES) needed for ip rule" + else + service_set_value "ip_rule" "${rules}" + _ip_rule_runner add "${rules}" + fi + fi ip route flush table cache dev "${IFACE}" fi @@ -259,6 +294,13 @@ iproute2_post_start() iproute2_post_stop() { + # Kernel may not have IP built in + if [ -e /proc/net/route ]; then + local rules="$(service_get_value "ip_rule")" + [ -n "${rules}" ] && _ip_rule_runner del "${rules}" + ip route flush table cache dev "${IFACE}" + fi + # Don't delete sit0 as it's a special tunnel if [ "${IFACE}" != "sit0" ]; then if [ -n "$(ip tunnel show "${IFACE}" 2>/dev/null)" ]; then -- cgit v1.2.3