NS3 WiFi环境中Packet从Socket到NetDevice的调用过程

从我的另一篇文章: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<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方法如下:

/**
 * 发送分组回调方法
 */
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发送Packet到NetDevice过程

NS3 Socket发送Packet的过程,这篇文章了解到UdpSocketImpl才是真正的socket对象,实现socket的功能。

GenerateTraffic 方法调用UdpSocketImpl对象的Send方法发送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方法调用DoSend方法,其中DoSend方法做了一些判断,判断socket实现已经bind和connection。

因为Socket通信是有三次握手和结束通信时的三次挥手。如果不知道这个的,请自行补脑socket通信。上面的代码我把这部分去掉了。

UdpSocketImpl::DoSend方法又调用了DoSendTo 方法,分为两种情况,一种是IPV4,一种是IPV6.

这里我们还是以Ipv4为例说明。

int
UdpSocketImpl::DoSendTo (Ptr<Packet> 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> 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 方法调用了一个m_downTarget 的回调地址。m_downTarget 的值的设置代码如下:

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 回调地址进行了设置,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
  // 数据包注定为子网定向的广播地址
  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发送packet分了五钟情况,五种如果分别来说,太麻烦了。

针对客户端代码中的设置,经过测试,packet会经过第五种情况向下层传递。
也就是会调用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会经过 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);
  .........
  
  // 是这个数据包针对本地接口?
  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方法会做一些判断,广播,多播、子网广播、ARP等,处理不同。
对于packet的发送,基本都是通过m_tc对象的Send方法。m_tc对象就是TrafficControlLayer类对象。

void
TrafficControlLayer::Send (Ptr<NetDevice> device, Ptr<QueueDiscItem> 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> 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<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 设置的就是m_forwardUp 回调地址值。
对于第二个m_promiscRx 的值,默认情况下,不会进行设置,但是需要明白的是,该值也是在Node类中完成设置的。

由此,我们知道,WifiNetDevice::ForwardUp 直接把packet上传到Node::NonPromiscReceiveFromDevice方法当中执行。

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方法调用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<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中就添加了一些处理协议。然后在Node::NonPromiscReceiveFromDevice方法中调用m_handlers中注册的处理方法。

通过全局搜索的话,调用Node::RegisterProtocolHandler方法的地方有很多,针对文章开头给出的客户端代码来说,调用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两个方法中,总共三处使用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<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这个方法的调用,就是上面提到的Ipv4L3Protocol::AddInterface方法中的这两行代码:

tc->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
                               Ipv4L3Protocol::PROT_NUMBER, device);
  tc->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
                               ArpL3Protocol::PROT_NUMBER, device);

具体执行哪里,要看使用的协议。对于packet数据包来说,处理起来就是Ipv4L3Protocol::Receive,如果使用到了ARP协议,处理起来就是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代码中有一个Ipv4RawSocketImpl。对于文章开头给出的客户端代码来说,没有使用Ipv4RawSocketImpl相关的类,所以for循环中不会执行。

接着会执行m_routingProtocol->RouteInput 方法,RouteInput 方法中有几个回调参数,会执行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));//这里调用传输层协议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<IpL4Protocol> protocol = GetProtocol (ipHeader.GetProtocol (), iif);
Ptr<Packet> copy = p->Copy ();
enum IpL4Protocol::RxStatus status = 
        protocol->Receive (p, ipHeader, GetInterface (iif));//这里调用传输层协议Receive方法。

其中的protocol 就是UdpL4Protocol。会执行它的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;
}

其中就会执行 (*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 的设置是通过来设置的:

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 也就是调用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);
    }
}

接着调用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

推荐阅读更多精彩内容