veridian_kernel/virt/containers/
networking.rs1#[cfg(feature = "alloc")]
5use alloc::{string::String, vec::Vec};
6use core::sync::atomic::{AtomicU64, Ordering};
7
8use crate::error::KernelError;
9
10#[cfg(feature = "alloc")]
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct VethEndpoint {
14 pub name: String,
16 pub peer_name: String,
18 pub mac: [u8; 6],
20 pub ipv4_addr: u32,
22 pub ipv4_mask: u32,
24 pub mtu: u16,
26 pub is_up: bool,
28 pub namespace_id: u64,
30}
31
32#[cfg(feature = "alloc")]
34#[derive(Debug, Clone)]
35pub struct VethPair {
36 pub host: VethEndpoint,
38 pub container: VethEndpoint,
40}
41
42#[cfg(feature = "alloc")]
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct NatPortMapping {
46 pub external_port: u16,
48 pub internal_port: u16,
50 pub protocol: u8,
52 pub container_ip: u32,
54}
55
56#[cfg(feature = "alloc")]
58#[derive(Debug, Clone)]
59pub struct NatTable {
60 pub host_ip: u32,
62 pub port_mappings: Vec<NatPortMapping>,
64 pub masquerade_enabled: bool,
66}
67
68#[cfg(feature = "alloc")]
69impl NatTable {
70 pub fn new(host_ip: u32) -> Self {
71 Self {
72 host_ip,
73 port_mappings: Vec::new(),
74 masquerade_enabled: false,
75 }
76 }
77
78 pub fn enable_masquerade(&mut self) {
80 self.masquerade_enabled = true;
81 }
82
83 pub fn add_port_mapping(&mut self, mapping: NatPortMapping) -> Result<(), KernelError> {
85 for existing in &self.port_mappings {
87 if existing.external_port == mapping.external_port
88 && existing.protocol == mapping.protocol
89 {
90 return Err(KernelError::AlreadyExists {
91 resource: "nat port mapping",
92 id: mapping.external_port as u64,
93 });
94 }
95 }
96 self.port_mappings.push(mapping);
97 Ok(())
98 }
99
100 pub fn remove_port_mapping(&mut self, external_port: u16, protocol: u8) -> bool {
102 let before = self.port_mappings.len();
103 self.port_mappings
104 .retain(|m| !(m.external_port == external_port && m.protocol == protocol));
105 self.port_mappings.len() < before
106 }
107
108 pub fn lookup_inbound(&self, external_port: u16, protocol: u8) -> Option<&NatPortMapping> {
110 self.port_mappings
111 .iter()
112 .find(|m| m.external_port == external_port && m.protocol == protocol)
113 }
114
115 pub fn snat_rewrite(&self, _src_ip: u32) -> Option<u32> {
117 if self.masquerade_enabled {
118 Some(self.host_ip)
119 } else {
120 None
121 }
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub struct ArpProxyEntry {
128 pub ip: u32,
130 pub mac: [u8; 6],
132}
133
134#[cfg(feature = "alloc")]
136#[derive(Debug, Clone)]
137pub struct VethBridge {
138 pub name: String,
140 pub bridge_ip: u32,
142 pub subnet_mask: u32,
144 pub attached_interfaces: Vec<String>,
146 pub arp_proxy_entries: Vec<ArpProxyEntry>,
148 pub nat: NatTable,
150}
151
152#[cfg(feature = "alloc")]
153impl VethBridge {
154 pub fn new(name: &str, bridge_ip: u32, subnet_mask: u32) -> Self {
155 Self {
156 name: String::from(name),
157 bridge_ip,
158 subnet_mask,
159 attached_interfaces: Vec::new(),
160 arp_proxy_entries: Vec::new(),
161 nat: NatTable::new(bridge_ip),
162 }
163 }
164
165 pub fn attach(&mut self, interface_name: &str) {
167 if !self.attached_interfaces.iter().any(|n| n == interface_name) {
168 self.attached_interfaces.push(String::from(interface_name));
169 }
170 }
171
172 pub fn detach(&mut self, interface_name: &str) {
174 self.attached_interfaces.retain(|n| n != interface_name);
175 }
176
177 pub fn add_arp_proxy(&mut self, entry: ArpProxyEntry) {
179 self.arp_proxy_entries.push(entry);
180 }
181
182 pub fn arp_lookup(&self, ip: u32) -> Option<&ArpProxyEntry> {
184 self.arp_proxy_entries.iter().find(|e| e.ip == ip)
185 }
186
187 pub fn in_subnet(&self, ip: u32) -> bool {
189 (ip & self.subnet_mask) == (self.bridge_ip & self.subnet_mask)
190 }
191
192 pub fn attached_count(&self) -> usize {
193 self.attached_interfaces.len()
194 }
195}
196
197static NEXT_VETH_ID: AtomicU64 = AtomicU64::new(1);
198
199pub fn generate_veth_mac(veth_id: u64) -> [u8; 6] {
201 [
202 0x02, 0x42,
204 ((veth_id >> 24) & 0xff) as u8,
205 ((veth_id >> 16) & 0xff) as u8,
206 ((veth_id >> 8) & 0xff) as u8,
207 (veth_id & 0xff) as u8,
208 ]
209}
210
211#[cfg(feature = "alloc")]
213pub fn create_veth_pair(host_name: &str, container_name: &str, namespace_id: u64) -> VethPair {
214 let id = NEXT_VETH_ID.fetch_add(1, Ordering::Relaxed);
215 let host_mac = generate_veth_mac(id);
216 let mut container_mac = generate_veth_mac(id);
218 container_mac[5] ^= 0x01;
219
220 VethPair {
221 host: VethEndpoint {
222 name: String::from(host_name),
223 peer_name: String::from(container_name),
224 mac: host_mac,
225 ipv4_addr: 0,
226 ipv4_mask: 0,
227 mtu: 1500,
228 is_up: false,
229 namespace_id: 0,
230 },
231 container: VethEndpoint {
232 name: String::from(container_name),
233 peer_name: String::from(host_name),
234 mac: container_mac,
235 ipv4_addr: 0,
236 ipv4_mask: 0,
237 mtu: 1500,
238 is_up: false,
239 namespace_id,
240 },
241 }
242}