2 # Copyright (c) 2004-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
5 # Contributed by Roy Marples (uberlord@gentoo.org)
6 # Many thanks to Aron Griffis (agriffis@gentoo.org)
7 # for help, ideas and patches
9 #NB: Config is in /etc/conf.d/net
11 # For pcmcia users. note that pcmcia must be added to the same
12 # runlevel as the net.* script that needs it.
15 after bootmisc hostname
16 use isapnp isdn pcmcia usb wlan
18 # Load any custom depend functions for the given interface
19 # For example, br0 may need eth0 and eth1
20 local iface="${SVCNAME#*.}"
21 [[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
23 if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
26 # Support new style RC_NEED and RC_USE in one net file
27 local x="RC_NEED_${iface}"
28 [[ -n ${!x} ]] && need ${!x}
30 [[ -n ${!x} ]] && use ${!x}
36 # Define where our modules are
37 MODULES_DIR="${svclib}/net"
39 # Make some wrappers to fudge after/before/need/use depend flags.
40 # These are callbacks so MODULE will be set.
42 eval "${MODULE}_after() { echo \"$*\"; }"
45 eval "${MODULE}_before() { echo \"$*\"; }"
48 eval "${MODULE}_need() { echo \"$*\"; }"
51 # We deliberately misspell this as _installed will probably be used
53 eval "${MODULE}_instlled() { echo \"$*\"; }"
56 eval "${MODULE}_provide() { echo \"$*\"; }"
59 eval "${MODULE}_functions() { echo \"$*\"; }"
62 eval "${MODULE}_variables() { echo \"$*\"; }"
66 [[ $1 == "lo" || $1 == "lo0" ]]
69 # char* interface_device(char *iface)
71 # Gets the base device of the interface
72 # Can handle eth0:1 and eth0.1
73 # Which returns eth0 in this case
76 [[ ${dev} == "$1" ]] && dev="${1%%:*}"
80 # char* interface_type(char* iface)
82 # Returns the base type of the interface
88 # int calculate_metric(char *interface, int base)
90 # Calculates the best metric for the interface
91 # We use this when we add routes so we can prefer interfaces over each other
93 local iface="$1" metric="$2"
95 # Have we already got a metric?
96 local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
98 if [[ -n ${m} ]] ; then
103 local i= dest= gw= flags= ref= u= m= mtu= metrics=
104 while read i dest gw flags ref u m mtu ; do
106 is_loopback "${i}" && continue
107 # We work out metrics from default routes only
108 [[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
109 metrics="${metrics}\n${m}"
110 done < /proc/net/route
112 # Now, sort our metrics
113 metrics=$(echo -e "${metrics}" | sort -n)
115 # Now, find the lowest we can use
117 for m in ${metrics} ; do
118 [[ ${m} -lt ${metric} ]] && continue
119 [[ ${m} == ${metric} ]] && ((metric++))
120 [[ ${m} -gt ${metric} ]] && break
126 # int netmask2cidr(char *netmask)
128 # Returns the CIDR of a given netmask
130 local binary= i= bin=
132 for i in ${1//./ }; do
134 while [[ ${i} != "0" ]] ; do
138 binary="${binary}${bin}"
140 binary="${binary%%0*}"
145 # bool is_function(char* name)
147 # Returns 0 if the given name is a shell function, otherwise 1
149 [[ -z $1 ]] && return 1
150 [[ $(type -t "$1") == "function" ]]
153 # void function_wrap(char* source, char* target)
155 # wraps function calls - for example function_wrap(this, that)
156 # maps function names this_* to that_*
160 is_function "${2}_depend" && return
162 for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
163 eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
167 # char[] * expand_parameters(char *cmd)
169 # Returns an array after expanding parameters. For example
170 # "192.168.{1..3}.{1..3}/24 brd +"
172 # "192.168.1.1/24 brd +"
173 # "192.168.1.2/24 brd +"
174 # "192.168.1.3/24 brd +"
175 # "192.168.2.1/24 brd +"
176 # "192.168.2.2/24 brd +"
177 # "192.168.2.3/24 brd +"
178 # "192.168.3.1/24 brd +"
179 # "192.168.3.2/24 brd +"
180 # "192.168.3.3/24 brd +"
181 expand_parameters() {
182 local x=$(eval echo ${@// /_})
190 # void configure_variables(char *interface, char *option1, [char *option2])
192 # Maps configuration options from <variable>_<option> to <variable>_<iface>
193 # option2 takes precedence over option1
194 configure_variables() {
195 local iface="$1" option1="$2" option2="$3"
197 local mod= func= x= i=
198 local -a ivars=() ovars1=() ovars2=()
199 local ifvar=$(bash_variable "${iface}")
201 for mod in ${MODULES[@]}; do
202 is_function ${mod}_variables || continue
203 for v in $(${mod}_variables) ; do
205 [[ -n ${option2} ]] && x="${v}_${option2}[@]"
206 [[ -z ${!x} ]] && x="${v}_${option1}[@]"
207 [[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
213 # bool module_load_minimum(char *module)
215 # Does the minimum checking on a module - even when forcing
216 module_load_minimum() {
217 local f="$1.sh" MODULE="${1##*/}"
219 if [[ ! -f ${f} ]] ; then
220 eerror "${f} does not exist"
224 if ! source "${f}" ; then
225 eerror "${MODULE} failed a sanity check"
230 is_function "${MODULE}_${f}" && continue
231 eerror "${MODULE}.sh does not support the required function ${f}"
238 # bool modules_load_auto()
240 # Load and check each module for sanity
241 # If the module is not installed, the functions are to be removed
242 modules_load_auto() {
245 # Populate the MODULES array
246 # Basically we treat evey file in ${MODULES_DIR} as a module
247 MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
249 for (( i=0; i<j; i++ )); do
250 MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
251 [[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
253 MODULES=( "${MODULES[@]}" )
255 # Each of these sources into the global namespace, so it's
256 # important that module functions and variables are prefixed with
257 # the module name, for example iproute2_
260 loaded_interface=false
261 for (( i=0; i<j; i++ )); do
262 MODULES[i]="${MODULES[i]%.sh*}"
263 if [[ ${MODULES[i]##*/} == "interface" ]] ; then
264 eerror "interface is a reserved name - cannot load a module called interface"
270 module_load_minimum "${MODULES[i]}" || u=1;
271 if [[ ${u} == 0 ]] ; then
272 inst="${MODULES[i]##*/}_check_installed";
273 if is_function "${inst}" ; then
274 ${inst} false || u=1;
280 if [[ $? == 0 ]] ; then
281 source "${MODULES[i]}.sh"
282 MODULES[i]="${MODULES[i]##*/}"
288 MODULES=( "${MODULES[@]}" )
292 # bool modules_check_installed(void)
294 # Ensure that all modules have the required modules loaded
295 # This enables us to remove modules from the MODULES array
296 # Whilst other modules can still explicitly call them
297 # One example of this is essidnet which configures network
298 # settings for the specific ESSID connected to as the user
299 # may be using a daemon to configure wireless instead of our
301 modules_check_installed() {
302 local i j missingdeps nmods="${#MODULES[@]}"
304 for (( i=0; i<nmods; i++ )); do
305 is_function "${MODULES[i]}_instlled" || continue
306 for j in $( ${MODULES[i]}_instlled ); do
308 if is_function "${j}_check_installed" ; then
309 ${j}_check_installed && missingdeps=false
310 elif is_function "${j}_depend" ; then
313 ${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
317 MODULES=( "${MODULES[@]}" )
318 PROVIDES=( "${PROVIDES[@]}" )
321 # bool modules_check_user(void)
322 modules_check_user() {
323 local iface="$1" ifvar=$(bash_variable "${IFACE}")
324 local i= j= k= l= nmods="${#MODULES[@]}"
327 # Has the interface got any specific modules?
328 umods="modules_${ifvar}[@]"
329 umods=( "${!umods}" )
331 # Global setting follows interface-specific setting
332 umods=( "${umods[@]}" "${modules[@]}" )
334 # Add our preferred modules
335 local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
336 umods=( "${umods[@]}" "${pmods[@]}" )
338 # First we strip any modules that conflict from user settings
339 # So if the user specifies pump then we don't use dhcpcd
340 for (( i=0; i<${#umods[@]}; i++ )); do
341 # Some users will inevitably put "dhcp" in their modules
342 # list. To keep users from screwing up their system this
343 # way, ignore this setting so that the default dhcp
344 # module will be used.
345 [[ ${umods[i]} == "dhcp" ]] && continue
347 # We remove any modules we explicitly don't want
348 if [[ ${umods[i]} == "!"* ]] ; then
349 for (( j=0; j<nmods; j++ )); do
350 [[ -z ${MODULES[j]} ]] && continue
351 if [[ ${umods[i]:1} == "${MODULES[j]}" \
352 || ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
353 # We may need to setup a class wrapper for it even though
354 # we don't use it directly
355 # However, we put it into an array and wrap later as
356 # another module may provide the same thing
357 ${MODULES[j]}_check_installed \
360 "${MODULES[j]} ${PROVIDES[j]}"
369 if ! is_function "${umods[i]}_depend" ; then
370 # If the module is one of our preferred modules, then
371 # ignore this error; whatever is available will be
373 (( i < ${#umods[@]} - ${#pmods[@]} )) || continue
375 # The function may not exist because the modules software is
376 # not installed. Load the module and report its error
377 if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
378 source "${MODULES_DIR}/${umods[i]}.sh"
379 is_function "${umods[i]}_check_installed" \
380 && ${umods[i]}_check_installed true
382 eerror "The module \"${umods[i]}\" does not exist"
387 if is_function "${umods[i]}_provide" ; then
388 mod=$(${umods[i]}_provide)
392 for (( j=0; j<nmods; j++ )); do
393 [[ -z ${MODULES[j]} ]] && continue
394 if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
395 # We don't have a match - now ensure that we still provide an
396 # alternative. This is to handle our preferred modules.
397 for (( l=0; l<nmods; l++ )); do
398 [[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
399 if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
409 # Then we strip conflicting modules.
410 # We only need to do this for 3rd party modules that conflict with
411 # our own modules and the preferred list AND the user modules
412 # list doesn't specify a preference.
413 for (( i=0; i<nmods-1; i++ )); do
414 [[ -z ${MODULES[i]} ]] && continue
415 for (( j=i+1; j<nmods; j++)); do
416 [[ -z ${MODULES[j]} ]] && continue
417 [[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
418 && unset MODULES[j] && unset PROVIDES[j]
422 MODULES=( "${MODULES[@]}" )
423 PROVIDES=( "${PROVIDES[@]}" )
427 # void modules_sort(void)
431 local i= j= nmods=${#MODULES[@]} m=
432 local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
434 # Make our provide list
435 for ((i=0; i<nmods; i++)); do
437 if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
439 for ((j=0; j<${#provide[@]}; j++)); do
440 if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
441 provide_list[j]="${provide_list[j]} ${MODULES[i]}"
445 if ! ${provided}; then
446 provide[j]="${PROVIDES[i]}"
447 provide_list[j]="${MODULES[i]}"
452 # Create an after array, which holds which modules the module at
453 # index i must be after
454 for ((i=0; i<nmods; i++)); do
455 if is_function "${MODULES[i]}_after" ; then
456 after[i]=" ${after[i]} $(${MODULES[i]}_after) "
458 if is_function "${MODULES[i]}_before" ; then
459 for m in $(${MODULES[i]}_before); do
460 for ((j=0; j<nmods; j++)) ; do
461 if [[ ${PROVIDES[j]} == "${m}" ]] ; then
462 after[j]=" ${after[j]} ${MODULES[i]} "
470 # Replace the after list modules with real modules
471 for ((i=0; i<nmods; i++)); do
472 if [[ -n ${after[i]} ]] ; then
473 for ((j=0; j<${#provide[@]}; j++)); do
474 after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
479 # We then use the below code to provide a topologial sort
480 module_after_visit() {
481 local name="$1" i= x=
483 for ((i=0; i<nmods; i++)); do
484 [[ ${MODULES[i]} == "$1" ]] && break
490 for x in ${after[i]} ; do
491 module_after_visit "${x}"
494 sorted=( "${sorted[@]}" "${MODULES[i]}" )
495 sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
498 for x in ${MODULES[@]}; do
499 module_after_visit "${x}"
502 MODULES=( "${sorted[@]}" )
503 PROVIDES=( "${sortedp[@]}" )
506 # bool modules_check_depends(bool showprovides)
507 modules_check_depends() {
508 local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
509 local missingdeps= p= interface=false
511 for (( i=0; i<nmods; i++ )); do
512 if is_function "${MODULES[i]}_need" ; then
513 for needmod in $(${MODULES[i]}_need); do
515 for (( j=0; j<nmods; j++ )); do
516 if [[ ${needmod} == "${MODULES[j]}" \
517 || ${needmod} == "${PROVIDES[j]}" ]] ; then
522 if ${missingdeps} ; then
523 eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
529 if is_function "${MODULES[i]}_functions" ; then
530 for f in $(${MODULES[i]}_functions); do
531 if ! is_function "${f}" ; then
532 eerror "${MODULES[i]}: missing required function \"${f}\""
538 [[ ${PROVIDES[i]} == "interface" ]] && interface=true
540 if ${showprovides} ; then
541 [[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
542 && veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
546 if ! ${interface} ; then
547 eerror "no interface module has been loaded"
554 # bool modules_load(char *iface, bool starting)
556 # Loads the defined handler and modules for the interface
557 # Returns 0 on success, otherwise 1
559 local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
561 local RC_INDENTATION="${RC_INDENTATION}"
562 local -a PROVIDES=() WRAP_MODULES=()
564 if ! is_loopback "${iface}" ; then
565 x="modules_force_${iface}[@]"
566 [[ -n ${!x} ]] && modules_force=( "${!x}" )
567 if [[ -n ${modules_force} ]] ; then
568 ewarn "WARNING: You are forcing modules!"
569 ewarn "Do not complain or file bugs if things start breaking"
574 veinfo "Loading networking modules for ${iface}"
577 if [[ -z ${modules_force} ]] ; then
578 modules_load_auto || return 1
580 j="${#modules_force[@]}"
581 for (( i=0; i<j; i++ )); do
582 module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
583 if is_function "${modules_force[i]}_check_installed" ; then
584 ${modules_force[i]}_check_installed || unset modules_force[i]
587 MODULES=( "${modules_force[@]}" )
591 for (( i=0; i<j; i++ )); do
592 # Now load our dependencies - we need to use the MODULE variable
593 # here as the after/before/need functions use it
594 MODULE="${MODULES[i]}"
597 # expose does exactly the same thing as depend
598 # However it is more "correct" as it exposes things to other modules
599 # instead of depending on them ;)
600 is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
602 # If no provide is given, assume module name
603 if is_function "${MODULES[i]}_provide" ; then
604 PROVIDES[i]=$(${MODULES[i]}_provide)
606 PROVIDES[i]="${MODULES[i]}"
610 if [[ -n ${modules_force[@]} ]] ; then
611 # Strip any duplicate modules providing the same thing
613 for (( i=0; i<j-1; i++ )); do
614 [[ -z ${MODULES[i]} ]] && continue
615 for (( k=i+1; k<j; k++ )); do
616 if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
622 MODULES=( "${MODULES[@]}" )
623 PROVIDES=( "${PROVIDES[@]}" )
626 modules_check_user "${iface}" || return 1
628 # Always prefer iproute2 for taking down interfaces
629 if is_function iproute2_provide ; then
630 function_wrap iproute2 "$(iproute2_provide)"
637 for (( i=0; i<j; i++ )); do
638 function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
640 j="${#WRAP_MODULES[@]}"
641 for (( i=0; i<j; i++ )); do
642 function_wrap ${WRAP_MODULES[i]}
645 if [[ -z ${modules_force[@]} ]] ; then
646 modules_check_installed || return 1
647 modules_sort || return 1
650 veinfo "modules: ${MODULES[@]}"
653 ${starting} && p=true
654 modules_check_depends "${p}" || return 1
658 # bool iface_start(char *interface)
660 # iface_start is called from start. It's expected to start the base
661 # interface (for example "eth0"), aliases (for example "eth0:1") and to start
662 # VLAN interfaces (for example eth0.0, eth0.1). VLAN setup is accomplished by
663 # calling itself recursively.
665 local iface="$1" mod config_counter="-1" x config_worked=false
666 local RC_INDENTATION="${RC_INDENTATION}"
667 local -a config=() fallback=() fallback_route=() conf=() a=() b=()
668 local ifvar=$(bash_variable "$1") i= j= metric=0
670 # pre Start any modules with
671 for mod in ${MODULES[@]}; do
672 if is_function "${mod}_pre_start" ; then
673 ${mod}_pre_start "${iface}" || { eend 1; return 1; }
678 # If we don't have a metric then calculate one
679 # Our modules will set the metric variable to a suitable base
680 # in their pre starts.
681 if [[ -z ${!x} ]] ; then
682 eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
685 # We now expand the configuration parameters and pray that the
686 # fallbacks expand to the same number as config or there will be
688 a="config_${ifvar}[@]"
690 for (( i=0; i<${#a[@]}; i++ )); do
691 eval b=( $(expand_parameters "${a[i]}") )
692 config=( "${config[@]}" "${b[@]}" )
695 a="fallback_${ifvar}[@]"
697 for (( i=0; i<${#a[@]}; i++ )); do
698 eval b=( $(expand_parameters "${a[i]}") )
699 fallback=( "${fallback[@]}" "${b[@]}" )
702 # We don't expand routes
703 fallback_route="fallback_route_${ifvar}[@]"
704 fallback_route=( "${!fallback_route}" )
706 # We must support old configs
707 if [[ -z ${config} ]] ; then
708 interface_get_old_config "${iface}" || return 1
709 if [[ -n ${config} ]] ; then
710 ewarn "You are using a deprecated configuration syntax for ${iface}"
711 ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
715 # Handle "noop" correctly
716 if [[ ${config[0]} == "noop" ]] ; then
717 if interface_is_up "${iface}" true ; then
718 einfo "Keeping current configuration for ${iface}"
723 # Remove noop from the config var
724 config=( "${config[@]:1}" )
727 # Provide a default of DHCP if no configuration is set and we're auto
728 # Otherwise a default of NULL
729 if [[ -z ${config} ]] ; then
730 ewarn "Configuration not set for ${iface} - assuming DHCP"
731 if is_function "dhcp_start" ; then
734 eerror "No DHCP client installed"
739 einfo "Bringing up ${iface}"
741 for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
742 # Handle null and noop correctly
743 if [[ ${config[config_counter]} == "null" \
744 || ${config[config_counter]} == "noop" ]] ; then
750 # We convert it to an array - this has the added
751 # bonus of trimming spaces!
752 conf=( ${config[config_counter]} )
755 # Do we have a function for our config?
756 if is_function "${conf[0]}_start" ; then
758 ${conf[0]}_start "${iface}" ; x=$?
760 [[ ${x} == 0 ]] && config_worked=true && continue
761 # We need to test to see if it's an IP address or a function
762 # We do this by testing if the 1st character is a digit
763 elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
765 if ! is_loopback "${iface}" ; then
766 if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
767 if arping_address_exists "${iface}" "${conf[0]}" ; then
768 eerror "${conf[0]%%/*} already taken on ${iface}"
773 [[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
774 eend "${x}" && config_worked=true && continue
776 if [[ ${conf[0]} == "dhcp" ]] ; then
777 eerror "No DHCP client installed"
779 eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
783 if [[ -n ${fallback[config_counter]} ]] ; then
784 einfo "Trying fallback configuration"
785 config[config_counter]="${fallback[config_counter]}"
786 fallback[config_counter]=""
788 # Do we have a fallback route?
789 if [[ -n ${fallback_route[config_counter]} ]] ; then
790 x="fallback_route[config_counter]"
791 eval "routes_${ifvar}=( \"\${!x}\" )"
792 fallback_route[config_counter]=""
795 (( config_counter-- )) # since the loop will increment it
801 # We return failure if no configuration parameters worked
802 ${config_worked} || return 1
804 # Start any modules with _post_start
805 for mod in ${MODULES[@]}; do
806 if is_function "${mod}_post_start" ; then
807 ${mod}_post_start "${iface}" || return 1
814 # bool iface_stop(char *interface)
816 # iface_stop: bring down an interface. Don't trust information in
817 # /etc/conf.d/net since the configuration might have changed since
818 # iface_start ran. Instead query for current configuration and bring
819 # down the interface.
821 local iface="$1" i= aliases= need_begin=false mod=
822 local RC_INDENTATION="${RC_INDENTATION}"
824 # pre Stop any modules
825 for mod in ${MODULES[@]}; do
826 if is_function "${mod}_pre_stop" ; then
827 ${mod}_pre_stop "${iface}" || return 1
831 einfo "Bringing down ${iface}"
834 # Collect list of aliases for this interface.
835 # List will be in reverse order.
836 if interface_exists "${iface}" ; then
837 aliases=$(interface_get_aliases_rev "${iface}")
840 # Stop aliases before primary interface.
841 # Note this must be done in reverse order, since ifconfig eth0:1
842 # will remove eth0:2, etc. It might be sufficient to simply remove
843 # the base interface but we're being safe here.
844 for i in ${aliases} ${iface}; do
845 # Stop all our modules
846 for mod in ${MODULES[@]}; do
847 if is_function "${mod}_stop" ; then
848 ${mod}_stop "${i}" || return 1
852 # A module may have removed the interface
853 if ! interface_exists "${iface}" ; then
858 # We don't delete ppp assigned addresses
859 if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
860 # Delete all the addresses for this alias
861 interface_del_addresses "${i}"
864 # Do final shut down of this alias
865 if [[ ${IN_BACKGROUND} != "true" \
866 && ${RC_DOWN_INTERFACE} == "yes" ]] ; then
867 ebegin "Shutting down ${i}"
868 interface_iface_stop "${i}"
873 # post Stop any modules
874 for mod in ${MODULES[@]}; do
875 # We have already taken down the interface, so no need to error
876 is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
882 # bool run_start(char *iface)
884 # Brings up ${IFACE}. Calls preup, iface_start, then postup.
885 # Returns 0 (success) unless preup or iface_start returns 1 (failure).
886 # Ignores the return value from postup.
887 # We cannot check that the device exists ourselves as modules like
888 # tuntap make create it.
890 local iface="$1" IFVAR=$(bash_variable "$1")
892 # We do this so users can specify additional addresses for lo if they
893 # need too - additional routes too
894 # However, no extra modules are loaded as they are just not needed
895 if [[ ${iface} == "lo" ]] ; then
897 config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
898 routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
899 elif [[ ${iface} == "lo0" ]] ; then
901 config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
902 routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
905 # We may not have a loaded module for ${iface}
906 # Some users may have "alias natsemi eth0" in /etc/modules.d/foo
907 # so we can work with this
908 # However, if they do the same with eth1 and try to start it
909 # but eth0 has not been loaded then the module gets loaded as
911 # Not much we can do about this :(
912 # Also, we cannot error here as some modules - such as bridge
914 if ! interface_exists "${iface}" ; then
915 /sbin/modprobe "${iface}" &>/dev/null
918 # Call user-defined preup function if it exists
919 if is_function preup ; then
920 einfo "Running preup function"
923 eend "$?" "preup ${iface} failed" || return 1
927 # If config is set to noop and the interface is up with an address
928 # then we don't start it
930 config="config_${IFVAR}[@]"
931 config=( "${!config}" )
932 if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
933 einfo "Keeping current configuration for ${iface}"
936 # Remove noop from the config var
937 [[ ${config[0]} == "noop" ]] \
938 && eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
940 # There may be existing ip address info - so we strip it
941 if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
942 && ${IN_BACKGROUND} != "true" ]] ; then
943 interface_del_addresses "${iface}"
946 # Start the interface
947 if ! iface_start "${iface}" ; then
948 if [[ ${IN_BACKGROUND} != "true" ]] ; then
949 interface_exists "${iface}" && interface_down "${iface}"
956 # Call user-defined postup function if it exists
957 if is_function postup ; then
958 # We need to mark the service as started incase a
959 # postdown function wants to restart services that depend on us
960 mark_service_started "net.${iface}"
961 end_service "net.${iface}" 0
962 einfo "Running postup function"
964 ( postup "${iface}" )
971 # bool run_stop(char *iface) {
973 # Brings down ${iface}. If predown call returns non-zero, then
974 # stop returns non-zero to indicate failure bringing down device.
975 # In all other cases stop returns 0 to indicate success.
977 local iface="$1" IFVAR=$(bash_variable "$1") x
979 # Load our ESSID variable so users can use it in predown() instead
980 # of having to write code.
981 local ESSID=$(get_options ESSID) ESSIDVAR=
982 [[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
984 # Call user-defined predown function if it exists
985 if is_function predown ; then
986 einfo "Running predown function"
988 ( predown "${iface}" )
989 eend $? "predown ${iface} failed" || return 1
991 elif is_net_fs / ; then
992 eerror "root filesystem is network mounted -- can't stop ${iface}"
994 elif is_union_fs / ; then
995 for x in $(unionctl "${dir}" --list \
996 | sed -e 's/^\(.*\) .*/\1/') ; do
997 if is_net_fs "${x}" ; then
998 eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
1004 iface_stop "${iface}" || return 1 # always succeeds, btw
1006 # Release resolv.conf information.
1007 [[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
1009 # Mark us as inactive if called from the background
1010 [[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
1012 # Call user-defined postdown function if it exists
1013 if is_function postdown ; then
1014 # We need to mark the service as stopped incase a
1015 # postdown function wants to restart services that depend on us
1016 [[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
1017 end_service "net.${iface}" 0
1018 einfo "Running postdown function"
1020 ( postdown "${iface}" )
1028 # bool run(char *iface, char *cmd)
1030 # Main start/stop entry point
1031 # We load modules here and remove any functions that they
1032 # added as we may be called inside the same shell scope for another interface
1034 local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
1036 local -a MODULES=() mods=()
1037 local IN_BACKGROUND="${IN_BACKGROUND}"
1039 if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
1045 # We need to override the exit function as runscript.sh now checks
1046 # for it. We need it so we can mark the service as inactive ourselves.
1050 [[ ${cmd} == "stop" ]] && starting=false
1052 # We force lo to only use these modules for a major speed boost
1053 if is_loopback "${iface}" ; then
1054 modules_force=( "iproute2" "ifconfig" "system" )
1057 if modules_load "${iface}" "${starting}" ; then
1058 if [[ ${cmd} == "stop" ]] ; then
1059 # Reverse the module list for stopping
1060 mods=( "${MODULES[@]}" )
1061 for ((i = 0; i < ${#mods[@]}; i++)); do
1062 MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
1065 run_stop "${iface}" && r=0
1067 # Only hotplug on ethernet interfaces
1068 if [[ ${IN_HOTPLUG} == 1 ]] ; then
1069 if ! interface_is_ethernet "${iface}" ; then
1070 eerror "We only hotplug for ethernet interfaces"
1075 run_start "${iface}" && r=0
1079 if [[ ${r} != "0" ]] ; then
1080 if [[ ${cmd} == "start" ]] ; then
1081 # Call user-defined failup if it exists
1082 if is_function failup ; then
1083 einfo "Running failup function"
1085 ( failup "${iface}" )
1089 # Call user-defined faildown if it exists
1090 if is_function faildown ; then
1091 einfo "Running faildown function"
1093 ( faildown "${iface}" )
1097 [[ ${IN_BACKGROUND} == "true" ]] \
1098 && mark_service_inactive "net.${iface}"
1106 # Start entry point so that we only have one function
1107 # which localises variables and unsets functions
1109 declare -r IFACE="${SVCNAME#*.}"
1110 einfo "Starting ${IFACE}"
1111 run "${IFACE}" start
1116 # Stop entry point so that we only have one function
1117 # which localises variables and unsets functions
1119 declare -r IFACE="${SVCNAME#*.}"
1120 einfo "Stopping ${IFACE}"