1use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
12
13use alloc::{collections::BTreeMap, sync::Arc};
14
15use crate::{silo::SiloId, sync::SpinLock};
16
17use super::{
18 lockfree_ring::{LockFreeRing, RingError, RingSlot},
19 mailbox::IntrusiveMailbox,
20};
21use alloc::vec::Vec;
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
28#[repr(u8)]
29pub enum TransportLevel {
30 TypeSafe = 1,
32 LockFree = 2,
34 Mmu = 3,
36}
37
38#[derive(Debug, Clone, Copy)]
44pub struct TransportCapabilities {
45 pub max_message_size: usize,
47 pub blocking: bool,
49 pub zero_copy: bool,
51 pub estimated_cost_cycles: u32,
53}
54
55pub trait IpcTransport: Send + Sync {
57 fn level(&self) -> TransportLevel;
59 fn capabilities(&self) -> TransportCapabilities;
61 fn name(&self) -> &'static str;
63}
64
65pub trait IpcProducer: IpcTransport {
67 fn send(&self, msg: &[u8]) -> Result<(), IpcError>;
69 fn try_send(&self, msg: &[u8]) -> Result<(), IpcError>;
71}
72
73pub trait IpcConsumer: IpcTransport {
75 fn recv(&self, buf: &mut [u8]) -> Result<usize, IpcError>;
77 fn try_recv(&self, buf: &mut [u8]) -> Result<Option<usize>, IpcError>;
79}
80
81pub trait IpcNotification: IpcTransport {
83 fn notify_consumer(&self);
85 fn notify_producer(&self);
87 fn wait_notification(&self) -> Result<(), IpcError>;
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum IpcError {
98 WouldBlock,
100 Disconnected,
102 MessageTooLarge,
104 BufferTooSmall,
106 TransportNotFound,
108 PermissionDenied,
110 TransportFailed,
112}
113
114#[derive(Debug, Clone)]
120pub enum TransportEndpoint {
121 Mailbox(Arc<IntrusiveMailbox>),
123 LockFree(Arc<LockFreeRing>),
125}
126
127impl IpcTransport for TransportEndpoint {
128 fn level(&self) -> TransportLevel {
129 match self {
130 Self::Mailbox(_) => TransportLevel::TypeSafe,
131 Self::LockFree(_) => TransportLevel::LockFree,
132 }
133 }
134
135 fn capabilities(&self) -> TransportCapabilities {
136 match self {
137 Self::Mailbox(m) => m.capabilities(),
138 Self::LockFree(r) => r.capabilities(),
139 }
140 }
141
142 fn name(&self) -> &'static str {
143 match self {
144 Self::Mailbox(_) => "mailbox",
145 Self::LockFree(_) => "lockfree",
146 }
147 }
148}
149
150impl IpcProducer for TransportEndpoint {
151 fn send(&self, msg: &[u8]) -> Result<(), IpcError> {
152 match self {
153 Self::Mailbox(m) => m.send(msg),
154 Self::LockFree(r) => r.send(msg),
155 }
156 }
157
158 fn try_send(&self, msg: &[u8]) -> Result<(), IpcError> {
159 match self {
160 Self::Mailbox(m) => m.try_send(msg),
161 Self::LockFree(r) => r.try_send(msg),
162 }
163 }
164}
165
166impl IpcConsumer for TransportEndpoint {
167 fn recv(&self, buf: &mut [u8]) -> Result<usize, IpcError> {
168 match self {
169 Self::Mailbox(m) => m.recv(buf),
170 Self::LockFree(r) => r.recv(buf),
171 }
172 }
173
174 fn try_recv(&self, buf: &mut [u8]) -> Result<Option<usize>, IpcError> {
175 match self {
176 Self::Mailbox(m) => m.try_recv(buf),
177 Self::LockFree(r) => r.try_recv(buf),
178 }
179 }
180}
181
182impl IpcTransport for LockFreeRing {
184 fn level(&self) -> TransportLevel {
185 TransportLevel::LockFree
186 }
187
188 fn capabilities(&self) -> TransportCapabilities {
189 TransportCapabilities {
190 max_message_size: RingSlot::SLOT_SIZE,
191 blocking: true,
192 zero_copy: true,
193 estimated_cost_cycles: 400,
194 }
195 }
196
197 fn name(&self) -> &'static str {
198 "lockfree"
199 }
200}
201
202impl IpcProducer for LockFreeRing {
203 fn send(&self, msg: &[u8]) -> Result<(), IpcError> {
204 self.write(msg).map_err(ring_to_ipc_error)?;
205 self.notify_consumer_raw();
206 Ok(())
207 }
208
209 fn try_send(&self, msg: &[u8]) -> Result<(), IpcError> {
210 self.write(msg).map_err(ring_to_ipc_error)?;
211 self.notify_consumer_raw();
212 Ok(())
213 }
214}
215
216impl IpcConsumer for LockFreeRing {
217 fn recv(&self, buf: &mut [u8]) -> Result<usize, IpcError> {
218 self.read(buf).map_err(ring_to_ipc_error)
219 }
220
221 fn try_recv(&self, buf: &mut [u8]) -> Result<Option<usize>, IpcError> {
222 self.try_read(buf).map_err(ring_to_ipc_error)
223 }
224}
225
226fn ring_to_ipc_error(e: RingError) -> IpcError {
227 match e {
228 RingError::Full => IpcError::WouldBlock,
229 RingError::Empty => IpcError::WouldBlock,
230 RingError::MessageTooLarge => IpcError::MessageTooLarge,
231 RingError::BufferTooSmall => IpcError::BufferTooSmall,
232 _ => IpcError::TransportFailed,
233 }
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
242pub struct TransportId(u64);
243
244impl TransportId {
245 fn new() -> Self {
246 static NEXT: AtomicU64 = AtomicU64::new(1);
247 TransportId(NEXT.fetch_add(1, Ordering::Relaxed))
248 }
249
250 pub fn from_u64(raw: u64) -> Self {
252 TransportId(raw)
253 }
254
255 pub fn as_u64(self) -> u64 {
257 self.0
258 }
259}
260
261#[derive(Debug, Clone)]
263pub struct TransportCreateResult {
264 pub id: TransportId,
265 pub local: TransportEndpoint,
266 pub remote: TransportEndpoint,
267 pub level: TransportLevel,
268}
269
270#[derive(Debug, Clone)]
276pub struct TransportConfig {
277 pub min_level: TransportLevel,
279 pub ring_capacity: Option<u32>,
281 pub slot_size: Option<usize>,
283}
284
285#[derive(Debug, Clone)]
291struct TransportPolicyEntry {
292 level: TransportLevel,
293 ring_capacity: u32,
294}
295
296const DECISION_MATRIX: [[TransportPolicyEntry; 3]; 3] = [
298 [
300 TransportPolicyEntry {
301 level: TransportLevel::TypeSafe,
302 ring_capacity: 0,
303 },
304 TransportPolicyEntry {
305 level: TransportLevel::TypeSafe,
306 ring_capacity: 0,
307 },
308 TransportPolicyEntry {
309 level: TransportLevel::LockFree,
310 ring_capacity: 256,
311 },
312 ],
313 [
315 TransportPolicyEntry {
316 level: TransportLevel::TypeSafe,
317 ring_capacity: 0,
318 },
319 TransportPolicyEntry {
320 level: TransportLevel::LockFree,
321 ring_capacity: 256,
322 },
323 TransportPolicyEntry {
324 level: TransportLevel::LockFree,
325 ring_capacity: 256,
326 },
327 ],
328 [
330 TransportPolicyEntry {
331 level: TransportLevel::LockFree,
332 ring_capacity: 256,
333 },
334 TransportPolicyEntry {
335 level: TransportLevel::LockFree,
336 ring_capacity: 256,
337 },
338 TransportPolicyEntry {
339 level: TransportLevel::LockFree,
340 ring_capacity: 256,
341 },
342 ],
343];
344
345#[derive(Debug, Clone)]
347pub struct TransportStats {
348 pub sent: u64,
350 pub received: u64,
352 pub errors: u64,
354 pub level: TransportLevel,
356}
357
358impl TransportStats {
359 const fn new(level: TransportLevel) -> Self {
360 TransportStats {
361 sent: 0,
362 received: 0,
363 errors: 0,
364 level,
365 }
366 }
367}
368
369impl TransportEndpoint {
374 pub fn has_data(&self) -> bool {
376 match self {
377 Self::Mailbox(m) => !m.is_empty(),
378 Self::LockFree(r) => r.has_data(),
379 }
380 }
381
382 pub fn has_space(&self) -> bool {
384 match self {
385 Self::Mailbox(_) => true, Self::LockFree(r) => r.has_space(),
387 }
388 }
389}
390
391pub struct TransportManager {
401 decision_matrix: [[TransportPolicyEntry; 3]; 3],
403 policy_overrides: SpinLock<BTreeMap<(u32, u32), TransportPolicyEntry>>,
405 active: SpinLock<BTreeMap<TransportId, TransportCreateResult>>,
407 cache: SpinLock<TransportCache>,
409 pub stats: SpinLock<TransportStats>,
411}
412
413impl TransportManager {
414 pub const fn new() -> Self {
416 TransportManager {
417 decision_matrix: DECISION_MATRIX,
418 policy_overrides: SpinLock::new(BTreeMap::new()),
419 active: SpinLock::new(BTreeMap::new()),
420 cache: SpinLock::new(TransportCache::new()),
421 stats: SpinLock::new(TransportStats::new(TransportLevel::LockFree)),
422 }
423 }
424
425 pub fn establish(
432 &self,
433 src: SiloId,
434 dst: SiloId,
435 config: TransportConfig,
436 ) -> Result<TransportCreateResult, IpcError> {
437 let pair = (src.sid, dst.sid);
438
439 {
441 let mut cache = self.cache.lock();
442 if let Some(cached) = cache.get(pair) {
443 if cached.level as u8 >= config.min_level as u8 {
444 return Ok(cached.clone());
445 }
446 }
447 }
448
449 {
451 let overrides = self.policy_overrides.lock();
452 if let Some(entry) = overrides.get(&pair) {
453 return self.create(pair, entry.level, entry.ring_capacity);
454 }
455 }
456
457 let entry = &self.decision_matrix[src.tier as usize][dst.tier as usize];
459 let level = if entry.level < config.min_level {
460 config.min_level
461 } else {
462 entry.level
463 };
464 self.create(
465 pair,
466 level,
467 config.ring_capacity.unwrap_or(entry.ring_capacity),
468 )
469 }
470
471 fn create(
473 &self,
474 _pair: (u32, u32),
475 level: TransportLevel,
476 capacity: u32,
477 ) -> Result<TransportCreateResult, IpcError> {
478 let id = TransportId::new();
479
480 let (local, remote) = match level {
481 TransportLevel::TypeSafe => {
482 let mb = IntrusiveMailbox::new();
483 let arc = Arc::new(mb);
484 (
485 TransportEndpoint::Mailbox(arc.clone()),
486 TransportEndpoint::Mailbox(arc),
487 )
488 }
489 TransportLevel::LockFree => {
490 let ring = LockFreeRing::new(capacity.max(4), 2048)
491 .map_err(|_| IpcError::TransportFailed)?;
492 (
493 TransportEndpoint::LockFree(ring.clone()),
494 TransportEndpoint::LockFree(ring),
495 )
496 }
497 TransportLevel::Mmu => {
498 let ring = LockFreeRing::new(capacity.max(4), 2048)
500 .map_err(|_| IpcError::TransportFailed)?;
501 (
502 TransportEndpoint::LockFree(ring.clone()),
503 TransportEndpoint::LockFree(ring),
504 )
505 }
506 };
507
508 let result = TransportCreateResult {
509 id,
510 local,
511 remote: remote.clone(),
512 level,
513 };
514
515 self.stats.lock().sent += 1;
518
519 {
520 let mut cache = self.cache.lock();
521 cache.put(_pair, result.clone());
522 }
523 {
524 let mut active = self.active.lock();
525 active.insert(id, result.clone());
526 }
527
528 Ok(result)
529 }
530
531 pub fn get_endpoint(&self, id: TransportId) -> Option<TransportEndpoint> {
533 let active = self.active.lock();
534 active.get(&id).map(|r| r.local.clone())
535 }
536
537 pub fn close(&self, id: TransportId) -> Result<(), IpcError> {
539 let mut active = self.active.lock();
540 active.remove(&id).ok_or(IpcError::TransportNotFound)?;
541 Ok(())
542 }
543
544 pub fn set_policy(&self, src: u32, dst: u32, level: TransportLevel, capacity: u32) {
546 let mut overrides = self.policy_overrides.lock();
547 overrides.insert(
548 (src, dst),
549 TransportPolicyEntry {
550 level,
551 ring_capacity: capacity,
552 },
553 );
554 }
555}
556
557const CACHE_SIZE: usize = 128;
562
563struct TransportCache {
564 entries: [((u32, u32), Option<TransportCreateResult>); CACHE_SIZE],
565 next: usize,
566}
567
568impl TransportCache {
569 const fn new() -> Self {
570 const NONE: ((u32, u32), Option<TransportCreateResult>) = ((0, 0), None);
571 TransportCache {
572 entries: [NONE; CACHE_SIZE],
573 next: 0,
574 }
575 }
576
577 fn get(&mut self, key: (u32, u32)) -> Option<&TransportCreateResult> {
578 self.entries
579 .iter()
580 .find_map(|(k, v)| if *k == key { v.as_ref() } else { None })
581 }
582
583 fn put(&mut self, key: (u32, u32), value: TransportCreateResult) {
584 let idx = self.next;
585 self.entries[idx] = (key, Some(value));
586 self.next = (self.next + 1) % CACHE_SIZE;
587 }
588}
589
590use core::marker::PhantomData;
595
596pub struct Producer;
598
599pub struct Consumer;
601
602pub struct TypedLockFreeRing<Role> {
608 inner: Arc<LockFreeRing>,
609 _role: PhantomData<Role>,
610}
611
612impl TypedLockFreeRing<Producer> {
613 pub fn write(&self, data: &[u8]) -> Result<(), RingError> {
615 self.inner.write(data)
616 }
617}
618
619impl<T> TypedLockFreeRing<T> {
620 pub fn read(&self, buf: &mut [u8]) -> Result<usize, RingError> {
622 self.inner.read(buf)
623 }
624}
625
626pub fn create_spsc_pair(
628 cap: u32,
629 slot_size: usize,
630) -> Result<(TypedLockFreeRing<Producer>, TypedLockFreeRing<Consumer>), RingError> {
631 let ring = LockFreeRing::new(cap, slot_size)?;
632 Ok((
633 TypedLockFreeRing {
634 inner: ring.clone(),
635 _role: PhantomData,
636 },
637 TypedLockFreeRing {
638 inner: ring,
639 _role: PhantomData,
640 },
641 ))
642}
643
644#[repr(C)]
653pub struct NicRoutingTable {
654 pub count: AtomicU32,
656 _pad: [u8; 60],
657 pub entries: [RoutingEntry; MAX_ROUTES],
659}
660
661#[repr(C, align(64))]
663pub struct RoutingEntry {
664 pub silo_id: u64,
665 pub core_id: u32,
666 pub state: AtomicU32,
667 pub rpc_count: AtomicU64,
668 pub generation: AtomicU64,
669}
670
671pub const MAX_ROUTES: usize = 64;
673
674impl Default for NicRoutingTable {
675 fn default() -> Self {
676 NicRoutingTable {
677 count: AtomicU32::new(0),
678 _pad: [0u8; 60],
679 entries: unsafe { core::mem::zeroed() },
680 }
681 }
682}
683
684pub struct RingPair {
686 pub rx: Arc<LockFreeRing>,
687 pub tx: Arc<LockFreeRing>,
688}
689
690pub struct NicDataPlane {
696 pub queues: Vec<RingPair>,
698 pub routing: NicRoutingTable,
700}