Mapping USB network devices to interfaces

From Electron Cloud

Revision as of 00:51, 19 December 2008 by Ecloud (Talk | contribs)
(diff) ← Older revision | Current revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Note: this stuff is quite obsolete since udev has replaced hotplug. And it's Gentoo-centric, too.

See also this article

Jean Tourrilhes's good (but old) tutorial talks a bit about how udev and hotplug can co-exist.

But the Gentoo udev guide says udev should be enough, ideally. Indeed, newer versions of Gentoo do not include /sbin/hotplug or coldplug at all, and /proc/sys/kernel/hotplug is empty. (But udev also interacts with HAL, which in turn interacts with KDE and such, via dbus.)

If /proc/sys/kernel/hotplug is empty, and udevd is running, udevd is receiving uevents over the netlink socket and choreographing all the work. If it's set to /sbin/hotplug, hotplug may or may not itself be using some aspect of udev to do some of its work (e.g. /etc/hotplug.d/default/ might contain a symlink to udevsend). The kernel emits uevents (the new method) and also can try to call the userspace program in /proc/sys/kernel/hotplug (the old method): that happens in lib/kobject_uevent.c.

Way before udev, hotplug did everything (and then there was coldplug... meh.) Hotplug is simpler, but udev seems to be the one with a future at this time.

Obsolete info begins here (it's so 2005)

I sometimes connect multiple usbnet/usblan devices to the same machine; some combination of a Zaurus, a Gumstix board and a Linux phone. They need different IP addresses. When I plug in one of these, Gentoo's hotplug process goes like this:

  1. /sbin/hotplug is called
  2. /sbin/hotplug checks scripts in /etc/hotplug.d for a match; but there is only default.hotplug
  3. /etc/hotplug.d/default/default.hotplug looks for an agent for the event type in /etc/hotplug and usb.agent is found
  4. /etc/hotplug/usb.agent reads /etc/conf.d/usb (and variables can be set, but there is nothing relevant to these devices)
  5. I did a mod so that usb.agent touches a file whose name is the usb device ID in the directory /tmp/lastusb
  6. /etc/hotplug/usb.agent eventually modprobes the driver (this script is complex to deal with different kernel versions, so is a little hard to follow). The result is that a new network interface appears - usb0 if it is the first one, usb1 for the second one, etc.
  7. Somehow in response to a new network interface appearing, /etc/init.d/net.usb0 (or usb1 etc.) is called.
  8. /etc/init.d/net.usb0 uses the file in /tmp/lastusb to decide which IP address to use.
  9. Since /etc/hosts has names for my devices, I can now telnet (or ssh or whatever) to the device by name.

Now here is the mod for /etc/hotplug/usb.agent:

usb_convert_vars ()
{
    # work around 2.2.early brokenness
    # munges the usb_bcdDevice such that it is a integer rather
    # than a float: e.g. 1.0 become 0100
    PRODUCT=`echo $PRODUCT | sed -e "s+\.\([0-9]\)$+.\10+" -e "s/\.$/00/" \
                                  -e "s+/\([0-9]\)\.\([0-9][0-9]\)+/0\1\2+" \
                          -e "s+/\([0-9][0-9]\)\.\([0-9][0-9]\)+/\1\2+"`
    set $(echo $PRODUCT | sed -e 's+\([^/]*\)/\([^/]*\)/\(.*\)+\1 \2 \3+')
    usb_idVendor=$((0x$1))
    usb_idProduct=$((0x$2))
    usb_bcdDevice=$((0x$3))

# my hack begins here
    ifconfig > /tmp/nets
    rm -rf /tmp/lastusb
    mkdir /tmp/lastusb
    touch /tmp/lastusb/"${usb_idVendor}:${usb_idProduct}"
    /bin/sync
    sleep 1
    echo -n "${usb_idVendor}:${usb_idProduct}" > /tmp/lastusbdev
# here endeth the hack

... rest of function

The /tmp/nets line and /tmp/lastusbdev are not necessary but I was experimenting with different ways to do this.

And here's /etc/init.d/net.usb0 (net.usb1 etc. must also exist, but are identical, and can actually just be symlinks):

#!/sbin/runscript
# Distributed under the terms of the GNU General Public License v2

start() {
        ebegin "Bringing ${IFACE} up"
        echo "Bringing ${IFACE} up" > /var/log/usb0.log
        if [ -e /tmp/lastusb/1245:36914 ]
        then
                /sbin/ifconfig ${IFACE} 192.168.129.200 up 2>/dev/null
        else
                /sbin/ifconfig ${IFACE} 192.168.1.1 up 2>/dev/null
        fi
        /etc/init.d/dhcp start
        eend 0
}

stop() {
        ebegin "Bringing ${IFACE} down"
        /sbin/ifconfig ${IFACE} down &>/dev/null
        /etc/init.d/dhcp stop
        eend 0
}

You can change it to use whatever IP's you want to assign to different USB device ID's. It's a little gross to have them hardcoded like that; it should use some stuff in /etc/conf.d instead, I suppose. But it works for me. The whole thing is an inelegant hack, and maybe in the future distros will make stuff like this easier by a completely different mechanism. Maybe there is a way that /sbin/hotplug could call a script that has the USB device ID in its name, if such a script exists; but it needs to be done after the modprobe, and anyway this idea clashes with the general use of /etc/init.d scripts to do such configuration. The problem is that AFAICT, the USB device ID that was just hotplugged is not available to the init.d script, and it really should be. Which is why I had to write it in /tmp.

Maybe the kernel ought to provide a list in order of hotplugging, of the devices that have been hotplugged since boot, in /sys or /proc or something. Or /sbin/hotplug could maintain a log in /var/log, the last line of which is guaranteed to have a well-formed description of the latest device by the time the appropriate /etc/init.d/whatever is called.

A related problem is how to have mountpoints for /mnt/sd0, /mnt/sd1, /mnt/cf0, /mnt/ms0 etc. for various kinds of memory cards, in the order that they were plugged in, in case you have multiple card readers attached, or sometimes attach some other USB mass storage device (which bumps down all the /dev/sd?? entries for the multi-card reader) and sometimes not. And it should add and remove the entries in /etc/fstab as well so you can mount them as soon as plugging them in. For extra points it could even automatically mount/unmount as necessary, like supermount did; I know there is some udev-compatible modern way of doing that. I have not yet solved this problem. And of course distros should be doing stuff like this out-of-the-box by now.

Another idea for mass storage devices would be to have their mountpoints named by their volume names. But often people don't bother with volume names so there has to be a backup strategy. Maybe it ought to just make a symlink /mnt/volumename -> /mnt/sd0 if there is a volume name.

Personal tools