#!/bin/ksh93 RULEFILE='/lib/udev/rules.d/76-ifname.rules' RAMFSHOOK='/usr/share/initramfs-tools/hooks/ifnames' function initrdNotice { print ' If you are booting via initrd, you should update the related image. E.g.: update-initramfs -k all -u ' } function check4systemd { (( FORCE )) && return 0 T=( ${ ls -l /sbin/init ; } ) if [[ ${T[10]##*/} == 'systemd' ]]; then print -u2 'This seems to be a systemd enabled system, which does not' \ 'require udev ifname hooks. Use option -f if you insist on the' \ 'related action.' return 1 fi return 0 } function installHook { check4systemd || return 1 HOOK='#!/bin/sh -e PREREQS="udev" # Since this stuff gets sourced in rather than execed by a very brain damaged, # limited and buggy shell, we need to use its poor, bloated syntax and can not # make use of advanced features provided by ksh93 ... :(((((((( MAPSCRIPT="/lib/udev/net.ifnames" # Just to avoid copy over itself if [ -z "${DESTDIR}" ]; then DESTDIR=/tmp fi if [ -n "$1" -a "$1" = "prereqs" ]; then echo "${PREREQS}" exit 0 fi . /usr/share/initramfs-tools/hook-functions while read LINE ; do if [ "${LINE#RULEFILE=}" != "${LINE}" ]; then RULEFILE="${LINE#RULEFILE=?}" RULEFILE="${RULEFILE%?}" break fi done < "${MAPSCRIPT}" if [ -z "${RULEFILE}" ] ; then echo "${MAPSCRIPT} script does not contain RULEFILE setting!" exit 1 fi cp -pL "${RULEFILE}" "${DESTDIR}/lib/udev/rules.d/" copy_exec /usr/sbin/dmidecode /usr/sbin ' if (( DRY )); then print "=== schnipp ===\n${HOOK}\n=== schnapp ===" print "Hook would be installed as '${RAMFSHOOK}'" else print "${HOOK}" >"${RAMFSHOOK}" && \ print "Hook installed as '${RAMFSHOOK}'" chmod 755 "${RAMFSHOOK}" fi initrdNotice } function makeRule { check4systemd || return 1 typeset RULE='# FIN/IWS NIC naming # '"${RULEFILE}"' ACTION=="add", SUBSYSTEM=="net", PROGRAM="net.ifnames $devpath", RESULT=="?*", NAME="%c" ' if (( DRY )); then print "=== schnipp ===\n${RULE}\n=== schnapp ===" print "Rule would be installed as '${RULEFILE}'" else print -n "${RULE}" >"${RULEFILE}" && \ print "Rule installed as '${RULEFILE}'" fi initrdNotice } # We usually get an env like this passed: # --------------------------------------- #DEVPATH=/devices/pci0000:00/0000:00:03.2/0000:05:00.0/net/eth1 #ID_BUS=pci #ID_MODEL_FROM_DATABASE='I350 Gigabit Network Connection' #ID_MODEL_ID=0x1521 #ID_NET_NAME_MAC=enx002590eb9eaa #ID_NET_NAME_PATH=enp5s0f0 #ID_OUI_FROM_DATABASE='Super Micro Computer, Inc.' #ID_PCI_CLASS_FROM_DATABASE='Network controller' #ID_PCI_SUBCLASS_FROM_DATABASE='Ethernet controller' #ID_VENDOR_FROM_DATABASE='Intel Corporation' #ID_VENDOR_ID=0x8086 #IFINDEX=2 #INTERFACE=eth1 #SUBSYSTEM=net # check with: udevadm trigger -c add -p ${DEVPATH} function lookup { integer DEBUG=1 typeset X="${1##*/}" [[ -z ${INTERFACE} ]] && INTERFACE="$X" if (( DEBUG )); then [[ -d /dev/.initramfs ]] && T='/dev/.initramfs' || T='/tmp' T+="/ifname-${INTERFACE}.debug" print "\n\n=====================">>$T set >>$T fi [[ $1 =~ /virtual/ ]] && print "${INTERFACE}" && return 0 [[ -z ${ID_NET_NAME_PATH} ]] && ID_NET_NAME_PATH="${INTERFACE}" [[ -z ${ID_NET_NAME_PATH} ]] && return 0 typeset -A X8DAH X9DRH X10DRH X10DRG HPZ400 HPZ420 LTP VBOX # MB = ( PCI-BUS_hex=slot_name ) X8DAH=( ['01']='mb' ['83']='a' ['85']='b' ['82']='c' ['84']='d' ['04']='e' ['03']='f' ['06']='g' ) X9DRH=( ['05']='mb' ['83']='a' ['82']='b' ['81']='c' ['84']='d' ['03']='e' ['02']='f' ['06']='g' ) X10DRH=( ['05']='mb' ['83']='a' ['82']='b' ['81']='c' ['80']='d' ['04']='e' ['03']='f' ['02']='g' ) X10DRG=( ['81']='mb' ['01']='j' ) HPZ400=( ['01']='mb' ) HPZ420=( ['01']='mb' ) LTP=( ['00']='mb' ) VBOX=( ['00']='mb' ) GA291_281=( ['01']='mb' [18]='a' ) #mb0 g0 1.0 #a0 g3 0.3 1 #nv 0.0 2 #c0 g2 0.2 3 #d0 g1 0.1 4 #e0 g4 0.4 5 #INTERFACE_NEW net.ifnames typeset PORT=${ID_NET_NAME_PATH##*f} typeset BUS=${.sh.match%f} [[ -z ${BUS} ]] && PORT=0 && BUS=${ID_NET_NAME_PATH} # we assume sub device is always 00 BUS=${BUS%s*} typeset MBV NO=${ printf "%02x" ${BUS##+([a-z])} ; } if [[ -x /usr/sbin/dmidecode ]]; then MBV=( ${ /usr/sbin/dmidecode -s baseboard-manufacturer 2>/dev/null ; } ) if [[ ${MBV} == 'Supermicro' ]]; then MBV=( ${ /usr/sbin/dmidecode -s baseboard-product-name 2>/dev/null; } ) MBV=${MBV%%-*} elif [[ ${MBV} == 'Hewlett-Packard' ]]; then MBV=( ${ /usr/sbin/dmidecode -s system-product-name 2>/dev/null; } ) if [[ ${MBV[@]} == 'HP Z400 Workstation' ]]; then MBV='HPZ400' elif [[ ${MBV[@]} == 'HP Z420 Workstation' ]]; then MBV='HPZ420' fi elif [[ ${MBV} == 'LENOVO' ]]; then MBV=( ${ /usr/sbin/dmidecode -s system-version 2>/dev/null; } ) [[ ${MBV} == 'ThinkPad' ]] && MBV='LTP' || MBV= elif [[ ${MBV} == 'Oracle' ]]; then MBV=( ${ /usr/sbin/dmidecode -s baseboard-product-name 2>/dev/null; } ) if [[ ${MBV} == 'VirtualBox' ]]; then MBV='VBOX' PORT=${INTERFACE##*s} fi elif [[ ${MBV} == 'GIGABYTE' ]]; then MBV=( ${ /usr/sbin/dmidecode -s system-product-name 2>/dev/null; } ) if [[ ${MBV} == 'G291-281-00' ]]; then MBV='GA291_281' # GA beginnt die Portnummerierung mit '1' =8-( [[ ${NO} == '01' ]] && (( PORT+=1 )) fi fi fi if [[ -n ${MBV} ]]; then typeset -n MAP=${MBV} typeset IF=${MAP["${NO}"]} if [[ -n ${IF} ]]; then print "${IF}${PORT}" (( DEBUG )) && print "RESULT=${IF}${PORT}" >>$T return 0 fi fi print "${INTERFACE}" } function fireUdev { typeset DEVS=${ ls -1 /sys/class/net/en* 2>/dev/null ; } F [[ -z ${DEVS} ]] && return 0 for D in ${DEVS} ; do udevadm trigger --action=add $D done } integer MKRULE=0 DRY=0 INSTHOOK=0 UDEV=0 FORCE=0 FPROG=${.sh.file} PROG=${FPROG##*/} function showUsage { typeset WHAT="$1" X='--man' [[ -z ${WHAT} ]] && WHAT='MAIN' && X='-?' getopts -a "${PROG}" "${ print ${USAGE}; }" OPT $X } USAGE='[-?$Id$ ] [-copyright?Copyright (c) 2014 Jens Elkner. All rights reserved.] [-license?CDDL 1.0] [+NAME?'"${PROG}"' - manage NIC names] [+DESCRIPTION?This script can be used on \bLinux\b to name NICs in a stable manner. However, newer aka systemd enabled systems should use systemd-networkd config files in \b/etc/systemd/network/\b to do the same.] [+?] [+?If no option is given, the environment variable \bID_NET_NAME_PATH\b will be used to determine the appropriate name of the related interface.] [h:help?Print this help and exit.] [F:functions?Print a list of all functions of this script.] [T:trace]:[functionList?A comma separated list of functions of this script to trace (convinience for troubleshooting).] [n:dry?Just print the related map or rule to stdout, but do not install it.] [r:rule?Generate the rule file, which makes use of this script.] [R:ramfs?Generate the initramfs hook, so that all related files get copied to the initrd image and thus the script can fire on boot.] [u:udevs?Triggers an udev add event for all ethernet devices (/sys/class/net/en*).] [f:force?Do it even if the target is a systemd enabled system.] \n\n[\adevpath\a] ' while getopts -a "${PROG}" "${ print ${USAGE}; }" OPT ; do case ${OPT} in h) showUsage MAIN ; exit 0 ;; F) typeset +f && exit 0 ;; T) if [[ ${OPTARG} == 'ALL' ]]; then typeset -ft ${ typeset +f ; } else typeset -ft ${OPTARG//,/ } fi ;; n) DRY=1 ;; m) MKMAP=1 ;; r) MKRULE=1 ;; R) INSTHOOK=1 ;; u) UDEV=1 ;; f) FORCE=1 ;; *) showUsage ;; esac done (( IDX=OPTIND-1 )) shift $IDX (( MKRULE )) && makeRule (( INSTHOOK )) && installHook if [[ -n $1 ]]; then lookup "$1" elif (( MKRULE + INSTHOOK + UDEV == 0 )); then showUsage fi