mirror of
				https://github.com/impact-eintr/netstack.git
				synced 2025-10-26 22:20:21 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package stack
 | ||
| 
 | ||
| import (
 | ||
| 	"netstack/sleep"
 | ||
| 	"netstack/tcpip"
 | ||
| 	"netstack/tcpip/buffer"
 | ||
| 	"netstack/tcpip/header"
 | ||
| )
 | ||
| 
 | ||
| // 贯穿整个协议栈的路由,也就是在链路层和网络层都可以路由
 | ||
| // 如果目标地址是链路层地址,那么在链路层路由,
 | ||
| // 如果目标地址是网络层地址,那么在网络层路由。
 | ||
| type Route struct {
 | ||
| 	// 远端网络层地址 ipv4 or ipv6 地址
 | ||
| 	RemoteAddress tcpip.Address
 | ||
| 	// 远端网卡MAC地址
 | ||
| 	RemoteLinkAddress tcpip.LinkAddress
 | ||
| 
 | ||
| 	// 本地网络层地址 ipv4 or ipv6 地址
 | ||
| 	LocalAddress tcpip.Address
 | ||
| 	// 本地网卡MAC地址
 | ||
| 	LocalLinkAddress tcpip.LinkAddress
 | ||
| 
 | ||
| 	// 下一跳网络层地址
 | ||
| 	NextHop tcpip.Address
 | ||
| 
 | ||
| 	// 网络层协议号
 | ||
| 	NetProto tcpip.NetworkProtocolNumber
 | ||
| 
 | ||
| 	// 相关的网络终端
 | ||
| 	ref *referencedNetworkEndpoint
 | ||
| }
 | ||
| 
 | ||
| // 根据参数新建一个路由,并关联一个网络层端
 | ||
| func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address,
 | ||
| 	localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint) Route {
 | ||
| 	return Route{
 | ||
| 		NetProto:         netProto,
 | ||
| 		LocalAddress:     localAddr,
 | ||
| 		LocalLinkAddress: localLinkAddr,
 | ||
| 		RemoteAddress:    remoteAddr,
 | ||
| 		ref:              ref,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // NICID returns the id of the NIC from which this route originates.
 | ||
| func (r *Route) NICID() tcpip.NICID {
 | ||
| 	return r.ref.ep.NICID()
 | ||
| }
 | ||
| 
 | ||
| // MaxHeaderLength forwards the call to the network endpoint's implementation.
 | ||
| func (r *Route) MaxHeaderLength() uint16 {
 | ||
| 	return r.ref.ep.MaxHeaderLength()
 | ||
| }
 | ||
| 
 | ||
| // Stats returns a mutable copy of current stats.
 | ||
| func (r *Route) Stats() tcpip.Stats {
 | ||
| 	return r.ref.nic.stack.Stats()
 | ||
| }
 | ||
| 
 | ||
| // PseudoHeaderChecksum forwards the call to the network endpoint's
 | ||
| // implementation.
 | ||
| // udp或tcp伪首部校验和的计算
 | ||
| func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber) uint16 {
 | ||
| 	return header.PseudoHeaderChecksum(protocol, r.LocalAddress, r.RemoteAddress)
 | ||
| }
 | ||
| 
 | ||
| // Capabilities returns the link-layer capabilities of the route.
 | ||
| func (r *Route) Capabilities() LinkEndpointCapabilities {
 | ||
| 	return r.ref.ep.Capabilities()
 | ||
| }
 | ||
| 
 | ||
| // Resolve 如有必要,解决尝试解析链接地址的问题。如果地址解析需要阻塞,则返回ErrWouldBlock,
 | ||
| // 例如等待ARP回复。地址解析完成(成功与否)时通知Waker。
 | ||
| // 如果需要地址解析,则返回ErrNoLinkAddress和通知通道,以阻止顶级调用者。
 | ||
| // 地址解析完成后,通道关闭(不管成功与否)。
 | ||
| func (r *Route) Resolve(waker *sleep.Waker) (<-chan struct{}, *tcpip.Error) {
 | ||
| 	if !r.IsResolutionRequired() {
 | ||
| 		// Nothing to do if there is no cache (which does the resolution on cache miss) or
 | ||
| 		// link address is already known.
 | ||
| 		return nil, nil
 | ||
| 	}
 | ||
| 
 | ||
| 	nextAddr := r.NextHop
 | ||
| 	if nextAddr == "" {
 | ||
| 		// Local link address is already known.
 | ||
| 		if r.RemoteAddress == r.LocalAddress { // 发给自己
 | ||
| 			r.RemoteLinkAddress = r.LocalLinkAddress // MAC 就是自己
 | ||
| 			return nil, nil
 | ||
| 		}
 | ||
| 		nextAddr = r.RemoteAddress // 下一跳是远端机
 | ||
| 	}
 | ||
| 
 | ||
| 	// 调用地址解析协议来解析IP地址
 | ||
| 	linkAddr, ch, err := r.ref.linkCache.GetLinkAddress(r.ref.nic.ID(), nextAddr, r.LocalAddress, r.NetProto, waker)
 | ||
| 	if err != nil {
 | ||
| 		return ch, err
 | ||
| 	}
 | ||
| 	r.RemoteLinkAddress = linkAddr
 | ||
| 	return nil, nil
 | ||
| }
 | ||
| 
 | ||
| // RemoveWaker removes a waker that has been added in Resolve().
 | ||
| func (r *Route) RemoveWaker(waker *sleep.Waker) {
 | ||
| 	nextAddr := r.NextHop
 | ||
| 	if nextAddr == "" {
 | ||
| 		nextAddr = r.RemoteAddress
 | ||
| 	}
 | ||
| 	r.ref.linkCache.RemoveWaker(r.ref.nic.ID(), nextAddr, waker)
 | ||
| }
 | ||
| 
 | ||
| // IsResolutionRequired returns true if Resolve() must be called to resolve
 | ||
| // the link address before the this route can be written to.
 | ||
| func (r *Route) IsResolutionRequired() bool {
 | ||
| 	return r.ref.linkCache != nil && r.RemoteLinkAddress == ""
 | ||
| }
 | ||
| 
 | ||
| // WritePacket writes the packet through the given route.
 | ||
| func (r *Route) WritePacket(hdr buffer.Prependable, payload buffer.VectorisedView,
 | ||
| 	protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error {
 | ||
| 	err := r.ref.ep.WritePacket(r, hdr, payload, protocol, ttl)
 | ||
| 	if err == tcpip.ErrNoRoute {
 | ||
| 		r.Stats().IP.OutgoingPacketErrors.Increment()
 | ||
| 	}
 | ||
| 	return err
 | ||
| }
 | ||
| 
 | ||
| // DefaultTTL returns the default TTL of the underlying network endpoint.
 | ||
| func (r *Route) DefaultTTL() uint8 {
 | ||
| 	return r.ref.ep.DefaultTTL()
 | ||
| }
 | ||
| 
 | ||
| // MTU returns the MTU of the underlying network endpoint.
 | ||
| func (r *Route) MTU() uint32 {
 | ||
| 	return r.ref.ep.MTU()
 | ||
| }
 | ||
| 
 | ||
| // Release frees all resources associated with the route.
 | ||
| func (r *Route) Release() {
 | ||
| 	if r.ref != nil {
 | ||
| 		r.ref.decRef()
 | ||
| 		r.ref = nil
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // Clone Clone a route such that the original one can be released and the new
 | ||
| // one will remain valid.
 | ||
| func (r *Route) Clone() Route {
 | ||
| 	r.ref.incRef()
 | ||
| 	return *r
 | ||
| }
 | 
