]> git.proxmox.com Git - qemu-server.git/blame - test/run_pci_addr_checks.pl
bump version to 8.2.1
[qemu-server.git] / test / run_pci_addr_checks.pl
CommitLineData
d7d698f6
TL
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5use experimental 'smartmatch';
6
7use lib qw(..);
8
9use Test::More;
10
d3815507 11use PVE::Tools qw(file_get_contents);
d7d698f6
TL
12use PVE::QemuServer::PCI;
13
30680751
TL
14my $qemu_cfg_base_path = "../qemu-configs";
15
d3815507
TL
16# not our format but that what QEMU gets passed with '-readconfig'
17sub slurp_qemu_config {
18 my ($fn) = @_;
19
20 my $raw = file_get_contents($fn);
21
22 my $lineno = 0;
23 my $cfg = {};
24 my $group;
25 my $skip_to_next_group;
26 while ($raw =~ /^\h*(.*?)\h*$/gm) {
27 my $line = $1;
28 $lineno++;
29 next if !$line || $line =~ /^#/;
30
31 # tried to follow qemu's qemu_config_parse function
32 if ($line =~ /\[(\S{1,63}) "([^"\]]{1,63})"\]/) {
33 $group = $2;
34 $skip_to_next_group = 0;
35 if ($1 ne 'device') {
36 $group = undef;
37 $skip_to_next_group = 1;
38 }
39 } elsif ($line =~ /\[([^\]]{1,63})\]/) {
40 $group = undef;
41 $skip_to_next_group = 1;
42 } elsif ($group) {
43 if ($line =~ /(\S{1,63}) = "([^\"]{1,1023})"/) {
44 my ($k, $v) = ($1, $2);
45 $cfg->{$group}->{$k} = $v;
46 } else {
47 print "ignoring $fn:$lineno: $line\n";
48 }
49 } else {
50 warn "ignore $fn:$lineno, currently no group\n" if !$skip_to_next_group;
51 }
52 }
53
6cb7b041
TL
54 return $cfg;
55}
56
57sub extract_qemu_config_addrs {
58 my ($qemu_cfg) = @_;
59
60 my $addr_map = {};
61 for my $k (keys %$qemu_cfg) {
62 my $v = $qemu_cfg->{$k};
63 next if !$v || !defined($v->{bus}) || !defined($v->{addr});
64
65 my $bus = $v->{bus};
66 $bus =~ s/pci\.//;
67
68 $addr_map->{$k} = { bus => $bus, addr => $v->{addr} };
69 }
70
71 return $addr_map;
d3815507 72}
d3815507 73
d7d698f6
TL
74print "testing PCI(e) address conflicts\n";
75
76# exec tests
77
78#FIXME: make cross PCI <-> PCIe check sense at all??
79my $addr_map = {};
80my ($fail, $ignored) = (0, 0);
81sub check_conflict {
6cb7b041 82 my ($id, $what, $ignore_if_same_key) = @_;
d7d698f6
TL
83
84 my ($bus, $addr) = $what->@{qw(bus addr)};
85 my $full_addr = "$bus:$addr";
86
87 if (defined(my $conflict = $addr_map->{$full_addr})) {
88 if (my @ignores = $what->{conflict_ok}) {
89 if ($conflict ~~ @ignores) {
90 note("OK: ignore conflict for '$full_addr' between '$id' and '$conflict'");
91 $ignored++;
92 return;
93 }
94 }
6cb7b041
TL
95 # this allows to read multiple pve-*.cfg qemu configs, and check them
96 # normally their OK if they conflict is on the same key. Else TODO??
97 return if $ignore_if_same_key && $id eq $conflict;
98
d7d698f6
TL
99 note("ERR: conflict for '$full_addr' between '$id' and '$conflict'");
100 $fail++;
101 } else {
102 $addr_map->{$full_addr} = $id;
103 }
104}
105
106
107my $pci_map = PVE::QemuServer::PCI::get_pci_addr_map();
108while (my ($id, $what) = each %$pci_map) {
109 check_conflict($id, $what);
110}
111
112my $pcie_map = PVE::QemuServer::PCI::get_pcie_addr_map();
113while (my ($id, $what) = each %$pcie_map) {
114 check_conflict($id, $what);
115}
116
30680751 117my $pve_qm_cfg = slurp_qemu_config("$qemu_cfg_base_path/pve-q35.cfg");
6cb7b041
TL
118my $pve_qm_cfg_map = extract_qemu_config_addrs($pve_qm_cfg);
119while (my ($id, $what) = each %$pve_qm_cfg_map) {
120 check_conflict($id, $what);
121}
122
123# FIXME: restart with clean conflict $addr_map with only get_pci*_addr_map ones?
30680751 124my $pve_qm4_cfg = slurp_qemu_config("$qemu_cfg_base_path/pve-q35-4.0.cfg");
6cb7b041
TL
125my $pve_qm4_cfg_map = extract_qemu_config_addrs($pve_qm4_cfg);
126while (my ($id, $what) = each %$pve_qm4_cfg_map) {
127 check_conflict($id, $what, 1);
128}
30680751 129my $pve_qm_usb_cfg = slurp_qemu_config("$qemu_cfg_base_path/pve-usb.cfg");
6cb7b041
TL
130my $pve_qm_usb_cfg_map = extract_qemu_config_addrs($pve_qm_usb_cfg);
131while (my ($id, $what) = each %$pve_qm_usb_cfg_map) {
132 check_conflict($id, $what, 1);
133}
134
135
d7d698f6
TL
136if ($fail) {
137 fail("PCI(e) address conflict check, ignored: $ignored, conflicts: $fail");
138} else {
139 pass("PCI(e) address conflict check, ignored: $ignored");
140}
141
142done_testing();