Roger Oberholtzer wrote:
I think it is the order the BIOS discovers/lists the cards. We have some SuperMicro MBs where each boot the drivers may be loaded in a different order. Then ethX moves around and we are not happy campers. The new naming has been a very good thing for us as our systems reboot at least once a day. The kernel naming is not usable as it is not consistent across boots.
I have a bash script I run as part of my boot procedure that checks the hardware-ethernet addrs and renames them. You could use it or adapt it to your setup... It reads it's config out of /etc/sysconfig/assign_netif_names. No guarantees, but seems to work for me. It's run as one of the S50boot scripts out of /etc/init.d/boot.d. ---- Might have to be adapted to work w/SD ... Sample /etc/sysconfig/assign_netif_names at the end of the script. #!/bin/bash #boot.assign_network_names ### BEGIN INIT INFO # Provides: net-devices # Required-Start: boot.usr-mount boot.udev boot.device-mapper boot.localfs # Required-Stop: $null # Default-Start: B # Default-Stop: # Short-Description: reorder and rename net devices # Description: reorder and rename net devs if needed ### END INIT INFO # # assign network names as rc-script # L A Walsh, (free to use/modify/distribute to nice people) (c) 2013-2014 # #include standard template: _prgpth=${0:?}; _prgpth=${_prgpth#-} _prg=${_prgpth##*/}; _prgdr=${_prgpth%/$_prg} [[ -z $_prgdr || $_prg == $_prgdr ]] && _prgdr="$PWD" #if ! typeset -f include >&/dev/null ;then # source ${_LOCAL_DIR:=/etc/local}/bash_env.sh; #fi export PATH="/etc/local/bin:/etc/local/lib:$PATH" export PS4='>>${BASH_SOURCE:+${BASH_SOURCE[0]}}#${LINENO}${FUNCNAME:+(${FUNCNAME[0]})}> ' #include stdalias (needed entries included "inline", below) shopt -s extglob expand_aliases alias dcl=declare sub=function alias int=dcl\ -i map=dcl\ -A hash=dcl\ -A array=dcl\ -a alias lower=dcl\ -l upper=dcl\ -u string=dcl my=dcl alias map2int=dcl\ -Ai intArray=dcl\ -ia cfg_fn="/etc/sysconfig/assign_netif_names" [[ -f $cfg_fn ]] || { echo "Cannot find required config file: $cfg_fn"; exit 1; } # expected variables to be read in array needed_drivers array Linknames array Default map if2hw . $cfg_fn || { echo "Error in reading config file $cfg_fn"; exit 2; } DfltRE="^+(${Default_good[@]})$" DfltRE=${DfltRE// /|} declare -a down_ln=() for ln in "${Linknames[@]}"; do [[ $DfltRE =~ $ln ]] && continue; down_ln+=($ln) done map hw2if for intf in "${!if2hw[@]}" ; do addr=${if2hw[$intf]} hw2if[$addr]="$intf" done ############# end read config ###### #include rc.status -- essential funcs included below: int rc_status=0 sub rc_reset { rc_status=0; } sub rc_status { rc_status=$?; if ((rc_status)) && { (($#)) && [[ $1 = -v ]] ; }; then echo "Abnormal rc_status was $rc_status." elif (($#)) && [[ $1 = -v ]] ; then echo "rc_status: ok" fi } sub rc_exit { rc_status=$?; rc_status exit $rc_status } sub warn () { local msg="Warning: ${1:-"general"}" printf "%s" >&2 "$msg" } sub die () { int stat=$?; local msg="Error. ${1:-"unknown"}" echo "$msg (errno=$stat)" >&2 (exit $stat); #sets $? (doesn't exit inside () rc_status -v rc_exit exit $stat # exit unless die called in subshell } sysfs=/sys sysnet=$sysfs/class/net [[ -d $sysfs && -d $sysnet ]] || sysnet=$sysfs/class/net sys_modules=$sysfs/module if [[ -z $(type -P modprobe) ]]; then # verify find of modprobe export PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH fi if [[ -n $(type -P modprobe) ]]; then # if found, alias it alias modprobe="$(type -P modprobe)" else # only throw error if needed alias modprobe="die 'cannot load required modules'" fi if [[ -z $(type -P ip ) ]]; then # ip is needed, so no delayed error die "Cannot find 'ip' util -- needed for network setup" fi alias ip="$(type -P ip)" sub varflags() { # util: get dcl flags of a var my var="${1:-""}" read out <<<$(declare -p "$var" ) [[ $out =~ /^declare.*=.*$/ ]] || die "no such variable" out="${out%% +([^-])=*}" out="${out#declare }" [[ ${out:0:1} == - ]] || { echo ""; return 0 ; } echo "${out#-}" } sub isarray() { # util: chk if pass name is an array my name="${1:-""}" flags=$(varflags $name) [[ $flags =~ a ]] && return 0 return 1 } sub ipcmd () { # unused/incomplete my ipcmd="${1:?}"; shift; array tmpbuff my outbuff="${2:-tmpbuff}" } sub rev () { # reverse elements of a list, 1/iteration (recursive) (($#==0)) && { echo ""; return 0 ;} my element=${1:?}; shift; (($#==0)) && { echo "$element"; return 0;} echo "$(rev "$@") $element" } sub rename_if () { my old_name=${1:?} new_name=${2:?} echo ip link set name "$new_name" dev "$old_name" } sub down_if () { my if_name=${1:?} echo ip link set down dev "$if_name" } sub set_links_down() { # can't operate on up links for int in "${down_ln[@]}"; do down_if "$int" down done } sub vrfy_drivers () { int errors=0; for i in ${needed_drivers[@]} ; do if [[ ! -d $sys_modules/$i ]]; then # check for loaded or static drivers modprobe "$i" || { warn "Module $i is not in kernel and can't be loaded" errors+=1 } fi done return $errors } map act_hw2if #actual values (to be read in) map act_if2hw map XIF #tmp array to hold exchanged IF's sub get_net_IFnames_hwaddrs () { # get names + addrs from /sys vrfy_drivers array pseudo_devs=(br bond ifb team) string pseudo_RE="^+(${pseudo_devs[@]})$" pseudo_RE=${pseudo_RE// /|} string netdev_pat="+([_0-9a-z])+([0-9])" ( cd "$sysnet" && for nm in $( echo $netdev_pat); do [[ $pseudo_re =~ $nm ]] && continue hwaddr="$(<$nm/address)" echo "$nm" "$(<$nm/address)" done ) } sub read_actuals () { # parse output stream from above my ifname hwaddr ls -ld /proc/self/fd /dev/fd >&2 while read ifname hwaddr; do act_hw2if[$hwaddr]="$ifname" act_if2hw["$ifname"]="$hwaddr" done < <(get_net_IFnames_hwaddrs) } sub ifaddr_cmd () { if ((${#act_hw2if[@]:-0}==0)) ;then read_actuals; fi for ifname in $(printf "%s\n" "${act_hw2if[@]}"|sort|tr "\n" " ") ; do my first_ifn="$ifname" if [[ $ifname =~ \+ ]] ; then first_ifn="${ifname%%+*}" fi printf "%s\t%s\n" "$ifname" "${act_if2hw["$first_ifn"]}" done } sub ifmap_cmd () { ifaddr_cmd "$@" ; } sub remap_cmd () { # remap devnames if needed if ((${#act_hw2if[@]}==0)); then read_actuals; fi my key ifname int count=0 array ifnames=$(printf "%s\n" "${!if2hw[@]}"|sort| grep -P '^[^~+]*$' |tr "\n" " ") array rev_ifns=($(rev "${ifnames[@]}" )) for key in "${rev_ifns[@]}"; do int is_regex=0; ifname="$key" if [[ ${key:0:1} == ~ ]];then ifname=${key:1}; is_regex=1; fi my hwaddr="${if2hw["$key"]:-""}" my actual_hw="${act_if2hw["$ifname"]:-""}" my actual_if="${act_hw2if["$actual_hw"]:-""}" ##line 233 if [[ ${actual_hw:-""} && ! $actual_hw =~ \+ ]]; then ## if ((is_regex)); then [[ $actual_hw =~ $hwaddr ]] && continue else [[ $actual_hw == $hwaddr ]] && continue; fi if [[ ! ${act_if2hw["$ifname"]:-} ]]; then down_if "$actual_hw" rename_if "$actual_hw" "$ifname" ; count+=1 else rename_if "$actual_if" "X$ifname"; #don't count temp renames 2x XIF["X$ifname"]="$hwaddr" fi fi done if ((${#XIF[@]}==0)); then echo "HW interfaces appear to be in order."; return 0; fi int count=0 for ifname in "${!XIF[@]}"; do hwaddr=${XIF[$ifname]}; ifname=${ifname#X} my destname=${hw2if[$hwaddr]} rename_if "$ifname" "$destname" ; count+=1 done printf "%d interface%s renamed\n" $count "$( (($count!=1)) && echo "s" )" } sub start_cmd () { remap_cmd "$@" ; } hash switches=([ifmap]=1 [remap]=1 [start]=1) sub help () { echo "$_prg:" echo "Options: ifmap - show current hw# -> IF map" echo " remap - verify & remap ifnames if needed" return 1 } if (($#)) ; then dcl op="${1#:-}" if [[ ${switches[$op]:-} ]]; then cmd="${op}_cmd" shift $cmd "$@" else echo "Unknown switch :-$op" fi else help fi # vim: ts=2 sw=2 number fdm=marker fdc=1 #/etc/sysconfig/assign_netif_names - sample config # to be sourced by BASH ###### # assign_netif_names reads this at boot to learn of a users # desired network naming (and ordering) #needed_drivers=(e1000e bnx2 ixgbe) # (list builtin as well as modules) # Note -- using brace_expansions #Linknames=( $(echo eth{0..5}) ) # Links that we _expect_ will come up with right names (built-mods) #Default_good=( $(echo eth{0..1}) ) # store as hash, with intfname as key and it's ethernet addr as the data # if2hw=([eth0]="00:15:17:bf:be:b2" [eth1]="00:15:17:bf:be:b3" # [eth2]="00:26:b9:48:71:e2" [eth3]="00:26:b9:48:71:e4" # [eth4]="a0:36:9f:15:c9:c0" [eth5]="a0:36:9f:15:c9:c2" )