XEN PVUSB: Unterschied zwischen den Versionen

Aus Neobikers Wiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Zeile 3: Zeile 3:
Bei mir gab es Probleme mit USB per PCI-Delegation unter XEN 3.4.1 auf Lenny (die Netzwerkkarten gingen, ''lsusb'' hat auch die USB Hostcontroller angezeigt, aber es wurden keine USB-Devices sichtbar), deshalb habe ich die seit Xen 3.4 neue USB-Virtualisierung '''PVUSB''' (paravirtualized USB support for Xen, Details siehe [http://www.nabble.com/-RFC--PATCH-0-4--PVUSB:-add-paravirtualized-USB-support-for-Xen-td22550607.html hier]) getestet und unter Lenny eingebaut. Dabei ist folgendes Skript herausgekommen, welches ich in '/etc/rc.local' als '''pvusb -b''' aufrufe, um beim booten des Host-Systems den USB-Drucker an meine Printer-Domain durchzureichen.
Bei mir gab es Probleme mit USB per PCI-Delegation unter XEN 3.4.1 auf Lenny (die Netzwerkkarten gingen, ''lsusb'' hat auch die USB Hostcontroller angezeigt, aber es wurden keine USB-Devices sichtbar), deshalb habe ich die seit Xen 3.4 neue USB-Virtualisierung '''PVUSB''' (paravirtualized USB support for Xen, Details siehe [http://www.nabble.com/-RFC--PATCH-0-4--PVUSB:-add-paravirtualized-USB-support-for-Xen-td22550607.html hier]) getestet und unter Lenny eingebaut. Dabei ist folgendes Skript herausgekommen, welches ich in '/etc/rc.local' als '''pvusb -b''' aufrufe, um beim booten des Host-Systems den USB-Drucker an meine Printer-Domain durchzureichen.


<pre>#!/bin/sh -e
<pre>#!/bin/sh
#
#
# paravirtualized USB Support
# paravirtualized USB Support
Zeile 14: Zeile 14:
# $Log$
# $Log$


set -e
#set -x
#set -x


Zeile 28: Zeile 29:
     -d device_id  # USB device_id e.g. "0912:1234"
     -d device_id  # USB device_id e.g. "0912:1234"
     -c comment    # e.g. "Canon IP4000"
     -c comment    # e.g. "Canon IP4000"
    -l            # list (default) actual PVUSB Devices
    -q            # don't list PVUSB devices
     -w            # write/activate PVUSB rule
     -w            # write/activate PVUSB rule
EOT
EOT
Zeile 155: Zeile 158:
     # find out where USB-Device is connected
     # find out where USB-Device is connected
     usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"
     usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"
     usb_bus=$(lsusb | grep $usbdev | awk '{printf "%d",$2}')
     usb_bus=$(lsusb | grep $usb_dev | awk '{printf "%d",$2}')
     usb_adr=$(lsusb | grep $usbdev | awk '{printf "%d",$4}')
     usb_adr=$(lsusb | grep $usb_dev | awk '{printf "%d",$4}')


     for port in $(echo "$usb_ports"|grep "$usb_bus"); do
     for port in $(echo "$usb_ports"|grep "$usb_bus"); do
Zeile 183: Zeile 186:
         # list static definitions here
         # list static definitions here
         # ----------------------------
         # ----------------------------
         # XXX: to be read from e.g. /etc/xen/pvusb.conf
         # XXX: to be read from /etc/pvusb/usb_setup
         case $usb_dev in
         case $usb_dev in
             04a9:1093)
             04a9:1093)
Zeile 264: Zeile 267:
}
}


pvusb_logme ()
pvusb_list ()
{
{
     # tell me what happened
     # tell me what happened
     # ---------------------
     # ---------------------
     PVUSB="$(cat /sys/bus/usb/drivers/usbback/grabbed_devices)"
     pvusb_grabbed="$(cat /sys/bus/usb/drivers/usbback/grabbed_devices)"
     for pvusb in $PVUSB; do
     for pvusb in $pvusb_grabbed; do
         echo "xen PVUSB grabbed USB-Port=$pvusb"
        usb_port=$(echo $pvusb| awk -F: '{print $1}')
        domain=$(cat /sys/bus/usb/drivers/usbback/vports | awk -F: "/$usb_port/"' {print $2}')
        dev_id="$(cat /sys/bus/usb/devices/$usb_port/idVendor)"
        dev_id="$dev_id:$(cat /sys/bus/usb/devices/$usb_port/idProduct)"
        product=$(lsusb | grep $dev_id | cut -d\  -f6-)
         echo "PVUSB: $usb_port on `xm domname $domain` ($domain) $product"
     done
     done
}
}
Zeile 278: Zeile 286:
# ------------------------
# ------------------------
VUSB_ID=0
VUSB_ID=0
list_pvusb=1


