From 8f1e045cfcdc0a109d606f6d1f12fc87b2bb9525 Mon Sep 17 00:00:00 2001 From: impact-eintr Date: Wed, 23 Nov 2022 15:41:57 +0800 Subject: [PATCH] fdbased test --- tcpip/buffer/prependable.go | 2 +- tcpip/link/fdbased/endpoint.go | 6 +- tcpip/link/fdbased/endpoint_test.go | 220 +++++++++++++++++++++++++++- tcpip/stack/route.go | 2 +- 4 files changed, 218 insertions(+), 12 deletions(-) diff --git a/tcpip/buffer/prependable.go b/tcpip/buffer/prependable.go index f0d5c0a..e2247ca 100644 --- a/tcpip/buffer/prependable.go +++ b/tcpip/buffer/prependable.go @@ -28,5 +28,5 @@ func (p *Prependable) Prepend(size int) []byte { return nil } p.usedIdx -= size - return p.View()[:size:size] // p.buf[p.usedIdx:size:size] + return p.View()[:size:size] // p.buf[p.usedIdx:p.usedIdx+size:size] } diff --git a/tcpip/link/fdbased/endpoint.go b/tcpip/link/fdbased/endpoint.go index e5675b3..d45b434 100644 --- a/tcpip/link/fdbased/endpoint.go +++ b/tcpip/link/fdbased/endpoint.go @@ -134,7 +134,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, } // Attach 启动从文件描述符中读取数据包的goroutine,并通过提供的分发函数来分发数据报 -func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) { +func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) { e.dispatcher = dispatcher // 链接端点不可靠。保存传输端点后,它们将停止发送传出数据包,并拒绝所有传入数据包。 go e.dispatchLoop() @@ -210,13 +210,13 @@ func (e *endpoint) dispatch() (bool, *tcpip.Error) { return true, nil } -// 循环地从fd中读取数据 然后就爱那个数据报分发给协议栈 +// 循环地从fd中读取数据 然后将数据报分发给协议栈 func (e *endpoint) dispatchLoop() *tcpip.Error { for { cont, err := e.dispatch() if err != nil || !cont { if e.closed != nil { - e.closed(err) + e.closed(err) // 阻塞中 } return err } diff --git a/tcpip/link/fdbased/endpoint_test.go b/tcpip/link/fdbased/endpoint_test.go index e35b02e..3371f81 100644 --- a/tcpip/link/fdbased/endpoint_test.go +++ b/tcpip/link/fdbased/endpoint_test.go @@ -1,8 +1,13 @@ package fdbased import ( + "fmt" + "reflect" + "time" + "math/rand" "netstack/tcpip" "netstack/tcpip/buffer" + "netstack/tcpip/header" "netstack/tcpip/stack" "syscall" "testing" @@ -10,8 +15,8 @@ import ( const ( mtu = 1500 - laddr = tcpip.LinkAddress("\x11\x22\x33\x44\x55\x66") - raddr = tcpip.LinkAddress("\x77\x88\x99\xaa\xbb\xcc") + laddr = tcpip.LinkAddress("\x65\x66\x67\x68\x69\x70") + raddr = tcpip.LinkAddress("\x71\x72\x73\x74\x75\x76") proto = 10 ) @@ -25,11 +30,11 @@ type context struct { t *testing.T fds [2]int ep stack.LinkEndpoint - ch chan packetInfo - done chan struct{} + ch chan packetInfo // 信道 + done chan struct{} // 通知退出 } -func NewContext(t *testing.T, opt *Options) *context { +func newContext(t *testing.T, opt *Options) *context { fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0) if err != nil { t.Fatalf("Socketpair failed: %v", err) @@ -41,7 +46,7 @@ func NewContext(t *testing.T, opt *Options) *context { } opt.FD = fds[1] - ep := stack.FindLinkEndpoint(New(opt)).(*endpoint) + ep := stack.FindLinkEndpoint(New(opt)).(*endpoint) // 找到端口实现 c := &context{ t: t, @@ -51,11 +56,16 @@ func NewContext(t *testing.T, opt *Options) *context { done: done, } - ep.Attach(c) + ep.Attach(c) // 启动端口 后台阻塞等待 return c } +func (c *context) cleanup() { + syscall.Close(c.fds[0]) + <-c.done + syscall.Close(c.fds[1]) +} func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, dstLinkAddr, srcLinkAddr tcpip.LinkAddress, @@ -64,4 +74,200 @@ func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, } func TestFdbased(t *testing.T) { + c := newContext(t, &Options{MTU: mtu, Address: tcpip.LinkAddress(laddr)}) + defer c.cleanup() + + // Build header + hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()) + 100) // 114 + b := hdr.Prepend(100) // payload + for i := range b { + b[i] = uint8(rand.Intn(256)) + } + + // Build payload and write + payload := make(buffer.View, 1024) // payload len = 1024 + for i := range payload { + payload[i] = uint8(rand.Intn(256)) + } + + if err := c.ep.WritePacket(&stack.Route{RemoteLinkAddress: raddr}, hdr, + payload.ToVectoriseView(), proto); err != nil { + panic(err) + } + + b = make([]byte, mtu) + n, err := syscall.Read(c.fds[0], b) + if err != nil { + panic(err) + } + b = b[:n] + h := header.Ethernet(b) + if h.DestinationAddress() != raddr || h.SourceAddress() != laddr { + panic("diff Err") + } +} + +func TestPreserveSrcAddress(t *testing.T) { + baddr := tcpip.LinkAddress("\xcc\xbb\xaa\x77\x88\x99") + + c := newContext(t, &Options{Address: laddr, MTU: mtu}) + defer c.cleanup() + + // Set LocalLinkAddress in route to the value of the bridged address. + r := &stack.Route{ + RemoteLinkAddress: raddr, + LocalLinkAddress: baddr, + } + + // WritePacket panics given a prependable with anything less than + // the minimum size of the ethernet header. + hdr := buffer.NewPrependable(header.EthernetMinimumSize) + if err := c.ep.WritePacket(r, hdr, buffer.VectorisedView{}, proto); err != nil { + t.Fatalf("WritePacket failed: %v", err) + } + + // Read from the FD, then compare with what we wrote. + b := make([]byte, mtu) + n, err := syscall.Read(c.fds[0], b) + if err != nil { + t.Fatalf("Read failed: %v", err) + } + b = b[:n] + h := header.Ethernet(b) + + if a := h.SourceAddress(); a != baddr { + t.Fatalf("SourceAddress() = %v, want %v", a, baddr) + } +} + +func TestDeliverPacket(t *testing.T) { + lengths := []int{100, 1000} + for _, plen := range lengths { + t.Run(fmt.Sprintf("PayloadLen=%v", plen), func(t *testing.T) { + c := newContext(t, &Options{Address: laddr, MTU: mtu}) + defer c.cleanup() + + // Build packet. + b := make([]byte, plen) + all := b + for i := range b { + b[i] = uint8(rand.Intn(256)) + } + + hdr := make(header.Ethernet, header.EthernetMinimumSize) + hdr.Encode(&header.EthernetFields{ + SrcAddr: raddr, + DstAddr: laddr, + Type: proto, + }) + all = append(hdr, b...) + + // Write packet via the file descriptor. + if _, err := syscall.Write(c.fds[0], all); err != nil { + t.Fatalf("Write failed: %v", err) + } + + // Receive packet through the endpoint. + select { + case pi := <-c.ch: + want := packetInfo{ + raddr: raddr, + proto: proto, + contents: b, + } + + if !reflect.DeepEqual(want, pi) { + t.Fatalf("Unexpected received packet: %+v, want %+v", pi, want) + } + case <-time.After(10 * time.Second): + t.Fatalf("Timed out waiting for packet") + } + }) + } +} + +//func TestBufConfigMaxLength(t *testing.T) { +// got := 0 +// for _, i := range BufConfig { +// got += i +// } +// want := header.MaxIPPacketSize // maximum TCP packet size +// if got < want { +// t.Errorf("total buffer size is invalid: got %d, want >= %d", got, want) +// } +//} + +func TestBufConfigFirst(t *testing.T) { + // The stack assumes that the TCP/IP header is enterily contained in the first view. + // Therefore, the first view needs to be large enough to contain the maximum TCP/IP + // header, which is 120 bytes (60 bytes for IP + 60 bytes for TCP). + want := 120 + got := BufConfig[0] + if got < want { + t.Errorf("first view has an invalid size: got %d, want >= %d", got, want) + } +} + +func build(bufConfig []int) *endpoint { + e := &endpoint{ + views: make([]buffer.View, len(bufConfig)), + iovecs: make([]syscall.Iovec, len(bufConfig)), + } + e.allocateViews(bufConfig) + return e +} + +var capLengthTestCases = []struct { + comment string + config []int + n int + wantUsed int + wantLengths []int +}{ + { + comment: "Single slice", + config: []int{2}, + n: 1, + wantUsed: 1, + wantLengths: []int{1}, + }, + { + comment: "Multiple slices", + config: []int{1, 2}, + n: 2, + wantUsed: 2, + wantLengths: []int{1, 1}, + }, + { + comment: "Entire buffer", + config: []int{1, 2}, + n: 3, + wantUsed: 2, + wantLengths: []int{1, 2}, + }, + { + comment: "Entire buffer but not on the last slice", + config: []int{1, 2, 3}, + n: 3, + wantUsed: 2, + wantLengths: []int{1, 2, 3}, + }, +} + +func TestCapLength(t *testing.T) { + for _, c := range capLengthTestCases { + e := build(c.config) + used := e.capViews(c.n, c.config) + if used != c.wantUsed { + t.Errorf("Test \"%s\" failed when calling capViews(%d, %v). Got %d. Want %d", c.comment, c.n, c.config, used, c.wantUsed) + } + lengths := make([]int, len(e.views)) + for i, v := range e.views { + lengths[i] = len(v) + } + if !reflect.DeepEqual(lengths, c.wantLengths) { + t.Errorf("Test \"%s\" failed when calling capViews(%d, %v). Got %v. Want %v", c.comment, c.n, c.config, lengths, c.wantLengths) + } + + } } diff --git a/tcpip/stack/route.go b/tcpip/stack/route.go index c56d633..3fb6af2 100644 --- a/tcpip/stack/route.go +++ b/tcpip/stack/route.go @@ -24,5 +24,5 @@ type Route struct { NetProto tcpip.NetworkProtocolNumber // 相关的网络终端 - ref *referenceNetworkEndpoint + //ref *referenceNetworkEndpoint }