mirror of
https://github.com/soypat/lneto.git
synced 2026-08-16 21:03:25 +00:00
Netdev revamp (#145)
* begin working on netdev solution * need to roll back some assumptions in next commit * dual poll/async mode for netdev.Runner * add wake on rx semantics * remove TODO * more reworking of Runner * work on applying @MDr164 suggestions and a couple extra revamps * add newline to end of test file
This commit is contained in:
+38
-19
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/netip"
|
||||
"unsafe"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
@@ -30,42 +31,48 @@ type DevEthernet interface {
|
||||
// HardwareAddr6 returns the device's 6-byte MAC address.
|
||||
// For PHY-only devices, returns the MAC provided at configuration.
|
||||
HardwareAddr6() ([6]byte, error)
|
||||
// SendEthFrameOffset transmits a complete Ethernet frame at offset given by [DevEthernet.MaxFrameSizeAndOffset].
|
||||
// SendOffsetEthFrame transmits a complete Ethernet frame at offset given by [DevEthernet.MaxFrameSizeAndOffset].
|
||||
// The frame includes the Ethernet header but NOT the FCS/CRC
|
||||
// trailer (device or stack handles CRC as appropriate).
|
||||
// SendEthFrameOffset blocks until the transmission is queued succesfully
|
||||
// SendOffsetEthFrame blocks until the transmission is queued succesfully
|
||||
// or finished sending. Should not be called concurrently
|
||||
// unless user is sure the driver supports it.
|
||||
SendOffsetEthFrame(offsetTxEthFrame []byte) error
|
||||
// SetRecvHandler registers the function called when an Ethernet
|
||||
// SetEthRecvHandler registers the function called when an Ethernet
|
||||
// frame is received. Buffers needed by the device to operate efficiently
|
||||
// should be allocated on its side. This function is mutually exclusive with EthPoll:
|
||||
// use on or the other to receive data.
|
||||
// should be allocated on its side.
|
||||
//
|
||||
// Frames may be delivered via this handler, via EthPoll's buffer, or both:
|
||||
// - Handler unset: EthPoll writes received frames into its argument buffer.
|
||||
// - Handler set: received frames are delivered to the handler. EthPoll must
|
||||
// not write to its argument buffer; it is called with a nil buffer purely
|
||||
// to pump devices that need explicit servicing to drive the handler.
|
||||
//
|
||||
// Quiescence guarantee: SetEthRecvHandler(nil) must not return while a
|
||||
// previously installed handler is executing on another goroutine, and after
|
||||
// it returns the old handler must not be invoked again (analogous to Linux
|
||||
// synchronize_irq semantics). Callers rely on this to safely reuse the
|
||||
// buffers a handler writes into.
|
||||
SetEthRecvHandler(handler func(rxEthframe []byte))
|
||||
// EthPoll services the device. For poll-based devices (e.g. CYW43439
|
||||
// over SPI), reads from the bus and invokes the handler for each
|
||||
// received frame. This method is mutually exclusive with SetEthRecvHandler:
|
||||
// use one or the other to receive data but not return data via both channels.
|
||||
// received frame.
|
||||
//
|
||||
// Behavior depends on whether a handler is set via SetEthRecvHandler:
|
||||
// - No handler: writes a received frame into buf, returning its offset/length.
|
||||
// - Handler set: buf is nil and must not be written to; EthPoll only pumps
|
||||
// the device so frames are delivered through the handler. Return values are ignored.
|
||||
EthPoll(buf []byte) (ethFrameOff, ethernetBytes int, err error)
|
||||
// MaxFrameSizeAndOffset returns the max complete device frame size
|
||||
// (including headers and any overhead) for buffer allocation.
|
||||
// (including headers and any overhead) for Ethernet Rx buffer allocation.
|
||||
// The second value returned is the offset at which the ethernet frame
|
||||
// should be stored when being passed to [DevEthernet.SendOffsetEthFrame].
|
||||
// Buffers allocated should be maxEthernetFrameSize+frameOff where maxEthernetFrameSize
|
||||
// is usually 1500 but less or equal to maxFrameSize-frameOff.
|
||||
// MTU can be calculated doing:
|
||||
// // mfu-(14+4+4) for:
|
||||
// // ethernet header+ethernet CRC if present+ethernet VLAN overhead for VLAN support.
|
||||
// mtu := dev.MaxFrameSizeAndOffset() - ethernet.MaxOverheadSize
|
||||
MaxFrameSizeAndOffset() (maxFrameSize int, frameOff int)
|
||||
// Buffers allocated for Rx should be maxFrameSize.
|
||||
MaxFrameSizeAndOffset() (maxFrameSize int, sendEthFrameOff int)
|
||||
}
|
||||
|
||||
// Stack is an abstraction for a networking stack.
|
||||
type Stack interface {
|
||||
// Configure configures this Stack with the argument mac, ip and gateway addresses.
|
||||
// The Stack must resolve the gateway hardware address if set.
|
||||
// Configure(mac net.HardwareAddr, ip netip.Prefix, gw netip.Addr) error
|
||||
|
||||
// EnableICMP enables responding/sending ICMP echo frames.
|
||||
EnableICMP(enabled bool) error
|
||||
// EnableDHCP enables DHCP on the device if enabled=true and performs a DHCP request.
|
||||
@@ -116,6 +123,18 @@ type InterfaceConfig struct {
|
||||
MTU uint16
|
||||
}
|
||||
|
||||
// RunnerBuffers returns 32-bit aligned contiguous buffers for using with [RunnerConfig].
|
||||
func (iface *Interface[C]) RunnerBuffers(n int) [][]byte {
|
||||
frmlen32 := (iface.frameSize + 3) / 4
|
||||
rawBuf32 := make([]uint32, n*frmlen32) // ensure memory aligned
|
||||
bufs := make([][]byte, n)
|
||||
for i := range n {
|
||||
buf32 := rawBuf32[i*frmlen32 : (i+1)*frmlen32]
|
||||
bufs[i] = unsafe.Slice((*byte)(unsafe.Pointer(&buf32[0])), iface.frameSize)
|
||||
}
|
||||
return bufs
|
||||
}
|
||||
|
||||
// Init initializes the interface from scratch with a netlink and device. If Init fails all methods on Interface are unsafe to call (panic).
|
||||
func (iface *Interface[C]) Init(netlink Netlink[C], dev DevEthernet, cfg InterfaceConfig) (err error) {
|
||||
if netlink == nil || dev == nil {
|
||||
|
||||
Reference in New Issue
Block a user