while getopts ":bc:d:hs:u:w" opt; do
while getopts ":bc:d:hs:lqu:w" opt; do
   case $opt in
   case $opt in
     b) # boot host with static defined rules
     b) # boot host with static defined rules
       pvusb_boot_host
       pvusb_boot_host
       pvusb_setup
       pvusb_setup
      pvusb_logme
       pvusb_trigger $PVUSB_DOMAINS
       pvusb_trigger $PVUSB_DOMAINS
       ;;
       ;;
Zeile 303: Zeile 311:
       pvusb_port $domain $usb_port "$comment"
       pvusb_port $domain $usb_port "$comment"
       pvusb_setup
       pvusb_setup
      pvusb_logme
       pvusb_trigger $PVUSB_DOMAINS
       pvusb_trigger $PVUSB_DOMAINS
      ;;
    l) # list (default=on) PVUSB Ports
      list_pvusb=1
      ;;
    q) # don't list PVUSB Ports
      list_pvusb=0
       ;;
       ;;
     h)
     h)
Zeile 314: Zeile 327:
   esac
   esac
done
done
[ $list_pvusb -gt 0 ] && pvusb_list
</pre>
</pre>

Version vom 20. August 2009, 12:19 Uhr

PVUSB mit XEN 3.4

Bei mir gab es Probleme mit USB per PCI-Delegation unter XEN 3.4.1 auf Lenny (die Netzwerkkarten gingen, lsusb hat auch die USB Hostcontroller angezeigt, aber es wurden keine USB-Devices sichtbar), deshalb habe ich die seit Xen 3.4 neue USB-Virtualisierung PVUSB (paravirtualized USB support for Xen, Details siehe hier) getestet und unter Lenny eingebaut. Dabei ist folgendes Skript herausgekommen, welches ich in '/etc/rc.local' als pvusb -b aufrufe, um beim booten des Host-Systems den USB-Drucker an meine Printer-Domain durchzureichen.

#!/bin/sh
#
# paravirtualized USB Support
#
# Version: $Revision$
# Datum:   $Date$
#
# Author:  neobiker
#
# $Log$

set -e
#set -x

usage ()
{
  cat <<-EOT
        usage:  $(basename $0) -b
                $(basename $0) -d device_id -s domain [-c comment] -w
                $(basename $0) -u usb-port  -s domain [-c comment] -w
    ------------
    -b            # boot host with static defined PVUSB rules
    -s domain     # server domainname or -id
    -u usb-port   # USB-PORT e.g. "3-2"
    -d device_id  # USB device_id e.g. "0912:1234"
    -c comment    # e.g. "Canon IP4000"
    -l            # list (default) actual PVUSB Devices
    -q            # don't list PVUSB devices
    -w            # write/activate PVUSB rule
EOT
}

#
# paravirtualized USB Support
# ---------------------------

XSWRITE=/usr/bin/xenstore-write
XSCHMOD=/usr/bin/xenstore-chmod

