net: report link state to userspace
This commit is contained in:
parent
8db05f304e
commit
b8078561bf
@ -27,37 +27,6 @@ pub struct L2Packet {
|
||||
pub data: Arc<DmaBuffer<[u8]>>,
|
||||
}
|
||||
|
||||
/// Defines an Ethernet link speed
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EthernetSpeed {
|
||||
/// 1Gbps link
|
||||
Speed1000,
|
||||
/// 100Mbps link
|
||||
Speed100,
|
||||
/// 10Mbps link
|
||||
Speed10,
|
||||
/// Link speed not available/unknown
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Defines whether an Ethernet link is capable of transmiting data both ways simultaneously
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Duplex {
|
||||
/// Half-duplex link with multiplexed Tx and Rx
|
||||
Half,
|
||||
/// Full-duplex link capable of simultaneous Tx and Rx
|
||||
Full,
|
||||
/// Duplex mode not available/unknown
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Represents the state of an Ethernet link
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EthernetLinkState {
|
||||
Up(EthernetSpeed, Duplex),
|
||||
Down,
|
||||
}
|
||||
|
||||
impl L2Packet {
|
||||
pub fn ethernet_frame(&self) -> &EthernetFrame {
|
||||
bytemuck::from_bytes(
|
||||
@ -109,39 +78,3 @@ pub fn handle(packet: L2Packet) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EthernetSpeed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let text = match self {
|
||||
Self::Speed10 => "10Mbps",
|
||||
Self::Speed100 => "100Mbps",
|
||||
Self::Speed1000 => "1Gbps",
|
||||
Self::Unknown => "N/A",
|
||||
};
|
||||
f.write_str(text)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Duplex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let text = match self {
|
||||
Self::Half => "half-duplex",
|
||||
Self::Full => "full-duplex",
|
||||
Self::Unknown => "N/A duplex mode",
|
||||
};
|
||||
f.write_str(text)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EthernetLinkState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Up(speed, duplex) => {
|
||||
write!(f, "up, speed {speed}, {duplex}")
|
||||
}
|
||||
Self::Down => {
|
||||
write!(f, "down")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use libk_util::{
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
net::{protocols::EthernetFrame, MacAddress},
|
||||
net::{link::LinkState, protocols::EthernetFrame, MacAddress},
|
||||
};
|
||||
|
||||
use crate::l3::{arp::ArpTable, Route};
|
||||
@ -25,6 +25,9 @@ pub trait NetworkDevice: Sync + Send {
|
||||
fn packet_prefix_size(&self) -> usize;
|
||||
|
||||
fn read_hardware_address(&self) -> MacAddress;
|
||||
fn link_state(&self) -> LinkState {
|
||||
LinkState::Other { up: true }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetworkInterface {
|
||||
@ -101,6 +104,10 @@ impl NetworkInterface {
|
||||
ArpTable::insert_address(self.id, self.mac, address, true);
|
||||
}
|
||||
|
||||
pub fn link_state(&self) -> LinkState {
|
||||
self.device.link_state()
|
||||
}
|
||||
|
||||
pub fn send_l2(&self, l2_frame: &EthernetFrame, l2_data: &[u8]) -> Result<(), Error> {
|
||||
let l2_offset = self.device.packet_prefix_size();
|
||||
let l2_data_offset = l2_offset + size_of::<EthernetFrame>();
|
||||
|
@ -250,6 +250,7 @@ fn describe_interface(interface: &NetworkInterface) -> InterfaceInfo {
|
||||
interface_name: interface.name.clone(),
|
||||
address: interface.address.read().map(Into::into),
|
||||
mac: interface.mac,
|
||||
link: interface.link_state(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ use ygg_driver_pci::{
|
||||
macros::pci_driver,
|
||||
PciBaseAddress, PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::net::MacAddress;
|
||||
use yggdrasil_abi::net::{link::LinkState, MacAddress};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@ -369,6 +369,10 @@ impl NetworkDevice for Igbe {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn link_state(&self) -> LinkState {
|
||||
LinkState::Ethernet(self.regs.lock().read_link())
|
||||
}
|
||||
}
|
||||
|
||||
pci_driver! {
|
||||
|
@ -4,9 +4,11 @@ use core::{cell::UnsafeCell, marker::PhantomData, time};
|
||||
use libk::error::Error;
|
||||
use libk_mm::{address::PhysicalAddress, device::RawDeviceMemoryMapping};
|
||||
use tock_registers::{fields::FieldValue, register_bitfields, LocalRegisterCopy, RegisterLongName};
|
||||
use ygg_driver_net_core::ethernet::{Duplex, EthernetLinkState, EthernetSpeed};
|
||||
use ygg_driver_pci::PciBaseAddress;
|
||||
use yggdrasil_abi::net::MacAddress;
|
||||
use yggdrasil_abi::net::{
|
||||
link::{Duplex, EthernetLinkState, EthernetSpeed},
|
||||
MacAddress,
|
||||
};
|
||||
use TXDCTL::LWTHRESH;
|
||||
|
||||
use crate::{RxRing, TxRing};
|
||||
|
@ -21,12 +21,17 @@ use tock_registers::{
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
};
|
||||
use ygg_driver_net_core::{
|
||||
ethernet::{Duplex, EthernetLinkState, EthernetSpeed},
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
Packet,
|
||||
};
|
||||
use ygg_driver_pci::device::{PciDeviceInfo, PreferredInterruptMode};
|
||||
use yggdrasil_abi::{bitflags, net::MacAddress};
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
net::{
|
||||
link::{Duplex, EthernetLinkState, EthernetSpeed, LinkState},
|
||||
MacAddress,
|
||||
},
|
||||
};
|
||||
|
||||
register_bitfields! {
|
||||
u8,
|
||||
@ -715,6 +720,10 @@ impl NetworkDevice for Rtl8168 {
|
||||
fn read_hardware_address(&self) -> MacAddress {
|
||||
self.mac
|
||||
}
|
||||
|
||||
fn link_state(&self) -> LinkState {
|
||||
LinkState::Ethernet(self.regs.lock().get_link_state())
|
||||
}
|
||||
}
|
||||
|
||||
impl Revision {
|
||||
|
@ -70,11 +70,11 @@ impl Serialize for SocketAddrV6 {
|
||||
}
|
||||
}
|
||||
|
||||
crate::impl_enum_serde!(IpAddr: [
|
||||
crate::impl_enum1_serde!(IpAddr: [
|
||||
V4 => 4,
|
||||
V6 => 6
|
||||
]);
|
||||
crate::impl_enum_serde!(SocketAddr: [
|
||||
crate::impl_enum1_serde!(SocketAddr: [
|
||||
V4 => 4,
|
||||
V6 => 6
|
||||
]);
|
||||
|
@ -20,7 +20,7 @@ pub use des::Deserialize;
|
||||
pub use ser::Serialize;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_enum_serde {
|
||||
macro_rules! impl_enum1_serde {
|
||||
(
|
||||
$name:ident $(<$lifetime:lifetime>)? : [
|
||||
$(
|
||||
|
@ -1,9 +1,13 @@
|
||||
/// Helper macro to define primitive enums with integer reprs, as well as their conversion methods
|
||||
#[macro_export]
|
||||
macro_rules! primitive_enum {
|
||||
($(#[$struct_meta:meta])* $vis:vis enum $name:ident: $repr:ty {
|
||||
(
|
||||
$(#[$struct_meta:meta])*
|
||||
$vis:vis enum $name:ident: $repr:ty {
|
||||
$( $(#[$variant_meta:meta])* $variant:ident = $discriminant:literal ),+ $(,)?
|
||||
}) => {
|
||||
}
|
||||
$([ $enum_extra:tt ]),* $(,)?
|
||||
) => {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[repr($repr)]
|
||||
$(#[$struct_meta])*
|
||||
@ -32,9 +36,36 @@ macro_rules! primitive_enum {
|
||||
v as $repr
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
$crate::primitive_enum_extra!($enum_extra,
|
||||
impl abi_serde::Serialize for $name {
|
||||
fn serialize<S: abi_serde::ser::Serializer>(&self, serializer: &mut S) -> Result<(), <S as abi_serde::ser::Serializer>::Error> {
|
||||
let repr = *self as $repr;
|
||||
repr.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> abi_serde::Deserialize<'de> for $name {
|
||||
fn deserialize<D: abi_serde::des::Deserializer<'de>>(deserializer: &mut D) -> Result<Self, <D as abi_serde::des::Deserializer<'de>>::Error> {
|
||||
let repr = <$repr>::deserialize(deserializer)?;
|
||||
Self::try_from(repr).map_err(|_| <<D as abi_serde::des::Deserializer<'de>>::Error as abi_serde::des::DeserializeError>::INVALID_ENUM_VARIANT)
|
||||
}
|
||||
}
|
||||
);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! primitive_enum_extra {
|
||||
(with_serde, $($inner:item)+) => {
|
||||
$($inner)+
|
||||
};
|
||||
($any_other:ident, $($inner:item)+) => {};
|
||||
}
|
||||
|
||||
/// Common implementations for bitflag definitions
|
||||
#[macro_export]
|
||||
macro_rules! bitflags_impl_common {
|
||||
|
161
lib/abi/src/net/link.rs
Normal file
161
lib/abi/src/net/link.rs
Normal file
@ -0,0 +1,161 @@
|
||||
//! Types for handling network interface link state information
|
||||
|
||||
use core::fmt;
|
||||
|
||||
use abi_serde::{
|
||||
des::{DeserializeError, Deserializer},
|
||||
ser::Serializer,
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
|
||||
use crate::primitive_enum;
|
||||
|
||||
primitive_enum! {
|
||||
/// Defines an Ethernet link speed
|
||||
pub enum EthernetSpeed: u8 {
|
||||
/// 1Gbps link
|
||||
Speed1000 = 3,
|
||||
/// 100Mbps link
|
||||
Speed100 = 2,
|
||||
/// 10Mbps link
|
||||
Speed10 = 1,
|
||||
/// Link speed not available/unknown
|
||||
Unknown = 0,
|
||||
}
|
||||
[with_serde]
|
||||
}
|
||||
|
||||
primitive_enum! {
|
||||
/// Defines whether an Ethernet link is capable of transmiting data both ways simultaneously
|
||||
pub enum Duplex: u32 {
|
||||
/// Half-duplex mode
|
||||
Half = 1,
|
||||
/// Full-duplex mode
|
||||
Full = 2,
|
||||
/// Duplex mode information not available/unknown
|
||||
Unknown = 0,
|
||||
}
|
||||
[with_serde]
|
||||
}
|
||||
|
||||
/// Represents the state of an Ethernet link
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum EthernetLinkState {
|
||||
/// Link is up, fields indicate the link configuration
|
||||
Up(EthernetSpeed, Duplex),
|
||||
/// Link is down
|
||||
Down,
|
||||
}
|
||||
|
||||
/// Represents the state of network interface's link
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum LinkState {
|
||||
/// Ethernet link state
|
||||
Ethernet(EthernetLinkState),
|
||||
/// Any other device, just indicates whether the link is up or down
|
||||
Other {
|
||||
/// If `true`, the link is up
|
||||
up: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Serialize for EthernetLinkState {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
match self {
|
||||
Self::Up(speed, duplex) => {
|
||||
serializer.write_u8(0x01)?;
|
||||
speed.serialize(serializer)?;
|
||||
duplex.serialize(serializer)
|
||||
}
|
||||
Self::Down => serializer.write_u8(0x00),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for LinkState {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
match self {
|
||||
Self::Ethernet(state) => {
|
||||
serializer.write_u8(0xEE)?;
|
||||
state.serialize(serializer)
|
||||
}
|
||||
Self::Other { up } => {
|
||||
serializer.write_u8(0xFF)?;
|
||||
up.serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for EthernetLinkState {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
match deserializer.read_u8()? {
|
||||
0x01 => {
|
||||
let speed = EthernetSpeed::deserialize(deserializer)?;
|
||||
let duplex = Duplex::deserialize(deserializer)?;
|
||||
Ok(Self::Up(speed, duplex))
|
||||
}
|
||||
0x00 => Ok(Self::Down),
|
||||
_ => Err(D::Error::INVALID_ENUM_VARIANT),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for LinkState {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
match deserializer.read_u8()? {
|
||||
0xEE => EthernetLinkState::deserialize(deserializer).map(Self::Ethernet),
|
||||
0xFF => {
|
||||
let up = bool::deserialize(deserializer)?;
|
||||
Ok(Self::Other { up })
|
||||
}
|
||||
_ => Err(D::Error::INVALID_ENUM_VARIANT),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EthernetSpeed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let text = match self {
|
||||
Self::Speed10 => "10Mbps",
|
||||
Self::Speed100 => "100Mbps",
|
||||
Self::Speed1000 => "1Gbps",
|
||||
Self::Unknown => "N/A",
|
||||
};
|
||||
f.write_str(text)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Duplex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let text = match self {
|
||||
Self::Half => "half-duplex",
|
||||
Self::Full => "full-duplex",
|
||||
Self::Unknown => "N/A duplex mode",
|
||||
};
|
||||
f.write_str(text)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EthernetLinkState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Up(speed, duplex) => {
|
||||
write!(f, "up, speed {speed}, {duplex}")
|
||||
}
|
||||
Self::Down => {
|
||||
write!(f, "down")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LinkState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Other { up: true } => write!(f, "up"),
|
||||
Self::Other { up: false } => write!(f, "down"),
|
||||
Self::Ethernet(ethernet) => fmt::Display::fmt(ethernet, f),
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ pub mod dns;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod netconfig;
|
||||
|
||||
pub mod link;
|
||||
pub mod options;
|
||||
pub mod protocols;
|
||||
pub mod types;
|
||||
@ -54,7 +55,7 @@ abi_serde::impl_struct_serde!(MessageHeader<'de>: [
|
||||
payload,
|
||||
ancillary
|
||||
]);
|
||||
abi_serde::impl_enum_serde!(AncillaryMessage: [
|
||||
abi_serde::impl_enum1_serde!(AncillaryMessage: [
|
||||
File => 1
|
||||
]);
|
||||
|
||||
@ -80,7 +81,7 @@ impl From<u32> for SocketInterfaceQuery<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
abi_serde::impl_enum_serde!(SocketInterfaceQuery<'de>: [
|
||||
abi_serde::impl_enum1_serde!(SocketInterfaceQuery<'de>: [
|
||||
ById => 1,
|
||||
ByName => 2
|
||||
]);
|
||||
|
@ -9,7 +9,7 @@ use abi_serde::{
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use super::{MacAddress, SocketInterfaceQuery, SubnetAddr};
|
||||
use super::{link::LinkState, MacAddress, SocketInterfaceQuery, SubnetAddr};
|
||||
|
||||
/// Describes the binding between interfaces and their IDs
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -80,12 +80,15 @@ pub struct InterfaceInfo {
|
||||
pub address: Option<IpAddr>,
|
||||
/// Interface hardware address
|
||||
pub mac: MacAddress,
|
||||
/// Interface link status
|
||||
pub link: LinkState,
|
||||
}
|
||||
abi_serde::impl_struct_serde!(InterfaceInfo: [
|
||||
interface_name,
|
||||
interface_id,
|
||||
address,
|
||||
mac
|
||||
mac,
|
||||
link
|
||||
]);
|
||||
|
||||
/// Describes a request to add a route to an interface
|
||||
@ -155,7 +158,7 @@ pub enum NetConfigRequest<'a> {
|
||||
/// Query the MAC address of the specified IP
|
||||
ArpQuery(ArpQueryRequest<'a>),
|
||||
}
|
||||
abi_serde::impl_enum_serde!(NetConfigRequest<'de>: [
|
||||
abi_serde::impl_enum1_serde!(NetConfigRequest<'de>: [
|
||||
ListRoutes => 1,
|
||||
ListInterfaces => 2,
|
||||
DescribeRoutes => 3,
|
||||
|
@ -63,7 +63,7 @@ pub enum LocalSocketAddress<'a> {
|
||||
/// Describes an anonymous socket
|
||||
Anonymous(u64),
|
||||
}
|
||||
abi_serde::impl_enum_serde!(LocalSocketAddress<'de>: [
|
||||
abi_serde::impl_enum1_serde!(LocalSocketAddress<'de>: [
|
||||
Path => 1,
|
||||
Anonymous => 2,
|
||||
]);
|
||||
|
@ -29,7 +29,7 @@ pub enum SubnetAddr {
|
||||
/// IPv4 subnetwork
|
||||
V4(SubnetV4Addr),
|
||||
}
|
||||
abi_serde::impl_enum_serde!(SubnetAddr: [
|
||||
abi_serde::impl_enum1_serde!(SubnetAddr: [
|
||||
V4 => 4
|
||||
]);
|
||||
|
||||
|
@ -227,6 +227,7 @@ pub fn run_action(section: Section) -> Result<(), Error> {
|
||||
fn print_interface_info(info: &InterfaceInfo) {
|
||||
println!("{}:", info.interface_name);
|
||||
println!(" Id: #{}", info.interface_id);
|
||||
println!(" Link: {}", info.link);
|
||||
if let Some(address) = info.address {
|
||||
println!(" Address: {}", address);
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user