Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#!/bin/sh -x########################################################### Copyright (C) 2001-2018 VMware, Inc. All rights reserved.## This program is free software; you can redistribute it and/or modify it# under the terms of the GNU Lesser General Public License as published# by the Free Software Foundation version 2.1 and no later version.## This program is distributed in the hope that it will be useful, but# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY# or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public# License for more details.## You should have received a copy of the GNU Lesser General Public License# along with this program; if not, write to the Free Software Foundation, Inc.,# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.############################################################# network (Linux)## Using a combination of a system networking script, ifconfig, ifup, ifdown# and the ip command, attempt to release and renew DHCP leases upon receipt# of suspend and resume events, respectively.#logbase=/var/log/vmware-networklogfile=$logbase.log## Rotate any logs#rotate_logfile() {max=9max=`expr $max - 1`for s in `seq $max -1 1`; dod=`expr $s + 1`mv -f $logbase.$s.log $logbase.$d.logdonemv -f $logbase.log $logbase.1.log}rotate_logfile# redirect stdioexec > $logfile 2>&1chmod 0600 $logfileecho `date` ": Executing '$0 $*'"echo. `dirname "$0"`/../../statechange.subr## find_networking_script --## Searches common Linux distro init/rc paths to find a singular network# services script.## Result:# Returns a valid networking script path on success or "error" on failure.## Side effects:# None.#find_networking_script() {local script="error"for dir in "/etc/init.d" "/sbin/init.d" "/etc" "/etc/rc.d" ; doif [ -d "$dir/rc0.d" ] &&[ -d "$dir/rc1.d" ] &&[ -d "$dir/rc2.d" ] &&[ -d "$dir/rc3.d" ] &&[ -d "$dir/rc4.d" ] &&[ -d "$dir/rc5.d" ] &&[ -d "$dir/rc6.d" ]; then# Now find the appropriate networking script.if [ -d "$dir/init.d" ]; thenif [ -x "$dir/init.d/network" ]; thenscript="$dir/init.d/network"elif [ -x "$dir/init.d/networking" ]; thenscript="$dir/init.d/networking"fielseif [ -x "$dir/network" ]; thenscript="$dir/network"elif [ -x "$dir/networking" ]; thenscript="$dir/networking"fififidoneecho "$script"}## exec_networking_script --## Execute the networking script to bring network interfaces up or down# based on the given input action argument.#exec_networking_script(){local script=$1local action=$2# Using SysV "service" if it exists, otherwise fall back to run the# script directlyservice=`which service 2>/dev/null`if [ $? = 0 -a -n "$service" ]; thenserviceName=`basename "$script"`"$service" "$serviceName" "$action"else"$script" "$action"fireturn $?}## exec_systemctl_service --## Handle linux distributions that use systemd to replace the legacy# system V startup scripts. The previous network script searching# approach is no longer viable in these systems. Invoke the systemctl# command to control the network service instead.#exec_systemctl_service(){local rc=1local action=$1local ctlcmd=$(which systemctl 2>/dev/null)local service[ -z "$ctlcmd" ] && return $rcfor svc in systemd-networkd network; doif ! $ctlcmd status $svc | grep -iq 'not-found'; thenservice=$svc && breakfidone[ -z "$service" ] && return $rc$ctlcmd $action $service; rc=$?# When use the systemd-networkd service to shut down interfaces, interface# address and state remain unchanged. Need to use ip command to change its# address and state.if [ $rc = 0 -a $service = 'systemd-networkd' -a $action = 'stop' ]; thenconfig_network_intfs $action; rc=$?fireturn $rc}## del_intf_ip --## Use the ip command to remove all the addresses of an interface.#del_intf_ip(){local nic=$1$ip_cmd addr flush dev $nicreturn $?}## ip_intf_ops --## Use the ip command to change the state of an interface to up or down.#ip_intf_ops(){local rc=1local nic=$1local ops=$2[ -z "$ip_cmd" ] && return $rc$ip_cmd link set $nic $ops; rc=$?# Remove interface addresses when taking an interface down.if [ $rc = 0 -a $ops = down ]; thendel_intf_ip $nic; rc=$?fireturn $rc}## intf_ops --## Execute the specified command (ifup or ifdown) if available, otherwise use# the ip command as fallback. If ifup or ifdown fails, run the ip command to# retry the intended operation.#intf_ops(){local rc=0local cmd=$1local ops=$2local nic=$3local tmpif [ ! -z "$cmd" ]; thentmp=$($cmd $nic 2>&1); rc=$?# Some systems still return a successful status even the command fails# because the interface is not configured in the configuration file. So# have to examine the command output to determine the actual status.if [ $rc = 0 ]; thenecho $tmp | egrep -iq 'not configured|ignoring unknown' && rc=1fifi# If ifup/ifdown fails, try the ip fallback.if [ -z "$cmd" -o $rc != 0 ]; thenip_intf_ops $nic $ops; rc=$?fireturn $rc}## exec_intf_ops --## Perform an operation to bring an individual interface up or down.#exec_intf_ops(){local rc=0local action=$1local nic=$2case $action instart)intf_ops "$ifup_cmd" up $nic; rc=$?;;stop)intf_ops "$ifdown_cmd" down $nic; rc=$?;;*)Panic "Illegal interface action: $action";;esacreturn $rc}## config_network_intfs --## For Linux systems not supporting networking scripts to bring interfaces# up or down, provide a way to change the interface state individually.#config_network_intfs(){local rc=0local action=$1if [ -f "$activeList" ]; thenwhile read nic; doexec_intf_ops $action $nicrc=$(expr $rc \| $?)done < $activeListfireturn $rc}## run_network_script --## Finds out how to run the system's script used to control networking, and# runs it with the given argument (which should be one of the usual SysV# init script arguments). If it does not work, tries the other alternatives.# So far, our alternatives are (a) systemctl (b) network script (c) perform# an individual interface state change.#run_network_script(){local action=$1local rc=0local scriptwhile true; doexec_systemctl_service $action[ $? != 0 ] || breakscript=`find_networking_script`if [ $script != "error" ]; thenexec_networking_script $script $action[ $? != 0 ] || breakfi# Since all the other alternatives fail, need to manually change# individual interface state.config_network_intfs $action; rc=$?breakdonereturn $rc}## save_active_NIC_list --## Records a list of every active NIC to /var/run/vmware-active-nics.## XXX What's the story on aliases? Should they still be included, or will# they be recreated automatically upon resume?## Results:# $activeList has, one per line, a list of all active NICs.## Side effects:# None.#save_active_NIC_list(){local intf_out>$activeList# Find out all the non-loopback up interfaces. Use ip if available# otherwise fall back to the ifconfig command.# ifconfig is buggy on some platforms and truncates long# network namesif [ -n "$ip_cmd" ]; thenfor nic in $($ip_cmd link show up | egrep '\bUP\b' | awk -F: '{print $2}'); do$ip_cmd link show ${nic%@*} | grep -iq 'link/ether' && echo ${nic%@*} >> $activeListdoneelsefor nic in $($ifconfig_cmd | sed -n 's/^\([^: \t]*\).*$/\1/p'); dointf_out=$($ifconfig_cmd $nic)echo $intf_out | grep -iq loopback && continueecho $intf_out | egrep -q '\bUP\b' && echo $nic >> $activeListdonefi}## rescue_NIC --## For each NIC recorded in $activeList that is not currently "up", run# "ifup $nic" or "ip link set $nic up" to bring the interface up.## Results:# All downed NICs should be active.#rescue_NIC(){local rc=0local intf_outif [ -f "$activeList" ]; thenwhile read nic; doif [ -n "$ip_cmd" ]; thenintf_out=$($ip_cmd link show $nic up)elseintf_out=$($ifconfig_cmd $nic)fiif echo $intf_out | grep -q 'UP'; thenecho `date` "[rescue_nic] $nic is already active."elseecho `date` "[rescue_nic] activating $nic ..."# Our best effort to activate interfaces, use ifup if available# otherwise use the ip command as fallback.intf_ops "$ifup_cmd" up $nicrc=$(expr $rc \| $?)fidone < $activeListrm -f $activeListfireturn $rc}## TranquilizeNetworkManager --## Put the NetworkManager daemon to sleep (maybe).## See http://projects.gnome.org/NetworkManager/developers/spec.html .## Results:# Sleep(true) request is sent to the NetworkManager D-Bus interface.## Side effects:# None.#TranquilizeNetworkManager(){# `which' may be a bit noisy, so we'll shush it.dbusSend=`which dbus-send 2>/dev/null`rc=$?if [ $rc -ne 0 ]; thenreturn $rcfi# Check NetworkManager state before disabling it.nm_state=`$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.DBus.Properties.Get \string:'org.freedesktop.NetworkManager' \string:'State' \| awk '/variant/ {print $3;}'`if [ -z "$nm_state" ]; thenreturn 1fi# NetworkManager API 0.7/0.8 0.9# NM_STATE_ASLEEP 1 10# NM_STATE_DISCONNECTED 4 20case $nm_state in1|4|10|20)# Nothing needs to be done.return 0;;esac# NetworkManager 0.8.0 and above$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.NetworkManager.Enable boolean:falserc=$?if [ $rc -eq 0 ]; thenreturn $rcfi# NetworkManager 0.7.0$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.NetworkManager.Sleep boolean:truerc=$?if [ $rc -eq 0 ]; thenreturn $rcfi# NetworkManager 0.6$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.NetworkManager.sleeprc=$?return $rc}## WakeNetworkManager --## Wake the NetworkManager daemon (maybe).## See http://projects.gnome.org/NetworkManager/developers/spec.html .## Results:# Sleep(false)request is sent to the NetworkManager D-Bus interface.## Side effects:# None.#WakeNetworkManager(){# `which' may be a bit noisy, so we'll shush it.dbusSend=`which dbus-send 2>/dev/null`rc=$?if [ $rc = 0 ]; then# NetworkManager 0.8.0$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.NetworkManager.Enable boolean:truerc=$?if [ $rc = 0 ]; thenreturn $rcfi# NetworkManager 0.7.0$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.NetworkManager.Sleep boolean:falserc=$?if [ $rc = 0 ]; thenreturn $rcfi# NetworkManager 0.6$dbusSend --system --print-reply \--dest=org.freedesktop.NetworkManager \/org/freedesktop/NetworkManager \org.freedesktop.NetworkManager.wakerc=$?fireturn $rc}## sanity_check --## Check if the script has all the commands it needs to carry out the# request. So far, it requires either ip or ifconfig command to read# interface configuration. Ifup is not checked here. It is checked at# the place where we need to do individual interface state change.#sanity_check(){ip_cmd=$(which ip 2>/dev/null)ifconfig_cmd=$(which ifconfig 2>/dev/null)ifup_cmd=$(which ifup 2>/dev/null)ifdown_cmd=$(which ifdown 2>/dev/null)[ -z "$ifconfig_cmd" -a -z "$ip_cmd" ] && \Panic "ip and ifconfig not in search path."}## main --## Main entry point. Perform some sanity checking, then map state change# events to relevant networking operations.## Results:# See comment at top of file.#main() {exitCode=0activeList=/var/run/vmware-active-nicscase "$1" inpoweron-vm)rm -f $activeList;;suspend-vm)TranquilizeNetworkManagerexitCode=$?if [ $exitCode != 0 ]; thensanity_check suspend-vmsave_active_NIC_listrun_network_script stopexitCode=$?fi;;resume-vm)WakeNetworkManagerexitCode=$?if [ $exitCode != 0 ]; thensanity_check resume-vm# According to hfu, "/etc/init.d/networking restart" on Debian 5.0# may bring down ethernet interfaces tagged as "allow-hotplug" without# bringing them back up.## This is especially a problem when reverting to a live, running# VM snapshot where an active NIC list hadn't yet been generated,# resulting in sudden loss of an otherwise operational NIC.## So, if the active list doesn't exist, assume we're coming back to# a live snapshot and capture the current active list now for# rescue later.if [ ! -s $activeList ]; thensave_active_NIC_listfi# We shall use start not restart here. Otherwise we may not be able# to bring back active list on distros like sles11sp2# -- PR 816791run_network_script startrescue_NICexitCode=$?fi;;*)echo "No argument supplied.";;esacreturn $exitCode}main "$@"echo `date` ": Finished '$0 $*'"