pvusb_init_xenstore ()
{
    # Setup and initialize the XenStore for PVUSB
    # based on init_xs.sh by Noboru Iwamatsu

    FRONT_ID=$(xm domid "$1")   # use domain id if dommane given
    DEV_ID=$2                   # vusb_bus typical 0

    DEV_NAME=vusb       # fix name
    NUM_PORTS=8         # Max 16 ports.

    # Write backend information into the location that frontend look for.
    $XSWRITE /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID/backend-id 0
    $XSWRITE /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID/backend \
            /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID

    # Write frontend information into the location that backend look for.
    $XSWRITE /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/frontend-id $FRONT_ID
    $XSWRITE /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/frontend \
            /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID

    # Write virtual root hub field.
    $XSWRITE /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/num-ports $NUM_PORTS
    for i in $(seq 1 $NUM_PORTS)
    do
        # Set all port to disconnected state
        $XSWRITE /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/port-$i "0"
    done

    # Set permission
    $XSCHMOD /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID n$FRONT_ID r0
    $XSCHMOD /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID/backend-id n$FRONT_ID r0
    $XSCHMOD /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID/backend n$FRONT_ID r0
    $XSCHMOD /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID n0 r$FRONT_ID
    $XSCHMOD /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/frontend-id n0 r$FRONT_ID
    $XSCHMOD /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/frontend n0 r$FRONT_ID
    $XSCHMOD /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/num-ports n0 r$FRONT_ID
    for i in $(seq 1 $NUM_PORTS)
    do
        $XSCHMOD /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/port-$i n0 r$FRONT_ID
    done

    # Set state to XenbusStateInitialising
    $XSWRITE /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID/state 1
    $XSCHMOD /local/domain/$FRONT_ID/device/$DEV_NAME/$DEV_ID/state n$FRONT_ID r0
    $XSWRITE /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/state 1
    $XSCHMOD /local/domain/0/backend/$DEV_NAME/$FRONT_ID/$DEV_ID/state n0 r$FRONT_ID
}

pvusb_init ()
{
    [ "$VUSB_ID" ] || return
    VUSB_ID=1

    # 1) First, you have to start from the state that no device is connected.
    #    remove all usb modules but usbbk
    usb_mods="$(lsmod | grep usb | grep -v usbcore | grep -v usbbk | awk '/^usb/ {print $1}')"
    [ -n "$usb_mods" ] && rmmod $usb_mods

    # stop udevd fetching events before the backend driver
    udevadm control --stop_exec_queue

    # load usb (backend) modules
    modprobe usbbk
}

pvusb_setup ()
{
    # connect USB devices to backend (and restart udevd afterwards)
    # XXX: better way to connect USB devices dynamically without udevd?
    rmmod uhci_hcd ehci_hcd
    modprobe -a uhci_hcd ehci_hcd

    # start udevd again after we have finished
    udevadm control --start_exec_queue
}

pvusb_port ()
{
    dom_id=$1           # domain to connect PVUSB Port
    usb_bus=$2          # where is usb device connected
    comment=$3          # a name for usb device
    vusb_bus=0          # virtual USB Bus in domain (we use always usb bus 0)
    ((++VUSB_ID))

    if [ -z "$dom_id" ]; then
        echo "missing option -s <dom_id>"
        return
    fi
    if [ -z "$usb_bus" ]; then
        echo "missing option -u <usb_port>"
        return
    fi

    # initialise paravirtualized USB Support in domain with pv-usb bus 0
    pvusb_init_xenstore $dom_id $vusb_bus

    # 2) test and remove existing hotplug-rule
    actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_bus/"'{print}')
    [ -n "$actual_vport" ] && echo "$actual_vport" > /sys/bus/usb/drivers/usbback/remove_vport

    # 2) Write the hotplug-rule through the sysfs interface of the backenend driver
    echo "$usb_bus:$dom_id:$vusb_bus:$VUSB_ID" > /sys/bus/usb/drivers/usbback/new_vport

    # tell me what happened
    actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_bus/"'{print}')
    echo "xen PVUSB Rule written: $actual_vport $comment on domain $DOM_NAME ($dom_id)"
}

get_usb_port ()
{
    usb_dev="$1"
    usb_port=""

    # find out where USB-Device is connected
    usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"
    usb_bus=$(lsusb | grep $usb_dev | awk '{printf "%d",$2}')
    usb_adr=$(lsusb | grep $usb_dev | awk '{printf "%d",$4}')

    for port in $(echo "$usb_ports"|grep "$usb_bus"); do
        adr=$(cat /sys/bus/usb/devices/$port/devnum)
        if [ "$adr" = "$usb_adr" ]; then
            usb_port=$port
            break
        fi
    done
    echo "$usb_port"
}

