1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-12 09:18:10 +03:00
samba-mirror/ctdb/tests/eventscripts/stubs/ip
Martin Schwenke 86f6481e99 ctdb-tests: Avoid creating files in /tmp.
Temporary test data should all go somewhere under TEST_VAR_DIR instead
of in the global /tmp.  The existing mktemp could be changed so the
data goes into the test directory but mktemp is overkill in this case.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2018-03-01 19:39:15 +01:00

677 lines
15 KiB
Bash
Executable File

#!/bin/sh
promote_secondaries=true
not_implemented ()
{
echo "ip stub command: \"$1\" not implemented"
exit 127
}
######################################################################
ip_link ()
{
case "$1" in
set)
shift
# iface="$1"
case "$2" in
up) ip_link_set_up "$1" ;;
down) ip_link_down_up "$1" ;;
*) not_implemented "\"$2\" in \"$orig_args\"" ;;
esac
;;
show) shift ; ip_link_show "$@" ;;
add*) shift ; ip_link_add "$@" ;;
del*) shift ; ip_link_delete "$@" ;;
*) not_implemented "$*" ;;
esac
}
ip_link_add ()
{
_link=""
_name=""
_type=""
while [ -n "$1" ] ; do
case "$1" in
link)
_link="$2"
shift 2
;;
name)
_name="$2"
shift 2
;;
type)
if [ "$2" != "vlan" ] ; then
not_implemented "link type $1"
fi
_type="$2"
shift 2
;;
id) shift 2 ;;
*) not_implemented "$1" ;;
esac
done
case "$_type" in
vlan)
if [ -z "$_name" -o -z "$_link" ] ; then
not_implemented "ip link add with null name or link"
fi
mkdir -p "${FAKE_IP_STATE}/interfaces-vlan"
echo "$_link" >"${FAKE_IP_STATE}/interfaces-vlan/${_name}"
ip_link_set_down "$_name"
;;
esac
}
ip_link_delete ()
{
mkdir -p "${FAKE_IP_STATE}/interfaces-deleted"
touch "${FAKE_IP_STATE}/interfaces-deleted/$1"
rm -f "${FAKE_IP_STATE}/interfaces-vlan/$1"
}
ip_link_set_up ()
{
rm -f "${FAKE_IP_STATE}/interfaces-down/$1"
rm -f "${FAKE_IP_STATE}/interfaces-deleted/$1"
}
ip_link_set_down ()
{
rm -f "${FAKE_IP_STATE}/interfaces-deleted/$1"
mkdir -p "${FAKE_IP_STATE}/interfaces-down"
touch "${FAKE_IP_STATE}/interfaces-down/$1"
}
ip_link_show ()
{
dev="$1"
if [ "$dev" = "dev" -a -n "$2" ] ; then
dev="$2"
fi
if [ -e "${FAKE_IP_STATE}/interfaces-deleted/$dev" ] ; then
echo "Device \"${dev}\" does not exist." >&2
exit 255
fi
if [ -r "${FAKE_IP_STATE}/interfaces-vlan/${dev}" ] ; then
read _link <"${FAKE_IP_STATE}/interfaces-vlan/${dev}"
dev="${dev}@${_link}"
fi
_state="UP"
_flags=",UP,LOWER_UP"
if [ -e "${FAKE_IP_STATE}/interfaces-down/$dev" ] ; then
_state="DOWN"
_flags=""
fi
case "$dev" in
lo)
_mac="00:00:00:00:00:00"
_brd="00:00:00:00:00:00"
_type="loopback"
_opts="<LOOPBACK${_flags}> mtu 65536 qdisc noqueue state UNKNOWN"
;;
*)
_mac=$(echo $dev | md5sum | sed -r -e 's@(..)(..)(..)(..)(..)(..).*@\1:\2:\3:\4:\5:\6@')
_brd="ff:ff:ff:ff:ff:ff"
_type="ether"
_opts="<BROADCAST,MULTICAST${_flags}> mtu 1500 qdisc pfifo_fast state ${_state} qlen 1000"
esac
echo "${n:-42}: ${dev}: ${_opts}"
echo " link/${_type} ${_mac} brd ${_brd}"
}
# This is incomplete because it doesn't actually look up table ids in
# /etc/iproute2/rt_tables. The rules/routes are actually associated
# with the name instead of the number. However, we include a variable
# to fake a bad table id.
[ -n "$IP_ROUTE_BAD_TABLE_ID" ] || IP_ROUTE_BAD_TABLE_ID=false
ip_check_table ()
{
_cmd="$1"
if [ "$_cmd" = "route" -a -z "$_table" ] ;then
_table="main"
fi
[ -n "$_table" ] || not_implemented "ip rule/route without \"table\""
# Only allow tables names from 13.per_ip_routing and "main". This
# is a cheap way of avoiding implementing the default/local
# tables.
case "$_table" in
ctdb.*|main)
if $IP_ROUTE_BAD_TABLE_ID ; then
# Ouch. Simulate inconsistent errors from ip. :-(
case "$_cmd" in
route)
echo "Error: argument "${_table}" is wrong: table id value is invalid" >&2
;;
*)
echo "Error: argument "${_table}" is wrong: invalid table ID" >&2
esac
exit 255
fi
;;
*) not_implemented "table=${_table} ${orig_args}" ;;
esac
}
######################################################################
ip_addr ()
{
case "$1" in
show|list|"") shift ; ip_addr_show "$@" ;;
add*) shift ; ip_addr_add "$@" ;;
del*) shift ; ip_addr_del "$@" ;;
*) not_implemented "\"$1\" in \"$orig_args\"" ;;
esac
}
ip_addr_show ()
{
dev=""
primary=true
secondary=true
_to=""
while [ -n "$1" ] ; do
case "$1" in
dev)
dev="$2" ; shift 2
;;
# Do stupid things and stupid things will happen!
primary)
primary=true ; secondary=false ; shift
;;
secondary)
secondary=true ; primary=false ; shift
;;
to)
_to="$2" ; shift 2
;;
*)
# Assume an interface name
dev="$1" ; shift 1
esac
done
devices="$dev"
if [ -z "$devices" ] ; then
# No device specified? Get all the primaries...
devices=$(ls "${FAKE_IP_STATE}/addresses/"*-primary 2>/dev/null | \
sed -e 's@.*/@@' -e 's@-.*-primary$@@' | sort -u)
fi
calc_brd ()
{
case "${local#*/}" in
24) brd="${local%.*}.255" ;;
32) brd="" ;;
*) not_implemented "list ... fake bits other than 24/32: ${local#*/}"
esac
}
show_iface()
{
ip_link_show "$dev"
nets=$(ls "${FAKE_IP_STATE}/addresses/${dev}"-*-primary 2>/dev/null | \
sed -e 's@.*/@@' -e "s@${dev}-\(.*\)-primary\$@\1@")
for net in $nets ; do
pf="${FAKE_IP_STATE}/addresses/${dev}-${net}-primary"
sf="${FAKE_IP_STATE}/addresses/${dev}-${net}-secondary"
if $primary && [ -r "$pf" ] ; then
read local scope <"$pf"
if [ -z "$_to" -o "${_to%/*}" = "${local%/*}" ] ; then
calc_brd
echo " inet ${local} ${brd:+brd ${brd} }scope ${scope} ${dev}"
fi
fi
if $secondary && [ -r "$sf" ] ; then
while read local scope ; do
if [ -z "$_to" -o "${_to%/*}" = "${local%/*}" ] ; then
calc_brd
echo " inet ${local} ${brd:+brd }${brd} scope ${scope} secondary ${dev}"
fi
done <"$sf"
fi
if [ -z "$_to" ] ; then
echo " valid_lft forever preferred_lft forever"
fi
done
}
n=1
for dev in $devices ; do
if [ -z "$_to" ] || \
grep -F "${_to%/*}/" "${FAKE_IP_STATE}/addresses/${dev}-"* >/dev/null ; then
show_iface
fi
n=$(($n + 1))
done
}
# Copied from 13.per_ip_routing for now... so this is lazy testing :-(
ipv4_host_addr_to_net ()
{
_host="$1"
_maskbits="$2"
# Convert the host address to an unsigned long by splitting out
# the octets and doing the math.
_host_ul=0
for _o in $(export IFS="." ; echo $_host) ; do
_host_ul=$(( ($_host_ul << 8) + $_o)) # work around Emacs color bug
done
# Calculate the mask and apply it.
_mask_ul=$(( 0xffffffff << (32 - $_maskbits) ))
_net_ul=$(( $_host_ul & $_mask_ul ))
# Now convert to a network address one byte at a time.
_net=""
for _o in $(seq 1 4) ; do
_net="$(($_net_ul & 255))${_net:+.}${_net}"
_net_ul=$(($_net_ul >> 8))
done
echo "${_net}/${_maskbits}"
}
ip_addr_add ()
{
local=""
dev=""
brd=""
scope="global"
while [ -n "$1" ] ; do
case "$1" in
*.*.*.*/*)
local="$1" ; shift
;;
local)
local="$2" ; shift 2
;;
broadcast|brd)
# For now assume this is always '+'.
if [ "$2" != "+" ] ; then
not_implemented "addr add ... brd $2 ..."
fi
shift 2
;;
dev)
dev="$2" ; shift 2
;;
scope)
scope="$2" ; shift 2
;;
*)
not_implemented "$@"
esac
done
if [ -z "$dev" ] ; then
not_implemented "addr add (without dev)"
fi
mkdir -p "${FAKE_IP_STATE}/addresses"
net_str=$(ipv4_host_addr_to_net $(IFS="/" ; echo $local))
net_str=$(echo "$net_str" | sed -e 's@/@_@')
pf="${FAKE_IP_STATE}/addresses/${dev}-${net_str}-primary"
sf="${FAKE_IP_STATE}/addresses/${dev}-${net_str}-secondary"
# We could lock here... but we should be the only ones playing
# around here with these stubs.
if [ ! -f "$pf" ] ; then
echo "$local $scope" >"$pf"
elif grep -Fq "$local" "$pf" ; then
echo "RTNETLINK answers: File exists" >&2
exit 254
elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then
echo "RTNETLINK answers: File exists" >&2
exit 254
else
echo "$local $scope" >>"$sf"
fi
}
ip_addr_del ()
{
local=""
dev=""
while [ -n "$1" ] ; do
case "$1" in
*.*.*.*/*)
local="$1" ; shift
;;
local)
local="$2" ; shift 2
;;
dev)
dev="$2" ; shift 2
;;
*)
not_implemented "addr del ... $1 ..."
esac
done
if [ -z "$dev" ] ; then
not_implemented "addr del (without dev)"
fi
mkdir -p "${FAKE_IP_STATE}/addresses"
net_str=$(ipv4_host_addr_to_net $(IFS="/" ; echo $local))
net_str=$(echo "$net_str" | sed -e 's@/@_@')
pf="${FAKE_IP_STATE}/addresses/${dev}-${net_str}-primary"
sf="${FAKE_IP_STATE}/addresses/${dev}-${net_str}-secondary"
# We could lock here... but we should be the only ones playing
# around here with these stubs.
if [ ! -f "$pf" ] ; then
echo "RTNETLINK answers: Cannot assign requested address" >&2
exit 254
elif grep -Fq "$local" "$pf" ; then
if $promote_secondaries && [ -s "$sf" ] ; then
head -n 1 "$sf" >"$pf"
sed -i -e '1d' "$sf"
else
# Remove primaries AND SECONDARIES.
rm -f "$pf" "$sf"
fi
elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then
grep -Fv "$local" "$sf" >"${sf}.new"
mv "${sf}.new" "$sf"
else
echo "RTNETLINK answers: Cannot assign requested address" >&2
exit 254
fi
}
######################################################################
ip_rule ()
{
case "$1" in
show|list|"") shift ; ip_rule_show "$@" ;;
add) shift ; ip_rule_add "$@" ;;
del*) shift ; ip_rule_del "$@" ;;
*) not_implemented "$1 in \"$orig_args\"" ;;
esac
}
# All non-default rules are in $FAKE_IP_STATE_RULES/rules. As with
# the real version, rules can be repeated. Deleting just deletes the
# 1st match.
ip_rule_show ()
{
ip_rule_show_1 ()
{
_pre="$1"
_table="$2"
_selectors="$3"
# potentially more options
printf "%d:\t%s lookup %s \n" $_pre "$_selectors" "$_table"
}
ip_rule_show_some ()
{
_min="$1"
_max="$2"
[ -f "${FAKE_IP_STATE}/rules" ] || return
while read _pre _table _selectors ; do
# Only print those in range
[ $_min -le $_pre -a $_pre -le $_max ] || continue
ip_rule_show_1 $_pre "$_table" "$_selectors"
done <"${FAKE_IP_STATE}/rules"
}
ip_rule_show_1 0 "local" "from all"
ip_rule_show_some 1 32765
ip_rule_show_1 32766 "main" "from all"
ip_rule_show_1 32767 "default" "from all"
ip_rule_show_some 32768 2147483648
}
ip_rule_common ()
{
_from=""
_pre=""
_table=""
while [ -n "$1" ] ; do
case "$1" in
from) _from="$2" ; shift 2 ;;
pref) _pre="$2" ; shift 2 ;;
table) _table="$2" ; shift 2 ;;
*) not_implemented "$1 in \"$orig_args\"" ;;
esac
done
[ -n "$_pre" ] || not_implemented "ip rule without \"pref\""
ip_check_table "rule"
# Relax this if more selectors added later...
[ -n "$_from" ] || not_implemented "ip rule without \"from\""
}
ip_rule_add ()
{
ip_rule_common "$@"
_f="${FAKE_IP_STATE}/rules"
touch "$_f"
(
flock 0
# Filter order must be consistent with the comparison in ip_rule_del()
echo "$_pre $_table${_from:+ from }$_from" >>"$_f"
) <"$_f"
}
ip_rule_del ()
{
ip_rule_common "$@"
_f="${FAKE_IP_STATE}/rules"
touch "$_f"
(
flock 0
_tmp="${_f}.new"
: >"$_tmp"
_found=false
while read _p _t _s ; do
if ! $_found && \
[ "$_p" = "$_pre" -a "$_t" = "$_table" -a \
"$_s" = "${_from:+from }$_from" ] ; then
# Found. Skip this one but not future ones.
_found=true
else
echo "$_p $_t $_s" >>"$_tmp"
fi
done
if cmp -s "$_tmp" "$_f" ; then
# No changes, must not have found what we wanted to delete
echo "RTNETLINK answers: No such file or directory" >&2
rm -f "$_tmp"
exit 2
else
mv "$_tmp" "$_f"
fi
) <"$_f" || exit $?
}
######################################################################
ip_route ()
{
case "$1" in
show|list) shift ; ip_route_show "$@" ;;
flush) shift ; ip_route_flush "$@" ;;
add) shift ; ip_route_add "$@" ;;
del*) shift ; ip_route_del "$@" ;;
*) not_implemented "$1 in \"ip route\"" ;;
esac
}
ip_route_common ()
{
if [ "$1" = table ] ; then
_table="$2"
shift 2
fi
ip_check_table "route"
}
# Routes are in a file per table in the directory
# $FAKE_IP_STATE/routes. These routes just use the table ID
# that is passed and don't do any lookup. This could be "improved" if
# necessary.
ip_route_show ()
{
ip_route_common "$@"
# Missing file is just an empty table
sort "$FAKE_IP_STATE/routes/${_table}" 2>/dev/null || true
}
ip_route_flush ()
{
ip_route_common "$@"
rm -f "$FAKE_IP_STATE/routes/${_table}"
}
ip_route_add ()
{
_prefix=""
_dev=""
_gw=""
_table=""
_metric=""
while [ -n "$1" ] ; do
case "$1" in
*.*.*.*/*|*.*.*.*) _prefix="$1" ; shift 1 ;;
local) _prefix="$2" ; shift 2 ;;
dev) _dev="$2" ; shift 2 ;;
via) _gw="$2" ; shift 2 ;;
table) _table="$2" ; shift 2 ;;
metric) _metric="$2" ; shift 2 ;;
*) not_implemented "$1 in \"$orig_args\"" ;;
esac
done
ip_check_table "route"
[ -n "$_prefix" ] || not_implemented "ip route without inet prefix in \"$orig_args\""
# This can't be easily deduced, so print some garbage.
[ -n "$_dev" ] || _dev="ethXXX"
# Alias or add missing bits
case "$_prefix" in
0.0.0.0/0) _prefix="default" ;;
*/*) : ;;
*) _prefix="${_prefix}/32" ;;
esac
_f="$FAKE_IP_STATE/routes/${_table}"
mkdir -p "$FAKE_IP_STATE/routes"
touch "$_f"
# Check for duplicate
_prefix_regexp=$(echo "^${_prefix}" | sed -e 's@\.@\\.@g')
if [ -n "$_metric" ] ; then
_prefix_regexp="${_prefix_regexp} .*metric ${_metric} "
fi
if grep -q "$_prefix_regexp" "$_f" ; then
echo "RTNETLINK answers: File exists" >&2
exit 1
fi
(
flock 0
_out="${_prefix} "
[ -z "$_gw" ] || _out="${_out}via ${_gw} "
[ -z "$_dev" ] || _out="${_out}dev ${_dev} "
[ -n "$_gw" ] || _out="${_out} scope link "
[ -z "$_metric" ] || _out="${_out} metric ${_metric} "
echo "$_out" >>"$_f"
) <"$_f"
}
ip_route_del ()
{
_prefix=""
_dev=""
_gw=""
_table=""
_metric=""
while [ -n "$1" ] ; do
case "$1" in
*.*.*.*/*|*.*.*.*) _prefix="$1" ; shift 1 ;;
local) _prefix="$2" ; shift 2 ;;
dev) _dev="$2" ; shift 2 ;;
via) _gw="$2" ; shift 2 ;;
table) _table="$2" ; shift 2 ;;
metric) _metric="$2" ; shift 2 ;;
*) not_implemented "$1 in \"$orig_args\"" ;;
esac
done
ip_check_table "route"
[ -n "$_prefix" ] || not_implemented "ip route without inet prefix in \"$orig_args\""
# This can't be easily deduced, so print some garbage.
[ -n "$_dev" ] || _dev="ethXXX"
# Alias or add missing bits
case "$_prefix" in
0.0.0.0/0) _prefix="default" ;;
*/*) : ;;
*) _prefix="${_prefix}/32" ;;
esac
_f="$FAKE_IP_STATE/routes/${_table}"
mkdir -p "$FAKE_IP_STATE/routes"
touch "$_f"
(
flock 0
# Escape some dots
[ -z "$_gw" ] || _gw=$(echo "$_gw" | sed -e 's@\.@\\.@g')
_prefix=$(echo "$_prefix" | sed -e 's@\.@\\.@g' -e 's@/@\\/@')
_re="^${_prefix}\>.*"
[ -z "$_gw" ] || _re="${_re}\<via ${_gw}\>.*"
[ -z "$_dev" ] || _re="${_re}\<dev ${_dev}\>.*"
[ -z "$_metric" ] || _re="${_re}.*\<metric ${_metric}\>.*"
sed -i -e "/${_re}/d" "$_f"
) <"$_f"
}
######################################################################
orig_args="$*"
case "$1" in
link) shift ; ip_link "$@" ;;
addr*) shift ; ip_addr "$@" ;;
rule) shift ; ip_rule "$@" ;;
route) shift ; ip_route "$@" ;;
*) not_implemented "$1" ;;
esac
exit 0