Files
netstack/tcpip/stack/route.go

152 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}