Merge pull request #1190 from dgibson/pcipath

Clean up PCI path handling
This commit is contained in:
David Gibson 2021-02-19 12:23:27 +11:00 committed by GitHub
commit a060b9a21b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 701 additions and 221 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
**/*.bk
**/*~
**/*.orig
**/*.rej
**/target

View File

@ -29,10 +29,8 @@ message Interface {
uint64 mtu = 4;
string hwAddr = 5;
// pciAddr is the PCI address in the format "bridgeAddr/deviceAddr".
// Here, bridgeAddr is the address at which the bridge is attached on the root bus,
// while deviceAddr is the address at which the network device is attached on the bridge.
string pciAddr = 6;
// PCI path for the device (see the pci::Path (Rust) or types.PciPath (Go) type for format details)
string pciPath = 6;
// Type defines the type of interface described by this structure.
// The expected values are the one that are defined by the netlink

View File

@ -9,11 +9,13 @@ use std::collections::HashMap;
use std::fs;
use std::os::unix::fs::MetadataExt;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::linux_abi::*;
use crate::mount::{DRIVER_BLK_TYPE, DRIVER_MMIO_BLK_TYPE, DRIVER_NVDIMM_TYPE, DRIVER_SCSI_TYPE};
use crate::pci;
use crate::sandbox::Sandbox;
use crate::{AGENT_CONFIG, GLOBAL_DEVICE_WATCHER};
use anyhow::{anyhow, Result};
@ -45,58 +47,44 @@ pub fn online_device(path: &str) -> Result<()> {
Ok(())
}
// get_pci_device_address fetches the complete PCI address in sysfs, based on the PCI
// identifier provided. This should be in the format: "bridgeAddr/deviceAddr".
// Here, bridgeAddr is the address at which the bridge is attached on the root bus,
// while deviceAddr is the address at which the device is attached on the bridge.
fn get_pci_device_address(pci_id: &str) -> Result<String> {
let tokens: Vec<&str> = pci_id.split('/').collect();
// pciPathToSysfs fetches the sysfs path for a PCI path, relative to
// the syfs path for the PCI host bridge, based on the PCI path
// provided.
fn pcipath_to_sysfs(root_bus_sysfs: &str, pcipath: &pci::Path) -> Result<String> {
let mut bus = "0000:00".to_string();
let mut relpath = String::new();
if tokens.len() != 2 {
return Err(anyhow!(
"PCI Identifier for device should be of format [bridgeAddr/deviceAddr], got {}",
pci_id
));
for i in 0..pcipath.len() {
let bdf = format!("{}:{}.0", bus, pcipath[i]);
relpath = format!("{}/{}", relpath, bdf);
if i == pcipath.len() - 1 {
// Final device need not be a bridge
break;
}
// Find out the bus exposed by bridge
let bridgebuspath = format!("{}{}/pci_bus", root_bus_sysfs, relpath);
let mut files: Vec<_> = fs::read_dir(&bridgebuspath)?.collect();
if files.len() != 1 {
return Err(anyhow!(
"Expected exactly one PCI bus in {}, got {} instead",
bridgebuspath,
files.len()
));
}
// unwrap is safe, because of the length test above
let busfile = files.pop().unwrap()?;
bus = busfile
.file_name()
.into_string()
.map_err(|e| anyhow!("Bad filename under {}: {:?}", &bridgebuspath, e))?;
}
let bridge_id = tokens[0];
let device_id = tokens[1];
// Deduce the complete bridge address based on the bridge address identifier passed
// and the fact that bridges are attached on the main bus with function 0.
let pci_bridge_addr = format!("0000:00:{}.0", bridge_id);
// Find out the bus exposed by bridge
let bridge_bus_path = format!("{}/{}/pci_bus/", SYSFS_PCI_BUS_PREFIX, pci_bridge_addr);
let files_slice: Vec<_> = fs::read_dir(&bridge_bus_path)
.unwrap()
.map(|res| res.unwrap().path())
.collect();
let bus_num = files_slice.len();
if bus_num != 1 {
return Err(anyhow!(
"Expected an entry for bus in {}, got {} entries instead",
bridge_bus_path,
bus_num
));
}
let bus = files_slice[0].file_name().unwrap().to_str().unwrap();
// Device address is based on the bus of the bridge to which it is attached.
// We do not pass devices as multifunction, hence the trailing 0 in the address.
let pci_device_addr = format!("{}:{}.0", bus, device_id);
let bridge_device_pci_addr = format!("{}/{}", pci_bridge_addr, pci_device_addr);
info!(
sl!(),
"Fetched PCI address for device PCIAddr:{}\n", bridge_device_pci_addr
);
Ok(bridge_device_pci_addr)
Ok(relpath)
}
async fn get_device_name(sandbox: &Arc<Mutex<Sandbox>>, dev_addr: &str) -> Result<String> {
@ -155,11 +143,15 @@ pub async fn get_scsi_device_name(
get_device_name(sandbox, &dev_sub_path).await
}
pub async fn get_pci_device_name(sandbox: &Arc<Mutex<Sandbox>>, pci_id: &str) -> Result<String> {
let pci_addr = get_pci_device_address(pci_id)?;
pub async fn get_pci_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
pcipath: &pci::Path,
) -> Result<String> {
let root_bus_sysfs = format!("{}{}", SYSFS_DIR, create_pci_root_bus_path());
let sysfs_rel_path = pcipath_to_sysfs(&root_bus_sysfs, pcipath)?;
rescan_pci_bus()?;
get_device_name(sandbox, &pci_addr).await
get_device_name(sandbox, &sysfs_rel_path).await
}
pub async fn get_pmem_device_name(
@ -294,9 +286,7 @@ async fn virtiommio_blk_device_handler(
update_spec_device_list(device, spec, devidx)
}
// device.Id should be the PCI address in the format "bridgeAddr/deviceAddr".
// Here, bridgeAddr is the address at which the brige is attached on the root bus,
// while deviceAddr is the address at which the device is attached on the bridge.
// device.Id should be a PCI path string
async fn virtio_blk_device_handler(
device: &Device,
spec: &mut Spec,
@ -305,10 +295,12 @@ async fn virtio_blk_device_handler(
) -> Result<()> {
let mut dev = device.clone();
// When "Id (PCIAddr)" is not set, we allow to use the predicted "VmPath" passed from kata-runtime
// Note this is a special code path for cloud-hypervisor when BDF information is not available
// When "Id (PCI path)" is not set, we allow to use the predicted
// "VmPath" passed from kata-runtime Note this is a special code
// path for cloud-hypervisor when BDF information is not available
if device.id != "" {
dev.vm_path = get_pci_device_name(sandbox, &device.id).await?;
let pcipath = pci::Path::from_str(&device.id)?;
dev.vm_path = get_pci_device_name(sandbox, &pcipath).await?;
}
update_spec_device_list(&dev, spec, devidx)
@ -443,6 +435,7 @@ pub fn update_device_cgroup(spec: &mut Spec) -> Result<()> {
mod tests {
use super::*;
use oci::Linux;
use tempfile::tempdir;
#[test]
fn test_update_device_cgroup() {
@ -722,4 +715,68 @@ mod tests {
assert_eq!(Some(host_major), specresources.devices[1].major);
assert_eq!(Some(host_minor), specresources.devices[1].minor);
}
#[test]
fn test_pcipath_to_sysfs() {
let testdir = tempdir().expect("failed to create tmpdir");
let rootbuspath = testdir.path().to_str().unwrap();
let path2 = pci::Path::from_str("02").unwrap();
let path23 = pci::Path::from_str("02/03").unwrap();
let path234 = pci::Path::from_str("02/03/04").unwrap();
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
assert!(relpath.is_err());
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
assert!(relpath.is_err());
// Create mock sysfs files for the device at 0000:00:02.0
let bridge2path = format!("{}{}", rootbuspath, "/0000:00:02.0");
fs::create_dir_all(&bridge2path).unwrap();
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
assert!(relpath.is_err());
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
assert!(relpath.is_err());
// Create mock sysfs files to indicate that 0000:00:02.0 is a bridge to bus 01
let bridge2bus = "0000:01";
let bus2path = format!("{}/pci_bus/{}", bridge2path, bridge2bus);
fs::create_dir_all(bus2path).unwrap();
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0");
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
assert!(relpath.is_err());
// Create mock sysfs files for a bridge at 0000:01:03.0 to bus 02
let bridge3path = format!("{}/0000:01:03.0", bridge2path);
let bridge3bus = "0000:02";
let bus3path = format!("{}/pci_bus/{}", bridge3path, bridge3bus);
fs::create_dir_all(bus3path).unwrap();
let relpath = pcipath_to_sysfs(rootbuspath, &path2);
assert_eq!(relpath.unwrap(), "/0000:00:02.0");
let relpath = pcipath_to_sysfs(rootbuspath, &path23);
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0");
let relpath = pcipath_to_sysfs(rootbuspath, &path234);
assert_eq!(relpath.unwrap(), "/0000:00:02.0/0000:01:03.0/0000:02:04.0");
}
}

View File

@ -9,7 +9,6 @@
use std::fs;
pub const SYSFS_DIR: &str = "/sys";
pub const SYSFS_PCI_BUS_PREFIX: &str = "/sys/bus/pci/devices";
pub const SYSFS_PCI_BUS_RESCAN_FILE: &str = "/sys/bus/pci/rescan";
#[cfg(any(
target_arch = "powerpc64",

View File

@ -49,6 +49,7 @@ mod mount;
mod namespace;
mod netlink;
mod network;
mod pci;
pub mod random;
mod sandbox;
#[cfg(test)]

View File

@ -12,6 +12,7 @@ use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::ptr::null;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
@ -26,6 +27,7 @@ use crate::device::{
get_pci_device_name, get_pmem_device_name, get_scsi_device_name, online_device,
};
use crate::linux_abi::*;
use crate::pci;
use crate::protocols::agent::Storage;
use crate::Sandbox;
use anyhow::{anyhow, Context, Result};
@ -310,8 +312,8 @@ async fn virtio_blk_storage_handler(
sandbox: Arc<Mutex<Sandbox>>,
) -> Result<String> {
let mut storage = storage.clone();
// If hot-plugged, get the device node path based on the PCI address else
// use the virt path provided in Storage Source
// If hot-plugged, get the device node path based on the PCI path
// otherwise use the virt path provided in Storage Source
if storage.source.starts_with("/dev") {
let metadata = fs::metadata(&storage.source)
.context(format!("get metadata on file {:?}", &storage.source))?;
@ -321,7 +323,8 @@ async fn virtio_blk_storage_handler(
return Err(anyhow!("Invalid device {}", &storage.source));
}
} else {
let dev_path = get_pci_device_name(&sandbox, &storage.source).await?;
let pcipath = pci::Path::from_str(&storage.source)?;
let dev_path = get_pci_device_name(&sandbox, &pcipath).await?;
storage.source = dev_path;
}

168
src/agent/src/pci.rs Normal file
View File

@ -0,0 +1,168 @@
// Copyright Red Hat.
//
// SPDX-License-Identifier: Apache-2.0
//
use std::convert::TryInto;
use std::fmt;
use std::ops::Deref;
use std::str::FromStr;
use anyhow::anyhow;
// The PCI spec reserves 5 bits for slot number (a.k.a. device
// number), giving slots 0..31
const SLOT_BITS: u8 = 5;
const SLOT_MAX: u8 = (1 << SLOT_BITS) - 1;
// Represents a PCI function's slot number (a.k.a. device number),
// giving its location on a single bus
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Slot(u8);
impl Slot {
pub fn new<T: TryInto<u8> + fmt::Display + Copy>(v: T) -> anyhow::Result<Self> {
if let Ok(v8) = v.try_into() {
if v8 <= SLOT_MAX {
return Ok(Slot(v8));
}
}
Err(anyhow!(
"PCI slot {} should be in range [0..{:#x}]",
v,
SLOT_MAX
))
}
}
impl FromStr for Slot {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self> {
let v = isize::from_str_radix(s, 16)?;
Slot::new(v)
}
}
impl fmt::Display for Slot {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:02x}", self.0)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Path(Vec<Slot>);
impl Path {
pub fn new(slots: Vec<Slot>) -> anyhow::Result<Self> {
if slots.is_empty() {
return Err(anyhow!("PCI path must have at least one element"));
}
Ok(Path(slots))
}
}
// Let Path be treated as a slice of Slots
impl Deref for Path {
type Target = [Slot];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for Path {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let sslots: Vec<String> = self
.0
.iter()
.map(std::string::ToString::to_string)
.collect();
write!(f, "{}", sslots.join("/"))
}
}
impl FromStr for Path {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self> {
let rslots: anyhow::Result<Vec<Slot>> = s.split('/').map(Slot::from_str).collect();
Path::new(rslots?)
}
}
#[cfg(test)]
mod tests {
use crate::pci::{Path, Slot};
use std::str::FromStr;
#[test]
fn test_slot() {
// Valid slots
let slot = Slot::new(0x00).unwrap();
assert_eq!(format!("{}", slot), "00");
let slot = Slot::from_str("00").unwrap();
assert_eq!(format!("{}", slot), "00");
let slot = Slot::new(31).unwrap();
let slot2 = Slot::from_str("1f").unwrap();
assert_eq!(slot, slot2);
// Bad slots
let slot = Slot::new(-1);
assert!(slot.is_err());
let slot = Slot::new(32);
assert!(slot.is_err());
let slot = Slot::from_str("20");
assert!(slot.is_err());
let slot = Slot::from_str("xy");
assert!(slot.is_err());
let slot = Slot::from_str("00/");
assert!(slot.is_err());
let slot = Slot::from_str("");
assert!(slot.is_err());
}
#[test]
fn test_path() {
let slot3 = Slot::new(0x03).unwrap();
let slot4 = Slot::new(0x04).unwrap();
let slot5 = Slot::new(0x05).unwrap();
// Valid paths
let pcipath = Path::new(vec![slot3]).unwrap();
assert_eq!(format!("{}", pcipath), "03");
let pcipath2 = Path::from_str("03").unwrap();
assert_eq!(pcipath, pcipath2);
assert_eq!(pcipath.len(), 1);
assert_eq!(pcipath[0], slot3);
let pcipath = Path::new(vec![slot3, slot4]).unwrap();
assert_eq!(format!("{}", pcipath), "03/04");
let pcipath2 = Path::from_str("03/04").unwrap();
assert_eq!(pcipath, pcipath2);
assert_eq!(pcipath.len(), 2);
assert_eq!(pcipath[0], slot3);
assert_eq!(pcipath[1], slot4);
let pcipath = Path::new(vec![slot3, slot4, slot5]).unwrap();
assert_eq!(format!("{}", pcipath), "03/04/05");
let pcipath2 = Path::from_str("03/04/05").unwrap();
assert_eq!(pcipath, pcipath2);
assert_eq!(pcipath.len(), 3);
assert_eq!(pcipath[0], slot3);
assert_eq!(pcipath[1], slot4);
assert_eq!(pcipath[2], slot5);
// Bad paths
assert!(Path::new(vec!()).is_err());
assert!(Path::from_str("20").is_err());
assert!(Path::from_str("//").is_err());
assert!(Path::from_str("xyz").is_err());
}
}

View File

@ -28,6 +28,7 @@ import (
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/uuid"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// Since ACRN is using the store in a quite abnormal way, let's first draw it back from store to here
@ -550,8 +551,8 @@ func (a *Acrn) updateBlockDevice(drive *config.BlockDrive) error {
slot := AcrnBlkdDevSlot[drive.Index]
//Explicitly set PCIAddr to NULL, so that VirtPath can be used
drive.PCIAddr = ""
//Explicitly set PCIPath to NULL, so that VirtPath can be used
drive.PCIPath = vcTypes.PciPath{}
args := []string{"blkrescan", a.acrnConfig.Name, fmt.Sprintf("%d,%s", slot, drive.File)}

View File

@ -10,6 +10,7 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// BridgedMacvlanEndpoint represents a macvlan endpoint that is bridged to the VM
@ -17,7 +18,7 @@ type BridgedMacvlanEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
PCIPath vcTypes.PciPath
RxRateLimiter bool
TxRateLimiter bool
}
@ -69,14 +70,14 @@ func (endpoint *BridgedMacvlanEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.

View File

@ -32,6 +32,7 @@ import (
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/config"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
//
@ -439,8 +440,8 @@ func (clh *cloudHypervisor) hotplugAddBlockDevice(drive *config.BlockDrive) erro
driveID := clhDriveIndexToID(drive.Index)
//Explicitly set PCIAddr to NULL, so that VirtPath can be used
drive.PCIAddr = ""
//Explicitly set PCIPath to NULL, so that VirtPath can be used
drive.PCIPath = vcTypes.PciPath{}
if drive.Pmem {
err = fmt.Errorf("pmem device hotplug not supported")

View File

@ -16,6 +16,7 @@ import (
"github.com/go-ini/ini"
"golang.org/x/sys/unix"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// DeviceType indicates device type
@ -156,8 +157,8 @@ type BlockDrive struct {
// MmioAddr is used to identify the slot at which the drive is attached (order?).
MmioAddr string
// PCIAddr is the PCI address used to identify the slot at which the drive is attached.
PCIAddr string
// PCIPath is the PCI path used to identify the slot at which the drive is attached.
PCIPath vcTypes.PciPath
// SCSI Address of the block device, in case the device is attached using SCSI driver
// SCSI address is in the format SCSI-Id:LUN
@ -249,9 +250,10 @@ type VhostUserDeviceAttrs struct {
CacheSize uint32
Cache string
// PCIAddr is the PCI address used to identify the slot at which the drive is attached.
// It is only meaningful for vhost user block devices
PCIAddr string
// PCIPath is the PCI path used to identify the slot at which
// the drive is attached. It is only meaningful for vhost
// user block devices
PCIPath vcTypes.PciPath
// Block index of the device if assigned
Index int

View File

@ -170,7 +170,7 @@ func (device *BlockDevice) Save() persistapi.DeviceState {
ID: drive.ID,
Index: drive.Index,
MmioAddr: drive.MmioAddr,
PCIAddr: drive.PCIAddr,
PCIPath: drive.PCIPath,
SCSIAddr: drive.SCSIAddr,
NvdimmID: drive.NvdimmID,
VirtPath: drive.VirtPath,
@ -196,7 +196,7 @@ func (device *BlockDevice) Load(ds persistapi.DeviceState) {
ID: bd.ID,
Index: bd.Index,
MmioAddr: bd.MmioAddr,
PCIAddr: bd.PCIAddr,
PCIPath: bd.PCIPath,
SCSIAddr: bd.SCSIAddr,
NvdimmID: bd.NvdimmID,
VirtPath: bd.VirtPath,

View File

@ -164,7 +164,7 @@ func (device *VhostUserBlkDevice) Save() persistapi.DeviceState {
DevID: vAttr.DevID,
SocketPath: vAttr.SocketPath,
Type: string(vAttr.Type),
PCIAddr: vAttr.PCIAddr,
PCIPath: vAttr.PCIPath,
Index: vAttr.Index,
}
}
@ -185,7 +185,7 @@ func (device *VhostUserBlkDevice) Load(ds persistapi.DeviceState) {
DevID: dev.DevID,
SocketPath: dev.SocketPath,
Type: config.DeviceType(dev.Type),
PCIAddr: dev.PCIAddr,
PCIPath: dev.PCIPath,
Index: dev.Index,
}
}

View File

@ -9,6 +9,7 @@ import (
"fmt"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// Endpoint represents a physical or virtual network interface.
@ -17,11 +18,11 @@ type Endpoint interface {
Name() string
HardwareAddr() string
Type() EndpointType
PciAddr() string
PciPath() vcTypes.PciPath
NetworkPair() *NetworkInterfacePair
SetProperties(NetworkInfo)
SetPciAddr(string)
SetPciPath(vcTypes.PciPath)
Attach(*Sandbox) error
Detach(netNsCreated bool, netNsPath string) error
HotAttach(h hypervisor) error

View File

@ -10,6 +10,7 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// IPVlanEndpoint represents a ipvlan endpoint that is bridged to the VM
@ -17,7 +18,7 @@ type IPVlanEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
PCIPath vcTypes.PciPath
RxRateLimiter bool
TxRateLimiter bool
}
@ -72,14 +73,14 @@ func (endpoint *IPVlanEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *IPVlanEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *IPVlanEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *IPVlanEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *IPVlanEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.

View File

@ -1074,7 +1074,7 @@ func (k *kataAgent) appendBlockDevice(dev ContainerDevice, c *Container) *grpc.D
kataDevice.Id = d.DevNo
case config.VirtioBlock:
kataDevice.Type = kataBlkDevType
kataDevice.Id = d.PCIAddr
kataDevice.Id = d.PCIPath.String()
kataDevice.VmPath = d.VirtPath
case config.VirtioSCSI:
kataDevice.Type = kataSCSIDevType
@ -1099,7 +1099,7 @@ func (k *kataAgent) appendVhostUserBlkDevice(dev ContainerDevice, c *Container)
kataDevice := &grpc.Device{
ContainerPath: dev.ContainerPath,
Type: kataBlkDevType,
Id: d.PCIAddr,
Id: d.PCIPath.String(),
}
return kataDevice
@ -1178,10 +1178,10 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat
rootfs.Source = blockDrive.DevNo
case sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock:
rootfs.Driver = kataBlkDevType
if blockDrive.PCIAddr == "" {
if blockDrive.PCIPath.IsNil() {
rootfs.Source = blockDrive.VirtPath
} else {
rootfs.Source = blockDrive.PCIAddr
rootfs.Source = blockDrive.PCIPath.String()
}
case sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioSCSI:
@ -1427,10 +1427,10 @@ func (k *kataAgent) handleDeviceBlockVolume(c *Container, m Mount, device api.De
vol.Source = blockDrive.DevNo
case c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock:
vol.Driver = kataBlkDevType
if blockDrive.PCIAddr == "" {
if blockDrive.PCIPath.IsNil() {
vol.Source = blockDrive.VirtPath
} else {
vol.Source = blockDrive.PCIAddr
vol.Source = blockDrive.PCIPath.String()
}
case c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioMmio:
vol.Driver = kataMmioBlkDevType
@ -1467,7 +1467,7 @@ func (k *kataAgent) handleVhostUserBlkVolume(c *Container, m Mount, device api.D
}
vol.Driver = kataBlkDevType
vol.Source = d.PCIAddr
vol.Source = d.PCIPath.String()
vol.Fstype = "bind"
vol.Options = []string{"bind"}
vol.MountPoint = m.Destination

View File

@ -32,6 +32,7 @@ import (
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/mock"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/rootless"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
var (
@ -39,7 +40,7 @@ var (
testBlockDeviceCtrPath = "testBlockDeviceCtrPath"
testDevNo = "testDevNo"
testNvdimmID = "testNvdimmID"
testPCIAddr = "04/02"
testPCIPath, _ = vcTypes.PciPathFromString("04/02")
testSCSIAddr = "testSCSIAddr"
testVirtPath = "testVirtPath"
)
@ -271,13 +272,13 @@ func TestHandleDeviceBlockVolume(t *testing.T) {
inputMount: Mount{},
inputDev: &drivers.BlockDevice{
BlockDrive: &config.BlockDrive{
PCIAddr: testPCIAddr,
PCIPath: testPCIPath,
VirtPath: testVirtPath,
},
},
resultVol: &pb.Storage{
Driver: kataBlkDevType,
Source: testPCIAddr,
Source: testPCIPath.String(),
},
},
{
@ -352,17 +353,19 @@ func TestHandleBlockVolume(t *testing.T) {
vDestination := "/VhostUserBlk/destination"
bDestination := "/DeviceBlock/destination"
dDestination := "/DeviceDirectBlock/destination"
vPCIAddr := "0001:01"
bPCIAddr := "0002:01"
dPCIAddr := "0003:01"
vPCIPath, err := vcTypes.PciPathFromString("01/02")
assert.NoError(t, err)
bPCIPath, err := vcTypes.PciPathFromString("03/04")
assert.NoError(t, err)
dPCIPath, err := vcTypes.PciPathFromString("04/05")
vDev := drivers.NewVhostUserBlkDevice(&config.DeviceInfo{ID: vDevID})
bDev := drivers.NewBlockDevice(&config.DeviceInfo{ID: bDevID})
dDev := drivers.NewBlockDevice(&config.DeviceInfo{ID: dDevID})
vDev.VhostUserDeviceAttrs = &config.VhostUserDeviceAttrs{PCIAddr: vPCIAddr}
bDev.BlockDrive = &config.BlockDrive{PCIAddr: bPCIAddr}
dDev.BlockDrive = &config.BlockDrive{PCIAddr: dPCIAddr}
vDev.VhostUserDeviceAttrs = &config.VhostUserDeviceAttrs{PCIPath: vPCIPath}
bDev.BlockDrive = &config.BlockDrive{PCIPath: bPCIPath}
dDev.BlockDrive = &config.BlockDrive{PCIPath: dPCIPath}
var devices []api.Device
devices = append(devices, vDev, bDev, dDev)
@ -411,21 +414,21 @@ func TestHandleBlockVolume(t *testing.T) {
Fstype: "bind",
Options: []string{"bind"},
Driver: kataBlkDevType,
Source: vPCIAddr,
Source: vPCIPath.String(),
}
bStorage := &pb.Storage{
MountPoint: bDestination,
Fstype: "bind",
Options: []string{"bind"},
Driver: kataBlkDevType,
Source: bPCIAddr,
Source: bPCIPath.String(),
}
dStorage := &pb.Storage{
MountPoint: dDestination,
Fstype: "ext4",
Options: []string{"ro"},
Driver: kataBlkDevType,
Source: dPCIAddr,
Source: dPCIPath.String(),
}
assert.Equal(t, vStorage, volumeStorages[0], "Error while handle VhostUserBlk type block volume")
@ -462,7 +465,7 @@ func TestAppendDevices(t *testing.T) {
ID: id,
},
BlockDrive: &config.BlockDrive{
PCIAddr: testPCIAddr,
PCIPath: testPCIPath,
},
},
}
@ -489,7 +492,7 @@ func TestAppendDevices(t *testing.T) {
{
Type: kataBlkDevType,
ContainerPath: testBlockDeviceCtrPath,
Id: testPCIAddr,
Id: testPCIPath.String(),
},
}
updatedDevList := k.appendDevices(devList, c)
@ -509,7 +512,7 @@ func TestAppendVhostUserBlkDevices(t *testing.T) {
},
VhostUserDeviceAttrs: &config.VhostUserDeviceAttrs{
Type: config.VhostUserBlk,
PCIAddr: testPCIAddr,
PCIPath: testPCIPath,
},
},
}
@ -537,7 +540,7 @@ func TestAppendVhostUserBlkDevices(t *testing.T) {
{
Type: kataBlkDevType,
ContainerPath: testBlockDeviceCtrPath,
Id: testPCIAddr,
Id: testPCIPath.String(),
},
}
updatedDevList := k.appendDevices(devList, c)

View File

@ -10,6 +10,7 @@ import (
"os"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// MacvtapEndpoint represents a macvtap endpoint
@ -18,7 +19,7 @@ type MacvtapEndpoint struct {
EndpointType EndpointType
VMFds []*os.File
VhostFds []*os.File
PCIAddr string
PCIPath vcTypes.PciPath
RxRateLimiter bool
TxRateLimiter bool
}
@ -93,14 +94,14 @@ func (endpoint *MacvtapEndpoint) HotDetach(h hypervisor, netNsCreated bool, netN
return fmt.Errorf("MacvtapEndpoint does not support Hot detach")
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *MacvtapEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *MacvtapEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *MacvtapEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *MacvtapEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.
@ -113,7 +114,7 @@ func (endpoint *MacvtapEndpoint) save() persistapi.NetworkEndpoint {
Type: string(endpoint.Type()),
Macvtap: &persistapi.MacvtapEndpoint{
PCIAddr: endpoint.PCIAddr,
PCIPath: endpoint.PCIPath,
},
}
}
@ -121,7 +122,7 @@ func (endpoint *MacvtapEndpoint) load(s persistapi.NetworkEndpoint) {
endpoint.EndpointType = MacvtapEndpointType
if s.Macvtap != nil {
endpoint.PCIAddr = s.Macvtap.PCIAddr
endpoint.PCIPath = s.Macvtap.PCIPath
}
}

View File

@ -984,7 +984,7 @@ func generateVCNetworkStructures(networkNS NetworkNamespace) ([]*pbTypes.Interfa
Mtu: uint64(endpoint.Properties().Iface.MTU),
RawFlags: noarp,
HwAddr: endpoint.HardwareAddr(),
PciAddr: endpoint.PciAddr(),
PciPath: endpoint.PciPath().String(),
}
ifaces = append(ifaces, &ifc)

View File

@ -6,6 +6,8 @@
package persistapi
import vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
// ============= sandbox level resources =============
// BlockDrive represents a block storage drive which may be used in case the storage
@ -26,8 +28,8 @@ type BlockDrive struct {
// MmioAddr is used to identify the slot at which the drive is attached (order?).
MmioAddr string
// PCIAddr is the PCI address used to identify the slot at which the drive is attached.
PCIAddr string
// PCIPath is the PCI path used to identify the slot at which the drive is attached.
PCIPath vcTypes.PciPath
// SCSI Address of the block device, in case the device is attached using SCSI driver
// SCSI address is in the format SCSI-Id:LUN
@ -71,9 +73,9 @@ type VhostUserDeviceAttrs struct {
// MacAddress is only meaningful for vhost user net device
MacAddress string
// PCIAddr is the PCI address used to identify the slot at which the drive is attached.
// PCIPath is the PCI path used to identify the slot at which the drive is attached.
// It is only meaningful for vhost user block devices
PCIAddr string
PCIPath vcTypes.PciPath
// Block index of the device if assigned
Index int

View File

@ -7,6 +7,7 @@
package persistapi
import (
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
"github.com/vishvananda/netlink"
)
@ -48,7 +49,7 @@ type PhysicalEndpoint struct {
type MacvtapEndpoint struct {
// This is for showing information.
// Remove this field won't impact anything.
PCIAddr string
PCIPath vcTypes.PciPath
}
type TapEndpoint struct {
@ -75,7 +76,7 @@ type VhostUserEndpoint struct {
// This is for showing information.
// Remove these fields won't impact anything.
IfaceName string
PCIAddr string
PCIPath vcTypes.PciPath
}
// NetworkEndpoint contains network interface information

View File

@ -17,6 +17,7 @@ import (
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/cgroups"
"github.com/safchain/ethtool"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// PhysicalEndpoint gathers a physical network interface and its properties
@ -28,7 +29,7 @@ type PhysicalEndpoint struct {
BDF string
Driver string
VendorDeviceID string
PCIAddr string
PCIPath vcTypes.PciPath
}
// Properties returns the properties of the physical interface.
@ -51,14 +52,14 @@ func (endpoint *PhysicalEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *PhysicalEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *PhysicalEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *PhysicalEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *PhysicalEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// SetProperties sets the properties of the physical endpoint.

View File

@ -96,10 +96,8 @@ type Interface struct {
IPAddresses []*IPAddress `protobuf:"bytes,3,rep,name=IPAddresses,proto3" json:"IPAddresses,omitempty"`
Mtu uint64 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"`
HwAddr string `protobuf:"bytes,5,opt,name=hwAddr,proto3" json:"hwAddr,omitempty"`
// pciAddr is the PCI address in the format "bridgeAddr/deviceAddr".
// Here, bridgeAddr is the address at which the bridge is attached on the root bus,
// while deviceAddr is the address at which the network device is attached on the bridge.
PciAddr string `protobuf:"bytes,6,opt,name=pciAddr,proto3" json:"pciAddr,omitempty"`
// PCI path for the device (see the pci::Path (Rust) or types.PciPath (Go) type for format details)
PciPath string `protobuf:"bytes,6,opt,name=pciPath,proto3" json:"pciPath,omitempty"`
// Type defines the type of interface described by this structure.
// The expected values are the one that are defined by the netlink
// library, regarding each type of link. Here is a non exhaustive
@ -242,37 +240,37 @@ func init() {
}
var fileDescriptor_b0c68e5b9fabcd81 = []byte{
// 470 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x31, 0x8f, 0xda, 0x30,
0x14, 0xc7, 0x31, 0x21, 0x39, 0x62, 0x74, 0x2d, 0xb2, 0xaa, 0x93, 0xd5, 0x4a, 0x51, 0xc4, 0xd2,
0xa8, 0x52, 0x89, 0x44, 0xab, 0xee, 0xd7, 0xe1, 0x24, 0x96, 0x8a, 0x7a, 0x6b, 0x97, 0xca, 0x18,
0x13, 0x22, 0x92, 0x38, 0xb2, 0x1d, 0x10, 0xea, 0xd2, 0x2f, 0xd2, 0xef, 0x73, 0x63, 0xc7, 0x8e,
0x77, 0x7c, 0x92, 0xca, 0x76, 0x40, 0x29, 0xed, 0x72, 0x13, 0xff, 0xdf, 0x7b, 0x36, 0xef, 0xff,
0xfe, 0x18, 0xf8, 0x39, 0xcb, 0xf5, 0xa6, 0x59, 0x4e, 0x99, 0x28, 0xd3, 0x2d, 0xd5, 0xf4, 0x2d,
0x13, 0x95, 0xa6, 0x79, 0xc5, 0xa5, 0xfa, 0x87, 0x95, 0x64, 0x29, 0xcd, 0x78, 0xa5, 0xd3, 0x5a,
0x0a, 0x2d, 0x98, 0x28, 0x94, 0x53, 0x2a, 0xd5, 0x87, 0x9a, 0xab, 0xa9, 0x05, 0xe4, 0x5b, 0x98,
0x2c, 0x61, 0x38, 0x5f, 0xdc, 0xae, 0x56, 0x92, 0x2b, 0x85, 0x5e, 0xc3, 0x60, 0x4d, 0xcb, 0xbc,
0x38, 0x60, 0x10, 0x83, 0xe4, 0xd9, 0xec, 0xf9, 0xd4, 0xdd, 0x98, 0x2f, 0xee, 0x6c, 0x99, 0xb4,
0x6d, 0x84, 0xe1, 0x15, 0x75, 0x77, 0x70, 0x3f, 0x06, 0x49, 0x48, 0x4e, 0x88, 0x10, 0x1c, 0x94,
0x54, 0x6d, 0xb1, 0x67, 0xcb, 0x56, 0x4f, 0x1e, 0x00, 0x0c, 0xe7, 0x95, 0xe6, 0x72, 0x4d, 0x19,
0x47, 0x37, 0x30, 0x58, 0xf1, 0x5d, 0xce, 0xb8, 0x1d, 0x12, 0x92, 0x96, 0xcc, 0xcd, 0x8a, 0x96,
0xbc, 0xfd, 0x42, 0xab, 0xd1, 0x0c, 0x8e, 0xce, 0xee, 0xb8, 0xc2, 0x5e, 0xec, 0x25, 0xa3, 0xd9,
0xf8, 0xec, 0xaa, 0xed, 0x90, 0xee, 0x21, 0x34, 0x86, 0x5e, 0xa9, 0x1b, 0x3c, 0x88, 0x41, 0x32,
0x20, 0x46, 0x9a, 0x89, 0x9b, 0xbd, 0x39, 0x80, 0x7d, 0x37, 0xd1, 0x91, 0xd9, 0xa2, 0x66, 0xb9,
0x6d, 0x04, 0x6e, 0x8b, 0x16, 0x8d, 0x17, 0x33, 0x03, 0x5f, 0x39, 0x2f, 0x46, 0xa3, 0x57, 0x30,
0x94, 0x74, 0xff, 0x6d, 0x5d, 0xd0, 0x4c, 0xe1, 0x61, 0x0c, 0x92, 0x6b, 0x32, 0x94, 0x74, 0x7f,
0x67, 0x78, 0xf2, 0x1d, 0xfa, 0x44, 0x34, 0xda, 0x6e, 0xb1, 0xe2, 0x4a, 0xb7, 0xbb, 0x59, 0x6d,
0xe6, 0x64, 0x54, 0xf3, 0x3d, 0x3d, 0x9c, 0xd2, 0x6a, 0xb1, 0x93, 0x85, 0xf7, 0x57, 0x16, 0x37,
0x30, 0x50, 0xa2, 0x91, 0x8c, 0xdb, 0x35, 0x42, 0xd2, 0x12, 0x7a, 0x01, 0x7d, 0xc5, 0x44, 0xcd,
0xed, 0x22, 0xd7, 0xc4, 0xc1, 0xe4, 0x27, 0x80, 0xa3, 0x5b, 0xb2, 0xf8, 0xc4, 0xf3, 0x6c, 0xb3,
0x14, 0xd2, 0xa4, 0xa6, 0xc5, 0x39, 0x12, 0x6b, 0xe5, 0xbf, 0xa9, 0x75, 0x0e, 0x75, 0x9c, 0xf4,
0x2f, 0x9d, 0x14, 0x85, 0xf9, 0x71, 0x4f, 0x0e, 0x1d, 0x59, 0x27, 0x9a, 0x6a, 0x67, 0xd0, 0x27,
0x0e, 0x4c, 0xd5, 0xe5, 0xe3, 0xbb, 0xaa, 0x85, 0x37, 0x2f, 0xe1, 0xf0, 0xf4, 0x82, 0x50, 0x00,
0xfb, 0xbb, 0xf7, 0xe3, 0x9e, 0xfd, 0xfc, 0x30, 0x06, 0x1f, 0xd5, 0xfd, 0x63, 0xd4, 0xfb, 0xfd,
0x18, 0xf5, 0x7e, 0x1c, 0x23, 0x70, 0x7f, 0x8c, 0xc0, 0xaf, 0x63, 0x04, 0x1e, 0x8e, 0x11, 0xf8,
0xfa, 0xe5, 0x89, 0x6f, 0x5e, 0x36, 0x95, 0xce, 0x4b, 0x9e, 0xee, 0x72, 0xa9, 0x3b, 0xad, 0x7a,
0x9b, 0x5d, 0xfe, 0x1d, 0x96, 0x81, 0x95, 0xef, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x11, 0x62,
0xe9, 0x09, 0x57, 0x03, 0x00, 0x00,
// 472 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x31, 0x8f, 0xd3, 0x30,
0x18, 0x86, 0xeb, 0xa6, 0xc9, 0x35, 0xae, 0x0e, 0x2a, 0x0b, 0x9d, 0x2c, 0x90, 0xa2, 0xa8, 0x0b,
0x11, 0x12, 0x8d, 0x54, 0x10, 0xfb, 0x31, 0x9c, 0xd4, 0x05, 0x15, 0x6f, 0xb0, 0x20, 0xd7, 0x75,
0xd3, 0xa8, 0x49, 0x1c, 0xd9, 0x4e, 0xab, 0x8a, 0x85, 0x3f, 0xc2, 0xff, 0xb9, 0x91, 0x91, 0xf1,
0xae, 0xbf, 0x04, 0xd9, 0x4e, 0xab, 0x50, 0x58, 0x6e, 0xca, 0xfb, 0x7c, 0xb6, 0xf3, 0xbd, 0xdf,
0x1b, 0x07, 0x7e, 0xce, 0x72, 0xbd, 0x69, 0x96, 0x53, 0x26, 0xca, 0x74, 0x4b, 0x35, 0x7d, 0xcb,
0x44, 0xa5, 0x69, 0x5e, 0x71, 0xa9, 0xfe, 0x61, 0x25, 0x59, 0x4a, 0x33, 0x5e, 0xe9, 0xb4, 0x96,
0x42, 0x0b, 0x26, 0x0a, 0xe5, 0x94, 0x4a, 0xf5, 0xa1, 0xe6, 0x6a, 0x6a, 0x01, 0xf9, 0x16, 0x26,
0x4b, 0x18, 0xce, 0x17, 0xb7, 0xab, 0x95, 0xe4, 0x4a, 0xa1, 0xd7, 0x30, 0x58, 0xd3, 0x32, 0x2f,
0x0e, 0x18, 0xc4, 0x20, 0x79, 0x36, 0x7b, 0x3e, 0x75, 0x27, 0xe6, 0x8b, 0x3b, 0x5b, 0x26, 0xed,
0x32, 0xc2, 0xf0, 0x8a, 0xba, 0x33, 0xb8, 0x1f, 0x83, 0x24, 0x24, 0x27, 0x44, 0x08, 0x0e, 0x4a,
0xaa, 0xb6, 0xd8, 0xb3, 0x65, 0xab, 0x27, 0x0f, 0x00, 0x86, 0xf3, 0x4a, 0x73, 0xb9, 0xa6, 0x8c,
0xa3, 0x1b, 0x18, 0xac, 0xf8, 0x2e, 0x67, 0xdc, 0x36, 0x09, 0x49, 0x4b, 0xe6, 0x64, 0x45, 0x4b,
0xde, 0xbe, 0xd0, 0x6a, 0x34, 0x83, 0xa3, 0xb3, 0x3b, 0xae, 0xb0, 0x17, 0x7b, 0xc9, 0x68, 0x36,
0x3e, 0xbb, 0x6a, 0x57, 0x48, 0x77, 0x13, 0x1a, 0x43, 0xaf, 0xd4, 0x0d, 0x1e, 0xc4, 0x20, 0x19,
0x10, 0x23, 0x4d, 0xc7, 0xcd, 0xde, 0x6c, 0xc0, 0xbe, 0xeb, 0xe8, 0xc8, 0x4c, 0x51, 0xb3, 0x7c,
0x41, 0xf5, 0x06, 0x07, 0x6e, 0x8a, 0x16, 0x8d, 0x17, 0xd3, 0x03, 0x5f, 0x39, 0x2f, 0x46, 0xa3,
0x57, 0x30, 0x94, 0x74, 0xff, 0x6d, 0x5d, 0xd0, 0x4c, 0xe1, 0x61, 0x0c, 0x92, 0x6b, 0x32, 0x94,
0x74, 0x7f, 0x67, 0x78, 0xf2, 0x1d, 0xfa, 0x44, 0x34, 0xda, 0x4e, 0xb1, 0xe2, 0x4a, 0xb7, 0xb3,
0x59, 0x6d, 0xfa, 0x64, 0x54, 0xf3, 0x3d, 0x3d, 0x9c, 0xd2, 0x6a, 0xb1, 0x93, 0x85, 0xf7, 0x57,
0x16, 0x37, 0x30, 0x50, 0xa2, 0x91, 0x8c, 0xdb, 0x31, 0x42, 0xd2, 0x12, 0x7a, 0x01, 0x7d, 0xc5,
0x44, 0xcd, 0xed, 0x20, 0xd7, 0xc4, 0xc1, 0xe4, 0x27, 0x80, 0xa3, 0x5b, 0xb2, 0xf8, 0xc4, 0xf3,
0x6c, 0xb3, 0x14, 0xd2, 0xa4, 0xa6, 0xc5, 0x39, 0x12, 0x6b, 0xe5, 0xbf, 0xa9, 0x75, 0x36, 0x75,
0x9c, 0xf4, 0x2f, 0x9d, 0x14, 0x85, 0xf9, 0xb8, 0x27, 0x87, 0x8e, 0xac, 0x13, 0x4d, 0xb5, 0x33,
0xe8, 0x13, 0x07, 0xa6, 0xea, 0xf2, 0xf1, 0x5d, 0xd5, 0xc2, 0x9b, 0x97, 0x70, 0x78, 0xba, 0x41,
0x28, 0x80, 0xfd, 0xdd, 0xfb, 0x71, 0xcf, 0x3e, 0x3f, 0x8c, 0xc1, 0x47, 0x75, 0xff, 0x18, 0xf5,
0x7e, 0x3f, 0x46, 0xbd, 0x1f, 0xc7, 0x08, 0xdc, 0x1f, 0x23, 0xf0, 0xeb, 0x18, 0x81, 0x87, 0x63,
0x04, 0xbe, 0x7e, 0x79, 0xe2, 0x9d, 0x97, 0x4d, 0xa5, 0xf3, 0x92, 0xa7, 0xbb, 0x5c, 0xea, 0xce,
0x52, 0xbd, 0xcd, 0x2e, 0x7f, 0x87, 0x65, 0x60, 0xe5, 0xbb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff,
0xed, 0x3e, 0x9a, 0x58, 0x57, 0x03, 0x00, 0x00,
}
func (m *IPAddress) Marshal() (dAtA []byte, err error) {
@ -357,10 +355,10 @@ func (m *Interface) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x3a
}
if len(m.PciAddr) > 0 {
i -= len(m.PciAddr)
copy(dAtA[i:], m.PciAddr)
i = encodeVarintTypes(dAtA, i, uint64(len(m.PciAddr)))
if len(m.PciPath) > 0 {
i -= len(m.PciPath)
copy(dAtA[i:], m.PciPath)
i = encodeVarintTypes(dAtA, i, uint64(len(m.PciPath)))
i--
dAtA[i] = 0x32
}
@ -591,7 +589,7 @@ func (m *Interface) Size() (n int) {
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
l = len(m.PciAddr)
l = len(m.PciPath)
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
@ -703,7 +701,7 @@ func (this *Interface) String() string {
`IPAddresses:` + repeatedStringForIPAddresses + `,`,
`Mtu:` + fmt.Sprintf("%v", this.Mtu) + `,`,
`HwAddr:` + fmt.Sprintf("%v", this.HwAddr) + `,`,
`PciAddr:` + fmt.Sprintf("%v", this.PciAddr) + `,`,
`PciPath:` + fmt.Sprintf("%v", this.PciPath) + `,`,
`Type:` + fmt.Sprintf("%v", this.Type) + `,`,
`RawFlags:` + fmt.Sprintf("%v", this.RawFlags) + `,`,
`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
@ -1066,7 +1064,7 @@ func (m *Interface) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PciAddr", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field PciPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
@ -1094,7 +1092,7 @@ func (m *Interface) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.PciAddr = string(dAtA[iNdEx:postIndex])
m.PciPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 7:
if wireType != 2 {

View File

@ -0,0 +1,100 @@
// Copyright Red Hat.
//
// SPDX-License-Identifier: Apache-2.0
//
package types
import (
"fmt"
"strconv"
"strings"
)
const (
// The PCI spec reserves 5 bits for slot number (a.k.a. device
// number), giving slots 0..31
pciSlotBits = 5
maxPciSlot = (1 << pciSlotBits) - 1
)
// A PciSlot describes where a PCI device sits on a single bus
//
// This encapsulates the PCI slot number a.k.a device number, which is
// limited to a 5 bit value [0x00..0x1f] by the PCI specification
//
// XXX In order to support multifunction device's we'll need to extend
// this to include the PCI 3-bit function number as well.
type PciSlot struct{ slot uint8 }
func PciSlotFromString(s string) (PciSlot, error) {
v, err := strconv.ParseUint(s, 16, pciSlotBits)
if err != nil {
return PciSlot{}, err
}
// The 5 bit width passed to ParseUint ensures the value is <=
// maxPciSlot
return PciSlot{slot: uint8(v)}, nil
}
func PciSlotFromInt(v int) (PciSlot, error) {
if v < 0 || v > maxPciSlot {
return PciSlot{}, fmt.Errorf("PCI slot 0x%x should be in range [0..0x%x]", v, maxPciSlot)
}
return PciSlot{slot: uint8(v)}, nil
}
func (slot PciSlot) String() string {
return fmt.Sprintf("%02x", slot.slot)
}
// A PciPath describes where a PCI sits in a PCI hierarchy.
//
// Consists of a list of PCI slots, giving the slot of each bridge
// that must be traversed from the PCI root to reach the device,
// followed by the slot of the device itself
//
// When formatted into a string is written as "xx/.../yy/zz" Here, zz
// is the slot of the device on its PCI bridge, yy is the slot of the
// bridge on its parent bridge and so forth until xx is the slot of
// the "most upstream" bridge on the root bus. If a device is
// connected directly to the root bus, its PciPath is just "zz"
type PciPath struct {
slots []PciSlot
}
func (p PciPath) String() string {
tokens := make([]string, len(p.slots))
for i, slot := range p.slots {
tokens[i] = slot.String()
}
return strings.Join(tokens, "/")
}
func (p PciPath) IsNil() bool {
return p.slots == nil
}
func PciPathFromString(s string) (PciPath, error) {
if s == "" {
return PciPath{}, nil
}
tokens := strings.Split(s, "/")
slots := make([]PciSlot, len(tokens))
for i, t := range tokens {
var err error
slots[i], err = PciSlotFromString(t)
if err != nil {
return PciPath{}, err
}
}
return PciPath{slots: slots}, nil
}
func PciPathFromSlots(slots ...PciSlot) (PciPath, error) {
if len(slots) == 0 {
return PciPath{}, fmt.Errorf("PCI path needs at least one component")
}
return PciPath{slots: slots}, nil
}

View File

@ -0,0 +1,110 @@
// Copyright Red Hat.
//
// SPDX-License-Identifier: Apache-2.0
//
package types
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPciSlot(t *testing.T) {
assert := assert.New(t)
// Valid slots
slot, err := PciSlotFromInt(0x00)
assert.NoError(err)
assert.Equal(slot, PciSlot{})
assert.Equal(slot.String(), "00")
slot, err = PciSlotFromString("00")
assert.NoError(err)
assert.Equal(slot, PciSlot{})
slot, err = PciSlotFromInt(31)
assert.NoError(err)
slot2, err := PciSlotFromString("1f")
assert.NoError(err)
assert.Equal(slot, slot2)
// Bad slots
_, err = PciSlotFromInt(-1)
assert.Error(err)
_, err = PciSlotFromInt(32)
assert.Error(err)
_, err = PciSlotFromString("20")
assert.Error(err)
_, err = PciSlotFromString("xy")
assert.Error(err)
_, err = PciSlotFromString("00/")
assert.Error(err)
_, err = PciSlotFromString("")
assert.Error(err)
}
func TestPciPath(t *testing.T) {
assert := assert.New(t)
slot3, err := PciSlotFromInt(0x03)
assert.NoError(err)
slot4, err := PciSlotFromInt(0x04)
assert.NoError(err)
slot5, err := PciSlotFromInt(0x05)
assert.NoError(err)
// Empty/nil paths
pcipath := PciPath{}
assert.True(pcipath.IsNil())
pcipath, err = PciPathFromString("")
assert.NoError(err)
assert.True(pcipath.IsNil())
assert.Equal(pcipath, PciPath{})
// Valid paths
pcipath, err = PciPathFromSlots(slot3)
assert.NoError(err)
assert.False(pcipath.IsNil())
assert.Equal(pcipath.String(), "03")
pcipath2, err := PciPathFromString("03")
assert.NoError(err)
assert.Equal(pcipath, pcipath2)
pcipath, err = PciPathFromSlots(slot3, slot4)
assert.NoError(err)
assert.False(pcipath.IsNil())
assert.Equal(pcipath.String(), "03/04")
pcipath2, err = PciPathFromString("03/04")
assert.NoError(err)
assert.Equal(pcipath, pcipath2)
pcipath, err = PciPathFromSlots(slot3, slot4, slot5)
assert.NoError(err)
assert.False(pcipath.IsNil())
assert.Equal(pcipath.String(), "03/04/05")
pcipath2, err = PciPathFromString("03/04/05")
assert.NoError(err)
assert.Equal(pcipath, pcipath2)
// Bad paths
_, err = PciPathFromSlots()
assert.Error(err)
_, err = PciPathFromString("20")
assert.Error(err)
_, err = PciPathFromString("//")
assert.Error(err)
_, err = PciPathFromString("xyz")
assert.Error(err)
}

View File

@ -39,6 +39,7 @@ import (
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/uuid"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// romFile is the file name of the ROM that can be used for virtio-pci devices.
@ -1288,8 +1289,18 @@ func (q *qemu) hotplugAddBlockDevice(drive *config.BlockDrive, op operation, dev
}
}()
// PCI address is in the format bridge-addr/device-addr eg. "03/02"
drive.PCIAddr = fmt.Sprintf("%02x", bridge.Addr) + "/" + addr
bridgeSlot, err := vcTypes.PciSlotFromInt(bridge.Addr)
if err != nil {
return err
}
devSlot, err := vcTypes.PciSlotFromString(addr)
if err != nil {
return err
}
drive.PCIPath, err = vcTypes.PciPathFromSlots(bridgeSlot, devSlot)
if err != nil {
return err
}
if err = q.qmpMonitorCh.qmp.ExecutePCIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, addr, bridge.ID, romFile, 0, true, defaultDisableModern); err != nil {
return err
@ -1340,8 +1351,15 @@ func (q *qemu) hotplugAddVhostUserBlkDevice(vAttr *config.VhostUserDeviceAttrs,
}
}()
// PCI address is in the format bridge-addr/device-addr eg. "03/02"
vAttr.PCIAddr = fmt.Sprintf("%02x", bridge.Addr) + "/" + addr
bridgeSlot, err := vcTypes.PciSlotFromInt(bridge.Addr)
if err != nil {
return err
}
devSlot, err := vcTypes.PciSlotFromString(addr)
if err != nil {
return err
}
vAttr.PCIPath, err = vcTypes.PciPathFromSlots(bridgeSlot, devSlot)
if err = q.qmpMonitorCh.qmp.ExecutePCIVhostUserDevAdd(q.qmpMonitorCh.ctx, driver, devID, vAttr.DevID, addr, bridge.ID); err != nil {
return err
@ -1546,8 +1564,16 @@ func (q *qemu) hotplugNetDevice(endpoint Endpoint, op operation) (err error) {
}
}()
pciAddr := fmt.Sprintf("%02x/%s", bridge.Addr, addr)
endpoint.SetPciAddr(pciAddr)
bridgeSlot, err := vcTypes.PciSlotFromInt(bridge.Addr)
if err != nil {
return err
}
devSlot, err := vcTypes.PciSlotFromString(addr)
if err != nil {
return err
}
pciPath, err := vcTypes.PciPathFromSlots(bridgeSlot, devSlot)
endpoint.SetPciPath(pciPath)
var machine govmmQemu.Machine
machine, err = q.getQemuMachine()

View File

@ -850,7 +850,7 @@ func (s *Sandbox) AddInterface(inf *pbTypes.Interface) (*pbTypes.Interface, erro
}
// Add network for vm
inf.PciAddr = endpoint.PciAddr()
inf.PciPath = endpoint.PciPath().String()
return s.agent.updateInterface(inf)
}

View File

@ -13,6 +13,7 @@ import (
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/uuid"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// TapEndpoint represents just a tap endpoint
@ -20,7 +21,7 @@ type TapEndpoint struct {
TapInterface TapInterface
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
PCIPath vcTypes.PciPath
RxRateLimiter bool
TxRateLimiter bool
}
@ -45,14 +46,14 @@ func (endpoint *TapEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *TapEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *TapEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *TapEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *TapEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.

View File

@ -14,6 +14,7 @@ import (
"github.com/vishvananda/netlink"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// TuntapEndpoint represents just a tap endpoint
@ -22,7 +23,7 @@ type TuntapEndpoint struct {
TuntapInterface TuntapInterface
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
PCIPath vcTypes.PciPath
RxRateLimiter bool
TxRateLimiter bool
}
@ -47,14 +48,14 @@ func (endpoint *TuntapEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *TuntapEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *TuntapEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *TuntapEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *TuntapEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.

View File

@ -10,6 +10,7 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// VethEndpoint gathers a network pair and its properties.
@ -17,7 +18,7 @@ type VethEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
PCIPath vcTypes.PciPath
RxRateLimiter bool
TxRateLimiter bool
}
@ -67,14 +68,14 @@ func (endpoint *VethEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *VethEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *VethEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *VethEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *VethEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.

View File

@ -13,6 +13,7 @@ import (
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/config"
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
)
// Long term, this should be made more configurable. For now matching path
@ -30,7 +31,7 @@ type VhostUserEndpoint struct {
IfaceName string
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
PCIPath vcTypes.PciPath
}
// Properties returns the properties of the interface.
@ -58,14 +59,14 @@ func (endpoint *VhostUserEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *VhostUserEndpoint) PciAddr() string {
return endpoint.PCIAddr
// PciPath returns the PCI path of the endpoint.
func (endpoint *VhostUserEndpoint) PciPath() vcTypes.PciPath {
return endpoint.PCIPath
}
// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *VhostUserEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
// SetPciPath sets the PCI path of the endpoint.
func (endpoint *VhostUserEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
endpoint.PCIPath = pciPath
}
// NetworkPair returns the network pair of the endpoint.
@ -156,7 +157,7 @@ func (endpoint *VhostUserEndpoint) save() persistapi.NetworkEndpoint {
Type: string(endpoint.Type()),
VhostUser: &persistapi.VhostUserEndpoint{
IfaceName: endpoint.IfaceName,
PCIAddr: endpoint.PCIAddr,
PCIPath: endpoint.PCIPath,
},
}
}
@ -166,7 +167,7 @@ func (endpoint *VhostUserEndpoint) load(s persistapi.NetworkEndpoint) {
if s.VhostUser != nil {
endpoint.IfaceName = s.VhostUser.IfaceName
endpoint.PCIAddr = s.VhostUser.PCIAddr
endpoint.PCIPath = s.VhostUser.PCIPath
}
}