122 lines
3.6 KiB
Nim
122 lines
3.6 KiB
Nim
# ION Soft-Switch
|
|
# Sovereign Dispatch Logic
|
|
|
|
import memory
|
|
import ../ring
|
|
import ../net # For LwIP fallback
|
|
|
|
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
|
|
|
type
|
|
FlowType* = enum
|
|
FLOW_LWIP # The Unix Path
|
|
FLOW_DIRECT # The ION Path
|
|
|
|
# A Subscription to the Bus
|
|
NetFlow* = object
|
|
port*: uint16
|
|
ring*: ptr RingBuffer[IonPacket, 256] # Direct injection ring
|
|
fType*: FlowType
|
|
|
|
var
|
|
# The Lookup Table (Simple Array for Phase 7)
|
|
# Index = Port Number.
|
|
flow_table: array[65536, ptr NetFlow]
|
|
|
|
proc ion_register*(port: uint16, flow: ptr NetFlow) =
|
|
flow_table[port] = flow
|
|
|
|
proc parse_dest_port(data: ptr UncheckedArray[byte]): uint16 =
|
|
# Ethernet Type at 12. IP Protocol at 23. Dest Port at 36.
|
|
if data[12] == 0x08 and data[13] == 0x00:
|
|
# IPv4
|
|
let proto = data[23]
|
|
if proto == 17: # UDP
|
|
let dport = (uint16(data[36]) shl 8) or uint16(data[37])
|
|
return dport
|
|
return 0
|
|
|
|
proc dispatch_packet(data: ptr UncheckedArray[byte], len: int, id: uint16) =
|
|
let dest_port = parse_dest_port(data)
|
|
let flow = if dest_port != 0: flow_table[dest_port] else: nil
|
|
|
|
if dest_port == 8080:
|
|
var msg = "[ION SW] 8080 Hit! RingPtr="
|
|
console_write(addr msg[0], csize_t(msg.len))
|
|
# Simple address check (first 8 bytes of ptr)
|
|
if flow != nil:
|
|
var hex_str = "ADR\n"
|
|
console_write(addr hex_str[0], 4)
|
|
|
|
var pkt: IonPacket
|
|
pkt.id = id
|
|
pkt.len = uint16(len)
|
|
pkt.data = data
|
|
|
|
if flow != nil and flow.fType == FLOW_DIRECT:
|
|
if flow.ring[].push(pkt):
|
|
var msg = "[ION SW] Pushed to Ring!\n"
|
|
console_write(addr msg[0], csize_t(msg.len))
|
|
else:
|
|
var msg = "[ION SW] Ring FULL!\n"
|
|
console_write(addr msg[0], csize_t(msg.len))
|
|
ion_free_raw(id)
|
|
else:
|
|
discard net_ingest_packet(cast[ptr byte](pkt.data), int(pkt.len))
|
|
ion_free_raw(id)
|
|
|
|
proc ion_ingress*(id: uint16, len: uint16) {.exportc.} =
|
|
## The Hot Path. Called by VirtIO Interrupt/Poller.
|
|
## Takes a Slab ID that has been filled by NIC or local TX.
|
|
|
|
const VIRTIO_NET_HDR_SIZE = 10
|
|
let slab_base = ion_get_virt(id)
|
|
|
|
if len <= VIRTIO_NET_HDR_SIZE:
|
|
# Packet too small (just header or less)
|
|
ion_free_raw(id)
|
|
return
|
|
|
|
# Adjust for Headroom (Zero-Copy Pointer Math)
|
|
# eth_frame points to the Ethernet Header, skipping VirtIO Header
|
|
let eth_frame = cast[ptr UncheckedArray[byte]](cast[uint](slab_base) + VIRTIO_NET_HDR_SIZE)
|
|
let eth_len = int(len) - VIRTIO_NET_HDR_SIZE
|
|
|
|
# DEBUG: Print RX packet info (Full Eth Header)
|
|
var prefix = "[ION] RX: "
|
|
console_write(addr prefix[0], csize_t(prefix.len))
|
|
|
|
const hexDigits = "0123456789ABCDEF"
|
|
for i in 0..<14:
|
|
let b = eth_frame[i]
|
|
var hex: array[3, char]
|
|
hex[0] = hexDigits[int(b shr 4)]
|
|
hex[1] = hexDigits[int(b and 0xF)]
|
|
hex[2] = if i == 5 or i == 11: '|' else: ' '
|
|
if i == 13: hex[2] = '\n'
|
|
console_write(addr hex[0], 3)
|
|
|
|
dispatch_packet(eth_frame, eth_len, id)
|
|
|
|
proc ion_egress*(pkt: IonPacket) {.exportc.} =
|
|
## The Fast Path TX (Standard Interface)
|
|
if not ion_tx_push(pkt):
|
|
# Backpressure / Ring Full -> Drop
|
|
var msg = "[ION SW] TX Ring FULL! Dropping.\n"
|
|
console_write(addr msg[0], csize_t(msg.len))
|
|
ion_free(pkt)
|
|
|
|
proc ion_egress_to_port*(port: uint16, pkt: IonPacket) {.exportc.} =
|
|
## Route a packet to a specific ION Port.
|
|
## Port 0 is reserved for Kernel Console.
|
|
if port == 0:
|
|
when defined(is_kernel):
|
|
console_write(pkt.data, csize_t(pkt.len))
|
|
ion_free(pkt)
|
|
else:
|
|
# In the Membrane, Port 0 egresses to the Bus
|
|
ion_egress(pkt)
|
|
else:
|
|
# Future: Internal routing via flow_table
|
|
ion_egress(pkt)
|