ip: rewrite routel in python

Not sure if anyone uses the routel script. The script was
a combination of ip route, shell and awk doing command scraping.
It is now possible to do this much better using the JSON
output formats and python.

Rewriting also fixes the bug where the old script could not parse
the current output format.  At the end was getting:
/usr/bin/routel: 48: shift: can't shift that many

The new script also has IPv6 as option.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
Stephen Hemminger 2021-09-01 13:47:01 -07:00 committed by David Ahern
parent 1eaebad2c5
commit 6d676ad934
2 changed files with 79 additions and 75 deletions

124
ip/routel
View File

@ -1,72 +1,62 @@
#!/bin/sh #! /usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
#
# Script created by: Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18
# Donated to the public domain.
#
# This script transforms the output of "ip" into more readable text.
# "ip" is the Linux-advanced-routing configuration tool part of the
# iproute package.
# #
# This is simple script to process JSON output from ip route
# command and format it. Based on earlier shell script version.
"""Script to parse ip route output into more readable text."""
test "X-h" = "X$1" && echo "Usage: $0 [tablenr [raw ip args...]]" && exit 64 import sys
import json
import getopt
import subprocess
test -z "$*" && set 0
ip route list table "$@" | def usage():
while read network rest '''Print usage and exit'''
do set xx $rest print("Usage: {} [tablenr [raw ip args...]]".format(sys.argv[0]))
shift sys.exit(64)
proto=""
via=""
dev="" def main():
scope="" '''Process the arguments'''
src="" family = 'inet'
table="" try:
case $network in opts, args = getopt.getopt(sys.argv[1:], "h46f:", ["help", "family="])
broadcast|local|unreachable) via=$network except getopt.GetoptError as err:
network=$1 print(err)
shift usage()
;;
esac for opt, arg in opts:
while test $# != 0 if opt in ["-h", "--help"]:
do usage()
case "$1" in elif opt == '-6':
proto|via|dev|scope|src|table) family = 'inet6'
key=$1 elif opt == "-4":
val=$2 family = 'inet'
eval "$key='$val'" elif opt in ["-f", "--family"]:
shift 2 family = arg
;; else:
dead|onlink|pervasive|offload|notify|linkdown|unresolved) assert False, "unhandled option"
shift
;; if not args:
*) args = ['0']
# avoid infinite loop on unknown keyword without value at line end
shift cmd = ['ip', '-f', family, '-j', 'route', 'list', 'table'] + args
shift process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
;; tbl = json.load(process.stdout)
esac if family == 'inet':
done fmt = '{:15} {:15} {:15} {:8} {:8}{:<16} {}'
echo "$network $via $src $proto $scope $dev $table" else:
done | awk -F ' ' ' fmt = '{:32} {:32} {:32} {:8} {:8}{:<16} {}'
BEGIN {
format="%15s%-3s %15s %15s %8s %8s%7s %s\n"; # ip route json keys
printf(format,"target","","gateway","source","proto","scope","dev","tbl"); keys = ['dst', 'gateway', 'prefsrc', 'protocol', 'scope', 'dev', 'table']
} print(fmt.format(*map(lambda x: x.capitalize(), keys)))
{ network=$1;
mask=""; for record in tbl:
if(match(network,"/")) fields = [record[k] if k in record else '' for k in keys]
{ mask=" "substr(network,RSTART+1); print(fmt.format(*fields))
network=substr(network,0,RSTART);
}
via=$2; if __name__ == "__main__":
src=$3; main()
proto=$4;
scope=$5;
dev=$6;
table=$7;
printf(format,network,mask,via,src,proto,scope,dev,table);
}
'

View File

@ -1,17 +1,31 @@
.TH "ROUTEL" "8" "3 Jan, 2008" "iproute2" "Linux" .TH ROUTEL 8 "1 Sept, 2021" "iproute2" "Linux"
.SH "NAME" .SH "NAME"
.LP
routel \- list routes with pretty output format routel \- list routes with pretty output format
.SH "SYNTAX" .SH SYNOPSIS
.LP .B routel
routel [\fItablenr\fP [\fIraw ip args...\fP]] .RI "[ " OPTIONS " ]"
.RI "[ " tablenr
[ \fIip route options...\fR ] ]
.P
.ti 8
.IR OPTIONS " := {"
\fB-h\fR | \fB--help\fR |
[{\fB-f\fR | \fB--family\fR }
{\fBinet\fR | \fBinet6\fR } |
\fB-4\fR | \fB-6\fR }
.SH "DESCRIPTION" .SH "DESCRIPTION"
.LP .LP
The routel script will list routes in a format that some might consider easier to interpret The routel script will list routes in a format that some might consider
then the ip route list equivalent. easier to interpret then the
.B ip
route list equivalent.
.SH "AUTHORS" .SH "AUTHORS"
.LP .LP
The routel script was written by Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18 and donated to the public domain. Rewritten by Stephen Hemminger <stephen@networkplumber.org>.
.br
Original script by Stephen R. van den Berg <srb@cuci.nl>.
.br .br
This manual page was written by Andreas Henriksson <andreas@fatal.se>, for the Debian GNU/Linux system. This manual page was written by Andreas Henriksson <andreas@fatal.se>, for the Debian GNU/Linux system.
.SH "SEE ALSO" .SH "SEE ALSO"