Commit dc72ce25 authored by Vitaly Lipatov's avatar Vitaly Lipatov

route-update.sh: derive table from rt_tables/IP, add options file with set-default

Table number is now resolved by: 1) legacy table file, 2) rt_tables by group name, 3) last octet of gateway IP (auto-registered in rt_tables). New options file support: set-default flag sets system default route via group's gateway. Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 93c3037e
......@@ -70,10 +70,20 @@ MODES OF OPERATION:
DIRECTORY STRUCTURE:
routes.d/GROUP/gateway Gateway IP(s), one per line. "default" = default gw.
Multiple lines = multipath (per-flow balancing).
routes.d/GROUP/table Routing table number. ip rule pref = table × 10.
routes.d/GROUP/options Optional flags, one per line:
set-default Also set system default route via gateway.
routes.d/GROUP/table (legacy) Routing table number override.
routes.d/GROUP/*.list Symlinks to files with IPs, subnets, or domains.
routes6.d/ Same structure for IPv6 groups.
TABLE RESOLUTION:
Table number is determined by (in order):
1. routes.d/GROUP/table file (legacy, if present)
2. /etc/iproute2/rt_tables entry matching GROUP name
3. Last numeric component of gateway IP (e.g. 91.232.225.122 → 122),
auto-registered in rt_tables for future use.
ip rule pref = table_number × 10.
EXAMPLES:
./route-update.sh # normal run
./route-update.sh --resolve -v # re-resolve DNS, verbose
......@@ -127,17 +137,55 @@ resolve_default_gw()
$1 route show default | awk '/default/ {print $3; exit}'
}
# Look up table number: first from rt_tables by name, then from last IP octet
# If derived from IP, auto-creates entry in rt_tables
# Usage: lookup_table NAME GATEWAY
lookup_table()
{
local name="$1"
local gateway="$2"
# Try rt_tables first
local num=$(awk -v n="$name" '$2 == n { print $1; exit }' /etc/iproute2/rt_tables 2>/dev/null)
if [ -n "$num" ] ; then
echo "$num"
return
fi
# Fallback: last component of gateway IP
# IPv4: 91.232.225.122 → 122
# IPv6: 2a03:5a00:c:20::122 → 122
num=$(echo "$gateway" | sed -E 's/.*[.:]([0-9]+)$/\1/')
# Auto-register in rt_tables
if [ -n "$num" ] ; then
echo "$num $name" >> /etc/iproute2/rt_tables
vlog "Added rt_tables entry: $num $name"
fi
echo "$num"
}
# Check if option is set in group's options file
# Usage: has_option DIR OPTION
has_option()
{
[ -f "$1/options" ] && grep -q "^$2$" "$1/options" 2>/dev/null
}
# Read gateway and table from a group directory
# Sets: gw, table, route_via
# Sets: gw, table, route_via, opt_set_default
# gw - first gateway (for display and IPv4/v6 detection)
# table - routing table number
# table - routing table number (from rt_tables or last IP octet)
# route_via - route suffix: "via GW table T" or "table T nexthop via GW1 ... nexthop via GW2 ..."
# opt_set_default - "1" if set-default option is enabled
# $1 - directory, $2 - ip command ("ip" or "ip -6")
read_group_config()
{
local dir="$1"
local ipcmd="${2:-ip}"
gw="" ; table="" ; route_via=""
local name=$(basename "$dir")
gw="" ; table="" ; route_via="" ; opt_set_default=""
if [ -f "$dir/gateway" ] ; then
gw=$(grep -v '^#' "$dir/gateway" | grep -m1 .)
......@@ -145,17 +193,25 @@ read_group_config()
gw=$(resolve_default_gw "$ipcmd")
fi
else
echo "[$(basename "$dir")] No gateway file, skipping" >&2
echo "[$name] No gateway file, skipping" >&2
return 1
fi
# Table from file (legacy) or by name lookup
if [ -f "$dir/table" ] ; then
table=$(grep -v '^#' "$dir/table" | grep -m1 .)
else
echo "[$(basename "$dir")] No table file, skipping" >&2
table=$(lookup_table "$name" "$gw")
fi
if [ -z "$table" ] ; then
echo "[$name] Cannot determine table number, skipping" >&2
return 1
fi
# Options
has_option "$dir" "set-default" && opt_set_default=1
# Build route suffix: single vs multipath
local gw_count=$(grep -v '^#' "$dir/gateway" | grep -c .)
if [ "$gw_count" -le 1 ] ; then
......@@ -267,8 +323,8 @@ process_routes()
continue
fi
# Compute hash of all list contents + gateway + table
local current_hash=$(md5_lists "$gwdir/gateway" "$gwdir/table" $lists)
# Compute hash of all list contents + gateway + options
local current_hash=$(md5_lists "$gwdir/gateway" "$gwdir/options" $lists)
if [ -z "$FORCE" ] && [ -z "$RESOLVE" ] && [ -f "$STATE_DIR/$state/hash" ] ; then
local saved_hash
......@@ -363,6 +419,7 @@ process_routes()
echo " Would flush table $table and load $count routes"
head -5 "$resolved_new" | sed 's/^/ /'
[ "$count" -gt 5 ] && echo " ... ($count total)"
[ -n "$opt_set_default" ] && echo " Would set default route via $gw"
rm -f "$resolved_new"
continue
fi
......@@ -378,6 +435,17 @@ process_routes()
$ipcmd rule add lookup "$table" pref "$pref" 2>/dev/null
fi
# Set default route in main table if requested
if [ -n "$opt_set_default" ] ; then
local cur_default=$($ipcmd route show default | awk '/default/ {print $3; exit}')
if [ "$cur_default" != "$gw" ] ; then
log "[$name]$label Setting default route via $gw"
$ipcmd route replace default via "$gw"
else
vlog "[$name]$label default route already via $gw"
fi
fi
# Save state
echo "$current_hash" > "$STATE_DIR/$state/hash"
echo "$table" > "$STATE_DIR/$state/table"
......@@ -427,6 +495,13 @@ if [ -n "$SET_RULES" ] ; then
if ! $ipcmd -N rule show | grep -q "lookup $table.*pref $pref" ; then
$ipcmd rule add lookup "$table" pref "$pref"
fi
# Also restore default route if set-default
if [ -n "$opt_set_default" ] ; then
local cur_default=$($ipcmd route show default | awk '/default/ {print $3; exit}')
if [ "$cur_default" != "$gw" ] ; then
$ipcmd route replace default via "$gw"
fi
fi
done
done
exit
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment