#[allow(missing_debug_implementations)]
#[allow(dead_code)]
pub struct EthernetPortInformation
{
ethernetPortIdentifier: EthernetPortIdentifier,
ethernetPort: EthernetPort,
driverName: String,
deviceInformation: rte_eth_dev_info,
underlyingEthernetDevice: rte_eth_dev,
requiresIntelI40eEightFragmentsWorkaround: bool,
requiresVmWareVmxNet3SixteenFragmentsWorkaround: bool,
parentNumaSocketId: Option<NumaSocketId>,
maximumNumberOfReceiveThenTransmitQueuePairs: u16,
receiveSideScalingRetaIndirectionTableNumberOfBits_and_supportedReceiveSideScalingHashKeySize: Option<(PowerOfTwoSixteenBit, ReceiveSideScalingHashKeySize)>,
logicalCoreUser: LogicalCoreUser,
supportedFilterTypes: HashSet<FilterType>,
deviceReceiveOffloadCapabilities: DeviceReceiveOffloadCapabilities,
deviceTransmitOffloadCapabilities: DeviceTransmitOffloadCapabilities,
receiveLargeReceiveOffloadSupported: bool, receiveIpV4TcpAndUdpChecksumOffloadSupported: bool,
transmitTcpSegmentationOffloadSupported: bool, transmitUdpSegmentationOffloadSupported: bool, transmitIpV4ChecksumOffloadSupported: bool,
transmitTcpAndUdpChecksumOffloadSupported: bool,
deviceName: String,
dataCentreBridgingInformation: Option<rte_eth_dcb_info>,
eepromSize: Option<u31>,
eepromInformation: Option<EepromInformation>,
deviceRegisters: Option<(u32, u32, u32, Vec<u8>)>,
}
impl EthernetPortInformation
{
#[inline(always)]
pub fn underlyingEthernetDevice(&self) -> &rte_eth_dev
{
&self.underlyingEthernetDevice
}
#[inline(always)]
pub fn deviceName(&self) -> &str
{
&self.deviceName
}
#[inline(always)]
pub fn portIdentifier(&self) -> EthernetPortIdentifier
{
self.ethernetPortIdentifier
}
#[inline(always)]
pub fn mediaAccessControlAddress(&self) -> MediaAccessControlAddress
{
self.ethernetPort().getDefaultMediaAccessControlAddress()
}
#[inline(always)]
pub fn ethernetPort(&self) -> &EthernetPort
{
&self.ethernetPort
}
#[inline(always)]
pub fn useLogicalCoreUser(&mut self) -> &mut LogicalCoreUser
{
&mut self.logicalCoreUser
}
#[inline(always)]
pub fn waitUntilLinkIsUp(&self) -> Result<LinkStatus, ()>
{
self.ethernetPort.linkStatusWaitingUpToNineSeconds()
}
#[inline(always)]
pub fn receiveIpV4TcpAndUdpChecksumOffloadSupported(&self) -> bool
{
self.receiveIpV4TcpAndUdpChecksumOffloadSupported
}
#[inline(always)]
pub fn createReceiveQueueConfigurations(&self, receiveQueueConfigurationTemplate: &ReceiveQueueConfiguration) -> ArrayVec<[ReceiveQueueConfiguration; MaximumReceiveQueues]>
{
let size = self.logicalCoreUser.numberOfReceiveThenTransmitQueuePairs() as usize;
let mut receiveQueueConfigurations = ArrayVec::new();
for _ in 0..size
{
receiveQueueConfigurations.push(receiveQueueConfigurationTemplate.clone());
}
receiveQueueConfigurations
}
#[inline(always)]
pub fn createTransmitQueueConfigurations(&self, transmitQueueConfigurationTemplate: &TransmitQueueConfiguration) -> ArrayVec<[TransmitQueueConfiguration; MaximumTransmitQueues]>
{
let size = self.logicalCoreUser.numberOfReceiveThenTransmitQueuePairs() as usize;
let mut transmitQueueConfigurations = ArrayVec::new();
for _ in 0..size
{
transmitQueueConfigurations.push(transmitQueueConfigurationTemplate.clone());
}
transmitQueueConfigurations
}
#[inline(always)]
pub fn logicalCoreFor(&self, queueIdentifier: QueueIdentifier) -> LogicalCore
{
*(self.logicalCoreUser.logicalCore(queueIdentifier).unwrap())
}
#[inline(always)]
pub fn startProcessingQueuePairs<Creator: ExecutionRoutineCreatorCreator<D, EC>, D, EC: ExecutionRoutineCreator>(&self, executionRoutineCreatorCreator: &Creator, data: Arc<D>)
-> Arc<Mutex<ExecutionRoutineGroup<ReceiveTransmitQueuePairSlaveLogicalCoreTask<EC>>>>
{
debug_assert!(LogicalCore::isCurrentMaster(), "Can not call tasks() on a slave logical core");
let taskCount = self.logicalCoreUser.numberOfReceiveThenTransmitQueuePairs() as usize;
let executionRoutineGroupWrapped = ExecutionRoutineGroup::new(taskCount);
{
let mut executionRoutineGroup = executionRoutineGroupWrapped.lock().unwrap();
for queueIdentifier in 0..(taskCount as QueueIdentifier)
{
let slaveLogicalCoreToExecuteOn = self.logicalCoreFor(queueIdentifier);
let task = ReceiveTransmitQueuePairSlaveLogicalCoreTask::new(executionRoutineGroup.canContinueClone(), executionRoutineGroupWrapped.clone(), executionRoutineCreatorCreator, data.clone(), queueIdentifier, slaveLogicalCoreToExecuteOn, self);
executionRoutineGroup.pushAndRunOnSlave(task);
}
}
executionRoutineGroupWrapped
}
#[inline(always)]
pub fn adjustConfiguration<'a, ReceiveSideScalingHashChooser: Fn(u16, ReceiveSideScalingHashKeySize, &'a str, &'a str) -> (Option<HashFilter>, ReceiveSideScalingHashFunctionConfiguration)>(&'a self, configuration: &mut EthernetPortConfiguration, receiveSideScalingHashChooser: &ReceiveSideScalingHashChooser)
{
self.adjustReceiveSideScalingConfiguration(configuration, receiveSideScalingHashChooser);
let receiveModeConfiguration = &mut configuration.receiveModeConfiguration;
self.adjustLargeReceiveOffloadConfiguration(receiveModeConfiguration);
self.adjustReceiveVlanStripping(receiveModeConfiguration);
Self::enableHardwareCrcStripping(receiveModeConfiguration);
self.adjustReceiveChecksumOffloadingConfiguration(receiveModeConfiguration);
}
#[inline(always)]
fn adjustReceiveSideScalingConfiguration<'a, ReceiveSideScalingHashChooser: Fn(u16, ReceiveSideScalingHashKeySize, &'a str, &'a str) -> (Option<HashFilter>, ReceiveSideScalingHashFunctionConfiguration)>(&'a self, configuration: &mut EthernetPortConfiguration, receiveSideScalingHashChooser: &ReceiveSideScalingHashChooser)
{
let numberOfReceiveThenTransmitQueuePairs = self.logicalCoreUser.numberOfReceiveThenTransmitQueuePairs();
assert!(numberOfReceiveThenTransmitQueuePairs != 0, "numberOfReceiveThenTransmitQueuePairs can not be zero");
configuration.restrictNumberOfQueuePairsToMaximum(numberOfReceiveThenTransmitQueuePairs);
let receiveModeConfiguration = &mut configuration.receiveModeConfiguration;
if self.receiveSideScalingRetaIndirectionTableNumberOfBits_and_supportedReceiveSideScalingHashKeySize.is_none() || numberOfReceiveThenTransmitQueuePairs == 1
{
receiveModeConfiguration.disableReceiveSideScaling();
configuration.receiveSideScalingHashFunctionConfiguration = ReceiveSideScalingHashFunctionConfiguration::NoneEthernetDeviceDefault;
configuration.receiveSideScalingHashFilter = None;
configuration.receiveSideScalingRetaIndirectionTable = None;
}
else
{
let (receiveSideScalingRetaIndirectionTableNumberOfBits, supportedReceiveSideScalingHashKeySize) = self.receiveSideScalingRetaIndirectionTableNumberOfBits_and_supportedReceiveSideScalingHashKeySize.unwrap();
let (receiveSideScalingHashFilter, receiveSideScalingHashFunctionConfiguration) = receiveSideScalingHashChooser(numberOfReceiveThenTransmitQueuePairs, supportedReceiveSideScalingHashKeySize, &self.driverName, &self.deviceName);
receiveModeConfiguration.enableReceiveSideScaling();
configuration.receiveSideScalingHashFunctionConfiguration = receiveSideScalingHashFunctionConfiguration;
configuration.receiveSideScalingHashFilter = receiveSideScalingHashFilter;
configuration.receiveSideScalingRetaIndirectionTable = Some(ReceiveSideScalingRetaIndirectionTable::new(receiveSideScalingRetaIndirectionTableNumberOfBits, numberOfReceiveThenTransmitQueuePairs));
}
}
#[inline(always)]
fn adjustLargeReceiveOffloadConfiguration(&self, receiveModeConfiguration: &mut EthernetPortReceiveModeConfiguration)
{
if self.receiveLargeReceiveOffloadSupported
{
receiveModeConfiguration.enableTcpLargeReceiveOffload()
}
else
{
receiveModeConfiguration.disableTcpLargeReceiveOffload()
}
}
#[inline(always)]
fn adjustReceiveVlanStripping(&self, receiveModeConfiguration: &mut EthernetPortReceiveModeConfiguration)
{
if self.deviceReceiveOffloadCapabilities.supportsVlanOrQinQStripping()
{
receiveModeConfiguration.enableHardwareVlanStripping()
}
else
{
receiveModeConfiguration.disableHardwareVlanStripping()
}
}
#[inline(always)]
fn enableHardwareCrcStripping(receiveModeConfiguration: &mut EthernetPortReceiveModeConfiguration)
{
receiveModeConfiguration.enableHardwareCyclicRedundancyChecksumStripping()
}
#[inline(always)]
fn adjustReceiveChecksumOffloadingConfiguration(&self, receiveModeConfiguration: &mut EthernetPortReceiveModeConfiguration)
{
if self.receiveIpV4TcpAndUdpChecksumOffloadSupported
{
receiveModeConfiguration.enableIpV4TcpAndUdpChecksumOffload()
}
else
{
receiveModeConfiguration.disableIpV4TcpAndUdpChecksumOffload()
}
}
#[inline(always)]
pub fn new_default_rxconf(&self) -> rte_eth_rxconf
{
self.deviceInformation.default_rxconf
}
#[inline(always)]
pub fn new_default_txconf(&self) -> rte_eth_txconf
{
self.deviceInformation.default_txconf
}
#[inline(always)]
pub fn new
(
ethernetPort: EthernetPort,
deviceInformation: rte_eth_dev_info,
underlyingEthernetDevice: rte_eth_dev,
deviceName: String,
parentNumaSocketId: Option<NumaSocketId>,
supportedFilterTypes: HashSet<FilterType>,
dataCentreBridgingInformation: Option<rte_eth_dcb_info>,
eepromSize: Option<u31>,
eepromInformation: Option<EepromInformation>,
deviceRegisters: Option<(u32, u32, u32, Vec<u8>)>) -> Self
{
let driverName = unsafe { CStr::from_ptr(deviceInformation.driver_name) }.to_str().expect("deviceInformation.driver_name contains non-Unicode data");
let deviceReceiveOffloadCapabilities = DeviceReceiveOffloadCapabilities::from_bits(deviceInformation.rx_offload_capa).expect("Unsupported rx_offload_capa value");
let deviceTransmitOffloadCapabilities = DeviceTransmitOffloadCapabilities::from_bits(deviceInformation.tx_offload_capa).expect("Unsupported tx_offload_capa value");
fn deviceMaximumReceiveQueuesInclusive(deviceInformation: &rte_eth_dev_info, deviceName: &str) -> u16
{
let deviceMaximumReceiveQueuesInclusive = deviceInformation.max_rx_queues;
assert!(deviceMaximumReceiveQueuesInclusive != 0, "deviceMaximumReceiveQueuesInclusive is zero; this shouldn't be possible but makes this device '{}' useless", deviceName);
assert!(deviceMaximumReceiveQueuesInclusive <= MaximumReceiveQueues as u16, "deviceMaximumReceiveQueuesInclusive '{}' exceeds MaximumReceiveQueues '{}' device '{}'", deviceMaximumReceiveQueuesInclusive, MaximumReceiveQueues, deviceName);
deviceMaximumReceiveQueuesInclusive
}
fn deviceMaximumTransmitQueuesInclusive(deviceInformation: &rte_eth_dev_info, deviceName: &str) -> u16
{
let deviceMaximumTransmitQueuesInclusive = deviceInformation.max_tx_queues;
assert!(deviceMaximumTransmitQueuesInclusive != 0, "deviceMaximumTransmitQueuesInclusive is zero; this shouldn't be possible but makes this device '{}' useless", deviceName);
assert!(deviceMaximumTransmitQueuesInclusive <= MaximumTransmitQueues as u16, "deviceMaximumTransmitQueuesInclusive '{}' exceeds MaximumTransmitQueues '{}' for device '{}'", deviceMaximumTransmitQueuesInclusive, MaximumTransmitQueues, deviceName);
deviceMaximumTransmitQueuesInclusive
}
println!("TODO: Driver name debugging, as we're not sure net_mlx4 is actually rte_mlx4_pmd, etc: '{}'", driverName);
let (requiresIntelI40eEightFragmentsWorkaround, requiresVmWareVmxNet3SixteenFragmentsWorkaround, maximumReceiveQueuesInclusive) = match driverName
{
"rte_i40e_pmd" => (true, false, 64),
"rte_i40evf_pmd" => (true, false, 16),
"rte_ixgbe_pmd" => (false, false, 16),
"rte_ixgbevf_pmd" => (false, false, 4),
"rte_vmxnet3_pmd" => (false, true, deviceMaximumReceiveQueuesInclusive(&deviceInformation, &deviceName)),
_ => (false, false, deviceMaximumReceiveQueuesInclusive(&deviceInformation, &deviceName)),
};
let receiveSideScalingRetaIndirectionTableNumberOfBits = match deviceInformation.reta_size
{
0 => None,
::dpdk_sys::ETH_RSS_RETA_SIZE_64 => Some(PowerOfTwoSixteenBit::_64),
::dpdk_sys::ETH_RSS_RETA_SIZE_128 => Some(PowerOfTwoSixteenBit::_128),
::dpdk_sys::ETH_RSS_RETA_SIZE_256 => Some(PowerOfTwoSixteenBit::_256),
::dpdk_sys::ETH_RSS_RETA_SIZE_512 => Some(PowerOfTwoSixteenBit::_512),
illegal @ _ => panic!("reta_size is not 64, 128, 256 or 512 bits but '{}'; this shouldn't be possible but makes this device '{}' useless", illegal, deviceName),
};
let maximumNumberOfReceiveThenTransmitQueuePairs = if let Some(receiveSideScalingRetaIndirectionTableNumberOfBits) = receiveSideScalingRetaIndirectionTableNumberOfBits
{
min(receiveSideScalingRetaIndirectionTableNumberOfBits as u16, min(maximumReceiveQueuesInclusive, deviceMaximumTransmitQueuesInclusive(&deviceInformation, &deviceName)))
}
else
{
1
};
let receiveSideScalingRetaIndirectionTableNumberOfBits_and_supportedReceiveSideScalingHashKeySize = match ReceiveSideScalingHashKeySize::fromNumberOrPanicAndZeroLengthIsNone(deviceInformation.hash_key_size)
{
Some(supportedReceiveSideScalingHashKeySize) =>
{
assert!(receiveSideScalingRetaIndirectionTableNumberOfBits.is_some(), "device '{}' supports a receive side scaling hash key size but does not support a RETA table", deviceName);
assert!(supportedFilterTypes.contains(&FilterType::Hash), "device '{}' supports a receive side scaling hash key size and a RETA table but does not support a Hash filter", deviceName);
Some((receiveSideScalingRetaIndirectionTableNumberOfBits.unwrap(), supportedReceiveSideScalingHashKeySize))
},
None =>
{
assert!(receiveSideScalingRetaIndirectionTableNumberOfBits.is_none(), "device '{}' does not support a receive side scaling hash key size but DOES support a RETA table", deviceName);
None
},
};
EthernetPortInformation
{
ethernetPortIdentifier: ethernetPort.portIdentifier(),
ethernetPort: ethernetPort,
driverName: driverName.to_owned(),
deviceInformation: deviceInformation,
underlyingEthernetDevice: underlyingEthernetDevice,
requiresIntelI40eEightFragmentsWorkaround: requiresIntelI40eEightFragmentsWorkaround,
requiresVmWareVmxNet3SixteenFragmentsWorkaround: requiresVmWareVmxNet3SixteenFragmentsWorkaround,
parentNumaSocketId: parentNumaSocketId,
maximumNumberOfReceiveThenTransmitQueuePairs: maximumNumberOfReceiveThenTransmitQueuePairs,
receiveSideScalingRetaIndirectionTableNumberOfBits_and_supportedReceiveSideScalingHashKeySize: receiveSideScalingRetaIndirectionTableNumberOfBits_and_supportedReceiveSideScalingHashKeySize,
logicalCoreUser: LogicalCoreUser::new(parentNumaSocketId, maximumNumberOfReceiveThenTransmitQueuePairs as usize),
supportedFilterTypes: supportedFilterTypes,
deviceReceiveOffloadCapabilities: deviceReceiveOffloadCapabilities,
deviceTransmitOffloadCapabilities: deviceTransmitOffloadCapabilities,
receiveLargeReceiveOffloadSupported: deviceReceiveOffloadCapabilities.supportsTcpLargeReceiveOffload(),
receiveIpV4TcpAndUdpChecksumOffloadSupported:
{
debug_assert!(deviceReceiveOffloadCapabilities.supportsIpV4TcpAndUdpChecksumOffload() || deviceReceiveOffloadCapabilities.supportsNoneOfIpV4TcpAndUdpChecksumOffload(), "device '{}' supports a mixture of IPv4, TCP and UDP receive checksum offloading");
deviceReceiveOffloadCapabilities.supportsIpV4TcpAndUdpChecksumOffload()
},
transmitTcpSegmentationOffloadSupported: deviceTransmitOffloadCapabilities.supportsTcpSegmentationOffload(),
transmitUdpSegmentationOffloadSupported: deviceTransmitOffloadCapabilities.supportsUdpSegmentationOffload(),
transmitIpV4ChecksumOffloadSupported: deviceTransmitOffloadCapabilities.supportsIpV4ChecksumOffload(),
transmitTcpAndUdpChecksumOffloadSupported:
{
debug_assert!(deviceTransmitOffloadCapabilities.supportsTcpAndUdpChecksumOffload() || deviceTransmitOffloadCapabilities.supportsNoneOfTcpAndUdpChecksumOffload(), "device '{}' supports a mixture of TCP and UDP transmit checksum offloading");
deviceTransmitOffloadCapabilities.supportsTcpAndUdpChecksumOffload()
},
deviceName: deviceName,
dataCentreBridgingInformation: dataCentreBridgingInformation,
eepromSize: eepromSize,
eepromInformation: eepromInformation,
deviceRegisters: deviceRegisters,
}
}
}