# Best Method ??

## OldManRiver

All,

I'm trying to add two NIC cards to my network server to do the following:

A. Monitor which external internet connection is up,

B. Auto Switch between them when one goes down,

C. Distribute packet load when they are both up.

This is the following specs on my connections:

A. eth1 = Time Warner Cable - 4.5 MBps

B. eth2 = Wrio wireless - 40.x MBps

We were on Comcast, which was stable, then TWC bought our area and they 

go down multiple time daily and will not fix their problem.  Wrio is a 

new company, so their link currently has no redunancy, but should later.

The server will act as DHCP Host for the rest of the network, which includes

VOIP phone service with Cisco ATAs (Vonage or equivalent).  Here is a diagram

of the implementation.

```

                    ----------------

                    |              |

 Internet 1 - eth1  |              |

--------------------|              |

 (DHCP Rcvr)        |              |   Network - eth0

                    |   Computer   |-------------------

 Internet 2 - eth2  |              |   (DHCP Server)

--------------------|              |

 (DHCP Rcvr)        |              |

                    |              |

                    ----------------

```

I GenToo guru friend of mine said I could do this with "IP traf" and/or "IP route" and 

sent me the following links:

http://www.linux.com.lb/wiki/index.pl?node=Load%20Balancing%20Across%20Multiple%20Links

http://lartc.org/howto/lartc.rpdb.multiple-links.html  (Closest to what we are doing)

I also found the following links in the gentoo-Wiki:

http://gentoo-wiki.com/TIP_Dual-Homed_Gentoo_Server

http://gentoo-wiki.com/Dual_internet_connections

http://gentoo-wiki.com/HOWTO_add_a_static_route

My problem is that both me and my partner are such noobies, we still don't understand all this 

so implementing is not clear to us.  At this point I do not know if I use just one of these 

solutions, a combination of them and which one or which combination is best.

I would appreciate any help in clarifying this so I can proceed.

Thanks!

OMR

----------

## erik258

http://gentoo-wiki.com/Dual_internet_connections

i think that's the one you want.  

a synopsis: emerge iproute2, reconfig kernel, and configure the system to set up the devices properly on boot.  That last one is the only one that might be a little problematic for you, because the wiki doesn't specify exactly how to configure for the gentoo network initscripts.  But read the page, maybe the point of writing a new initscript like they do is that you don't have to mess with gentoo's configuraiton.

----------

## OldManRiver

Added my 3com card an now eth0 is not working, evidently GenToo decided one of the add-in cards is now eth0, but I do not have the drivers so it does not work either.

Trying to resolve this problem now!

Addin NICs are 3Com 3c905B cards.

Found the drivers at:

http://support.3com.com/infodeli/tools/nic/linuxdownload.htm

----------

## OldManRiver

all,

All my eth[0-2] cards are now working, but a friend helped me with the eth2 and he used a "ln" link to the localhost def file.

I'm not happy about this and want if to operate seperate of the localhost, so need to know what I need to do here.

OMR

----------

## NeddySeagoon

OldManRiver,

Your friend did 

```
ln -s net.lo net.eth2
```

to create a new startup scrip for net.eth2

Its run once at startup and does not use the interface lo at all.

In short, its the Gentoo way. You could maje a copy of net.lo and rename it but thats a really bad idea because it will no longer be updated by portage when net.lo changes.

----------

## OldManRiver

 *erik258 wrote:*   

> http://gentoo-wiki.com/Dual_internet_connections 
> 
> i think that's the one you want.  
> 
> a synopsis: emerge iproute2, reconfig kernel, and configure the system to set up the devices properly on boot.  That last one is the only one that might be a little problematic for you, because the wiki doesn't specify exactly how to configure for the gentoo network initscripts.  But read the page, maybe the point of writing a new initscript like they do is that you don't have to mess with gentoo's configuraiton.

 

I started trying to install this one, but it is too cryptic, missing commands, filenames of where to do what, etc.  Also since I must have the following: *Quote:*   

> ETH1 with DHCP (rcvr) to find available incoming IP Address
> 
> ETH2 with DHCP (rcvr) to find available incoming IP Address
> 
> ETH0 as DHCP server, serving IP Address to 20 plus computer on network, without routers.

 The part in this config howto, when they start talking about using DHCP is the most confusing.  I looks like the script shown, is a manually operated script to manually obtain the IP address and then manually plug it back into the original script, where the script should be called inside the orignal script and find and return the IP address as a var to executed in the original script, preferrably as a function.

Most disconcerting on this Howto is I see nothing to allow the config of my ETH0 to the DHCP server, but I'm a novice, so what do I know.  Anyone seeing this differently please chime in.

If anyone has anymore info on this and/or links I will appreciate it, as I need to finish on this soon.

Thanks!

OMR

----------

## erik258

 *Quote:*   

> I started trying to install this one, but it is too cryptic, missing commands, filenames of where to do what, etc. 

 

I recommend starting with getting this working, then implementing your DHCP server on eth0 when you have it down.  Why don't you post a quote of the step on which you're getting tripped up, and then give us a short description of your problem.  It looks fairly striaghtforward to me, but I've been doing this a little while now.  If you let us know your specific problem(s), I'm sure we can help.  

 *Quote:*   

> Most disconcerting on this Howto is I see nothing to allow the config of my ETH0 to the DHCP server, but I'm a novice, so what do I know. Anyone seeing this differently please chime in. 

 

