-
-
Notifications
You must be signed in to change notification settings - Fork 170
SNP Integration Test: Improve Clarity #1621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2decf67
9236836
88ee82c
51fce1f
de58824
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,82 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
|
||
use core::time::Duration; | ||
|
||
use core::ops::DerefMut; | ||
use uefi::proto::device_path::DevicePath; | ||
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly}; | ||
use uefi::proto::network::MacAddress; | ||
use uefi::proto::network::snp::{InterruptStatus, ReceiveFlags, SimpleNetwork}; | ||
use uefi::proto::network::snp::{InterruptStatus, NetworkState, ReceiveFlags, SimpleNetwork}; | ||
use uefi::{Status, boot}; | ||
|
||
const ETHERNET_PROTOCOL_IPV4: u16 = 0x0800; | ||
|
||
/// Receives the next IPv4 packet and prints corresponding metadata. | ||
fn receive(simple_network: &mut SimpleNetwork, buffer: &mut [u8]) -> uefi::Result<usize> { | ||
let mut recv_src_mac = MacAddress([0; 32]); | ||
let mut recv_dst_mac = MacAddress([0; 32]); | ||
let mut recv_ethernet_protocol = 0; | ||
|
||
let res = simple_network.receive( | ||
buffer, | ||
None, | ||
Some(&mut recv_src_mac), | ||
Some(&mut recv_dst_mac), | ||
Some(&mut recv_ethernet_protocol), | ||
); | ||
|
||
res.inspect(|_| { | ||
debug!("Received:"); | ||
debug!(" src_mac = {:x?}", recv_src_mac); | ||
debug!(" dst_mac = {:x?}", recv_dst_mac); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now a fixed value right? So let's assert that it matches |
||
debug!(" ethernet_proto=0x{:x?}", recv_ethernet_protocol); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is asserted below so no need to print. (In general, I would like to stick to asserting rather than printing as much as possible in tests, because 99% of the time we're not going to look that carefully at the output and won't notice if something doesn't match expectations. For ad-hoc debugging it's easy enough to throw a log line in while working on the code.) |
||
|
||
// Ensure that we do not accidentally get an ARP packet, which we | ||
// do not expect in this test. | ||
assert_eq!(recv_ethernet_protocol, ETHERNET_PROTOCOL_IPV4); | ||
}) | ||
} | ||
|
||
/// This test sends a simple UDP/IP packet to the `EchoService` (created by | ||
/// `cargo xtask run`) and receives its message. | ||
pub fn test() { | ||
info!("Testing the simple network protocol"); | ||
|
||
let handles = boot::find_handles::<SimpleNetwork>().unwrap_or_default(); | ||
|
||
for handle in handles { | ||
let simple_network = boot::open_protocol_exclusive::<SimpleNetwork>(handle); | ||
if simple_network.is_err() { | ||
let Ok(mut simple_network) = boot::open_protocol_exclusive::<SimpleNetwork>(handle) else { | ||
continue; | ||
}; | ||
// Print device path | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not clear on why it's useful to see the device path for the network interface. |
||
{ | ||
let simple_network_dvp = boot::open_protocol_exclusive::<DevicePath>(handle) | ||
.expect("Should have device path"); | ||
log::info!( | ||
"Network interface: {}", | ||
simple_network_dvp | ||
.to_string(DisplayOnly(true), AllowShortcuts(true)) | ||
.unwrap() | ||
); | ||
} | ||
let simple_network = simple_network.unwrap(); | ||
|
||
// Check shutdown | ||
let res = simple_network.shutdown(); | ||
assert!(res == Ok(()) || res == Err(Status::NOT_STARTED.into())); | ||
assert_eq!( | ||
simple_network.mode().state, | ||
NetworkState::STOPPED, | ||
"Should be in stopped state" | ||
); | ||
|
||
// Check stop | ||
let res = simple_network.stop(); | ||
assert!(res == Ok(()) || res == Err(Status::NOT_STARTED.into())); | ||
// Check media | ||
if !bool::from(simple_network.mode().media_present_supported) | ||
|| !bool::from(simple_network.mode().media_present) | ||
{ | ||
continue; | ||
} | ||
|
||
// Check start | ||
simple_network | ||
.start() | ||
.expect("Failed to start Simple Network"); | ||
.expect("Network should not be started yet"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
// Check initialize | ||
simple_network | ||
.initialize(0, 0) | ||
.expect("Failed to initialize Simple Network"); | ||
.expect("Network should not be initialized yet"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, |
||
|
||
// edk2 virtio-net driver does not support statistics, so | ||
// allow UNSUPPORTED (same for collect_statistics below). | ||
|
@@ -54,13 +96,12 @@ pub fn test() { | |
) | ||
.expect("Failed to set receive filters"); | ||
|
||
// Check media | ||
if !bool::from(simple_network.mode().media_present_supported) | ||
|| !bool::from(simple_network.mode().media_present) | ||
{ | ||
continue; | ||
} | ||
|
||
// EthernetFrame(IPv4Packet(UDPPacket(Payload))). | ||
// The ethernet frame header will be filled by `transmit()`. | ||
// The UDP packet contains the byte sequence `4, 4, 3, 2, 1`. | ||
// | ||
// The packet is sent to the `EchoService` created by | ||
// `cargo xtask run`. It runs on UDP port 21572. | ||
let payload = b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ | ||
\x45\x00\ | ||
\x00\x21\ | ||
|
@@ -77,7 +118,6 @@ pub fn test() { | |
\xa9\xe4\ | ||
\x04\x01\x02\x03\x04"; | ||
|
||
let dest_addr = MacAddress([0xffu8; 32]); | ||
assert!( | ||
!simple_network | ||
.get_interrupt_status() | ||
|
@@ -91,8 +131,8 @@ pub fn test() { | |
simple_network.mode().media_header_size as usize, | ||
payload, | ||
None, | ||
Some(dest_addr), | ||
Some(0x0800), | ||
Some(simple_network.mode().broadcast_address), | ||
Some(ETHERNET_PROTOCOL_IPV4), | ||
) | ||
.expect("Failed to transmit frame"); | ||
|
||
|
@@ -107,16 +147,10 @@ pub fn test() { | |
let mut buffer = [0u8; 1500]; | ||
|
||
info!("Waiting for the reception"); | ||
if simple_network.receive(&mut buffer, None, None, None, None) | ||
== Err(Status::NOT_READY.into()) | ||
{ | ||
boot::stall(Duration::from_secs(1)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we sure this stall is no longer needed? I'm guessing it was added because sometimes the interface isn't ready yet, although I'm not clear on the details from a quick look at the commit history. |
||
|
||
simple_network | ||
.receive(&mut buffer, None, None, None, None) | ||
.unwrap(); | ||
} | ||
let n = receive(simple_network.deref_mut(), &mut buffer).unwrap(); | ||
debug!("Reply has {n} bytes"); | ||
|
||
// Check payload in UDP packet that was reversed by our EchoService. | ||
assert_eq!(buffer[42..47], [4, 4, 3, 2, 1]); | ||
|
||
// Get stats | ||
|
@@ -137,5 +171,7 @@ pub fn test() { | |
} | ||
} | ||
} | ||
|
||
simple_network.shutdown().unwrap(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's change this to disabling at runtime like how
pxe.rs
did it before this PR --if cfg!(feature = "pxe") { ... }
. That way, we always get a compilation test, even when we're not running the code.