148 lines
4.1 KiB
Nim
148 lines
4.1 KiB
Nim
# SPDX-License-Identifier: LSL-1.0
|
|
# Copyright (c) 2026 Markus Maiwald
|
|
# Stewardship: Self Sovereign Society Foundation
|
|
#
|
|
# This file is part of the Nexus Sovereign Core.
|
|
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
|
|
|
## Rumpk Layer 1: Software Network Switch
|
|
|
|
# core/rumpk/core/netswitch.nim
|
|
# Phase 36.2: The Traffic Cop (Network Membrane Layer 2 Switch)
|
|
#
|
|
# Responsibilities:
|
|
# - Poll VirtIO-Net hardware for incoming packets
|
|
# - Route RX packets to s_net_rx ring (Kernel -> Userland)
|
|
# - Drain s_net_tx ring and transmit via VirtIO-Net (Userland -> Kernel)
|
|
# - Never yield during active traffic (War Mode latency optimization)
|
|
|
|
{.push stackTrace: off, lineTrace: off.}
|
|
|
|
import ion
|
|
|
|
# Forward declare fiber_yield to avoid circular import
|
|
proc fiber_yield*() {.importc, cdecl.}
|
|
proc fiber_sleep*(ms: int) {.importc, cdecl.}
|
|
|
|
# HAL Imports
|
|
proc virtio_net_poll() {.importc, cdecl.}
|
|
proc virtio_net_send(data: pointer, len: uint32) {.importc, cdecl.}
|
|
|
|
# Logging
|
|
proc kprintln(s: cstring) {.importc, cdecl.}
|
|
proc kprint(s: cstring) {.importc, cdecl.}
|
|
proc kprint_hex(v: uint64) {.importc, cdecl.}
|
|
proc get_now_ns(): uint64 {.importc, cdecl.}
|
|
|
|
# Membrane Infrastructure (LwIP Glue)
|
|
proc membrane_init*() {.importc, cdecl.}
|
|
proc pump_membrane_stack*() {.importc, cdecl.}
|
|
|
|
var netswitch_initialized: bool = false
|
|
|
|
proc netswitch_init*() =
|
|
## Initialize network channels and populate SysTable
|
|
## MUST be called before userland starts!
|
|
ion_init_network()
|
|
kprintln("[NetSwitch] Network Rings Initialized")
|
|
netswitch_initialized = true
|
|
|
|
proc netswitch_attach_systable*(sys: ptr SysTable) =
|
|
## Attach network ring pointers to SysTable for userland access
|
|
sys.s_net_rx = chan_net_rx.ring
|
|
sys.s_net_tx = chan_net_tx.ring
|
|
kprintln("[NetSwitch] SysTable Rings Attached")
|
|
|
|
type
|
|
EthHeader* {.packed.} = object
|
|
dst*: array[6, byte]
|
|
src*: array[6, byte]
|
|
ethertype*: uint16 # Big Endian
|
|
|
|
proc swap16(v: uint16): uint16 =
|
|
((v and 0xFF) shl 8) or (v shr 8)
|
|
|
|
proc netswitch_process_packet(pkt: IonPacket): bool =
|
|
## Layer 2 Demultiplexer
|
|
if pkt.len < 14:
|
|
ion_free(pkt)
|
|
return false
|
|
|
|
let eth = cast[ptr EthHeader](pkt.data)
|
|
let etype = swap16(eth.ethertype)
|
|
|
|
case etype:
|
|
of 0x0800, 0x0806, 0x86DD: # IPv4, ARP, IPv6
|
|
# Route to Legacy/LwIP Membrane
|
|
if not chan_net_rx.send(pkt):
|
|
# Ring full (Backpressure)
|
|
ion_free(pkt)
|
|
return false
|
|
return true
|
|
|
|
of 0x88B5: # Sovereign UTCP (SPEC-410)
|
|
# TODO: Route to dedicated UTCP channel
|
|
# kprintln("[NetSwitch] UTCP Sovereign Packet Identified")
|
|
ion_free(pkt)
|
|
return true # Handled (dropped)
|
|
|
|
else:
|
|
# Drop unknown EtherTypes (Security/Sovereignty)
|
|
ion_free(pkt)
|
|
return false
|
|
|
|
proc fiber_netswitch_entry*() {.cdecl.} =
|
|
membrane_init()
|
|
kprintln("[NetSwitch] Fiber Entry - The Traffic Cop is ON DUTY")
|
|
|
|
var rx_activity: bool = false
|
|
var tx_activity: bool = false
|
|
var rx_count: uint64 = 0
|
|
var tx_count: uint64 = 0
|
|
var last_stat_print: uint64 = 0
|
|
|
|
while true:
|
|
rx_activity = false
|
|
tx_activity = false
|
|
|
|
# 1. Drive the hardware poll (fills chan_netswitch_rx)
|
|
virtio_net_poll()
|
|
|
|
# 2. Drive the LwIP Stack (Timers/RX)
|
|
pump_membrane_stack()
|
|
|
|
# 2. Consume from the Driver -> Switch internal ring
|
|
var raw_pkt: IonPacket
|
|
while chan_netswitch_rx.recv(raw_pkt):
|
|
if netswitch_process_packet(raw_pkt):
|
|
rx_activity = true
|
|
inc rx_count
|
|
|
|
# 3. TX PATH: Userland -> Hardware
|
|
var tx_pkt: IonPacket
|
|
while chan_net_tx.recv(tx_pkt):
|
|
if tx_pkt.data != nil and tx_pkt.len > 0:
|
|
virtio_net_send(cast[pointer](tx_pkt.data), uint32(tx_pkt.len))
|
|
inc tx_count
|
|
ion_free(tx_pkt)
|
|
tx_activity = true
|
|
|
|
# 4. Periodically print stats
|
|
let now = get_now_ns()
|
|
if now - last_stat_print > 5000000000'u64: # 5 seconds
|
|
kprint("[NetSwitch] STATS - RX: ")
|
|
kprint_hex(rx_count)
|
|
kprint(" TX: ")
|
|
kprint_hex(tx_count)
|
|
kprintln("")
|
|
last_stat_print = now
|
|
|
|
# 5. Yield Strategy
|
|
if rx_activity or tx_activity:
|
|
# War Mode: High priority processing
|
|
continue
|
|
else:
|
|
fiber_sleep(10)
|
|
|
|
{.pop.}
|