...
 
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";
Host openbsd58-install
Image openbsd58
Memory 512M
VNC 52
Type openbsd
Host openbsd58
Image openbsd58
Memory 512M
Type openbsd
Cow yes
Host openbsd64-install
Image openbsd64
Memory 512M
VNC 52
Type openbsd
Host openbsd64
Image openbsd64
Memory 512M
Type openbsd
Cow yes
Host freebsd10-install
Image freebsd10
Memory 512M
VNC 51
Type freebsd
Host freebsd11-install
Image freebsd11
Memory 512M
# VNC 54
Type freebsd
Host freebsd082
Image freebsd082
Memory 8G
VNC 82
Type freebsd
Host freebsd10
Image freebsd10
Memory 512M
Type freebsd
Cow yes
Host freebsd11
Image freebsd11
Memory 512M
Type freebsd
Cow yes
Host netbsd70-install
Image netbsd70
Memory 512M
VNC 53
Type netbsd
Host netbsd70
Image netbsd70
Memory 512M
Type netbsd
Cow yes
Host debian9-i386-install
Image debian9-i386
Memory 512M
VNC 16
Arch i386
Type linux
Host debian9-i386
Image debian9-i386
Memory 512M
Type linux
Arch i386
Cow yes
Host debian8-install
Image debian8
Memory 512M
VNC 11
Type linux
Host debian8
Image debian8
Memory 512M
Type linux
Cow yes
Host debian7-install
Image debian7
Memory 512M
VNC 12
Type linux
Host debian7
Image debian7
Memory 512M
Type linux
Cow yes
Host centos6-install
Image centos6
Memory 512M
VNC 13
Type linux
Host centos6
Image centos6
Memory 512M
Type linux
Cow yes
Host centos7-install
Image centos7
Memory 512M
VNC 13
Type linux
Host centos7
Image centos7
Memory 512M
Type linux
Cow yes
Host mikrotik-install
Image mikrotik
Memory 128M
VNC 14
Type mikrotik
Host mikrotik
Image mikrotik
Memory 128M
Cow yes
Type mikrotik
Host rpki-rtr
Image rpki-rtr
Memory 1024M
VNC 6
Type linux
Host netlink
Image debian8-netlink
Memory 2G
VNC 15
Type linux
Copy openbsd58 ob1 ob2 ob3
Copy freebsd10 fb1 fb2 fb3
Copy netbsd70 nb1 nb2 nb3
Copy debian8 d1 d2 d3 d4
Copy debian8 minidebian
Host minidebian
Memory 512M
Copy openbsd64 miniob
Host miniob
Memory 512M
Copy freebsd10 minifb10
Host minifb10
Memory 1024M
Copy freebsd11 minifb11
Host minifb11
Memory 1024M
Copy netbsd70 mininb
Host mininb
Memory 512M
Copy minidebian mov
Host mov
VNC 5
Copy centos7 minicentos
Host minicentos
Memory 512M
Copy minidebian md1111 md1112 md1121 md1122 md1211 md1212 md1221 md1222 md2111 md2112 md2121 md2122 md2211 md2212 md2221 md2222
#Copy minidebian md1111 md1112
#Copy miniob md1211 md1212
#Copy minifb11 md1121 md1122
#Copy mininb md1221 md1222
Dummy md1111 md1111 10.200.0.50/32 fd01::1111/128
Dummy md1112 md1112 10.200.0.51/32 fd01::1112/128
Dummy md1121 md1121 10.200.0.52/32 fd01::1121/128
Dummy md1122 md1122 10.200.0.53/32 fd01::1122/128
Dummy md1211 md1211 10.200.0.54/32 fd01::1211/128