mirror of
https://github.com/soypat/lneto.git
synced 2026-08-19 22:24:03 +00:00
add ipv6 to xnet.StackAsync (#107)
* add ipv6 to xnet.StackAsync * dns improvements * improve DNS workings of StackAsync * add tentative ICMPv6 * work on prefixes and fix some small bugs, plan UDP/TCP6 * fix bugs in StackAsync and ipv4.Prefix.Contains * update arpsubtable * completely remove legacy internet.StackIP for StackIPv4/v6 * ipv4/ipv6 tcp/udp * add TCP6/UDP6 dialing APIs * add xnet.Stack6 interface * more ipv6 integration into StackAsync; various tweaks to lneto and documentation+TODOs * add stack6 tests * replace netip.Prefix with ipv4.Prefix where it makes sense
This commit is contained in:
@@ -137,7 +137,7 @@ func run() error {
|
||||
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
|
||||
addr := stack.Addr4()
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ipv4.AppendFormatAddr(nil, addr), []byte("us"))
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddress()), []byte("us"))
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddr()), []byte("us"))
|
||||
pfbuf = append(pfbuf, ']', '\n')
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -232,7 +232,7 @@ func run() error {
|
||||
return fmt.Errorf("ARP resolution of router failed: %w", err)
|
||||
}
|
||||
// Set gateway on the async stack (exported API).
|
||||
stack.SetGateway6(routerHw)
|
||||
stack.SetGatewayHardwareAddr(routerHw)
|
||||
|
||||
// Create Berkeley listener via SocketNetip
|
||||
laddr := netip.AddrPortFrom(netip.IPv4Unspecified(), uint16(flagPort))
|
||||
@@ -332,7 +332,7 @@ func mockClient(stack *xnet.StackAsync, port uint16, subnet netip.Prefix) {
|
||||
err := mockStack.Reset(xnet.StackConfig{
|
||||
StaticAddress4: subnet.Addr().Next().As4(),
|
||||
MaxActiveTCPPorts: 1,
|
||||
HardwareAddress: stack.Gateway6(),
|
||||
HardwareAddress: stack.GatewayHardwareAddr(),
|
||||
Hostname: "the-other",
|
||||
MTU: uint16(stack.MTU()),
|
||||
RandSeed: int64(stack.Prand32()),
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
//go:build !tinygo && linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type program struct {
|
||||
Name string
|
||||
Link string // relative path for README link
|
||||
Dir string // directory to build from, relative to repo root
|
||||
ExtraProtocols string
|
||||
PacketCapture bool
|
||||
}
|
||||
|
||||
type buildTarget struct {
|
||||
Name string
|
||||
ext string // output file extension (determines format for tinygo)
|
||||
build func(dir, outFile string) error
|
||||
}
|
||||
|
||||
type result struct {
|
||||
BinarySize int64
|
||||
CompileTime time.Duration
|
||||
DNC bool // Does Not Compile
|
||||
Err error
|
||||
}
|
||||
|
||||
func (r result) sizeString() string {
|
||||
if r.DNC {
|
||||
return "DNC"
|
||||
}
|
||||
if r.Err != nil {
|
||||
return "ERR"
|
||||
}
|
||||
return formatSize(r.BinarySize)
|
||||
}
|
||||
|
||||
func formatSize(n int64) string {
|
||||
const mb = 1024 * 1024
|
||||
if n >= mb {
|
||||
return fmt.Sprintf("%.1fMB", float64(n)/mb)
|
||||
}
|
||||
return fmt.Sprintf("%dkB", (n+512)/1024)
|
||||
}
|
||||
|
||||
func goBuild(goos, goarch string) func(dir, out string) error {
|
||||
return func(dir, out string) error {
|
||||
cmd := exec.Command("go", "build", "-o", out, ".")
|
||||
cmd.Dir = dir
|
||||
cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("%w: %s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func tinygoBuild(target string) func(dir, out string) error {
|
||||
return func(dir, out string) error {
|
||||
args := []string{"build"}
|
||||
if target != "" {
|
||||
args = append(args, "-target="+target)
|
||||
}
|
||||
args = append(args, "-o", out, ".")
|
||||
cmd := exec.Command("tinygo", args...)
|
||||
cmd.Dir = dir
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("%w: %s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var buildTargets = []buildTarget{
|
||||
{Name: "amd64 Go", ext: ".elf", build: goBuild("linux", "amd64")},
|
||||
{Name: "WASM Go", ext: ".wasm", build: goBuild("wasip1", "wasm")},
|
||||
{Name: "amd64 TinyGo", ext: ".elf", build: tinygoBuild("")},
|
||||
{Name: "WASM TinyGo", ext: ".wasm", build: tinygoBuild("wasm")},
|
||||
{Name: "Pico TinyGo", ext: ".bin", build: tinygoBuild("pico")},
|
||||
}
|
||||
|
||||
var programs = []program{
|
||||
{
|
||||
Name: "Lneto MWE",
|
||||
Link: "./examples/min-working-example/",
|
||||
Dir: "examples/min-working-example",
|
||||
ExtraProtocols: "DNS,NTP,DHCP",
|
||||
PacketCapture: true,
|
||||
},
|
||||
{
|
||||
Name: "Gvisor MWE w/ go-net",
|
||||
Link: "./examples/_import_examples/gvisor-mwe/",
|
||||
Dir: "examples/_import_examples/gvisor-mwe",
|
||||
ExtraProtocols: "None",
|
||||
PacketCapture: false,
|
||||
},
|
||||
}
|
||||
|
||||
func measure(dir, outFile string, fn func(dir, out string) error) result {
|
||||
start := time.Now()
|
||||
err := fn(dir, outFile)
|
||||
elapsed := time.Since(start)
|
||||
if err != nil {
|
||||
return result{DNC: true, CompileTime: elapsed, Err: err}
|
||||
}
|
||||
fi, err := os.Stat(outFile)
|
||||
if err != nil {
|
||||
return result{Err: err, CompileTime: elapsed}
|
||||
}
|
||||
size := fi.Size()
|
||||
os.Remove(outFile)
|
||||
return result{BinarySize: size, CompileTime: elapsed}
|
||||
}
|
||||
|
||||
func main() {
|
||||
root := flag.String("root", ".", "path to repository root")
|
||||
flag.Parse()
|
||||
|
||||
repoRoot, err := filepath.Abs(*root)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "binbench-*")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
type row struct {
|
||||
prog program
|
||||
results []result
|
||||
}
|
||||
rows := make([]row, len(programs))
|
||||
for i, prog := range programs {
|
||||
dir := filepath.Join(repoRoot, prog.Dir)
|
||||
results := make([]result, len(buildTargets))
|
||||
for j, bt := range buildTargets {
|
||||
outFile := filepath.Join(tmpDir, fmt.Sprintf("p%d_t%d%s", i, j, bt.ext))
|
||||
fmt.Fprintf(os.Stderr, "building %s for %s...\n", prog.Name, bt.Name)
|
||||
r := measure(dir, outFile, bt.build)
|
||||
if r.DNC {
|
||||
fmt.Fprintf(os.Stderr, " DNC: %v\n", r.Err)
|
||||
}
|
||||
results[j] = r
|
||||
}
|
||||
rows[i] = row{prog: prog, results: results}
|
||||
}
|
||||
|
||||
// Print markdown table.
|
||||
headers := []string{"Program", "Extra Protocols", "Packet capture printing"}
|
||||
for _, bt := range buildTargets {
|
||||
headers = append(headers, bt.Name)
|
||||
}
|
||||
fmt.Printf("| %s |\n", strings.Join(headers, " | "))
|
||||
|
||||
aligns := make([]string, len(headers))
|
||||
aligns[0] = "---"
|
||||
aligns[1] = ":---:"
|
||||
aligns[2] = ":---:"
|
||||
for i := 3; i < len(aligns); i++ {
|
||||
aligns[i] = "---"
|
||||
}
|
||||
fmt.Printf("|%s|\n", strings.Join(aligns, "|"))
|
||||
|
||||
for _, r := range rows {
|
||||
pcap := "❌"
|
||||
if r.prog.PacketCapture {
|
||||
pcap = "✅"
|
||||
}
|
||||
cols := []string{
|
||||
fmt.Sprintf("[%s](%s)", r.prog.Name, r.prog.Link),
|
||||
r.prog.ExtraProtocols,
|
||||
pcap,
|
||||
}
|
||||
for _, res := range r.results {
|
||||
cols = append(cols, res.sizeString())
|
||||
}
|
||||
fmt.Printf("| %s |\n", strings.Join(cols, " | "))
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func run() (err error) {
|
||||
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
|
||||
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ipv4.AppendFormatAddr(nil, stack.Addr4()), []byte("us"))
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddress()), []byte("us"))
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddr()), []byte("us"))
|
||||
pfbuf = append(pfbuf, ']', '\n')
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -220,7 +220,7 @@ func run() (err error) {
|
||||
return fmt.Errorf("ARP resolution of router failed: %w", err)
|
||||
}
|
||||
timeResolveRouterHW()
|
||||
stack.SetGateway6(routerHw)
|
||||
stack.SetGatewayHardwareAddr(routerHw)
|
||||
|
||||
svPort := uint16(flagPort)
|
||||
fmt.Printf("Listening on %s:%d\n", ipv4.AppendFormatAddr(nil, stack.Addr4()), svPort)
|
||||
@@ -233,7 +233,7 @@ func run() (err error) {
|
||||
TxBuf: make([]byte, mtu),
|
||||
TxPacketQueueSize: 3,
|
||||
})
|
||||
err = stack.ListenTCP(&conn, svPort)
|
||||
err = stack.ListenTCP4(&conn, svPort)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listen TCP: %w", err)
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ type arpEntry struct {
|
||||
|
||||
// newDHCPInterceptor creates a dhcpInterceptor that wraps iface and serves
|
||||
// DHCP from the given server address and subnet.
|
||||
func newDHCPInterceptor(iface ltesto.Interface, svIP [4]byte, svMAC [6]byte, subnet netip.Prefix) (*dhcpInterceptor, error) {
|
||||
func newDHCPInterceptor(iface ltesto.Interface, svIP [4]byte, svMAC [6]byte, subnet ipv4.Prefix) (*dhcpInterceptor, error) {
|
||||
d := &dhcpInterceptor{
|
||||
inner: iface,
|
||||
svMAC: svMAC,
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/soypat/lneto/internal"
|
||||
"github.com/soypat/lneto/internal/ltesto"
|
||||
"github.com/soypat/lneto/internet/pcap"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -73,8 +74,10 @@ func run() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svIP := ipMask.Addr().As4()
|
||||
iface, err = newDHCPInterceptor(iface, svIP, hwaddr, ipMask.Masked())
|
||||
subnet := ipv4.PrefixFromNetip(ipMask)
|
||||
iface, err = newDHCPInterceptor(iface, svIP, hwaddr, subnet.Masked())
|
||||
if err != nil {
|
||||
return fmt.Errorf("DHCP interceptor: %w", err)
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func run(ctx context.Context, stack *xnet.StackAsync) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolving router MAC: %w", err)
|
||||
}
|
||||
stack.SetGateway6(gateway)
|
||||
stack.SetGatewayHardwareAddr(gateway)
|
||||
berkstack := stack.StackBlocking(stackBackoff).StackGo(xnet.StackGoConfig{
|
||||
ListenerPoolConfig: xnet.TCPPoolConfig{
|
||||
PoolSize: tcpConnPoolSize,
|
||||
|
||||
@@ -159,7 +159,7 @@ func run() (err error) {
|
||||
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
|
||||
addr := stack.Addr4()
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, addr[:], []byte("us"))
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddress()), []byte("us"))
|
||||
pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddr()), []byte("us"))
|
||||
pfbuf = append(pfbuf, ']', '\n')
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -248,7 +248,7 @@ func run() (err error) {
|
||||
return fmt.Errorf("ARP resolution of router failed: %w", err)
|
||||
}
|
||||
timeResolveRouterHW()
|
||||
stack.SetGateway6(routerHw)
|
||||
stack.SetGatewayHardwareAddr(routerHw)
|
||||
if flagDoNTP {
|
||||
timeLookupNTP := timer("NTP IP lookup")
|
||||
const ntpHost = "pool.ntp.org"
|
||||
|
||||
Reference in New Issue
Block a user