From: Dominik Csapak <d.csapak@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH common 3/3] add PVE/HardwareMap and Plugins
Date: Mon, 21 Jun 2021 15:55:17 +0200 [thread overview]
Message-ID: <20210621135534.14807-5-d.csapak@proxmox.com> (raw)
In-Reply-To: <20210621135534.14807-1-d.csapak@proxmox.com>
adds the Top level package PVE::HardwareMap that
registers the Plugins for the config, as well
as provides some convenience methods
(find_device_on_current_node, lock/write/get config)
The Plugins themselves are usual SectionConfigs plugins
with (for now) two types: usb, pci
each type gets an 'assert_device_valid' method that
checks the local node for validity of the device
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/Makefile | 4 ++
src/PVE/HardwareMap.pm | 54 ++++++++++++++++++++
src/PVE/HardwareMap/PCIPlugin.pm | 87 ++++++++++++++++++++++++++++++++
src/PVE/HardwareMap/Plugin.pm | 82 ++++++++++++++++++++++++++++++
src/PVE/HardwareMap/USBPlugin.pm | 69 +++++++++++++++++++++++++
5 files changed, 296 insertions(+)
create mode 100644 src/PVE/HardwareMap.pm
create mode 100644 src/PVE/HardwareMap/PCIPlugin.pm
create mode 100644 src/PVE/HardwareMap/Plugin.pm
create mode 100644 src/PVE/HardwareMap/USBPlugin.pm
diff --git a/src/Makefile b/src/Makefile
index 13de6c6..7cd20d5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -17,6 +17,10 @@ LIB_SOURCES = \
Daemon.pm \
Exception.pm \
Format.pm \
+ HardwareMap.pm \
+ HardwareMap/Plugin.pm \
+ HardwareMap/PCIPlugin.pm \
+ HardwareMap/USBPlugin.pm \
INotify.pm \
JSONSchema.pm \
LDAP.pm \
diff --git a/src/PVE/HardwareMap.pm b/src/PVE/HardwareMap.pm
new file mode 100644
index 0000000..a0f4a9f
--- /dev/null
+++ b/src/PVE/HardwareMap.pm
@@ -0,0 +1,54 @@
+package PVE::HardwareMap;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::HardwareMap::Plugin;
+use PVE::HardwareMap::PCIPlugin;
+use PVE::HardwareMap::USBPlugin;
+use PVE::INotify;
+
+use base qw(Exporter);
+
+our @EXPORT_OK = qw(find_device_on_current_node);
+
+PVE::HardwareMap::PCIPlugin->register();
+PVE::HardwareMap::USBPlugin->register();
+
+PVE::HardwareMap::Plugin->init();
+
+sub find_device_on_current_node {
+ my ($type, $id) = @_;
+
+ my $data = cfs_read_file($PVE::HardwareMap::Plugin::FILENAME);
+
+ my $res = {};
+
+ my $node = PVE::INotify::nodename();
+ my $sectionid = "$node:$id";
+
+ return $data->{ids}->{$sectionid};
+}
+
+sub config {
+ return cfs_read_file($PVE::HardwareMap::Plugin::FILENAME);
+}
+
+sub lock_config {
+ my ($code, $errmsg) = @_;
+
+ cfs_lock_file($PVE::HardwareMap::Plugin::FILENAME, undef, $code);
+ if (my $err = $@) {
+ $errmsg ? die "$errmsg: $err" : die $err;
+ }
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file($PVE::HardwareMap::Plugin::FILENAME, $cfg);
+}
+
+
+1;
diff --git a/src/PVE/HardwareMap/PCIPlugin.pm b/src/PVE/HardwareMap/PCIPlugin.pm
new file mode 100644
index 0000000..eb6d090
--- /dev/null
+++ b/src/PVE/HardwareMap/PCIPlugin.pm
@@ -0,0 +1,87 @@
+package PVE::HardwareMap::PCIPlugin;
+
+use strict;
+use warnings;
+
+use PVE::HardwareMap::Plugin;
+use PVE::SysFSTools;
+
+use base qw(PVE::HardwareMap::Plugin);
+
+sub type {
+ return 'pci';
+}
+
+sub properties {
+ return {
+ pcipath => {
+ description => "The path to the device. If the function is omitted, the whole device is mapped. In that case use the attrubes of the first device.",
+ type => 'string',
+ pattern => qr/^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}(:?.[0-9A-Fa-f])?$/,
+ },
+ mdev => {
+ description => "The Device supports mediated devices.",
+ type => 'boolean',
+ },
+ iommugroup => {
+ type => 'integer',
+ description => "The IOMMU group in which the device is in.",
+ }
+ };
+}
+
+sub options {
+ return {
+ node => { fixed => 1 },
+ name => { fixed => 1 },
+ pcipath => { },
+ vendor => { },
+ device => { },
+ iommugroup => { },
+ subsystem_vendor => { optional => 1 },
+ subsystem_device => { optional => 1 },
+ mdev => { optional => 1 },
+ };
+}
+
+sub assert_device_valid {
+ my ($class, $cfg) = @_;
+
+ my $path = $cfg->{pcipath};
+
+ if ($path !~ m/\.[a-f0-9]/i) {
+ # whole device, add .0 (must exist)
+ $path = "$path.0";
+ }
+
+ my $info = PVE::SysFSTools::pci_device_info($path, 1);
+ die "pci device '$path' not found\n" if !defined($info);
+
+ my $props = {
+ vendor => $cfg->{vendor},
+ device => $cfg->{device},
+ subsystem_vendor => $cfg->{subsystem_vendor},
+ subsystem_device => $cfg->{subsystem_device},
+ iommugroup => $cfg->{iommugroup},
+ mdev => $cfg->{mdev},
+ };
+
+ for my $prop (keys %$props) {
+ next if !defined($info->{$prop});
+ die "no '$prop' for device '$path'\n"
+ if defined($info->{$prop}) && !$props->{$prop};
+
+
+ my $correct_prop = $info->{$prop};
+ $correct_prop =~ s/^0x//;
+ my $configured_prop = $props->{$prop};
+ $configured_prop =~ s/^0x//;
+
+ die "'$prop' does not match for '$cfg->{name}' ($correct_prop != $configured_prop)\n"
+ if $correct_prop ne $configured_prop;
+ }
+
+ return 1;
+}
+
+1;
diff --git a/src/PVE/HardwareMap/Plugin.pm b/src/PVE/HardwareMap/Plugin.pm
new file mode 100644
index 0000000..2d33785
--- /dev/null
+++ b/src/PVE/HardwareMap/Plugin.pm
@@ -0,0 +1,82 @@
+package PVE::HardwareMap::Plugin;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(cfs_register_file cfs_read_file);
+use PVE::JSONSchema qw(get_standard_option);
+
+use base qw(PVE::SectionConfig);
+
+our $FILENAME = "nodes/hardware-map.conf";
+cfs_register_file($FILENAME,
+ sub { PVE::HardwareMap::Plugin->parse_config(@_); },
+ sub { PVE::HardwareMap::Plugin->write_config(@_); });
+
+my $defaultData = {
+ propertyList => {
+ type => { description => "Hardware Type", },
+ name => {
+ description => "The custom name for the device",
+ type => 'string',
+ format => 'pve-configid',
+ },
+ node => get_standard_option('pve-node'),
+ vendor => {
+ description => "The vendor ID",
+ type => 'string',
+ pattern => qr/^(:?0x)?[0-9A-Fa-f]{4}$/,
+ },
+ device => {
+ description => "The device ID",
+ type => 'string',
+ pattern => qr/^(:?0x)?[0-9A-Fa-f]{4}$/,
+ },
+ subsystem_vendor => {
+ description => "The subsystem vendor ID",
+ type => 'string',
+ pattern => qr/^(:?0x)?[0-9A-Fa-f]{4}$/,
+ optional => 1,
+ },
+ subsystem_device => {
+ description => "The subsystem device ID",
+ type => 'string',
+ pattern => qr/^(:?0x)?[0-9A-Fa-f]{4}$/,
+ optional => 1,
+ },
+ },
+};
+
+sub private {
+ return $defaultData;
+}
+
+sub parse_section_header {
+ my ($class, $line) = @_;
+
+ if ($line =~ m/^(\S+):\s*(\S+):(\S+)\s*$/) {
+ my ($type, $node, $name) = ($1, $2, $3);
+ # TODO verify properties
+ my $errmsg = undef;
+ my $config = {
+ node => $node,
+ name => $name,
+ };
+ return ($type, "$node:$name", $errmsg, $config);
+ }
+ return undef;
+}
+
+sub format_section_header {
+ my ($class, $type, $sectionId, $scfg, $done_hash) = @_;
+ $done_hash->{name} = 1;
+ $done_hash->{node} = 1;
+ return $class->SUPER::format_section_header($type, $sectionId, $scfg, $done_hash);
+}
+
+sub assert_device_valid {
+ my ($cfg) = @_;
+ die "implement me";
+}
+
+1;
diff --git a/src/PVE/HardwareMap/USBPlugin.pm b/src/PVE/HardwareMap/USBPlugin.pm
new file mode 100644
index 0000000..a1fff77
--- /dev/null
+++ b/src/PVE/HardwareMap/USBPlugin.pm
@@ -0,0 +1,69 @@
+package PVE::HardwareMap::USBPlugin;
+
+use strict;
+use warnings;
+
+use PVE::HardwareMap::Plugin;
+
+use base qw(PVE::HardwareMap::Plugin);
+
+sub type {
+ return 'usb';
+}
+
+sub properties {
+ return {
+ usbpath => {
+ description => "The path to the usb device.",
+ type => 'string',
+ pattern => qr/^(\d+)\-(\d+(\.\d+)*)$/,
+ },
+ };
+}
+
+sub options {
+ return {
+ node => { fixed => 1 },
+ name => { fixed => 1 },
+ vendor => { },
+ device => { },
+ usbpath => { optional => 1 },
+ };
+}
+
+sub assert_device_valid {
+ my ($class, $cfg) = @_;
+
+ my $name = $cfg->{name};
+ my $vendor = $cfg->{vendor};
+ my $device = $cfg->{device};
+
+ my $usb_list = PVE::SysFSTools::scan_usb();
+
+ my $info;
+ if (my $path = $cfg->{usbpath}) {
+ for my $dev (@$usb_list) {
+ next if !$dev->{usbpath} || !$dev->{busnum};
+ my $usbpath = "$dev->{busnum}-$dev->{usbpath}";
+ next if $usbpath ne $path;
+ $info = $dev;
+ }
+ die "usb device '$path' not found\n" if !defined($info);
+
+ die "'vendor' does not match for '$name'\n"
+ if $info->{vendid} ne $cfg->{vendor};
+ die "'device' does not match for '$name'\n"
+ if $info->{prodid} ne $cfg->{device};
+ } else {
+ for my $dev (@$usb_list) {
+ next if $dev->{vendid} ne $vendor;
+ next if $dev->{prodid} ne $device;
+ $info = $dev;
+ }
+ die "usb device '$vendor:$device' not found\n" if !defined($info);
+ }
+
+ return 1;
+}
+
+1;
--
2.20.1
next prev parent reply other threads:[~2021-06-21 13:56 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-21 13:55 [pve-devel] [PATCH/RFC cluster/common/... many] add cluster-wide hardware device mapping Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH cluster 1/1] add nodes/hardware-map.conf Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH common 1/3] SysFSTools: add verbose flag to pci_device_info Dominik Csapak
2021-06-21 15:31 ` [pve-devel] applied: " Thomas Lamprecht
2021-06-21 13:55 ` [pve-devel] [PATCH common 2/3] SysFSTools: change 'product' to 'device' Dominik Csapak
2021-06-21 15:31 ` [pve-devel] applied: " Thomas Lamprecht
2021-06-21 13:55 ` Dominik Csapak [this message]
2021-06-21 13:55 ` [pve-devel] [PATCH access-control 1/2] PVE/AccessControl: add Hardware.* privileges and /hardware/ paths Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH access-control 2/2] PVE/RPCEnvironment: add helper for checking hw permissions Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 1/7] PVE/QemuServer: allow mapped usb devices in config Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 2/7] PVE/QemuServer: allow mapped pci deviced " Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 3/7] PVE/API2/Qemu: add permission checks for mapped usb devices Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 4/7] PVE/API2/Qemu: add permission checks for mapped pci devices Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 5/7] PVE/QemuServer: extend 'check_local_resources' for mapped resources Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 6/7] PVE/API2/Qemu: migrate preconditions: use new check_local_resources info Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH qemu-server 7/7] PVE/QemuMigrate: check for mapped resources on migration Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 1/8] PVE/API2/Hardware: add Mapping.pm Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 2/8] ui: form/USBSelector: make it more flexible with nodename Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 3/8] ui: form: add PCIMapSelector Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 4/8] ui: form: add USBMapSelector Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 5/8] ui: node: add HardwareView and relevant edit windows Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 6/8] ui: qemu/PCIEdit: rework panel to add a mapped configuration Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 7/8] ui: qemu/USBEdit: add 'mapped' device case Dominik Csapak
2021-06-21 13:55 ` [pve-devel] [PATCH manager 8/8] ui: window/Migrate: allow mapped devices Dominik Csapak
2021-06-22 7:07 ` [pve-devel] [PATCH/RFC cluster/common/... many] add cluster-wide hardware device mapping Dominik Csapak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210621135534.14807-5-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox