從我的另一篇文章:NS3 WiFiNetDevice結(jié)構(gòu)大致可以了解到Packet從NetDevice到物理層之間的調(diào)用過程。
本章文章說一說Packet從Socket到NetDevice的發(fā)送和接收過程识啦。
前言
1继效、調(diào)用過程,以Udp協(xié)議為基礎(chǔ)敞葛,因?yàn)閁dp協(xié)議簡單些,Tcp類似。
2毒租、需要了解到NS3 Node聚合對象說明,這篇文章說明了對象的聚合關(guān)系。
3箱叁、需要了解到NS3 Socket發(fā)送Packet的過程,這篇文章說明了socket對象的創(chuàng)建過程和socket發(fā)送packet的簡單過程墅垮。
客戶端代碼
InternetStackHelper internet;
internet.SetIpv6StackInstall(false);
internet.Install (c);
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer i = ipv4.Assign (devices);
TypeId tid=UdpSocketFactory::GetTypeId();
Ptr<Socket> recvSink = Socket::CreateSocket (c.Get (0), tid);
InetSocketAddress local = InetSocketAddress (Ipv4Address ("10.1.1.1"), 80);
recvSink->Bind (local);
recvSink->SetRecvCallback (MakeCallback (&ReceivePacket));
Ptr<Socket> source = Socket::CreateSocket (c.Get (1), tid);
InetSocketAddress remote = InetSocketAddress (Ipv4Address ("10.1.1.2"), 80);
source->SetAllowBroadcast (false);
source->Bind(remote);
source->Connect (local);
Simulator::ScheduleWithContext (source->GetNode ()->GetId (),
Seconds (startSec), &GenerateTraffic,
source, PpacketSize, numPackets, interPacketInterval);
其中GenerateTraffic方法如下:
/**
* 發(fā)送分組回調(diào)方法
*/
static void GenerateTraffic (Ptr<Socket> socket, uint32_t pktSize,
uint32_t pktCount, Time pktInterval )
{
NS_LOG_FUNCTION(socket<<pktSize<<pktCount<<pktInterval);
if (pktCount > 0)
{
startTime=Simulator::Now();
NS_LOG_LOGIC("start time:"<<startTime);
socket->Send (Create<Packet> (pktSize));
Simulator::Schedule (pktInterval, &GenerateTraffic,
socket, pktSize,pktCount-1, pktInterval);
}
else
{
socket->Close ();
}
}
Socket發(fā)送Packet到NetDevice過程
從NS3 Socket發(fā)送Packet的過程,這篇文章了解到UdpSocketImpl才是真正的socket對象,實(shí)現(xiàn)socket的功能耕漱。
GenerateTraffic 方法調(diào)用UdpSocketImpl對象的Send方法發(fā)送packet對象算色。代碼如下:
int
Socket::Send (Ptr<Packet> p)
{
return Send (p, 0);
}
int
UdpSocketImpl::Send (Ptr<Packet> p, uint32_t flags)
{
if (!m_connected)
{
m_errno = ERROR_NOTCONN;
return -1;
}
return DoSend (p);
}
int
UdpSocketImpl::DoSend (Ptr<Packet> p)
{
NS_LOG_FUNCTION (this << p);
......
if (Ipv4Address::IsMatchingType (m_defaultAddress))
{
return DoSendTo (p, Ipv4Address::ConvertFrom (m_defaultAddress), m_defaultPort, GetIpTos ());
}
else if (Ipv6Address::IsMatchingType (m_defaultAddress))
{
return DoSendTo (p, Ipv6Address::ConvertFrom (m_defaultAddress), m_defaultPort);
}
m_errno = ERROR_AFNOSUPPORT;
return(-1);
}
Send方法調(diào)用DoSend方法,其中DoSend方法做了一些判斷螟够,判斷socket實(shí)現(xiàn)已經(jīng)bind和connection灾梦。
因?yàn)镾ocket通信是有三次握手和結(jié)束通信時(shí)的三次揮手峡钓。如果不知道這個(gè)的,請自行補(bǔ)腦socket通信若河。上面的代碼我把這部分去掉了能岩。
UdpSocketImpl::DoSend方法又調(diào)用了DoSendTo 方法,分為兩種情況萧福,一種是IPV4拉鹃,一種是IPV6.
這里我們還是以Ipv4為例說明。
int
UdpSocketImpl::DoSendTo (Ptr<Packet> p, Ipv4Address dest, uint16_t port, uint8_t tos)
{
.....
....
....
/*
* 如果dest設(shè)置為有限廣播地址(全部)鲫忍,則將其轉(zhuǎn)換為將每個(gè)接口的數(shù)據(jù)包副本作為子網(wǎng)定向廣播發(fā)送膏燕。
* 例外:如果接口有一個(gè)/ 32地址,那么沒有有效的子網(wǎng)定向廣播饲窿,所以發(fā)送它作為有限廣播煌寇。
* 還要注意,一些系統(tǒng)只會從“默認(rèn)”接口發(fā)送有限的廣播數(shù)據(jù)包; 這里我們發(fā)送所有接口
*/
if (dest.IsBroadcast ())
{
....
}
else if (m_endPoint->GetLocalAddress () != Ipv4Address::GetAny ())
{
m_udp->Send (p->Copy (), m_endPoint->GetLocalAddress (), dest,
m_endPoint->GetLocalPort (), port, 0);
NotifyDataSent (p->GetSize ());
NotifySend (GetTxAvailable ());
return p->GetSize ();
}
else if (ipv4->GetRoutingProtocol () != 0)
{
.....
}
else
{
NS_LOG_ERROR ("ERROR_NOROUTETOHOST");
m_errno = ERROR_NOROUTETOHOST;
return -1;
}
return 0;
}
UdpSocketImpl::DoSendTo方法會對目的地地址做一個(gè)判斷逾雄,如果目的地是廣播做一個(gè)處理阀溶,不是廣播地址再做一個(gè)處理。
以不是廣播來處理鸦泳,就會調(diào)用
m_udp->Send (p->Copy (), m_endPoint->GetLocalAddress (), dest,
m_endPoint->GetLocalPort (), port, 0);
其中的m_udp對象就是UdpL4Protocol類對象银锻。
void
UdpL4Protocol::Send (Ptr<Packet> packet,
Ipv4Address saddr, Ipv4Address daddr,
uint16_t sport, uint16_t dport, Ptr<Ipv4Route> route)
{
UdpHeader udpHeader;
if(Node::ChecksumEnabled ())
{
udpHeader.EnableChecksums ();
udpHeader.InitializeChecksum (saddr,
daddr,
PROT_NUMBER);
}
udpHeader.SetDestinationPort (dport);
udpHeader.SetSourcePort (sport);
packet->AddHeader (udpHeader);
m_downTarget (packet, saddr, daddr, PROT_NUMBER, route);
}
UdpL4Protocol::Send 方法調(diào)用了一個(gè)m_downTarget 的回調(diào)地址。m_downTarget 的值的設(shè)置代碼如下:
void
UdpL4Protocol::NotifyNewAggregate ()
{
NS_LOG_FUNCTION (this);
Ptr<Node> node = this->GetObject<Node> ();
Ptr<Ipv4> ipv4 = this->GetObject<Ipv4> ();
Ptr<Ipv6> ipv6 = node->GetObject<Ipv6> ();
if (m_node == 0)
{
if ((node != 0) && (ipv4 != 0 || ipv6 != 0))
{
this->SetNode (node);
Ptr<UdpSocketFactoryImpl> udpFactory = CreateObject<UdpSocketFactoryImpl> ();
udpFactory->SetUdp (this);
node->AggregateObject (udpFactory);
}
}
if (ipv4 != 0 && m_downTarget.IsNull())
{
ipv4->Insert (this);
this->SetDownTarget (MakeCallback (&Ipv4::Send, ipv4));
}
IpL4Protocol::NotifyNewAggregate ();
}
UdpL4Protocol在于其他對象如Node對象 UdpSocketFactoryImpl對象聚合過程中做鹰,對m_downTarget 回調(diào)地址進(jìn)行了設(shè)置击纬,SetDownTarget 方法便是。
其中的Ipv4::Send就是Ipv4L3Protocol::Send钾麸。
void
Ipv4L3Protocol::Send (Ptr<Packet> packet,
Ipv4Address source,
Ipv4Address destination,
uint8_t protocol,
Ptr<Ipv4Route> route)
{
.....
.....
// Handle a few cases:
// 1) packet is destined to limited broadcast address
// 2) packet is destined to a subnet-directed broadcast address
// 3) packet is not broadcast, and is passed in with a route entry
// 4) packet is not broadcast, and is passed in with a route entry but route->GetGateway is not set
// 5) packet is not broadcast, and route is NULL (e.g., a raw socket call, or ICMP)
// 1) packet is destined to limited broadcast address or link-local multicast address
// 目的地址是廣播或者本地組播
if (destination.IsBroadcast () || destination.IsLocalMulticast ())
{
.......
return;
}
// 2) check: packet is destined to a subnet-directed broadcast address
// 數(shù)據(jù)包注定為子網(wǎng)定向的廣播地址
uint32_t ifaceIndex = 0;
for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
{
......
}
// 3) packet is not broadcast, and is passed in with a route entry
// with a valid Ipv4Address as the gateway
if (route && route->GetGateway () != Ipv4Address ())
{
......
}
// 4) packet is not broadcast, and is passed in with a route entry but route->GetGateway is not set
if (route && route->GetGateway () == Ipv4Address ())
{
..........
NS_FATAL_ERROR ("Ipv4L3Protocol::Send case 4: This case not yet implemented");
}
// 5) packet is not broadcast, and route is NULL (e.g., a raw socket call)
NS_LOG_LOGIC ("Ipv4L3Protocol::Send case 5: passed in with no route " << destination);
Socket::SocketErrno errno_;
Ptr<NetDevice> oif (0); // unused for now
ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, tos, mayFragment);
Ptr<Ipv4Route> newRoute;
if (m_routingProtocol != 0)
{
newRoute = m_routingProtocol->RouteOutput (packet, ipHeader, oif, errno_);
}
else
{
NS_LOG_ERROR ("Ipv4L3Protocol::Send: m_routingProtocol == 0");
}
if (newRoute)
{
int32_t interface = GetInterfaceForDevice (newRoute->GetOutputDevice ());
m_sendOutgoingTrace (ipHeader, packet, interface);
SendRealOut (newRoute, packet->Copy (), ipHeader);
}
else
{
NS_LOG_WARN ("No route to host. Drop.");
m_dropTrace (ipHeader, packet, DROP_NO_ROUTE, m_node->GetObject<Ipv4> (), 0);
}
}
Ipv4L3Protocol::Send發(fā)送packet分了五鐘情況更振,五種如果分別來說,太麻煩了饭尝。
針對客戶端代碼中的設(shè)置肯腕,經(jīng)過測試,packet會經(jīng)過第五種情況向下層傳遞钥平。
也就是會調(diào)用SendRealOut (newRoute, packet->Copy (), ipHeader);方法实撒。
void
Ipv4L3Protocol::SendRealOut (Ptr<Ipv4Route> route,
Ptr<Packet> packet,
Ipv4Header const &ipHeader)
{
NS_LOG_FUNCTION (this << route << packet << &ipHeader);
......
Ptr<NetDevice> outDev = route->GetOutputDevice ();
int32_t interface = GetInterfaceForDevice (outDev);
NS_ASSERT (interface >= 0);
Ptr<Ipv4Interface> outInterface = GetInterface (interface);
NS_LOG_LOGIC ("Send via NetDevice ifIndex " << outDev->GetIfIndex () << " ipv4InterfaceIndex " << interface);
if (!route->GetGateway ().IsEqual (Ipv4Address ("0.0.0.0")))
{
.....
.....
}
else
{
if (outInterface->IsUp ())
{
NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ());
if ( packet->GetSize () + ipHeader.GetSerializedSize () > outInterface->GetDevice ()->GetMtu () )
{
.......
}
else
{
CallTxTrace (ipHeader, packet, m_node->GetObject<Ipv4> (), interface);
outInterface->Send (packet, ipHeader, ipHeader.GetDestination ());
}
}
else
{
NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << ipHeader.GetDestination ());
m_dropTrace (ipHeader, packet, DROP_INTERFACE_DOWN, m_node->GetObject<Ipv4> (), interface);
}
}
}
其中packet會經(jīng)過 outInterface->Send (packet, ipHeader, ipHeader.GetDestination ());方法傳遞。
outInterface對象是Ipv4Interface類對象涉瘾。
void
Ipv4Interface::Send (Ptr<Packet> p, const Ipv4Header & hdr, Ipv4Address dest)
{
NS_LOG_FUNCTION (this << *p << dest);
.........
// 是這個(gè)數(shù)據(jù)包針對本地接口知态?
for (Ipv4InterfaceAddressListCI i = m_ifaddrs.begin (); i != m_ifaddrs.end (); ++i)
{
if (dest == (*i).GetLocal ())
{
p->AddHeader (hdr);
m_tc->Receive (m_device, p, Ipv4L3Protocol::PROT_NUMBER,
m_device->GetBroadcast (),
m_device->GetBroadcast (),
NetDevice::PACKET_HOST);
return;
}
}
if (m_device->NeedsArp ())
{
NS_LOG_LOGIC ("Needs ARP" << " " << dest);
Ptr<ArpL3Protocol> arp = m_node->GetObject<ArpL3Protocol> ();
Address hardwareDestination;
bool found = false;
if (dest.IsBroadcast ())
{
.....
}
else if (dest.IsMulticast ())
{
......
}
else
{
for (Ipv4InterfaceAddressListCI i = m_ifaddrs.begin (); i != m_ifaddrs.end (); ++i)
{
if (dest.IsSubnetDirectedBroadcast ((*i).GetMask ()))
{
......
}
}
if (!found)
{
NS_LOG_LOGIC ("ARP Lookup");
found = arp->Lookup (p, hdr, dest, m_device, m_cache, &hardwareDestination);
}
}
if (found)
{
NS_LOG_LOGIC ("Address Resolved. Send.");
m_tc->Send (m_device, Create<Ipv4QueueDiscItem> (p, hardwareDestination,
Ipv4L3Protocol::PROT_NUMBER, hdr));
}
}
else
{
NS_LOG_LOGIC ("Doesn't need ARP");
m_tc->Send (m_device, Create<Ipv4QueueDiscItem> (p, m_device->GetBroadcast (),
Ipv4L3Protocol::PROT_NUMBER, hdr));
}
}
Ipv4Interface的Send方法會做一些判斷,廣播立叛,多播负敏、子網(wǎng)廣播、ARP等囚巴,處理不同原在。
對于packet的發(fā)送友扰,基本都是通過m_tc對象的Send方法彤叉。m_tc對象就是TrafficControlLayer類對象庶柿。
void
TrafficControlLayer::Send (Ptr<NetDevice> device, Ptr<QueueDiscItem> item)
{
.....
if (ndi->second.rootQueueDisc == 0)
{
// 設(shè)備沒有附加的隊(duì)列磁盤,因此將報(bào)頭添加到數(shù)據(jù)包秽浇,如果所選隊(duì)列未停止浮庐,
// 則將其直接發(fā)送到設(shè)備
if (!devQueueIface->GetTxQueue (txq)->IsStopped ())
{
item->AddHeader ();
// a single queue device makes no use of the priority tag
if (devQueueIface->GetNTxQueues () == 1)
{
SocketPriorityTag priorityTag;
item->GetPacket ()->RemovePacketTag (priorityTag);
}
device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ());
}
}
else
{
......
}
}
TrafficControlLayer::Send方法會通過device->Send發(fā)送packet。
其中的device對象就是WiFiNetDevice對象柬焕。
由此审残,完成了packet從socket對象到netdevice的發(fā)送過程。
總結(jié)一下發(fā)送過程就是:
Socket::Send
|
UdpSocketImpl::Send
|
UdpSocketImpl::DoSend
|
UdpSocketImpl::DoSendTo
|
UdpL4Protocol::Send
|
Ipv4L3Protocol::Send
|
Ipv4L3Protocol::SendRealOut
|
Ipv4Interface::Send
|
TrafficControlLayer::Send
|
NetDevice->Send
NetDevice接收Packet到Socket的過程
這個(gè)過程比較復(fù)雜斑举,這個(gè)過程不像上面packet的發(fā)送過程那樣搅轿,一步一步接下來就成。
packet的接收過程用到了大量的回調(diào)富玷。比較復(fù)雜一些璧坟。
收到看WiFiNetDevice的packet接收:
void
WifiNetDevice::ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to)
{
NS_LOG_FUNCTION (this << packet << from << to);
LlcSnapHeader llc;
enum NetDevice::PacketType type;
......
if (type != NetDevice::PACKET_OTHERHOST)
{
m_mac->NotifyRx (packet);
packet->RemoveHeader (llc);
m_forwardUp (this, packet, llc.GetType (), from);
}
else
{
packet->RemoveHeader (llc);
}
if (!m_promiscRx.IsNull ())
{
m_mac->NotifyPromiscRx (packet);
m_promiscRx (this, packet, llc.GetType (), from, to, type);
}
}
從上面的代碼中可以看出,從WifiNetDevice向上層協(xié)議傳輸?shù)倪^程赎懦,是通過兩個(gè)回調(diào)函數(shù)來完成的雀鹃。
一個(gè)是m_forwardUp ,另一個(gè)是m_promiscRx 励两。這兩個(gè)都是回調(diào)函數(shù)指針黎茎。
這兩個(gè)值的設(shè)定在哪里呢?
是在Node.cc中完成的当悔。
uint32_t
Node::AddDevice (Ptr<NetDevice> device)
{
NS_LOG_FUNCTION (this << device);
uint32_t index = m_devices.size ();
m_devices.push_back (device);
device->SetNode (this);
device->SetIfIndex (index);
device->SetReceiveCallback (MakeCallback (&Node::NonPromiscReceiveFromDevice, this));
Simulator::ScheduleWithContext (GetId (), Seconds (0.0),
&NetDevice::Initialize, device);
NotifyDeviceAdded (device);
return index;
}
上面的代碼device->SetReceiveCallback 設(shè)置的就是m_forwardUp 回調(diào)地址值傅瞻。
對于第二個(gè)m_promiscRx 的值,默認(rèn)情況下盲憎,不會進(jìn)行設(shè)置嗅骄,但是需要明白的是,該值也是在Node類中完成設(shè)置的焙畔。
由此掸读,我們知道,WifiNetDevice::ForwardUp 直接把packet上傳到Node::NonPromiscReceiveFromDevice方法當(dāng)中執(zhí)行宏多。
bool
Node::NonPromiscReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
const Address &from)
{
NS_LOG_FUNCTION (this << device << packet << protocol << &from);
return ReceiveFromDevice (device, packet, protocol, from, device->GetAddress (),
NetDevice::PacketType (0), false);
}
bool
Node::ReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
const Address &from, const Address &to, NetDevice::PacketType packetType, bool promiscuous)
{
bool found = false;
for (ProtocolHandlerList::iterator i = m_handlers.begin ();
i != m_handlers.end (); i++)
{
if (i->device == 0 ||
(i->device != 0 && i->device == device))
{
if (i->protocol == 0 ||
i->protocol == protocol)
{
if (promiscuous == i->promiscuous)
{
i->handler (device, packet, protocol, from, to, packetType);
found = true;
}
}
}
}
NS_LOG_DEBUG("m_handlers found:"<<found);
return found;
}
Node::NonPromiscReceiveFromDevice方法調(diào)用Node::ReceiveFromDevice方法儿惫,方法內(nèi)部會循環(huán)判斷是否是合適的處理packet的協(xié)議,如果有found為true伸但,則就有該協(xié)議來處理packet肾请。
m_handlers是一個(gè)列表,針對文章開始的客戶端代碼更胖,m_handlers的size是3.也就是說有三個(gè)這樣的協(xié)議能夠處理packet铛铁。
m_handlers的值的設(shè)置是通過Node::RegisterProtocolHandler方法設(shè)置的隔显。代碼如下:
void
Node::RegisterProtocolHandler (ProtocolHandler handler,
uint16_t protocolType,
Ptr<NetDevice> device,
bool promiscuous)
{
NS_LOG_FUNCTION (this << &handler << protocolType << device << promiscuous);
struct Node::ProtocolHandlerEntry entry;
entry.handler = handler;
entry.protocol = protocolType;
entry.device = device;
entry.promiscuous = promiscuous;
// On demand enable promiscuous mode in netdevices
if (promiscuous)
{
if (device == 0)
{
for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
i != m_devices.end (); i++)
{
Ptr<NetDevice> dev = *i;
dev->SetPromiscReceiveCallback (MakeCallback (&Node::PromiscReceiveFromDevice, this));
}
}
else
{
device->SetPromiscReceiveCallback (MakeCallback (&Node::PromiscReceiveFromDevice, this));
}
}
m_handlers.push_back (entry);
}
通過以上的代碼m_handlers中就添加了一些處理協(xié)議。然后在Node::NonPromiscReceiveFromDevice方法中調(diào)用m_handlers中注冊的處理方法饵逐。
通過全局搜索的話括眠,調(diào)用Node::RegisterProtocolHandler方法的地方有很多,針對文章開頭給出的客戶端代碼來說倍权,調(diào)用Node::RegisterProtocolHandler方法的地方有三處:
uint32_t
Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
{
NS_LOG_FUNCTION (this << device);
NS_ASSERT (m_node != 0);
Ptr<TrafficControlLayer> tc = m_node->GetObject<TrafficControlLayer> ();
NS_ASSERT (tc != 0);
m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc),
Ipv4L3Protocol::PROT_NUMBER, device);
m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc),
ArpL3Protocol::PROT_NUMBER, device);
tc->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
tc->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
ArpL3Protocol::PROT_NUMBER, device);
Ptr<Ipv4Interface> interface = CreateObject<Ipv4Interface> ();
interface->SetNode (m_node);
interface->SetDevice (device);
interface->SetTrafficControl (tc);
interface->SetForwarding (m_ipForward);
tc->SetupDevice (device);
return AddIpv4Interface (interface);
}
-------------
void
Ipv4L3Protocol::SetupLoopback (void)
{
NS_LOG_FUNCTION (this);
Ptr<Ipv4Interface> interface = CreateObject<Ipv4Interface> ();
Ptr<LoopbackNetDevice> device = 0;
// First check whether an existing LoopbackNetDevice exists on the node
for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
{
if ((device = DynamicCast<LoopbackNetDevice> (m_node->GetDevice (i))))
{
break;
}
}
if (device == 0)
{
device = CreateObject<LoopbackNetDevice> ();
m_node->AddDevice (device);
}
interface->SetDevice (device);
interface->SetNode (m_node);
Ipv4InterfaceAddress ifaceAddr = Ipv4InterfaceAddress (Ipv4Address::GetLoopback (), Ipv4Mask::GetLoopback ());
interface->AddAddress (ifaceAddr);
uint32_t index = AddIpv4Interface (interface);
Ptr<Node> node = GetObject<Node> ();
node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
interface->SetUp ();
if (m_routingProtocol != 0)
{
m_routingProtocol->NotifyInterfaceUp (index);
}
}
Ipv4L3Protocol::AddInterface和Ipv4L3Protocol::SetupLoopback兩個(gè)方法中掷豺,總共三處使用node->RegisterProtocolHandler 來注冊處理方法的。
m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc),
Ipv4L3Protocol::PROT_NUMBER, device);
m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc),
ArpL3Protocol::PROT_NUMBER, device);
node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
前兩種處理方式薄声,都是通過TrafficControlLayer::Receive來完成的当船,只不過協(xié)議不同。
后一種是通過Ipv4L3Protocol::Receive來完成的默辨,協(xié)議是Ipv4L3Protocol德频。不過,需要注意的是device缩幸,這里的device指的是LoopbackNetDevice壹置,這與文章開頭設(shè)置的WiFiNetDevice不同,所以這種情況不會調(diào)用桌粉,除非你設(shè)置有LoopbackNetDevice蒸绩。
void
TrafficControlLayer::Receive (Ptr<NetDevice> device, Ptr<const Packet> p,
uint16_t protocol, const Address &from, const Address &to,
NetDevice::PacketType packetType)
{
NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
bool found = false;
for (ProtocolHandlerList::iterator i = m_handlers.begin ();
i != m_handlers.end (); i++)
{
if (i->device == 0
|| (i->device != 0 && i->device == device))
{
if (i->protocol == 0
|| i->protocol == protocol)
{
NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
protocol << " and NetDevice " << device <<
". Send packet up");
i->handler (device, p, protocol, from, to, packetType);
found = true;
}
}
}
if (! found)
{
NS_FATAL_ERROR ("Handler for protocol " << p << " and device " << device <<
" not found. It isn't forwarded up; it dies here.");
}
}
TrafficControlLayer::Receive中的m_handlers與上面提到的Node中的m_handlers類似,代碼如下:
void
TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler,
uint16_t protocolType, Ptr<NetDevice> device)
{
NS_LOG_FUNCTION (this << protocolType << device);
struct ProtocolHandlerEntry entry;
entry.handler = handler;
entry.protocol = protocolType;
entry.device = device;
entry.promiscuous = false;
m_handlers.push_back (entry);
NS_LOG_DEBUG ("Handler for NetDevice: " << device << " registered for protocol " <<
protocolType << ".");
}
TrafficControlLayer::RegisterProtocolHandler這個(gè)方法的調(diào)用铃肯,就是上面提到的Ipv4L3Protocol::AddInterface方法中的這兩行代碼:
tc->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
tc->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
ArpL3Protocol::PROT_NUMBER, device);
具體執(zhí)行哪里患亿,要看使用的協(xié)議。對于packet數(shù)據(jù)包來說押逼,處理起來就是Ipv4L3Protocol::Receive步藕,如果使用到了ARP協(xié)議,處理起來就是ArpL3Protocol::Receive挑格。
這里以Ipv4L3Protocol::Receive為例說明咙冗。
void
Ipv4L3Protocol::Receive ( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
const Address &to, NetDevice::PacketType packetType)
{
.....
.....
.....
for (SocketList::iterator i = m_sockets.begin (); i != m_sockets.end (); ++i)
{
NS_LOG_LOGIC ("Forwarding to raw socket");
Ptr<Ipv4RawSocketImpl> socket = *i;
socket->ForwardUp (packet, ipHeader, ipv4Interface);
}
NS_ASSERT_MSG (m_routingProtocol != 0, "Need a routing protocol object to process packets");
if (!m_routingProtocol->RouteInput (packet, ipHeader, device,
MakeCallback (&Ipv4L3Protocol::IpForward, this),
MakeCallback (&Ipv4L3Protocol::IpMulticastForward, this),
MakeCallback (&Ipv4L3Protocol::LocalDeliver, this),
MakeCallback (&Ipv4L3Protocol::RouteInputError, this)
))
{
NS_LOG_WARN ("No route found for forwarding packet. Drop.");
m_dropTrace (ipHeader, packet, DROP_NO_ROUTE, m_node->GetObject<Ipv4> (), interface);
}
}
Ipv4L3Protocol::Receive代碼中有一個(gè)Ipv4RawSocketImpl。對于文章開頭給出的客戶端代碼來說漂彤,沒有使用Ipv4RawSocketImpl相關(guān)的類雾消,所以for循環(huán)中不會執(zhí)行。
接著會執(zhí)行m_routingProtocol->RouteInput 方法挫望,RouteInput 方法中有幾個(gè)回調(diào)參數(shù)立润,會執(zhí)行Ipv4L3Protocol::LocalDeliver,就會回到Ipv4L3Protocol類中媳板。
void
Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
{
.....
.....
Ptr<IpL4Protocol> protocol = GetProtocol (ipHeader.GetProtocol (), iif);
if (protocol != 0)
{
Ptr<Packet> copy = p->Copy ();
enum IpL4Protocol::RxStatus status =
protocol->Receive (p, ipHeader, GetInterface (iif));//這里調(diào)用傳輸層協(xié)議Receive方法桑腮。
switch (status) {
case IpL4Protocol::RX_OK:
// fall through
case IpL4Protocol::RX_ENDPOINT_CLOSED:
// fall through
case IpL4Protocol::RX_CSUM_FAILED:
break;
case IpL4Protocol::RX_ENDPOINT_UNREACH:
if (ipHeader.GetDestination ().IsBroadcast () == true ||
ipHeader.GetDestination ().IsMulticast () == true)
{
break; // Do not reply to broadcast or multicast
}
.....
}
}
}
上面關(guān)鍵的代碼是這幾行:
Ptr<IpL4Protocol> protocol = GetProtocol (ipHeader.GetProtocol (), iif);
Ptr<Packet> copy = p->Copy ();
enum IpL4Protocol::RxStatus status =
protocol->Receive (p, ipHeader, GetInterface (iif));//這里調(diào)用傳輸層協(xié)議Receive方法。
其中的protocol 就是UdpL4Protocol蛉幸。會執(zhí)行它的Receive方法破讨。
enum IpL4Protocol::RxStatus
UdpL4Protocol::Receive (Ptr<Packet> packet,
Ipv4Header const &header,
Ptr<Ipv4Interface> interface)
{
.....
.....
Ipv4EndPointDemux::EndPoints endPoints =
m_endPoints->Lookup (header.GetDestination (), udpHeader.GetDestinationPort (),
header.GetSource (), udpHeader.GetSourcePort (), interface);
if (endPoints.empty ())
{
if (this->GetObject<Ipv6L3Protocol> () != 0)
{
NS_LOG_LOGIC (" No Ipv4 endpoints matched on UdpL4Protocol, trying Ipv6 "<<this);
.....
}
NS_LOG_LOGIC ("RX_ENDPOINT_UNREACH");
return IpL4Protocol::RX_ENDPOINT_UNREACH;
}
packet->RemoveHeader(udpHeader);
for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
endPoint != endPoints.end (); endPoint++)
{
(*endPoint)->ForwardUp (packet->Copy (), header, udpHeader.GetSourcePort (),
interface);
}
return IpL4Protocol::RX_OK;
}
其中就會執(zhí)行 (*endPoint)->ForwardUp丛晦。
void
Ipv4EndPoint::ForwardUp (Ptr<Packet> p, const Ipv4Header& header, uint16_t sport,
Ptr<Ipv4Interface> incomingInterface)
{
NS_LOG_FUNCTION (this << p << &header << sport << incomingInterface);
if (!m_rxCallback.IsNull ())
{
m_rxCallback (p, header, sport, incomingInterface);
}
}
其中的m_rxCallback 的設(shè)置是通過來設(shè)置的:
int
UdpSocketImpl::FinishBind (void)
{
NS_LOG_FUNCTION_NOARGS ();
bool done = false;
if (m_endPoint != 0)
{
m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, Ptr<UdpSocketImpl> (this)));
m_endPoint->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp, Ptr<UdpSocketImpl> (this)));
m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, Ptr<UdpSocketImpl> (this)));
done = true;
}
if (m_endPoint6 != 0)
{
m_endPoint6->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp6, Ptr<UdpSocketImpl> (this)));
m_endPoint6->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp6, Ptr<UdpSocketImpl> (this)));
m_endPoint6->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy6, Ptr<UdpSocketImpl> (this)));
done = true;
}
if (done)
{
return 0;
}
return -1;
}
m_rxCallback 也就是調(diào)用UdpSocketImpl::ForwardUp:
void
UdpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port,
Ptr<Ipv4Interface> incomingInterface)
{
....
....
SocketPriorityTag priorityTag;
packet->RemovePacketTag (priorityTag);
if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
{
Address address = InetSocketAddress (header.GetSource (), port);
m_deliveryQueue.push (std::make_pair (packet, address));
m_rxAvailable += packet->GetSize ();
NotifyDataRecv ();
}
else
{
NS_LOG_WARN ("No receive buffer space available. Drop.");
m_dropTrace (packet);
}
}
接著調(diào)用NotifyDataRecv ();通知數(shù)據(jù)接收。該方法有父類Socket類完成提陶。
void
Socket::NotifyDataRecv (void)
{
NS_LOG_FUNCTION (this);
if (!m_receivedData.IsNull ())
{
m_receivedData (this);
}
}
m_receivedData 是一個(gè)回調(diào)函數(shù)指針烫沙。客戶端代碼可以設(shè)置搁骑,例如文章開頭的代碼:
recvSink->SetRecvCallback (MakeCallback (&ReceivePacket));
就是將ReceivePacket函數(shù)地址設(shè)置給m_receivedData 回調(diào)函數(shù)指針斧吐。
至此又固,將packet從netdevice接收到socket的過程順著捋了一遍仲器。
總結(jié)一下這個(gè)過程:
WifiNetDevice::ForwardUp
|
Node::NonPromiscReceiveFromDevice
|
Node::ReceiveFromDevice
|
TrafficControlLayer::Receive
|
Ipv4L3Protocol::Receive
|
Ipv4L3Protocol::LocalDeliver
|
UdpL4Protocol::Receive
|
Ipv4EndPoint::ForwardUp
|
UdpSocketImpl::ForwardUp
|
Socket::NotifyDataRecv
總結(jié)
Socket::Send Socket::NotifyDataRecv
| |
UdpSocketImpl::Send UdpSocketImpl::ForwardUp
| |
UdpSocketImpl::DoSend Ipv4EndPoint::ForwardUp
| |
UdpSocketImpl::DoSendTo |
| |
UdpL4Protocol::Send UdpL4Protocol::Receive
| |
Ipv4L3Protocol::Send UdpL4Protocol::Receive
| |
Ipv4L3Protocol::SendRealOut Ipv4L3Protocol::Receive
| |
Ipv4Interface::Send |
| |
TrafficControlLayer::Send TrafficControlLayer::Receive
| |
| Node::NonPromiscReceiveFromDevice
| |
NetDevice->Send ---------------------------------> WifiNetDevice::ForwardUp