diff --git a/run/network.sh b/run/network.sh index c84638e..c8a7fc9 100644 --- a/run/network.sh +++ b/run/network.sh @@ -1,22 +1,87 @@ #!/usr/bin/env bash set -eu -: ${VM_NET_TAP:=''} -: ${VM_NET_IP:='20.20.20.21'} +# Docker environment variabeles + : ${VM_NET_HOST:='QEMU'} : ${VM_NET_MAC:='82:cf:d0:5e:57:66'} +: ${DHCP:='N'} : ${DNS_SERVERS:=''} -: ${DNSMASQ:='/usr/sbin/dnsmasq'} : ${DNSMASQ_OPTS:=''} +: ${DNSMASQ:='/usr/sbin/dnsmasq'} : ${DNSMASQ_CONF_DIR:='/etc/dnsmasq.d'} # ###################################### # Functions # ###################################### -# Setup macvtap device to connect later the VM and setup a new macvlan device to connect the host machine to the network -configureNatNetworks () { +configureDHCP() { + + # Create /dev/vhost-net + if [ ! -c /dev/vhost-net ]; then + mknod /dev/vhost-net c 10 238 + chmod 660 /dev/vhost-net + fi + + if [ ! -c /dev/vhost-net ]; then + echo -n "Error: VHOST interface not available. Please add the following " + echo "docker variable to your container: --device=/dev/vhost-net" && exit 85 + fi + + VM_NET_TAP="_VmMacvtap" + echo "Info: Retrieving IP via DHCP using MAC ${VM_NET_MAC}..." + + ip l add link eth0 name ${VM_NET_TAP} address ${VM_NET_MAC} type macvtap mode bridge || true + ip l set ${VM_NET_TAP} up + + ip a flush eth0 + ip a flush ${VM_NET_TAP} + + DHCP_IP=$( dhclient -v ${VM_NET_TAP} 2>&1 | grep ^bound | cut -d' ' -f3 ) + + if [[ "${DHCP_IP}" == [0-9.]* ]]; then + echo "Info: Retrieved IP ${DHCP_IP} via DHCP" + else + echo "ERROR: Cannot retrieve IP from DHCP using MAC ${VM_NET_MAC}" && exit 16 + fi + + ip a flush ${VM_NET_TAP} + + TAP_PATH="/dev/tap$(>$TAP_PATH; then + echo -n "ERROR: Please add the following docker variables to your container: " + echo "--device=/dev/vhost-net --device-cgroup-rule='c ${MAJOR}:* rwm'" && exit 21 + fi + + if ! exec 40>>/dev/vhost-net; then + echo -n "ERROR: VHOST can not be found. Please add the following docker " + echo "variable to your container: --device=/dev/vhost-net" && exit 22 + fi + + NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30" +} + +configureNAT () { + + VM_NET_IP='20.20.20.21' + VM_NET_TAP="_VmNatTap" #Create bridge with static IP for the VM guest brctl addbr dockerbridge @@ -32,6 +97,9 @@ configureNatNetworks () { iptables -t nat -A PREROUTING -i eth0 -p tcp -j DNAT --to $VM_NET_IP iptables -t nat -A PREROUTING -i eth0 -p udp -j DNAT --to $VM_NET_IP + # Hack for guest VMs complaining about "bad udp checksums in 5 packets" + iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill + #Enable port forwarding flag [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]] && sysctl -w net.ipv4.ip_forward=1 @@ -41,6 +109,33 @@ configureNatNetworks () { # Create lease file for faster resolve echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:${VM_NET_MAC}" > /var/lib/misc/dnsmasq.leases chmod 644 /var/lib/misc/dnsmasq.leases + + NET_OPTS="-netdev tap,ifname=${VM_NET_TAP},script=no,downscript=no,id=hostnet0" + + # Build DNS options from container /etc/resolv.conf + nameservers=($(grep '^nameserver' /etc/resolv.conf | sed 's/nameserver //')) + searchdomains=$(grep '^search' /etc/resolv.conf | sed 's/search //' | sed 's/ /,/g') + domainname=$(echo $searchdomains | awk -F"," '{print $1}') + + for nameserver in "${nameservers[@]}"; do + if ! [[ $nameserver =~ .*:.* ]]; then + [[ -z $DNS_SERVERS ]] && DNS_SERVERS=$nameserver || DNS_SERVERS="$DNS_SERVERS,$nameserver" + fi + done + + [[ -z $DNS_SERVERS ]] && DNS_SERVERS="1.1.1.1" + + DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,$DNS_SERVERS --dhcp-option=option:router,${VM_NET_IP%.*}.1" + + if [ -n "$searchdomains" -a "$searchdomains" != "." ]; then + DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-search,$searchdomains --dhcp-option=option:domain-name,$domainname" + else + [[ -z $(hostname -d) ]] || DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-name,$(hostname -d)" + fi + + [ "$DEBUG" = "Y" ] && echo && echo "$DNSMASQ $DNSMASQ_OPTS" + + $DNSMASQ $DNSMASQ_OPTS } # ###################################### @@ -59,34 +154,30 @@ fi update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null -VM_NET_TAP="_VmNatTap" -configureNatNetworks -KVM_NET_OPTS="-netdev tap,ifname=${VM_NET_TAP},script=no,downscript=no,id=hostnet0" +GATEWAY=$(ip r | grep default | awk '{print $3}') -# Build DNS options from container /etc/resolv.conf -nameservers=($(grep '^nameserver' /etc/resolv.conf | sed 's/nameserver //')) -searchdomains=$(grep '^search' /etc/resolv.conf | sed 's/search //' | sed 's/ /,/g') -domainname=$(echo $searchdomains | awk -F"," '{print $1}') +if [ "$DEBUG" = "Y" ]; then -for nameserver in "${nameservers[@]}"; do - if ! [[ $nameserver =~ .*:.* ]]; then - [[ -z $DNS_SERVERS ]] && DNS_SERVERS=$nameserver || DNS_SERVERS="$DNS_SERVERS,$nameserver" - fi -done + IP=$(ip address show dev eth0 | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/) + echo "Info: Container IP is ${IP} with gateway ${GATEWAY}" -[[ -z $DNS_SERVERS ]] && DNS_SERVERS="1.1.1.1" - -DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,$DNS_SERVERS --dhcp-option=option:router,${VM_NET_IP%.*}.1" - -if [ -n "$searchdomains" -a "$searchdomains" != "." ]; then - DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-search,$searchdomains --dhcp-option=option:domain-name,$domainname" -else - [[ -z $(hostname -d) ]] || DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-name,$(hostname -d)" fi -$DNSMASQ $DNSMASQ_OPTS +if [ "$DHCP" != "Y" ]; then -KVM_NET_OPTS="${KVM_NET_OPTS} -device virtio-net-pci,romfile=,netdev=hostnet0,mac=${VM_NET_MAC},id=net0" + # Configuration for static IP + configureNAT -# Hack for guest VMs complaining about "bad udp checksums in 5 packets" -iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill +else + + if [[ "$GATEWAY" == "172."* ]]; then + echo -n "ERROR: You cannot enable DHCP while the container is " + echo "in a bridge network, only on a macvlan network!" && exit 86 + fi + + # Configuration for DHCP IP + configureDHCP + +fi + +NET_OPTS="${NET_OPTS} -device virtio-net-pci,romfile=,netdev=hostnet0,mac=${VM_NET_MAC},id=net0"