XEN PVUSB: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
Zeile 61: | Zeile 61: | ||
# paravirtualized USB Support | # paravirtualized USB Support | ||
# | # | ||
# Version: $Revision: 1. | # Version: $Revision: 1.5 $ | ||
# Datum: $Date: 2009/08/23 | # Datum: $Date: 2009/08/23 20:28:30 $ | ||
# | # | ||
# Author: neobiker | # Author: neobiker | ||
# | # | ||
# $Log: pvusb,v $ | # $Log: pvusb,v $ | ||
# Revision 1.5 2009/08/23 20:28:30 root | |||
# new options -t and -i | |||
# | |||
# Revision 1.4 2009/08/23 17:06:54 root | # Revision 1.4 2009/08/23 17:06:54 root | ||
# optimization and code readability | # optimization and code readability | ||
Zeile 92: | Zeile 95: | ||
{ | { | ||
cat <<-EOT | cat <<-EOT | ||
usage: $(basename $0) -b | usage: $(basename $0) -b | -i | -l | ||
$(basename $0) -d device_id -s domain [-c comment] -w | $(basename $0) -d <device_id> -s <domain> [-c comment] -w [ -t ] | ||
$(basename $0) -u usb-port | $(basename $0) -u <usb-port> -s <domain> [-c comment] -w [ -t ] | ||
$(basename $0) -r | |||
$(basename $0) -x <usb-port>:<domain>:0:<vport> | |||
------------ | ------------ | ||
-b # boot | -b # boot/initialise PVUSB with setup ($CONFIG) | ||
-i # initialize PVUSB without any rules | |||
-s domain # server domain_name or domain_id | -s domain # server domain_name or domain_id | ||
-u usb-port # USB-PORT e.g. "3-2" | -u usb-port # USB-PORT e.g. "3-2" | ||
Zeile 102: | Zeile 108: | ||
-c comment # e.g. "Canon IP4000" | -c comment # e.g. "Canon IP4000" | ||
-l # list grabbed PVUSB Devices | -l # list grabbed PVUSB Devices | ||
-r # read PVUSB rules | |||
-r # | |||
-w # write/activate PVUSB rule | -w # write/activate PVUSB rule | ||
-x # delete PVUSB rule | -x # delete PVUSB rule | ||
-t # try to trigger domain (per ssh) | |||
-q # be quiet | |||
EOT | EOT | ||
} | } | ||
Zeile 111: | Zeile 118: | ||
init () | init () | ||
{ | { | ||
NUM_PORTS=8 # Max 16 PVUSB ports. | |||
NUM_PORTS=8 # Max 16 ports. | |||
CONFIG=/etc/xen/pvusb.conf | CONFIG=/etc/xen/pvusb.conf | ||
[ -e $CONFIG ] || cat >$CONFIG <<-EOT | [ -e $CONFIG ] || cat >$CONFIG <<-EOT | ||
Zeile 181: | Zeile 186: | ||
{ | { | ||
# initialise backend only once | # initialise backend only once | ||
[ "$PVUSB_INIT" ] | [ "$PVUSB_INIT" = "1" ] && { PVUSB_INIT=1; return; } | ||
# 1) First, you have to start from the state that no device is connected. | # 1) First, you have to start from the state that no device is connected. | ||
Zeile 195: | Zeile 200: | ||
# remember that pvusb is initialised | # remember that pvusb is initialised | ||
} | } | ||
pvusb_trigger_backend () | |||
{ | { | ||
# connect USB devices to backend (and restart udevd afterwards) | # connect USB devices to backend (and restart udevd afterwards) | ||
# XXX: find better way to connect USB devices dynamically!!! | |||
rmmod uhci_hcd ehci_hcd | |||
modprobe -a uhci_hcd ehci_hcd | |||
# start udevd again after we have finished | # start udevd again after we have finished | ||
Zeile 243: | Zeile 238: | ||
fi | fi | ||
vusb_port=$(get_vusb_port $usb_port) | |||
vusb_port= | |||
# initialise paravirtualized USB Support in domain with vusb bus 0 | # initialise paravirtualized USB Support in domain with vusb bus 0 | ||
Zeile 272: | Zeile 255: | ||
echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)" | echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)" | ||
fi | fi | ||
} | |||
get_vusb_port () | |||
{ | |||
usb_port=$1 | |||
# get new vusb_port between 2 .. $NUM_PORTS | |||
vports=`cat /sys/bus/usb/drivers/usbback/vports | grep $usb_port | cut -d: -f4 | sort -n` | |||
if [ -z "$vports" ]; then | |||
echo "2" | |||
return | |||
else | |||
for ((i=2; $i<=$NUM_PORTS; i++)); do | |||
if [ -z "$(echo $vports | grep $i)" ]; then | |||
echo "$i" | |||
return | |||
fi | |||
done | |||
fi | |||
echo "Error: no virtual USB-Port free for $usb_port" >2 | |||
} | } | ||
Zeile 287: | Zeile 290: | ||
adr=$(cat /sys/bus/usb/devices/$port/devnum) | adr=$(cat /sys/bus/usb/devices/$port/devnum) | ||
if [ "$adr" = "$usb_adr" ]; then | if [ "$adr" = "$usb_adr" ]; then | ||
echo "$port" | |||
return | |||
fi | fi | ||
done | done | ||
echo "$ | echo "Error: no USB-Port not found for $usb_dev" >2 | ||
} | } | ||
pvusb_write_connected_devices_from_configfile () | |||
{ | { | ||
# | # $CONFIG: where to connect my USB-Devices | ||
# | # ---------------------------------------- | ||
# see dmesg (syslog) where device ist connected: | # see dmesg (syslog) where device ist connected: | ||
# e.g.: usb 3-2: new full speed USB device using uhci_hcd and address 4 | # e.g.: usb 3-2: new full speed USB device using uhci_hcd and address 4 | ||
Zeile 308: | Zeile 311: | ||
# where to connect my usb devices to? | # where to connect my usb devices to? | ||
# | # read static definitions from $CONFIG | ||
pvusb_conf=$(grep "$usb_dev" $CONFIG) | pvusb_conf=$(grep "$usb_dev" $CONFIG) | ||
Zeile 354: | Zeile 357: | ||
# PVUSB initialising / prerequisits | # PVUSB initialising / prerequisits | ||
# ------------------ | # ------------------ | ||
pvusb_init_backend | pvusb_init_backend | ||
# PVUSB write backend rules | # PVUSB write backend rules | ||
# ------------------------- | # ------------------------- | ||
pvusb_write_connected_devices_from_configfile "$usb_devices" | |||
} | } | ||
Zeile 365: | Zeile 367: | ||
{ | { | ||
# PVUSB trigger for all relevant domains | # PVUSB trigger for all relevant domains | ||
# XXX: better way to trigger domU? | # XXX: better way to trigger domU? | ||
for domain in $(echo "$1" | sort -u); do | for domain in $(echo "$1" | sort -u); do | ||
ssh $domain "[ -n \"\$(lsusb | | ssh $domain "[ -n \"\$(lsusb || true)\" ] && exit 0 ; | ||
rmmod xen_hcd usbcore ; | rmmod xen_hcd usbcore ; | ||
modprobe xen_hcd | modprobe xen_hcd | ||
Zeile 400: | Zeile 398: | ||
init | init | ||
while getopts ":bc:d: | while getopts ":bc:d:Dhilqrs:tu:wx:" opt; do | ||
case $opt in | case $opt in | ||
b) # boot host with | b) # boot host with setup rules in $CONFIG | ||
pvusb_boot_init | pvusb_boot_init | ||
pvusb_trigger_backend | |||
pvusb_trigger $PVUSB_DOMAINS | pvusb_trigger $PVUSB_DOMAINS | ||
;; | |||
i) # initialise PVUSB without any rules | |||
pvusb_init_backend | |||
pvusb_trigger_backend | |||
;; | ;; | ||
c) # comment e.g. Canon IP4000 | c) # comment e.g. Canon IP4000 | ||
Zeile 425: | Zeile 427: | ||
;; | ;; | ||
s) # Server Domain-name or -id | s) # Server Domain-name or -id | ||
domain=$OPTARG | domain=$(xm domname $OPTARG) # check if domain exists | ||
;; | |||
t) # try to trigger domain with ssh | |||
pvusb_trigger $PVUSB_DOMAINS $domain | |||
;; | ;; | ||
u) # USB-PORT (3-2) | u) # USB-PORT (3-2) | ||
Zeile 436: | Zeile 438: | ||
pvusb_init_backend | pvusb_init_backend | ||
pvusb_write_rule $domain $usb_port "$comment" | pvusb_write_rule $domain $usb_port "$comment" | ||
pvusb_trigger_backend | |||
pvusb_trigger $PVUSB_DOMAINS | |||
LIST_PVUSB=1 | LIST_PVUSB=1 | ||
;; | ;; | ||
x) # delete PVUSB rule | x) # delete PVUSB rule | ||
echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true | echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true | ||
;; | |||
D) set -x | |||
;; | ;; | ||
\?) | \?) |
Version vom 23. August 2009, 21:35 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.
Beispiele PVUSB Konfigfile zum automatischen Verbinden von USB-Devices z.B. beim booten des XEN Hostsystems. Ich verbinde meinen USB-Drucker nach dem Start mit meinen CUPS Printserver (srv), und USB-Sticks z.B. mit dem Webserver in der DMZ (dmz).
File /etc/xen/pvusb.conf
# Configfile for pvusb # Device_Id Domain Comment 04a9:1093 srv Canon IP4000 13fe:1d00 srv Sun USB-Stick 1GB 090c:1000 dmz Novell USB-Stick 2GB
File /etc/rc.local
#!/bin/sh ... /usr/local/sbin/pvusb -b ...
Beispiele für pvusb
m450:~# pvusb -h usage: pvusb -b pvusb -d device_id -s domain [-c comment] -w pvusb -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 -r # list PVUSB rules -w # write/activate PVUSB rule -x # delete PVUSB rule m450:~# pvusb -l PVUSB: 3-2 on srv (3) 04a9:1093 Canon, Inc. PIXMA iP4000 m450:~# pvusb -r 5-1:5:0:2 3-2:3:0:3 5-2:3:0:2 m450:~# pvusb -x 5-2:3:0:2 m450:~# pvusb -r 5-1:5:0:2 3-2:3:0:3
File /usr/local/sbin/pvusb
#!/bin/sh # # paravirtualized USB Support # # Version: $Revision: 1.5 $ # Datum: $Date: 2009/08/23 20:28:30 $ # # Author: neobiker # # $Log: pvusb,v $ # Revision 1.5 2009/08/23 20:28:30 root # new options -t and -i # # Revision 1.4 2009/08/23 17:06:54 root # optimization and code readability # # Revision 1.3 2009/08/22 19:35:40 root # bugfix convert dom_id+dom_nam # # Revision 1.2 2009/08/21 22:24:27 root # bugfix: rename $server to $domain # # Revision 1.1 2009/08/20 20:28:14 root # Initial revision # LSUSB=$(lsusb||echo "Error") if [ "$LSUSB" = "Error" ]; then echo "Error: Missing /usr/bin/lsusb, please install usbutils" exit 1 fi set -e #set -x usage () { cat <<-EOT usage: $(basename $0) -b | -i | -l $(basename $0) -d <device_id> -s <domain> [-c comment] -w [ -t ] $(basename $0) -u <usb-port> -s <domain> [-c comment] -w [ -t ] $(basename $0) -r $(basename $0) -x <usb-port>:<domain>:0:<vport> ------------ -b # boot/initialise PVUSB with setup ($CONFIG) -i # initialize PVUSB without any rules -s domain # server domain_name or domain_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 grabbed PVUSB Devices -r # read PVUSB rules -w # write/activate PVUSB rule -x # delete PVUSB rule -t # try to trigger domain (per ssh) -q # be quiet EOT } init () { NUM_PORTS=8 # Max 16 PVUSB ports. CONFIG=/etc/xen/pvusb.conf [ -e $CONFIG ] || cat >$CONFIG <<-EOT # Configfile for pvusb # 'pvusb -b' connects Device_Id to Domain # Device_Id Domain Comment # 1234:5678 server USB-Printer EOT } # # paravirtualized USB Support # --------------------------- pvusb_init_xenstore () { # Setup and initialize the XenStore for PVUSB # based on init_xs.sh by Noboru Iwamatsu dom_id=$1 vusb_bus=$2 # vusb_bus (typical 0) XSWRITE=/usr/bin/xenstore-write XSCHMOD=/usr/bin/xenstore-chmod # Write backend information into the location that frontend look for. $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/backend-id 0 $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/backend \ /local/domain/0/backend/vusb/$dom_id/$vusb_bus # Write frontend information into the location that backend look for. $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend-id $dom_id $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend \ /local/domain/$dom_id/device/vusb/$vusb_bus # Write virtual root hub field. $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/num-ports $NUM_PORTS for i in $(seq 1 $NUM_PORTS) do # Set all port to disconnected state $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port-$i "0" done # Set permission $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus n$dom_id r0 $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/backend-id n$dom_id r0 $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/backend n$dom_id r0 $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus n0 r$dom_id $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend-id n0 r$dom_id $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend n0 r$dom_id $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/num-ports n0 r$dom_id for i in $(seq 1 $NUM_PORTS) do $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port-$i n0 r$dom_id done # Set state to XenbusStateInitialising $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/state 1 $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/state n$dom_id r0 $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/state 1 $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/state n0 r$dom_id } pvusb_init_backend () { # initialise backend only once [ "$PVUSB_INIT" = "1" ] && { PVUSB_INIT=1; return; } # 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 # remember that pvusb is initialised } pvusb_trigger_backend () { # connect USB devices to backend (and restart udevd afterwards) # XXX: find better way to connect USB devices dynamically!!! rmmod uhci_hcd ehci_hcd modprobe -a uhci_hcd ehci_hcd # start udevd again after we have finished udevadm control --start_exec_queue } pvusb_write_rule () { domain=$1 # domain to connect PVUSB Port usb_port=$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) if [ -z "$domain" ]; then echo "missing option -s <domain>" return fi if [ -z "$usb_port" ]; then echo "missing option -u <usb_port>" return fi if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then dom_name=$(xm domname $domain) dom_id=$domain else dom_name=$domain dom_id=$(xm domid $domain) fi vusb_port=$(get_vusb_port $usb_port) # initialise paravirtualized USB Support in domain with vusb 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_port/"'{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_port:$dom_id:$vusb_bus:$vusb_port" > /sys/bus/usb/drivers/usbback/new_vport # tell me what happened if [ -z "$QUIET" ]; then actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_port/"'{print}') echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)" fi } get_vusb_port () { usb_port=$1 # get new vusb_port between 2 .. $NUM_PORTS vports=`cat /sys/bus/usb/drivers/usbback/vports | grep $usb_port | cut -d: -f4 | sort -n` if [ -z "$vports" ]; then echo "2" return else for ((i=2; $i<=$NUM_PORTS; i++)); do if [ -z "$(echo $vports | grep $i)" ]; then echo "$i" return fi done fi echo "Error: no virtual USB-Port free for $usb_port" >2 } 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=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}') usb_adr=$(echo "$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 echo "$port" return fi done echo "Error: no USB-Port not found for $usb_dev" >2 } pvusb_write_connected_devices_from_configfile () { # $CONFIG: where to connect my USB-Devices # ---------------------------------------- # 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" # XXX: only normal USB-Ports (1-1) are supported yet, no cascaded USB-Hubs (1-1.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? # read static definitions from $CONFIG pvusb_conf=$(grep "$usb_dev" $CONFIG) if [ -n "$pvusb_conf" ]; then domain=$(echo $pvusb_conf | awk '{print $2}') comment=$(echo $pvusb_conf | cut -d\ -f3-) else continue fi # find out where USB-Device is connected usb_bus=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}') usb_adr=$(echo "$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_write_rule $domain $usb_port "$comment" # remember domain to be triggered PVUSB_DOMAINS=$(cat <<-EOT | sort -u $PVUSB_DOMAINS $domain) done } pvusb_boot_init () { # get all connected USB devices usb_devices=$(echo "$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_backend # PVUSB write backend rules # ------------------------- pvusb_write_connected_devices_from_configfile "$usb_devices" } pvusb_trigger () { # PVUSB trigger for all relevant domains # XXX: better way to trigger domU? for domain in $(echo "$1" | sort -u); do ssh $domain "[ -n \"\$(lsusb || true)\" ] && exit 0 ; rmmod xen_hcd usbcore ; modprobe xen_hcd " || true 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}') dom_id=$(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=$(echo "$LSUSB" | grep $dev_id | cut -d\ -f6-) echo "PVUSB: $usb_port on `xm domname $dom_id` ($dom_id) $product" done } # ------------------------ # Script starts here # ------------------------ init while getopts ":bc:d:Dhilqrs:tu:wx:" opt; do case $opt in b) # boot host with setup rules in $CONFIG pvusb_boot_init pvusb_trigger_backend pvusb_trigger $PVUSB_DOMAINS ;; i) # initialise PVUSB without any rules pvusb_init_backend pvusb_trigger_backend ;; c) # comment e.g. Canon IP4000 comment=$OPTARG ;; d) # USB DEVICE_ID (0912:1234) usb_port=$(get_usb_port $OPTARG) ;; h) usage ;; l) # list PVUSB Ports LIST_PVUSB=1 ;; q) # don't list PVUSB Ports QUIET=0 ;; r) # list rules cat /sys/bus/usb/drivers/usbback/vports ;; s) # Server Domain-name or -id domain=$(xm domname $OPTARG) # check if domain exists ;; t) # try to trigger domain with ssh pvusb_trigger $PVUSB_DOMAINS $domain ;; u) # USB-PORT (3-2) usb_port=$OPTARG ;; w) # write rule PVUSB pvusb_init_backend pvusb_write_rule $domain $usb_port "$comment" pvusb_trigger_backend pvusb_trigger $PVUSB_DOMAINS LIST_PVUSB=1 ;; x) # delete PVUSB rule echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true ;; D) set -x ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; esac done [ "$LIST_PVUSB" = "1" ] && pvusb_list