更新笔记 添加更详细的注释 截止到地址解析的实现

This commit is contained in:
impact-eintr
2022-12-30 16:04:13 +08:00
parent 49c7cd2ff4
commit 12c26a86f1
7 changed files with 566 additions and 16 deletions

View File

@@ -91,6 +91,7 @@ func (n *NIC) isPromiscuousMode() bool {
// 相当于给网卡添加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 {
return nil, tcpip.ErrUnknownProtocol
@@ -112,15 +113,20 @@ func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.
n.removeEndpointLocked(ref) // 这里被调用的时候已经上过锁了 NOTE
}
// 新建一个网络端点的引用 为什么是一个引用
// 这是为了复用 所有使用该IP地址的传输层报文都可以复用它
ref := &referencedNetworkEndpoint{
refs: 1,
ep: ep,
nic: n,
protocol: protocol,
holdsInsertRef: true,
refs: 1, // 初始的引用计数
ep: ep, // 引用的网络端点
nic: n, // 网络端点所在的网卡
protocol: protocol, // 网络协议
holdsInsertRef: true, // 防止空引用
}
// Set up cache if link address resolution exists for this protocol.
// 如果该网卡驱动 配置了允许地址解析
// 我们让网卡绑定的协议栈来作为该网络端点的MAC解析缓存器
// 这样当我们向目标地址发送ip报文的时候 会检查缓存里是否存在 ip:mac 的对应关系
// 如果不存在 就会调用arp协议发广播来定位这个ip对应的设备
if n.linkEP.Capabilities()&CapabilityResolutionRequired != 0 {
if _, ok := n.stack.linkAddrResolvers[protocol]; ok {
ref.linkCache = n.stack
@@ -134,12 +140,17 @@ func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.
log.Printf("基于[%d]协议 为 #%d 网卡 添加网络层实现 并绑定地址到: %s\n", netProto.Number(), n.id, ep.ID().LocalAddress)
})
/*
[tcp]->192.168.1.1->192.168.1.2->172.10.1.1->...
[udp]->10.10.1.1->192.168.1.1->...
**/
l, ok := n.primary[protocol]
if !ok {
l = &ilist.List{}
n.primary[protocol] = l
}
// 保存该ip的引用
switch peb {
case CanBePrimaryEndpoint:
l.PushBack(ref) // 目前走这一支

View File

@@ -298,13 +298,21 @@ func New(network []string, transport []string, opts Options) *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),
// 链路层MAC缓存器
linkAddrCache: newLinkAddrCache(ageLimit, resolutionTimeout, resolutionAttempts),
// 端口管理器
PortManager: ports.NewPortManager(),
// 协议栈时钟
clock: clock,
// 协议栈状态管理器
stats: opts.Stats.FillIn(),
}
@@ -474,8 +482,9 @@ func (s *Stack) CreateNamedNIC(id tcpip.NICID, name string, linkEP tcpip.LinkEnd
return s.createNIC(id, name, linkEP, true)
}
// 新建一个网卡对象,并且激活它 激活就是准备好网卡中读取和写入数据
// 新建一个网卡对象,并且激活它 激活就是准备好网卡中读取和写入数据
func (s *Stack) createNIC(id tcpip.NICID, name string, linkEP tcpip.LinkEndpointID, enable bool) *tcpip.Error {
// 从全局寻找该链路层设备是否注册过
ep := FindLinkEndpoint(linkEP)
if ep == nil {
return tcpip.ErrBadLinkEndpoint
@@ -488,8 +497,10 @@ func (s *Stack) createNIC(id tcpip.NICID, name string, linkEP tcpip.LinkEndpoint
if _, ok := s.nics[id]; ok {
return tcpip.ErrDuplicateNICID
}
// 新建网卡对象 包括 网卡归属的协议栈 网卡号 网卡名 网卡驱动
n := newNIC(s, id, name, ep)
// 给协议栈注册这个网卡设备
s.nics[id] = n
if enable {
n.attachLinkEndpoint()
@@ -586,9 +597,9 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address,
}
var ref *referencedNetworkEndpoint
if len(localAddr) != 0 {
if len(localAddr) != 0 { // 要是指定了本地ip
ref = nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint) // 找到绑定LocalAddr的IP端
} else {
} else { // 要是没指定本地ip 从当前网卡绑定的所有ip里找个能用的
ref = nic.primaryEndpoint(netProto)
}
if ref == nil {
@@ -606,7 +617,6 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address,
logger.GetInstance().Info(logger.IP, func() {
log.Println(r.LocalLinkAddress, r.LocalAddress, r.RemoteLinkAddress, r.RemoteAddress, r.NextHop)
})
log.Println(s.routeTable[i])
return r, nil
}

View File

@@ -19,6 +19,8 @@ type transportEndpoints struct {
// transportDemuxer 解复用战队传输端点的数据包
// 他执行两级解复用:首先基于网络层和传输协议 然后基于端点ID
// 在我们注册完各种网络层、传输层协议后我们还需要一个分流器让各种数据准确地找到自己的处理端不能让一个ipv4的tcp连接最终被一个ipv6的udp处理端解析。
// 那么对于任意一个传输层数据流,它应当唯一标识为 `网络层协议-传输层协议-目标IP-目标端口-本地IP-本地端口`的一个六元组
type transportDemuxer struct {
protocol map[protocolIDs]*transportEndpoints
}