commit d585771c9a8a3839418742aa566e22069c6333706c720cda972eb1caa5c3e232 Author: Ludwig Nussel Date: Wed Jun 10 12:46:03 2015 +0000 Accepting request 308347 from home:jengelh:branches:Base:System it's not really SLE-only, so I opted to name it udev-persistent-ifnames instead of udev-branding-SLE OBS-URL: https://build.opensuse.org/request/show/308347 OBS-URL: https://build.opensuse.org/package/show/Base:System/udev-persistent-ifnames?expand=0&rev=1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/75-persistent-net-generator.rules b/75-persistent-net-generator.rules new file mode 100644 index 0000000..bbd3241 --- /dev/null +++ b/75-persistent-net-generator.rules @@ -0,0 +1,107 @@ +# 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=="?*", GOTO="persistent_net_generator_end" + +# device name whitelist +KERNEL!="eth*|ath*|wlan*[0-9]|msh*|ra*|sta*|ctc*|lcs*|hsi*", GOTO="persistent_net_generator_end" + +IMPORT{cmdline}="net.ifnames" +ENV{net.ifnames}=="1", 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}" + +# ignore KVM virtual interfaces +ENV{MATCHADDR}=="52:54:00:*", GOTO="persistent_net_generator_end" +# ignore VMWare virtual interfaces +ENV{MATCHADDR}=="00:0c:29:*|00:50:56:*", GOTO="persistent_net_generator_end" +# ignore Hyper-V virtual interfaces +ENV{MATCHADDR}=="00:15:5d:*", GOTO="persistent_net_generator_end" + +# 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" +# Xensource +ENV{MATCHADDR}=="00:16:3e:*", GOTO="globally_administered_whitelist" + +# match interface dev_id +# HACK: for s390x, if layer2 == 0, dont use dev_id +ENV{LAYER2}="1", TEST=="device/layer2", ENV{LAYER2}="$attr{device/layer2}" +ENV{LAYER2}!="0", ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}" + +# do not use "locally administered" MAC address +ENV{MATCHADDR}=="?[2367abef]:*", ENV{MATCHADDR}="" + +# do not use empty address +ENV{MATCHADDR}=="00:00:00:00:00:00", 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)" + +# 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}="" + +# 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" diff --git a/76-net-sriov-names.rules b/76-net-sriov-names.rules new file mode 100644 index 0000000..78b9674 --- /dev/null +++ b/76-net-sriov-names.rules @@ -0,0 +1,19 @@ +# do not edit this file, it will be overwritten on update +# +# rename SRIOV virtual function interfaces + +ACTION=="remove", GOTO="net-sriov-names_end" +SUBSYSTEM!="net", GOTO="net-sriov-names_end" +KERNEL!="eth*", GOTO="net-sriov-names_end" +NAME=="?*", GOTO="net-sriov-names_end" + +IMPORT{cmdline}="net.ifnames" +ENV{net.ifnames}=="1", GOTO="net-sriov-names_end" + +SUBSYSTEM=="net", SUBSYSTEMS=="pci", ACTION=="add", NAME=="?*", ENV{INTERFACE_NEW}="$name" +SUBSYSTEM=="net", SUBSYSTEMS=="pci", ACTION=="add", IMPORT{program}="net-set-sriov-names" + +# rename interface if needed +ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}" + +LABEL="net-sriov-names_end" diff --git a/net-set-sriov-names b/net-set-sriov-names new file mode 100644 index 0000000..94ee5a4 --- /dev/null +++ b/net-set-sriov-names @@ -0,0 +1,79 @@ +#!/bin/bash -e +# +# This script is run to rename virtual interfaces +# + +if [ -n "$UDEV_LOG" ]; then + if [ "$UDEV_LOG" -ge 7 ]; then + set -x + fi +fi + +# according to dev_new_index(), ifindex is within [1, INT_MAX] +int_max=$(/usr/bin/getconf INT_MAX) +ifindex_before() { + a=$1 + b=$2 + + ((0 < (b - a) && (b - a) < int_max / 2 || + -1 * int_max < (b - a) && (b - a) < -1 * int_max / 2)) +} + +rename_interface() { + local src_net=$1 + local dest_net=$2 + local err=0 + + /sbin/ip link set dev $src_net down + /sbin/ip link set dev $src_net name $dest_net +} + +if [ -z "$INTERFACE" ]; then + echo "missing \$INTERFACE" >&2 + exit 1 +fi + +if [ -e "/sys/class/net/$INTERFACE/device/physfn" ]; then + pf=$(ls -1 "/sys/class/net/$INTERFACE/device/physfn/net") + if [ $(echo "$pf" | wc -l) -ne 1 ]; then + echo "too many pf's" >&2 + exit 1 + fi + read vfindex < "/sys/class/net/$INTERFACE/ifindex" + read pfindex < "/sys/class/net/$pf/ifindex" + if ifindex_before $pfindex $vfindex; then + bus_info=$(basename $(readlink "/sys/class/net/$INTERFACE/device")) + for virtfn in "/sys/class/net/$pf/device/"virtfn*; do + if [ "$(basename $(readlink "$virtfn"))" = "$bus_info" ]; then + vfnum=$(basename "$virtfn") + vfnum=${vfnum#virtfn} + echo "INTERFACE_NEW=$pf.vf$vfnum" + exit 0 + fi + done + fi +fi + +read pfindex < "/sys/class/net/$INTERFACE/ifindex" +shopt -s nullglob +for virtfn in "/sys/class/net/$INTERFACE/device/"virtfn*; do + vf=$(ls -1 "$virtfn/net") + if [ $(echo "$vf" | wc -l) -ne 1 ]; then + echo "too many vf's" >&2 + exit 1 + fi + read vfindex < "/sys/class/net/$vf/ifindex" + if ifindex_before $vfindex $pfindex; then + vfnum=$(basename "$virtfn") + vfnum=${vfnum#virtfn} + if [ "$INTERFACE_NEW" ]; then + new_name=$INTERFACE_NEW + else + new_name=$INTERFACE + fi + new_name="$new_name.vf$vfnum" + if [ "$vf" != "$new_name" ]; then + rename_interface "$vf" "$new_name" + fi + fi +done diff --git a/rule_generator.functions b/rule_generator.functions new file mode 100644 index 0000000..6f118a6 --- /dev/null +++ b/rule_generator.functions @@ -0,0 +1,113 @@ +# functions used by the udev rule generator + +# Copyright (C) 2006 Marco d'Itri + +# 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, either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PATH='/usr/bin:/bin:/usr/sbin:/sbin' + +# 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() { + RUNDIR="/run/udev" + [ -e "$RUNDIR" ] || return 0 + + RULES_LOCK="$RUNDIR/.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() { + RUNDIR="/run/udev" + local tmp_rules_file="$RUNDIR/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="$1" + + 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) +} diff --git a/udev-persistent-ifnames.changes b/udev-persistent-ifnames.changes new file mode 100644 index 0000000..d43190f --- /dev/null +++ b/udev-persistent-ifnames.changes @@ -0,0 +1,5 @@ +------------------------------------------------------------------- +Mon May 18 18:27:59 UTC 2015 - jengelh@inai.de + +- Split off network device naming preferences into separate package + [bnc#931165] diff --git a/udev-persistent-ifnames.spec b/udev-persistent-ifnames.spec new file mode 100644 index 0000000..28567b6 --- /dev/null +++ b/udev-persistent-ifnames.spec @@ -0,0 +1,66 @@ +# +# spec file for package udev-persistent-ifnames +# +# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + + +Name: udev-persistent-ifnames +Version: 0 +Release: 0 +Summary: Persistent classic network interface naming scheme +License: GPL-2.0 +Group: System/Base + +Source: 75-persistent-net-generator.rules +Source2: 76-net-sriov-names.rules +Source3: rule_generator.functions +Source4: write_net_rules +Source5: net-set-sriov-names +BuildArch: noarch +BuildRoot: %_tmppath/%name-%version-build + +%description +This package, when installed, disables the default "Predictable +Network Interface Naming" scheme[PNIN] in udev, and switches it to a +first-loaded-first-named, reboot-persistent scheme. + +[PNIN] http://freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/ + +Differences from PNIN: +* Re-enumeration when the L2 address changes. +* Interface names are not - and cannot be - derived from another property + like PCI bus address. + +%install +b="%buildroot" +mkdir -p "$b/%_sysconfdir/udev/rules.d" +# We _absolutely do_ want to have this symlink in /etc, such that +# `systemd-delta` will show that something is not the same as upstream. +ln -s /dev/null "$b/%_sysconfdir/udev/rules.d/80-net-setup-link.rules" +mkdir -p "$b/%_prefix/lib/udev/rules.d" +install -pm0644 \ + "%_sourcedir"/*.rules \ + "$b/%_prefix/lib/udev/rules.d/" +install -pm0755 \ + "%_sourcedir"/{net-set-sriov-names,rule_generator.functions} \ + "%_sourcedir"/write_net_rules \ + "$b/%_prefix/lib/udev/" + +%files +%defattr(-,root,root) +%_sysconfdir/udev/ +%_prefix/lib/udev/ + +%changelog diff --git a/write_net_rules b/write_net_rules new file mode 100644 index 0000000..1f7a2ad --- /dev/null +++ b/write_net_rules @@ -0,0 +1,153 @@ +#!/bin/sh -e + +# 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= 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 + +# Copyright (C) 2006 Marco d'Itri +# Copyright (C) 2007 Kay Sievers +# +# 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, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# debug, if UDEV_LOG= +if [ -n "$UDEV_LOG" ]; then + if [ "$UDEV_LOG" -ge 7 ]; then + set -x + fi +fi + +RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules' + +. /usr/lib/udev/rule_generator.functions + +interface_name_taken() { + local value="$(find_all_rules 'NAME=' $INTERFACE)" + if [ "$value" ]; then + return 0 + else + return 1 + fi +} + +find_next_available() { + raw_find_next_available "$(find_all_rules 'NAME=' "$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 + # Check if MACADDR doesn't exist already in the generated rules + MAC="$(/usr/bin/grep -w -o -C1 -m1 "$MATCHADDR" "$RULES_FILE" 2>/dev/null || true)" + if [ "$MAC" = "$MATCHADDR" ]; then + unlock_rules_file + exit 0 + fi + match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\"" +fi + +if [ "$MATCHDRV" ]; then + match="$match, DRIVERS==\"$MATCHDRV\"" +fi + +if [ "$MATCHDEVID" ]; then + match="$match, ATTR{dev_id}==\"$MATCHDEVID\"" +fi + +if [ "$MATCHID" ]; then + # Check if KERNEL doesn't exist already in the generated rules + KERNEL="$(find_all_rules 'KERNELS==' "$MATCHID")" + if [ "$KERNEL" = "$MATCHID" ]; then + unlock_rules_file + exit 0 + fi + 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 + +write_rule "$match" "$INTERFACE" "$COMMENT" + +unlock_rules_file + +exit 0