pvusb_write_connected_devices_static ()
{
    # Define where to connect my USB-Devices (static definitions)
    # -----------------------------------------------------------
    #    see dmesg (syslog) where device ist connected:
    #    e.g.: usb 3-2: new full speed USB device using uhci_hcd and address 4

    devices="$1"
    usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"

    for usb_dev in $devices; do

        # where to connect my usb devices to?
        # list static definitions here
        # ----------------------------
        # XXX: to be read from /etc/pvusb/usb_setup
        case $usb_dev in
            04a9:1093)
                comment="Canon-IP4000"
                server=srv
                domain=$(xm domid $server)
                ;;
            13fe:1d00)
                comment="Sun USB-Stick 1GB"
                server=srv
                domain=$(xm domid $server)
                ;;
            090c:1000)
                comment="Novell USB-Stick 2GB"
                server=srv
                domain=$(xm domid $server)
                ;;
            *)
                continue
                ;;
        esac

        # find out where USB-Device is connected
        usb_bus=$(lsusb | grep $usb_dev | awk '{printf "%d",$2}')
        usb_adr=$(lsusb | grep $usb_dev | awk '{printf "%d",$4}')
        for port in $(echo "$usb_ports"|grep "$usb_bus"); do
            adr=$(cat /sys/bus/usb/devices/$port/devnum)
            if [ "$adr" = "$usb_adr" ]; then
                usb_port=$port
                break
            fi
        done
        echo "found $comment ($usb_dev) on USB-Port $usb_port"

        # PVUSB write xen backend rules for usb device
        # --------------------------------------------
        pvusb_port $domain $usb_port "$comment"

        # remember domain to be triggered
        PVUSB_DOMAINS=$(cat <<-EOT | sort -u
                $PVUSB_DOMAINS
                $domain)
    done
}

pvusb_boot_host ()
{
    # get all connected USB devices
    usb_devices=$(lsusb | grep -v '0000:0000' | awk '{print $6}')

    # ready if no devices are found
    if [ -z "$usb_devices" ]; then
        echo "$(basename $0): No USB Devices found"
        return
    fi

    # PVUSB initialising / prerequisits
    # ------------------
    pvusb_init

    # PVUSB write backend rules
    # -------------------------
    pvusb_write_connected_devices_static "$usb_devices"
}

pvusb_trigger ()
{
    # PVUSB trigger for all relevant domains
    # --------------------------------------
    [ -n "$PVUSB" ] || return

    # tell PV domain to reload USB
    # XXX: better way to trigger domU?
    for server in $(echo "$1" | sort -u); do
        ssh $server "[ -n \"\$(lsusb|grep -v '0000:0000')\" ] || exit 0 ;
                     rmmod xen_hcd usbcore ;
                     modprobe xen_hcd
                    "
    done
}

pvusb_list ()
{
    # tell me what happened
    # ---------------------
    pvusb_grabbed="$(cat /sys/bus/usb/drivers/usbback/grabbed_devices)"
    for pvusb in $pvusb_grabbed; do
        usb_port=$(echo $pvusb| awk -F: '{print $1}')
        domain=$(cat /sys/bus/usb/drivers/usbback/vports | awk -F: "/$usb_port/"' {print $2}')
        dev_id="$(cat /sys/bus/usb/devices/$usb_port/idVendor)"
        dev_id="$dev_id:$(cat /sys/bus/usb/devices/$usb_port/idProduct)"
        product=$(lsusb | grep $dev_id | cut -d\  -f6-)
        echo "PVUSB: $usb_port on `xm domname $domain` ($domain) $product"
    done
}

# ------------------------
# Script starts here
# ------------------------
VUSB_ID=0
list_pvusb=1

while getopts ":bc:d:hs:lqu:w" opt; do
  case $opt in
    b) # boot host with static defined rules
      pvusb_boot_host
      pvusb_setup
      pvusb_trigger $PVUSB_DOMAINS
      ;;
    c) # COMMENT (Canon IP4000)
      comment=$OPTARG
      ;;
    d) # USB DEVICE_ID (0912:1234)
      usb_port=$(get_usb_port $OPTARG)
      ;;
    s) # Server Domain name od id
      domain=$OPTARG
      ;;
    u) # USB-PORT (3-2)
      usb_port=$OPTARG
      ;;
    w) # write rule PVUSB
      pvusb_init
      pvusb_port $domain $usb_port "$comment"
      pvusb_setup
      pvusb_trigger $PVUSB_DOMAINS
      ;;
    l) # list (default=on) PVUSB Ports
      list_pvusb=1
      ;;
    q) # don't list PVUSB Ports
      list_pvusb=0
      ;;
    h)
      usage
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done

[ $list_pvusb -gt 0 ] && pvusb_list