[erlang-questions] Setting virtual IP via Erlang
Claes Wikstrom
klacke@REDACTED
Fri Dec 8 00:54:23 CET 2006
t ty wrote:
> Hello,
>
> I need to failover a virtual IP b/w machines purely in Erlang avoiding
> heartbeat/stonith.
>
> Klacke gave an answer to this question in 2002
> http://www1.erlang.org/ml-archive/erlang-questions/200212/msg00049.html
>
I've got linux-only in erlang + os:cmd + /sbin/ip + /sbin/arping
that does this.
It's always going to be very OS specific
Here is one good function:
%% Send four unsolicited / gratuitous ARPs on interface Ifc
garp(Ifc, IP) ->
garp(Ifc, IP, 4, 250).
%% Send <Count> unsolicited / gratuitous ARPs for <IP> on interface
%% <Ifc> with <Delay> milliseconds in between
garp(Ifc, IP, Count, Delay) when Count>0 ->
Loop = fun (1, F) ->
send_garps(Ifc, IP);
(N, F) ->
send_garps(Ifc, IP),
timer:sleep(Delay),
F(N-1, F)
end,
spawn(fun () ->
Loop(Count, Loop)
end).
%% Use this function to send garps
send_garps(Ifc, IP) ->
send_garps(Ifc, IP, 1, 0).
%%
%% arping -q -c <N> -w <Delay> -U -I <Ifc> -s <IP> <IP>
%%
%% Note: don't send more than one through this interface - it ties up the
%% isd_rtarp program in a loop.
%%
send_garps(Ifc, IP, N, Delay) ->
IPStr = ipcalc:format(IP),
Cmd = io_lib:format("sudo /sbin/arping -q -c ~p -w ~p -U -I ~s -s ~s ~s\n",
[N, Delay, Ifc, IPStr, IPStr]),
case os:cmd(Cmd) of
[] ->
ok;
ErrStr ->
error_logger:format("output from vip:garp/4 : ~s~n", [ErrStr])
end.
os_cmd(Str) ->
case os:cmd(Str) of
[] ->
ok;
Err ->
error_logger:format("CMD ~s failed with ~n~s~n",
[Str, Err])
end.
-----------------
and here is how to bring up a VIP
%% This is version two of this code which
%% will bring up the VIp on the primary iface (i.e flip addresses)
%% This is due to racoon not working very well with
%% secondary interfaces
vipup(IP, NumBitsInMask, IfName, DefGw) ->
OldStr = string:tokens(
os:cmd(["ip addr ls ", IfName,
" | grep inet | head -n 1 | awk '{print $2 \" \" $4}'"]),
" \n"),
case OldStr of
[OldIp, OldBcast] ->
%% Remove old address completely
os_cmd(["sudo ip addr del ", OldIp,
" dev ", IfName]),
%% bring up VIP
os_cmd(io_lib:format("sudo ip addr add ~s/~w broadcast ~s"
" dev ~s",
[ipcalc:format(IP), NumBitsInMask,
OldBcast, IfName])),
%% and bring up the old addr on a secondary iface
os_cmd(io_lib:format("sudo ip addr add ~s broadcast ~s"
" dev ~s label ~s:orig",
[OldIp, OldBcast,
IfName, IfName])),
%% since we for a short while didn't have any IP
%% at all, we lost our defualt gw,
os_cmd(io_lib:format("sudo route add default gw ~s",
[ipcalc:format(DefGw)])),
NewIp = lists:flatten(
io_lib:format("~s/~w", [ipcalc:format(IP), NumBitsInMask])),
%% The port command will flip back to the old IP
PortCmd = "/usr/bin/sudo " ++ code:priv_dir(kdb) ++ "/autoifdown.sh " +
+
OldIp ++ " " ++ NewIp ++ " " ++
OldBcast ++ " " ++ IfName ++ " " ++ ipcalc:fformat(DefGw),
io:format("Cmd=~s~n", [PortCmd]),
garp(IfName, IP),
error_logger:format("Brought up IP ~s/~w on ~s~n",
[ipcalc:format(IP), NumBitsInMask,IfName]),
%% Now start the vip auto-downer
%% which possibly also has to stop racoon
open_port({spawn, PortCmd}, [stream])
end.
-- and then the autoifdown script
#!/bin/sh
oldip=$1
newip=$2
bcast=$3
iface=$4
defgw=$5
read
echo "Autobring VIP down " 1>&2
echo "" 1>&2
ip addr del ${newip} dev ${iface}
ip addr add ${oldip} broadcast ${bcast} dev ${iface}
route add default gw ${defgw}
##ip addr flush dev eth0 label eth0:svip
More information about the erlang-questions
mailing list