Subversion Repositories configs

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
192 - 1
#!/bin/sh -x
2
##########################################################
3
# Copyright (C) 2001-2018 VMware, Inc. All rights reserved.
4
#
5
# This program is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU Lesser General Public License as published
7
# by the Free Software Foundation version 2.1 and no later version.
8
#
9
# This program is distributed in the hope that it will be useful, but
10
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
# or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
12
# License for more details.
13
#
14
# You should have received a copy of the GNU Lesser General Public License
15
# along with this program; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
17
#
18
##########################################################
19
 
20
 
21
#
22
# network (Linux)
23
#
24
# Using a combination of a system networking script, ifconfig, ifup, ifdown
25
# and the ip command, attempt to release and renew DHCP leases upon receipt
26
# of suspend and resume events, respectively.
27
#
28
 
29
logbase=/var/log/vmware-network
30
logfile=$logbase.log
31
 
32
#
33
# Rotate any logs
34
#
35
rotate_logfile() {
36
    max=9
37
    max=`expr $max - 1`
38
    for s in `seq $max -1 1`; do
39
        d=`expr $s + 1`
40
        mv -f $logbase.$s.log $logbase.$d.log
41
    done
42
    mv -f $logbase.log $logbase.1.log
43
}
44
 
45
rotate_logfile
46
 
47
# redirect stdio
48
exec > $logfile 2>&1
49
chmod 0600 $logfile
50
 
51
 
52
echo `date` ": Executing '$0 $*'"
53
echo
54
 
55
. `dirname "$0"`/../../statechange.subr
56
 
57
 
58
#
59
# find_networking_script --
60
#
61
#    Searches common Linux distro init/rc paths to find a singular network
62
#    services script.
63
#
64
# Result:
65
#    Returns a valid networking script path on success or "error" on failure.
66
#
67
# Side effects:
68
#    None.
69
#
70
 
71
find_networking_script() {
72
   local script="error"
73
   for dir in "/etc/init.d" "/sbin/init.d" "/etc" "/etc/rc.d" ; do
74
      if [ -d "$dir/rc0.d" ] &&
75
         [ -d "$dir/rc1.d" ] &&
76
         [ -d "$dir/rc2.d" ] &&
77
         [ -d "$dir/rc3.d" ] &&
78
         [ -d "$dir/rc4.d" ] &&
79
         [ -d "$dir/rc5.d" ] &&
80
         [ -d "$dir/rc6.d" ]; then
81
 
82
         # Now find the appropriate networking script.
83
         if [ -d "$dir/init.d" ]; then
84
            if [ -x "$dir/init.d/network" ]; then
85
               script="$dir/init.d/network"
86
            elif [ -x "$dir/init.d/networking" ]; then
87
               script="$dir/init.d/networking"
88
            fi
89
         else
90
            if [ -x "$dir/network" ]; then
91
               script="$dir/network"
92
            elif [ -x "$dir/networking" ]; then
93
               script="$dir/networking"
94
            fi
95
         fi
96
      fi
97
   done
98
 
99
   echo "$script"
100
}
101
 
102
 
103
#
104
# exec_networking_script --
105
#
106
#    Execute the networking script to bring network interfaces up or down
107
#    based on the given input action argument.
108
#
109
 
110
exec_networking_script()
111
{
112
   local script=$1
113
   local action=$2
114
 
115
   # Using SysV "service" if it exists, otherwise fall back to run the
116
   # script directly
117
   service=`which service 2>/dev/null`
118
   if [ $? = 0 -a -n "$service" ]; then
119
      serviceName=`basename "$script"`
120
      "$service" "$serviceName" "$action"
121
   else
122
      "$script" "$action"
123
   fi
124
 
125
   return $?
126
}
127
 
128
 
129
#
130
# exec_systemctl_service --
131
#
132
#    Handle linux distributions that use systemd to replace the legacy
133
#    system V startup scripts. The previous network script searching
134
#    approach is no longer viable in these systems. Invoke the systemctl
135
#    command to control the network service instead.
136
#
137
 
138
exec_systemctl_service()
139
{
140
   local rc=1
141
   local action=$1
142
   local ctlcmd=$(which systemctl 2>/dev/null)
143
   local service
144
 
145
   [ -z "$ctlcmd" ] && return $rc
146
 
147
   for svc in systemd-networkd network; do
148
      if ! $ctlcmd status $svc | grep -iq 'not-found'; then
149
         service=$svc && break
150
      fi
151
   done
152
 
153
   [ -z "$service" ] && return $rc
154
 
155
   $ctlcmd $action $service; rc=$?
156
 
157
   # When use the systemd-networkd service to shut down interfaces, interface
158
   # address and state remain unchanged. Need to use ip command to change its
159
   # address and state.
160
   if [ $rc = 0 -a $service = 'systemd-networkd' -a $action = 'stop' ]; then
161
      config_network_intfs $action; rc=$?
162
   fi
163
 
164
   return $rc
165
}
166
 
