对外接口
ax-net 的 public API 面向三类调用方:启动阶段的 runtime、系统 ABI/socket 层,以及设备驱动适配层。API 设计保持一个原则:外部通过稳定的接口 ID、快照和 trait object 访问网络栈,不直接接触 Service、Router、smoltcp SocketSet 等内部对象。
核心 re-export 定义在 lib.rs:
pub use self::{
config::{
DeviceBinding, InterfaceConfig, InterfaceFlags, InterfaceId, InterfaceInfo,
InterfaceKind, InterfaceMatcher, Ipv4InterfaceConfig, NetworkConfig,
RouteInfo, StaticIpConfig,
},
device::{ArpEntry, EthernetFramePort, EthernetFramePortList, NetDeviceError, NetDeviceResult},
queue_runtime::{
NetQueueStats, NetworkDeviceInput, NetworkQueueRuntime,
NetworkRuntimeBuilder, NetworkRuntimeError, PinnedNetIrqAction,
PinnedNetIrqError, PinnedNetIrqOutcome, PinnedNetIrqRegistrar,
PinnedNetIrqRegistration, ResolvedNetIrqSource, TxQueueDiscipline,
},
socket::{
CMsgData, IpCmsg, RecvFlags, RecvOptions, SendFlags, SendOptions,
Shutdown, Socket, SocketAddrEx, SocketCmsg, SocketOps,
},
router::NetDevStats,
};
pub use error::{NetError, NetResult};
pub use rd_net::{WifiLinkPolicy, WifiOperation, WifiTransaction, Wpa2Pmk};
re-export 列表构成调用方可依赖的稳定表面,内部 Service、Router queue 与 smoltcp handle 均未公开。API 分层据此按能力和生命周期组织这些类型,而不是按内部模块目录暴露实现。
1. API 分层
公共 API 按生命周期和调用方划分为初始化、驱动、socket、查询、运行期配置与名称解析边界。每类入口只暴露上层完成工作所需的能力,并把 Service、NetControl、Router 和 smoltcp 类型留在 crate 内部,避免调用者依赖锁与存储细节。
- 初始化与配置 API:由
ax-runtime或平台初始化代码调用。 - 运行时查询 API: 由系统 ABI、诊断接口、
/proc、ioctl 等读取网络状态。 - Socket facade API:由 syscall/socket 层创建并操作具体 socket。
- Socket option API:由 getsockopt/setsockopt 层转发。
- 设备驱动 API:由 NIC driver、IRQ registrar、运行期设备注册路径使用。
- DNS/ARP 辅助 API:由 resolver 和 Linux 兼容层使用。
API 边界如下:
图中的多个入口最终汇合到共享实现,但这不意味着调用者可以跨边界交换内部对象。初始化 API 负责创建所有者,查询 API 只返回快照,socket 与驱动 API 则通过 trait 或枚举表达受限能力。
2. 初始化配置
初始化 API 构造全局网络栈。它们是全局单例初始化入口,不返回 Service 或 Router 的可变引用。
2.1 网络配置模型
NetworkConfig 描述启动阶段接口匹配、IPv4 来源、route metric 与 DNS 配置,是 init_network() 发布全局状态前校验的顶层输入。调用方传递拥有型结构,而不是逐项修改 Service,从而保证接口、路由和 DNS 可以作为一个一致配置构建。
pub struct NetworkConfig {
pub interfaces: Vec<InterfaceConfig>,
pub default_dns_servers: Vec<Ipv4Addr>,
}
pub struct InterfaceConfig {
pub name: String,
pub match_by: InterfaceMatcher,
pub static_ip: Option<StaticIpConfig>,
pub dhcp: bool,
pub metric: u32,
pub dns_servers: Vec<Ipv4Addr>,
}
InterfaceMatcher 支持按探测顺序、MAC 或 driver name 匹配设备:
pub enum InterfaceMatcher {
ByOrder(usize),
ByMac(EthernetAddress),
ByDriverName(String),
}
静态 IPv4 配置使用:
pub struct StaticIpConfig {
pub ip: Ipv4Addr,
pub prefix_len: u8,
pub gateway: Ipv4Addr,
}
配置语义:
lo由ax-net固定创建,不通过NetworkConfig覆盖。- 未显式匹配的 Ethernet 设备按默认策略加入接口 registry。
static_ip和dhcp表达互斥配置。metric同时影响路由选择和 DNS server 排序。default_dns_servers是 接口级 DNS 不可用时的 fallback 来源。
字段列表显示 NetworkConfig 只描述期望状态,真正的全局所有者尚未创建。网络初始化入口负责校验并把这些配置原子转化为接口、路由、DNS 与已经建立好的 queue runtime。
2.2 网络初始化
init_network() 是协议网络栈的唯一全局构造入口。调用者先用 NetworkRuntimeBuilder 消费全部物理设备、固定 queue executor 与 IRQ,再把得到的 NetworkQueueRuntime、协议端口列表和 NetworkConfig 一次性交给本函数。维护初始化代码时必须保持 queue runtime 就绪、协议状态构造、全局单例发布和唯一 protocol executor 启动的先后关系,因为 socket API 在该入口返回后会立即依赖这些对象。
pub fn init_network(
queue_runtime: NetworkQueueRuntime,
frame_ports: EthernetFramePortList,
config: NetworkConfig,
);
调用方传入已发现的 Ethernet driver 列表和结构化配置。初始化会完成:
- 创建 loopback。
- 为每个 Ethernet 设备分配
InterfaceId和接口名。 - 创建
Router、NetControl、smoltcpInterface和全局SocketSet。 - 安装静态地址、DHCP client 状态、DNS entries 和 route rules。
- 安装已经通过 fixed-affinity 握手并完成 IRQ rearm 的 queue runtime。
- 在选定 CPU 启动唯一 protocol executor。
NetworkQueueRuntime 是必选参数:物理 NIC 必须已经完成 typed IRQ source 解析、
fixed-affinity worker 启动和初始 rearm,网络栈没有 no-IRQ 或周期轮询降级路径。
loopback 可以作为唯一接口存在,但仍由同一个 runtime 选择并持有唯一 protocol owner。
init_network() 是一次性初始化入口,重复初始化会触发全局单例保护。
2.3 轮询触发
普通调用者通过 request_poll() 发布 generation,表达“协议状态需要继续推进”,而不直接持有 SERVICE 执行 smoltcp poll。只有固定 CPU 的 protocol executor 能消费 generation 并调用 smoltcp;socket、queue executor、协议定时器和同步 flush 都只是请求方。
pub fn request_poll();
request_poll() 是 socket、设备和控制路径使用的轻量进度请求入口:
pub fn request_poll() {
let _ = PROTOCOL_POLL.request();
}
ProtocolPollRuntime::request() 先对 requested generation 做 fetch_add,再由
schedule() 用 swap(false→true) 合并重复请求:只有从未 scheduled 变为 scheduled
的第一次调用会真正唤醒固定 CPU 的 protocol executor。这样 socket 热路径可以频繁请求
协议推进,而不会在 worker 尚未消费请求时制造重复唤醒。
2.4 Vsock 初始化
init_vsock() 只负责发布 vsock 设备并启动其连接管理运行时,不参与 Ethernet
Router 或 smoltcp Interface 的初始化。设备输入必须同时携带已解析的 IRQ 和从
driver 一次性转移的 hard-IRQ/task-rearm capability;当前拓扑只允许零个或恰好一个
设备,多个设备会显式失败,不能再静默丢弃列表成员。
#[cfg(feature = "vsock")]
pub fn init_vsock(
devices: VsockDeviceList,
registrar: &dyn PinnedNetIrqRegistrar,
active_cpus: CpuSet,
) -> Result<(), VsockRuntimeError>;
#[cfg(feature = "vsock")]
pub type VsockDevice = Box<dyn rdif_vsock::Interface>;
#[cfg(feature = "vsock")]
pub type VsockDeviceList = Vec<VsockDeviceInput>;
pub struct VsockDeviceInput {
pub name: String,
pub device: VsockDevice,
pub irq: IrqId,
pub endpoints: VsockIrqEndpoints,
}
vsock 不进入 smoltcp SocketSet,也不实现 ax-net 内部 IP Device trait。它通过
rdif_vsock::Interface 和 vsock connection manager 进入 AF_VSOCK socket backend。
固定 worker 复用 Ethernet runtime 选定的 protocol owner CPU;hard IRQ 只 ACK/coalesce,
worker 在 task context 预算 drain 后执行 rearm/recheck,没有 timer fallback。
列表为空时仅记录 warning,不创建“已初始化但无设备”的独立状态位。没有注册设备时,
AF_VSOCK 后续操作会在 device::vsock_*() 路径返回 NotFound。设备、IRQ binding、
endpoint transfer、worker affinity 或 registration 任一步不完整都会 fail closed。
3. 运行时查询
查询 API 返回只读快照。调用方不应持有快照并假设其永久有效;DHCP、运行期设备注册或后续 link state 更新都可能改变接口、路由和 DNS 状态。