diff --git a/contrib/hyperv/tools/scripts/hyperv_vfattach b/contrib/hyperv/tools/scripts/hyperv_vfattach new file mode 100644 index 000000000000..e1ed1849f98f --- /dev/null +++ b/contrib/hyperv/tools/scripts/hyperv_vfattach @@ -0,0 +1,79 @@ +#!/bin/sh + +# +# If transparent VF is enabled, don't do anything. +# + +sysctl -n hw.hn.vf_transparent > /dev/null 2>&1 +if [ $? -ne 0 ] +then + # Old kernel; no transparent VF. + vf_transparent=0 +else + vf_transparent=`sysctl -n hw.hn.vf_transparent` +fi + +if [ $vf_transparent -ne 0 ] +then + # Transparent VF; done! + exit 0 +fi + +iface=$1 +delay=$2 + +if [ $delay -gt 0 ] +then + # + # Delayed VF up. + # + sleep $delay + ifconfig $iface up + # Done! + exit $? +fi + +# +# Check to see whether $iface is a VF or not. +# If $iface is a VF, bring it up now. +# + +# for hyperv_vf_delay +. /etc/rc.conf + +sysctl -n hw.hn.vflist > /dev/null 2>&1 +if [ $? -ne 0 ] +then + # Old kernel; nothing could be done properly. + exit 0 +fi +vf_list=`sysctl -n hw.hn.vflist` + +for vf in $vf_list +do + if [ $vf = $iface ] + then + # + # Linger a little bit (at least 2 seconds) mainly to + # make sure that $iface is fully attached. + # + # NOTE: + # In Azure hyperv_vf_delay should be configured to a + # large value, e.g. 120 seconds, to avoid racing cloud + # agent goofs. + # + test $hyperv_vf_delay -ge 2 > /dev/null 2>&1 + if [ $? -ne 0 ] + then + hyperv_vf_delay=2 + fi + # + # NOTE: + # "(sleep ..; ifconfig .. up) > /dev/null 2>&1 &" + # does _not_ work. + # + daemon -f /usr/libexec/hyperv/hyperv_vfattach \ + $iface $hyperv_vf_delay + break + fi +done diff --git a/contrib/hyperv/tools/scripts/hyperv_vfup b/contrib/hyperv/tools/scripts/hyperv_vfup new file mode 100644 index 000000000000..7a2bc595c212 --- /dev/null +++ b/contrib/hyperv/tools/scripts/hyperv_vfup @@ -0,0 +1,119 @@ +#!/bin/sh + +. /etc/rc.subr +. /etc/network.subr + +load_rc_config netif + +# +# Customized per-interface setup, e.g. hyperv_vfup.hn1 +# +# NOTE-CUSTOMIZE: +# Comment this out, if this script is used as template +# for the customized per-interface setup. +# +if [ -f /usr/libexec/hyperv/hyperv_vfup.$1 ] +then + /usr/libexec/hyperv/hyperv_vfup.$1 + exit $? +fi + +# NOTE-CUSTOMIZE: +#hn=${0##*.} +hn=$1 +hn_unit=`echo $hn | sed 's/[^0-9]*//g'` + +vf=`sysctl -n dev.hn.$hn_unit.vf` +if [ ! $vf ] +then + # Race happened; VF was removed, before we ran. + echo "$hn: VF was detached" + exit 0 +fi + +# +# Create laggX for hnX. +# Add VF and hnX to laggX. +# + +lagg=lagg$hn_unit + +ifconfig $lagg > /dev/null 2>&1 +if [ $? -ne 0 ] +then + # + # No laggX, create it now. + # + ifconfig $lagg create > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo "$lagg creation failed" + exit 1 + fi + + # + # Configure laggX (failover), add hnX and VF to it. + # + ifconfig $lagg laggproto failover laggport $hn laggport $vf + ifconfig $lagg inet6 no_dad + + # + # Stop dhclient on hnX, if any. + # + pidfile=/var/run/dhclient.$hn.pid + if [ -f $pidfile ] + then + kill -TERM `cat $pidfile` + fi + + # + # Remove all configured IPv4 addresses on hnX, e.g. + # configured by dhclient. laggX will take over the + # network operations. + # + while true + do + ifconfig $hn -alias > /dev/null 2>&1 + if [ $? -ne 0 ] + then + break + fi + done + + # TODO: Remove IPv6 addresses on hnX + + # + # Use hnX's configuration for laggX + # + # NOTE-CUSTOMIZE: + # If this script is used as template for the customized + # per-interface setup, replace this with whatever you + # want to do with the laggX. + # + if dhcpif $hn; + then + ifconfig $lagg up + if syncdhcpif $hn; + then + dhclient $lagg + else + dhclient -b $lagg + fi + else + ifconfig_args=`ifconfig_getargs $hn` + if [ -n "$ifconfig_args" ] + then + ifconfig $lagg $ifconfig_args + fi + fi +else + # + # laggX exists. Check whether VF was there or not. + # If VF was not added to laggX, add it now. + # + ifconfig $lagg | grep "laggport: $vf" > /dev/null 2>&1 + if [ $? -ne 0 ] + then + ifconfig $lagg laggport $vf + fi +fi diff --git a/etc/devd/hyperv.conf b/etc/devd/hyperv.conf index 0abf284a9ce0..10a4e2b9e5ce 100644 --- a/etc/devd/hyperv.conf +++ b/etc/devd/hyperv.conf @@ -33,3 +33,76 @@ notify 11 { match "cdev" "hv_fsvss_dev"; action "pkill -x hv_vss_daemon"; }; + +# +# Rules for non-transparent network VF. +# +# How network VF works with hn(4) on Hyper-V in non-transparent mode: +# +# - Each network VF has a cooresponding hn(4). +# - The network VF and the it's cooresponding hn(4) have the same hardware +# address. +# - Once the network VF is up, e.g. ifconfig VF up: +# o All of the transmission should go through the network VF. +# o Most of the reception goes through the network VF. +# o Small amount of reception may go through the cooresponding hn(4). +# This reception will happen, even if the the cooresponding hn(4) is +# down. The cooresponding hn(4) will change the reception interface +# to the network VF, so that network layer and application layer will +# be tricked into thinking that these packets were received by the +# network VF. +# o The cooresponding hn(4) pretends the physical link is down. +# - Once the network VF is down or detached: +# o All of the transmission should go through the cooresponding hn(4). +# o All of the reception goes through the cooresponding hn(4). +# o The cooresponding hn(4) fallbacks to the original physical link +# detection logic. +# +# All these features are mainly used to help live migration, during which +# the network VF will be detached, while the network communication to the +# VM must not be cut off. In order to reach this level of live migration +# transparency, we use failover mode lagg(4) with the network VF and the +# cooresponding hn(4) attached to it. +# +# To ease user configuration for both network VF and non-network VF, the +# lagg(4) will be created by the following rules, and the configuration +# of the cooresponding hn(4) will be applied to the lagg(4) automatically. +# +# NOTE: +# If live migration is not needed at all, the following rules could be +# commented out, and the network VF interface could be used exclusively. +# Most often the cooresponding hn(4) could be completely ignored. +# +# +# Default workflow for the network VF bringup: +# 1) ETHERNET/IFATTACH -> VF interface up (delayed by rc.conf hyperv_vf_delay +# seconds). This operation will trigger HYPERV_NIC_VF/VF_UP. +# 2) HYPERV_NIC_VF/VF_UP: +# a) Create laggX coresponding to hnX. +# b) Add hnX and VF to laggX. +# c) Whack all previous network configuration on hnX, including stopping +# dhclient. +# d) Apply rc.conf ifconfig_hnX to laggX; i.e. including starting dhclient. +# +# NOTE: +# HYPERV_NIC_VF/VF_UP action script could be customized per-interface by +# adding /usr/libexec/hyperv/hyperv_vfup.hnX script. +# /usr/libexec/hyperv/hyperv_vfup could be used as the template for the +# customized per-interface script. +# +# NOTE: +# For transparent network VF, hyperv_vfattach does nothing and +# HYPERV_NIC_VF/VF_UP will not be triggered at all. +# + +notify 10 { + match "system" "HYPERV_NIC_VF"; + match "type" "VF_UP"; + action "/usr/libexec/hyperv/hyperv_vfup $subsystem"; +}; + +notify 10 { + match "system" "ETHERNET"; + match "type" "IFATTACH"; + action "/usr/libexec/hyperv/hyperv_vfattach $subsystem 0"; +}; diff --git a/libexec/hyperv/Makefile b/libexec/hyperv/Makefile index a89b7435d2e5..6e251b24faa7 100644 --- a/libexec/hyperv/Makefile +++ b/libexec/hyperv/Makefile @@ -5,5 +5,6 @@ BINDIR= ${LIBEXECDIR}/hyperv SCRIPTS= hv_set_ifconfig hv_get_dns_info hv_get_dhcp_info +SCRIPTS+= hyperv_vfattach hyperv_vfup .include