167
 
168
#
169
# del_intf_ip --
170
#
171
#    Use the ip command to remove all the addresses of an interface.
172
#
173
 
174
del_intf_ip()
175
{
176
   local nic=$1
177
 
178
   $ip_cmd addr flush dev $nic
179
   return $?
180
}
181
 
182
 
183
#
184
# ip_intf_ops --
185
#
186
#    Use the ip command to change the state of an interface to up or down.
187
#
188
 
189
ip_intf_ops()
190
{
191
   local rc=1
192
   local nic=$1
193
   local ops=$2
194
 
195
   [ -z "$ip_cmd" ] && return $rc
196
 
197
   $ip_cmd link set $nic $ops; rc=$?
198
 
199
   # Remove interface addresses when taking an interface down.
200
   if [ $rc = 0 -a $ops = down ]; then
201
      del_intf_ip $nic; rc=$?
202
   fi
203
 
204
   return $rc
205
}
206
 
207
 
208
#
209
# intf_ops --
210
#
211
#    Execute the specified command (ifup or ifdown) if available, otherwise use
212
#    the ip command as fallback. If ifup or ifdown fails, run the ip command to
213
#    retry the intended operation.
214
#
215
 
216
intf_ops()
217
{
218
   local rc=0
219
   local cmd=$1
220
   local ops=$2
221
   local nic=$3
222
   local tmp
223
 
224
   if [ ! -z "$cmd" ]; then
225
      tmp=$($cmd $nic 2>&1); rc=$?
226
 
227
      # Some systems still return a successful status even the command fails
228
      # because the interface is not configured in the configuration file. So
229
      # have to examine the command output to determine the actual status.
230
      if [ $rc = 0 ]; then
231
         echo $tmp | egrep -iq 'not configured|ignoring unknown' && rc=1
232
      fi
233
   fi
234
 
235
   # If ifup/ifdown fails, try the ip fallback.
236
   if [ -z "$cmd" -o $rc != 0 ]; then
237
      ip_intf_ops $nic $ops; rc=$?
238
   fi
239
 
240
   return $rc
241
}
242
 
243
 
244
#
245
# exec_intf_ops --
246
#
247
#    Perform an operation to bring an individual interface up or down.
248
#
249
 
250
exec_intf_ops()
251
{
252
   local rc=0
253
   local action=$1
254
   local nic=$2
255
 
256
   case $action in
257
      start)
258
         intf_ops "$ifup_cmd" up $nic; rc=$?
259
         ;;
260
      stop)
261
         intf_ops "$ifdown_cmd" down $nic; rc=$?
262
         ;;
263
      *)
264
         Panic "Illegal interface action: $action"
265
         ;;
266
   esac
267
 
268
   return $rc
269
}
270
 
271
 
272
#
273
# config_network_intfs --
274
#
275
#    For Linux systems not supporting networking scripts to bring interfaces
276
#    up or down, provide a way to change the interface state individually.
277
#
278
 
279
config_network_intfs()
280
{
281
   local rc=0
282
   local action=$1
283
 
284
   if [ -f "$activeList" ]; then
285
 
286
      while read nic; do
287
         exec_intf_ops $action $nic
288
         rc=$(expr $rc \| $?)
289
      done < $activeList
290
   fi
291
 
292
   return $rc
293
}
294
 
295
 
296
#
297
# run_network_script --
298
#
299
#    Finds out how to run the system's script used to control networking, and
300
#    runs it with the given argument (which should be one of the usual SysV
301
#    init script arguments). If it does not work, tries the other alternatives.
302
#    So far, our alternatives are (a) systemctl (b) network script (c) perform
303
#    an individual interface state change.
304
#
305
 
306
run_network_script()
307
{
308
   local action=$1
309
   local rc=0
310
   local script
311
 
312
   while true; do
313
 
314
      exec_systemctl_service $action
315
      [ $? != 0 ] || break
316
 
317
      script=`find_networking_script`
318
 
319
      if [ $script != "error" ]; then
320
         exec_networking_script $script $action
321
         [ $? != 0 ] || break
322
      fi
323
 
324
      # Since all the other alternatives fail, need to manually change
325
      # individual interface state.
326
      config_network_intfs $action; rc=$?
327
      break
328
   done
329
 
330
   return $rc
331
}
332
 
333
 
334
#
335
# save_active_NIC_list --
336
#
337
#    Records a list of every active NIC to /var/run/vmware-active-nics.
338
#
339
#    XXX What's the story on aliases?  Should they still be included, or will
340
#    they be recreated automatically upon resume?
341
#
342
# Results:
343
#    $activeList has, one per line, a list of all active NICs.
344
#
345
# Side effects:
346
#    None.
347
#
348
 
