continue reworking node API

This commit is contained in:
soypat
2025-07-13 01:07:08 -03:00
parent 2bd056a04c
commit 1549e563e9
7 changed files with 64 additions and 33 deletions
+6 -8
View File
@@ -14,7 +14,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/soypat/lneto"
"github.com/soypat/lneto/arp" "github.com/soypat/lneto/arp"
"github.com/soypat/lneto/dhcpv4" "github.com/soypat/lneto/dhcpv4"
"github.com/soypat/lneto/dns" "github.com/soypat/lneto/dns"
@@ -82,7 +81,6 @@ func run() (err error) {
return err return err
} }
brHW := nicHW brHW := nicHW
brHW[4]++
mtu, err := iface.MTU() mtu, err := iface.MTU()
if err != nil { if err != nil {
return err return err
@@ -138,8 +136,6 @@ func run() (err error) {
hw, err := stack.ResultResolveHardwareAddress6(netip.AddrFrom4(router)) hw, err := stack.ResultResolveHardwareAddress6(netip.AddrFrom4(router))
if err == nil { if err == nil {
stack.link.SetGateway6(hw) stack.link.SetGateway6(hw)
stack.link.SetHardwareAddr6([6]byte{0xd8, 0x5e, 0xd3, 0x43, 0x03, 0xeb})
stack.ip.SetAddr(netip.AddrFrom4([4]byte{192, 168, 1, 53}))
if flagDoNTP { if flagDoNTP {
state = stateDNSNTP state = stateDNSNTP
err = stack.StartLookupIP("pool.ntp.org") err = stack.StartLookupIP("pool.ntp.org")
@@ -274,11 +270,12 @@ func (s *Stack) Encapsulate(b []byte, _ int) (int, error) {
} }
func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error { func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error {
err := s.link.Reset6(mac, ethernet.BroadcastAddr(), int(mtu)) const maxNodes = 8
err := s.link.Reset6(mac, ethernet.BroadcastAddr(), int(mtu), maxNodes)
if err != nil { if err != nil {
return err return err
} }
err = s.ip.Reset(addr) err = s.ip.Reset(addr, maxNodes)
if err != nil { if err != nil {
return err return err
} }
@@ -298,7 +295,7 @@ func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error {
if err != nil { if err != nil {
return err return err
} }
err = s.udps.Reset(uint64(lneto.IPProtoUDP), 2) err = s.udps.ResetUDP(maxNodes)
if err != nil { if err != nil {
return err return err
} }
@@ -355,6 +352,7 @@ func (s *Stack) StartLookupIP(host string) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Println("START LOOKUP", host, dns4[:])
return nil return nil
} }
@@ -404,7 +402,7 @@ func (s *Stack) BeginDHCPRequest(request [4]byte) error {
} }
func (s *Stack) StartNTP(addr netip.Addr) error { func (s *Stack) StartNTP(addr netip.Addr) error {
s.ntp.Reset(time.Now, s.sysprec) s.ntp.Reset(s.sysprec, time.Now)
var u internet.StackUDPPort var u internet.StackUDPPort
addr4 := addr.As4() addr4 := addr.As4()
u.SetStackNode(&s.ntp, addr4[:], ntp.ServerPort) u.SetStackNode(&s.ntp, addr4[:], ntp.ServerPort)
+4 -3
View File
@@ -185,15 +185,16 @@ type Stack struct {
} }
func (stack *Stack) Reset(ourMAC, gwMAC [6]byte, ip netip.Addr, mtu int) (err error) { func (stack *Stack) Reset(ourMAC, gwMAC [6]byte, ip netip.Addr, mtu int) (err error) {
err = stack.ethernet.Reset6(ourMAC, gwMAC, mtu) const maxNodes = 8
err = stack.ethernet.Reset6(ourMAC, gwMAC, mtu, maxNodes)
if err != nil { if err != nil {
return err return err
} }
err = stack.ip.Reset(ip) err = stack.ip.Reset(ip, maxNodes)
if err != nil { if err != nil {
return err return err
} }
stack.tcpports.Reset(uint64(lneto.IPProtoTCP), 2) stack.tcpports.ResetTCP(maxNodes)
ipaddr := ip.As4() ipaddr := ip.As4()
err = stack.arp.Reset(arp.HandlerConfig{ err = stack.arp.Reset(arp.HandlerConfig{
HardwareAddr: ourMAC[:], HardwareAddr: ourMAC[:],
+14 -6
View File
@@ -4,7 +4,6 @@ import (
"errors" "errors"
"math" "math"
"net" "net"
"slices"
) )
// StackNode is an abstraction of a packet exchanging protocol controller. This is the building block for all protocols, // StackNode is an abstraction of a packet exchanging protocol controller. This is the building block for all protocols,
@@ -46,9 +45,21 @@ var (
errZeroPort = errors.New("port must be greater than zero") errZeroPort = errors.New("port must be greater than zero")
errInvalidProto = errors.New("invalid protocol") errInvalidProto = errors.New("invalid protocol")
errProtoRegistered = errors.New("protocol already registered") errProtoRegistered = errors.New("protocol already registered")
errNodesFull = errors.New("no more room for new nodes")
_ = net.ErrClosed _ = net.ErrClosed
) )
func registerNode(nodesPtr *[]node, h node) error {
if cap(*nodesPtr)-len(*nodesPtr) <= 0 {
*nodesPtr = nodesCompact(*nodesPtr)
}
if cap(*nodesPtr)-len(*nodesPtr) <= 0 {
return errNodesFull
}
*nodesPtr = append(*nodesPtr, h)
return nil
}
func handleNodeError(nodesPtr *[]node, nodeIdx int, err error) (discarded bool) { func handleNodeError(nodesPtr *[]node, nodeIdx int, err error) (discarded bool) {
if err != nil { if err != nil {
if nodeIdx >= len(*nodesPtr) { if nodeIdx >= len(*nodesPtr) {
@@ -56,7 +67,8 @@ func handleNodeError(nodesPtr *[]node, nodeIdx int, err error) (discarded bool)
} }
nodes := *nodesPtr nodes := *nodesPtr
if checkNodeErr(&nodes[nodeIdx], err) { if checkNodeErr(&nodes[nodeIdx], err) {
*nodesPtr = slices.Delete(nodes, nodeIdx, nodeIdx+1) // *nodesPtr = slices.Delete(nodes, nodeIdx, nodeIdx+1)
(*nodesPtr)[nodeIdx] = node{} // 'Delete' node without modifying slice length.
discarded = true discarded = true
} }
} }
@@ -71,10 +83,6 @@ func checkNodeErr(node *node, err error) (discard bool) {
return checkNode(node) || (err != nil && err == net.ErrClosed) return checkNode(node) || (err != nil && err == net.ErrClosed)
} }
func addNode(nodes *[]node, h StackNode, port uint16, protocol uint64) {
*nodes = append(*nodes, nodeFromStackNode(h, port, protocol))
}
func nodeFromStackNode(s StackNode, port uint16, protocol uint64) node { func nodeFromStackNode(s StackNode, port uint16, protocol uint64) node {
if protocol > math.MaxUint16 { if protocol > math.MaxUint16 {
panic(">16bit protocol number unsupported") panic(">16bit protocol number unsupported")
+4 -2
View File
@@ -6,6 +6,7 @@ import (
"log/slog" "log/slog"
"math" "math"
"net" "net"
"slices"
"github.com/soypat/lneto" "github.com/soypat/lneto"
"github.com/soypat/lneto/ethernet" "github.com/soypat/lneto/ethernet"
@@ -32,13 +33,14 @@ func (ls *StackEthernet) HardwareAddr6() [6]byte {
return ls.mac return ls.mac
} }
func (ls *StackEthernet) Reset6(mac, gateway [6]byte, mtu int) error { func (ls *StackEthernet) Reset6(mac, gateway [6]byte, mtu, maxNodes int) error {
if mtu > math.MaxUint16 || mtu < 256 { if mtu > math.MaxUint16 || mtu < 256 {
return errors.New("invalid MTU") return errors.New("invalid MTU")
} }
ls.handlers = slices.Grow(ls.handlers[:0], maxNodes)
*ls = StackEthernet{ *ls = StackEthernet{
connID: ls.connID + 1, connID: ls.connID + 1,
handlers: ls.handlers[:0], handlers: ls.handlers,
logger: ls.logger, logger: ls.logger,
mac: mac, mac: mac,
gwmac: gateway, gwmac: gateway,
+5 -3
View File
@@ -5,6 +5,7 @@ import (
"io" "io"
"log/slog" "log/slog"
"net/netip" "net/netip"
"slices"
"github.com/soypat/lneto" "github.com/soypat/lneto"
"github.com/soypat/lneto/ethernet" "github.com/soypat/lneto/ethernet"
@@ -25,15 +26,16 @@ type StackIP struct {
logger logger
} }
func (sb *StackIP) Reset(addr netip.Addr) error { func (sb *StackIP) Reset(addr netip.Addr, maxNodes int) error {
err := sb.SetAddr(addr) err := sb.SetAddr(addr)
if err != nil { if err != nil {
return err return err
} }
sb.handlers = slices.Grow(sb.handlers[:0], maxNodes)
*sb = StackIP{ *sb = StackIP{
connID: sb.connID + 1, connID: sb.connID + 1,
validator: sb.validator, validator: sb.validator,
handlers: sb.handlers[:0], handlers: sb.handlers,
logger: sb.logger, logger: sb.logger,
ip: sb.ip, ip: sb.ip,
} }
@@ -157,7 +159,7 @@ func (sb *StackIP) Encapsulate(carrierData []byte, frameOffset int) (int, error)
n, err := h.encapsulate(frame[:], headerlen) n, err := h.encapsulate(frame[:], headerlen)
if err != nil { if err != nil {
if handleNodeError(&sb.handlers, i, err) { if handleNodeError(&sb.handlers, i, err) {
println("NODE REMOVED", proto.String(), h.port) println("IP NODE REMOVED", proto.String(), h.port)
h.destroy() h.destroy()
} }
sb.error("StackIP:encapsulate", slog.String("proto", proto.String()), slog.String("err", err.Error())) sb.error("StackIP:encapsulate", slog.String("proto", proto.String()), slog.String("err", err.Error()))
+30 -10
View File
@@ -4,22 +4,34 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"math" "math"
"slices"
"github.com/soypat/lneto"
) )
type StackPorts struct { type StackPorts struct {
connID uint64 connID uint64
handlers []node handlers []node
dstPortOff int dstPortOff uint16
protocol uint16 protocol uint16
} }
func (ps *StackPorts) Reset(protocol uint64, dstPortOffset int) error { func (ps *StackPorts) ResetUDP(maxNodes int) error {
return ps.Reset(uint64(lneto.IPProtoUDP), 2, maxNodes)
}
func (ps *StackPorts) ResetTCP(maxNodes int) error {
return ps.Reset(uint64(lneto.IPProtoTCP), 2, maxNodes)
}
func (ps *StackPorts) Reset(protocol uint64, dstPortOffset uint16, maxNodes int) error {
if protocol > math.MaxUint16 { if protocol > math.MaxUint16 {
return errInvalidProto return errInvalidProto
} }
ps.handlers = slices.Grow(ps.handlers[:0], maxNodes)
*ps = StackPorts{ *ps = StackPorts{
connID: ps.connID + 1, connID: ps.connID + 1,
handlers: ps.handlers[:0], handlers: ps.handlers,
dstPortOff: dstPortOffset, dstPortOff: dstPortOffset,
protocol: uint16(protocol), protocol: uint16(protocol),
} }
@@ -33,25 +45,28 @@ func (ps *StackPorts) Protocol() uint64 { return uint64(ps.protocol) }
func (ps *StackPorts) ConnectionID() *uint64 { return &ps.connID } func (ps *StackPorts) ConnectionID() *uint64 { return &ps.connID }
func (ps *StackPorts) Encapsulate(b []byte, offset int) (n int, err error) { func (ps *StackPorts) Encapsulate(b []byte, offset int) (n int, err error) {
if ps.dstPortOff+offset+2 > len(b) { if int(ps.dstPortOff)+offset+2 > len(b) {
return 0, io.ErrShortBuffer return 0, io.ErrShortBuffer
} }
var i int var i int
for i = 0; i < len(ps.handlers); i++ { for i = 0; i < len(ps.handlers); i++ {
n, err = ps.handlers[i].encapsulate(b, offset) n, err = ps.handlers[i].encapsulate(b, offset)
if err != nil || n > 0 { if err != nil || n > 0 {
if ps.handleResult(i, n, err) {
err = nil // Handler discarded. Keep looking for other handlers.
continue
}
break break
} }
} }
ps.handleResult(i, n, err)
return n, err return n, err
} }
func (ps *StackPorts) Demux(b []byte, offset int) (err error) { func (ps *StackPorts) Demux(b []byte, offset int) (err error) {
if ps.dstPortOff+offset+2 > len(b) { if int(ps.dstPortOff)+offset+2 > len(b) {
return io.ErrShortBuffer return io.ErrShortBuffer
} }
port := binary.BigEndian.Uint16(b[ps.dstPortOff+offset:]) port := binary.BigEndian.Uint16(b[int(ps.dstPortOff)+offset:])
var i int var i int
for i = 0; i < len(ps.handlers); i++ { for i = 0; i < len(ps.handlers); i++ {
if port != ps.handlers[i].port { if port != ps.handlers[i].port {
@@ -59,6 +74,10 @@ func (ps *StackPorts) Demux(b []byte, offset int) (err error) {
} }
err = ps.handlers[i].demux(b, offset) err = ps.handlers[i].demux(b, offset)
if err != nil { if err != nil {
if ps.handleResult(i, 0, err) {
err = nil // Handler discarded. Keep looking for other maybe available handlers.
continue
}
break break
} }
} }
@@ -74,16 +93,17 @@ func (ps *StackPorts) Register(h StackNode) error {
} else if proto != uint64(ps.protocol) { } else if proto != uint64(ps.protocol) {
return errInvalidProto return errInvalidProto
} }
ps.handlers = append(ps.handlers, node{ return registerNode(&ps.handlers, node{
demux: h.Demux, demux: h.Demux,
encapsulate: h.Encapsulate, encapsulate: h.Encapsulate,
port: port, port: port,
}) })
return nil
} }
func (ps *StackPorts) handleResult(handlerIdx, n int, err error) { func (ps *StackPorts) handleResult(handlerIdx, n int, err error) (discarded bool) {
if handleNodeError(&ps.handlers, handlerIdx, err) { if handleNodeError(&ps.handlers, handlerIdx, err) {
discarded = true
println("DISCARD", handlerIdx, "witherr", err.Error()) println("DISCARD", handlerIdx, "witherr", err.Error())
} }
return discarded
} }
+1 -1
View File
@@ -35,7 +35,7 @@ type Client struct {
sysprec int8 sysprec int8
} }
func (c *Client) Reset(now func() time.Time, sysprec int8) { func (c *Client) Reset(sysprec int8, now func() time.Time) {
*c = Client{ *c = Client{
connID: c.connID + 1, connID: c.connID + 1,
_now: now, _now: now,