Skip to main content

ax_net/
config.rs

1//! Network interface and route configuration types.
2//!
3//! This module is the data model for ax-net's control plane. It is shared by
4//! startup configuration, dynamic IPv4 updates, route table replacement, socket
5//! device binding, DHCP client/server integration, and userspace interface
6//! queries.
7//!
8//! # Design Notes
9//!
10//! `InterfaceId` is stable for the lifetime of the stack and is also exported
11//! as the Linux ifindex. Route and binding structures refer to this identifier
12//! rather than a device vector index so public state survives internal device
13//! ordering details.
14//!
15//! `DeviceBinding` is deliberately small: sockets can bind to an interface, and
16//! the service/router layer performs source-address and next-hop selection from
17//! the route table. Socket implementations should not duplicate route logic.
18
19use alloc::{string::String, vec::Vec};
20use core::net::Ipv4Addr;
21
22use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv4Cidr};
23
24/// Stable network interface identifier.
25///
26/// The numeric value is also used as the Linux ifindex exposed by StarryOS.
27#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
28pub struct InterfaceId(u32);
29
30impl InterfaceId {
31    pub const LOOPBACK: Self = Self(1);
32
33    pub const fn new(raw: u32) -> Self {
34        Self(raw)
35    }
36
37    pub const fn get(self) -> u32 {
38        self.0
39    }
40
41    /// Convert to Linux ifindex (i32).
42    pub const fn to_linux_ifindex(self) -> i32 {
43        self.0 as i32
44    }
45
46    /// Create from Linux ifindex (i32), rejecting invalid values.
47    pub const fn from_linux_ifindex(ifindex: i32) -> Option<Self> {
48        if ifindex > 0 {
49            Some(Self(ifindex as u32))
50        } else {
51            None
52        }
53    }
54}
55
56/// Network interface kind.
57#[derive(Debug, Clone, Copy, Eq, PartialEq)]
58pub enum InterfaceKind {
59    Loopback,
60    Ethernet,
61}
62
63bitflags::bitflags! {
64    /// Runtime interface flags.
65    #[derive(Debug, Clone, Copy, Eq, PartialEq)]
66    pub struct InterfaceFlags: u32 {
67        const UP = 1 << 0;
68        const RUNNING = 1 << 1;
69        const LOOPBACK = 1 << 2;
70        const BROADCAST = 1 << 3;
71        const MULTICAST = 1 << 4;
72    }
73}
74
75/// Public snapshot of a network interface.
76#[derive(Debug, Clone)]
77pub struct InterfaceInfo {
78    pub id: InterfaceId,
79    pub name: String,
80    pub kind: InterfaceKind,
81    pub mac: Option<EthernetAddress>,
82    pub ipv4: Option<Ipv4InterfaceConfig>,
83    pub mtu: usize,
84    pub flags: InterfaceFlags,
85    pub metric: u32,
86}
87
88/// Interface matching rule for explicit configuration.
89#[derive(Debug, Clone)]
90pub enum InterfaceMatcher {
91    /// Match the Nth probed Ethernet device.
92    ByOrder(usize),
93    /// Match a device by its Ethernet MAC address.
94    ByMac(EthernetAddress),
95    /// Match a device by the name reported by its driver.
96    ByDriverName(String),
97}
98
99/// Network initialization configuration.
100#[derive(Debug, Clone, Default)]
101pub struct NetworkConfig {
102    /// Per-interface configuration.
103    pub interfaces: Vec<InterfaceConfig>,
104    /// DNS servers used when no interface-level DNS server is available.
105    pub default_dns_servers: Vec<Ipv4Addr>,
106}
107
108/// Per-interface network configuration.
109#[derive(Debug, Clone)]
110pub struct InterfaceConfig {
111    /// Public interface name, for example `eth0`.
112    pub name: String,
113    /// Rule used to bind this config to one probed device.
114    pub match_by: InterfaceMatcher,
115    /// Static IPv4 configuration. Mutually exclusive with DHCP.
116    pub static_ip: Option<StaticIpConfig>,
117    /// Whether DHCP client configuration is enabled.
118    pub dhcp: bool,
119    /// Route metric used for routes installed from this interface.
120    pub metric: u32,
121    /// Static DNS servers associated with this interface.
122    pub dns_servers: Vec<Ipv4Addr>,
123}
124
125/// Static IP configuration.
126#[derive(Debug, Clone)]
127pub struct StaticIpConfig {
128    /// IPv4 address assigned to the interface.
129    pub ip: Ipv4Addr,
130    /// CIDR prefix length.
131    pub prefix_len: u8,
132    /// Default gateway; `0.0.0.0` means no gateway.
133    pub gateway: Ipv4Addr,
134}
135
136/// Runtime IPv4 configuration of a network interface.
137#[derive(Debug, Clone, Copy, Eq, PartialEq)]
138pub struct Ipv4InterfaceConfig {
139    /// Interface address and prefix.
140    pub address: Ipv4Cidr,
141    /// Optional default gateway learned or configured for this interface.
142    pub gateway: Option<Ipv4Address>,
143}
144
145/// DNS server origin.
146#[derive(Debug, Clone, Copy, Eq, PartialEq)]
147pub enum DnsSource {
148    /// Learned from DHCP.
149    Dhcp,
150    /// Configured on a matching interface.
151    Static,
152    /// Global fallback DNS server.
153    Fallback,
154}
155
156/// Internal DNS server entry with origin metadata.
157#[derive(Debug, Clone, Copy, Eq, PartialEq)]
158pub(crate) struct DnsServerEntry {
159    /// DNS server address.
160    pub server: Ipv4Address,
161    /// Interface that owns or should route to this server.
162    pub interface_id: InterfaceId,
163    /// Route/DNS priority; lower values are preferred.
164    pub metric: u32,
165    /// Source used for priority and reporting decisions.
166    pub source: DnsSource,
167}
168
169/// Public route snapshot.
170#[derive(Debug, Clone, Copy, Eq, PartialEq)]
171pub struct RouteInfo {
172    /// Destination prefix.
173    pub filter: smoltcp::wire::IpCidr,
174    /// Optional gateway/next hop.
175    pub via: Option<smoltcp::wire::IpAddress>,
176    /// Egress interface.
177    pub interface_id: InterfaceId,
178    /// Source address selected by this route.
179    pub source: smoltcp::wire::IpAddress,
180    /// Route metric; lower values are preferred.
181    pub metric: u32,
182}
183
184/// Ordinary socket interface binding.
185#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
186pub struct DeviceBinding {
187    /// If set, route selection is constrained to this interface.
188    pub bound_if: Option<InterfaceId>,
189}