349
save_active_NIC_list()
350
{
351
   local intf_out
352
 
353
   >$activeList
354
 
355
   # Find out all the non-loopback up interfaces. Use ip if available
356
   # otherwise fall back to the ifconfig command.
357
   # ifconfig is buggy on some platforms and truncates long
358
   # network names
359
   if [ -n "$ip_cmd" ]; then
360
      for nic in $($ip_cmd link show up | egrep '\bUP\b' | awk -F: '{print $2}'); do
361
         $ip_cmd link show ${nic%@*} | grep -iq 'link/ether' && echo ${nic%@*} >> $activeList
362
      done
363
   else
364
      for nic in $($ifconfig_cmd | sed -n 's/^\([^: \t]*\).*$/\1/p'); do
365
         intf_out=$($ifconfig_cmd $nic)
366
         echo $intf_out | grep -iq loopback && continue
367
         echo $intf_out | egrep -q '\bUP\b' && echo $nic >> $activeList
368
      done
369
   fi
370
}
371
 
372
 
373
#
374
# rescue_NIC --
375
#
376
#    For each NIC recorded in $activeList that is not currently "up", run
377
#    "ifup $nic" or "ip link set $nic up" to bring the interface up.
378
#
379
# Results:
380
#    All downed NICs should be active.
381
#
382
 
383
rescue_NIC()
384
{
385
   local rc=0
386
   local intf_out
387
 
388
   if [ -f "$activeList" ]; then
389
      while read nic; do
390
         if [ -n "$ip_cmd" ]; then
391
            intf_out=$($ip_cmd link show $nic up)
392
         else
393
            intf_out=$($ifconfig_cmd $nic)
394
         fi
395
 
396
         if echo $intf_out | grep -q 'UP'; then
397
            echo `date` "[rescue_nic] $nic is already active."
398
         else
399
            echo `date` "[rescue_nic] activating $nic ..."
400
 
401
            # Our best effort to activate interfaces, use ifup if available
402
            # otherwise use the ip command as fallback.
403
            intf_ops "$ifup_cmd" up $nic
404
            rc=$(expr $rc \| $?)
405
         fi
406
      done < $activeList
407
 
408
      rm -f $activeList
409
   fi
410
 
411
   return $rc
412
}
413
 
414
 
415
#
416
# TranquilizeNetworkManager --
417
#
418
#    Put the NetworkManager daemon to sleep (maybe).
419
#
420
#    See http://projects.gnome.org/NetworkManager/developers/spec.html .
421
#
422
# Results:
423
#    Sleep(true) request is sent to the NetworkManager D-Bus interface.
424
#
425
# Side effects:
426
#    None.
427
#
428
 
429
TranquilizeNetworkManager()
430
{
431
   # `which' may be a bit noisy, so we'll shush it.
432
   dbusSend=`which dbus-send 2>/dev/null`
433
   rc=$?
434
   if [ $rc -ne 0 ]; then
435
      return $rc
436
   fi
437
 
438
   # Check NetworkManager state before disabling it.
439
   nm_state=`$dbusSend --system --print-reply		\
440
             --dest=org.freedesktop.NetworkManager	\
441
             /org/freedesktop/NetworkManager		\
442
             org.freedesktop.DBus.Properties.Get	\
443
             string:'org.freedesktop.NetworkManager'	\
444
             string:'State'				\
445
             | awk '/variant/ {print $3;}'`
446
   if [ -z "$nm_state" ]; then
447
      return 1
448
   fi
449
   # NetworkManager API     0.7/0.8   0.9
450
   # NM_STATE_ASLEEP           1      10
451
   # NM_STATE_DISCONNECTED     4      20
452
   case $nm_state in
453
      1|4|10|20)
454
         # Nothing needs to be done.
455
         return 0
456
         ;;
457
   esac
458
 
459
   # NetworkManager 0.8.0 and above
460
   $dbusSend --system --print-reply          \
461
      --dest=org.freedesktop.NetworkManager  \
462
      /org/freedesktop/NetworkManager        \
463
      org.freedesktop.NetworkManager.Enable boolean:false
464
   rc=$?
465
   if [ $rc -eq 0 ]; then
466
      return $rc
467
   fi
468
   # NetworkManager 0.7.0
469
   $dbusSend --system --print-reply          \
470
      --dest=org.freedesktop.NetworkManager  \
471
      /org/freedesktop/NetworkManager        \
472
      org.freedesktop.NetworkManager.Sleep boolean:true
473
   rc=$?
474
   if [ $rc -eq 0 ]; then
475
      return $rc
476
   fi
477
   # NetworkManager 0.6
478
   $dbusSend --system --print-reply          \
