blob: 12fc20e15863a0f6d6b0f5cf3e11141ead777980 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![cfg(test)]
use assert_matches::assert_matches;
use fidl_fuchsia_hardware_network as fhardware_network;
use fidl_fuchsia_net as fnet;
use fidl_fuchsia_net_debug as fnet_debug;
use fidl_fuchsia_net_interfaces_admin as fnet_interfaces_admin;
use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext;
use futures::TryStreamExt as _;
use net_declare::fidl_mac;
use netstack_testing_common::{
devices::{create_tun_device, create_tun_port, install_device},
realms::{Netstack, Netstack2, TestRealmExt as _, TestSandboxExt as _},
};
use netstack_testing_macros::variants_test;
async fn get_loopback_id(realm: &netemul::TestRealm<'_>) -> u64 {
let fnet_interfaces_ext::Properties {
id,
name: _,
device_class: _,
online: _,
addresses: _,
has_default_ipv4_route: _,
has_default_ipv6_route: _,
} = realm.loopback_properties().await.expect("loopback properties").expect("loopback missing");
id
}
#[fuchsia::test]
async fn get_admin_unknown() {
// TODO(https://fxbug.dev/88797): Test against Netstack3.
type N = Netstack2;
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<N, _>("get_admin_unknown").expect("create realm");
let id = get_loopback_id(&realm).await;
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
// Request unknown NIC ID, expect request channel to be closed.
let (admin_control, server_end) =
fidl::endpoints::create_proxy::<fnet_interfaces_admin::ControlMarker>()
.expect("create proxy");
let () = debug_interfaces.get_admin(id + 1, server_end).expect("get admin failed");
assert_matches!(
admin_control.take_event_stream().try_collect::<Vec<_>>().await.as_ref().map(Vec::as_slice),
// TODO(https://fxbug.dev/8018): Sending epitaphs not supported in Go.
// TODO(https://fxbug.dev/88797): Verify epitaph from Nestack3 (Rust).
Ok([])
);
}
#[fuchsia::test]
async fn get_admin_loopback() {
// TODO(https://fxbug.dev/88797): Test against Netstack3.
type N = Netstack2;
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<N, _>("get_admin_loopback").expect("create realm");
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
let (admin_control, server_end) =
fidl::endpoints::create_proxy::<fnet_interfaces_admin::ControlMarker>()
.expect("create proxy");
let id = get_loopback_id(&realm).await;
debug_interfaces.get_admin(id, server_end).expect("get admin failed");
// Actuate the admin API to verify it's hooked up correctly.
assert_eq!(admin_control.get_id().await.expect("get id"), id);
}
#[variants_test]
async fn get_admin_netemul_endpoint<E: netemul::Endpoint>(name: &str) {
// TODO(https://fxbug.dev/88797): Test against Netstack3.
type N = Netstack2;
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<N, _>(name).expect("create realm");
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
let device = sandbox.create_endpoint::<E, _>(name).await.expect("create netemul endpoint");
// Retain `_control` and `_device_control` to keep the FIDL channel open.
let (id, _control, _device_control) = device
.add_to_stack(&realm, netemul::InterfaceConfig::default())
.await
.expect("add to stack");
let (admin_control, server_end) =
fidl::endpoints::create_proxy::<fnet_interfaces_admin::ControlMarker>()
.expect("create proxy");
debug_interfaces.get_admin(id, server_end).expect("get admin failed");
// Actuate the admin API to verify it's hooked up correctly.
assert_eq!(admin_control.get_id().await.expect("get id"), id);
}
// Retrieve the MAC address for the given device id, expecting no FIDL errors.
//
// This helper extracts the MAC from its `Box` making matching easier. See
// https://doc.rust-lang.org/beta/unstable-book/language-features/box-patterns.html.
async fn get_mac(
id: u64,
debug_interfaces: &fnet_debug::InterfacesProxy,
) -> Result<Option<fnet::MacAddress>, fnet_debug::InterfacesGetMacError> {
let mac = debug_interfaces.get_mac(id).await.expect("get mac");
mac.map(|option| option.map(|box_| *box_))
}
#[variants_test]
async fn get_mac_not_found<N: Netstack>(name: &str) {
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<N, _>(name).expect("create realm");
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
let loopback_id = get_loopback_id(&realm).await;
// Unknown device ID produces an error.
assert_matches!(
get_mac(loopback_id + 1, &debug_interfaces).await,
Err(fnet_debug::InterfacesGetMacError::NotFound)
);
}
#[variants_test]
async fn get_mac_loopback<N: Netstack>(name: &str) {
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<N, _>(name).expect("create realm");
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
let loopback_id = get_loopback_id(&realm).await;
// Loopback has the all-zero MAC address.
assert_matches!(
get_mac(loopback_id, &debug_interfaces).await,
Ok(Some(fnet::MacAddress { octets: [0, 0, 0, 0, 0, 0] }))
);
}
// Add a pure IP interface to the given device/port, returning the created
// `fuchsia.net.interfaces.admin/Control` handle.
async fn add_pure_ip_interface(
network_port: &fhardware_network::PortProxy,
admin_device_control: &fnet_interfaces_admin::DeviceControlProxy,
interface_name: &str,
) -> fnet_interfaces_admin::ControlProxy {
let fhardware_network::PortInfo { id, .. } = network_port.get_info().await.expect("get info");
let mut port_id = id.expect("port id");
let (admin_control, server_end) =
fidl::endpoints::create_proxy::<fnet_interfaces_admin::ControlMarker>()
.expect("create proxy");
let () = admin_device_control
.create_interface(
&mut port_id,
server_end,
fnet_interfaces_admin::Options {
name: Some(interface_name.to_string()),
..fnet_interfaces_admin::Options::EMPTY
},
)
.expect("create interface");
admin_control
}
// TODO(https://fxbug.dev/100871): Parameterize by Netstack to test NS3.
#[fuchsia::test]
async fn get_mac_pure_ip() {
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<Netstack2, _>("get_mac").expect("create realm");
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
const PORT_ID: u8 = 7; // Arbitrary nonzero to avoid masking default value assumptions.
const INTERFACE_NAME: &str = "ihazmac";
let (tun_device, network_device) = create_tun_device();
let admin_device_control = install_device(&realm, network_device);
// Retain `_tun_port` to keep the FIDL channel open.
let (_tun_port, network_port) = create_tun_port(&tun_device, Some(PORT_ID)).await;
let admin_control =
add_pure_ip_interface(&network_port, &admin_device_control, INTERFACE_NAME).await;
let virtual_id = admin_control.get_id().await.expect("get id");
// Pure IP interfaces do not have MAC addresses.
assert_matches!(get_mac(virtual_id, &debug_interfaces).await, Ok(None));
}
#[variants_test]
async fn get_mac_netemul_endpoint<N: Netstack, E: netemul::Endpoint>(name: &str) {
let sandbox = netemul::TestSandbox::new().expect("create sandbox");
let realm = sandbox.create_netstack_realm::<N, _>(name).expect("create realm");
let debug_interfaces =
realm.connect_to_protocol::<fnet_debug::InterfacesMarker>().expect("connect to protocol");
const DEFAULT_MAC: fnet::MacAddress = fidl_mac!("00:03:00:00:00:00");
let device = sandbox
.create_endpoint_with("get_mac", E::make_config(netemul::DEFAULT_MTU, Some(DEFAULT_MAC)))
.await
.expect("create netemul endpoint");
// Retain `_control` and `_device_control` to keep the FIDL channel open.
let (id, _control, _device_control) = device
.add_to_stack(&realm, netemul::InterfaceConfig::default())
.await
.expect("add to stack");
assert_matches!(get_mac(id.into(), &debug_interfaces).await, Ok(Some(DEFAULT_MAC)));
}