views:

586

answers:

2

I'm writing on an udev-rule to automatically rename and number NICs with specific MAC addresses.

The resulting rule should do nearly the same 75-persistent-net-generator.rules does (match first 3 bytes of the MAC address of card, name it 'mycard*' depending on how much cards of this vendor are installed, write the renaming-rule into 70-persistent-net.rules).

This is how far I've come until now:

# udev rules to name rename cards to mycard

ACTION!="add", GOTO="persistent_mycard_generator_end"
SUBSYSTEM!="net", GOTO="persistent_mycard_generator_end"

# ignore the interface if a name has already been set
NAME=="mycard*", GOTO="persistent_mycard_generator_end"

# device name whitelist
KERNEL!="eth*", GOTO="persistent_mycard_generator_end"

# read MAC address
ENV{MATCHADDR}="$attr{address}"

# match interface type
ENV{MATCHIFTYPE}="$attr{type}"

# ignore non mycard MAC addresses
ENV{MATCHADDR}!="00:11:22:*", GOTO="persistent_mycard_generator_end"

# default comment
ENV{COMMENT}=="", ENV{COMMENT}="mycard connected through ($attr{driver})"

#### THIS IS THE PART I DON'T GET ####

# write rule
DRIVERS=="?*", IMPORT{program}="write_net_rules"

# rename interface if needed
ENV{INTERFACE_NEW}=="?*", NAME="mycard*"

#### THIS IS THE END OF THE PART I DON'T GET ####

LABEL="persistent_mycard_generator_end

The task "THE PART I DON'T GET" should do is to rename a card (lets say it's eth3) to mycard0 or if it's the second card in the system with a matching MAC address mycard1 and so on.

Thanks in advance, flokra

A: 

If you set ENV{INTERFACE} to "mycard0" before calling write_net_rules, it will find the first unused mycardN for you, write out the rule for it, and return the name in ENV{INTERFACE_NEW}.

Alexey Feldgendler
that's nearly it. leaves one problem: the rule written has `KERNEL==mycard*` instead of `KERNEL==eth*` and so it is not applied. I wrote a complete solution today morning and will post it, when I'm back home.
flokra
A: 

OK, here's my solution (I've tested it with Debian 5.0 and Ubuntu 9.04, so I'm not sure if it works with the udev-implementations of other distributions):

  1. 75-persistent-mycard-generator.rules

    ACTION!="add", GOTO="persistent_mycard_generator_end"
    SUBSYSTEM!="net", GOTO="persistent_mycard_generator_end"
    
    
    # ignore the interface if a name has already been set
    NAME=="?*", GOTO="persistent_mycard_generator_end"
    
    
    # device name whitelist
    KERNEL!="eth*", GOTO="persistent_mycard_generator_end"
    
    
    # by default match on the MAC address and interface type
    ENV{MATCHADDR}="$attr{address}"
    ENV{MATCHIFTYPE}="$attr{type}"
    
    
    # match interface dev_id
    ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}"
    
    
    # by default match on the MAC address and interface type
    ENV{MATCHADDR}="$attr{address}"
    ENV{MATCHIFTYPE}="$attr{type}"
    
    
    # match interface dev_id
    ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}"
    
    
    # terminate processing if card is not a mycard
    ENV{MATCHADDR}!="AA:BB:CC:*", GOTO="persistent_mycard_generator_end"
    
    
    # provide nice comments for the generated rules
    SUBSYSTEMS=="pci", ENV{COMMENT}="PCI device $attr{vendor}:$attr{device}"
    SUBSYSTEMS=="pcmcia", ENV{COMMENT}="PCMCIA device $attr{card_id}:$attr{manf_id}"
    SUBSYSTEMS=="usb", ENV{COMMENT}="USB device 0x$attr{idVendor}:0x$attr{idProduct}"
    ENV{COMMENT}=="", ENV{COMMENT}="Unknown $env{SUBSYSTEM} device($env{DEVPATH})"
    ATTRS{driver}=="?*", ENV{COMMENT}="$env{COMMENT} ($attr{driver})"
    
    
    # add mycard to comment
    ENV{COMMENT}="$env{COMMENT} (mycard)"
    
    
    # set interface name to mycard0 (initially)
    ENV{INTERFACE}="mycard0"
    
    
    # generate and write the rule
    DRIVERS=="?*", IMPORT{program}="write_mycard_rules"
    
    
    # rename the interface if requested
    ENV{INTERFACE_NEW}=="?*",NAME="$env{INTERFACE_NEW}"
    
    
    LABEL="persistent_mycard_generator_end"
    
  2. write_mycard_rules

    RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
    
    
    . /lib/udev/hotplug.functions
    
    
    interface_name_taken() {
        local value="$(find_all_rules 'NAME=' $INTERFACE)"
        if [ "$value" ]; then
         return 0
        fi
        return 1
    
    
    }
    
    
    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-mycard-generator.rules rules file."
     echo "#"
     echo "# You can modify it, as long as you keep each rule on a single line."
    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==\"eth*\"" 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]*")" echo "INTERFACE_NEW=$INTERFACE" fi fi write_rule "$match" "$INTERFACE" "$COMMENT" unlock_rules_file exit 0

The most important changes are ENV{INTERFACE}="mycard0" in 75-persistent-mycard-generator.rules which sets the name the card should get and match="$match, KERNEL==\"eth*\"" in write_mycard_rules which forces udev to not override the used Kernel Subsystem with the new name.

HTH, flokra

flokra