mirror of
https://github.com/samba-team/samba.git
synced 2025-01-14 19:24:43 +03:00
dc2f87737d
since that will usually be /etc/ctdb/state and storing this under /etc is just wrong. Add a new variable CTDB_VARDIR that defaults to /var/ctdb and store the data there instead. (This used to be ctdb commit 516423c25afa9861d9988096efa8a4a2b12b31b1)
504 lines
11 KiB
Bash
Executable File
504 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
. $CTDB_BASE/functions
|
|
loadconfig
|
|
|
|
[ -z "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
|
CTDB_PER_IP_ROUTING_STATE="$CTDB_VARDIR/state/per_ip_routing"
|
|
}
|
|
|
|
AUTO_LINK_LOCAL="no"
|
|
|
|
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
|
|
|
|
_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()
|
|
{
|
|
echo -n ""
|
|
}
|
|
|
|
############################
|
|
# 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`
|
|
|
|
if [ "$pid" = "$$" ]; then
|
|
locknesting=`expr $locknesting + 1`
|
|
lock_debug "lock nesting now $locknesting"
|
|
return 0
|
|
fi
|
|
|
|
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
|
|
}
|
|
/bin/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"
|
|
/bin/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"
|
|
else
|
|
lckf="$lock_root/$1"
|
|
/bin/rm -f "$lckf"
|
|
fi
|
|
}
|
|
|
|
generate_table_id () {
|
|
local _ip=$1
|
|
local _ipsdir="$CTDB_PER_IP_ROUTING_STATE/ips"
|
|
local _ipdir="$_ipsdir/$_ip"
|
|
|
|
mkdir -p $_ipdir
|
|
|
|
#echo "generate_table_id $_ip"
|
|
|
|
local _id=`cat $_ipdir/table_id 2>/dev/null| xargs`
|
|
test -n "$_id" && {
|
|
#echo "IP: $_ip => OLD TABLE: $_id"
|
|
table_id=$_id
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
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()
|
|
{
|
|
local _script=$1
|
|
|
|
#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
|
|
done
|
|
|
|
$_setup_script
|
|
return $?;
|
|
}
|
|
|
|
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-`
|
|
|
|
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.
|
|
[ -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
|
|
|
|
;;
|
|
|
|
################################################
|
|
# called when ctdbd wants to claim an IP address
|
|
takeip)
|
|
if [ $# != 4 ]; then
|
|
echo "must supply interface, IP and maskbits"
|
|
exit 1
|
|
fi
|
|
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;
|
|
}
|
|
|
|
# flush our route cache
|
|
echo 1 > /proc/sys/net/ipv4/route/flush
|
|
ctdb gratiousarp $ip $iface
|
|
|
|
;;
|
|
|
|
################################################
|
|
# called when ctdbd wants to claim an IP address
|
|
updateip)
|
|
if [ $# != 5 ]; then
|
|
echo "must supply old interface, new interface, IP and maskbits"
|
|
exit 1
|
|
fi
|
|
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;
|
|
}
|
|
|
|
# flush our route cache
|
|
echo 1 > /proc/sys/net/ipv4/route/flush
|
|
|
|
ctdb gratiousarp $ip $niface
|
|
tickle_tcp_connections $ip
|
|
|
|
;;
|
|
|
|
##################################################
|
|
# called when ctdbd wants to release an IP address
|
|
releaseip)
|
|
if [ $# != 4 ]; then
|
|
echo "must supply interface, IP and maskbits"
|
|
exit 1
|
|
fi
|
|
|
|
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"
|
|
|
|
;;
|
|
|
|
|
|
###########################################
|
|
# called when ctdbd has finished a recovery
|
|
recovered)
|
|
;;
|
|
|
|
####################################
|
|
# called when ctdbd is shutting down
|
|
shutdown)
|
|
;;
|
|
|
|
monitor)
|
|
;;
|
|
*)
|
|
ctdb_standard_event_handler "$@"
|
|
;;
|
|
esac
|
|
|
|
exit 0
|
|
|