diff --git a/tcpip/buffer/prependable.go b/tcpip/buffer/prependable.go index 5e6c426..d6c06a8 100644 --- a/tcpip/buffer/prependable.go +++ b/tcpip/buffer/prependable.go @@ -1,6 +1,8 @@ package buffer type Prependable struct { + buf View // Buf 是支持前置缓冲区的缓冲区 + usedIdx int // 是缓冲区的使用部分开始的索引 } func NewPrependable(size int) Prependable { diff --git a/tcpip/buffer/view.go b/tcpip/buffer/view.go new file mode 100644 index 0000000..2dfac3b --- /dev/null +++ b/tcpip/buffer/view.go @@ -0,0 +1,104 @@ +package buffer + +type View []byte + +func NewView(size int) View { + return make(View, size) +} + +func NewViewFromBytes(b []byte) View { + return append(View(nil), b...) +} + +func (v *View) TrimFront(count int) { + *v = (*v)[count:] +} + +func (v *View) CapLength(length int) { + *v = (*v)[:length:length] +} + +func (v View) ToVectorisedView() VectorisedView { + return NewVectorisedView(len(v), []View{v}) +} + +// VectorisedView 是使用非连续内存的矢量化视图版本。它支持视图支持的所有便捷方法。 +type VectorisedView struct { + views []View + size int +} + +func NewVectorisedView(size int, views []View) VectorisedView { + return VectorisedView{views: views, size: size} +} + +func (vv *VectorisedView) TrimFront(count int) { + for count > 0 && len(vv.views) > 0 { + if count < len(vv.views[0]) { + vv.size -= count + vv.views[0].TrimFront(count) + return + } + count -= len(vv.views[0]) + vv.RemoveFirst() + } +} + +func (vv *VectorisedView) CapLength(length int) { + if length < 0 { + length = 0 + } + if vv.size < length { + return + } + vv.size = length + for i := range vv.views { + v := &vv.views[i] + if len(*v) >= length { + if length == 0 { + vv.views = vv.views[:i] + } else { + v.CapLength(length) + vv.views = vv.views[:i+1] // 更新view 这个写法太艹了 底层数组没有共享可以直接修改 + } + return + } + length -= len(*v) + } +} + +// 会把buffer原来的内容覆盖 +func (vv *VectorisedView) Clone(buffer []View) VectorisedView { + return VectorisedView{views: append(buffer[:0], vv.views...), size: vv.size} +} + +func (vv *VectorisedView) First() View { + if len(vv.views) == 0 { + return nil + } + return vv.views[0] +} + +func (vv *VectorisedView) RemoveFirst() { + if len(vv.views) == 0 { + return + } + vv.size -= len(vv.views[0]) + vv.views = vv.views[1:] +} + +func (vv *VectorisedView) Size() int { + return vv.size +} + +func (vv VectorisedView) ToView() View { + u := make([]byte, 0, vv.size) + for _, v := range vv.views { + u = append(u, v...) + } + return u +} + +func (vv VectorisedView) Views() []View { + return vv.views +} diff --git a/tcpip/buffer/view_test.go b/tcpip/buffer/view_test.go new file mode 100644 index 0000000..7bae37a --- /dev/null +++ b/tcpip/buffer/view_test.go @@ -0,0 +1,235 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package buffer_test contains tests for the VectorisedView type. +package buffer + +import ( + "reflect" + "testing" +) + +// copy returns a deep-copy of the vectorised view. +func (vv VectorisedView) copy() VectorisedView { + uu := VectorisedView{ + views: make([]View, 0, len(vv.views)), + size: vv.size, + } + for _, v := range vv.views { + uu.views = append(uu.views, append(View(nil), v...)) + } + return uu +} + +// vv is an helper to build VectorisedView from different strings. +func vv(size int, pieces ...string) VectorisedView { + views := make([]View, len(pieces)) + for i, p := range pieces { + views[i] = []byte(p) + } + + return NewVectorisedView(size, views) +} + +var capLengthTestCases = []struct { + comment string + in VectorisedView + length int + want VectorisedView +}{ + { + comment: "Simple case", + in: vv(2, "12"), + length: 1, + want: vv(1, "1"), + }, + { + comment: "Case spanning across two Views", + in: vv(4, "123", "4"), + length: 2, + want: vv(2, "12"), + }, + { + comment: "Corner case with negative length", + in: vv(1, "1"), + length: -1, + want: vv(0), + }, + { + comment: "Corner case with length = 0", + in: vv(3, "12", "3"), + length: 0, + want: vv(0), + }, + { + comment: "Corner case with length = size", + in: vv(1, "1"), + length: 1, + want: vv(1, "1"), + }, + { + comment: "Corner case with length > size", + in: vv(1, "1"), + length: 2, + want: vv(1, "1"), + }, +} + +func TestCapLength(t *testing.T) { + for _, c := range capLengthTestCases { + orig := c.in.copy() + c.in.CapLength(c.length) + if !reflect.DeepEqual(c.in, c.want) { + t.Errorf("Test \"%s\" failed when calling CapLength(%d) on %v. Got %v. Want %v", + c.comment, c.length, orig, c.in, c.want) + } + } +} + +var trimFrontTestCases = []struct { + comment string + in VectorisedView + count int + want VectorisedView +}{ + { + comment: "Simple case", + in: vv(2, "12"), + count: 1, + want: vv(1, "2"), + }, + { + comment: "Case where we trim an entire View", + in: vv(2, "1", "2"), + count: 1, + want: vv(1, "2"), + }, + { + comment: "Case spanning across two Views", + in: vv(3, "1", "23"), + count: 2, + want: vv(1, "3"), + }, + { + comment: "Corner case with negative count", + in: vv(1, "1"), + count: -1, + want: vv(1, "1"), + }, + { + comment: " Corner case with count = 0", + in: vv(1, "1"), + count: 0, + want: vv(1, "1"), + }, + { + comment: "Corner case with count = size", + in: vv(1, "1"), + count: 1, + want: vv(0), + }, + { + comment: "Corner case with count > size", + in: vv(1, "1"), + count: 2, + want: vv(0), + }, +} + +func TestTrimFront(t *testing.T) { + for _, c := range trimFrontTestCases { + orig := c.in.copy() + c.in.TrimFront(c.count) + if !reflect.DeepEqual(c.in, c.want) { + t.Errorf("Test \"%s\" failed when calling TrimFront(%d) on %v. Got %v. Want %v", + c.comment, c.count, orig, c.in, c.want) + } + } +} + +var toViewCases = []struct { + comment string + in VectorisedView + want View +}{ + { + comment: "Simple case", + in: vv(2, "12"), + want: []byte("12"), + }, + { + comment: "Case with multiple views", + in: vv(2, "1", "2"), + want: []byte("12"), + }, + { + comment: "Empty case", + in: vv(0), + want: []byte(""), + }, +} + +func TestToView(t *testing.T) { + for _, c := range toViewCases { + got := c.in.ToView() + if !reflect.DeepEqual(got, c.want) { + t.Errorf("Test \"%s\" failed when calling ToView() on %v. Got %v. Want %v", + c.comment, c.in, got, c.want) + } + } +} + +var toCloneCases = []struct { + comment string + inView VectorisedView + inBuffer []View +}{ + { + comment: "Simple case", + inView: vv(1, "1"), + inBuffer: make([]View, 1), + }, + { + comment: "Case with multiple views", + inView: vv(2, "1", "2"), + inBuffer: make([]View, 2), + }, + { + comment: "Case with buffer too small", + inView: vv(2, "1", "2"), + inBuffer: make([]View, 1), + }, + { + comment: "Case with buffer larger than needed", + inView: vv(1, "1"), + inBuffer: make([]View, 2), + }, + { + comment: "Case with nil buffer", + inView: vv(1, "1"), + inBuffer: nil, + }, +} + +func TestToClone(t *testing.T) { + for _, c := range toCloneCases { + t.Run(c.comment, func(t *testing.T) { + got := c.inView.Clone(c.inBuffer) + if !reflect.DeepEqual(got, c.inView) { + t.Fatalf("got (%+v).Clone(%+v) = %+v, want = %+v", + c.inView, c.inBuffer, got, c.inView) + } + }) + } +} diff --git a/tcpip/link/fdbased/endpoint.go b/tcpip/link/fdbased/endpoint.go index 95f8cd5..86fd48d 100644 --- a/tcpip/link/fdbased/endpoint.go +++ b/tcpip/link/fdbased/endpoint.go @@ -1 +1,47 @@ package fdbased + +import ( + "syscall" + + "github.com/impact-eintr/netstack/tcpip" + "github.com/impact-eintr/netstack/tcpip/buffer" + "github.com/impact-eintr/netstack/tcpip/stack" +) + +// 负责底层网卡的io读写以及数据分发 +type endpoint struct { + // 发送和接收数据的文件描述符 + fd int + + // 单个帧的最大长度 + mtu uint32 + + // 以太网头部长度 + hdrSize int + + // 网卡地址 + addr tcpip.LinkAddress + + // 网卡的能力 + caps stack.LinkEndpointCapabilities + + // closed is a function to be called when the FD's peer (if any) closes + // its end of the communication pipe. + closed func(*tcpip.Error) + + iovecs []syscall.Iovec + views []buffer.View + dispatcher stack.NetworkDispatcher + + // handleLocal indicates whether packets destined to itself should be + // handled by the netstack internally (true) or be forwarded to the FD + // endpoint (false). + // handleLocal指示发往自身的数据包是由内部netstack处理(true)还是转发到FD端点(false)。 + // Resend packets back to netstack if destined to itself + // Add option to redirect packet back to netstack if it's destined to itself. + // This fixes the problem where connecting to the local NIC address would + // not work, e.g.: + // echo bar | nc -l -p 8080 & + // echo foo | nc 192.168.0.2 8080 + handleLocal bool +} diff --git a/tcpip/stack/nic.go b/tcpip/stack/nic.go new file mode 100644 index 0000000..e949c3d --- /dev/null +++ b/tcpip/stack/nic.go @@ -0,0 +1,11 @@ +package stack + +type referencedNetworkEndpoint struct { + //ilist.Entry + //refs int32 + //ep NetworkEndpoint + //nic *NIC + //protocol tcpip.NetworkProtocolNumber + //linkCache LinkAddressCache + //holdsInserRef bool +} diff --git a/tcpip/stack/registration.go b/tcpip/stack/registration.go index 3545c47..c7e4b5f 100644 --- a/tcpip/stack/registration.go +++ b/tcpip/stack/registration.go @@ -1,6 +1,9 @@ package stack -import "github.com/impact-eintr/netstack/tcpip" +import ( + "github.com/impact-eintr/netstack/tcpip" + "github.com/impact-eintr/netstack/tcpip/buffer" +) // LinkEndpoint是由数据链路层协议(以太 环回 原始)实现的接口 // 并由网络层协议用于实施者的数据链路端点发送数据包 @@ -40,3 +43,6 @@ const ( CapabilityDisconnectOk CapabilityLoopback ) + +type NetworkDispatcher interface { +} diff --git a/tcpip/stack/route.go b/tcpip/stack/route.go new file mode 100644 index 0000000..71e1e0f --- /dev/null +++ b/tcpip/stack/route.go @@ -0,0 +1,26 @@ +package stack + +import "github.com/impact-eintr/netstack/tcpip" + +// 贯穿整个协议栈的路由,也就是在链路层和网络层都可以路由 +// 如果目标地址是链路层地址,那么在链路层路由 +// 如果目标地址是网络层地址,那么在网络层路由 +type Route struct { + // 远端网络层地址 ipv4 or ipv6 + RemoteAddress tcpip.Address + + // 远端网卡MAC地址 + RemoteLinkAddress tcpip.LinkAddress + + // 本地网络层地址 + LocalAddress tcpip.Address + + // 下一跳网络层地址 + NextHop tcpip.Address + + // 网络层协议号 + NextProto tcpip.NetworkProtocolNumber + + // 相关的网络终端 + ref *referencedNetworkEndpoint +}