Index: systemd-210/src/udev/rule_generator/75-persistent-net-generator.rules
===================================================================
--- /dev/null
+++ systemd-210/src/udev/rule_generator/75-persistent-net-generator.rules
@@ -0,0 +1,105 @@
+# 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
+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"
Index: systemd-210/src/udev/rule_generator/rule_generator.functions
===================================================================
--- /dev/null
+++ systemd-210/src/udev/rule_generator/rule_generator.functions
@@ -0,0 +1,113 @@
+# functions used by the udev rule generator
+
+# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
+
+# 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 <http://www.gnu.org/licenses/>.
+
+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)
+}
Index: systemd-210/src/udev/rule_generator/write_net_rules
===================================================================
--- /dev/null
+++ systemd-210/src/udev/rule_generator/write_net_rules
@@ -0,0 +1,141 @@
+#!/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=<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
+
+# Copyright (C) 2006 Marco d'Itri <md@Linux.IT>
+# Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+# debug, if UDEV_LOG=<debug>
+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
+        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
+        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
Index: systemd-210/Makefile.am
===================================================================
--- systemd-210.orig/Makefile.am
+++ systemd-210/Makefile.am
@@ -2552,7 +2552,14 @@ dist_udevrules_DATA += \
 	rules/75-tty-description.rules \
 	rules/78-sound-card.rules \
 	rules/80-net-setup-link.rules \
-	rules/95-udev-late.rules
+	rules/95-udev-late.rules \
+	src/udev/rule_generator/75-persistent-net-generator.rules \
+	src/udev/rule_generator/76-net-sriov-names.rules
+
+udevlibexec_PROGRAMS += \
+	src/udev/rule_generator/rule_generator.functions \
+	src/udev/rule_generator/write_net_rules \
+	src/udev/rule_generator/net-set-sriov-names
 
 dist_udevhwdb_DATA = \
 	hwdb/20-pci-vendor-model.hwdb \
Index: systemd-210/src/udev/rule_generator/76-net-sriov-names.rules
===================================================================
--- /dev/null
+++ systemd-210/src/udev/rule_generator/76-net-sriov-names.rules
@@ -0,0 +1,18 @@
+# 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"
+
+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}"
+ENV{INTERFACE_NEW}=="", DRIVERS=="cxgb4vf|igbvf|ixgbevf", NAME="vf$attr{ifindex}"
+
+LABEL="net-sriov-names_end"
Index: systemd-210/src/udev/rule_generator/net-set-sriov-names
===================================================================
--- /dev/null
+++ systemd-210/src/udev/rule_generator/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
Index: systemd-210/src/udev/net/link-config.c
===================================================================
--- systemd-210.orig/src/udev/net/link-config.c
+++ systemd-210/src/udev/net/link-config.c
@@ -193,6 +193,18 @@ static bool enable_name_policy(void) {
         r = proc_cmdline(&line);
         if (r < 0)
                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
+#if defined(NET_IFNAMES) && (NET_IFNAMES == 1)
+# warning Using persistent rules as a default
+        if (r <= 0)
+                return false;
+
+        FOREACH_WORD_QUOTED(w, l, line, state)
+                if (strneq(w, "net.ifnames=1", l))
+                       return true;
+
+        return false;
+#else
+# warning Using predictable rules as a default
         if (r <= 0)
                 return true;
 
@@ -201,6 +213,7 @@ static bool enable_name_policy(void) {
                         return false;
 
         return true;
+#endif
 }
 
 int link_config_load(link_config_ctx *ctx) {
