XEN PVUSB: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| Zeile 12: | Zeile 12: | ||
<pre> | <pre> | ||
# Configfile for pvusb | # Configfile for pvusb | ||
# Dev_Id | # Dev_Id <domain> <Comment> | ||
# USBPort | # USBPort <domain> <Comment> | ||
04a9:1093 srv Canon IP4000 | # 0000:0000 <domain> <Comment> | ||
04a9:1093 srv Canon Printer IP4000 | |||
5-1 dmz Anything on USB Port 5-1 | |||
0000:0000 vm01 initialize 'vm01' for PVUSB | |||
</pre> | </pre> | ||
| Zeile 23: | Zeile 25: | ||
<pre>#!/bin/sh | <pre>#!/bin/sh | ||
... | ... | ||
/usr/local/sbin/pvusb -b | /usr/local/sbin/pvusb -b | ||
... | ... | ||
</pre> | </pre> | ||
| Zeile 30: | Zeile 32: | ||
<pre> | <pre> | ||
m450:~# pvusb -h | m450:~# pvusb -h | ||
usage: pvusb -b [-t] | -i | - | usage: pvusb -b [-t] | -i | -a | ||
pvusb -d <device_id> -s <domain> [-c comment] -w [ -t ] | |||
pvusb -u <usb-port> -s <domain> [-c comment] -w [ -t ] | |||
pvusb -l | -r | |||
pvusb -x <usb-port>:<domain>:0:<vport> | |||
------------ | ------------ | ||
-b # boot/initialise PVUSB with | -a # activate PVUSB for <domain> without any rules | ||
-i # initialize PVUSB without | -b # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE) | ||
-s domain | -i # initialize PVUSB without hotplug rules ($CONFIG_FILE) | ||
-u usb-port | -s <domain> # server domain_name or domain_id | ||
-d device_id | -u <usb-port> # USB-PORT e.g. '3-2' | ||
-c comment | -d <device_id># USB device_id e.g. '0912:1234' (use 'lsusb' to get the ID) | ||
-c <comment> # e.g. "Canon IP4000 Printer" | |||
-l # list grabbed PVUSB Devices | -l # list grabbed PVUSB Devices | ||
-r # read PVUSB rules | -r # read PVUSB hotplug rules | ||
-w # write/activate PVUSB rule | -w # write/activate PVUSB hotplug rule | ||
-x # delete PVUSB rule | -x # delete PVUSB hotplug rule | ||
-t # try to trigger | -t # try to trigger all domains (per ssh) to init PVUSB | ||
-q # be quiet | -q # be quiet | ||
-D # Debug option (set -x) | |||
m450:~# pvusb -l | m450:~# pvusb -l | ||
Version vom 30. August 2009, 21:05 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).
Die USB DeviceIDs (z.B. '04a9:1093') kann man mit dem Komamndo lsusb ermitteln. Die USB-Ports (z.B. '3-2') werden beim Anstecken der Devices auf der Systemkonsole (Dom0) angezeigt.
File /etc/xen/pvusb.conf
# Configfile for pvusb # Dev_Id <domain> <Comment> # USBPort <domain> <Comment> # 0000:0000 <domain> <Comment> 04a9:1093 srv Canon Printer IP4000 5-1 dmz Anything on USB Port 5-1 0000:0000 vm01 initialize 'vm01' for PVUSB
File /etc/rc.local
Für die Option -t ("Trigger Domain") muss SSH Access per SSH-Keys funktionieren, da mit ssh <domain> <Befehle> versucht wird, Remote-Kommandos innerhalb der Domain auszuführen.
#!/bin/sh ... /usr/local/sbin/pvusb -b ...
Beispiele für pvusb
m450:~# pvusb -h
usage: pvusb -b [-t] | -i | -a
pvusb -d <device_id> -s <domain> [-c comment] -w [ -t ]
pvusb -u <usb-port> -s <domain> [-c comment] -w [ -t ]
pvusb -l | -r
pvusb -x <usb-port>:<domain>:0:<vport>
------------
-a # activate PVUSB for <domain> without any rules
-b # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE)
-i # initialize PVUSB without hotplug rules ($CONFIG_FILE)
-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' (use 'lsusb' to get the ID)
-c <comment> # e.g. "Canon IP4000 Printer"
-l # list grabbed PVUSB Devices
-r # read PVUSB hotplug rules
-w # write/activate PVUSB hotplug rule
-x # delete PVUSB hotplug rule
-t # try to trigger all domains (per ssh) to init PVUSB
-q # be quiet
-D # Debug option (set -x)
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
Das Skript /usr/local/sbin/pvusb
#!/bin/sh
#
# paravirtualized USB Support
#
# Version: $Revision: 1.14 $
# Datum: $Date: 2009/08/26 17:15:17 $
#
# Author: neobiker
#
# $Log: pvusb,v $
# Revision 1.14 2009/08/26 17:15:17 root
# updated usage () and some info's
#
# Revision 1.13 2009/08/26 07:12:35 root
# bugfix: get_free_vusb_port ()
# check if xenstore is initialized
#
# Revision 1.12 2009/08/25 20:05:43 root
# some optimization and error handling
#
# Revision 1.11 2009/08/24 19:01:36 root
# rename _trigger_backend () to _connect_backend ()
#
# Revision 1.10 2009/08/24 18:52:53 root
# bugfix: lsusb test fixed, ohci_hcd added
#
# Revision 1.9 2009/08/23 23:50:35 root
# bugfix with domain not started
#
# Revision 1.8 2009/08/23 23:14:05 root
# use -t to trigger domain needed
#
# Revision 1.7 2009/08/23 21:41:27 root
# optimzed trigger_backend
#
# Revision 1.6 2009/08/23 21:01:21 root
# read USB-Ports from $CONFIG
#
# 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 2>/dev/null | grep -v '0000:0000' || echo "Error")
if [ "$LSUSB" = "Error" ]; then
echo "Error: Missing command 'lsusb', please install usbutils"
exit 1
fi
set -e
usage ()
{
cat <<-EOT
usage: $(basename $0) -b [-t] | -i | -a
$(basename $0) -d <device_id> -s <domain> [-c comment] -w [ -t ]
$(basename $0) -u <usb-port> -s <domain> [-c comment] -w [ -t ]
$(basename $0) -l | -r
$(basename $0) -x <usb-port>:<domain>:0:<vport>
------------
-a # activate PVUSB for <domain> without any rules
-b # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE)
-i # initialize PVUSB without hotplug rules ($CONFIG_FILE)
-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' (use 'lsusb' to get the ID)
-c <comment> # e.g. "Canon IP4000 Printer"
-l # list grabbed PVUSB Devices
-r # read PVUSB hotplug rules
-w # write/activate PVUSB hotplug rule
-x # delete PVUSB hotplug rule
-t # try to trigger all domains (per ssh) to init PVUSB
-q # be quiet
-D # Debug option (set -x)
EOT
}
init ()
{
NUM_PORTS=8 # Max 16 PVUSB ports.
VUSB_BUS=0 # virtual USB Bus in <domain> (we use always usb bus 0)
CONFIG_FILE=/etc/xen/pvusb.conf
[ -e $CONFIG_FILE ] || cat >$CONFIG_FILE <<-EOT
# Configfile for pvusb
# 'pvusb -b' connects <Device_Id> / <USB-Port> to <Domain>
# 'pvusb -i' initializes <Domain> for PVUSB
# <Device_Id> <Domain> <Comment>
# 1234:5678 server USB-Printer on an USB-Port
# <USB-Port> <Domain> <Comment>
# 3-2 server Any Device on Port 3-2
# <Device_Id> <Domain> <Comment>
# 0000:0000 server initialize 'server' for PVUSB
EOT
CONFIG=$(cat $CONFIG_FILE | sed -e 's/#.*$//' -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e '/^$/ d' -e '/^[[:graph:]]*$/ d')
}
#
# 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)
# check if xenstore is already initialized
[ -e /sys/devices/xen-backend/vusb-$dom_id-$vusb_bus ] && return
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
# load usb (backend) modules
modprobe usbbk
}
pvusb_connect_backend ()
{
# connect USB devices to backend (and restart udevd afterwards)
# stop udevd fetching events before the backend driver
udevadm control --stop_exec_queue
# XXX: find better way to connect USB devices dynamically!!!
rmmod uhci_hcd ehci_hcd ohci_hcd 2>/dev/null || true
modprobe -a uhci_hcd ehci_hcd ohci_hcd || true
# 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
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
# get the next free USB Port in <domain>
vusb_port=$(get_free_vusb_port $dom_id)
# 1) initialise paravirtualized USB Support for dom_id
pvusb_init_xenstore $dom_id $VUSB_BUS
# 2a) 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
# 2b) 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_free_vusb_port ()
{
dom_id=$1
# get new vusb_port between 2 .. $NUM_PORTS
vports=$(cat /sys/bus/usb/drivers/usbback/vports | awk -v FS=: "/^.*:$dom_id:.*:.*/ {print \$4}")
if [ -z "$vports" ]; then
echo "2"
return
else
for ((i=2; $i<=$NUM_PORTS; i++)); do
for vport in $vports; do
[ "$vport" -eq $i ] && break
done
[ $vport -ne $i ] && { echo "$i"; return; }
done
fi
echo "Error: no virtual USB-Port free for $dom_id" >&2
exit 1
}
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 || true); do
adr=$(cat /sys/bus/usb/devices/$port/devnum)
if [ "$adr" = "$usb_adr" ]; then
echo "$port"
return
fi
done
echo "Error: no USB-Port found for $usb_dev" >2
}
pvusb_init_domains_from_configfile ()
{
domains=$(echo "$CONFIG" | awk '/^0000:0000 / {print $2}')
for domain in $domains; do
dom_id=$(xm domid $domain || continue)
[ -n "$dom_id" ] || continue
pvusb_init_xenstore $dom_id $VUSB_BUS
# remember domain to be triggered
PVUSB_DOMAINS=$(cat <<-EOT | sort -u
$PVUSB_DOMAINS
$domain)
done
}
pvusb_write_defined_ports_from_configfile ()
{
# $CONFIG: where to connect the USB-Ports
# ---------------------------------------
ports=$(echo "$CONFIG" | awk '/^[0-9]-[0-9] / {print $1}')
for usb_port in $ports; do
# read static definitions from $CONFIG
pvusb_conf=$(echo "$CONFIG" | grep $usb_port | tail -1)
if [ -n "$pvusb_conf" ]; then
domain=$(echo $pvusb_conf | awk '{print $2}')
comment=$(echo $pvusb_conf | cut -d\ -f3-)
[ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
else
continue
fi
# 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_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
# 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 connected USB Devices found."
return
fi
# 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 $usb_devices; do
# where to connect my usb devices to?
# read static definitions from $CONFIG
pvusb_conf=$(echo "$CONFIG" | grep $usb_dev | tail -1)
if [ -n "$pvusb_conf" ]; then
domain=$(echo $pvusb_conf | awk '{print $2}')
comment=$(echo $pvusb_conf | cut -d\ -f3-)
# skip if <domain> isn't activ
[ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
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 || true); do
adr=$(cat /sys/bus/usb/devices/$port/devnum)
if [ "$adr" = "$usb_adr" ]; then
usb_port=$port
break
fi
done
if [ -z "$usb_port" ]; then
echo "Error: No USB Port found for $usb_dev"
continue
fi
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_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 || true ;
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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
done
}
# ------------------------
# Script starts here
# ------------------------
init
while getopts ":abc:d:Dhilqrs:tu:wx:" opt; do
case $opt in
a) # activate PVUSB for <domain> without any rules
#pvusb_init_backend
dom_id=$(xm domid $domain)
pvusb_init_xenstore $dom_id $VUSB_BUS
#pvusb_connect_backend
;;
b) # boot host with setup rules in $CONFIG
pvusb_init_backend
pvusb_init_domains_from_configfile
pvusb_write_connected_devices_from_configfile
pvusb_write_defined_ports_from_configfile
pvusb_connect_backend
;;
i) # initialise PVUSB without any rules
pvusb_init_backend
pvusb_init_domains_from_configfile
pvusb_connect_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_connect_backend
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