Skip to content

Instantly share code, notes, and snippets.

@gpoole
Last active November 1, 2025 00:19
Show Gist options
  • Select an option

  • Save gpoole/c89807e9de9cb5c87bbcc2da27e0c3e4 to your computer and use it in GitHub Desktop.

Select an option

Save gpoole/c89807e9de9cb5c87bbcc2da27e0c3e4 to your computer and use it in GitHub Desktop.

Revisions

  1. gpoole revised this gist Jan 16, 2024. 3 changed files with 32 additions and 3 deletions.
    6 changes: 5 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -2,12 +2,14 @@

    A set of command line tools and a service to make setting up passthrough USB devices easier:

    - `add-custom-usb-policies` - script to store and apply custom USB policies required for specific devices
    - `attach-usb-devices` - script and service to automatically connect USB devices to VMS when XCP-ng boots up
    - `plug-usb` - attach a physical USB device to a VM in one command
    - `unplug-usb` - remove a physical USB device from a VM in one command

    To set up, copy the files onto your server and run `install.sh` to copy everything and set up the service.
    You can add any `plug-usb` commands you want to run on boot by modifying `/usr/bin/attach-usb-devices`.
    You can add any custom USB policies you need applied on install or after updates by modifying `add-custom-usb-policies` _before_ running `install.sh`.

    You can also use `plug-usb` directly if you want to attach a new device on demand:

    @@ -22,4 +24,6 @@ If you want to unplug a device later, you can use `unplug-usb`:
    unplug-usb <vusb-uuid>
    ```

    You can list all physical USB devices available and get their UUIDs with `xe pusb-list`.
    You can list all physical USB devices available and get their UUIDs with `xe pusb-list`.

    If you customise `add-custom-usb-policies`, you can run it again after upgrades to ensure your custom policies are applied again.
    23 changes: 23 additions & 0 deletions add-custom-usb-policies
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    #!/bin/bash

    # find information about which device you want to add a policy for with:
    # lsusb
    # Bus 001 Device 049: ID 1cf1:0030 Dresden Elektronik
    # =>
    # ALLOW:vid=1cf1 pid=0030 # Dresden Elektronik

    # add the following policies to usb-policy.conf if they don't already exist
    USB_POLICY_DRESDEN="ALLOW:vid=1cf1 pid=0030 # Dresden Elektronik"
    USB_POLICY_BLUETOOTH="ALLOW:vid=0b05 pid=190e # Asus USB-BT500"

    POLICY_FILE="/etc/xensource/usb-policy.conf"

    for POLICY in "${USB_POLICY_DRESDEN}" "${USB_POLICY_BLUETOOTH}"; do
    # -q be quiet
    # -x match the whole line
    # -F pattern is a plain string
    grep -xqF -- "$POLICY" "$POLICY_FILE" || sed -i "1s/^/${POLICY}\n/" "$POLICY_FILE"
    done

    # NOTE: assumes you only have one host...
    xe pusb-scan host-uuid=$(xe host-list --minimal)
    6 changes: 4 additions & 2 deletions install.sh
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,11 @@
    #/bin/bash

    cp attach-usb-devices plug-usb unplug-usb /usr/bin
    chmod +x /usr/bin/attach-usb-devices /usr/bin/plug-usb /usr/bin/unplug-usb
    cp attach-usb-devices plug-usb unplug-usb add-custom-usb-policies /usr/bin
    chmod +x /usr/bin/attach-usb-devices /usr/bin/plug-usb /usr/bin/unplug-usb /usr/bin/add-custom-usb-policies

    cp attach-usb-devices.service /etc/systemd/system
    systemctl enable attach-usb-devices

    add-custom-usb-policies

    # You can try running systemctl start attach-usb-devices but it'll fail to attach any VMs that are already running.
  2. gpoole revised this gist Oct 28, 2023. 3 changed files with 8 additions and 18 deletions.
    8 changes: 2 additions & 6 deletions attach-usb-devices
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,14 @@
    #!/bin/bash

    function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    function get-vm-uuid-by-name() {
    vm_name="$1"
    xe vm-list name-label="$vm_name" | get-uuid
    xe vm-list name-label="$vm_name" --minimal
    }

    function get-usb-uuid-by() {
    key="$1"
    value="$2"
    xe pusb-list $key="$value" | get-uuid
    xe pusb-list $key="$value" --minimal
    }

    # Below list all the connections you want made automatically on boot
    6 changes: 1 addition & 5 deletions plug-usb
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,5 @@
    #!/bin/bash

    function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    pusb_uuid="$1"
    vm_uuid="$2"

    @@ -22,7 +18,7 @@ fi


    echo -n "Attaching $pusb_name ($pusb_uuid) to $vm_name ($vm_uuid)..."
    group_uuid=`xe usb-group-list PUSB-uuids="$pusb_uuid" | get-uuid`
    group_uuid=`xe usb-group-list PUSB-uuids="$pusb_uuid" --minimal`
    xe pusb-param-set uuid="$pusb_uuid" passthrough-enabled=true
    if [ -z "`xe vusb-list vm-uuid="$vm_uuid" usb-group-uuid="$group_uuid"`" ]; then
    xe vusb-create usb-group-uuid="$group_uuid" vm-uuid="$vm_uuid" > /dev/null
    12 changes: 5 additions & 7 deletions unplug-usb
    Original file line number Diff line number Diff line change
    @@ -7,18 +7,14 @@ if [ -z "$pusb_uuid" ]; then
    exit 1
    fi

    function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    group_uuid=`xe usb-group-list PUSB-uuids="$pusb_uuid" | get-uuid`
    group_uuid=`xe usb-group-list PUSB-uuids="$pusb_uuid" --minimal`

    if [ -z "$group_uuid" ]; then
    echo "Could not find USB group."
    exit 1
    fi

    vusb_uuid=`xe vusb-list usb-group-uuid="$group_uuid" | get-uuid`
    vusb_uuid=`xe vusb-list usb-group-uuid="$group_uuid" --minimal`

    if [ -z "$vusb_uuid" ]; then
    echo "Failed to find virtual USB."
    @@ -31,4 +27,6 @@ if ! [ -z "`xe vm-list uuid="$vm_uuid" power-state=running`" ]; then
    xe vusb-unplug uuid="$vusb_uuid"
    fi

    xe vusb-destroy uuid="$vusb_uuid"
    xe vusb-destroy uuid="$vusb_uuid"

    xe pusb-param-set uuid="$pusb_uuid" passthrough-enabled=false
  3. gpoole revised this gist Aug 5, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -22,4 +22,4 @@ If you want to unplug a device later, you can use `unplug-usb`:
    unplug-usb <vusb-uuid>
    ```

    You can list all physical USB devices available and get their UUIDs with `xe vusb-list`.
    You can list all physical USB devices available and get their UUIDs with `xe pusb-list`.
  4. gpoole revised this gist Jul 11, 2022. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion attach-usb-devices
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,6 @@ function get-vm-uuid-by-name() {
    xe vm-list name-label="$vm_name" | get-uuid
    }


    function get-usb-uuid-by() {
    key="$1"
    value="$2"
  5. gpoole revised this gist Jul 11, 2022. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    # XCP-ng USB passthrough tools

    A set of command line tools and a service to make setting up passthrough USB devices easier:

    - `attach-usb-devices` - script and service to automatically connect USB devices to VMS when XCP-ng boots up
    - `plug-usb` - attach a physical USB device to a VM in one command
    - `unplug-usb` - remove a physical USB device from a VM in one command

    To set up, copy the files onto your server and run `install.sh` to copy everything and set up the service.
    You can add any `plug-usb` commands you want to run on boot by modifying `/usr/bin/attach-usb-devices`.

    You can also use `plug-usb` directly if you want to attach a new device on demand:

    ```sh
    # You can use xe vusb-list and xe vm-list to figure out the IDs you need
    plug-usb <vusb-uuid> <vm-uuid>
    ```

    If you want to unplug a device later, you can use `unplug-usb`:

    ```sh
    unplug-usb <vusb-uuid>
    ```

    You can list all physical USB devices available and get their UUIDs with `xe vusb-list`.
  6. gpoole revised this gist Jul 11, 2022. 4 changed files with 80 additions and 33 deletions.
    39 changes: 8 additions & 31 deletions attach-usb-devices
    Original file line number Diff line number Diff line change
    @@ -4,44 +4,21 @@ function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    function attach-usb-device() {
    uuid="$1"
    vm_name="$2"

    if ! [ -z "`xe vm-list name-label="$vm_name" power-state=running`" ]; then
    echo "$vm_name must be stopped first."
    return 1
    fi

    echo -n "Attaching $1 to $2..."
    group_uuid=`xe usb-group-list PUSB-uuids="$uuid" | get-uuid`
    vm_uuid=`xe vm-list name-label="$vm_name" | get-uuid`
    xe pusb-param-set uuid="$uuid" passthrough-enabled=true
    if [ -z "`xe vusb-list vm-uuid="$vm_uuid" usb-group-uuid="$group_uuid"`" ]; then
    xe vusb-create usb-group-uuid="$group_uuid" vm-uuid="$vm_uuid" > /dev/null
    if [ $? -eq 0 ]; then
    echo "Attached"
    else
    echo "Failed."
    fi
    else
    echo "Already attached."
    fi
    function get-vm-uuid-by-name() {
    vm_name="$1"
    xe vm-list name-label="$vm_name" | get-uuid
    }


    function get-usb-uuid-by() {
    key="$1"
    value="$2"
    xe pusb-list $key="$value" | get-uuid
    }

    # Below just add attach-usb-device commands for all the devices you want to attach
    # when you run this script.
    # You can figure out which devices you have available with:
    # xe pusb-list
    # Below list all the connections you want made automatically on boot

    # Device 1
    attach-usb-device "`get-usb-uuid-by product-desc "Some brand name"`" "VM 1"
    # The name here ("Example Disk Name") is the pusb product-desc,
    # which you can find with: xe pusb-list params=uuid,product-desc

    # Device 2
    attach-usb-device "`get-usb-uuid-by description "Some device name"`" "VM 2"
    plug-usb "`get-usb-uuid-by product-desc "Example Disk Name"`" "`get-vm-uuid-by-name "Some VM Name"`"
    4 changes: 2 additions & 2 deletions install.sh
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    #/bin/bash

    cp attach-usb-devices /usr/bin
    chmod +x /usr/bin/attach-usb-devices
    cp attach-usb-devices plug-usb unplug-usb /usr/bin
    chmod +x /usr/bin/attach-usb-devices /usr/bin/plug-usb /usr/bin/unplug-usb

    cp attach-usb-devices.service /etc/systemd/system
    systemctl enable attach-usb-devices
    36 changes: 36 additions & 0 deletions plug-usb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    #!/bin/bash

    function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    pusb_uuid="$1"
    vm_uuid="$2"

    if [ -z "$pusb_uuid" ] || [ -z "$vm_uuid" ]; then
    echo "Usage: plug-usb <pusb-device-uuid> <vm-uuid>"
    exit 1
    fi

    vm_name=`xe vm-list uuid="$vm_uuid" | grep name-label | sed -E 's/^.*: //g'`
    pusb_name=`xe pusb-list uuid="$pusb_uuid" | grep product-desc | sed -E 's/^.*: //g'`

    if ! [ -z "`xe vm-list uuid="$vm_uuid" power-state=running`" ]; then
    echo "VM $vm_name must be stopped first."
    exit 1
    fi


    echo -n "Attaching $pusb_name ($pusb_uuid) to $vm_name ($vm_uuid)..."
    group_uuid=`xe usb-group-list PUSB-uuids="$pusb_uuid" | get-uuid`
    xe pusb-param-set uuid="$pusb_uuid" passthrough-enabled=true
    if [ -z "`xe vusb-list vm-uuid="$vm_uuid" usb-group-uuid="$group_uuid"`" ]; then
    xe vusb-create usb-group-uuid="$group_uuid" vm-uuid="$vm_uuid" > /dev/null
    if [ $? -eq 0 ]; then
    echo "Attached"
    else
    echo "Failed."
    fi
    else
    echo "Already attached."
    fi
    34 changes: 34 additions & 0 deletions unplug-usb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    #!/bin/bash

    pusb_uuid="$1"

    if [ -z "$pusb_uuid" ]; then
    echo "Usage: usb-unplug <pusb-uuid>"
    exit 1
    fi

    function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    group_uuid=`xe usb-group-list PUSB-uuids="$pusb_uuid" | get-uuid`

    if [ -z "$group_uuid" ]; then
    echo "Could not find USB group."
    exit 1
    fi

    vusb_uuid=`xe vusb-list usb-group-uuid="$group_uuid" | get-uuid`

    if [ -z "$vusb_uuid" ]; then
    echo "Failed to find virtual USB."
    exit 1
    fi

    # Unplug from running VM
    vm_uuid=`xe vusb-list usb-group-uuid="$group_uuid" | grep vm-uuid | sed -E 's/^.*: //g'`
    if ! [ -z "`xe vm-list uuid="$vm_uuid" power-state=running`" ]; then
    xe vusb-unplug uuid="$vusb_uuid"
    fi

    xe vusb-destroy uuid="$vusb_uuid"
  7. gpoole revised this gist May 30, 2022. No changes.
  8. gpoole revised this gist May 30, 2022. 3 changed files with 23 additions and 0 deletions.
    File renamed without changes.
    14 changes: 14 additions & 0 deletions attach-usb-devices.service
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    [Unit]
    Description=Automatically attach USB devices on startup
    Wants=xapi-init-complete.target
    # Runs BEFORE xapi-domains.service which is when VMS are autostarted
    Before=xapi-domains.service
    After=remote-fs.target xapi-init-complete.target xapi.service

    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/usr/bin/attach-usb-devices

    [Install]
    WantedBy=multi-user.target
    9 changes: 9 additions & 0 deletions install.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    #/bin/bash

    cp attach-usb-devices /usr/bin
    chmod +x /usr/bin/attach-usb-devices

    cp attach-usb-devices.service /etc/systemd/system
    systemctl enable attach-usb-devices

    # You can try running systemctl start attach-usb-devices but it'll fail to attach any VMs that are already running.
  9. gpoole revised this gist May 6, 2022. No changes.
  10. gpoole revised this gist May 6, 2022. 1 changed file with 17 additions and 5 deletions.
    22 changes: 17 additions & 5 deletions attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ function get-uuid() {
    }

    function attach-usb-device() {
    dev_name="$1"
    uuid="$1"
    vm_name="$2"

    if ! [ -z "`xe vm-list name-label="$vm_name" power-state=running`" ]; then
    @@ -14,7 +14,6 @@ function attach-usb-device() {
    fi

    echo -n "Attaching $1 to $2..."
    uuid=`xe pusb-list product-desc="$dev_name" | get-uuid`
    group_uuid=`xe usb-group-list PUSB-uuids="$uuid" | get-uuid`
    vm_uuid=`xe vm-list name-label="$vm_name" | get-uuid`
    xe pusb-param-set uuid="$uuid" passthrough-enabled=true
    @@ -30,6 +29,19 @@ function attach-usb-device() {
    fi
    }

    # The name here ("Example Disk Name") is the pusb product-desc,
    # which you can find with: xe pusb-list params=uuid,product-desc
    attach-usb-device "Example Disk Name" "VM Name"
    function get-usb-uuid-by() {
    key="$1"
    value="$2"
    xe pusb-list $key="$value" | get-uuid
    }

    # Below just add attach-usb-device commands for all the devices you want to attach
    # when you run this script.
    # You can figure out which devices you have available with:
    # xe pusb-list

    # Device 1
    attach-usb-device "`get-usb-uuid-by product-desc "Some brand name"`" "VM 1"

    # Device 2
    attach-usb-device "`get-usb-uuid-by description "Some device name"`" "VM 2"
  11. gpoole revised this gist Apr 20, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ function attach-usb-device() {
    dev_name="$1"
    vm_name="$2"

    if ! [ -z `xe vm-list name-label="$vm_name" power-state=running` ]; then
    if ! [ -z "`xe vm-list name-label="$vm_name" power-state=running`" ]; then
    echo "$vm_name must be stopped first."
    return 1
    fi
  12. gpoole revised this gist Apr 10, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ function attach-usb-device() {
    dev_name="$1"
    vm_name="$2"

    if ! [ `xe vm-list name-label="$vm_name" power-state=running` ]; then
    if ! [ -z `xe vm-list name-label="$vm_name" power-state=running` ]; then
    echo "$vm_name must be stopped first."
    return 1
    fi
  13. gpoole revised this gist Apr 10, 2022. 1 changed file with 7 additions and 8 deletions.
    15 changes: 7 additions & 8 deletions attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,12 @@ function get-uuid() {
    function attach-usb-device() {
    dev_name="$1"
    vm_name="$2"

    if ! [ `xe vm-list name-label="$vm_name" power-state=running` ]; then
    echo "$vm_name must be stopped first."
    return 1
    fi

    echo -n "Attaching $1 to $2..."
    uuid=`xe pusb-list product-desc="$dev_name" | get-uuid`
    group_uuid=`xe usb-group-list PUSB-uuids="$uuid" | get-uuid`
    @@ -24,13 +30,6 @@ function attach-usb-device() {
    fi
    }

    vm_name="VM Name"

    if ! [ `xe vm-list name-label="$vm_name" power-state=running` ]; then
    echo "$vm_name must be stopped first."
    exit 1
    fi

    # The name here ("Example Disk Name") is the pusb product-desc,
    # which you can find with: xe pusb-list params=uuid,product-desc
    attach-usb-device "Example Disk Name" "$vm_name"
    attach-usb-device "Example Disk Name" "VM Name"
  14. gpoole revised this gist Nov 11, 2020. 1 changed file with 9 additions and 3 deletions.
    12 changes: 9 additions & 3 deletions attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,6 @@ function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    # Based on https://xcp-ng.org/docs/compute.html#usb-passthrough
    function attach-usb-device() {
    dev_name="$1"
    vm_name="$2"
    @@ -15,7 +14,7 @@ function attach-usb-device() {
    xe pusb-param-set uuid="$uuid" passthrough-enabled=true
    if [ -z "`xe vusb-list vm-uuid="$vm_uuid" usb-group-uuid="$group_uuid"`" ]; then
    xe vusb-create usb-group-uuid="$group_uuid" vm-uuid="$vm_uuid" > /dev/null
    if $?; then
    if [ $? -eq 0 ]; then
    echo "Attached"
    else
    echo "Failed."
    @@ -25,6 +24,13 @@ function attach-usb-device() {
    fi
    }

    vm_name="VM Name"

    if ! [ `xe vm-list name-label="$vm_name" power-state=running` ]; then
    echo "$vm_name must be stopped first."
    exit 1
    fi

    # The name here ("Example Disk Name") is the pusb product-desc,
    # which you can find with: xe pusb-list params=uuid,product-desc
    attach-usb-device "Example Disk Name" "VM Name"
    attach-usb-device "Example Disk Name" "$vm_name"
  15. gpoole revised this gist Jul 3, 2020. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@ function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    # Based on https://xcp-ng.org/docs/compute.html#usb-passthrough
    function attach-usb-device() {
    dev_name="$1"
    vm_name="$2"
  16. gpoole revised this gist Jul 3, 2020. No changes.
  17. gpoole created this gist Jul 3, 2020.
    29 changes: 29 additions & 0 deletions attach-usb-drives.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    #!/bin/bash

    function get-uuid() {
    grep ^uuid | sed -E 's/^.*: //g'
    }

    function attach-usb-device() {
    dev_name="$1"
    vm_name="$2"
    echo -n "Attaching $1 to $2..."
    uuid=`xe pusb-list product-desc="$dev_name" | get-uuid`
    group_uuid=`xe usb-group-list PUSB-uuids="$uuid" | get-uuid`
    vm_uuid=`xe vm-list name-label="$vm_name" | get-uuid`
    xe pusb-param-set uuid="$uuid" passthrough-enabled=true
    if [ -z "`xe vusb-list vm-uuid="$vm_uuid" usb-group-uuid="$group_uuid"`" ]; then
    xe vusb-create usb-group-uuid="$group_uuid" vm-uuid="$vm_uuid" > /dev/null
    if $?; then
    echo "Attached"
    else
    echo "Failed."
    fi
    else
    echo "Already attached."
    fi
    }

    # The name here ("Example Disk Name") is the pusb product-desc,
    # which you can find with: xe pusb-list params=uuid,product-desc
    attach-usb-device "Example Disk Name" "VM Name"