mirror of
https://github.com/samba-team/samba.git
synced 2025-03-23 06:50:21 +03:00
Eventscripts - redesign and rewrite 13.per_ip_routing
The current version is quite difficult to read. This one is hopefully clearer. Major changes: * The configuration file has a more forgiving syntax. Items can be separated by arbitrary whitespace. * Mappings between IP addresses and table IDs are no longer stored in files in a state directory. Instead they are stored in /etc/iproute2/rt_tables as mappings between table IDs and labels, as allowed by the ip command. The current structure of the labels is ctdb.<source-ip>. This means that once the labels are setup the routing tables can be referenced by just knowing the source IP. As with the old state directory, mappings in this file owned by CTDB are deleted when CTDB shuts down. * There are no release or re-add scripts. - Release scripts are not necessary as an optimisation because of the previous improvement (i.e. use of rt_tables). No lookup is necessary to delete rules or flush tables. - Re-add scripts are no longer used. Routes can still go missing when removal of a primary IP from an interfaces (or similar) causes removal of all other addresses (i.e. secondaries) and also all associated routes. However, any missing routes are now re-added in the "ipreallocated" event. This happens shortly after takeip/releaseip/updateip and means that the routes will only be re-added once. The window for missing routes is slightly bigger but is not expected to be significant. * The magic "__auto_link_local__" configuration value no longer causes a dynamic configuration file to be maintained in a state directory. The link local configuration is now generated when needed from the public_addresses file. This greatly simplifies the code. This approach is slightly less efficient but should not be significant. The above changes mean that, apart from maintaining mappings in the rt_tables file, there are no state files kept anymore. Some utility functions only used by this script have been rewritten and moved into this script. They will be removed from the functions file by a future commit. The route re-add code will also be removed from interface_modify.sh by a future commit. It is currently harmless. Signed-off-by: Martin Schwenke <martin@meltin.net> (This used to be ctdb commit 0f7cbbb55f26cf3c953e98fe5e7eaa12f59fbf78)
This commit is contained in:
parent
0d67779c67
commit
95e10b20cb
@ -3,492 +3,345 @@
|
||||
. $CTDB_BASE/functions
|
||||
loadconfig
|
||||
|
||||
ctdb_setup_service_state_dir "per_ip_routing"
|
||||
# Do nothing if unconfigured
|
||||
[ -n "$CTDB_PER_IP_ROUTING_CONF" ] || exit 0
|
||||
|
||||
[ -z "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
CTDB_PER_IP_ROUTING_STATE="$service_state_dir"
|
||||
}
|
||||
table_id_prefix="ctdb."
|
||||
|
||||
AUTO_LINK_LOCAL="no"
|
||||
[ -n "$CTDB_PER_IP_ROUTING_RULE_PREF" ] || \
|
||||
die "error: CTDB_PER_IP_ROUTING_RULE_PREF not configured"
|
||||
|
||||
case "$CTDB_PER_IP_ROUTING_CONF" in
|
||||
__auto_link_local__)
|
||||
AUTO_LINK_LOCAL="yes"
|
||||
CTDB_PER_IP_ROUTING_CONF="$CTDB_PER_IP_ROUTING_STATE/auto_link_local.conf"
|
||||
;;
|
||||
*)
|
||||
[ -z "$CTDB_PER_IP_ROUTING_CONF" ] && {
|
||||
#echo "No config file found. Nothing to do for 13.per_ip_routing"
|
||||
exit 0;
|
||||
}
|
||||
;;
|
||||
esac
|
||||
[ "$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" -lt "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] 2>/dev/null || \
|
||||
die "error: CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$CTDB_PER_IP_ROUTING_TABLE_ID_LOW] and/or CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH] improperly configured"
|
||||
|
||||
_low=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW
|
||||
_high=$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH
|
||||
######################################################################
|
||||
|
||||
test -z "$_low" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_LOW not configured";
|
||||
exit 1;
|
||||
}
|
||||
test -z "$_high" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_HIGH not configured";
|
||||
exit 1;
|
||||
}
|
||||
test "$_low" -ge "$_high" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$_low] needs to be below CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$_high]";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
test -z "$CTDB_PER_IP_ROUTING_RULE_PREF" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_RULE_PREF not configured";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
locknesting=0
|
||||
lock_root="$CTDB_PER_IP_ROUTING_STATE"
|
||||
host=`hostname`
|
||||
|
||||
lock_debug()
|
||||
ipv4_is_valid_addr()
|
||||
{
|
||||
echo -n ""
|
||||
_ip="$1"
|
||||
|
||||
_count=0
|
||||
# Get the shell to break up the address into 1 word per octet
|
||||
for _o in $(export IFS="." ; echo $_ip) ; do
|
||||
# The 2>/dev/null stops output from failures where an "octet"
|
||||
# is not numeric. The test will still fail.
|
||||
if ! [ 0 -le $_o -a $_o -le 255 ] 2>/dev/null ; then
|
||||
return 1
|
||||
fi
|
||||
_count=$(($_count + 1))
|
||||
done
|
||||
|
||||
# A valid IPv4 address has 4 octets
|
||||
[ $_count -eq 4 ]
|
||||
}
|
||||
|
||||
############################
|
||||
# grab a lock file. Not atomic, but close :)
|
||||
# tries to cope with NFS
|
||||
lock_file() {
|
||||
if [ -z "$lock_root" ]; then
|
||||
lock_root=`pwd`;
|
||||
fi
|
||||
lckf="$lock_root/$1"
|
||||
machine=`cat "$lckf" 2> /dev/null | cut -d: -f1`
|
||||
pid=`cat "$lckf" 2> /dev/null | cut -d: -f2`
|
||||
ensure_ipv4_is_valid_addr ()
|
||||
{
|
||||
_event="$1"
|
||||
_ip="$2"
|
||||
|
||||
if [ "$pid" = "$$" ]; then
|
||||
locknesting=`expr $locknesting + 1`
|
||||
lock_debug "lock nesting now $locknesting"
|
||||
ipv4_is_valid_addr "$_ip" || {
|
||||
echo "$0: $_event not an ipv4 address skipping IP:$_ip"
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
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}"
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
# Setup a table id to use for the given IP. We don't need to know it,
|
||||
# it just needs to exist in /etc/iproute2/rt_tables. Fail if no free
|
||||
# table id could be found in the configured range.
|
||||
ensure_table_id_for_ip ()
|
||||
{
|
||||
_ip=$1
|
||||
|
||||
_f="$CTDB_ETCDIR/iproute2/rt_tables"
|
||||
# This file should always exist, but...
|
||||
if [ ! -f "$_f" ] ; then
|
||||
mkdir -p $(basename "$_f")
|
||||
touch "$_f"
|
||||
fi
|
||||
|
||||
# Maintain a table id for each IP address we've ever seen in
|
||||
# rt_tables. We use a "ctdb." prefix on the label.
|
||||
_label="${table_id_prefix}${_ip}"
|
||||
|
||||
# This finds either the table id corresponding to the label or a
|
||||
# new unused one (that is greater than all the used ones in the
|
||||
# range).
|
||||
(
|
||||
# Note that die() just gets us out of the subshell...
|
||||
flock --timeout 30 0 || \
|
||||
die "ensure_table_id_for_ip: failed to lock file $_f"
|
||||
|
||||
_new=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW
|
||||
while read _t _l ; do
|
||||
# Skip comments
|
||||
case "$_t" in
|
||||
\#*) continue ;;
|
||||
esac
|
||||
# Found existing: done
|
||||
if [ "$_l" = "$_label" ] ; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
# Potentially update the new table id to be used. The
|
||||
# redirect stops error spam for a non-numeric value.
|
||||
if [ $_new -le $_t -a \
|
||||
$_t -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] 2>/dev/null ; then
|
||||
_new=$(($_t + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if test -f "$lckf"; then
|
||||
test $machine = $host || {
|
||||
lock_debug "lock file $lckf is valid for other machine $machine"
|
||||
stat -c%y "$lckf"
|
||||
return 1
|
||||
}
|
||||
kill -0 $pid && {
|
||||
lock_debug "lock file $lckf is valid for process $pid"
|
||||
stat -c%y "$lckf"
|
||||
return 1
|
||||
}
|
||||
lock_debug "stale lock file $lckf for $machine:$pid"
|
||||
cat "$lckf"
|
||||
rm -f "$lckf"
|
||||
fi
|
||||
echo "$host:$$" > "$lckf"
|
||||
return 0
|
||||
}
|
||||
|
||||
############################
|
||||
# unlock a lock file
|
||||
unlock_file() {
|
||||
if [ -z "$lock_root" ]; then
|
||||
lock_root=`pwd`;
|
||||
fi
|
||||
if [ "$locknesting" != "0" ]; then
|
||||
locknesting=`expr $locknesting - 1`
|
||||
lock_debug "lock nesting now $locknesting"
|
||||
# If the new table id is legal then add it to the file and
|
||||
# print it.
|
||||
if [ $_new -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] ; then
|
||||
printf "%d\t%s\n" "$_new" "$_label" >>"$_f"
|
||||
return 0
|
||||
else
|
||||
lckf="$lock_root/$1"
|
||||
rm -f "$lckf"
|
||||
return 1
|
||||
fi
|
||||
) <"$_f"
|
||||
}
|
||||
|
||||
generate_table_id () {
|
||||
local _ip=$1
|
||||
local _ipsdir="$CTDB_PER_IP_ROUTING_STATE/ips"
|
||||
local _ipdir="$_ipsdir/$_ip"
|
||||
# Clean up all the table ids that we might own.
|
||||
clean_up_table_ids ()
|
||||
{
|
||||
_f="$CTDB_ETCDIR/iproute2/rt_tables"
|
||||
# Even if this didn't exist on the system, adding a route will
|
||||
# have created it. What if we startup and immediately shutdown?
|
||||
if [ ! -f "$_f" ] ; then
|
||||
mkdir -p $(basename "$_f")
|
||||
touch "$_f"
|
||||
fi
|
||||
|
||||
mkdir -p $_ipdir
|
||||
(
|
||||
# Note that die() just gets us out of the subshell...
|
||||
flock --timeout 30 0 || \
|
||||
die "clean_up_table_ids: failed to lock file $_f"
|
||||
|
||||
#echo "generate_table_id $_ip"
|
||||
# Delete any items from the file that have a table id in our
|
||||
# range or a label matching our label. Preserve comments.
|
||||
_tmp="${_f}.$$.ctdb"
|
||||
awk -v min="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" \
|
||||
-v max="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" \
|
||||
-v pre="$table_id_prefix" \
|
||||
'/^#/ || \
|
||||
!(min <= $1 && $1 <= max) && \
|
||||
!(index($2, pre) == 1) \
|
||||
{ print $0 }' "$_f" >"$_tmp"
|
||||
|
||||
local _id=`cat $_ipdir/table_id 2>/dev/null| xargs`
|
||||
test -n "$_id" && {
|
||||
#echo "IP: $_ip => OLD TABLE: $_id"
|
||||
table_id=$_id
|
||||
return 0;
|
||||
}
|
||||
mv "$_tmp" "$_f"
|
||||
# The lock is gone - don't do anything else here
|
||||
) <"$_f"
|
||||
}
|
||||
|
||||
local _low="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW"
|
||||
local _high="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH"
|
||||
######################################################################
|
||||
|
||||
local _newid=""
|
||||
for _id in `seq $_low $_high | xargs`; do
|
||||
local _table_lck="table_id_$_id.lock"
|
||||
lock_file $_table_lck 2>/dev/null || {
|
||||
continue;
|
||||
}
|
||||
local _taken=`grep "^$_id$" $_ipsdir/*/table_id 2>/dev/null| wc -l | xargs`
|
||||
test x"$_taken" != x"0" && {
|
||||
unlock_file $_table_lck
|
||||
#echo "tableid: $_id taken"
|
||||
continue
|
||||
}
|
||||
_newid=$_id;
|
||||
echo "$_newid" > $_ipdir/table_id
|
||||
unlock_file $_table_lck
|
||||
break;
|
||||
# This prints the config for an IP, which is either relevant entries
|
||||
# from the config file or, if set to the magic link local value, some
|
||||
# link local routing config for the IP.
|
||||
get_config_for_ip ()
|
||||
{
|
||||
_ip="$1"
|
||||
|
||||
if [ "$CTDB_PER_IP_ROUTING_CONF" = "__auto_link_local__" ] ; then
|
||||
# When parsing public_addresses also split on '/'. This means
|
||||
# that we get the maskbits as item #2 without further parsing.
|
||||
while IFS="/$IFS" read _i _maskbits _x ; do
|
||||
if [ "$_ip" = "$_i" ] ; then
|
||||
echo -n "$_ip "; ipv4_host_addr_to_net "$_ip" "$_maskbits"
|
||||
fi
|
||||
done <"${CTDB_PUBLIC_ADDRESSES:-/dev/null}"
|
||||
else
|
||||
while read _i _rest ; do
|
||||
if [ "$_ip" = "$_i" ] ; then
|
||||
printf "%s\t%s\n" "$_ip" "$_rest"
|
||||
fi
|
||||
done <"$CTDB_PER_IP_ROUTING_CONF"
|
||||
fi
|
||||
}
|
||||
|
||||
ip_has_configuration ()
|
||||
{
|
||||
_ip="$1"
|
||||
|
||||
[ -n "$(get_config_for_ip $_ip)" ]
|
||||
}
|
||||
|
||||
add_routing_for_ip ()
|
||||
{
|
||||
_iface="$1"
|
||||
_ip="$2"
|
||||
|
||||
# Do nothing if no config for this IP.
|
||||
ip_has_configuration "$_ip" || return 0
|
||||
|
||||
ensure_table_id_for_ip "$_ip" || \
|
||||
die "add_routing_for_ip: out of table ids in range $CTDB_PER_IP_ROUTING_TABLE_ID_LOW - $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH"
|
||||
|
||||
_pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
|
||||
_table_id="${table_id_prefix}${_ip}"
|
||||
|
||||
del_routing_for_ip "$_ip"
|
||||
|
||||
ip rule add from "$_ip" pref "$_pref" table "$_table_id" || \
|
||||
die "add_routing_for_ip: failed to add rule for $_ip"
|
||||
|
||||
# Add routes to table for any lines matching the IP.
|
||||
get_config_for_ip "$_ip" |
|
||||
while read _i _dest _gw ; do
|
||||
_r="$_dest ${_gw:+via} $_gw dev $_iface table $_table_id"
|
||||
ip route add $_r || \
|
||||
die "add_routing_for_ip: failed to add route: $_r"
|
||||
done
|
||||
}
|
||||
|
||||
del_routing_for_ip ()
|
||||
{
|
||||
_ip="$1"
|
||||
|
||||
_pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
|
||||
_table_id="${table_id_prefix}${_ip}"
|
||||
|
||||
# Do this unconditionally since we own any matching table ids...
|
||||
ip rule del from $_ip pref $_pref table $_table_id 2>/dev/null
|
||||
ip route flush table $_table_id 2>/dev/null
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
flush_rules_and_routes ()
|
||||
{
|
||||
ip rule show |
|
||||
while read _p _x _i _x _t ; do
|
||||
# Remove trailing colon after priority/preference.
|
||||
_p="${_p%:}"
|
||||
# Only remove rules that match our priority/preference.
|
||||
[ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue
|
||||
|
||||
echo "Removing ip rule for public address $_i for routing table $_t"
|
||||
ip rule del from "$_i" table "$_t" pref "$_p"
|
||||
ip route flush table "$_t" 2>/dev/null
|
||||
done
|
||||
|
||||
test -z "$_newid" && {
|
||||
echo "generate_table_id: out of table ids: $_low - $_high"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
#echo "IP: $_ip => NEW TABLE: $_newid"
|
||||
table_id=$_newid
|
||||
return 0;
|
||||
}
|
||||
|
||||
run_release_script_once()
|
||||
# Add any missing routes. Some might have gone missing if, for
|
||||
# example, all IPs on the network were removed (possibly if the
|
||||
# primary was removed).
|
||||
add_missing_routes ()
|
||||
{
|
||||
local _script=$1
|
||||
ctdb ip -v -Y | {
|
||||
read _x # skip header line
|
||||
|
||||
#echo "run_release_script_once[$_script]"
|
||||
|
||||
test -x "$_script" && {
|
||||
#echo "run it: start"
|
||||
$_script || {
|
||||
echo "release_script: $_script - failed $?"
|
||||
return $?;
|
||||
}
|
||||
#echo "run it: end"
|
||||
}
|
||||
|
||||
echo '#!/bin/sh' > $_script
|
||||
echo '#' >> $_script
|
||||
echo >> $_script
|
||||
|
||||
chmod +x $_script
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
generate_auto_link_local()
|
||||
{
|
||||
local _ip=$1
|
||||
local _maskbits=$2
|
||||
|
||||
#echo "generate_auto_link_local $_ip $_maskbits"
|
||||
|
||||
local _netip=`ipv4_host_addr_to_net_addr $_ip $_maskbits`
|
||||
|
||||
local _line="$_ip $_netip/$_maskbits"
|
||||
|
||||
local _lockfile="$CTDB_PER_IP_ROUTING_CONF.lock"
|
||||
local _script="$CTDB_PER_IP_ROUTING_CONF.$$.sh"
|
||||
|
||||
echo "#!/bin/sh" > $_script
|
||||
echo "#" >> $_script
|
||||
echo "" >> $_script
|
||||
echo "_config=\`cat $CTDB_PER_IP_ROUTING_CONF 2>/dev/null\`" >> $_script
|
||||
echo "_exact=\`echo -n \"\$_config\" | grep \"^$_line\$\" | wc -l | xargs\`" >> $_script
|
||||
echo "" >> $_script
|
||||
|
||||
echo "test x\"\$_exact\" = x\"1\" && {" >> $_script
|
||||
echo " exit 0;" >> $_script
|
||||
echo "}" >> $_script
|
||||
echo "" >> $_script
|
||||
|
||||
echo "_tmp=\"$CTDB_PER_IP_ROUTING_CONF.$$.tmp\"" >> $_script
|
||||
echo "echo -n \"\$_config\" | grep -v \"^$_ip \" | cat > \$_tmp || {" >> $_script
|
||||
echo " echo \"echo -n \\\"\$_config\\\" | grep -v \\\"^$_ip \\\" > \$_tmp - failed\"" >> $_script
|
||||
echo " exit 1;" >> $_script
|
||||
echo "}" >> $_script
|
||||
echo "echo \"$_line\" >> \$_tmp || {" >> $_script
|
||||
echo " echo \"echo \\\"$_line\\\" >> \$_tmp - failed\"" >> $_script
|
||||
echo " exit 1;" >> $_script
|
||||
echo "}" >> $_script
|
||||
echo "" >> $_script
|
||||
|
||||
echo "mv \$_tmp $CTDB_PER_IP_ROUTING_CONF || {" >> $_script
|
||||
echo " echo \"mv \$_tmp $CTDB_PER_IP_ROUTING_CONF - failed\"" >> $_script
|
||||
echo " exit 1;" >> $_script
|
||||
echo "}" >> $_script
|
||||
echo "" >> $_script
|
||||
|
||||
echo "echo \"Added '$_line' to $CTDB_PER_IP_ROUTING_CONF\"">> $_script
|
||||
echo "exit 0" >> $_script
|
||||
|
||||
chmod +x $_script
|
||||
|
||||
test -f $_lockfile || {
|
||||
touch $_lockfile
|
||||
}
|
||||
|
||||
flock --timeout 30 $_lockfile $_script
|
||||
ret=$?
|
||||
rm $_script
|
||||
return $ret
|
||||
}
|
||||
|
||||
generate_per_ip_routing()
|
||||
{
|
||||
local _ip=$1
|
||||
local _maskbits=$2
|
||||
local _iface=$3
|
||||
local _readonly=$4
|
||||
local _ipdir="$CTDB_PER_IP_ROUTING_STATE/ips/$_ip"
|
||||
|
||||
table_id=""
|
||||
release_script="$_ipdir/per_ip_routing_release.sh"
|
||||
setup_script="$_ipdir/per_ip_routing_setup.sh"
|
||||
|
||||
test x"$_readonly" = x"yes" && {
|
||||
test -d $_ipdir || {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
mkdir -p $_ipdir || {
|
||||
echo "mkdir -p $_ipdir failed"
|
||||
return 1;
|
||||
}
|
||||
echo "$_ip" > $_ipdir/ip
|
||||
|
||||
generate_table_id $_ip
|
||||
|
||||
test x"$AUTO_LINK_LOCAL" = x"yes" && {
|
||||
generate_auto_link_local $_ip $_maskbits
|
||||
}
|
||||
|
||||
run_release_script_once $release_script
|
||||
|
||||
echo '#!/bin/sh' > $setup_script
|
||||
echo '#' >> $setup_script
|
||||
echo >> $setup_script
|
||||
chmod +x $setup_script
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
setup_per_ip_routing()
|
||||
{
|
||||
local _ip=$1
|
||||
local _iface=$2
|
||||
local _table_id=$3
|
||||
local _release_script=$4
|
||||
local _setup_script=$5
|
||||
|
||||
local _config=`cat $CTDB_PER_IP_ROUTING_CONF`
|
||||
local _lines=`echo -n "$_config" | grep -n "^$_ip " | cut -d ':' -f1 | xargs`
|
||||
|
||||
local _pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
|
||||
|
||||
test -n "$_lines" && {
|
||||
echo "ip rule del from $_ip pref $_pref table $_table_id" >> $_release_script
|
||||
echo "ip route flush table $_table_id 2>/dev/null" >> $_release_script
|
||||
|
||||
cmd="ip rule del from $_ip pref $_pref 2>/dev/null"
|
||||
echo "$cmd" >> $_setup_script
|
||||
|
||||
cmd="ip route flush table $_table_id 2>/dev/null"
|
||||
echo "$cmd" >> $_setup_script
|
||||
|
||||
cmd="ip rule add from $_ip pref $_pref table $_table_id"
|
||||
echo "$cmd || {" >> $_setup_script
|
||||
echo " echo \"$cmd - failed \$ret\"" >> $_setup_script
|
||||
echo " exit \$ret" >> $_setup_script
|
||||
echo "}" >> $_setup_script
|
||||
}
|
||||
local _l
|
||||
for _l in $_lines; do
|
||||
local _line=`echo -n "$_config" | head -n $_l | tail -n 1`
|
||||
local _dest=`echo -n "$_line" | cut -d ' ' -f 2`
|
||||
local _gw=`echo -n "$_line" | cut -d ' ' -f 3`
|
||||
|
||||
local _via=""
|
||||
test -n "$_gw" && {
|
||||
_via="via $_gw"
|
||||
}
|
||||
|
||||
cmd="ip route add $_dest $_via dev $_iface table $_table_id"
|
||||
echo "$cmd || {" >> $_setup_script
|
||||
echo " echo \"$cmd - failed \$ret\"" >> $_setup_script
|
||||
echo " exit \$ret" >> $_setup_script
|
||||
echo "}" >> $_setup_script
|
||||
# Read the rest of the lines. We're only interested in the
|
||||
# "IP" and "ActiveInterface" columns. The latter is only set
|
||||
# for addresses local to this node, making it easy to skip
|
||||
# non-local addresses. For each IP local address we check if
|
||||
# the relevant routing table is populated and populate it if
|
||||
# not.
|
||||
while IFS=":" read _x _ip _x _iface _x ; do
|
||||
[ -n "$_iface" ] || continue
|
||||
|
||||
_table_id="${table_id_prefix}${_ip}"
|
||||
if [ -z "$(ip route show table $_table_id 2>/dev/null)" ] ; then
|
||||
add_routing_for_ip "$_iface" "$_ip"
|
||||
fi
|
||||
done
|
||||
|
||||
$_setup_script
|
||||
return $?;
|
||||
}
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
ctdb_check_args "$@"
|
||||
|
||||
case "$1" in
|
||||
#############################
|
||||
# called when ctdbd starts up
|
||||
startup)
|
||||
# cleanup old rules
|
||||
pref=$CTDB_PER_IP_ROUTING_RULE_PREF
|
||||
rules=`ip rule show | grep "^$pref:" | sed -e 's/.*from \([^ ][^ ]*\) lookup \([^ ][^ ]*\)/\2;\1/' | xargs`
|
||||
for r in $rules; do
|
||||
table_id=`echo -n "$r" | cut -d ';' -f1`
|
||||
ip=`echo -n "$r" | cut -d ';' -f2-`
|
||||
startup)
|
||||
flush_rules_and_routes
|
||||
|
||||
echo "Removing ip rule for public address $ip for routing table $table_id"
|
||||
cmd="ip rule del from $ip table $table_id pref $pref"
|
||||
#echo $cmd
|
||||
eval $cmd
|
||||
cmd="ip route flush table $table_id"
|
||||
#echo $cmd
|
||||
eval $cmd 2>/dev/null
|
||||
done
|
||||
|
||||
# make sure that we only respond to ARP messages from the NIC where
|
||||
# a particular ip address is associated.
|
||||
# make sure that we only respond to ARP messages from the NIC
|
||||
# where a particular ip address is associated.
|
||||
[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
|
||||
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
|
||||
}
|
||||
|
||||
mkdir -p $CTDB_PER_IP_ROUTING_STATE
|
||||
|
||||
;;
|
||||
|
||||
shutdown)
|
||||
|
||||
for s in $CTDB_PER_IP_ROUTING_STATE/ips/*/per_ip_routing_release.sh; do
|
||||
run_release_script_once "$s"
|
||||
done
|
||||
rm -rf $CTDB_PER_IP_ROUTING_STATE
|
||||
|
||||
shutdown)
|
||||
flush_rules_and_routes
|
||||
clean_up_table_ids
|
||||
;;
|
||||
|
||||
################################################
|
||||
# called when ctdbd wants to claim an IP address
|
||||
takeip)
|
||||
takeip)
|
||||
iface=$2
|
||||
ip=$3
|
||||
maskbits=$4
|
||||
|
||||
ipv4_is_valid_addr $ip || {
|
||||
echo "$0: $1 not an ipv4 address skipping IP:$ip"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
echo "$0: $1 No state directory found, waiting for startup."
|
||||
exit 0;
|
||||
}
|
||||
|
||||
generate_per_ip_routing $ip $maskbits $iface "no" || {
|
||||
echo "$0: $1: generate_per_ip_routing $ip $maskbits $iface no - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
setup_per_ip_routing $ip $iface $table_id $release_script $setup_script || {
|
||||
echo "$0: $1: setup_per_ip_routing $ip $iface $table_id $release_script $setup_script - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
setup_iface_ip_readd_script $iface $ip $maskbits $setup_script || {
|
||||
echo "$0: $1: setup_iface_ip_readd_script $iface $ip $maskbits $setup_script - failed"
|
||||
exit 1;
|
||||
}
|
||||
ensure_ipv4_is_valid_addr "$1" "$ip"
|
||||
add_routing_for_ip "$iface" "$ip"
|
||||
|
||||
# flush our route cache
|
||||
echo 1 > /proc/sys/net/ipv4/route/flush
|
||||
ctdb gratiousarp $ip $iface
|
||||
|
||||
ctdb gratiousarp "$ip" "$iface"
|
||||
;;
|
||||
|
||||
################################################
|
||||
# called when ctdbd wants to claim an IP address
|
||||
updateip)
|
||||
updateip)
|
||||
oiface=$2
|
||||
niface=$3
|
||||
ip=$4
|
||||
maskbits=$5
|
||||
|
||||
ipv4_is_valid_addr $ip || {
|
||||
echo "$0: $1 not an ipv4 address skipping IP:$ip"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
echo "$0: $1 No state directory found, waiting for startup."
|
||||
exit 0;
|
||||
}
|
||||
|
||||
generate_per_ip_routing $ip $maskbits $niface "no" || {
|
||||
echo "$0: $1: generate_per_ip_routing $ip $maskbits $niface no - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
setup_per_ip_routing $ip $niface $table_id $release_script $setup_script || {
|
||||
echo "$0: $1: setup_per_ip_routing $ip $niface $table_id $release_script $setup_script - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
setup_iface_ip_readd_script $niface $ip $maskbits $setup_script || {
|
||||
echo "$0: $1: setup_iface_ip_readd_script $niface $ip $maskbits $setup_script - failed"
|
||||
exit 1;
|
||||
}
|
||||
ensure_ipv4_is_valid_addr "$1" "$ip"
|
||||
add_routing_for_ip "$niface" "$ip"
|
||||
|
||||
# flush our route cache
|
||||
echo 1 > /proc/sys/net/ipv4/route/flush
|
||||
|
||||
ctdb gratiousarp $ip $niface
|
||||
tickle_tcp_connections $ip
|
||||
|
||||
ctdb gratiousarp "$ip" "$niface"
|
||||
tickle_tcp_connections "$ip"
|
||||
;;
|
||||
|
||||
##################################################
|
||||
# called when ctdbd wants to release an IP address
|
||||
releaseip)
|
||||
releaseip)
|
||||
iface=$2
|
||||
ip=$3
|
||||
maskbits=$4
|
||||
|
||||
ipv4_is_valid_addr $ip || {
|
||||
echo "$0: $1 not an ipv4 address skipping IP:$ip"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
echo "$0: $1 No state directory found, waiting for startup."
|
||||
exit 0;
|
||||
}
|
||||
|
||||
generate_per_ip_routing $ip $maskbits $iface "yes" || {
|
||||
echo "$0: $1: generate_per_ip_routing $ip $maskbits $iface yes - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
run_release_script_once "$release_script"
|
||||
|
||||
ensure_ipv4_is_valid_addr "$1" "$ip"
|
||||
del_routing_for_ip "$ip"
|
||||
;;
|
||||
|
||||
|
||||
###########################################
|
||||
# called when ctdbd has finished a recovery
|
||||
recovered)
|
||||
ipreallocated)
|
||||
add_missing_routes
|
||||
;;
|
||||
|
||||
####################################
|
||||
# called when ctdbd is shutting down
|
||||
shutdown)
|
||||
;;
|
||||
|
||||
monitor)
|
||||
;;
|
||||
*)
|
||||
ctdb_standard_event_handler "$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user