I've put together scripts to save the routing tables in text or xml form. This message explains 1. how they are used 2. the approach I have taken 3. what is needed next. This is related to other work which converts iptables to xml and back (now in iptables 1.3.7), htb files into xml and xml to tc commands (complete but not yet released) and ebtables to xml and back (to be released any day now). I find that having iptables, ebtables, tc and ip route as xml permits some very useful manipulations. This first draft is thorough, but maybe not correct, so I welcome feedback; please see STRATEGY further down: I've made use of bash's <( ) to package some external resource files (large sed script and xslt) in the same bash script so there is only one file to distribute and try out. You will need xsltproc to restore xml routes Basic Usage =========== iproute save [-x][-t][-s] [filename]xml will save the rules and routes in text [-t] format (default), xml [-x] format, and with [-s] or without the /proc/sys/net/ipv4/route routing paramters. The save is atomic. xml iproute restore [-x][-t][-s] [filename] behaves similarly. If iproute restore fails to restore the routes, it attempts to rollback to the previous set of routes. Conversion to xml is managed with sed; conversion from xml requires xsltproc, a command line C based xslt 1.0 processor. iproute flush will pretty much flush the rules and routes; this is also done before restore or rollback. See Strategy. Formats - TEXT -------------- The text format is roughly the same as: ( ip -o rule show ; ip -o route show table all ) but has a notation like: > error_burst 1250 for the sysctl paramters; which are converted to echo 1250 > /proc/sys/net/ipv4/route/error_burst Formats - XML ------------- The xml format is along these lines: <ip-route version="1.0" error_burst="1250" gc_elasticity="8" ... > <rules> ... <rule priority="298" from="11.22.111.222" table="222"/> ... </rules> <tables> <table id="222"> <route prefix="1.1.0.0/8" mtu="100" metric="40"> <next-hop via="192.168.0.23" dev="eth3" weight="2"/> <next-hop via="10.1.1.1" dev="eth4" weight="3" type="onlink"/> </route> ... </table> ... </tables> </ip-route> Stategy ======= Flushing -------- Before applying routes and rules (or rolling back previous routes and rules on failure) some kind of routing table flush is needed. The difficulty I am under is knowing what should be flushed and what should not. I guess if someone is using a routing daemon, they won't be using this - although I could be wrong; thus I only need to be careful where proto = kernel, or I can be liberal where proto = boot (or not specified). As the kernel only fiddles with routes in the main and default tables, I don't bother to check proto generally. Also I don't want to fiddle with the local table. I've decided not to fiddle with the default table (is this right?) I empty every other table totally, except the main table where I preserve routes with scope=link, as to my dull mind messing with these would be silly. I delete all rules except 0, 32766 and 32767 So, yes, I also delete the default gateway. If someone also wanted to use this on a system with a routing daemon running, we should probably pay more attention to the proto parameter; I would need to talk with someone who knows more about mixing routing daemons with non-daemon routes. I flush tables using the "ip route flush" command. Parsing / Restoring ------------------- I flush or restore rules by some sed which converts the initial priority and colon to the keyword priority; combined with the rest of the output these seems parsable as input. similarly for tables, prefixing route add or route delete to the results of a line from: ip -o route show table all seems a good way to delete or restore a route individually. dev entry --------- When restoring routes it seems prudent to remove the dev entry for any via unless it is an onlink route; for the reason that generally the dev entry was not specified initially but divined from the device tables and netmasks and such, and it would be a good idea to let ip route do this again in case the interface addressing has changed. Currently the dev entry is removed during xml restore and not text restore. It should probably be removed during save, so that it may be specified strictly as part of a fresh xml routing profile without being ignored. This would have the disadvantage that when save were used for diagnostic or informational purposes the dev information would be missing. Local Main Default ------------------ Likewise, for informational reasons, the default, local and main table (and their rules) are saved; but skipped when a restore takes place. It is presumed that whatever set these tables up in the first place (and their rules) has done the same again. The only exception is that routes for default are processed if they have no scope (text restore) or they are default routes (xml restore). This difference is historical and should be removed. Converting to XML ----------------- I've written a few scripts to convert from various text formats to xml. This one was the most fun yet. I do rely on the fact that ip route spits out simple text that does not need any xml escaping (my other conversions do xml escaping properly). Because the output of ip route is structured fluidly (the via information appears in the middle of the per-route information unless there is more than one hop) and because I'm not entirely sure of all the outputs of ip route, I've structured the xml conversion to detect when unrecognized parameters exist, and output xml comments to warn of this.today Those who have used sed heavily will know it only has 2 variables: the "current" line, and a "spare". I've made cunning use of these in ways that will be hard to grasp and easy to break if you don't know sed well. It's not as spaghetti as it looks, I have had do develop certain idioms for converting to xml and once you spot these a new macro-level understanding will coalesce making the whole thing easier to understand. Why did I use sed seeing how complicated it is? I've learned that using bash to convert xml is a SLOW mistake, and I really don't want to introduce dependancies on anything even as big as awk - which probably would have done a better job (what with having more than two variables, and hashes and all!). So what about xsltproc? libxslt and xsltproc are smaller than gawk. Also, I was learning sed for fun and wanted to see how far I could push it. However, Generating XML is generally simple; if what I have done is worthwhile, it will be simple enough to get the ip command to output xml as an alternative format. Converting from XML ------------------- I've been generating bash-able output from XML for quite some time and developed a full xslt library of escape functions to prevent injection errors from crafted xml. For this project, and to keep the xslt dependancies simple, I've tried a new strategy which is to not generate bash script lines and execute them, but instead to validate the output in bash and use them as parameters instead of commands, reducing the scope for naughtiness. Because the xml saving was done before the text saving, the xslt generates ip route commands directly instead of the text format and then using the text format conversion. The asymmetry is interesting but I don't plan to do anything about it. Next Steps ========== This work suits me and my employer, but we don't see why we should be the only ones to benefit. Our benefit is not in having xml routes, but how we process the xml. Those who have an interest, please examine this and see how useful it is. I have a source-rpm as well which I will distriute once we've reviewed this once.
#! /bin/bash # iproute - save and restore ip route's in text or xml format # Copyright (C) UFO Mechanic <azez@xxxxxxxxxxxxxxx> # # This program 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 program 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Severe error means we left the system in an unknown state # probably with partial routing. It means the new routes wouldn't # go in and we couldn't restore the old ones ERROR_SEVERE=4 # Mild errors means we didn't do what we were asked, but as far as # we can tell it was a clean failure and nothing is damaged # System error means basic things failed, like creating files in /tmp # If the environment isn't useful, there's not much we can do. # System errors are mild ERROR_SYSTEM=3 # XML error means the xml processor failed, probably bad xml ERROR_XML=2 # ROUTE error means that ip would not process the route commands, # perhaps bad xslt or good xml specifying a bad configuration ERROR_ROUTE=1 SYSCTL_ATTR="error_burst gc_elasticity gc_min_interval_ms max_delay min_delay redirect_load secret_interval error_cost gc_interval gc_thresh max_size min_pmtu redirect_number gc_min_interval gc_timeout min_adv_mss mtu_expires redirect_silence" SYSCTL_PATH="/proc/sys/net/ipv4/route" IPROUTE_TMP=/tmp/iproute-save.$$ SYSCTL="" FORMAT="text" # clean up temporary files on_exit() { rm -f /tmp/rollback.$$ /tmp/route.$$ $IPROUTE_TMP } trap on_exit 0 # validate echo nnn > /proc/sys/net/ipv4/route/* # and execute according to PERMIT_SYSCTL ip_sysctl() { if [ "$1" = "echo" -a "$3" = ">" -a "$#" = 4 ] then case "$4" in *..*) ;; # escape any dodgy paths /proc/sys/net/ipv4/route/*) # it's legal, is it permitted? if [ -n "$SYSCTL" ] then echo "$2" > "$4" || return $ERROR_ROUTE fi return ;; esac fi echo "Bad set route paramter: $*" >&2 return $ERROR_ROUTE } # Rather than pipe output xsltproc output directly to a shell, # we avoid shell injection, and inspect each line (read from stdin) ip_run_commands() { while read ip_line do set -- $ip_line case "$1" in ip) "$@" || return $?;; echo) ip_sysctl "$@" || return $?;; '#'*|'') ;; *) echo "Invalid IP command: $*" >&2 # It's severe until we rollback return $ERROR_SEVERE;; esac done } # convert ip show/save format to shell commands. # also handles systl's denoted by > ip_save_to_commands() { sed -e '/^[0-9]*:/{ # its a rule /^0:/d;/^32766:/d;/^32767:/d; s/ none *$/ 0/;s/^\([^: \t]*\)[:\t ]*/ip rule add pref \1 /;t;d } /^> /{ # its a sysctl tSYSCTL :SYSCTL s/^> *\([^ ]*\) *\(.*[^ ]\) *$/echo \2 > \/proc\/sys\/net\/ipv4\/route\/\1/ tSYSCTL_OK s/^/#/ :SYSCTL_OK b } # must be a table / table local /d; / table default /d; # ignore non-global scope for main / table /!{ / scope /d }; / table main /{ / scope /d }; s/\\\t/ /g; # fix bad rtt suffixes s/\( rtt[^ ]* [0-9]*\)[^ ]*/\1/g; s/^/ip route add /' } # read rules in a way ready to do ip rule add, ip rule delete on # "$1" is inserted to the beginning of the line # Ignores rules 0, 32766 and 32767 ip_read_rules() { ip rule show | sed -e '/^0:/d;/^32766:/d;/^32767:/d;s/ none *$/ 0/;s/^\([^: \t]*\)[:\t ]*/'"$1"' pref \1 /;t;d' } # read routes in a way to do ip route add or ip route delete on # "$1" is inserted at the beginning of the line # Ignore default and local and scope links in main ip_read_routes() { # here we are relying on the double space that occurs before the keyword table and the single space that always follows the table name # We also remove the ms suffix from the rtt and rttvar parameters. # BUG: route show displays a smaller rtt than was set, so each rollback shrinks rtt. rttvar does not have this problem ip -o route show table all | \ sed -e '/ table local /d;/ table default /d;/ table /!{/ scope /d};s/\\\t/ /g;s/\( rtt[^ ]* [0-9]*\)[^ ]*/\1/g; s/^/'"$1"' /' } # output table names apart from main, local, default ip_show_tables() { ip -o route show table all | \ sed -ne '1{x;s/^.*/ main local default 255 254 253 /;x;tDone;:Done;};s/^.* table *\([^ ]*\).*/\1/;T;G;/^\([^\n]*\)\n.* \1 /!{P;s/\n/ /;s/^/ /;x;}' } # Flush existing rules ip_flush_rules() { ip_read_rules "ip rule del" | ip_run_commands } # Flush existing tables entirely (except local, main, default) # Of main, flush non local scope rules. Local scope rules seem to # refer to per-local-ip routes ip_flush_routes() { ip_show_tables | \ while read table do ip -o route flush table $table done # Flush non link scope'd rules from main - call that scope global for now ip route del table main scope global &>/dev/null } # produce a set of ip commands which will restore a newly # flushed routing table to it's current state ip_prepare_rollback() { save_text } flush() { # perhaps we should only delete proto boot routes (and only scope globan for table main) ip_flush_routes # ..and perhaps we should only delete rules whose tables are now empty? ip_flush_rules } ip_rollback() { flush ip_save_to_commands < /tmp/rollback.$$ | ip_run_commands } restore_text() { ip_save_to_commands < "$FILE" > /tmp/route.$$ || return $ERROR_ROUTE ip_run_commands < /tmp/route.$$ || return $? } # generate ip commands, don't execute unless we do this successfully restore_xml() { xsltproc <( iproutexml_xslt ) "$FILE" > /tmp/route.$$ || return $ERROR_XML ip_run_commands < /tmp/route.$$ || return $? } save_text() { test -n "$SYSCTL" && for attr in $SYSCTL_ATTR do read f < "$SYSCTL_PATH/$attr" echo "> $attr $f" done ip -o rule show ip -o route show table all } save_xml() { save_text | iproute2xml } save() { test -n "$1" && IPROUTE_TMP="$1.$$" if save_$FORMAT > "$IPROUTE_TMP" then if [ -n "$1" ] then mv "$IPROUTE_TMP" "$1" || exit 1 else cat "$IPROUTE_TMP" fi else exit 1 fi } restore() { FILE="${1:-/dev/stdin}" if ! ip_prepare_rollback > /tmp/rollback.$$ then echo "Can't prepare rollback file" >&2 return $ERROR_SYSTEM fi flush # apply xml routes or rollback if restore_$FORMAT "$@" then # flush routing cache ip route flush cache else # need to roll-back previous route echo "Attempting to restore previous routing table" >&2 if ! ip_rollback then echo "Rollback failed!" >&2 return $ERROR_SEVERE fi return $ERROR_ROUTE fi } help() { case "$0" in *save) ;; *restore) ;; *) action=" [save|restore]";; esac cat<<HELP Usage: $0 [-s][-x]$action [filename] -x File in xml format -x File in text format (default) -s Also restore sysctl settings (if any) to $SYSCTL_PATH filename The name of the route save file, defaults to stdin/stdout HELP exit } main() { while getopts "htxs" Option do case $Option in s) SYSCTL=1;; x) FORMAT=xml;; t) FORMAT=text;; h) help;; *) echo "Unknown Option: $Option $OPTARG" >&2 ; help >&2; exit 1;; esac done shift $(($OPTIND - 1)) case "$0" in *save) save "$@";; *restore) restore "$@";; *) "$@";; esac } # This was a standalone sed script, but I built it into bash for fun and ease of initial distribution iproute2xml() { sed -n -f <( iproute2xml_sed ) } iproute2xml_sed() { cat<<'ENDOFSED' #! /bin/sed -nf # invoke like this: # ( ip -o rule show ; ip -o route show table all ) | ./iproute2xml # or # ( echo 'echo attr="value" attr2="value2"' ; ip -o rule show ; ip -o route show table all ) | ./iproute2xml # to have the attributes inserted into the outer node; e.g. # e.g. # ( echo "echo 2 > /proc/sys/net/ipv4/route/error_bust"; ip -o rule show ; ip -o route show table all ) | ./iproute2xml 1{ # if it's a "special" attributes line merge it with the open tag tOpenTag :OpenTag /^> /{ # looks like a sysctl routing param x s/^.*/<ip-route version="1.0"/ x tMakeAttr :MakeAttr s/^> *\([^ \/]*\) *\(.*[^ ]\) *$/\1="\2"/ TSkipAttr H :SkipAttr n /^> /bMakeAttr # thats all attributes done x s/\n/ /g s/$/>/ p s/^.*// x bDoneOpenTag } :StaticOpenTag i<ip-route version="1.0" \/> :DoneOpenTag } ${# close dangling tags x /^:/a\ \ </rules> /^[^:\n]/{ a\ \ \ \ </table> a\ \ </tables> } a</ip-route> x } # line 1 of h will contain the current table, or : if we are processing rules /^[0-9][0-9]*:/{# rules... x /^:/!{# open rules tag i\ \ <rules> } s/^.*// # keep copy of line for error reporting g x # now process input line itself. # leave un-recognized fragments on line 2 so we can warn about them s/^\([0-9][0-9]*\):[\t ]*/ <rule priority="\1"\n / # get rid of some default values s/\n\(.*\) from all */\n\1 / # recognize known attributes and values tPullRuleAttributes :PullRuleAttributes s/\n\(.*\) \(from\|to\|iif\|tos\|fwmark\|realms\|nat\) \([^ ]*\)/ \2="\3"\n \1/ tPullRuleAttributes s/\n\(.*\) lookup \([^ ]*\)/ table="\2"\n \1/ s/\n\(.*\) \(blackhole\|prohibit\|reject\|unreachable\|unicast\|none\|[0-9][0-9]*\)/ type="\2"\n \1/ s/\n/\/>\n/ # anything left on line 2 is unrecognized attributes of the rule /\n *[^ ]/{ # save line 2 on to the end of holding space as warning s/\n */\n Warning; Unknown ip rule arguments: / G h s/[^\n]*\n\([^\n]*\)\(.*\)/\2\n\1/ s/^\n* *// x } # strip line 2 s/\n.*// # print output, comments first, if any... x ## ADJUST: Un-comment this line to stop input appearing as output comment unless there is an error /\n/!s/^.*// /^./{ s/^/\n <!-- / s/$/ -->/ p } x p # note that we have an open rule tag s/^.*/:/ x d } # soo... it must be a table entry { # holding space line 1 is used to hold currently open table name # holding space line 2 and onwards will be for xml comments and errors x s/\n.*// # keep copy of input for error reporting G x # normalize multi-hop lines into multiple lines s/\\\tnexthop /\n /g tStartRoute :StartRoute s/^ *\(via\|anycast\|unicast\|local\|broadcast\|multicast\|throw\|unreachable\|prohibit\|\blackhole\|\nat\) *\([^ ]*\)/ <route prefix="\2" type="\1"\n/ tDonePrefix s/^ *\([^ ]*\)/ <route prefix="\1"\n/ :DonePrefix # line 1 has start of tag, type (if any) and prefix # line 2 has unrecognized tags # line 3 has explicit hop statements which dont contain any NODE_SPEC # so we only need to pull NODE_SPEC from line 2. # If there is a line 3 then anything left in line2 is unknown, otherwise line 2 may contain NODE_SPEC and unknown INFO_SPEC mixed # gather infospec fragments from lines 2 onwards # look for mtu-lock specially s/^\([^\n]*\)\n\(.* \)\(mtu lock\) *\([^ ]*\)/\1 mtu="\4" mtu-lock="yes"\n\2/ tPullNodeSpec # reset t command :PullNodeSpec # of course mtu\|advmss\|rtt\|rttvar\|window\|cwnd\|ssthresh\|realms only make sense if there are vias # but we dont check that here s/^\([^\n]*\)\n\([^\n]* *\|\)\(tos\|reordering\|proto\|scope\|metric\|src\|preference\|mtu lock\|mtu\|advmss\|rtt\|rttvar\|window\|cwnd\|ssthresh\|realms\) *\([^ \n]*\) */\1 \3="\4"\n\2 / tPullNodeSpec # before we split on via, move table attribute to beginning of line 2 s/^\([^\n]*\)\n\([^\n]*\) table *\([^\n ]*\)/\1\ntable \3\2/ # if there is a via on line 2 then there are not multiple hops, so split a line 3 # although there could still be some unknown INFO_SPEC on the end. # thus we keep a dev with its preceeding via if we can tSplitVia :SplitVia s/^\([^\n]*\n[^\n]*\) \(via\) /\1\n via / # if this works we need to pull the table entry (if any) from the new line 3 back to line 2 # now with all recognized node-spec from line 2, # if we have 1 dev entry in line 2, (and no vias), we will pull it into main node # There wont be a dev on line 2 if we have multiple hops anyway # Also this depends on the fact that dev appears after a via tPullDev # reset t command :PullDev s/^\([^\n]*\)\n\([^\n]*\)\(dev\) *\([^ ]*\)/\1 \3="\4"\n\2/ tPullDev # whatever is left in line 2 we did not recognize as NODE_SPEC even though it occured before INFO_SPEC # the table declaration should also be in line 2, which we will now recognize # if there is no table declaration then it is table main which we will fake /^[^\n]*\ntable *[^\n ]/!s/\n/\ntable main / # now see if the current table is the same as the active table # ASSERT: The hold space must have exactly 2 lines in it H x /\([^\n]*\)\n[^\n]*\n[^\n]*\ntable \1[ \n]/!{ # different table! # do we need to close a rules tag? /^:/i\ \ </rules> # do we need to open a tables tag? /^:*\n/i\ \ <tables> # do we need to close a table tag? /^[^:\n]/i\ \ \ \ </table> # get rid of table tag s/[^\n]*\n\([^\n]*\n[^\n]*\ntable *\([^ \n]*\)\)/ <table id="\2">\n\2\n\1/ P # strip tag s/^[^\n]*\n// } # and strip current line so we just have table name and original line again s/\n\([^\n]*\).*/\n\1/ x # combine the table tag from line 2 with line 1 s/^\([^\n]*\)\ntable *\([^\n ]*\) */\1\n/ # anything left in line 2 is unrecognized NODE-SPEC. { H x tNodeSpecWarning :NodeSpecWarning # Copy unknown node-spec to line 3 s/^\([^\n]*\)\n *\([^\n]*\n\)[^\n]*\n\([^\n][^\n]*\).*/\2 Warning; Unknown NODE-SPEC attributes: \3 \n\1/ tDoneNodeSpecWarning # There was no warning needed, copy a second line instead of warning s/^\([^\n]*\)\n *\([^\n]*\n\).*/\2\n\1/ :DoneNodeSpecWarning # And if there is no warning, remove the input line unless it is wanted anyway # ADJUST: Comment-out this line to show input lines even if no error s/^\([^\n]*\)\n\n\(.*\)/\n\n\2/ s/ *\n *\n */\n/ /^[^\n].*\n/{ # is there anything to be said? s/^/\n <!-- / s/^\(.*\)\n/\1 -->\n/ # Need to print everything except last line; :NodeSpecWarningPrint P s/^[^\n]*\n// /\n/bNodeSpecWarningPrint } s/.*\n// x } # ASSERT holding space has only 1 line again which is the table name # close the tag on line 1 s/\n/>\n/ # if we dont have anything else to analyse then self-close the tag # is there a none-space character after line 2? tclosing :closing /^[^\n]*\n[^\n]*\n.*[^ \n]/!s/>\n/\/>\n/ P tend # we have to output the different hop tags, chop off first line s/^[^\n]*\n// tvia # reset t command :via # and empty the second line s/^[^\n]*// # if there is nothing left we are done... /^\n./!bdonevia # chop off previous line s/[^\n]*\n// # remember current line for warnings H x s/$/\n/ # Store line after line 1 table name s/\([^\n]*\n[^\n]*\).*/\1/ x # off we go... s/^/ <next-hop\n / tPullNextHop :PullNextHop s/^\([^\n]*\)\n *\([^\n]*\) \(via\|dev\|weight\) *\([^ \n]*\)/\1 \3="\4"\n \2/ tPullNextHop # NH flags s/^\([^\n]*\)\n\([^\n]*\) *\(onlink\|pervasive\)\( .*\|\n.*\|\)$/\1 type="\3"\n \2 \4/ # close the tag s/ *\n/\/>\n/ # if there is anything left in line 2 we need to raise a warning { H x tHopSpecWarning :HopSpecWarning # Copy unknown node-spec to line 3 s/^\([^\n]*\)\n *\([^\n]*\n\)[^\n]*\n *\([^\n ][^\n]*\).*/\2 Warning; Unknown NEXT-HOP attributes: \3\n\1/ tDoneHopSpecWarning # There was no warning needed, copy a blank line s/^\([^\n]*\)\n *\([^\n]*\n\).*/\2\n\1/ :DoneHopSpecWarning # And if there is no warning, remove the input line unless it is wanted anyway # ADJUST: Comment-out this line to show input lines even if no error s/^\([^\n]*\)\n\n\(.*\)/\n\n\2/ s/ *\n *\n */\n/ /^[^\n].*\n/{ # is there anything to be said? s/^/\n <!-- / s/^\(.*\)\n/\1 -->\n/ # Need to print everything except last line; :HopSpecWarningPrint P s/^[^\n]*\n// /\n/bHopSpecWarningPrint } s/.*\n// x } P s/^[^\n]*\n// bvia :donevia i\ \ \ \ \ \ </route> :end } ENDOFSED } iproutexml_xslt() { cat<<'ENDOFXSLT' <?xml version="1.0" encoding="ISO-8859-1"?> <!-- Converts from the ufomechanic simple ip route xml format to ip route commands that could be executed by a shell or shell wrapper --> <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:apply-templates select="/ip-route" /> </xsl:template> <xsl:template name="iproute-arg"> <xsl:param name="arg"/> <xsl:if test="string-length(translate($arg,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:-./','')) != 0"> <xsl:message terminate="yes">Illegal characters in iproute attributes: <xsl:value-of select="$arg"/></xsl:message> </xsl:if> <xsl:value-of select="$arg"/> </xsl:template> <xsl:template name="write-routing-sysctl"> <xsl:param name="name"/> <xsl:param name="value"/> <xsl:if test="string-length($name) and string-length($value)"> <xsl:text>echo </xsl:text> <xsl:value-of select="$value"/> <xsl:text> > </xsl:text> <xsl:value-of select="concat('/proc/sys/net/ipv4/route/',$name)"/> <xsl:text>
</xsl:text> </xsl:if> </xsl:template> <!-- We iterate the rules directly in order, pulling in tables that are called by rules so we can combine the criteria --> <xsl:template match="ip-route"> <xsl:for-each select="@*[name()='error_burst' or name()='gc_elasticity' or name()='gc_min_interval_ms' or name()='max_delay' or name()='min_delay' or name()='redirect_load' or name()='secret_interval' or name()='error_cost' or name()='gc_interval' or name()='gc_thresh' or name()='max_size' or name()='min_pmtu' or name()='redirect_number' or name()='gc_min_interval' or name()='gc_timeout min_adv_mss' or name()='mtu_expires redirect_silence']"> <xsl:call-template name="write-routing-sysctl"> <xsl:with-param name="name" select="name()"/> <xsl:with-param name="value" select="."/> </xsl:call-template> </xsl:for-each> <xsl:apply-templates select="rules/rule[@priority and not(@priority = 0 and (@table='local' or @table=255)) and not(@priority = 32766 and (@table='main' or @table=254)) and not(@priority = 32767 and (@table='default' or @table=253)) ]"/> <xsl:apply-templates select="tables/table[@id!='local' and @id!='default' and @id!='255' and @id!='254']/route[not((../@id='main' or string-length(../@id)=0) and @scope='link')]"/> </xsl:template> <xsl:template match="rules/rule"> <xsl:variable name="rule" select="."/> <xsl:text>ip rule add</xsl:text> <xsl:if test="@from"> <xsl:text> from </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@from"/> </xsl:call-template> </xsl:if> <xsl:if test="@to"> <xsl:text> to </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@to"/> </xsl:call-template> </xsl:if> <xsl:if test="@tos"> <xsl:text> tos </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@tos"/> </xsl:call-template> </xsl:if> <xsl:if test="@fwmark"> <xsl:text> fwmark </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@fwmark"/> </xsl:call-template> </xsl:if> <xsl:if test="@dev"> <xsl:text> dev </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@dev"/> </xsl:call-template> </xsl:if> <xsl:if test="@priority"> <xsl:text> pref </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@priority"/> </xsl:call-template> </xsl:if> <xsl:if test="@table"> <xsl:text> table </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@table"/> </xsl:call-template> </xsl:if> <xsl:if test="@type"> <xsl:text> </xsl:text> <xsl:choose> <xsl:when test="@type='none'"> <xsl:text>0</xsl:text> </xsl:when> <xsl:otherwise test="@type='none'"> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@type"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:if> <xsl:if test="@realm"> <xsl:text> realms </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@realm"/> </xsl:call-template> </xsl:if> <xsl:text>
</xsl:text> </xsl:template> <xsl:template match="tables/table/route"> <xsl:text>ip route add</xsl:text> <xsl:if test="@type"> <xsl:text> </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@type"/> </xsl:call-template> </xsl:if> <xsl:if test="@prefix"> <xsl:text> </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@prefix"/> </xsl:call-template> </xsl:if> <xsl:if test="@dev"> <xsl:text> dev </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@dev"/> </xsl:call-template> </xsl:if> <xsl:if test="@tos"> <xsl:text> tos </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@tos"/> </xsl:call-template> </xsl:if> <xsl:if test="../@id and ../@id != 'main' and string-length(../@id)"> <xsl:text> table </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="../@id"/> </xsl:call-template> </xsl:if> <xsl:if test="@proto"> <xsl:text> proto </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@proto"/> </xsl:call-template> </xsl:if> <xsl:if test="@scope"> <xsl:text> scope </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@scope"/> </xsl:call-template> </xsl:if> <xsl:if test="@src"> <xsl:text> src </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@src"/> </xsl:call-template> </xsl:if> <xsl:if test="@metric"> <xsl:text> metric </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@metric"/> </xsl:call-template> </xsl:if> <xsl:if test="@mtu"> <xsl:text> mtu </xsl:text> <xsl:if test="@mtu-lock='yes' or @mtu-lock='on' or @mtu-lock='1'"> <xsl:text>lock </xsl:text> </xsl:if> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@mtu"/> </xsl:call-template> </xsl:if> <xsl:if test="@advmss"> <xsl:text> advmss </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@advmss"/> </xsl:call-template> </xsl:if> <xsl:if test="@rtt"> <xsl:text> rtt </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="substring-before(@rtt,'ms')"/> </xsl:call-template> </xsl:if> <xsl:if test="@rttvar"> <xsl:text> rttvar </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="substring-before(@rttvar,'ms')"/> </xsl:call-template> </xsl:if> <xsl:if test="@window"> <xsl:text> window </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@window"/> </xsl:call-template> </xsl:if> <xsl:if test="@cwnd"> <xsl:text> cwn </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@cwnd"/> </xsl:call-template> </xsl:if> <xsl:if test="@realm"> <xsl:text> realms </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@realm"/> </xsl:call-template> </xsl:if> <xsl:apply-templates select="next-hop"/> <xsl:text>
</xsl:text> </xsl:template> <xsl:template match="tables/table/route/next-hop"> <xsl:text> nexthop</xsl:text> <xsl:if test="@via"> <xsl:text> via </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@via"/> </xsl:call-template> </xsl:if> <!-- don't output dev unless onlink, because interfaces may have changed, so make route look it up --> <xsl:if test="@dev and @type"> <xsl:text> dev </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@dev"/> </xsl:call-template> </xsl:if> <xsl:if test="@weight"> <xsl:text> weight </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@weight"/> </xsl:call-template> </xsl:if> <xsl:if test="@type"> <xsl:text> </xsl:text> <xsl:call-template name="iproute-arg"> <xsl:with-param name="arg" select="@type"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:transform> ENDOFXSLT } main "$@"
_______________________________________________ LARTC mailing list LARTC@xxxxxxxxxxxxxxx http://mailman.ds9a.nl/cgi-bin/mailman/listinfo/lartc