diff --git a/tcpip/stack/nic.go b/tcpip/stack/nic.go index 16f22e6..95ffa30 100644 --- a/tcpip/stack/nic.go +++ b/tcpip/stack/nic.go @@ -1,11 +1,32 @@ package stack import ( + "log" "netstack/ilist" "netstack/tcpip" + "netstack/tcpip/buffer" "sync" ) +// PrimaryEndpointBehavior 是端点首要行为的枚举 +type PrimaryEndpointBehavior int + +const ( + // CanBePrimaryEndpoint indicates the endpoint can be used as a primary + // endpoint for new connections with no local address. This is the + // default when calling NIC.AddAddress. + CanBePrimaryEndpoint PrimaryEndpointBehavior = iota + + // FirstPrimaryEndpoint indicates the endpoint should be the first + // primary endpoint considered. If there are multiple endpoints with + // this behavior, the most recently-added one will be first. + FirstPrimaryEndpoint + + // NeverPrimaryEndpoint indicates the endpoint should never be a + // primary endpoint. + NeverPrimaryEndpoint +) + // 代表一个网卡对象 当我们创建好tap网卡对象后 我们使用NIC来代表它在我们自己的协议栈中的网卡对象 type NIC struct { stack *Stack @@ -24,7 +45,57 @@ type NIC struct { promiscuous bool // 混杂模式 primary map[tcpip.NetworkProtocolNumber]*ilist.List // 网络层端的记录 - endpoints map[NetworkEndpoingID]*referencedNetworkEndpoint + endpoints map[NetworkEndpointID]*referencedNetworkEndpoint // 子网的记录 subnets []tcpip.Subnet } + +// 创建新的网卡对象 +func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint) *NIC { + return &NIC{ + stack: stack, + id: id, + name: name, + linkEP: ep, + demux: nil, // TODO 需要处理 + primary: make(map[tcpip.NetworkProtocolNumber]*ilist.List), + endpoints: make(map[NetworkEndpointID]*referencedNetworkEndpoint), + } +} + +func (n *NIC) attachLinkEndpoint() { + n.linkEP.Attach(n) +} + +// 在NIC上添加addr地址,注册和初始化网络层协议 +// 相当于给网卡添加ip地址 +func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, + peb PrimaryEndpointBehavior, replace bool) (*referencedNetworkEndpoint, *tcpip.Error) { + netProto, ok := n.stack.networkProtocols[protocol] + if !ok { + log.Println("添加失败") + return nil, tcpip.ErrUnknownProtocol + } + log.Println(netProto.Number(), "添加ip", addr.String()) + // TODO 接着这里实现 22/11/24 21:29 + return nil, nil +} + +func (n *NIC) AddAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error { + return n.AddAddressWithOptions(protocol, addr, CanBePrimaryEndpoint) +} + +func (n *NIC) AddAddressWithOptions(protocol tcpip.NetworkProtocolNumber, + addr tcpip.Address, peb PrimaryEndpointBehavior) *tcpip.Error { + n.mu.Lock() + _, err := n.addAddressLocked(protocol, addr, peb, false) + n.mu.Unlock() + + return err +} + +func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, dstLinkAddr, srcLinkAddr tcpip.LinkAddress, + protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) { + // TODO 需要完成逻辑 + log.Println(vv.ToView()) +} diff --git a/tcpip/stack/registration.go b/tcpip/stack/registration.go index ee6b802..e5ae3ef 100644 --- a/tcpip/stack/registration.go +++ b/tcpip/stack/registration.go @@ -1,6 +1,7 @@ package stack import ( + "log" "netstack/ilist" "netstack/sleep" "netstack/tcpip" @@ -89,9 +90,16 @@ type NetworkDispatcher interface { type LinkEndpointCapabilities uint +// type TransportProtocolFactory func() TransportProtocol TODO + +type NetworkProtocolFactory func() NetworkProtocol + var ( + // 以下两个map需要在init函数中注册 // 传输层协议的注册存储结构 TODO - // 网络层协议的注册存储结构 TODO + //transportProtocols = make(map[string]TransportProtocolFactory) + // 网络层协议的注册存储结构 + networkProtocols = make(map[string]NetworkProtocolFactory) linkEPMu sync.RWMutex nextLinkEndpointID tcpip.LinkEndpointID = 1 @@ -100,7 +108,8 @@ var ( // ==============================网络层相关============================== type NetworkProtocol interface { - // TODO 需要添加 + Number() tcpip.NetworkProtocolNumber + // todo 需要添加 } // NetworkEndpoint是需要由网络层协议(例如,ipv4,ipv6)的端点实现的接口 @@ -108,7 +117,7 @@ type NetworkEndpoint interface { // TODO 需要添加 } -type NetworkEndpoingID struct { +type NetworkEndpointID struct { LocalAddress tcpip.Address } @@ -147,6 +156,12 @@ type referencedNetworkEndpoint struct { holdsInsertRef bool } +// 注册一个新的网络协议工厂 +func RegisterNetworkProtocolFactory(name string, p NetworkProtocolFactory) { + networkProtocols[name] = p + log.Println(networkProtocols) +} + // 注册一个链路层设备 func RegisterLinkEndpoint(linkEP LinkEndpoint) tcpip.LinkEndpointID { linkEPMu.Lock() diff --git a/tcpip/stack/stack.go b/tcpip/stack/stack.go index 3e4d948..7e5f2a1 100644 --- a/tcpip/stack/stack.go +++ b/tcpip/stack/stack.go @@ -1,6 +1,7 @@ package stack import ( + "log" "netstack/tcpip" "netstack/tcpip/ports" "sync" @@ -48,6 +49,31 @@ type Stack struct { clock tcpip.Clock } +func New(network []string) *Stack { + s := &Stack{ + transportProtocols: make(map[tcpip.TransportProtocolNumber]*transportProtocolState), + networkProtocols: make(map[tcpip.NetworkProtocolNumber]NetworkProtocol), + linkAddrResolvers: make(map[tcpip.NetworkProtocolNumber]LinkAddressResolver), + nics: make(map[tcpip.NICID]*NIC), + } + + // 添加指定的网络端协议 必须已经在init中注册过 + for _, name := range network { + // 先检查这个网络协议是否注册过工厂方法 + netProtoFactory, ok := networkProtocols[name] + if !ok { + log.Println(name) + continue // 没有就略过 + } + netProto := netProtoFactory() // 制造一个该型号协议的示实例 + s.networkProtocols[netProto.Number()] = netProto // 注册该型号的网络协议 + } + + // 添加指定的传输层协议 必已经在init中注册过 + // TODO + return s +} + func (s *Stack) CreateNIC(id tcpip.NICID, linkEP tcpip.LinkEndpointID) *tcpip.Error { return s.createNIC(id, "", linkEP, true) } @@ -66,10 +92,30 @@ func (s *Stack) createNIC(id tcpip.NICID, name string, linkEP tcpip.LinkEndpoint if _, ok := s.nics[id]; ok { return tcpip.ErrDuplicateNICID } - n := newIC(s, id, name, ep) + n := newNIC(s, id, name, ep) s.nics[id] = n if enable { n.attachLinkEndpoint() } + + return nil +} + +// 给网卡添加ip地址 +func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error { + return s.AddAddressWithOptions(id, protocol, addr, CanBePrimaryEndpoint) +} + +func (s *Stack) AddAddressWithOptions(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, + addr tcpip.Address, peb PrimaryEndpointBehavior) *tcpip.Error { + s.mu.RLock() + defer s.mu.RUnlock() + + nic := s.nics[id] + if nic == nil { + return tcpip.ErrUnknownNICID + } + + return nic.AddAddressWithOptions(protocol, addr, peb) } diff --git a/tcpip/stack/stack_test.go b/tcpip/stack/stack_test.go index eb230c2..82188a6 100644 --- a/tcpip/stack/stack_test.go +++ b/tcpip/stack/stack_test.go @@ -1,6 +1,9 @@ package stack_test import ( + "log" + "netstack/tcpip" + "netstack/tcpip/buffer" "netstack/tcpip/link/channel" "netstack/tcpip/stack" "testing" @@ -10,12 +13,33 @@ const ( defaultMTU = 65536 ) +type fakeNetworkProtocol struct { +} + +func (f *fakeNetworkProtocol) Number() tcpip.NetworkProtocolNumber { + return 114514 +} + +func init() { + stack.RegisterNetworkProtocolFactory("fakeNet", func() stack.NetworkProtocol { + return &fakeNetworkProtocol{} + }) +} + func TestStackBase(t *testing.T) { - myStack := &stack.Stack{} - id, _ := channel.New(10, defaultMTU, "") + myStack := stack.New([]string{"fakeNet"}) + id, ep := channel.New(10, defaultMTU, "") // 这是一个物理设备 + log.Println(id) - if err := myStack.CreateNIC(1, id); err != nil { + if err := myStack.CreateNIC(1, id); err != nil { // 将上面的物理设备抽象成我们的网卡对象 panic(err) } + myStack.AddAddress(1, 114514, "\x01") // 给网卡对象绑定一个IP地址 可以绑定多个 + + buf := buffer.NewView(30) + for i := range buf { + buf[i] = 1 + } + ep.Inject(114514, buf.ToVectoriseView()) } diff --git a/tcpip/tcpip.go b/tcpip/tcpip.go index cc477a4..ea406ca 100644 --- a/tcpip/tcpip.go +++ b/tcpip/tcpip.go @@ -108,12 +108,11 @@ type Stats struct { } func (a Address) String() string { + fmt.Println(string(a), len(a)) switch len(a) { case 4: - fmt.Println(string(a)) return fmt.Sprintf("%d.%d.%d.%d", int(a[0]), int(a[1]), int(a[2]), int(a[3])) case 16: - fmt.Println(string(a)) // Find the longest subsequence of hexadecimal zeros. start, end := -1, -1 for i := 0; i < len(a); i += 2 {