All quoted scripts are direct copy from latest CentOS 6
-
Logon under root or sudo -s
-
Create "/lib/udev/write_net_rules" file with content:
#!/bin/sh -e
#
# Copyright (C) 2006 Marco d'Itri <[email protected]>
# Copyright (C) 2007 Kay Sievers <[email protected]>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation version 2 of the License.
#
# This script is run to create persistent network device naming rules
# based on properties of the device.
# If the interface needs to be renamed, INTERFACE_NEW=<name> will be printed
# on stdout to allow udev to IMPORT it.
# variables used to communicate:
# MATCHADDR MAC address used for the match
# MATCHID bus_id used for the match
# MATCHDEVID dev_id used for the match
# MATCHDRV driver name used for the match
# MATCHIFTYPE interface type match
# COMMENT comment to add to the generated rule
# INTERFACE_NAME requested name supplied by external tool
# INTERFACE_NEW new interface name returned by rule writer
# debug, if UDEV_LOG=<debug>
if [ -n "$UDEV_LOG" ]; then
if [ "$UDEV_LOG" -ge 7 ]; then
set -x
fi
fi
if [ -n "$ASSIGNED_INTERFACE_NAME" -a "$ASSIGNED_INTERFACE_NAME" = "$INTERFACE_NAME" ]; then
exit 0
fi
RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
. /lib/udev/rule_generator.functions
find_all_ifcfg() {
local links=$1
local __sed_discard_ignored_files='/\(~\|\.bak\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d'
files=$(echo /etc/sysconfig/network-scripts/ifcfg-* \
| LC_ALL=C sed -e "$__sed_discard_ignored_files")
for i in $files; do
(
. $i
[ -n "$HWADDR" ] && [ "${links%%[ \[\]0-9]*}" = "${DEVICE%%[ \[\]0-9]*}" ] && echo $DEVICE
)
done
}
interface_name_taken() {
local value="$(find_all_rules 'NAME=' $INTERFACE)"
if [ "$value" ]; then
return 0
else
for i in $(find_all_ifcfg "$INTERFACE"); do
[ "$INTERFACE" = "$i" ] && return 0
done
return 1
fi
}
find_next_available() {
raw_find_next_available $(find_all_rules 'NAME=' "$1") $(find_all_ifcfg "$1")
}
write_rule() {
local match="$1"
local name="$2"
local comment="$3"
{
if [ "$PRINT_HEADER" ]; then
PRINT_HEADER=
echo "# This file was automatically generated by the $0"
echo "# program, run by the persistent-net-generator.rules rules file."
echo "#"
echo "# You can modify it, as long as you keep each rule on a single"
echo "# line, and change only the value of the NAME= key."
fi
echo ""
[ "$comment" ] && echo "# $comment"
echo "SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$name\""
} >> $RULES_FILE
}
if [ -z "$INTERFACE" ]; then
echo "missing \$INTERFACE" >&2
exit 1
fi
# Prevent concurrent processes from modifying the file at the same time.
lock_rules_file
# Check if the rules file is writeable.
choose_rules_file
# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces
if [ "$MATCHADDR" ]; then
match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\""
else
if [ "$INTERFACE_NAME" ]; then
match="$match, DRIVERS==\"?*\", ENV{INTERFACE_NAME}==\"$INTERFACE_NAME\""
fi
fi
if [ "$MATCHDRV" ]; then
match="$match, DRIVERS==\"$MATCHDRV\""
fi
if [ "$MATCHDEVID" ]; then
match="$match, ATTR{dev_id}==\"$MATCHDEVID\""
fi
if [ "$MATCHID" ]; then
match="$match, KERNELS==\"$MATCHID\""
fi
if [ "$MATCHIFTYPE" ]; then
match="$match, ATTR{type}==\"$MATCHIFTYPE\""
fi
if [ -z "$match" ]; then
echo "missing valid match" >&2
unlock_rules_file
exit 1
fi
basename=${INTERFACE%%[0-9]*}
match="$match, KERNEL==\"$basename*\""
if [ "$INTERFACE_NAME" ]; then
# external tools may request a custom name
COMMENT="$COMMENT (custom name provided by external tool)"
if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then
INTERFACE=$INTERFACE_NAME;
echo "INTERFACE_NEW=$INTERFACE"
fi
else
# if a rule using the current name already exists, find a new name
if interface_name_taken; then
INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
# prevent INTERFACE from being "eth" instead of "eth0"
[ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0
echo "INTERFACE_NEW=$INTERFACE"
fi
fi
# build a regular expression that matches the new rule that we want to write
new_rule_pattern=$(echo "^SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$INTERFACE\"$" | sed -re 's/([\?\*\{\}])/\\\1/g')
# Double check if the new rule has already been written. This happens if
# multiple add events are generated before the script returns and udevd
# renames the interfaces. See #765577 for details.
if egrep -qs "$new_rule_pattern" $RO_RULES_FILE $RULES_FILE; then
unlock_rules_file
exit 0
fi
write_rule "$match" "$INTERFACE" "$COMMENT"
unlock_rules_file
exit 0
- Make it executable:
chmod +x /lib/udev/write_net_rules
- Create file "/lib/udev/rule_generator.functions" with content:
# functions used by the udev rule generator
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation version 2 of the License.
PATH='/sbin:/bin'
# Read a single line from file $1 in the $DEVPATH directory.
# The function must not return an error even if the file does not exist.
sysread() {
local file="$1"
[ -e "/sys$DEVPATH/$file" ] || return 0
local value
read value < "/sys$DEVPATH/$file" || return 0
echo "$value"
}
sysreadlink() {
local file="$1"
[ -e "/sys$DEVPATH/$file" ] || return 0
readlink -f /sys$DEVPATH/$file 2> /dev/null || true
}
# Return true if a directory is writeable.
writeable() {
if ln -s test-link $1/.is-writeable 2> /dev/null; then
rm -f $1/.is-writeable
return 0
else
return 1
fi
}
# Create a lock file for the current rules file.
lock_rules_file() {
[ -e /dev/.udev/ ] || return 0
RULES_LOCK="/dev/.udev/.lock-${RULES_FILE##*/}"
retry=30
while ! mkdir $RULES_LOCK 2> /dev/null; do
if [ $retry -eq 0 ]; then
echo "Cannot lock $RULES_FILE!" >&2
exit 2
fi
sleep 1
retry=$(($retry - 1))
done
}
unlock_rules_file() {
[ "$RULES_LOCK" ] || return 0
rmdir $RULES_LOCK || true
}
# Choose the real rules file if it is writeable or a temporary file if not.
# Both files should be checked later when looking for existing rules.
choose_rules_file() {
local tmp_rules_file="/dev/.udev/tmp-rules--${RULES_FILE##*/}"
[ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1
if writeable ${RULES_FILE%/*}; then
RO_RULES_FILE='/dev/null'
else
RO_RULES_FILE=$RULES_FILE
RULES_FILE=$tmp_rules_file
fi
}
# Return the name of the first free device.
raw_find_next_available() {
local links="$*"
local basename=${links%%[ 0-9]*}
local max=-1
for name in $links; do
local num=${name#$basename}
[ "$num" ] || num=0
[ $num -gt $max ] && max=$num
done
local max=$(($max + 1))
# "name0" actually is just "name"
[ $max -eq 0 ] && return
echo "$max"
}
# Find all rules matching a key (with action) and a pattern.
find_all_rules() {
local key="$1"
local linkre="$2"
local match="$3"
local search='.*[[:space:],]'"$key"'"('"$linkre"')".*'
echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \
$RO_RULES_FILE \
$([ -e $RULES_FILE ] && echo $RULES_FILE) \
2>/dev/null)
}
- Create file "/lib/udev/rules.d/75-persistent-net-generator.rules" with content:
# do not edit this file, it will be overwritten on update
# these rules generate rules for persistent network device naming
#
# variables used to communicate:
# MATCHADDR MAC address used for the match
# MATCHID bus_id used for the match
# MATCHDRV driver name used for the match
# MATCHIFTYPE interface type match
# COMMENT comment to add to the generated rule
# INTERFACE_NAME requested name supplied by external tool
# INTERFACE_NEW new interface name returned by rule writer
ACTION!="add", GOTO="persistent_net_generator_end"
SUBSYSTEM!="net", GOTO="persistent_net_generator_end"
# ignore the interface if a name has already been set
NAME=="?*", ENV{INTERFACE_NAME}=="", GOTO="persistent_net_generator_end"
NAME=="?*", ENV{INTERFACE_NAME}=="?*", ENV{ASSIGNED_INTERFACE_NAME}="$name"
# device name whitelist
KERNEL!="eth*|ath*|wlan*[0-9]|msh*|ra*|sta*|ctc*|lcs*|hsi*", GOTO="persistent_net_generator_end"
# ignore Xen virtual interfaces
SUBSYSTEMS=="xen", GOTO="persistent_net_generator_end"
# read MAC address
ENV{MATCHADDR}="$attr{address}"
# match interface type
ENV{MATCHIFTYPE}="$attr{type}"
# do not use empty address
ENV{MATCHADDR}=="00:00:00:00:00:00", ENV{MATCHADDR}=""
# do not use "locally administered" MAC address
ATTR{addr_assign_type}=="?*", ATTR{addr_assign_type}!="0", ENV{MATCHADDR}="", ENV{MATCHID}="$env{NET_MATCHID}"
ATTR{addr_assign_type}=="0", GOTO="globally_administered_whitelist"
# These vendors are known to violate the local MAC address assignment scheme
# Interlan, DEC (UNIBUS or QBUS), Apollo, Cisco, Racal-Datacom
ENV{MATCHADDR}=="02:07:01:*", GOTO="globally_administered_whitelist"
# 3Com
ENV{MATCHADDR}=="02:60:60:*", GOTO="globally_administered_whitelist"
# 3Com IBM PC; Imagen; Valid; Cisco; Apple
ENV{MATCHADDR}=="02:60:8c:*", GOTO="globally_administered_whitelist"
# Intel
ENV{MATCHADDR}=="02:a0:c9:*", GOTO="globally_administered_whitelist"
# Olivetti
ENV{MATCHADDR}=="02:aa:3c:*", GOTO="globally_administered_whitelist"
# CMC Masscomp; Silicon Graphics; Prime EXL
ENV{MATCHADDR}=="02:cf:1f:*", GOTO="globally_administered_whitelist"
# Prominet Corporation Gigabit Ethernet Switch
ENV{MATCHADDR}=="02:e0:3b:*", GOTO="globally_administered_whitelist"
# BTI (Bus-Tech, Inc.) IBM Mainframes
ENV{MATCHADDR}=="02:e6:d3:*", GOTO="globally_administered_whitelist"
# Realtek
ENV{MATCHADDR}=="52:54:00:*", GOTO="globally_administered_whitelist"
# Novell 2000
ENV{MATCHADDR}=="52:54:4c:*", GOTO="globally_administered_whitelist"
# Realtec
ENV{MATCHADDR}=="52:54:ab:*", GOTO="globally_administered_whitelist"
# Kingston Technologies
ENV{MATCHADDR}=="e2:0c:0f:*", GOTO="globally_administered_whitelist"
# match interface dev_id
ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}"
# do not use "locally administered" MAC address
ENV{MATCHADDR}=="?[2367abef]:*", ENV{MATCHADDR}=""
LABEL="globally_administered_whitelist"
# build comment line for generated rule:
SUBSYSTEMS=="pci", ENV{COMMENT}="PCI device $attr{vendor}:$attr{device} ($driver)"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="?*", ENV{COMMENT}="USB device 0x$attr{idVendor}:0x$attr{idProduct} ($driver)"
SUBSYSTEMS=="pcmcia", ENV{COMMENT}="PCMCIA device $attr{card_id}:$attr{manf_id} ($driver)"
SUBSYSTEMS=="ieee1394", ENV{COMMENT}="Firewire device $attr{host_id})"
# ibmveth likes to use "locally administered" MAC addresses
DRIVERS=="ibmveth", ENV{MATCHADDR}="$attr{address}", ENV{COMMENT}="ibmveth ($id)", ENV{MATCHID}=""
# S/390 uses id matches only, do not use MAC address match
SUBSYSTEMS=="ccwgroup", ENV{COMMENT}="S/390 $driver device at $id", ENV{MATCHID}="$id", ENV{MATCHDRV}="$driver", ENV{MATCHADDR}="", ENV{MATCHDEVID}=""
# see if we got enough data to create a rule
ENV{MATCHADDR}=="", ENV{MATCHID}=="", ENV{INTERFACE_NAME}=="", GOTO="persistent_net_generator_end"
# default comment
ENV{COMMENT}=="", ENV{COMMENT}="net device ($attr{driver})"
# write rule
DRIVERS=="?*", IMPORT{program}="write_net_rules"
# rename interface if needed
ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}"
LABEL="persistent_net_generator_end"
- Try it out:
/sbin/udevadm trigger --type=devices --action=add
cat /etc/udev/rules.d/70-persistent-net.rules