You may have to go elsewhere for that information -- it's beyond the scope of that document.  I think setting up DHCP is fairly easy with the Internet Software Consortium's DHCP server.  I like the ISC's dhcpd because it's what lots of the big boys use on their networks, it's the most flexible out there (at least I've never seen another dhcp server that compares), and it's really easy on resources.  My dhcpd process has run for five hundreths of a second, and is using around 3M of  virtual memory, of which only 1.26M is resident.  The server manages few leases, but I don't think more would change very much.  I've had it managing around a dozen clients before, and I would feel perfectly confident asking it to do 20, or thirty, or even a hundred such leases or more.  

I found a nice howto on DHCPd on the gentoo wiki: http://gentoo-wiki.com/HOWTO_setup_DHCP  That passed an initial inspection for ease of following.  If you need more help, please let us know.

----------

## OldManRiver

 *erik258 wrote:*   

> Why don't you post a quote of the step on which you're getting tripped up, and then give us a short description of your problem.

 

First step in this process is Kernel Options where the config screen is shown.  There is no reference to where this utility is or how to call it,

Then it is suggeted that you have the manual option, but no explaination of whether this is at the command line or in the make.conf file,

Under the Helpful Script there is no shell version of the script and I'm not sure if I have Perl loaded on my machine.

The person submitting this script forgot to mention how to check for absense of Perl and it's subsequent installation, if it is missing.

So this is where I'm at.  I can ask my partner, who knows where the config menu is, when he gets back in the shop, but all other noobies will be also stumped at this so I think it should be corrected (violates the "No Assumptions" rule.

Thanks!

OMR

----------

## erik258

 *Quote:*   

