mirror of
https://github.com/impact-eintr/netstack.git
synced 2025-10-18 18:54:30 +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>")
|
||||
}
|
||||
|
||||
logger.SetFlags(logger.IP)
|
||||
//logger.SetFlags(logger.IP)
|
||||
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
||||
|
||||
tapName := flag.Arg(0)
|
||||
@@ -130,7 +130,8 @@ func main() {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -147,7 +148,7 @@ func main() {
|
||||
{
|
||||
Destination: tcpip.Address(strings.Repeat("\x00", len(addr))),
|
||||
Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))),
|
||||
Gateway: "",
|
||||
Gateway: "", // 路由器
|
||||
NIC: 1,
|
||||
},
|
||||
{
|
||||
@@ -158,6 +159,8 @@ func main() {
|
||||
},
|
||||
})
|
||||
|
||||
s.SetForwarding(true)
|
||||
|
||||
done := make(chan struct{}, 2)
|
||||
|
||||
//logger.SetFlags(logger.TCP)
|
||||
@@ -190,27 +193,10 @@ func main() {
|
||||
|
||||
log.Printf("客户端 建立连接\n\n客户端 写入数据\n")
|
||||
|
||||
cnt := 0
|
||||
size := 1 << 10
|
||||
for i := 0; i < 1; i++ {
|
||||
size := 1 << 11
|
||||
for i := 0; i < 100; i++ {
|
||||
//conn.Write([]byte("Hello Netstack"))
|
||||
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()
|
||||
@@ -244,7 +230,6 @@ func TestServerEcho(conn *TcpConn) {
|
||||
}
|
||||
_ = n
|
||||
logger.NOTICE("服务端读取数据", string(buf[:]))
|
||||
conn.Write(buf)
|
||||
}
|
||||
|
||||
conn.ep.Close()
|
||||
|
@@ -283,7 +283,13 @@ func (n *NIC) attachLinkEndpoint() {
|
||||
在上面的函数中,我们开启了网卡的数据读取机制,对于fdbased这个驱动而言,他的实现设这样的
|
||||
|
||||
``` go
|
||||
|
||||
// Attach 启动从文件描述符中读取数据包的goroutine,并通过提供的分发函数来分发数据报
|
||||
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
e.dispatcher = dispatcher // 将这张网卡注册为该链路的网络分发器
|
||||
// 链接端点不可靠。保存传输端点后,它们将停止发送传出数据包,并拒绝所有传入数据包。
|
||||
go e.dispatchLoop()
|
||||
}
|
||||
|
||||
// 循环地从fd中读取数据 然后将数据报分发给协议栈
|
||||
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的内存
|
||||
log.Println(eth,hdr, hdr.Prepend(header.EthernetMinimumSize))
|
||||
ethHdr := &header.EthernetFields{ // 配置以太帧信息
|
||||
DstAddr: r.RemoteLinkAddress,
|
||||
Type: protocol,
|
||||
|
@@ -108,15 +108,6 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload b
|
||||
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)
|
||||
}
|
||||
|
||||
|
@@ -339,20 +339,24 @@ func (n *NIC) RemoveAddress(addr tcpip.Address) *tcpip.Error {
|
||||
// 当前实现的网络层协议有 arp、ipv4 和 ipv6。
|
||||
func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr, localLinkAddr tcpip.LinkAddress,
|
||||
protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
|
||||
// 检查本协议栈是否注册过该网络协议
|
||||
netProto, ok := n.stack.networkProtocols[protocol]
|
||||
if !ok {
|
||||
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
// 网络层协议状态统计
|
||||
if netProto.Number() == header.IPv4ProtocolNumber || netProto.Number() == header.IPv6ProtocolNumber {
|
||||
n.stack.stats.IP.PacketsReceived.Increment()
|
||||
}
|
||||
|
||||
// 报文内容过小 判断为受损报文 丢弃
|
||||
if len(vv.First()) < netProto.MinimumPacketSize() {
|
||||
n.stack.stats.MalformedRcvdPackets.Increment()
|
||||
return
|
||||
}
|
||||
// 解析源 IP 和目标IP
|
||||
src, dst := netProto.ParseAddresses(vv.First())
|
||||
logger.GetInstance().Info(logger.ETH, func() {
|
||||
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()
|
||||
}())
|
||||
})
|
||||
// 根据网络协议和数据包的目的地址,找到网络端
|
||||
// 然后将数据包分发给网络层
|
||||
// 根据网络协议和数据包的目的地址,找到绑定该目标地址的网络端
|
||||
if ref := n.getRef(protocol, dst); ref != nil {
|
||||
// 路由 源 与 目标 反转
|
||||
r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref)
|
||||
r.RemoteLinkAddress = remoteLinkAddr
|
||||
logger.GetInstance().Info(logger.ETH, func() {
|
||||
log.Println("准备前往 IP 将本地和远端的MAC、IP 保存在路由中 以便协议栈使用",
|
||||
r.LocalLinkAddress, r.RemoteLinkAddress, r.LocalAddress, r.RemoteAddress)
|
||||
})
|
||||
// 将数据包分发给网络层
|
||||
ref.ep.HandlePacket(&r, vv)
|
||||
ref.decRef()
|
||||
return
|
||||
}
|
||||
|
||||
// 如果配置了允许转发 什么意思呢
|
||||
// 就是说当前网卡并没有找到目标IP 我们来试试本机的其他网卡
|
||||
// 其他网卡-其他网卡上的一个可用地址-目标地址
|
||||
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 {
|
||||
n.stack.stats.IP.InvalidAddressesReceived.Increment()
|
||||
return
|
||||
@@ -390,10 +398,12 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr, localLin
|
||||
// Found a NIC.
|
||||
n := r.ref.nic
|
||||
n.mu.RLock()
|
||||
ref, ok := n.endpoints[NetworkEndpointID{dst}]
|
||||
ref, ok := n.endpoints[NetworkEndpointID{dst}] // 检查这张网卡是否绑定了目标IP
|
||||
n.mu.RUnlock()
|
||||
|
||||
if ok && ref.tryIncRef() {
|
||||
ref.ep.HandlePacket(&r, vv)
|
||||
logger.NOTICE("转发数据")
|
||||
ref.decRef()
|
||||
} else {
|
||||
// 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
|
||||
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() {
|
||||
log.Println(r.LocalLinkAddress, r.LocalAddress, r.RemoteLinkAddress, r.RemoteAddress, r.NextHop)
|
||||
})
|
||||
|
Reference in New Issue
Block a user