Linux lhjmq-records 5.15.0-118-generic #128-Ubuntu SMP Fri Jul 5 09:28:59 UTC 2024 x86_64
Your IP : 3.141.41.109
#!/bin/sh -x
##########################################################
# Copyright (C) 2001-2018, 2021 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.
#
SOURCE=$0
logdir=/var/log
logbase=$logdir/vmware-network
logfile=$logbase.log
# Defines logging mode enabled (1) or disabled (0)
logmode=1
# Defines whether to rotate logs (1) or not (0)
logrotate=1
#
# Get log file path
#
get_logfile() {
file=`vmware-toolbox-cmd config get logging network.data | \
sed -e 's/.*= *//' -e 's/ *$//'`
if [ -n "${file##*"UNSET"*}" ]; then
logfile=$file
logdir=`dirname $logfile`
logbase=`echo $logfile | sed 's/\..*$//'`
fi
}
#
# Get Network logging config
#
get_logconfig() {
handler=`vmware-toolbox-cmd config get logging network.handler | \
sed -e 's/.*= *//' -e 's/ *$//'`
case $handler in
"file")
get_logfile
;;
"file+")
get_logfile
logrotate=0
;;
"vmx"|"std")
logrotate=0
;;
"syslog")
logfile=/var/log/syslog
logdir=`dirname $logfile`
logrotate=0
;;
*)
;;
esac
}
#
# Rotate any logs
#
rotate_logfile() {
if [ $logrotate -eq 1 ]; then
max=`vmware-toolbox-cmd config get logging network.maxOldLogFiles | \
sed -e 's/.*= *//' -e 's/ *$//'`
if [ -z "${max##*"UNSET"*}" -o `expr "$max" : '[0-9]\+$'` -eq 0 ]; then
max=9
fi
max=`expr $max - 1`
for s in `seq $max -1 1`; do
d=`expr $s + 1`
mv -f $logbase.$s.log $logbase.$d.log
done
mv -f $logbase.log $logbase.1.log
fi
}
#
# Logging api
#
log() {
if [ $logmode -eq 1 ]; then
if [ "$handler" = "vmx" ]; then
`vmtoolsd --cmd "log $*"`
elif [ "$handler" = "std" ]; then
echo `date` ": $*"
elif [ -w $logdir ]; then
space=`df -k $logdir | awk 'NR == 2 { print $4 }'`
if [ $space -gt 1024 ]; then
echo `date` ": $*" >> $logfile
else
`vmtoolsd --cmd "log WARNING: [$SOURCE] Logging disabled. No space left in $logdir"`
logmode=0
fi
else
`vmtoolsd --cmd "log WARNING: [$SOURCE] Logging disabled. $logdir is not writable"`
logmode=0
fi
fi
}
get_logconfig
rotate_logfile
log "Executing '$0 $*'"
. `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" ; do
if [ -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" ]; then
if [ -x "$dir/init.d/network" ]; then
script="$dir/init.d/network"
elif [ -x "$dir/init.d/networking" ]; then
script="$dir/init.d/networking"
fi
else
if [ -x "$dir/network" ]; then
script="$dir/network"
elif [ -x "$dir/networking" ]; then
script="$dir/networking"
fi
fi
fi
done
log "$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=$1
local action=$2
# Using SysV "service" if it exists, otherwise fall back to run the
# script directly
service=`which service 2>/dev/null`
if [ $? = 0 -a -n "$service" ]; then
serviceName=`basename "$script"`
"$service" "$serviceName" "$action"
else
"$script" "$action"
fi
return $?
}
#
# 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=1
local action=$1
local ctlcmd=$(which systemctl 2>/dev/null)
local service
[ -z "$ctlcmd" ] && return $rc
for svc in systemd-networkd network; do
if ! $ctlcmd status $svc | grep -iq 'not-found'; then
service=$svc && break
fi
done
[ -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' ]; then
config_network_intfs $action; rc=$?
fi
return $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 $nic
return $?
}
#
# ip_intf_ops --
#
# Use the ip command to change the state of an interface to up or down.
#
ip_intf_ops()
{
local rc=1
local nic=$1
local 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 ]; then
del_intf_ip $nic; rc=$?
fi
return $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=0
local cmd=$1
local ops=$2
local nic=$3
local tmp
if [ ! -z "$cmd" ]; then
tmp=$($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 ]; then
echo $tmp | egrep -iq 'not configured|ignoring unknown' && rc=1
fi
fi
# If ifup/ifdown fails, try the ip fallback.
if [ -z "$cmd" -o $rc != 0 ]; then
ip_intf_ops $nic $ops; rc=$?
fi
return $rc
}
#
# exec_intf_ops --
#
# Perform an operation to bring an individual interface up or down.
#
exec_intf_ops()
{
local rc=0
local action=$1
local nic=$2
case $action in
start)
intf_ops "$ifup_cmd" up $nic; rc=$?
;;
stop)
intf_ops "$ifdown_cmd" down $nic; rc=$?
;;
*)
Panic "Illegal interface action: $action"
;;
esac
return $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=0
local action=$1
if [ -f "$activeList" ]; then
while read nic; do
exec_intf_ops $action $nic
rc=$(expr $rc \| $?)
done < $activeList
fi
return $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=$1
local rc=0
local script
while true; do
exec_systemctl_service $action
[ $? != 0 ] || break
script=`find_networking_script`
if [ $script != "error" ]; then
exec_networking_script $script $action
[ $? != 0 ] || break
fi
# Since all the other alternatives fail, need to manually change
# individual interface state.
config_network_intfs $action; rc=$?
break
done
return $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 names
if [ -n "$ip_cmd" ]; then
for 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%@*} >> $activeList
done
else
for nic in $($ifconfig_cmd | sed -n 's/^\([^: \t]*\).*$/\1/p'); do
intf_out=$($ifconfig_cmd $nic)
echo $intf_out | grep -iq loopback && continue
echo $intf_out | egrep -q '\bUP\b' && echo $nic >> $activeList
done
fi
}
#
# 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=0
local intf_out
if [ -f "$activeList" ]; then
while read nic; do
if [ -n "$ip_cmd" ]; then
intf_out=$($ip_cmd link show $nic up)
else
intf_out=$($ifconfig_cmd $nic)
fi
if echo $intf_out | grep -q 'UP'; then
log "[rescue_nic] $nic is already active."
else
log "[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 $nic
rc=$(expr $rc \| $?)
fi
done < $activeList
rm -f $activeList
fi
return $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 ]; then
return $rc
fi
# 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" ]; then
return 1
fi
# NetworkManager API 0.7/0.8 0.9
# NM_STATE_ASLEEP 1 10
# NM_STATE_DISCONNECTED 4 20
case $nm_state in
1|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:false
rc=$?
if [ $rc -eq 0 ]; then
return $rc
fi
# NetworkManager 0.7.0
$dbusSend --system --print-reply \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.Sleep boolean:true
rc=$?
if [ $rc -eq 0 ]; then
return $rc
fi
# NetworkManager 0.6
$dbusSend --system --print-reply \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.sleep
rc=$?
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:true
rc=$?
if [ $rc = 0 ]; then
return $rc
fi
# NetworkManager 0.7.0
$dbusSend --system --print-reply \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.Sleep boolean:false
rc=$?
if [ $rc = 0 ]; then
return $rc
fi
# NetworkManager 0.6
$dbusSend --system --print-reply \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.wake
rc=$?
fi
return $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=0
activeList=/var/run/vmware-active-nics
case "$1" in
poweron-vm)
rm -f $activeList
;;
suspend-vm)
TranquilizeNetworkManager
exitCode=$?
if [ $exitCode != 0 ]; then
sanity_check suspend-vm
save_active_NIC_list
run_network_script stop
exitCode=$?
fi
;;
resume-vm)
WakeNetworkManager
exitCode=$?
if [ $exitCode != 0 ]; then
sanity_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 ]; then
save_active_NIC_list
fi
# We shall use start not restart here. Otherwise we may not be able
# to bring back active list on distros like sles11sp2
# -- PR 816791
run_network_script start
rescue_NIC
exitCode=$?
fi
;;
*)
log "No argument supplied."
;;
esac
return $exitCode
}
main "$@"
log "Finished '$0 $*'"
|