> 
> 
> ```
> Networking  --->
> 
> ...

 

That's a screenshot from menuconfig.  First make sure you're familiar with rebuilding the kernel, then go to /usr/src/linux and type make menuconfig.  You'll want to enable the options shown.  

You could do the same thing manually by editing .config in the same directory, /usr/src/linux.  

all my boxes seem to have perl on them already, and I don't develop in perl.  I dont' think the version should matter much.

----------

## OldManRiver

All,

Went to my menuconfig and found I had the following:

```
Networking  --->

  Networking support  --->

    Networking options  --->

      TCP/IP networking

        [*] IP: multicasting                                                 

        [*] IP: advanced router

             Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure) ( 

        [*] IP: policy routing

        [*] IP: use netfilter MARK value as routing key                   

        [*] IP: equal cost multipath

        [*] IP: verbose route monitoring                                    

        [*] IP: kernel level autoconfiguration                              

        [*] IP: DHCP support                                              

       <M> IP: tunneling                                                  

       <M> IP: GRE tunnels over IP         

```

Not sure if some of these are conflicting or not so not sure it this is correct.  Would like and explaination, please!

Thanks!

OMR

----------

## erik258

Some options have been added since the howto was written, but that should be fine.  It doesn't seem likely that they'll conflict.

----------

## OldManRiver

All,

We had both our ISP lines go down, so ordered the third from another source, so now this is more critical than ever.

Also had so much trouble with TW that we dropped them and replaced them with SBC/Yahoo.  Current config now looks like:

```

                                  ----------------

                                  |              |

  Internet 1 - eth1               |              |

 ---------------------------------|              |

  (DHCP Rcvr - Wrio 70Mb)         |              |

                                  |              |

  Internet 2 - eth2               |              |   Network - eth0

 ---------------------------------|   Computer   |-------------------

  (DHCP Rcvr - SBC 628K-D/293K-U) |              |  (DHCP Server)

                                  |              |

  Internet 3 - eth3               |              |

 ---------------------------------|              |

  (DHCP Rcvr - Covad 144K)        |              |

                                  |              |

                                  ----------------

```

ETH1-3 are all 3Com Cards, ETH0 is on-board Intel NIC.  You can easily see from the speeds, which is our primary service.

Input will be appreciated.

Thanks!

OMRLast edited by OldManRiver on Fri Jun 08, 2007 4:48 pm; edited 3 times in total

----------

## OldManRiver

 *NeddySeagoon wrote:*   

> Your friend did 
> 
> ```
> ln -s net.lo net.eth2
> ```
> ...

 

I understand what my friend did, but my real question, as I understand, is localhost is set up for/as the DHCP server, so per my drawing shouldn't net.eth1, net.eth2 and net.eth3 should have their own init files, and the net.eth0 should be the one linked to the localhost?

Thanks!

OMR

----------

## erik258

The job of net.lo is to store the algorithm for reading /etc/conf.d/net and configuring the devices accordingly.  Regardless of what the devices are used for, the correct way for the gentoo init scripts to initialize them is by the same algorithm as in net.lo -- therefore, to automatically update all network initscripts, they should all be linked to net.lo

----------

## OldManRiver

 *erik258 wrote:*   

> The job of net.lo is to store the algorithm for reading /etc/conf.d/net and configuring the devices accordingly.

 

I ran the following commands:

```
cd /etc/conf.d

ls -al

gedit net
```

My net file contained:

```
config_eth0=( "dhcp" )

config_eth1=( "dhcp" )

config_eth2=( "dhcp" )

# config_eth3=( "dhcp" )

# config_eth0=( "192.168.10.30/24" )

# config_eth1=( "192.168.10.31/24" )

# config_eth2=( "192.168.10.32/24" )

# dns_domain_lo="homenetwork"

# nis_domain_lo="my-nisdomain"

routes_eth0=( "default via 192.168.1.1" )

routes_eth1=( "default via 192.168.10.200" )

routes_eth2=( "default via 192.168.1.200" )

# routes_eth3=( "default via 192.168.7.200" )
```

ETH3 is not active yet.

I know I need to change ETH0 to get the DHCP outbound, but don't know what I do to change that.

My net.eth0 file reads:

```
#!/sbin/runscript

# Copyright (c) 2004-2006 Gentoo Foundation

# Distributed under the terms of the GNU General Public License v2

# Contributed by Roy Marples (uberlord@gentoo.org)

# Many thanks to Aron Griffis (agriffis@gentoo.org)

# for help, ideas and patches

#NB: Config is in /etc/conf.d/net

# For pcmcia users. note that pcmcia must be added to the same

# runlevel as the net.* script that needs it.

depend() {

   need localmount

   after bootmisc hostname

   use isapnp isdn pcmcia usb wlan

   # Load any custom depend functions for the given interface

   # For example, br0 may need eth0 and eth1

   local iface="${SVCNAME#*.}"

   [[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}

   if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then

      after net.lo net.lo0

      # Support new style RC_NEED and RC_USE in one net file

      local x="RC_NEED_${iface}"

      [[ -n ${!x} ]] && need ${!x}

      x="RC_USE_${iface}"

      [[ -n ${!x} ]] && use ${!x}

   fi

   return 0

}

# Define where our modules are

MODULES_DIR="${svclib}/net"

# Make some wrappers to fudge after/before/need/use depend flags.

# These are callbacks so MODULE will be set.

after() {

   eval "${MODULE}_after() { echo \"$*\"; }"

}

before() {

   eval "${MODULE}_before() { echo \"$*\"; }"

}

need() {

   eval "${MODULE}_need() { echo \"$*\"; }"

}

installed() {

   # We deliberately misspell this as _installed will probably be used

   # at some point

   eval "${MODULE}_instlled() { echo \"$*\"; }"

}

provide() {

   eval "${MODULE}_provide() { echo \"$*\"; }"

}

functions() {

   eval "${MODULE}_functions() { echo \"$*\"; }"

}

variables() {

   eval "${MODULE}_variables() { echo \"$*\"; }"

}

is_loopback() {

   [[ $1 == "lo" || $1 == "lo0" ]]

}

# char* interface_device(char *iface)

#

# Gets the base device of the interface

# Can handle eth0:1 and eth0.1

# Which returns eth0 in this case

interface_device() {

   local dev="${1%%.*}"

   [[ ${dev} == "$1" ]] && dev="${1%%:*}"

   echo "${dev}"

}

# char* interface_type(char* iface)

#

# Returns the base type of the interface

# eth, ippp, etc

interface_type() {

   echo "${1%%[0-9]*}"

}

# int calculate_metric(char *interface, int base)

#

# Calculates the best metric for the interface

# We use this when we add routes so we can prefer interfaces over each other

calculate_metric() {

   local iface="$1" metric="$2"

   # Have we already got a metric?

   local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \

      /proc/net/route)

   if [[ -n ${m} ]] ; then

      echo "${m}"

      return 0

   fi

   local i= dest= gw= flags= ref= u= m= mtu= metrics=

   while read i dest gw flags ref u m mtu ; do

      # Ignore lo

      is_loopback "${i}" && continue

      # We work out metrics from default routes only

      [[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue

      metrics="${metrics}\n${m}"

   done < /proc/net/route

   # Now, sort our metrics

   metrics=$(echo -e "${metrics}" | sort -n)

   # Now, find the lowest we can use

   local gotbase=false

   for m in ${metrics} ; do

      [[ ${m} -lt ${metric} ]] && continue

      [[ ${m} == ${metric} ]] && ((metric++))

      [[ ${m} -gt ${metric} ]] && break

   done

   

   echo "${metric}"

}

# int netmask2cidr(char *netmask)

#

# Returns the CIDR of a given netmask

netmask2cidr() {

   local binary= i= bin=

   for i in ${1//./ }; do

      bin=""

      while [[ ${i} != "0" ]] ; do

         bin=$[${i}%2]${bin}

         (( i=i>>1 ))

      done

      binary="${binary}${bin}"

   done

   binary="${binary%%0*}"

   echo "${#binary}"

}

# bool is_function(char* name)

#

# Returns 0 if the given name is a shell function, otherwise 1

is_function() {

   [[ -z $1 ]] && return 1

   [[ $(type -t "$1") == "function" ]]

}

# void function_wrap(char* source, char* target)

#

# wraps function calls - for example function_wrap(this, that)

# maps function names this_* to that_*

function_wrap() {

   local i=

   is_function "${2}_depend" && return

   for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do

      eval "${2}${i#${1}}() { ${i} \"\$@\"; }"

   done

}

# char[] * expand_parameters(char *cmd)

#

# Returns an array after expanding parameters. For example

# "192.168.{1..3}.{1..3}/24 brd +"

# will return

# "192.168.1.1/24 brd +"

# "192.168.1.2/24 brd +"

# "192.168.1.3/24 brd +"

# "192.168.2.1/24 brd +"

# "192.168.2.2/24 brd +"

# "192.168.2.3/24 brd +"

# "192.168.3.1/24 brd +"

# "192.168.3.2/24 brd +"

# "192.168.3.3/24 brd +"

expand_parameters() {

   local x=$(eval echo ${@// /_})

   local -a a=( ${x} )

   a=( "${a[@]/#/\"}" )

   a=( "${a[@]/%/\"}" )

   echo "${a[*]//_/ }"

}

# void configure_variables(char *interface, char *option1, [char *option2])

#

# Maps configuration options from <variable>_<option> to <variable>_<iface>

# option2 takes precedence over option1

configure_variables() {

   local iface="$1" option1="$2" option2="$3"

   local mod= func= x= i=

   local -a ivars=() ovars1=() ovars2=()

   local ifvar=$(bash_variable "${iface}")

   for mod in ${MODULES[@]}; do

      is_function ${mod}_variables || continue

      for v in $(${mod}_variables) ; do

         x=

         [[ -n ${option2} ]] && x="${v}_${option2}[@]"

         [[ -z ${!x} ]] && x="${v}_${option1}[@]"

         [[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"

      done

   done

   return 0

}

# bool module_load_minimum(char *module)

#

# Does the minimum checking on a module - even when forcing

module_load_minimum() {

   local f="$1.sh" MODULE="${1##*/}"

   if [[ ! -f ${f} ]] ; then

      eerror "${f} does not exist"

      return 1

   fi

   if ! source "${f}" ; then

      eerror "${MODULE} failed a sanity check"

      return 1

   fi

   for f in depend; do

      is_function "${MODULE}_${f}" && continue

      eerror "${MODULE}.sh does not support the required function ${f}"

      return 1

   done

   return 0

}

# bool modules_load_auto()

#

# Load and check each module for sanity

# If the module is not installed, the functions are to be removed

modules_load_auto() {

   local i j inst

   # Populate the MODULES array

   # Basically we treat evey file in ${MODULES_DIR} as a module

   MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )

   j="${#MODULES[@]}"

   for (( i=0; i<j; i++ )); do

      MODULES[i]="${MODULES_DIR}/${MODULES[i]}"

      [[ ! -f ${MODULES[i]} ]] && unset MODULES[i]

   done

   MODULES=( "${MODULES[@]}" )

   # Each of these sources into the global namespace, so it's

   # important that module functions and variables are prefixed with

   # the module name, for example iproute2_

   j="${#MODULES[@]}"

   loaded_interface=false

   for (( i=0; i<j; i++ )); do

      MODULES[i]="${MODULES[i]%.sh*}"

      if [[ ${MODULES[i]##*/} == "interface" ]] ; then

         eerror "interface is a reserved name - cannot load a module called interface"

         return 1

      fi

      

      (

      u=0;

      module_load_minimum "${MODULES[i]}" || u=1;

      if [[ ${u} == 0 ]] ; then

         inst="${MODULES[i]##*/}_check_installed";

         if is_function "${inst}" ; then

            ${inst} false || u=1;

         fi

      fi

      exit "${u}";

      )

      if [[ $? == 0 ]] ; then

         source "${MODULES[i]}.sh"

         MODULES[i]="${MODULES[i]##*/}"

      else

         unset MODULES[i]

      fi

   done

   MODULES=( "${MODULES[@]}" )

   return 0

}

# bool modules_check_installed(void)

#

# Ensure that all modules have the required modules loaded

# This enables us to remove modules from the MODULES array

# Whilst other modules can still explicitly call them

# One example of this is essidnet which configures network

# settings for the specific ESSID connected to as the user

# may be using a daemon to configure wireless instead of our

# iwconfig module

modules_check_installed() {

   local i j missingdeps nmods="${#MODULES[@]}"

   for (( i=0; i<nmods; i++ )); do

      is_function "${MODULES[i]}_instlled" || continue

      for j in $( ${MODULES[i]}_instlled ); do

         missingdeps=true

         if is_function "${j}_check_installed" ; then

            ${j}_check_installed && missingdeps=false

         elif is_function "${j}_depend" ; then

            missingdeps=false

         fi

         ${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break

      done

   done

   MODULES=( "${MODULES[@]}" )

   PROVIDES=( "${PROVIDES[@]}" )

}

# bool modules_check_user(void)

modules_check_user() {

   local iface="$1" ifvar=$(bash_variable "${IFACE}")

   local i= j= k= l= nmods="${#MODULES[@]}"

   local -a umods=()

   # Has the interface got any specific modules?

   umods="modules_${ifvar}[@]"

   umods=( "${!umods}" )

   # Global setting follows interface-specific setting

   umods=( "${umods[@]}" "${modules[@]}" )

   # Add our preferred modules

   local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )

   umods=( "${umods[@]}" "${pmods[@]}" )

   # First we strip any modules that conflict from user settings

   # So if the user specifies pump then we don't use dhcpcd

   for (( i=0; i<${#umods[@]}; i++ )); do

      # Some users will inevitably put "dhcp" in their modules

      # list.  To keep users from screwing up their system this

      # way, ignore this setting so that the default dhcp

      # module will be used.

      [[ ${umods[i]} == "dhcp" ]] && continue

      # We remove any modules we explicitly don't want

      if [[ ${umods[i]} == "!"* ]] ; then

         for (( j=0; j<nmods; j++ )); do

            [[ -z ${MODULES[j]} ]] && continue

            if [[ ${umods[i]:1} == "${MODULES[j]}" \

               || ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then

               # We may need to setup a class wrapper for it even though

               # we don't use it directly

               # However, we put it into an array and wrap later as

               # another module may provide the same thing

               ${MODULES[j]}_check_installed \

                  && WRAP_MODULES=(

                     "${WRAP_MODULES[@]}"

                     "${MODULES[j]} ${PROVIDES[j]}"

                  )

               unset MODULES[j]

               unset PROVIDES[j]

            fi

         done

         continue

      fi

      if ! is_function "${umods[i]}_depend" ; then

         # If the module is one of our preferred modules, then

         # ignore this error; whatever is available will be

         # used instead.

         (( i < ${#umods[@]} - ${#pmods[@]} )) || continue

         # The function may not exist because the modules software is

         # not installed. Load the module and report its error

         if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then

            source "${MODULES_DIR}/${umods[i]}.sh"

            is_function "${umods[i]}_check_installed" \

               && ${umods[i]}_check_installed true

         else

            eerror "The module \"${umods[i]}\" does not exist"

         fi

         return 1

      fi

      if is_function "${umods[i]}_provide" ; then

         mod=$(${umods[i]}_provide)

      else

         mod="${umods[i]}"

      fi

      for (( j=0; j<nmods; j++ )); do

         [[ -z ${MODULES[j]} ]] && continue

         if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then

            # We don't have a match - now ensure that we still provide an

            # alternative. This is to handle our preferred modules.

            for (( l=0; l<nmods; l++ )); do

               [[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue

               if [[ ${PROVIDES[l]} == "${mod}" ]] ; then

                  unset MODULES[j]

                  unset PROVIDES[j]

                  break

               fi

            done

         fi

      done

   done

   # Then we strip conflicting modules.

   # We only need to do this for 3rd party modules that conflict with

   # our own modules and the preferred list AND the user modules

   # list doesn't specify a preference.

   for (( i=0; i<nmods-1; i++ )); do

      [[ -z ${MODULES[i]} ]] && continue         

      for (( j=i+1; j<nmods; j++)); do

         [[ -z ${MODULES[j]} ]] && continue

         [[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \

         && unset MODULES[j] && unset PROVIDES[j]

      done

   done

   MODULES=( "${MODULES[@]}" )

   PROVIDES=( "${PROVIDES[@]}" )

   return 0

}

# void modules_sort(void)

#

# Sort our modules

modules_sort() {

   local i= j= nmods=${#MODULES[@]} m=

   local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()

   # Make our provide list

   for ((i=0; i<nmods; i++)); do

      dead[i]="false"

      if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then

         local provided=false

         for ((j=0; j<${#provide[@]}; j++)); do

            if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then

               provide_list[j]="${provide_list[j]} ${MODULES[i]}"

               provided=true

            fi

         done

         if ! ${provided}; then

            provide[j]="${PROVIDES[i]}"

            provide_list[j]="${MODULES[i]}"

         fi

      fi

   done

   # Create an after array, which holds which modules the module at

   # index i must be after

   for ((i=0; i<nmods; i++)); do

      if is_function "${MODULES[i]}_after" ; then

         after[i]=" ${after[i]} $(${MODULES[i]}_after) "

      fi

      if is_function "${MODULES[i]}_before" ; then

         for m in $(${MODULES[i]}_before); do

            for ((j=0; j<nmods; j++)) ; do

               if [[ ${PROVIDES[j]} == "${m}" ]] ; then

                  after[j]=" ${after[j]} ${MODULES[i]} "

                  break

               fi

            done

         done

      fi

   done

   # Replace the after list modules with real modules

   for ((i=0; i<nmods; i++)); do

      if [[ -n ${after[i]} ]] ; then

         for ((j=0; j<${#provide[@]}; j++)); do

            after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"

         done

      fi

   done

   

   # We then use the below code to provide a topologial sort

    module_after_visit() {

        local name="$1" i= x=

      for ((i=0; i<nmods; i++)); do

         [[ ${MODULES[i]} == "$1" ]] && break

      done

        ${dead[i]} && return

        dead[i]="true"

        for x in ${after[i]} ; do

            module_after_visit "${x}"

        done

        sorted=( "${sorted[@]}" "${MODULES[i]}" )

      sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )

    }

   for x in ${MODULES[@]}; do

      module_after_visit "${x}"

   done

   MODULES=( "${sorted[@]}" )

   PROVIDES=( "${sortedp[@]}" )

}

# bool modules_check_depends(bool showprovides)

modules_check_depends() {

   local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=

   local missingdeps= p= interface=false

   for (( i=0; i<nmods; i++ )); do

      if is_function "${MODULES[i]}_need" ; then

         for needmod in $(${MODULES[i]}_need); do

            missingdeps=true

            for (( j=0; j<nmods; j++ )); do

               if [[ ${needmod} == "${MODULES[j]}" \

                  || ${needmod} == "${PROVIDES[j]}" ]] ; then

                  missingdeps=false

                  break

               fi

            done

            if ${missingdeps} ; then

               eerror "${MODULES[i]} needs ${needmod} (dependency failure)"

               return 1

            fi

         done

      fi

      if is_function "${MODULES[i]}_functions" ; then

         for f in $(${MODULES[i]}_functions); do

            if ! is_function "${f}" ; then

               eerror "${MODULES[i]}: missing required function \"${f}\""

               return 1

            fi

         done

      fi

      [[ ${PROVIDES[i]} == "interface" ]] && interface=true

      if ${showprovides} ; then

         [[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \

         && veinfo "${MODULES[i]} provides ${PROVIDES[i]}"

      fi

   done

   if ! ${interface} ; then

      eerror "no interface module has been loaded"

      return 1

   fi

   return 0

}

# bool modules_load(char *iface, bool starting)

#

# Loads the defined handler and modules for the interface

# Returns 0 on success, otherwise 1

modules_load()  {

   local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=

   local -a x=()

   local RC_INDENTATION="${RC_INDENTATION}"

   local -a PROVIDES=() WRAP_MODULES=()

   if ! is_loopback "${iface}" ; then

      x="modules_force_${iface}[@]"

      [[ -n ${!x} ]] && modules_force=( "${!x}" )

      if [[ -n ${modules_force} ]] ; then

         ewarn "WARNING: You are forcing modules!"

         ewarn "Do not complain or file bugs if things start breaking"

         report=true

      fi

   fi

   veinfo "Loading networking modules for ${iface}"

   eindent

   if [[ -z ${modules_force} ]] ; then

      modules_load_auto || return 1

   else

      j="${#modules_force[@]}"

      for (( i=0; i<j; i++ )); do

         module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1

         if is_function "${modules_force[i]}_check_installed" ; then

            ${modules_force[i]}_check_installed || unset modules_force[i]

         fi

      done

      MODULES=( "${modules_force[@]}" )

   fi

   j="${#MODULES[@]}"

   for (( i=0; i<j; i++ )); do

      # Now load our dependencies - we need to use the MODULE variable

      # here as the after/before/need functions use it

      MODULE="${MODULES[i]}"

      ${MODULE}_depend

      # expose does exactly the same thing as depend

      # However it is more "correct" as it exposes things to other modules

      # instead of depending on them ;)

      is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose

      # If no provide is given, assume module name

      if is_function "${MODULES[i]}_provide" ; then

         PROVIDES[i]=$(${MODULES[i]}_provide)

      else

         PROVIDES[i]="${MODULES[i]}"

      fi

   done

   if [[ -n ${modules_force[@]} ]] ; then

      # Strip any duplicate modules providing the same thing

      j="${#MODULES[@]}"

      for (( i=0; i<j-1; i++ )); do

         [[ -z ${MODULES[i]} ]] && continue

         for (( k=i+1; k<j; k++ )); do

            if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then

               unset MODULES[k]

               unset PROVIDES[k]

            fi

         done

      done

      MODULES=( "${MODULES[@]}" )

      PROVIDES=( "${PROVIDES[@]}" )

   else

      if ${starting}; then

         modules_check_user "${iface}" || return 1

      else

         # Always prefer iproute2 for taking down interfaces

         if is_function iproute2_provide ; then

            function_wrap iproute2 "$(iproute2_provide)"

         fi

      fi

   fi

   

   # Wrap our modules

   j="${#MODULES[@]}"

   for (( i=0; i<j; i++ )); do

      function_wrap "${MODULES[i]}" "${PROVIDES[i]}"

   done

   j="${#WRAP_MODULES[@]}"

   for (( i=0; i<j; i++ )); do

      function_wrap ${WRAP_MODULES[i]}

   done

   

   if [[ -z ${modules_force[@]} ]] ; then

      modules_check_installed || return 1

      modules_sort || return 1

   fi

   veinfo "modules: ${MODULES[@]}"

   eindent

   ${starting} && p=true

   modules_check_depends "${p}" || return 1

   return 0

}

# bool iface_start(char *interface)

#

# iface_start is called from start.  It's expected to start the base

# interface (for example "eth0"), aliases (for example "eth0:1") and to start

# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by

# calling itself recursively.

iface_start() {

   local iface="$1" mod config_counter="-1" x config_worked=false

   local RC_INDENTATION="${RC_INDENTATION}"

   local -a config=() fallback=() fallback_route=() conf=() a=() b=()

   local ifvar=$(bash_variable "$1") i= j= metric=0

   # pre Start any modules with

   for mod in ${MODULES[@]}; do

      if is_function "${mod}_pre_start" ; then

         ${mod}_pre_start "${iface}" || { eend 1; return 1; }

      fi

   done

   x="metric_${ifvar}"

   # If we don't have a metric then calculate one

   # Our modules will set the metric variable to a suitable base

   # in their pre starts.

   if [[ -z ${!x} ]] ; then

      eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""

   fi

   # We now expand the configuration parameters and pray that the

   # fallbacks expand to the same number as config or there will be

   # trouble!

   a="config_${ifvar}[@]"

   a=( "${!a}" )

   for (( i=0; i<${#a[@]}; i++ )); do 

      eval b=( $(expand_parameters "${a[i]}") )

      config=( "${config[@]}" "${b[@]}" )

   done

   a="fallback_${ifvar}[@]"

   a=( "${!a}" )

   for (( i=0; i<${#a[@]}; i++ )); do 

      eval b=( $(expand_parameters "${a[i]}") )

      fallback=( "${fallback[@]}" "${b[@]}" )

   done

   # We don't expand routes

   fallback_route="fallback_route_${ifvar}[@]"

   fallback_route=( "${!fallback_route}" )

   

   # We must support old configs

   if [[ -z ${config} ]] ; then

      interface_get_old_config "${iface}" || return 1

      if [[ -n ${config} ]] ; then

         ewarn "You are using a deprecated configuration syntax for ${iface}"

         ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"

      fi

   fi

   # Handle "noop" correctly

   if [[ ${config[0]} == "noop" ]] ; then

      if interface_is_up "${iface}" true ; then

         einfo "Keeping current configuration for ${iface}"

         eend 0

         return 0

      fi

      # Remove noop from the config var

      config=( "${config[@]:1}" )

   fi

   # Provide a default of DHCP if no configuration is set and we're auto

   # Otherwise a default of NULL

   if [[ -z ${config} ]] ; then

      ewarn "Configuration not set for ${iface} - assuming DHCP"

      if is_function "dhcp_start" ; then

         config=( "dhcp" )

      else

         eerror "No DHCP client installed"

         return 1

      fi

   fi

   einfo "Bringing up ${iface}"

   eindent

   for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do

      # Handle null and noop correctly

      if [[ ${config[config_counter]} == "null" \

         || ${config[config_counter]} == "noop" ]] ; then

         eend 0

         config_worked=true

         continue

      fi

      # We convert it to an array - this has the added

      # bonus of trimming spaces!

      conf=( ${config[config_counter]} )

      einfo "${conf[0]}"

      # Do we have a function for our config?

      if is_function "${conf[0]}_start" ; then

         eindent

         ${conf[0]}_start "${iface}" ; x=$?

         eoutdent

         [[ ${x} == 0 ]] && config_worked=true && continue

         # We need to test to see if it's an IP address or a function

         # We do this by testing if the 1st character is a digit

      elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then

         x="0"

         if ! is_loopback "${iface}" ; then

            if [[ " ${MODULES[@]} " == *" arping "* ]] ; then

               if arping_address_exists "${iface}" "${conf[0]}" ; then

                  eerror "${conf[0]%%/*} already taken on ${iface}"

                  x="1"

               fi

            fi

         fi

         [[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"

         eend "${x}" && config_worked=true && continue

      else

         if [[ ${conf[0]} == "dhcp" ]] ; then

            eerror "No DHCP client installed"

         else

            eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"

         fi

      fi

      if [[ -n ${fallback[config_counter]} ]] ; then

         einfo "Trying fallback configuration"

         config[config_counter]="${fallback[config_counter]}"

         fallback[config_counter]=""

         # Do we have a fallback route?

         if [[ -n ${fallback_route[config_counter]} ]] ; then

            x="fallback_route[config_counter]"

            eval "routes_${ifvar}=( \"\${!x}\" )"

            fallback_route[config_counter]=""

         fi

         (( config_counter-- )) # since the loop will increment it

         continue

      fi

   done

   eoutdent

   # We return failure if no configuration parameters worked

   ${config_worked} || return 1

   # Start any modules with _post_start

   for mod in ${MODULES[@]}; do

      if is_function "${mod}_post_start" ; then

         ${mod}_post_start "${iface}" || return 1

      fi

   done

   return 0

}

# bool iface_stop(char *interface)

#

# iface_stop: bring down an interface.  Don't trust information in

# /etc/conf.d/net since the configuration might have changed since

# iface_start ran.  Instead query for current configuration and bring

# down the interface.

iface_stop() {

   local iface="$1" i= aliases= need_begin=false mod=

   local RC_INDENTATION="${RC_INDENTATION}"

   # pre Stop any modules

   for mod in ${MODULES[@]}; do

      if is_function "${mod}_pre_stop" ; then

         ${mod}_pre_stop "${iface}" || return 1

      fi

   done

   einfo "Bringing down ${iface}"

   eindent

   # Collect list of aliases for this interface.

   # List will be in reverse order.

   if interface_exists "${iface}" ; then

      aliases=$(interface_get_aliases_rev "${iface}")

   fi

   # Stop aliases before primary interface.

   # Note this must be done in reverse order, since ifconfig eth0:1 

   # will remove eth0:2, etc.  It might be sufficient to simply remove 

   # the base interface but we're being safe here.

   for i in ${aliases} ${iface}; do

      # Stop all our modules

      for mod in ${MODULES[@]}; do

         if is_function "${mod}_stop" ; then

            ${mod}_stop "${i}" || return 1

         fi

      done

      # A module may have removed the interface

      if ! interface_exists "${iface}" ; then

         eend 0

         continue

      fi

      # We don't delete ppp assigned addresses

      if ! is_function pppd_exists || ! pppd_exists "${i}" ; then

         # Delete all the addresses for this alias

         interface_del_addresses "${i}"

      fi

      # Do final shut down of this alias

      if [[ ${IN_BACKGROUND} != "true" \

         && ${RC_DOWN_INTERFACE} == "yes" ]] ; then

         ebegin "Shutting down ${i}"

         interface_iface_stop "${i}"

         eend "$?"

      fi

   done

   # post Stop any modules

   for mod in ${MODULES[@]}; do

      # We have already taken down the interface, so no need to error

      is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"

   done

   return 0

}

# bool run_start(char *iface)

#

# Brings up ${IFACE}.  Calls preup, iface_start, then postup.

# Returns 0 (success) unless preup or iface_start returns 1 (failure).

# Ignores the return value from postup.

# We cannot check that the device exists ourselves as modules like

# tuntap make create it.

run_start() {

   local iface="$1" IFVAR=$(bash_variable "$1")

   # We do this so users can specify additional addresses for lo if they

   # need too - additional routes too

   # However, no extra modules are loaded as they are just not needed

   if [[ ${iface} == "lo" ]] ; then

      metric_lo="0"

      config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )

      routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )

   elif [[ ${iface} == "lo0" ]] ; then

      metric_lo0="0"

      config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )

      routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )

   fi

   # We may not have a loaded module for ${iface}

   # Some users may have "alias natsemi eth0" in /etc/modules.d/foo

   # so we can work with this

   # However, if they do the same with eth1 and try to start it

   # but eth0 has not been loaded then the module gets loaded as

   # eth0.

   # Not much we can do about this :(

   # Also, we cannot error here as some modules - such as bridge

   # create interfaces

   if ! interface_exists "${iface}" ; then

      /sbin/modprobe "${iface}" &>/dev/null

   fi

   # Call user-defined preup function if it exists

   if is_function preup ; then

      einfo "Running preup function"

      eindent

      ( preup "${iface}" )

      eend "$?" "preup ${iface} failed" || return 1

      eoutdent

   fi

   # If config is set to noop and the interface is up with an address

   # then we don't start it

   local config=

   config="config_${IFVAR}[@]"

   config=( "${!config}" )

   if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then

      einfo "Keeping current configuration for ${iface}"

      eend 0

   else

      # Remove noop from the config var

      [[ ${config[0]} == "noop" ]] \

         && eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"

      # There may be existing ip address info - so we strip it

      if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \

         && ${IN_BACKGROUND} != "true" ]] ; then

         interface_del_addresses "${iface}"

      fi

      # Start the interface

      if ! iface_start "${iface}" ; then

         if [[ ${IN_BACKGROUND} != "true" ]] ; then

            interface_exists "${iface}" && interface_down "${iface}"

         fi

         eend 1

         return 1

      fi

   fi

   # Call user-defined postup function if it exists

   if is_function postup ; then

      # We need to mark the service as started incase a

      # postdown function wants to restart services that depend on us

      mark_service_started "net.${iface}"

      end_service "net.${iface}" 0

      einfo "Running postup function"

      eindent

      ( postup "${iface}" )

      eoutdent

   fi

   return 0

}

# bool run_stop(char *iface) {

#

# Brings down ${iface}.  If predown call returns non-zero, then

# stop returns non-zero to indicate failure bringing down device.

# In all other cases stop returns 0 to indicate success.

run_stop() {

   local iface="$1" IFVAR=$(bash_variable "$1") x

   # Load our ESSID variable so users can use it in predown() instead

   # of having to write code.

   local ESSID=$(get_options ESSID) ESSIDVAR=

   [[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")

   # Call user-defined predown function if it exists

   if is_function predown ; then

      einfo "Running predown function"

      eindent

      ( predown "${iface}" )

      eend $? "predown ${iface} failed" || return 1

      eoutdent

   elif is_net_fs / ; then

      eerror "root filesystem is network mounted -- can't stop ${iface}"

      return 1

   elif is_union_fs / ; then

      for x in $(unionctl "${dir}" --list \

      | sed -e 's/^\(.*\) .*/\1/') ; do

         if is_net_fs "${x}" ; then

            eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"

            return 1

         fi

      done

   fi

   iface_stop "${iface}" || return 1  # always succeeds, btw

   # Release resolv.conf information.

   [[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"

   

   # Mark us as inactive if called from the background

   [[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"

   # Call user-defined postdown function if it exists

   if is_function postdown ; then

      # We need to mark the service as stopped incase a

      # postdown function wants to restart services that depend on us

      [[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"

      end_service "net.${iface}" 0

      einfo "Running postdown function"

      eindent

      ( postdown "${iface}" )

      eoutdent

   fi

   return 0

}

# bool run(char *iface, char *cmd)

#

# Main start/stop entry point

# We load modules here and remove any functions that they

# added as we may be called inside the same shell scope for another interface

run() {

   local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"

   local starting=true

   local -a MODULES=() mods=()

   local IN_BACKGROUND="${IN_BACKGROUND}"

   if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then

      IN_BACKGROUND=true

   else

      IN_BACKGROUND=false

   fi

   # We need to override the exit function as runscript.sh now checks

   # for it. We need it so we can mark the service as inactive ourselves.

   unset -f exit

   eindent

   [[ ${cmd} == "stop" ]] && starting=false

   # We force lo to only use these modules for a major speed boost

   if is_loopback "${iface}" ; then   

      modules_force=( "iproute2" "ifconfig" "system" )

   fi

   if modules_load "${iface}" "${starting}" ; then

      if [[ ${cmd} == "stop" ]] ; then

         # Reverse the module list for stopping

         mods=( "${MODULES[@]}" )

         for ((i = 0; i < ${#mods[@]}; i++)); do

            MODULES[i]=${mods[((${#mods[@]} - i - 1))]}

         done

         run_stop "${iface}" && r=0

      else

         # Only hotplug on ethernet interfaces

         if [[ ${IN_HOTPLUG} == 1 ]] ; then

            if ! interface_is_ethernet "${iface}" ; then

               eerror "We only hotplug for ethernet interfaces"

               return 1

            fi

         fi

         run_start "${iface}" && r=0

      fi

   fi

   if [[ ${r} != "0" ]] ; then

      if [[ ${cmd} == "start" ]] ; then

         # Call user-defined failup if it exists

         if is_function failup ; then

            einfo "Running failup function"

            eindent

            ( failup "${iface}" )

            eoutdent

         fi

      else

         # Call user-defined faildown if it exists

         if is_function faildown ; then

            einfo "Running faildown function"

            eindent

            ( faildown "${iface}" )

            eoutdent

         fi

      fi

      [[ ${IN_BACKGROUND} == "true" ]] \

         && mark_service_inactive "net.${iface}"

   fi

   return "${r}"

}

# bool start(void)

#

# Start entry point so that we only have one function

# which localises variables and unsets functions

start() {

   declare -r IFACE="${SVCNAME#*.}"

   einfo "Starting ${IFACE}"

   run "${IFACE}" start

}

# bool stop(void)

#

# Stop entry point so that we only have one function

# which localises variables and unsets functions

stop() {

   declare -r IFACE="${SVCNAME#*.}"

   einfo "Stopping ${IFACE}"

   run "${IFACE}" stop

}

# vim:ts=4
```

It appears the other files for eth1 and eth2 are the same.  Don't have a clue here!!!!

All help and explaination appreciated!!

Thanks!

OMR

----------

## OldManRiver

All,

Ran diff on all the net.ethx files and they are in fact all the same.

OMR

----------