479
      --dest=org.freedesktop.NetworkManager  \
480
      /org/freedesktop/NetworkManager        \
481
      org.freedesktop.NetworkManager.sleep
482
   rc=$?
483
 
484
   return $rc
485
}
486
 
487
 
488
#
489
# WakeNetworkManager --
490
#
491
#    Wake the NetworkManager daemon (maybe).
492
#
493
#    See http://projects.gnome.org/NetworkManager/developers/spec.html .
494
#
495
# Results:
496
#    Sleep(false)request is sent to the NetworkManager D-Bus interface.
497
#
498
# Side effects:
499
#    None.
500
#
501
 
502
WakeNetworkManager()
503
{
504
   # `which' may be a bit noisy, so we'll shush it.
505
   dbusSend=`which dbus-send 2>/dev/null`
506
   rc=$?
507
   if [ $rc = 0 ]; then
508
      # NetworkManager 0.8.0
509
      $dbusSend --system --print-reply          \
510
         --dest=org.freedesktop.NetworkManager  \
511
         /org/freedesktop/NetworkManager        \
512
         org.freedesktop.NetworkManager.Enable boolean:true
513
      rc=$?
514
      if [ $rc = 0 ]; then
515
         return $rc
516
      fi
517
      # NetworkManager 0.7.0
518
      $dbusSend --system --print-reply          \
519
         --dest=org.freedesktop.NetworkManager  \
520
         /org/freedesktop/NetworkManager        \
521
         org.freedesktop.NetworkManager.Sleep boolean:false
522
      rc=$?
523
      if [ $rc = 0 ]; then
524
         return $rc
525
      fi
526
      # NetworkManager 0.6
527
      $dbusSend --system --print-reply          \
528
         --dest=org.freedesktop.NetworkManager  \
529
         /org/freedesktop/NetworkManager        \
530
         org.freedesktop.NetworkManager.wake
531
      rc=$?
532
   fi
533
   return $rc
534
}
535
 
536
 
537
#
538
# sanity_check --
539
#
540
#    Check if the script has all the commands it needs to carry out the
541
#    request. So far, it requires either ip or ifconfig command to read
542
#    interface configuration. Ifup is not checked here. It is checked at
543
#    the place where we need to do individual interface state change.
544
#
545
 
546
sanity_check()
547
{
548
   ip_cmd=$(which ip 2>/dev/null)
549
   ifconfig_cmd=$(which ifconfig 2>/dev/null)
550
   ifup_cmd=$(which ifup 2>/dev/null)
551
   ifdown_cmd=$(which ifdown 2>/dev/null)
552
 
553
   [ -z "$ifconfig_cmd" -a -z "$ip_cmd" ] && \
554
       Panic "ip and ifconfig not in search path."
555
}
556
 
557
 
558
#
559
# main --
560
#
561
#    Main entry point.  Perform some sanity checking, then map state change
562
#    events to relevant networking operations.
563
#
564
# Results:
565
#    See comment at top of file.
566
#
567
 
568
main() {
569
   exitCode=0
570
   activeList=/var/run/vmware-active-nics
571
 
572
   case "$1" in
573
      poweron-vm)
574
         rm -f $activeList
575
         ;;
576
      suspend-vm)
577
         TranquilizeNetworkManager
578
         exitCode=$?
579
         if [ $exitCode != 0 ]; then
580
            sanity_check suspend-vm
581
            save_active_NIC_list
582
            run_network_script stop
583
            exitCode=$?
584
         fi
585
         ;;
586
      resume-vm)
587
         WakeNetworkManager
588
         exitCode=$?
589
         if [ $exitCode != 0 ]; then
590
            sanity_check resume-vm
591
            # According to hfu, "/etc/init.d/networking restart" on Debian 5.0
592
            # may bring down ethernet interfaces tagged as "allow-hotplug" without
593
            # bringing them back up.
594
            #
595
            # This is especially a problem when reverting to a live, running
596
            # VM snapshot where an active NIC list hadn't yet been generated,
597
            # resulting in sudden loss of an otherwise operational NIC.
598
            #
599
            # So, if the active list doesn't exist, assume we're coming back to
600
            # a live snapshot and capture the current active list now for
601
            # rescue later.
602
            if [ ! -s $activeList ]; then
603
               save_active_NIC_list
604
            fi
605
 
606
            # We shall use start not restart here. Otherwise we may not be able
607
            # to bring back active list on distros like sles11sp2
608
            # -- PR 816791
609
            run_network_script start
610
            rescue_NIC
611
            exitCode=$?
612
         fi
613
         ;;
614
      *)
615
         echo "No argument supplied."
616
         ;;
617
   esac
618
 
619
   return $exitCode
620
}
621
 
622
main "$@"
623
echo `date` ": Finished '$0 $*'"