diff --git a/README.md b/README.md index 6de6538..a19944f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ can help a lot :-) - [CDROMs](#cdroms) - [Input](#input) - [PCI device passthrough](#pci-device-passthrough) +- [USB Redirector Devices](#usb-redirector-devices) - [Random number generator passthrough](#random-number-generator-passthrough) - [CPU Features](#cpu-features) - [No box and PXE boot](#no-box-and-pxe-boot) @@ -744,6 +745,58 @@ Note! Above options affect configuration only at domain creation. It won't chang Don't forget to [set](#domain-specific-options) `kvm_hidden` option to `true` especially if you are passthroughing NVIDIA GPUs. Otherwise GPU is visible from VM but cannot be operated. +## USB Redirector Devices +You can specify multiple redirect devices via `libvirt.redirdev`. There are two types, `tcp` and `spicevmc` supported, for forwarding USB-devices to the guest. Available options are listed below. + +* `type` - The type of the USB redirector device. (`tcp` or `spicevmc`) +* `host` - The host where the device is attached to. (mandatory for type `tcp`) +* `port` - The port where the device is listening. (mandatory for type `tcp`) + +```ruby +Vagrant.configure("2") do |config| + config.vm.provider :libvirt do |libvirt| + # add two devices using spicevmc channel + (1..2).each do + libvirt.redirdev :type => "spicevmc" + end + # add device, provided by localhost:4000 + libvirt.redirdev :type => "tcp", :host => "localhost", :port => "4000" + end +end +``` + +### Filter for USB Redirector Devices +You can define filter for redirected devices. These filters can be positiv or negative, by setting the mandatory option `allow=yes` or `allow=no`. All available options are listed below. Note the option `allow` is mandatory. + +* `class` - The device class of the USB device. A list of device classes is available on [Wikipedia](https://en.wikipedia.org/wiki/USB#Device_classes). +* `vendor` - The vendor of the USB device. +* `product` - The product id of the USB device. +* `version` - The version of the USB device. Note that this is the version of `bcdDevice` +* `allow` - allow or disallow redirecting this device. (mandatory) + +You can extract that information from output of `lsusb` command. Every line contains the information in format `Bus [] Device []: ID [:[]`. The `version` can be extracted from the detailed output of the device using `lsusb -D /dev/usb/[]/[]`. For example: + +```shell +# get bcdDevice from +$: lsusb +Bus 001 Device 009: ID 08e6:3437 Gemalto (was Gemplus) GemPC Twin SmartCard Reader + +$: lsusb -D /dev/bus/usb/001/009 | grep bcdDevice + bcdDevice 2.00 +``` + +In this case, the USB device with `class 0x0b`, `vendor 0x08e6`, `product 0x3437` and `bcdDevice version 2.00` is allowed to be redirected to the guest. All other devices will be refused. + +```ruby +Vagrant.configure("2") do |config| + config.vm.provider :libvirt do |libvirt| + libvirt.redirdev :type => "spicevmc" + libvirt.redirfilter :class => "0x0b" :vendor => "0x08e6" :product => "0x3437" :version => "2.00" :allow => "yes" + libvirt.redirfilter :allow => "no" + end +end +``` + ## Random number generator passthrough You can pass through `/dev/random` to your VM by configuring the domain like this: diff --git a/lib/vagrant-libvirt/action/create_domain.rb b/lib/vagrant-libvirt/action/create_domain.rb index 0cbb3b1..8873220 100644 --- a/lib/vagrant-libvirt/action/create_domain.rb +++ b/lib/vagrant-libvirt/action/create_domain.rb @@ -88,6 +88,10 @@ module VagrantPlugins # USB device passthrough @usbs = config.usbs + + # Redirected devices + @redirdevs = config.redirdevs + @redirfilters = config.redirfilters # RNG device passthrough @rng =config.rng @@ -235,6 +239,28 @@ module VagrantPlugins env[:ui].info(" -- USB passthrough: #{usb_dev.join(', ')}") end + if not @redirdevs.empty? + env[:ui].info(" -- Redirected Devices: ") + @redirdevs.each do |redirdev| + msg = " -> bus=usb, type=#{redirdev[:type]}" + env[:ui].info(msg) + end + end + + + if not @redirfilters.empty? + env[:ui].info(" -- USB Device filter for Redirected Devices: ") + @redirfilters.each do |redirfilter| + msg = " -> class=#{redirfilter[:class]}, " + msg += "vendor=#{redirfilter[:vendor]}, " + msg += "product=#{redirfilter[:product]}, " + msg += "version=#{redirfilter[:version]}, " + msg += "allow=#{redirfilter[:allow]}" + env[:ui].info(msg) + end + end + + env[:ui].info(" -- Command line : #{@cmd_line}") # Create libvirt domain. diff --git a/lib/vagrant-libvirt/config.rb b/lib/vagrant-libvirt/config.rb index ad7a5cf..df6f640 100644 --- a/lib/vagrant-libvirt/config.rb +++ b/lib/vagrant-libvirt/config.rb @@ -117,6 +117,10 @@ module VagrantPlugins # USB device passthrough attr_accessor :usbs + # Redirected devices + attr_accessor :redirdevs + attr_accessor :redirfilters + # Suspend mode attr_accessor :suspend_mode @@ -197,6 +201,10 @@ module VagrantPlugins # USB device passthrough @usbs = UNSET_VALUE + + # Redirected devices + @redirdevs = UNSET_VALUE + @redirfilters = UNSET_VALUE # Suspend mode @suspend_mode = UNSET_VALUE @@ -369,6 +377,38 @@ module VagrantPlugins }) end + def redirdev(options={}) + if options[:type].nil? + raise 'Type must be specified.' + end + + if @redirdevs == UNSET_VALUE + @redirdevs = [] + end + + @redirdevs.push({ + type: options[:type], + }) + end + + def redirfilter(options={}) + if options[:allow].nil? + raise 'Option allow must be specified.' + end + + if @redirfilters == UNSET_VALUE + @redirfilters = [] + end + + @redirfilters.push({ + class: options[:class] || -1, + vendor: options[:class] || -1, + product: options[:class] || -1, + version: options[:class] || -1, + allow: options[:allow], + }) + end + # NOTE: this will run twice for each time it's needed- keep it idempotent def storage(storage_type, options={}) if storage_type == :file @@ -562,6 +602,10 @@ module VagrantPlugins # USB device passthrough @usbs = [] if @usbs == UNSET_VALUE + + # Redirected devices + @redirdevs = [] if @redirdevs == UNSET_VALUE + @redirfilters = [] if @redirfilters == UNSET_VALUE # Suspend mode @suspend_mode = "pause" if @suspend_mode == UNSET_VALUE diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb index 9c53a1f..1e3e416 100644 --- a/lib/vagrant-libvirt/templates/domain.xml.erb +++ b/lib/vagrant-libvirt/templates/domain.xml.erb @@ -170,6 +170,19 @@ <% end %> + <% unless @redirdevs.empty? %> + <% @redirdevs.each do |redirdev| %> + + + <% end %> + <% unless @redirfilters.empty? %> + + <% @redirfilters.each do |usbdev| %> + + <% end %> + + <% end %> + <% end %> <% if @tpm_path -%> <%# TPM Device -%>