从我的另一篇文章:NS3 WiFiNetDevice结构大致可以了解到Packet从NetDevice到物理层之间的调用过程。
本章文章说一说Packet从Socket到NetDevice的发送和接收过程。
前言
1、调用过程,以Udp协议为基础,因为Udp协议简单些,Tcp类似。
2、需要了解到NS3 Node聚合对象说明,这篇文章说明了对象的聚合关系。
3、需要了解到NS3 Socket发送Packet的过程,这篇文章说明了socket对象的创建过程和socket发送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 recvSink = Socket::CreateSocket (c.Get (0), tid);
InetSocketAddress local = InetSocketAddress (Ipv4Address ("10.1.1.1"), 80);
recvSink->Bind (local);
recvSink->SetRecvCallback (MakeCallback (&ReceivePacket));
Ptr 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方法如下:
/**
* 发送分组回调方法
*/
static void GenerateTraffic (Ptr socket, uint32_t pktSize,
uint32_t pktCount, Time pktInterval )
{
NS_LOG_FUNCTION(socket< 0)
{
startTime=Simulator::Now();
NS_LOG_LOGIC("start time:"<Send (Create (pktSize));
Simulator::Schedule (pktInterval, &GenerateTraffic,
socket, pktSize,pktCount-1, pktInterval);
}
else
{
socket->Close ();
}
}
Socket发送Packet到NetDevice过程
从NS3 Socket发送Packet的过程,这篇文章了解到UdpSocketImpl才是真正的socket对象,实现socket的功能。
GenerateTraffic 方法调用UdpSocketImpl对象的Send方法发送packet对象。代码如下:
int
Socket::Send (Ptr p)
{
return Send (p, 0);
}
int
UdpSocketImpl::Send (Ptr p, uint32_t flags)
{
if (!m_connected)
{
m_errno = ERROR_NOTCONN;
return -1;
}
return DoSend (p);
}
int
UdpSocketImpl::DoSend (Ptr 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方法调用DoSend方法,其中DoSend方法做了一些判断,判断socket实现已经bind和connection。
因为Socket通信是有三次握手和结束通信时的三次挥手。如果不知道这个的,请自行补脑socket通信。上面的代码我把这部分去掉了。
UdpSocketImpl::DoSend方法又调用了DoSendTo 方法,分为两种情况,一种是IPV4,一种是IPV6.
这里我们还是以Ipv4为例说明。
int
UdpSocketImpl::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port, uint8_t tos)
{
.....
....
....
/*
* 如果dest设置为有限广播地址(全部),则将其转换为将每个接口的数据包副本作为子网定向广播发送。
* 例外:如果接口有一个/ 32地址,那么没有有效的子网定向广播,所以发送它作为有限广播。
* 还要注意,一些系统只会从“默认”接口发送有限的广播数据包; 这里我们发送所有接口
*/
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方法会对目的地地址做一个判断,如果目的地是广播做一个处理,不是广播地址再做一个处理。
以不是广播来处理,就会调用
m_udp->Send (p->Copy (), m_endPoint->GetLocalAddress (), dest,
m_endPoint->GetLocalPort (), port, 0);
其中的m_udp对象就是UdpL4Protocol类对象。
void
UdpL4Protocol::Send (Ptr packet,
Ipv4Address saddr, Ipv4Address daddr,
uint16_t sport, uint16_t dport, Ptr 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 方法调用了一个m_downTarget 的回调地址。m_downTarget 的值的设置代码如下:
void
UdpL4Protocol::NotifyNewAggregate ()
{
NS_LOG_FUNCTION (this);
Ptr node = this->GetObject ();
Ptr ipv4 = this->GetObject ();
Ptr ipv6 = node->GetObject ();
if (m_node == 0)
{
if ((node != 0) && (ipv4 != 0 || ipv6 != 0))
{
this->SetNode (node);
Ptr udpFactory = CreateObject ();
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 回调地址进行了设置,SetDownTarget 方法便是。
其中的Ipv4::Send就是Ipv4L3Protocol::Send。
void
Ipv4L3Protocol::Send (Ptr packet,
Ipv4Address source,
Ipv4Address destination,
uint8_t protocol,
Ptr 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
// 数据包注定为子网定向的广播地址
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 oif (0); // unused for now
ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, tos, mayFragment);
Ptr 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 (), 0);
}
}
Ipv4L3Protocol::Send发送packet分了五钟情况,五种如果分别来说,太麻烦了。
针对客户端代码中的设置,经过测试,packet会经过第五种情况向下层传递。
也就是会调用SendRealOut (newRoute, packet->Copy (), ipHeader);方法。
void
Ipv4L3Protocol::SendRealOut (Ptr route,
Ptr packet,
Ipv4Header const &ipHeader)
{
NS_LOG_FUNCTION (this << route << packet << &ipHeader);
......
Ptr outDev = route->GetOutputDevice ();
int32_t interface = GetInterfaceForDevice (outDev);
NS_ASSERT (interface >= 0);
Ptr 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 (), 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 (), interface);
}
}
}
其中packet会经过 outInterface->Send (packet, ipHeader, ipHeader.GetDestination ());方法传递。
outInterface对象是Ipv4Interface类对象。
void
Ipv4Interface::Send (Ptr p, const Ipv4Header & hdr, Ipv4Address dest)
{
NS_LOG_FUNCTION (this << *p << dest);
.........
// 是这个数据包针对本地接口?
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 arp = m_node->GetObject ();
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 (p, hardwareDestination,
Ipv4L3Protocol::PROT_NUMBER, hdr));
}
}
else
{
NS_LOG_LOGIC ("Doesn't need ARP");
m_tc->Send (m_device, Create (p, m_device->GetBroadcast (),
Ipv4L3Protocol::PROT_NUMBER, hdr));
}
}
Ipv4Interface的Send方法会做一些判断,广播,多播、子网广播、ARP等,处理不同。
对于packet的发送,基本都是通过m_tc对象的Send方法。m_tc对象就是TrafficControlLayer类对象。
void
TrafficControlLayer::Send (Ptr device, Ptr item)
{
.....
if (ndi->second.rootQueueDisc == 0)
{
// 设备没有附加的队列磁盘,因此将报头添加到数据包,如果所选队列未停止,
// 则将其直接发送到设备
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发送packet。
其中的device对象就是WiFiNetDevice对象。
由此,完成了packet从socket对象到netdevice的发送过程。
总结一下发送过程就是:
Socket::Send
|
UdpSocketImpl::Send
|
UdpSocketImpl::DoSend
|
UdpSocketImpl::DoSendTo
|
UdpL4Protocol::Send
|
Ipv4L3Protocol::Send
|
Ipv4L3Protocol::SendRealOut
|
Ipv4Interface::Send
|
TrafficControlLayer::Send
|
NetDevice->Send
NetDevice接收Packet到Socket的过程
这个过程比较复杂,这个过程不像上面packet的发送过程那样,一步一步接下来就成。
packet的接收过程用到了大量的回调。比较复杂一些。
收到看WiFiNetDevice的packet接收:
void
WifiNetDevice::ForwardUp (Ptr 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向上层协议传输的过程,是通过两个回调函数来完成的。
一个是m_forwardUp ,另一个是m_promiscRx 。这两个都是回调函数指针。
这两个值的设定在哪里呢?
是在Node.cc中完成的。
uint32_t
Node::AddDevice (Ptr 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 设置的就是m_forwardUp 回调地址值。
对于第二个m_promiscRx 的值,默认情况下,不会进行设置,但是需要明白的是,该值也是在Node类中完成设置的。
由此,我们知道,WifiNetDevice::ForwardUp 直接把packet上传到Node::NonPromiscReceiveFromDevice方法当中执行。
bool
Node::NonPromiscReceiveFromDevice (Ptr device, Ptr 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 device, Ptr 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:"<
Node::NonPromiscReceiveFromDevice方法调用Node::ReceiveFromDevice方法,方法内部会循环判断是否是合适的处理packet的协议,如果有found为true,则就有该协议来处理packet。
m_handlers是一个列表,针对文章开始的客户端代码,m_handlers的size是3.也就是说有三个这样的协议能够处理packet。
m_handlers的值的设置是通过Node::RegisterProtocolHandler方法设置的。代码如下:
void
Node::RegisterProtocolHandler (ProtocolHandler handler,
uint16_t protocolType,
Ptr 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 >::iterator i = m_devices.begin ();
i != m_devices.end (); i++)
{
Ptr dev = *i;
dev->SetPromiscReceiveCallback (MakeCallback (&Node::PromiscReceiveFromDevice, this));
}
}
else
{
device->SetPromiscReceiveCallback (MakeCallback (&Node::PromiscReceiveFromDevice, this));
}
}
m_handlers.push_back (entry);
}
通过以上的代码m_handlers中就添加了一些处理协议。然后在Node::NonPromiscReceiveFromDevice方法中调用m_handlers中注册的处理方法。
通过全局搜索的话,调用Node::RegisterProtocolHandler方法的地方有很多,针对文章开头给出的客户端代码来说,调用Node::RegisterProtocolHandler方法的地方有三处:
uint32_t
Ipv4L3Protocol::AddInterface (Ptr device)
{
NS_LOG_FUNCTION (this << device);
NS_ASSERT (m_node != 0);
Ptr tc = m_node->GetObject ();
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::PROT_NUMBER, device);
Ptr interface = CreateObject ();
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 interface = CreateObject ();
Ptr 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 (m_node->GetDevice (i))))
{
break;
}
}
if (device == 0)
{
device = CreateObject ();
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 = GetObject ();
node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
interface->SetUp ();
if (m_routingProtocol != 0)
{
m_routingProtocol->NotifyInterfaceUp (index);
}
}
Ipv4L3Protocol::AddInterface和Ipv4L3Protocol::SetupLoopback两个方法中,总共三处使用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来完成的,只不过协议不同。
后一种是通过Ipv4L3Protocol::Receive来完成的,协议是Ipv4L3Protocol。不过,需要注意的是device,这里的device指的是LoopbackNetDevice,这与文章开头设置的WiFiNetDevice不同,所以这种情况不会调用,除非你设置有LoopbackNetDevice。
void
TrafficControlLayer::Receive (Ptr device, Ptr 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 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这个方法的调用,就是上面提到的Ipv4L3Protocol::AddInterface方法中的这两行代码:
tc->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
tc->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject ())),
ArpL3Protocol::PROT_NUMBER, device);
具体执行哪里,要看使用的协议。对于packet数据包来说,处理起来就是Ipv4L3Protocol::Receive,如果使用到了ARP协议,处理起来就是ArpL3Protocol::Receive。
这里以Ipv4L3Protocol::Receive为例说明。
void
Ipv4L3Protocol::Receive ( Ptr device, Ptr 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 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 (), interface);
}
}
Ipv4L3Protocol::Receive代码中有一个Ipv4RawSocketImpl。对于文章开头给出的客户端代码来说,没有使用Ipv4RawSocketImpl相关的类,所以for循环中不会执行。
接着会执行m_routingProtocol->RouteInput 方法,RouteInput 方法中有几个回调参数,会执行Ipv4L3Protocol::LocalDeliver,就会回到Ipv4L3Protocol类中。
void
Ipv4L3Protocol::LocalDeliver (Ptr packet, Ipv4Header const&ip, uint32_t iif)
{
.....
.....
Ptr protocol = GetProtocol (ipHeader.GetProtocol (), iif);
if (protocol != 0)
{
Ptr copy = p->Copy ();
enum IpL4Protocol::RxStatus status =
protocol->Receive (p, ipHeader, GetInterface (iif));//这里调用传输层协议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
}
.....
}
}
}
上面关键的代码是这几行:
Ptr protocol = GetProtocol (ipHeader.GetProtocol (), iif);
Ptr copy = p->Copy ();
enum IpL4Protocol::RxStatus status =
protocol->Receive (p, ipHeader, GetInterface (iif));//这里调用传输层协议Receive方法。
其中的protocol 就是UdpL4Protocol。会执行它的Receive方法。
enum IpL4Protocol::RxStatus
UdpL4Protocol::Receive (Ptr packet,
Ipv4Header const &header,
Ptr interface)
{
.....
.....
Ipv4EndPointDemux::EndPoints endPoints =
m_endPoints->Lookup (header.GetDestination (), udpHeader.GetDestinationPort (),
header.GetSource (), udpHeader.GetSourcePort (), interface);
if (endPoints.empty ())
{
if (this->GetObject () != 0)
{
NS_LOG_LOGIC (" No Ipv4 endpoints matched on UdpL4Protocol, trying Ipv6 "<RemoveHeader(udpHeader);
for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
endPoint != endPoints.end (); endPoint++)
{
(*endPoint)->ForwardUp (packet->Copy (), header, udpHeader.GetSourcePort (),
interface);
}
return IpL4Protocol::RX_OK;
}
其中就会执行 (*endPoint)->ForwardUp。
void
Ipv4EndPoint::ForwardUp (Ptr p, const Ipv4Header& header, uint16_t sport,
Ptr incomingInterface)
{
NS_LOG_FUNCTION (this << p << &header << sport << incomingInterface);
if (!m_rxCallback.IsNull ())
{
m_rxCallback (p, header, sport, incomingInterface);
}
}
其中的m_rxCallback 的设置是通过来设置的:
int
UdpSocketImpl::FinishBind (void)
{
NS_LOG_FUNCTION_NOARGS ();
bool done = false;
if (m_endPoint != 0)
{
m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, Ptr (this)));
m_endPoint->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp, Ptr (this)));
m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, Ptr (this)));
done = true;
}
if (m_endPoint6 != 0)
{
m_endPoint6->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp6, Ptr (this)));
m_endPoint6->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp6, Ptr (this)));
m_endPoint6->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy6, Ptr (this)));
done = true;
}
if (done)
{
return 0;
}
return -1;
}
m_rxCallback 也就是调用UdpSocketImpl::ForwardUp:
void
UdpSocketImpl::ForwardUp (Ptr packet, Ipv4Header header, uint16_t port,
Ptr 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);
}
}
接着调用NotifyDataRecv ();通知数据接收。该方法有父类Socket类完成。
void
Socket::NotifyDataRecv (void)
{
NS_LOG_FUNCTION (this);
if (!m_receivedData.IsNull ())
{
m_receivedData (this);
}
}
m_receivedData 是一个回调函数指针。客户端代码可以设置,例如文章开头的代码:
recvSink->SetRecvCallback (MakeCallback (&ReceivePacket));
就是将ReceivePacket函数地址设置给m_receivedData 回调函数指针。
至此,将packet从netdevice接收到socket的过程顺着捋了一遍。
总结一下这个过程:
WifiNetDevice::ForwardUp
|
Node::NonPromiscReceiveFromDevice
|
Node::ReceiveFromDevice
|
TrafficControlLayer::Receive
|
Ipv4L3Protocol::Receive
|
Ipv4L3Protocol::LocalDeliver
|
UdpL4Protocol::Receive
|
Ipv4EndPoint::ForwardUp
|
UdpSocketImpl::ForwardUp
|
Socket::NotifyDataRecv
总结
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