WIP Progress updates.

This commit is contained in:
SimonFair
2025-11-09 08:58:50 +00:00
parent 4c86497ab4
commit 1266a3dfe4
7 changed files with 475 additions and 264 deletions
+114 -14
View File
@@ -25,22 +25,15 @@ $(function(){
function applyCfg() {
var message = "_(System Devices)_: _(A reboot is required to apply changes)_";
var string = "BIND=";
var vfstring = "BIND=";
var elements = document.getElementById("vfiopci").elements;
for (var i = 0, element; element = elements[i++];) {
if (element.type === "checkbox" && element.checked === true && element.className.substring(0, 5) === "iommu")
string = string + element.value + " ";
if (element.type === "checkbox" && element.checked === true && element.className.substring(0, 7) === "vfiommu")
vfstring = vfstring + element.value + " ";
}
string = string.trim();
if (string === "BIND=") {
string = "";
}
vfstring = vfstring.trim();
if (vfstring === "BIND=") {
vfstring = "";
}
$.post( "/plugins/dynamix/include/update.vfio-pci-cfg.php", { cfg: string } )
.done(function(d) {
if (d==1) {
@@ -54,24 +47,24 @@ function applyCfg() {
});
}
function saveVFSettingsConfig(pciId,vd) {
function saveVFSettingsConfig(pciId,vd,interactive=1) {
var message = "_(System Devices)_: _(A reboot is required to apply changes)_";
var mac = document.getElementById("vfmac" + pciId).value;
var vfio = document.getElementById("vfio" + pciId).value;
var vfio = document.getElementById("vfvfio" + pciId).checked;
$.post( "/plugins/dynamix/include/update.sriov-cfg.php", { type:"sriovmac", pciid: pciId, vd:vd, vfio:vfio, mac:mac } )
$.post( "/plugins/dynamix/include/update.sriov-cfg.php", { type:"sriovsettings", pciid: pciId, vd:vd, vfio:vfio, mac:mac } )
.done(function(d) {
if (d==1) {
addRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(ALERT)_: _(Changes saved)_. _(Reboot to take effect)_.</b>";
swal("MACs Saved", "success");
if (interactive == 1) swal("MACs Saved","", "success");
} else {
removeRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(No changes)_.</b>";
}
});
}
function saveVFsConfig(pciId,vd) {
function saveVFsConfig(pciId,vd,interactive=1) {
var message = "_(System Devices)_: _(A reboot is required to apply changes)_";
var numvfs = document.getElementById("vf" + pciId).value;
@@ -80,13 +73,14 @@ function saveVFsConfig(pciId,vd) {
if (d==1) {
addRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(ALERT)_: _(Changes saved)_. _(Reboot to take effect)_.</b>";
swal("VFs Saved ","success");
docum
if (interactive == 1) swal("VFs Saved ","","success");
} else {
removeRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(No changes)_.</b>";
}
$('#t1').load('/webGui/include/SysDevs.php', { table: 't1' });
});
}
function generateMAC(pciId) {
@@ -148,6 +142,112 @@ function generateMAC(pciId) {
});
}
function applyVFSettings(pciId,vd) {
saveVFSettingsConfig(pciId,vd,0);
var message = "_(System Devices)_: _(A reboot is required to apply changes)_";
var mac = document.getElementById("vfmac" + pciId).value;
var vfio = document.getElementById("vfvfio" + pciId).checked;
$.post( "/plugins/dynamix/include/apply.sriov-cfg.php", { type:"sriovsettings", pciid: pciId, vd:vd, vfio:vfio, mac:mac } )
.done(function(d) {
if (d==1) {
addRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(ALERT)_: _(Changes saved)_. _(Reboot to take effect)_.</b>";
swal("VFs Saved ","","success");
} else {
removeRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(No changes)_.</b>";
}
});
}
function applyVFsConfig(pciId, vd, vfs) {
saveVFsConfig(pciId,vd,0);
var message = "_(System Devices)_: _(A reboot is required to apply changes)_";
var numvfs = document.getElementById("vf" + pciId).value;
// Case 1: VFs will be removed
if (vfs != 0 && numvfs == 0) {
swal({
title: "VFs will be removed",
text: "Card will reset.",
type: "warning",
showCancelButton: false,
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
closeOnConfirm: true
}, function() {
doApply(pciId, vd, numvfs, message);
});
return;
}
// Case 2: Number of VFs changed
if (vfs != numvfs && numvfs != 0) {
swal({
title: "Number of VFs changed",
text: "Will need to remove and re-add VFs.",
type: "warning",
showCancelButton: false,
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
closeOnConfirm: true
}, function() {
doApply(pciId, vd, numvfs, message);
});
}
}
function doApply(pciId, vd, numvfs, message) {
// Show "updating" alert immediately
swal({
title: "Updating...",
text: "Please wait while configuration is applied.",
type: "info",
showConfirmButton: false,
allowOutsideClick: false
});
// Perform the POST
$.post("/plugins/dynamix/include/apply.sriov-cfg.php", {
type: "sriov",
pciid: pciId,
vd: vd,
numvfs: numvfs
})
.done(function (d) {
// Update UI based on server response
if (d == 1) {
addRebootNotice(message);
document.getElementById("warning").innerHTML =
"<b>_(ALERT)_: _(Changes saved)_. _(Reboot to take effect)_.</b>";
} else {
removeRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(No changes)_.</b>";
}
// Replace the "updating" alert with "done"
swal({
title: "Update Complete",
text: "Configuration successfully applied.",
type: "success",
timer: 3000, // show for 3 seconds
showConfirmButton: false // hide OK button
});
// Reload table
$('#t1').load('/webGui/include/SysDevs.php', { table: 't1' });
})
.fail(function () {
swal({
title: "Error",
text: "Failed to apply configuration.",
type: "error",
showConfirmButton: true
});
});
}
function formatFullInput(input) {
return input
@@ -0,0 +1,254 @@
<?PHP
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
#$allowedPCIClass = ['0x02','0x03'];
$allowedPCIClass = ['0x02'];
/**
* Enumerate SR-IOV capable PCI devices (keyed by PCI address).
*
* Example JSON:
* {
* "0000:03:00.0": {
* "class": "Ethernet controller",
* "class_id": "0x0200",
* "name": "Intel Corporation X710 for 10GbE SFP+",
* "driver": "i40e",
* "module": "i40e",
* "vf_param": "max_vfs",
* "total_vfs": 64,
* "num_vfs": 8,
* "vfs": [
* {"pci": "0000:03:10.0", "iface": "enp3s0f0v0", "mac": "52:54:00:aa:00:01"}
* ]
* }
* }
*/
function getSriovInfoJson(bool $includeVfDetails = true): string {
$results = [];
$paths = glob('/sys/bus/pci/devices/*/sriov_totalvfs') ?: [];
foreach ($paths as $totalvfFile) {
$devdir = dirname($totalvfFile);
$pci = basename($devdir);
$total_vfs = (int) @file_get_contents($totalvfFile);
$num_vfs = (int) @file_get_contents("$devdir/sriov_numvfs");
// Driver/module detection
$driver = $module = $vf_param = null;
$driver_link = "$devdir/driver";
if (is_link($driver_link)) {
$driver = basename(readlink($driver_link));
$module_link = "$driver_link/module";
$module = is_link($module_link) ? basename(readlink($module_link)) : $driver;
$vf_param = detectVfParam($driver);
}
// Device class + numeric class + name
[$class, $class_id, $name] = getPciClassNameAndId($pci);
// Virtual functions
$vfs = [];
foreach (glob("$devdir/virtfn*") as $vf) {
if (!is_link($vf)) continue;
$vf_pci = basename(readlink($vf));
$vf_entry = ['pci' => $vf_pci];
if ($includeVfDetails) {
// Network interface info
$net = glob("/sys/bus/pci/devices/{$vf_pci}/net/*");
if ($net && isset($net[0])) {
$iface = basename($net[0]);
$vf_entry['iface'] = $iface;
$macFile = "/sys/class/net/{$iface}/address";
if (is_readable($macFile)) {
$vf_entry['mac'] = trim(file_get_contents($macFile));
}
}
// IOMMU group
$iommu_link = "/sys/bus/pci/devices/{$vf_pci}/iommu_group";
if (is_link($iommu_link)) {
$vf_entry['iommu_group'] = basename(readlink($iommu_link));
} else {
$vf_entry['iommu_group'] = null;
}
// --- Current driver ---
$driver_link = "/sys/bus/pci/devices/{$vf_pci}/driver";
if (is_link($driver_link)) {
$vf_entry['driver'] = basename(readlink($driver_link));
} else {
$vf_entry['driver'] = null; // no driver bound
}
}
$vfs[] = $vf_entry;
}
$results[$pci] = [
'class' => $class,
'class_id' => $class_id,
'name' => $name,
'driver' => $driver,
'module' => $module,
'vf_param' => $vf_param,
'total_vfs' => $total_vfs,
'num_vfs' => $num_vfs,
'vfs' => $vfs
];
}
ksort($results, SORT_NATURAL);
return json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
function detectVfParam(string $driver): ?string {
if (!function_exists('shell_exec')) return null;
$out = @shell_exec('modinfo ' . escapeshellarg($driver) . ' 2>/dev/null');
if (!$out) return null;
$lines = explode("\n", strtolower($out));
$params = [];
foreach ($lines as $line) {
if (preg_match('/^parm:\s+(\S+)/', $line, $m)) $params[] = $m[1];
}
foreach (['max_vfs', 'num_vfs', 'sriov_numvfs', 'sriov_vfs'] as $key)
if (in_array($key, $params, true)) return $key;
foreach ($params as $p)
if (preg_match('/vf/', $p)) return $p;
return null;
}
/**
* Robustly get PCI class (text + numeric ID) and device name from lspci/sysfs.
*/
function getPciClassNameAndId(string $pci): array {
$class = 'Unknown';
$class_id = null;
$name = 'Unknown';
// Numeric class code from sysfs
$classFile = "/sys/bus/pci/devices/{$pci}/class";
if (is_readable($classFile)) {
$raw = trim(file_get_contents($classFile));
$class_id = sprintf("0x%04x", (hexdec($raw) >> 8) & 0xFFFF);
}
// Try lspci -mm for machine-readable info
$out = trim(@shell_exec('lspci -mm -s ' . escapeshellarg($pci) . ' 2>/dev/null'));
if ($out && preg_match('/"([^"]+)"\s+"([^"]+)"\s+"([^"]+)"/', $out, $m)) {
$class = $m[1];
$name = trim($m[3]);
return [$class, $class_id, $name];
}
// Fallback to regular lspci output
$alt = trim(@shell_exec('lspci -s ' . escapeshellarg($pci) . ' 2>/dev/null'));
if ($alt && preg_match('/^[\da-fA-F:.]+\s+([^:]+):\s+(.+)/', $alt, $m)) {
$class = trim($m[1]);
$name = trim($m[2]);
}
return [$class, $class_id, $name];
}
/**
* Enumerate all VFs and group them by IOMMU group
* Output: associative array or JSON with keys like "IOMMU group 29"
*/
function getVfListByIommuGroup(): array {
$groups = [];
foreach (glob('/sys/bus/pci/devices/*/physfn') as $vf_physfn) {
$vf_dir = dirname($vf_physfn);
$vf_pci = basename($vf_dir);
$iommu_link = "$vf_dir/iommu_group";
if (is_link($iommu_link)) {
$iommu_group = basename(readlink($iommu_link));
} else {
$iommu_group = "unknown";
}
$groups[] = "IOMMU group " . $iommu_group;
$groups[] = $vf_pci;
}
ksort($groups, SORT_NATURAL);
return $groups;
}
// ----------------------
// Parse SR-IOV VF counts
// ----------------------
function parseVFvalues() {
$sriov_devices = [];
$DBDF_SRIOV_REGEX = '/^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]\|[[:xdigit:]]{4}:[[:xdigit:]]{4}\|[[:digit:]]+$/';
if (is_file("/boot/config/sriov.cfg")) {
$file = trim(file_get_contents("/boot/config/sriov.cfg"));
$file = preg_replace('/^VFS=/', '', $file); // Remove prefix
$entries = preg_split('/\s+/', $file, -1, PREG_SPLIT_NO_EMPTY);
foreach ($entries as $entry) {
if (preg_match($DBDF_SRIOV_REGEX, $entry)) {
// Format: <DBDF>|<Vendor:Device>|<VF_count>
[$dbdf, $ven_dev, $vf_count] = explode('|', $entry);
$sriov_devices[$dbdf] = [
'dbdf' => $dbdf,
'vendor' => $ven_dev,
'vf_count' => (int)$vf_count,
];
}
}
# $sriov_devices = array_values(array_unique($sriov_devices, SORT_REGULAR));
return $sriov_devices;
}
}
// ---------------------------------
// Parse SR-IOV VF settings (VFIO+MAC)
// ---------------------------------
function parseVFSettings() {
$sriov_devices_settings = [];
$DBDF_SRIOV_SETTINGS_REGEX = '/^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]\|[[:xdigit:]]{4}:[[:xdigit:]]{4}\|[01]\|([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}$/';
if (is_file("/boot/config/sriovvfs.cfg")) {
$file = trim(file_get_contents("/boot/config/sriovvfs.cfg"));
$file = preg_replace('/^VFSETTINGS=/', '', $file); // Remove prefix
$entries = preg_split('/\s+/', $file, -1, PREG_SPLIT_NO_EMPTY);
foreach ($entries as $entry) {
if (preg_match($DBDF_SRIOV_SETTINGS_REGEX, $entry)) {
// Format: <DBDF>|<Vendor:Device>|<VFIO_flag>|<MAC>
[$dbdf, $ven_dev, $vfio_flag, $mac] = explode('|', $entry);
$sriov_devices_settings[$dbdf] = [
'dbdf' => $dbdf,
'vendor' => $ven_dev,
'vfio' => (int)$vfio_flag,
'mac' => strtoupper($mac),
];
}
}
# $sriov_devices_settings = array_values(array_unique($sriov_devices_settings, SORT_REGULAR));
return $sriov_devices_settings;
}
}
?>
+11 -242
View File
@@ -1,6 +1,7 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -13,6 +14,7 @@
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/SriovHelpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'tools';
@@ -37,189 +39,11 @@ function usb_physical_port($usbbusdev) {
return($physical_busid);
}
/**
* Enumerate SR-IOV capable PCI devices (keyed by PCI address).
*
* Example JSON:
* {
* "0000:03:00.0": {
* "class": "Ethernet controller",
* "class_id": "0x0200",
* "name": "Intel Corporation X710 for 10GbE SFP+",
* "driver": "i40e",
* "module": "i40e",
* "vf_param": "max_vfs",
* "total_vfs": 64,
* "num_vfs": 8,
* "vfs": [
* {"pci": "0000:03:10.0", "iface": "enp3s0f0v0", "mac": "52:54:00:aa:00:01"}
* ]
* }
* }
*/
function getSriovInfoJson(bool $includeVfDetails = true): string {
$results = [];
$paths = glob('/sys/bus/pci/devices/*/sriov_totalvfs') ?: [];
foreach ($paths as $totalvfFile) {
$devdir = dirname($totalvfFile);
$pci = basename($devdir);
$total_vfs = (int) @file_get_contents($totalvfFile);
$num_vfs = (int) @file_get_contents("$devdir/sriov_numvfs");
// Driver/module detection
$driver = $module = $vf_param = null;
$driver_link = "$devdir/driver";
if (is_link($driver_link)) {
$driver = basename(readlink($driver_link));
$module_link = "$driver_link/module";
$module = is_link($module_link) ? basename(readlink($module_link)) : $driver;
$vf_param = detectVfParam($driver);
}
// Device class + numeric class + name
[$class, $class_id, $name] = getPciClassNameAndId($pci);
// Virtual functions
$vfs = [];
foreach (glob("$devdir/virtfn*") as $vf) {
if (!is_link($vf)) continue;
$vf_pci = basename(readlink($vf));
$vf_entry = ['pci' => $vf_pci];
if ($includeVfDetails) {
// Network interface info
$net = glob("/sys/bus/pci/devices/{$vf_pci}/net/*");
if ($net && isset($net[0])) {
$iface = basename($net[0]);
$vf_entry['iface'] = $iface;
$macFile = "/sys/class/net/{$iface}/address";
if (is_readable($macFile)) {
$vf_entry['mac'] = trim(file_get_contents($macFile));
}
}
// IOMMU group
$iommu_link = "/sys/bus/pci/devices/{$vf_pci}/iommu_group";
if (is_link($iommu_link)) {
$vf_entry['iommu_group'] = basename(readlink($iommu_link));
} else {
$vf_entry['iommu_group'] = null;
}
// --- Current driver ---
$driver_link = "/sys/bus/pci/devices/{$vf_pci}/driver";
if (is_link($driver_link)) {
$vf_entry['driver'] = basename(readlink($driver_link));
} else {
$vf_entry['driver'] = null; // no driver bound
}
}
$vfs[] = $vf_entry;
}
$results[$pci] = [
'class' => $class,
'class_id' => $class_id,
'name' => $name,
'driver' => $driver,
'module' => $module,
'vf_param' => $vf_param,
'total_vfs' => $total_vfs,
'num_vfs' => $num_vfs,
'vfs' => $vfs
];
}
ksort($results, SORT_NATURAL);
return json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
function detectVfParam(string $driver): ?string {
if (!function_exists('shell_exec')) return null;
$out = @shell_exec('modinfo ' . escapeshellarg($driver) . ' 2>/dev/null');
if (!$out) return null;
$lines = explode("\n", strtolower($out));
$params = [];
foreach ($lines as $line) {
if (preg_match('/^parm:\s+(\S+)/', $line, $m)) $params[] = $m[1];
}
foreach (['max_vfs', 'num_vfs', 'sriov_numvfs', 'sriov_vfs'] as $key)
if (in_array($key, $params, true)) return $key;
foreach ($params as $p)
if (preg_match('/vf/', $p)) return $p;
return null;
}
/**
* Robustly get PCI class (text + numeric ID) and device name from lspci/sysfs.
*/
function getPciClassNameAndId(string $pci): array {
$class = 'Unknown';
$class_id = null;
$name = 'Unknown';
// Numeric class code from sysfs
$classFile = "/sys/bus/pci/devices/{$pci}/class";
if (is_readable($classFile)) {
$raw = trim(file_get_contents($classFile));
$class_id = sprintf("0x%04x", (hexdec($raw) >> 8) & 0xFFFF);
}
// Try lspci -mm for machine-readable info
$out = trim(@shell_exec('lspci -mm -s ' . escapeshellarg($pci) . ' 2>/dev/null'));
if ($out && preg_match('/"([^"]+)"\s+"([^"]+)"\s+"([^"]+)"/', $out, $m)) {
$class = $m[1];
$name = trim($m[3]);
return [$class, $class_id, $name];
}
// Fallback to regular lspci output
$alt = trim(@shell_exec('lspci -s ' . escapeshellarg($pci) . ' 2>/dev/null'));
if ($alt && preg_match('/^[\da-fA-F:.]+\s+([^:]+):\s+(.+)/', $alt, $m)) {
$class = trim($m[1]);
$name = trim($m[2]);
}
return [$class, $class_id, $name];
}
/* --- CLI Entry --- */
$sriov = json_decode(getSriovInfoJson(true),true);
/**
* Enumerate all VFs and group them by IOMMU group
* Output: associative array or JSON with keys like "IOMMU group 29"
*/
function getVfListByIommuGroup(): array {
$groups = [];
foreach (glob('/sys/bus/pci/devices/*/physfn') as $vf_physfn) {
$vf_dir = dirname($vf_physfn);
$vf_pci = basename($vf_dir);
$iommu_link = "$vf_dir/iommu_group";
if (is_link($iommu_link)) {
$iommu_group = basename(readlink($iommu_link));
} else {
$iommu_group = "unknown";
}
$groups[] = "IOMMU group " . $iommu_group;
$groups[] = $vf_pci;
}
ksort($groups, SORT_NATURAL);
return $groups;
}
$sriov = json_decode(getSriovInfoJson(true),true);
$sriovvfs = getVfListByIommuGroup();
$sriov_devices=parseVFvalues();
$sriov_devices_settings=parseVFSettings();
switch ($_POST['table']) {
@@ -258,60 +82,6 @@ case 't1':
$vfio_cfg_devices = array_values(array_unique($vfio_cfg_devices, SORT_STRING));
}
$DBDF_SRIOV_REGEX = '/^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]\|[[:xdigit:]]{4}:[[:xdigit:]]{4}\|[[:digit:]]+$/';
$DBDF_SRIOV_SETTINGS_REGEX = '/^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]\|[[:xdigit:]]{4}:[[:xdigit:]]{4}\|[01]\|([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}$/';
// ----------------------
// Parse SR-IOV VF counts
// ----------------------
$sriov_devices = [];
if (is_file("/boot/config/sriov.cfg")) {
$file = trim(file_get_contents("/boot/config/sriov.cfg"));
$file = preg_replace('/^VFS=/', '', $file); // Remove prefix
$entries = preg_split('/\s+/', $file, -1, PREG_SPLIT_NO_EMPTY);
foreach ($entries as $entry) {
if (preg_match($DBDF_SRIOV_REGEX, $entry)) {
// Format: <DBDF>|<Vendor:Device>|<VF_count>
[$dbdf, $ven_dev, $vf_count] = explode('|', $entry);
$sriov_devices[$dbdf] = [
'dbdf' => $dbdf,
'vendor' => $ven_dev,
'vf_count' => (int)$vf_count,
];
}
}
# $sriov_devices = array_values(array_unique($sriov_devices, SORT_REGULAR));
}
// ---------------------------------
// Parse SR-IOV VF settings (VFIO+MAC)
// ---------------------------------
$sriov_devices_settings = [];
if (is_file("/boot/config/sriovvfs.cfg")) {
$file = trim(file_get_contents("/boot/config/sriovvfs.cfg"));
$file = preg_replace('/^VFSETTINGS=/', '', $file); // Remove prefix
$entries = preg_split('/\s+/', $file, -1, PREG_SPLIT_NO_EMPTY);
foreach ($entries as $entry) {
if (preg_match($DBDF_SRIOV_SETTINGS_REGEX, $entry)) {
// Format: <DBDF>|<Vendor:Device>|<VFIO_flag>|<MAC>
[$dbdf, $ven_dev, $vfio_flag, $mac] = explode('|', $entry);
$sriov_devices_settings[$dbdf] = [
'dbdf' => $dbdf,
'vendor' => $ven_dev,
'vfio' => (int)$vfio_flag,
'mac' => strtoupper($mac),
];
}
}
# $sriov_devices_settings = array_values(array_unique($sriov_devices_settings, SORT_REGULAR));
}
$disks = (array)parse_ini_file('state/disks.ini',true);
$devicelist = array_column($disks, 'device');
$lines = array ();
@@ -430,7 +200,6 @@ if (is_file("/boot/config/sriovvfs.cfg")) {
echo "SRIOV Available VFs:{$sriov[$pciaddress]['total_vfs']}";
$num_vfs= $sriov[$pciaddress]['num_vfs'];
if (isset($sriov_devices[$pciaddress]))
$file_numvfs = $sriov_devices[$pciaddress]['vf_count'];
else $file_numvfs = 0;
@@ -452,7 +221,7 @@ if (is_file("/boot/config/sriovvfs.cfg")) {
echo " "._("Current:").$num_vfs;
#sprintf(" "._("Current").":%1s",$num_vfs);
echo ' <a class="info" href="#" title="'._("Save VFs config").'" onclick="saveVFsConfig(\''.htmlentities($pciaddress).'\',\''.htmlentities($vd).'\'); return false;"><i class="fa fa-save"> </i></a>';
echo ' <a class="info" href="#" title="'._("Action VFs update").'" onclick="applyVFsConfig(\''.htmlentities($pciaddress).'\',\''.htmlentities($vd).'\'); return false;"><i title="Apply now" class="fa fa-play"></i></a>';
echo ' <a class="info" href="#" title="'._("Action VFs update").'" onclick="applyVFsConfig(\''.htmlentities($pciaddress).'\',\''.htmlentities($vd).'\',\''.htmlentities($num_vfs).'\'); return false;"><i title="Apply now" class="fa fa-play"></i></a>';
if ($file_numvfs != $num_vfs) echo " <span id='vfnotice".$pciaddress."'><i class=\"fa fa-warning fa-fw orange-text\"></i> ".sprintf(_("Pending action or reboot"));
@@ -479,9 +248,9 @@ if (is_file("/boot/config/sriovvfs.cfg")) {
if (file_exists('/sys/bus/pci/devices/'.$pciaddress.'/reset')) echo "<i class=\"fa fa-retweet grey-orb middle\" title=\"",_('Function Level Reset (FLR) supported'),".\"></i>";
echo "</td><td>";
if (!$removed) {
echo '<input type="checkbox" class="vfiommu'.$vrf['iommu_group'].'" value="'.$pciaddress."|".$vd.'" ';
echo '<input type="checkbox" id="vfvfio'.$pciaddress.'" class="vfiommu'.$vrf['iommu_group'].'" value="'.$pciaddress."|".$vd.'" ';
// check config file for two formats: <Domain:Bus:Device.Function>|<Vendor:Device> or just <Domain:Bus:Device.Function>
echo (in_array($pciaddress."|".$vd, $vfio_cfg_devices) || in_array($pciaddress, $vfio_cfg_devices)) ? " checked>" : ">";
echo (array_key_exists($pciaddress,$sriov_devices_settings) && $sriov_devices_settings[$pciaddress]['vfio'] == 1) ? " checked>" : ">";
}
} else { echo "</td><td>"; }
echo '</td><td title="';
@@ -515,7 +284,7 @@ if (is_file("/boot/config/sriovvfs.cfg")) {
echo '<label for="mac_address">MAC Address:</label>';
echo "<input class='narrow' type=\"text\" name=\"vfmac$pciaddress\" id=\"vfmac$pciaddress\" value=\"$value_attr\" placeholder=\"$placeholder\">";
echo '<a class="info" href="#" title="'._("Generate MAC").'" onclick="generateMAC(\''.htmlentities($pciaddress).'\'); return false;"><i class="fa fa-refresh mac_generate"> </i></a>';
echo '<a class="info" href="#" title="'._("Save MAC config").'" onclick="saveMACConfig(\''.htmlentities($pciaddress).'\',\''.htmlentities($vd).'\'); return false;"><i class="fa fa-save"> </i></a>';
echo '<a class="info" href="#" title="'._("Save MAC config").'" onclick="saveVFSettingsConfig(\''.htmlentities($pciaddress).'\',\''.htmlentities($vd).'\'); return false;"><i class="fa fa-save"> </i></a>';
if ($vrf['driver'] == "vfio-pci")
echo _("Current").": ";
echo $vrf['driver'] == "vfio-pci" ? _("Bound to VFIO") : strtoupper($vrf['mac']);
@@ -0,0 +1,94 @@
<?PHP
/* Copyright 2025-, Lime Technology
* Copyright 2025-, Simon Fairweather.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
#VFSETTINGS=0000:04:11.5|8086:1520|0|62:00:04:11:05:01 0000:04:10.5|8086:1520|1|62:00:04:10:05:01
#VFS=0000:04:00.1|8086:1521|3 0000:04:00.0|8086:1521|2
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Secure.php";
require_once "$docroot/webGui/include/Wrappers.php";
$sriov = '/boot/config/sriov.cfg';
$sriovvfs = '/boot/config/sriovvfs.cfg';
$type = _var($_POST,'type');
$pciid = _var($_POST,'pciid');
$vd = _var($_POST,'vd');
if (isset($pciid) && isset($vd)) {
$newelement_check = $pciid.'|'.$vd.'|';
switch($type) {
case "sriov":
$old = is_file($sriov) ? rtrim(file_get_contents($sriov)) : '';
$newexplode = explode(" ",str_replace("VFS=","",$old));
$new = $old;
$numvfs= _var($_POST,'numvfs');
$currentvfs = _var($_POST,'currentvfs');
$newelement_change = $newelement_check.$numfs;
$found = false;
$filepath = "/sys/bus/pci/devices/$pciid/sriov_numvfs";
if ($numvfs == 0) {
file_put_contents($filepath,0);
echo 1;
return;
}
if ($numvfs != $currentvfs) {
file_put_contents($filepath,0);
file_put_contents($filepath,$numvfs);
# Apply VF changes.
# foreach VF.
echo 1;
return;
}
file_put_contents($filepath,$numvfs);
# Apply VF changes.
# foreach VF.
echo 1;
return;
#else action numvfs > pf
#Apply VF settings.
break;
case "sriovsettings":
$old = is_file($sriovvfs) ? rtrim(file_get_contents($sriovvfs)) : '';
$newexplode = explode(" ",str_replace("VFSETTINGS=","",$old));
$mac= _var($_POST,'mac');
$vfio= _var($_POST,'vfio');
if ($vfio == "true") $vfio = 1; else $vfio = 0;
$found = false;
foreach($newexplode as $key => $newelement) {
if (strpos($newelement,$newelement_check) !== false) {
$found = true;
if($mac == "" && $vfio == 0) {
unset($newexplode[$key]) ;
break;
} else {
$newexplode[$key] = $newelement_check.$vfio."|".$mac;
break;
}
}
}
if (!$found) $newexplode[] = $newelement_check.$vfio."|".$mac;
$new = "VFSETTINGS=".implode(" ",$newexplode);
$file = $sriovvfs;
break;
}
}
?>
@@ -58,6 +58,7 @@ if (isset($pciid) && isset($vd)) {
$newexplode = explode(" ",str_replace("VFSETTINGS=","",$old));
$mac= _var($_POST,'mac');
$vfio= _var($_POST,'vfio');
if ($vfio == "true") $vfio = 1; else $vfio = 0;
$found = false;
foreach($newexplode as $key => $newelement) {
if (strpos($newelement,$newelement_check) !== false) {
+1 -8
View File
@@ -67,15 +67,8 @@ VFSETTINGS_LINE=$(grep "^VFSETTINGS=" "$CFG_VFS" | cut -d= -f2- | tr -d '"')
for PARAM_VFS in $VFSETTINGS_LINE; do
IFS='|' read -r arg1 arg2 arg3 arg4 <<< "$PARAM_VFS"
echo "Processing $arg1 $arg2 set Mac to $arg4"
/usr/local/sbin/sriov-setmac.sh "$arg1" "$arg2" "$arg4"
/usr/local/sbin/sriov-vfsettings.sh "$arg1" "$arg2" "$arg3" "$arg4"
echo "---"
if [[ "$arg3" == "1" ]]; then
/usr/local/sbin/vfio-pci-bind.sh "$arg1" "$arg2" \
1>>/var/log/vfio-pci \
2>>/var/log/vfio-pci-errors
fi
done
View File