...
 
Commits (13)
[submodule "perf/violin"]
path = perf/violin
url = git://trezor.joja.cz/violin.git
Birdlab je hypervisor, který vytváří on-demand testovací prostředí pro Birda.
Podle definičního souboru vytvoří a spustí sadu virtuálních strojů, spojí je do
sítí podle definice a nastaví příslušným rozhraním IP adresy.
Celé prostředí sídlí v ROOT=/var/lib/virt, definice prostředí v $ROOT/etc/virtlist.
S ohledem na malý počet členů týmu návrh systému neřeší kolize mezi jednotlivými uživateli.
Ukázková konfigurace:
####################################################################
# Tento host slouží k instalaci a nastavování image OpenBSD 5.8
Host openbsd58-install
Image openbsd58
Memory 512M
VNC 52 # Je přístupný na IP adrese hypervizora na VNC portu 52
Type openbsd
# Tento host je konfigurační template pro vytváření dalších hostů s OpenBSD 5.8
Host openbsd58
Image openbsd58
Memory 512M
Type openbsd
Cow yes # Všechny změny na disku zapisuj do paměti a po ukončení zahoď
Host freebsd10-install
Image freebsd10
Memory 512M
VNC 51
Type freebsd
Host freebsd10
Image freebsd10
Memory 512M
Type freebsd
Cow yes
Host debian8-install
Image debian8
Memory 512M
VNC 11
Type linux
Host debian8
Image debian8
Memory 512M
Type linux
Cow yes
Host debian5-install
Image debian5
Memory 512M
VNC 12
Type linux
Host debian5
Image debian5
Memory 512M
Type linux
Cow yes
# Naklonuj konfiguraci hosta openbsd58 (3x) a vytvoř tak hosty ob1, ob2, ob3
Copy openbsd58 ob1 ob2 ob3
Copy freebsd10 fb1 fb2 fb3
Copy debian8 d1 d2 d3 d4
# Naklonuj hosta debian8 a vytvoř minidebian; uprav nastavení klonu
Copy debian8 minidebian
Host minidebian
Memory 64M
# Vytvoř 6 dalších debianů s 64M paměti
Copy minidebian md1 md2 md3 md4 md5 md6
# Vytvoř síťový segment, připoj na něj uvedené hosty a nastav jim příslušné IP adresy
Net md1 192.168.1.1/24 md2 192.168.1.2/24 md3 192.168.1.3/24 md4 192.168.1.4/24 md5 192.168.1.5/24 md6 192.168.1.6/24
# Vytvoř p2p linky mezi uvedenými dvojicemi hostů
Link fb1 192.168.55.64/32 d1 192.168.55.71/32
Link ob1 192.168.55.77/32 d1 192.168.55.33/32
Link ob1 192.168.55.17/32 fb1 192.168.55.241/32
Link d2 192.168.55.15/32 d3 192.168.55.117/32
Link d3 192.168.93.15/32 d4 192.168.15.93/32
Net fb1 192.168.44.1/24 fb2 192.168.44.2/24 fb3 192.168.44.3/24
Net d1 192.168.66.1/24 d2 192.168.66.2/24 d3 192.168.66.3/24
Net ob1 192.168.77.1/24 ob2 192.168.77.2/24 ob3 192.168.77.3/24
####################### Konec konfigurace ###########################
Manipulaci s virtuály zajišťuje příkaz vctl.
vctl prepare: vytvoř potřebná rozhraní, spusť potřebné daemony
vctl status: vypiš stav všech virtuálů
vctl cleanup: zruš rozhraní a vypni daemony, ukliď po sobě; nevypíná virtuály
vctl start <host> [args...]: nastartuj virtuál <host>; argumenty navíc se předají přímo Qemu.
vctl ssh <host>: připoj se na terminál <host>ovi
vctl mon <host>: otevři monitorovací socket Qemu
vctl stop <host>: vypni virtuál <host>; pokouší se o to několika způsoby, poslední je sigkill.
Virtuály běží v Qemu a jejich síťová rozhraní jsou připojená do openVswitche
(s tím se dá povídat přes ovs-vsctl, základní příkaz je ovs-vsctl show).
Linky a sítě jsou vytvořené jako jednotlivé VLANy v OVS, tag se generuje hashovací funkcí z definice sítě.
Každý virtuál má k dispozici /mnt/nfs, kam se namontuje $ROOT/nfs. Při startu se spustí /mnt/nfs/rc.local.
V základu se tímto skriptem nastaví sítě. Adresář $ROOT/nfs/net obsahuje další
důležité soubory definující nastavení sítě v závislosti na MAC adrese
virtuálního rozhraní.
Je-li tedy třeba po startu také přeložit Birda a spustit jej se správným
configem, $ROOT/nfs/rc.local je správné místo pro zavolání takové věci.
TODO: IPv6
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
ID=$2
if [ -z "$NAME" ] || [ -z "$ID" ]; then
echo "Usage: $0 NAME ID"
exit 2
fi
socat UNIX-CONNECT:$ROOT/run/$NAME.sock - >/dev/null <<EOF
netdev_add type=tap,id=$ID,ifname=$ID,script=no
device_add e1000,netdev=$ID
EOF
#!/bin/bash
. $(dirname $0)/virt-lib
[ -f $ROOT/run/dhcpd.pid ] && kill $(cat $ROOT/run/dhcpd.pid)
iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
iptables -D FORWARD -i eth0 -o $VIRTCTRL -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -D FORWARD -i eth0 -o $VIRTCTRL -j ACCEPT
iptables -D FORWARD -i $VIRTCTRL -o eth0 -j ACCEPT
iptables -D FORWARD -o eth0 -j REJECT
ovs-vsctl del-br $VIRTBR
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NETLIST=$ROOT/run/networks
NET=$1
if [ -z "$NET" ] || [ -z "$2" ]; then
echo "Usage: $0 NET hosts"
exit 2
fi
shift
if grep -q $NET $NETLIST; then
echo "Network $NET exists"
exit 2
fi
MAXID=$(sort -k1,1nr $NETLIST | head -n1|cut -f1 -d' ')
MAXID=$((MAXID+1))
echo "$MAXID $NET" >> $NETLIST
i=0
idprefix=auto-$MAXID
for H in "$@"; do
$ROOT/bin/addnic $H $idprefix-$i
ip link set $idprefix-$i up
ovs-vsctl add-port $VIRTBR $idprefix-$i tag=$MAXID
i=$((i+1))
done
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
ID=$2
if [ -z "$NAME" ] || [ -z "$ID" ]; then
echo "Usage: $0 NAME ID"
exit 2
fi
socat UNIX-CONNECT:$ROOT/run/$NAME.sock - >/dev/null <<EOF
netdev_del $ID
device_del e1000,netdev=$ID
EOF
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
if [ -z "$NAME" ]; then
echo "Usage: $0 NAME"
exit 2
fi
$SOCAT READLINE,history=$ROOT/run/$NAME.mon-history UNIX-CONNECT:$ROOT/run/$NAME.sock
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
set -e
EVENT=$1
shift
idtoip() {
echo 10.255.$(($1 / 254)).$(($1 % 254))
}
idtolink() {
echo 10.254.$(($1 / 254)).$(($1 % 254))
}
if ! brctl show | grep -q br-mpls; then brctl addbr br-mpls; ip link set br-mpls up; fi
case $EVENT in
add-rr|add-p|add-pe)
T=${EVENT##add-}
id=$1
ip=$(idtoip $id)
vctl start -t mpls-auto $T-$id
gethost mpls-auto-$T-$id
vctl serial-mikrotik-fix.pl mpls-auto-$T-$id
vctl ssh mpls-auto-$T-$id -t <<EOF
/interface bridge add name=lo
/ip address add address=$ip/32 interface=lo
/routing ospf instance set distribute-default=never redistribute-connected=as-type-1 router-id=$ip 0
/routing ospf network add network=$ip/32 area=backbone
EOF
if [ "$EVENT" != "add-rr" ]; then
echo "/mpls ldp set enabled=yes lsr-id=$ip transport-address=$ip" | vctl ssh mpls-auto-$T-$id -t
fi
;;
add-c)
id=$1
vpn=$2
pe=$3
ip=$(idtoip $id)
peip=$(idtoip $pe)
linkip=$(idtolink $id)
linkpeip=$(idtolink $pe)
vctl start -t mpls-auto c-$id
gethost mpls-auto-c-$id
cip=$HOSTIP4
gethost mpls-auto-pe-$pe
cpeip=$HOSTIP4
vctl serial-mikrotik-fix.pl mpls-auto-c-$id
vctl ssh mpls-auto-c-$id -t <<EOF
/interface bridge add name=lo
/ip address add address=$ip/32 interface=lo
/interface gre add remote-address=$cpeip name=pe-$pe
/ip address add address=$linkip/32 network=$linkpeip interface=pe-$pe
/routing ospf instance set distribute-default=never redistribute-connected=as-type-1 router-id=$ip 0
/routing ospf network add network=$ip/32 area=backbone
/routing ospf network add network=$linkpeip/32 area=backbone
EOF
vctl ssh mpls-auto-pe-$pe -t <<EOF
/interface gre add remote-address=$cip name=c-$id
/ip address add address=$linkpeip/32 network=$linkip interface=c-$id
/ip route vrf add routing-mark=$vpn interfaces=c-$id route-distinguisher=$vpn import-route-targets=$vpn export-route-targets=$vpn
/routing bgp instance vrf add instance=default routing-mark=$vpn redistribute-connected=yes redistribute-ospf=yes
/routing ospf instance add name=c-$id routing-table=$vpn redistribute-bgp=as-type-1
/routing ospf area add instance=c-$id name=c-$id
/routing ospf network add network=$linkip/32 area=c-$id
EOF
;;
add-link)
from=$1
to=$2
fip=$(idtolink ${from##*-})
tip=$(idtolink ${to##*-})
gethost mpls-auto-$from
cfip=$HOSTIP4
gethost mpls-auto-$to
ctip=$HOSTIP4
vctl ssh mpls-auto-$from -t <<EOF
/interface gre add remote-address=$ctip name=$to
/ip address add address=$fip/32 network=$tip interface=$to
/routing ospf network add network=$tip/32 area=backbone
EOF
vctl ssh mpls-auto-$to -t <<EOF
/interface gre add remote-address=$cfip name=$from
/ip address add address=$tip/32 network=$fip interface=$from
/routing ospf network add network=$fip/32 area=backbone
EOF
case "$from$to" in
*rr*) :
;;
*)
echo "/mpls ldp interface add interface=$to" | vctl ssh mpls-auto-$from -t
echo "/mpls ldp interface add interface=$from" | vctl ssh mpls-auto-$to -t
;;
esac
;;
bgp-rr)
pe=$1
rr=$2
peip=$(idtoip $pe)
rrip=$(idtoip $rr)
echo "/routing bgp peer add remote-address=$rrip remote-as=65530 address-families=vpnv4 update-source=lo" | vctl ssh mpls-auto-pe-$pe -t
echo "/routing bgp peer add remote-address=$peip remote-as=65530 address-families=vpnv4 update-source=lo route-reflect=yes" | vctl ssh mpls-auto-rr-$rr -t
;;
bgp-link)
from=$1
to=$2
fip=$(idtoip ${from})
tip=$(idtoip ${to})
echo "/routing bgp peer add remote-address=$tip remote-as=65530 address-families=vpnv4 update-source=lo" | vctl ssh mpls-auto-rr-$from -t
echo "/routing bgp peer add remote-address=$fip remote-as=65530 address-families=vpnv4 update-source=lo" | vctl ssh mpls-auto-rr-$to -t
;;
*)
echo "Commands: add-rr ID, add-p ID, add-pe ID, add-c ID VPN PE, add-link FROM TO, bgp-rr PE RR"
exit 2
;;
esac
#!/usr/bin/env python
import pypureomapi
import sys
keyname = "dhcp_key"
#secret = "6Qsf2UG4cvSli+Fup3bHI/4lCGO4i3SO6hl6WWBr042vUHktQ/1KiQwI 3MQrNrGs7c7EMDr/fho2Fzr3y1EP/Q=="
secret = "3MQrNrGs7c7EMDr/fho2Fzr3y1EP/Q=="
server = "127.0.0.1"
port = 7911
try:
oma = pypureomapi.Omapi(server, port, keyname, secret)
except pypureomapi.OmapiError, err:
print "OMAPI error: %s" % (err,)
sys.exit(1)
if sys.argv[1] == "add":
oma.add_host_supersede_name(sys.argv[4], sys.argv[3], sys.argv[2])
elif sys.argv[1] == "del":
oma.del_host(sys.argv[2])
else:
print("Usage: omapi (add MAC IP|del MAC)")
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
HOST=$1
if ! gethost $HOST; then
echo "Unknown host: $HOST"
exit 2
fi
case ${HOSTTYPE^^} in
FREEBSD)
INSTALLPKG="pkg install rsync autotools bison flex readline gmake"
FSTAB="192.168.192.1:/var/lib/virt/nfs /mnt/nfs nfs rw 0 0"
DHCPFIX="echo 'request broadcast-address, domain-name, domain-name-servers, domain-search, host-name, routers;' >> /etc/dhclient.conf"
;;
OPENBSD) ;&
NETBSD)
FSTAB="192.168.192.1:/var/lib/virt/nfs /mnt/nfs nfs rw 0 0"
;;
LINUX)
FSTAB="192.168.192.1:/var/lib/virt/nfs /mnt/nfs nfs defaults,intr,_netdev 0 0"
;;
*)
echo "Unknown type of host: $TYPE"
exit 2
;;
esac
AUTH=`mktemp`
cat >$AUTH <<EOF
mkdir -p /root/.ssh
cat >/root/.ssh/authorized_keys <<EOC
EOF
cat /home/birdlab/.ssh/authorized_keys >> $AUTH
cat /root/.ssh/virt-rsa.pub >>$AUTH
echo EOC >>$AUTH
ssh root@$HOSTIP4 bash <$AUTH
SCRIPT=`mktemp`
cat >$SCRIPT <<EOF
if [ ! -x /bin/bash ]; then
ln -s \$(command -v bash) /bin/bash
fi
rm -f /etc/udev/rules.d/70-persistent-net.rules
if egrep -q '/mnt/nfs[[:space:]]+nfs[[:space:]]+' /etc/fstab; then
( egrep -v '/mnt/nfs[[:space:]]+nfs[[:space:]]+' /etc/fstab ; echo "$FSTAB") > /etc/fstab.new
cp /etc/fstab.new /etc/fstab
mkdir -p /mnt/nfs
mount -o remount /mnt/nfs
else
echo "$FSTAB" >> /etc/fstab
mkdir -p /mnt/nfs
mount /mnt/nfs
fi
$DHCPFIX
cat >/etc/rc.local <<EOC
#!/bin/bash
until [ -x /mnt/nfs/rc.local ]; do
sleep 1
done
/mnt/nfs/rc.local > /tmp/rc-local-log 2>/tmp/rc-local-err
EOC
chmod +x /etc/rc.local
$INSTALLPKG
EOF
ssh root@$HOSTIP4 bash <$SCRIPT
rm $SCRIPT
rm $AUTH
#!/bin/bash
. $(dirname $0)/virt-lib
vsctl add-br $VIRTBR
ip link set $VIRTBR up
ip addr add 192.168.10.1/28 dev $VIRTBR
ip link add $VIRTCTRL type veth peer name $VIRTUPLINK
ip link set $VIRTCTRL up
ip link set $VIRTUPLINK up
ip addr add 192.168.192.1/18 dev $VIRTCTRL
ip -6 addr add 2001:1488:A001::1/64 dev $VIRTCTRL
vsctl add-port $VIRTBR $VIRTUPLINK tag=1
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o $VIRTCTRL -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth0 -o $VIRTCTRL -j ACCEPT
iptables -A FORWARD -i $VIRTCTRL -o eth0 -j ACCEPT
iptables -A FORWARD -o eth0 -j REJECT
dhcpd -cf $ROOT/etc/dhcpd.conf -pf $ROOT/run/dhcpd.pid $VIRTCTRL
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
[ -f $ROOT/run/dhcpd.pid ] && kill $(cat $ROOT/run/dhcpd.pid)
dhcpd -cf $ROOT/etc/dhcpd.conf -pf $ROOT/run/dhcpd.pid $VIRTCTRL
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
if [ -z "$NAME" ]; then
echo -e "Usage: $0 name [custom options for qemu]\n or $0 -m list of names"
exit 2
fi
vctl stop "$@"
vctl start "$@"
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
if [ -z "$NAME" ]; then
echo "Usage: $0 NAME"
exit 2
fi
minicom -D unix\#$ROOT/run/$1.serial
#!/usr/bin/perl -CL
use common::sense;
use Data::Dumper;
use IO::Socket::UNIX;
my $client = IO::Socket::UNIX->new( Type => SOCK_STREAM(), Peer => "/var/lib/virt/run/$ARGV[0].serial");
my $data;
my $debug = 0;
sub D { say @_ if $debug; }
sub S { say "\rmikrotik init ", @_; }
$/ = "";
my $state = "login";
say "";
S "started";
D "init client";
syswrite $client, "\r";
while (1) {
D "";
sleep 1;
sysread $client, $data, 65536;
$data =~ s/[^ -~]/?/g;
D Dumper \$data;
if ($data =~ /MikroTik Login: $/) {
S "sending login";
syswrite $client, "root\r";
$state = "login";
next;
}
if ($data =~ /assword: $/) {
S "sending password";
syswrite $client, "root\r";
next;
}
if ($data =~ /tinue!/) {
S "continue boilerplate";
syswrite $client, "\r";
# $state = "export";
$state = "macreset";
next;
}
if ($data =~ /\[root\@MikroTik\] > $/ && $state eq "export") {
D "export";
syswrite $client, "export\r";
$state = "macreset";
next;
}
if ($data =~ /\[root\@MikroTik\] > $/ && $state eq "macreset") {
D "interface ethernet reset-mac-address numbers=0";
S "reset mac address";
syswrite $client, "interface ethernet reset-mac-address numbers=0\r";
$state = "dhcp";
next;
}
if ($data =~ /\[root\@MikroTik\] > $/ && $state eq "dhcp") {
D "ip dhcp-client renew numbers=0";
S "flush dhcp";
syswrite $client, "ip dhcp-client renew numbers=0\r";
$state = "quit";
next;
}
if ($data =~ /\[root\@MikroTik\] > $/ && $state eq "quit") {
D "quit";
syswrite $client, "quit\r";
sleep 1;
sysread $client, $data, 65536;
$data =~ s/[^ -~]/?/g;
D Dumper \$data;
S "done", " "x50;
exit 0;
}
if ($data =~ /\[root\@MikroTik\] > $/) {
D "Logged in, noop now";
syswrite $client, "\r";
$state = "macreset";
next;
}
D "NOP, strange input";
}
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
if [ -z "$NAME" ]; then
echo "Usage: $0 NAME"
exit 2
fi
shift
gethost $NAME
if [ "${#@}" == "0" ]; then
TERM=rxvt-256color ssh -i /root/.ssh/virt-rsa -t root@$HOSTIP4 bash
else
TERM=rxvt-256color ssh -i /root/.ssh/virt-rsa root@$HOSTIP4 "$@"
fi
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
shift
usage() {
echo -e "Usage: $0 name [custom options for qemu]\n or $0 -m list of names\n or $0 -t name suffix [custom options for qemu]"
exit 2
}
check_stale() {
local NAME=$1
if [ -e $ROOT/run/$NAME.pid ]; then
echo -n "Host $NAME pidfile found"
if [ -d /proc/$(<$ROOT/run/$NAME.pid) ]; then
echo " running with PID $(<$ROOT/run/$NAME.pid)"
exit 1
else
echo " stale ... removing"
rm $ROOT/run/$NAME.pid
fi
fi
}
[ -z "$NAME" ] && usage
if [ "$NAME" = "-m" ]; then
set -e
for N in "$@"; do
echo Starting "$N"
$0 "$N"
done
exit 0
fi
if [ "$NAME" = "-t" ]; then
NAME=$1
SUFFIX=$2
([ -z "$SUFFIX" ] || [ -z "$NAME" ]) && usage
ID=0
if [ -e $ROOT/run/tmp-$NAME-$SUFFIX ]; then
echo "Host $NAME tmpfile found."
check_stale $NAME-$SUFFIX
rm $(readlink -f $ROOT/run/tmp-$NAME-$SUFFIX) $ROOT/run/tmp-$NAME-$SUFFIX
fi
while [ -e $ROOT/run/tmp-$ID ]; do
ID=$((ID+1))
done
HEXID=$(printf "%02x" $ID)
echo "$SUFFIX" > $ROOT/run/tmp-$ID
ln -s tmp-$ID $ROOT/run/tmp-$NAME-$SUFFIX
shift 2
else
check_stale $NAME
fi
NAME=$NAME${SUFFIX:+-$SUFFIX}
gethost $NAME
if [ "$?" != 0 ]; then
echo "Host $NAME not configured"
exit 2
fi
if [ "$1" = "--install" ]; then
INSTALL="-cdrom $2 -boot d"
shift 2
fi
RCGFILE=$ROOT/nfs/rc/rc-gen-$HOSTNAME
truncate -s0 $RCGFILE
declare -a HOSTNICVLAN
if [ -n "$HOSTNIC" ]; then
declare -a HOSTNIC=( $HOSTNIC )
for N in ${HOSTNIC[@]}; do
IFS=';' read NETNAME MAC TAG IP4 IP4PEER <<<"$N"
TAPID=$(mactotap $MAC)
HOSTNICDEV="$HOSTNICDEV -netdev tap,id=$TAPID,ifname=$TAPID,script=no -device e1000,netdev=$TAPID,mac=$MAC"
echo "N=\$(ifname \${IFBYMAC[$MAC]} $NETNAME)" >>$RCGFILE
echo "ifnameset $MAC \$N" >>$RCGFILE
if [ -n "$IP4PEER" ]; then
echo "ip4ptp \$N $IP4 $IP4PEER" >>$RCGFILE
else
echo "ip4 \$N $IP4" >>$RCGFILE
fi
echo "ifup \$N" >>$RCGFILE
HOSTNICVLAN+=( $TAPID,$TAG )
done
fi
if [ -n "$HOSTVARS" ]; then
declare -a HOSTVARS=( $HOSTVARS )
for V in ${HOSTVARS[@]}; do
echo "export $V" >> $RCGFILE
done
declare -a HOSTVARNAMES
for V in ${HOSTVARS[@]}; do
HOSTVARNAMES+=( ${V%%=*} )
done
echo "declare -a VARNAMES=(${HOSTVARNAMES[@]})" >> $RCGFILE
fi
if [ -n "$HOSTDUMMY" ]; then
declare -a HOSTDUMMY=( $HOSTDUMMY )
for D in ${HOSTDUMMY[@]}; do
IFS=';' read DNAME IP4 IP6 <<<"$D"
echo "N=\$(dummy $DNAME)" >>$RCGFILE
echo "INTERFACES+=(\$N)" >>$RCGFILE
echo "ip4 \$N $IP4" >>$RCGFILE
echo "ip6 \$N $IP6" >>$RCGFILE
done
fi
if [ -n "$HOSTGRE" ]; then
declare -a HOSTGRE=( $HOSTGRE )
for G in ${HOSTGRE[@]}; do
IFS=';' read GRENAME PEER IP4 IP4PEER <<<"$G"
echo "N=\$(gre $GRENAME $HOSTIP4 ${CONF[$PEER;IP4]})" >>$RCGFILE
echo "INTERFACES+=(\$N)" >>$RCGFILE
echo "ip4ptp \$N $IP4 $IP4PEER" >>$RCGFILE
done
fi
if [ -n "$HOSTSOCK" ]; then
declare -a HOSTSOCK=( $HOSTSOCK )
for S in ${HOSTSOCK[@]}; do
IFS=';' read SOCKNAME APPEND MAC IP4 <<<"$S"
TAPID=$(mactotap $MAC)
HOSTNICDEV="$HOSTNICDEV -netdev socket,$APPEND,id=$SOCKNAME -device e1000,netdev=$SOCKNAME,mac=$MAC"
echo "N=\$(ifname \${IFBYMAC[$MAC]} $SOCKNAME)" >>$RCGFILE
echo "IFBYMAC[$MAC]=\$N" >>$RCGFILE
if [ -n "$IP4PEER"]; then
echo "ip4ptp \$N $IP4 $IP4PEER" >>$RCGFILE
else
echo "ip4 \$N $IP4" >>$RCGFILE
fi
echo "ifup \$N" >>$RCGFILE
done
fi
echo -e "hostname $HOSTNAME\nexport HOSTNAME=$HOSTNAME" > $ROOT/nfs/net/hostname-${HOSTMAC//:}
$ROOT/bin/omapi add $NAME $HOSTMAC $HOSTIP4
qemu-system-$HOSTARCH -enable-kvm -m $HOSTMEMORY -hda $ROOT/img/$HOSTIMAGE $HOSTCOW -display none ${HOSTVNCID:+-vnc 172.20.20.180:$HOSTVNCID} -netdev tap,id=ctl,ifname=$HOSTTAP,script=no -device e1000,netdev=ctl,mac=$HOSTMAC $HOSTNICDEV -pidfile $ROOT/run/$NAME.pid -monitor unix:$ROOT/run/$NAME.sock,server,nowait -serial unix:$ROOT/run/$NAME.serial,server,nowait -daemonize $INSTALL "$@"
#-runas $VIRTUSER
ip link set $HOSTTAP up
vsctl add-port $VIRTBR $HOSTTAP tag=1
echo vsctl add-port $VIRTBR $HOSTTAP tag=1
for T in ${HOSTNICVLAN[@]}; do
IFS=, read TAPID TAG <<<"$T"
ip link set $TAPID up
if ip link show br-$TAG 2>/dev/null >/dev/null; then :; else
brctl addbr br-$TAG
ip link set br-$TAG up
fi
echo "brctl addif br-$TAG $TAPID"
brctl addif br-$TAG $TAPID
# vsctl add-port $VIRTBR $TAPID tag=$TAG
done
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
if [ "$1" == "-n" ]; then
shift
DO_PING=false
else
DO_PING=true
fi
if [ "$1" == "-v" ]; then
for C in $(echo ${!CONF[@]} | tr ' ' '\n' | sort); do
echo $C: ${CONF[$C]}
done
exit 0
fi
declare -A seen
seen[dhcpd]=1
for H in $(hostlist); do
if [ -S $ROOT/run/$H.sock ]; then
if [ -e $ROOT/run/tmp-$H ]; then
ID=$(basename $(readlink -f $ROOT/run/tmp-$H))
ID=${ID##tmp-}
HOSTIP4=192.168.255.$(($ID % 254))
else
HOSTIP4=${CONF[$H;IP4]}
fi
if $DO_PING; then
if ping -nc1 $HOSTIP4 >/dev/null; then
PING="(ping ok)"
else
PING="(ping FAIL)"
fi
else
PING=""
fi
echo "$H running, IPv4 $HOSTIP4 $PING, monitor $ROOT/run/$H.sock"
elif [ -f $ROOT/run/$H.pid ]; then
if ps -p $(<$ROOT/run/$H.pid) >/dev/null; then
echo "$H probably running at PID $(<$ROOT/run/$H.pid), no socket, IPv4 ${CONF[$H;IP4]}"
else
echo "$H stopped, $ROOT/run/$H.pid stale pidfile found, removing"
rm $ROOT/run/$H.pid
fi
else
echo "$H stopped"
fi
done
#!/bin/bash
. $(dirname $(readlink -f $0))/virt-lib
NAME=$1
shift
if [ -z "$NAME" ]; then
echo -e "Usage: $0 name\n or $0 -m list of names"
exit 2
fi
if [ "$NAME" = "-m" ]; then
set -e
declare -a PIDS
for N in "$@"; do
echo Stopping "$N"
$0 -q "$N" &
PIDS+=($!)
done
echo ${PIDS[@]}
while true; do
declare -a NEWPIDS
NEWPIDS=()
for P in ${PIDS[@]}; do
if [ -d /proc/$P ]; then
NEWPIDS+=($P)
fi
done
PIDS=( ${NEWPIDS[@]} )
if [ "${#PIDS[@]}" -eq 0 ]; then break; fi
echo -e "Still ${#PIDS[@]} machine(s) running ... \r"
sleep 1
done
echo "Everything OK. "
exit 0
fi
QUIET=false
if [ "$NAME" = "-q" ]; then
QUIET=true
NAME=$1
shift
fi
function ok() {
E
rm -f $ROOT/run/$NAME.sock $ROOT/run/$NAME.pid
if gethost $NAME; then
echo "$NAME"
if [ -e $ROOT/run/tmp-$NAME ]; then rm $(readlink -f $ROOT/run/tmp-$NAME) $ROOT/run/tmp-$NAME; fi
$ROOT/bin/omapi del $HOSTMAC
vsctl del-port $HOSTTAP
if [ -n "$HOSTNIC" ]; then
for N in ${HOSTNIC[@]}; do
IFS=';' read _ MAC TAG _ <<<"$N"
TAPID=$(mactotap $MAC)
E $TAPID
brctl delif br-$TAG $TAPID
# vsctl del-port $TAPID
done
fi
else
E "Warning: Config not found for this host"
fi
E "OK"
exit 0
}
if [ -e $ROOT/run/$NAME.sock ]; then
E -n "Graceful powerdown "
echo "system_powerdown" | socat - UNIX-CONNECT:$ROOT/run/$NAME.sock >/dev/null
if wait_pidfile $ROOT/run/$NAME.pid 30; then ok; fi
else
E "No monitor socket found."
fi
if [ -e $ROOT/run/$NAME.pid ]; then
if [ ! -d /proc/$(<$ROOT/run/$NAME.pid) ]; then
E "Stale pidfile found, cleaning up"
rm $ROOT/run/$NAME.pid
return 0
fi
E -n "Sending TERM "
kill -15 $(<$ROOT/run/$NAME.pid)
if wait_pidfile $ROOT/run/$NAME.pid 30; then ok; fi
E -n "Sending KILL "
kill -9 $(<$ROOT/run/$NAME.pid)
if wait_pidfile $ROOT/run/$NAME.pid 30; then ok; fi
E "Did not stop even after KILL, strange."
exit 1
fi
#!/bin/bash
#ROOT=$(readlink -f $(dirname $(readlink -f $0))/../)
ROOT=/var/lib/virt
VIRTBR=virtbr
VIRTCTRL=virtctrl
VIRTUPLINK=virtuplink
VIRTUALS=$ROOT/etc/virtlist
VIRTUSER=virt-qemu
function E() {
$QUIET || echo "$@"
}
function virtns() {
"$@"
}
function vsctl() {
virtns ovs-vsctl "$@"
}
function mactotap() {
echo vl-$(tr -d ':' <<<"$1")
}
function wait_pidfiles() {
local -A PIDS
while [ -r $1 ]; do
${PIDS[$(<$1)]}=1
shift
done
TIMEOUT=${1:-30}
while [ ! -z "${!PIDS[@]}" ]; do
E -n "."
for pid in "${!PIDS[@]}"; do
if [ ! -d /proc/$pid ]; then
unset PIDS[$pid]
fi
done
done
}
function wait_pidfile() {
CNT=0
FILE=$1
TIMEOUT=${2:-30}
while [ -d /proc/$(<$FILE) ]; do
E -n "."
sleep 1
CNT=$((CNT+1))
if [ $CNT -eq $TIMEOUT ]; then
E
E "Timeout ${TIMEOUT}s reached."
return 1
fi
done
return 0
}
SOCAT=$ROOT/bin/socat
#SOCAT=$(which socat)
declare -A HOSTS
declare -A CONF
function getmac() {
echo 52:54:$(sed -r 's/^.*(..)(..)(..)(..)$/\1:\2:\3:\4/'<<<"$1")
}
function hostctlnet() {
if [ -z "${CONF[$1;NETWORK]}" ]; then
local SHA=$(sha1sum <<<"$1" | head -c 12)
CONF[$1;MAC]=$(getmac $SHA)
CONF[$1;TAP]=$(mactotap ${CONF[$1;MAC]} | sed 's/vl-/vc-/')
CONF[$1;IP4]=192.168.$((193+((0x$SHA / 254) % 62))).$((0x$SHA % 254))
else
read CONF[$1;TAP] CONF[$1;MAC] CONF[$1;IP4] <<<"${CONF[$1;NETWORK]}"
fi
}
function hostdefaults() {
if [ -z "${CONF[$HOSTNAME;IMAGE]}" ]; then echo "Error: Image not set"; return 1; fi
if [ -z "${CONF[$HOSTNAME;ARCH]}" ]; then CONF[$HOSTNAME;ARCH]=x86_64; fi
if [ -z "${CONF[$HOSTNAME;MEMORY]}" ]; then CONF[$HOSTNAME;MEMORY]=64M; fi
if [ "${CONF[$HOSTNAME;COW]^^}" = "YES" ] || [ "${CONF[$HOSTNAME;COW]}" = "-snapshot" ]; then CONF[$HOSTNAME;COW]=-snapshot; else CONF[$HOSTNAME;COW]=; fi
hostctlnet $HOSTNAME
HOSTS[$HOSTNAME]=true
HOSTNAME=
}
function copyhost() {
local src=$1
shift
if [ -z "${HOSTS[$src]}" ]; then
echo "No host '$src' found to copy from in config."
exit 2
fi
for H in "$@"; do
eval $(echo ${!CONF[@]} | tr ' ' '\n' | sed -rn "/^$src;/{ s/$src;//; s/.*/CONF[$H;&]=\\\${CONF[$src;&]}/p }")
hostctlnet $H
HOSTS[$H]=true
done
}
function linkhosts() {
local NAME=$1
local an=$2
local ai=$3
local bn=$4
local bi=$5
if [ -z "$an" ] || [ -z "$ai" ] || [ -z "$bn" ] || [ -z "$bi" ]; then
echo "Link usage: 'Link host IP host IP' in config."
exit 2
fi
local SHA=$(sha1sum <<<"$an;$ai;$bn;$bi" | head -c 20)
local AMAC=$(getmac ${SHA:0:8})
local BMAC=$(getmac ${SHA:8:8})
local TAG=$((100 + (0x${SHA:16:4} % 3800)))
CONF[$an;NIC]="${CONF[$an;NIC]} $NAME;$AMAC;$TAG;$ai;$bi"
CONF[$bn;NIC]="${CONF[$bn;NIC]} $NAME;$BMAC;$TAG;$bi;$ai"
}
function nethosts() {
local SHA=$(sha1sum <<<"$*" | head -c 20)
local TAG=$((100 + (0x${SHA:0:4} % 3800)))
local H
local A
local MAC
local NAME=$1
shift
until [ -z "$1" ]; do
if [ -z "$2" ]; then
echo "Missing address for interface $1 in config."
exit 2
fi
H=$1
A=$2
SHA=$(sha1sum <<<"$SHA $H $A" | head -c 20)
MAC=$(getmac ${SHA:0:8})
shift 2
CONF[$H;NIC]="${CONF[$H;NIC]} $NAME;$MAC;$TAG;$A;"
done
}
function grehosts() {
local NAME=$1
local an=$2
local ai=$3
local bn=$4
local bi=$5
if [ -z "$an" ] || [ -z "$ai" ] || [ -z "$bn" ] || [ -z "$bi" ]; then
echo "Link usage: 'Link host IP host IP' in config."
exit 2
fi
CONF[$an;GRE]="${CONF[$an;GRE]} $NAME;$bn;$ai;$bi"
CONF[$bn;GRE]="${CONF[$bn;GRE]} $NAME;$an;$bi;$ai"
}
function sockethosts() {
local NAME=$1
local PORT=$2
local an=$3
local ai=$4
shift 4
if [ -z "$PORT" ] || [ -z "$NAME" ] || [ -z "$an" ] || [ -z "$ai" ]; then
echo "Socket usage: Socket PORT host IP [[host IP] ...]"
exit 2
fi
local SHA=$(sha1sum <<<"$NAME;$PORT;$an;$ai" | head -c 20)
local AMAC=$(getmac ${SHA:0:8})
CONF[$an;SOCK]="${CONF[$an;SOCK]} $NAME;listen=127.0.0.1:$PORT;$AMAC;$ai"
while [ ! -z "$1" ] && [ ! -z "$2" ]; do
local bn=$1
local bi=$2
local SHA=$(sha1sum <<<"$NAME;$PORT;$an;$ai;$bn;$bi" | head -c 20)
local BMAC=$(getmac ${SHA:0:8})
shift 2
CONF[$bn;SOCK]="${CONF[$bn;SOCK]} $NAME;connect=127.0.0.1:$PORT;$BMAC;$bi"
done
if [ ! -z "$1" ]; then
echo "Socket usage: Socket PORT host IP [[host IP] ...]"
exit 2
fi
}
function dummynic() {
local h=$1
local n=$2
local v4=$3
local v6=$4
if [ -z "$v4" ] || [ -z "$v6" ]; then
echo "Dummy usage: 'Dummy name IP4 IP6' in config."
exit 2
fi
CONF[$h;DUMMY]="${CONF[$h;DUMMY]} $n;$v4;$v6"
}
varput() {
local h=$1
shift
while [ -n "$1" ]; do
CONF[$h;VARS]="${CONF[$h;VARS]} $1"
shift
done
}
HOSTNAME=
while read item value; do
if [ -z "$HOSTNAME" ]; then
if [ -z "$item" ]; then
continue
elif [ "${item^^}" = "HOST" ]; then
HOSTNAME=$value
continue
else
echo "Config must begin by host definition."
exit 2
fi
fi
if [ -z "$item" ]; then continue; fi
case ${item^^} in
\#*) continue ;;
HOST) hostdefaults
HOSTNAME=$value
;;
IMAGE) CONF[$HOSTNAME;IMAGE]="$value" ;;
NETWORK)CONF[$HOSTNAME;NETWORK]="$value" ;;
CDROM) CONF[$HOSTNAME;CDROM]="$value" ;;
ARCH) CONF[$HOSTNAME;ARCH]="$value" ;;
MEMORY) CONF[$HOSTNAME;MEMORY]="$value" ;;
COW) CONF[$HOSTNAME;COW]="$value" ;;
VNC) CONF[$HOSTNAME;VNCID]="$value" ;;
TYPE) CONF[$HOSTNAME;TYPE]="$value" ;;
COPY) copyhost $value ;;
LINK) linkhosts $value ;;
NET) nethosts $value ;;
GRE) grehosts $value ;;
DUMMY) dummynic $value ;;
VAR) varput $value ;;
SOCKET) sockethosts $value ;;
*) echo "Unknown directive '$item' in config"
exit 2 ;;
esac
done <$VIRTUALS
hostdefaults
HOSTNAME=
function gethost() {
local NAME=$1 SUFFIX ID HEXID
if [ -e $ROOT/run/tmp-$NAME ]; then
SUFFIX=$(<$ROOT/run/tmp-$NAME)
ID=$(basename $(readlink -f $ROOT/run/tmp-$NAME))
ID=${ID##tmp-}
HEXID=$(printf "%02x" $ID)
NAME=${NAME%%-$SUFFIX}
fi
if ${HOSTS[$NAME]}; then
eval $(echo ${!CONF[@]} | tr ' ' '\n' | sed -rn "/^$NAME;/{ s/$NAME;//; s/.*/HOST&=\"\\\${CONF[$NAME;&]}\"/p }")
HOSTNAME=$1
if [ -n "$SUFFIX" ]; then
# echo "Assigned MAC for $NAME is $HOSTMAC, tapname is $HOSTTAP"
HOSTMAC=$(echo $HOSTMAC | sed "s/^52:54/52:$HEXID/")
HOSTTAP=$(echo $HOSTTAP | sed "s/^vc-5254/vc-52$HEXID/")
HOSTIP4=192.168.255.$(($ID % 254))
HOSTNIC=
# echo "Changed to $HOSTMAC, tapname $HOSTTAP"
fi
return 0
else
echo "Unknown host: $1"
return 1
fi
}
function hostlist() {
for H in ${!HOSTS[@]}; do echo $H; ls $ROOT/run/tmp-$H-* 2>/dev/null | sed "s#.*run/tmp-##"; done | sort
}
_virt() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
case "$prev" in
start) opts=$(vctl status | sed -n "s/ not running$//p")
;;
stop) opts=$(vctl status | grep -v "not running" | sed "s/ .*//")
;;
*) opts=$(vctl | tail -n+2)
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _virt vctl
option domain-name "bird-virtual.nic.cz";
option domain-name-servers 8.8.8.8;
default-lease-time 600;
max-lease-time 7200;
authoritative;
log-facility local7;
subnet 192.168.192.0 netmask 255.255.192.0 {
range 192.168.193.0 192.168.254.0;
option routers 192.168.192.1;
default-lease-time 15555555;
}
key dhcp_key {
algorithm HMAC-MD5;
secret "3MQrNrGs7c7EMDr/fho2Fzr3y1EP/Q==";
}
#6Qsf2UG4cvSli+Fup3bHI/4lCGO4i3SO6hl6WWBr042vUHktQ/1KiQwI
omapi-port 7911;
omapi-key dhcp_key;
#include "/var/lib/virt/etc/dhcpd-hosts.conf";
This diff is collapsed.
#!/bin/bash
export PATH=$PATH:/usr/local/bin:/usr/pkg/bin
. /mnt/nfs/rclib
case $UNAME in
linux)
AUTOCONF=autoreconf
MAKE=make
iptables -F # Flush predefined firewall
;;
freebsd|netbsd)
AUTOCONF=autoreconf
MAKE=gmake
sysctl -w net.inet6.ip6.forwarding=1
sysctl -w net.inet.ip.forwarding=1
;;
openbsd)
AUTOCONF=autoreconf-2.69
MAKE=gmake
sysctl -w net.inet6.ip6.forwarding=1
sysctl -w net.inet.ip.forwarding=1
sysctl -w net.inet.esp.enable=1
sysctl -w net.inet.gre.allow=1
;;
*)
echo "Unknown system $UNAME"
;;
esac
echo "Ifaces list: $(ifaces)"
for I in $(ifaces); do
NAME=${I%%,*}
MAC=${I##*,}
MAC=${MAC,,}
echo "Iface $NAME ($MAC)"
case $UNAME in
linux)
CIP4=$(ip addr show dev $NAME | sed -nr 's/\s+inet ([^ ]*) brd 192.168.255.255 .*/\1/p' )
if [ -n "$CIP4" ]; then
CIP6DEC=$(echo $CIP4 | sed -r 's#192\.168\.([0-9]+)\.([0-9]+)/[0-9]+#2001:1488:a001::\1:\2/64#')
CIP6HEX=$(printf "2001:1488:a001::ffff:%02x%02x/64" $(echo $CIP4 | sed -r 's#192\.168\.([0-9]+)\.([0-9]+)/[0-9]+#\1 \2#'))
ip6 $NAME $CIP6HEX
ip6 $NAME $CIP6DEC
ip -6 route add default via 2001:1488:a001::1
continue
fi
;;
netbsd|openbsd|freebsd)
CIP4=$(ifconfig $NAME | sed -nr 's/[[:space:]]+inet (192.168.[^ ]*) netmask 0x[0-9a-f]+ broadcast 192.168.255.255/\1/p' )
echo "CIP4=$CIP4"
if [ -n "$CIP4" ]; then
CIP6DEC=$(echo $CIP4 | sed -r 's#192\.168\.([0-9]+)\.([0-9]+)#2001:1488:a001::\1:\2/64#')
CIP6HEX=$(printf "2001:1488:a001::ffff:%02x%02x/64" $(echo $CIP4 | sed -r 's#192\.168\.([0-9]+)\.([0-9]+)#\1 \2#'))
echo "CIP6DEC=$CIP6DEC"
echo "CIP6HEX=$CIP6HEX"
ip6 $NAME $CIP6HEX
ip6 $NAME $CIP6DEC
route add -inet6 default 2001:1488:a001::1
continue
fi
;;
esac
IFBYMAC[$MAC]=$NAME
INTERFACES+=( $I )
done
RCGFILE=/mnt/nfs/rc/rc-gen-$HOSTNAME
if [ -f $RCGFILE ]; then
. $RCGFILE
fi
RCFILE=/mnt/nfs/rc/rc-loc-$HOSTNAME
if [ -f $RCFILE ]; then
. $RCFILE
fi
#!/bin/bash
UNAME=$(uname)
UNAME=${UNAME,,}
declare -a INTERFACES
declare -A IFBYMAC
function D() {
echo DBG: "$@" 1>&2
}
function ifup() {
D ifup "$@"
case $UNAME in
linux)
ip link set $1 up
;;
netbsd|openbsd|freebsd)
ifconfig $1 up
;;
esac
}
function ip4() {
D ip4 "$@"
case $UNAME in
linux)
ip addr add $2 dev $1
;;
netbsd|openbsd|freebsd)
ifconfig $1 inet $2
;;
esac
}
function ip6() {
D ip6 "$@"
case $UNAME in
linux)
ip -6 addr add $2 dev $1
;;
netbsd|openbsd|freebsd)
ifconfig $1 inet6 $2
;;
esac
}
function ip4ptp() {
D ip4ptp "$@"
case $UNAME in
linux)
ip addr add $2 peer $3 dev $1
;;
netbsd|openbsd|freebsd)
ifconfig $1 inet $2 ${3%%/*}
;;
esac
}
function cnt() {
D cnt "$@"
local OUT
if [ ! -r /tmp/${1}count ]; then
OUT=16
else
OUT=$(</tmp/${1}count)
fi
echo $((OUT+1)) > /tmp/${1}count
echo $OUT
}
function grecount() {
cnt gre
}
function locount() {
cnt lo
}
function gre() {
D gre "$@"
case $UNAME in
linux)
ip tunnel add $1 mode gre remote $3 local $2
ip link set $1 up
echo $1
INTERFACES+=( $1, )
;;
freebsd)
GIF=gre$(grecount)
ifconfig $GIF create
ifconfig $GIF tunnel $2 $3
ifconfig $GIF name $1 >/dev/null
echo $1
INTERFACES+=( $1, )
;;
openbsd)
GIF=gre$(grecount)
ifconfig $GIF create
ifconfig $GIF tunnel $2 $3
ifconfig $GIF inet6 eui64 # OpenBSD needs to explicitly add link-local address for IPv6
ifconfig $GIF description $1
echo $GIF
INTERFACES+=( $GIF, )
;;
netbsd)
GIF=gre$(grecount)
ifconfig $GIF create
ifconfig $GIF tunnel $2 $3
echo $GIF
INTERFACES+=( $GIF, )
;;
esac
}
function dummy() {
D dummy "$@"
case $UNAME in
linux)
ip link add $1 type dummy
ip link set $1 up
echo $1
INTERFACES+=( $1, )
;;
netbsd)
LIF=lo$(locount)
ifconfig $LIF create
ifconfig $LIF inet6 fe80::1/64