mirror of
https://github.com/impact-eintr/netstack.git
synced 2025-10-20 03:24:33 +08:00
路由转发还是没整明白
This commit is contained in:
@@ -34,7 +34,7 @@ func main() {
|
|||||||
log.Fatal("Usage: ", os.Args[0], " <tap-device> <local-address/mask> <ip-address> <local-port>")
|
log.Fatal("Usage: ", os.Args[0], " <tap-device> <local-address/mask> <ip-address> <local-port>")
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.SetFlags(logger.IP)
|
//logger.SetFlags(logger.IP)
|
||||||
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
||||||
|
|
||||||
tapName := flag.Arg(0)
|
tapName := flag.Arg(0)
|
||||||
@@ -130,7 +130,8 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.AddAddress(2, proto, "192.168.1.2"); err != nil {
|
addr2 := tcpip.Address(net.ParseIP("192.168.1.20").To4())
|
||||||
|
if err := s.AddAddress(2, proto, addr2); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ func main() {
|
|||||||
{
|
{
|
||||||
Destination: tcpip.Address(strings.Repeat("\x00", len(addr))),
|
Destination: tcpip.Address(strings.Repeat("\x00", len(addr))),
|
||||||
Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))),
|
Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))),
|
||||||
Gateway: "",
|
Gateway: "", // 路由器
|
||||||
NIC: 1,
|
NIC: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -158,6 +159,8 @@ func main() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
s.SetForwarding(true)
|
||||||
|
|
||||||
done := make(chan struct{}, 2)
|
done := make(chan struct{}, 2)
|
||||||
|
|
||||||
//logger.SetFlags(logger.TCP)
|
//logger.SetFlags(logger.TCP)
|
||||||
@@ -190,27 +193,10 @@ func main() {
|
|||||||
|
|
||||||
log.Printf("客户端 建立连接\n\n客户端 写入数据\n")
|
log.Printf("客户端 建立连接\n\n客户端 写入数据\n")
|
||||||
|
|
||||||
cnt := 0
|
size := 1 << 11
|
||||||
size := 1 << 10
|
for i := 0; i < 100; i++ {
|
||||||
for i := 0; i < 1; i++ {
|
|
||||||
//conn.Write([]byte("Hello Netstack"))
|
//conn.Write([]byte("Hello Netstack"))
|
||||||
conn.Write(make([]byte, size))
|
conn.Write(make([]byte, size))
|
||||||
buf := make([]byte, 1024)
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err := conn.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cnt+=n
|
|
||||||
logger.NOTICE("客户端读取", string(buf[:]))
|
|
||||||
log.Println(cnt)
|
|
||||||
if cnt == size {
|
|
||||||
logger.NOTICE("退出")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@@ -244,7 +230,6 @@ func TestServerEcho(conn *TcpConn) {
|
|||||||
}
|
}
|
||||||
_ = n
|
_ = n
|
||||||
logger.NOTICE("服务端读取数据", string(buf[:]))
|
logger.NOTICE("服务端读取数据", string(buf[:]))
|
||||||
conn.Write(buf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.ep.Close()
|
conn.ep.Close()
|
||||||
|
@@ -283,7 +283,13 @@ func (n *NIC) attachLinkEndpoint() {
|
|||||||
在上面的函数中,我们开启了网卡的数据读取机制,对于fdbased这个驱动而言,他的实现设这样的
|
在上面的函数中,我们开启了网卡的数据读取机制,对于fdbased这个驱动而言,他的实现设这样的
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
|
|
||||||
|
// Attach 启动从文件描述符中读取数据包的goroutine,并通过提供的分发函数来分发数据报
|
||||||
|
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||||
|
e.dispatcher = dispatcher // 将这张网卡注册为该链路的网络分发器
|
||||||
|
// 链接端点不可靠。保存传输端点后,它们将停止发送传出数据包,并拒绝所有传入数据包。
|
||||||
go e.dispatchLoop()
|
go e.dispatchLoop()
|
||||||
|
}
|
||||||
|
|
||||||
// 循环地从fd中读取数据 然后将数据报分发给协议栈
|
// 循环地从fd中读取数据 然后将数据报分发给协议栈
|
||||||
func (e *endpoint) dispatchLoop() *tcpip.Error {
|
func (e *endpoint) dispatchLoop() *tcpip.Error {
|
||||||
@@ -778,5 +784,69 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload b
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
在前面我们提到过链路层设备拥有读写两个接口,在激活设备的时候我们执行了读取函数,现在,我们该使用写入函数了(以fdbased为例)。
|
||||||
|
|
||||||
|
``` go
|
||||||
|
// 将上层的报文经过链路层封装,写入网卡中,如果写入失败则丢弃该报文
|
||||||
|
func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable,
|
||||||
|
payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
|
||||||
|
// 如果目标地址是设备自己 那么将报文重新返回给协议栈 也就是环回
|
||||||
|
if e.handleLocal && r.LocalAddress != "" && r.LocalAddress == r.RemoteAddress {
|
||||||
|
views := make([]buffer.View, 1, 1+len(payload.Views()))
|
||||||
|
views[0] = hdr.View()
|
||||||
|
views = append(views, payload.Views()...)
|
||||||
|
vv := buffer.NewVectorisedView(len(views[0])+payload.Size(), views) // 添加报文头
|
||||||
|
e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, r.LocalLinkAddress,
|
||||||
|
protocol, vv) // 分发数据报
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非本地环回数据
|
||||||
|
// 封装增加以太网头部
|
||||||
|
eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize)) // 分配14B的内存
|
||||||
|
ethHdr := &header.EthernetFields{ // 配置以太帧信息
|
||||||
|
DstAddr: r.RemoteLinkAddress,
|
||||||
|
Type: protocol,
|
||||||
|
}
|
||||||
|
// 如果路由信息中有配置源MAC地址,那么使用该地址
|
||||||
|
// 如果没有,则使用本网卡的地址
|
||||||
|
if r.LocalLinkAddress != "" {
|
||||||
|
ethHdr.SrcAddr = r.LocalLinkAddress
|
||||||
|
} else {
|
||||||
|
ethHdr.SrcAddr = e.addr
|
||||||
|
}
|
||||||
|
eth.Encode(ethHdr) // 将以太帧信息作为报文头编入
|
||||||
|
logger.GetInstance().Info(logger.ETH, func() {
|
||||||
|
log.Println(ethHdr.SrcAddr, "链路层写回以太报文 ", r.RemoteLinkAddress, " to ", r.RemoteAddress)
|
||||||
|
})
|
||||||
|
// 写入网卡中
|
||||||
|
if payload.Size() == 0 {
|
||||||
|
return rawfile.NonBlockingWrite(e.fd, hdr.View())
|
||||||
|
}
|
||||||
|
return rawfile.NonBlockingWrite2(e.fd, hdr.View(), payload.ToView())
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
我们现在来捋一下,除了传输层以外的数据传输机制:
|
||||||
|
|
||||||
|
首先,数据发送方将数据从应用层复制数据到传输层,在封装传输层数据之前,我们会先解析路由。
|
||||||
|
|
||||||
|
路由: 网卡-网络协议-本地IP-本地MAC-目标IP-目标MAC
|
||||||
|
|
||||||
|
先查找路由表,查看路由表中是否有目标网卡,如果有,检查指定IP该网卡是否绑定过,如果没有指定IP,就从网卡绑定的IP里找一个能用的,然后本地MAC就使用这个网卡的MAC。目标IP是数据发送方提供的,目标MAC通过查询arp缓存或者发送arp广播获取。
|
||||||
|
|
||||||
|
有了路由信息,我们就可以执行网络层和链路层的工作了。从路由信息中获取IP的处理端点,封装IP报文,封装以太报文,写入网卡,网卡将这些数据发送出去。
|
||||||
|
|
||||||
|
目标主机网卡接受到数据时,dispatchLoop中的阻塞读不再阻塞,读取数据。解析以太报文,获取远端IP和远端MAC,在上面我们新建网卡的时候,我们已经将这张网卡作为本链路的网络分发器,所以调用网卡的分发函数。
|
||||||
|
|
||||||
|
``` go
|
||||||
|
|
||||||
|
case header.ARPProtocolNumber, header.IPv4ProtocolNumber:
|
||||||
|
e.dispatcher.DeliverNetworkPacket(e, remoteLinkAddr, localLinkAddr, p, vv)
|
||||||
|
```
|
||||||
|
|
||||||
|
``` go
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
@@ -116,6 +116,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable,
|
|||||||
}
|
}
|
||||||
// 封装增加以太网头部
|
// 封装增加以太网头部
|
||||||
eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize)) // 分配14B的内存
|
eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize)) // 分配14B的内存
|
||||||
|
log.Println(eth,hdr, hdr.Prepend(header.EthernetMinimumSize))
|
||||||
ethHdr := &header.EthernetFields{ // 配置以太帧信息
|
ethHdr := &header.EthernetFields{ // 配置以太帧信息
|
||||||
DstAddr: r.RemoteLinkAddress,
|
DstAddr: r.RemoteLinkAddress,
|
||||||
Type: protocol,
|
Type: protocol,
|
||||||
|
@@ -108,15 +108,6 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload b
|
|||||||
r.Stats().IP.PacketsSent.Increment()
|
r.Stats().IP.PacketsSent.Increment()
|
||||||
|
|
||||||
// 写入网卡接口
|
// 写入网卡接口
|
||||||
if protocol == header.ICMPv4ProtocolNumber {
|
|
||||||
log.Println("IP 写回ICMP报文", header.IPv4(append(ip, payload.ToView()...)))
|
|
||||||
} else {
|
|
||||||
logger.GetInstance().Info(logger.IP, func() {
|
|
||||||
if payload.Size() == 0 {
|
|
||||||
log.Printf("发送 IP 报文 %d bytes", hdr.UsedLength()+payload.Size())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return e.linkEP.WritePacket(r, hdr, payload, ProtocolNumber)
|
return e.linkEP.WritePacket(r, hdr, payload, ProtocolNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -339,20 +339,24 @@ func (n *NIC) RemoveAddress(addr tcpip.Address) *tcpip.Error {
|
|||||||
// 当前实现的网络层协议有 arp、ipv4 和 ipv6。
|
// 当前实现的网络层协议有 arp、ipv4 和 ipv6。
|
||||||
func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr, localLinkAddr tcpip.LinkAddress,
|
func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr, localLinkAddr tcpip.LinkAddress,
|
||||||
protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
|
protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
|
||||||
|
// 检查本协议栈是否注册过该网络协议
|
||||||
netProto, ok := n.stack.networkProtocols[protocol]
|
netProto, ok := n.stack.networkProtocols[protocol]
|
||||||
if !ok {
|
if !ok {
|
||||||
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
|
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 网络层协议状态统计
|
||||||
if netProto.Number() == header.IPv4ProtocolNumber || netProto.Number() == header.IPv6ProtocolNumber {
|
if netProto.Number() == header.IPv4ProtocolNumber || netProto.Number() == header.IPv6ProtocolNumber {
|
||||||
n.stack.stats.IP.PacketsReceived.Increment()
|
n.stack.stats.IP.PacketsReceived.Increment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 报文内容过小 判断为受损报文 丢弃
|
||||||
if len(vv.First()) < netProto.MinimumPacketSize() {
|
if len(vv.First()) < netProto.MinimumPacketSize() {
|
||||||
n.stack.stats.MalformedRcvdPackets.Increment()
|
n.stack.stats.MalformedRcvdPackets.Increment()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 解析源 IP 和目标IP
|
||||||
src, dst := netProto.ParseAddresses(vv.First())
|
src, dst := netProto.ParseAddresses(vv.First())
|
||||||
logger.GetInstance().Info(logger.ETH, func() {
|
logger.GetInstance().Info(logger.ETH, func() {
|
||||||
log.Printf("网卡[%v]准备从 [%s] 向 [%s] 分发数据: %v\n", linkEP.LinkAddress(), src, dst, func() []byte {
|
log.Printf("网卡[%v]准备从 [%s] 向 [%s] 分发数据: %v\n", linkEP.LinkAddress(), src, dst, func() []byte {
|
||||||
@@ -362,22 +366,26 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr, localLin
|
|||||||
return vv.ToView()
|
return vv.ToView()
|
||||||
}())
|
}())
|
||||||
})
|
})
|
||||||
// 根据网络协议和数据包的目的地址,找到网络端
|
// 根据网络协议和数据包的目的地址,找到绑定该目标地址的网络端
|
||||||
// 然后将数据包分发给网络层
|
|
||||||
if ref := n.getRef(protocol, dst); ref != nil {
|
if ref := n.getRef(protocol, dst); ref != nil {
|
||||||
|
// 路由 源 与 目标 反转
|
||||||
r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref)
|
r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref)
|
||||||
r.RemoteLinkAddress = remoteLinkAddr
|
r.RemoteLinkAddress = remoteLinkAddr
|
||||||
logger.GetInstance().Info(logger.ETH, func() {
|
logger.GetInstance().Info(logger.ETH, func() {
|
||||||
log.Println("准备前往 IP 将本地和远端的MAC、IP 保存在路由中 以便协议栈使用",
|
log.Println("准备前往 IP 将本地和远端的MAC、IP 保存在路由中 以便协议栈使用",
|
||||||
r.LocalLinkAddress, r.RemoteLinkAddress, r.LocalAddress, r.RemoteAddress)
|
r.LocalLinkAddress, r.RemoteLinkAddress, r.LocalAddress, r.RemoteAddress)
|
||||||
})
|
})
|
||||||
|
// 将数据包分发给网络层
|
||||||
ref.ep.HandlePacket(&r, vv)
|
ref.ep.HandlePacket(&r, vv)
|
||||||
ref.decRef()
|
ref.decRef()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果配置了允许转发 什么意思呢
|
||||||
|
// 就是说当前网卡并没有找到目标IP 我们来试试本机的其他网卡
|
||||||
|
// 其他网卡-其他网卡上的一个可用地址-目标地址
|
||||||
if n.stack.Forwarding() {
|
if n.stack.Forwarding() {
|
||||||
r, err := n.stack.FindRoute(0, "", dst, protocol)
|
r, err := n.stack.FindRoute(0, dst, src, protocol) // FIXME 将dst和src调转?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.stack.stats.IP.InvalidAddressesReceived.Increment()
|
n.stack.stats.IP.InvalidAddressesReceived.Increment()
|
||||||
return
|
return
|
||||||
@@ -390,10 +398,12 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr, localLin
|
|||||||
// Found a NIC.
|
// Found a NIC.
|
||||||
n := r.ref.nic
|
n := r.ref.nic
|
||||||
n.mu.RLock()
|
n.mu.RLock()
|
||||||
ref, ok := n.endpoints[NetworkEndpointID{dst}]
|
ref, ok := n.endpoints[NetworkEndpointID{dst}] // 检查这张网卡是否绑定了目标IP
|
||||||
n.mu.RUnlock()
|
n.mu.RUnlock()
|
||||||
|
|
||||||
if ok && ref.tryIncRef() {
|
if ok && ref.tryIncRef() {
|
||||||
ref.ep.HandlePacket(&r, vv)
|
ref.ep.HandlePacket(&r, vv)
|
||||||
|
logger.NOTICE("转发数据")
|
||||||
ref.decRef()
|
ref.decRef()
|
||||||
} else {
|
} else {
|
||||||
// n doesn't have a destination endpoint.
|
// n doesn't have a destination endpoint.
|
||||||
|
@@ -616,7 +616,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address,
|
|||||||
|
|
||||||
// 构建一个路由 包括 目标ip 目标mac 本地ip 本地mac
|
// 构建一个路由 包括 目标ip 目标mac 本地ip 本地mac
|
||||||
r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref)
|
r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref)
|
||||||
r.NextHop = s.routeTable[i].Gateway
|
r.NextHop = s.routeTable[i].Gateway // 路由器地址
|
||||||
logger.GetInstance().Info(logger.IP, func() {
|
logger.GetInstance().Info(logger.IP, func() {
|
||||||
log.Println(r.LocalLinkAddress, r.LocalAddress, r.RemoteLinkAddress, r.RemoteAddress, r.NextHop)
|
log.Println(r.LocalLinkAddress, r.LocalAddress, r.RemoteLinkAddress, r.RemoteAddress, r.NextHop)
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user