NS3 MacRxMiddle类说明

作者: shawn168 | 来源:发表于2017-06-25 20:34 被阅读78次

    官方文档说明

    该类处理片段的重复检测和重组。

    也就是说该类的功能主要是检测节点接收到的分组是否重复,以及是否是分片,如果是分片的话,缓存分片。并且等待接收到最后一个分片的情况下,重新组合接收到的分片成为一个完整的packet,也就是重组。

    源码解析

    源码位置
    /src/wifi/model/mac-rx-middle.cc

    从源码的角度来看,整个MacRxMiddle类还是比较简单的。

    方法数并不是很多。只有一个构造函数。

    MacRxMiddle::MacRxMiddle ()
    {
      NS_LOG_FUNCTION_NOARGS ();
    }
    

    ns3中使用到MacRxMiddle类对象的地方,也就是RegularWifiMac类中使用。是通过回调实现的。
    RegularWifiMac类在其构造器中使用下面的代码创建MacRxMiddle类对象那个,并将RegularWifiMac::Receive方法设置为回调函数地址。

    m_rxMiddle = new MacRxMiddle ();
    m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));
    

    而MacRxMiddle的SetForwardCallback方法源码为:

    void
    MacRxMiddle::SetForwardCallback (ForwardUpCallback callback)
    {
      NS_LOG_FUNCTION_NOARGS ();
      m_callback = callback;
    }
    

    MacRxMiddle类比较重要的方法是Receive方法。

    void
    MacRxMiddle::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
    {
      NS_LOG_FUNCTION (packet << hdr);
      NS_ASSERT (hdr->IsData () || hdr->IsMgt ());
      OriginatorRxStatus *originator = Lookup (hdr);
    
      if (!(SequenceNumber16 (originator->GetLastSequenceControl ()) < SequenceNumber16 (hdr->GetSequenceControl ())))
        {
          NS_LOG_DEBUG ("Sequence numbers have looped back. last recorded=" << originator->GetLastSequenceControl () <<
                        " currently seen=" << hdr->GetSequenceControl ());
        }
      //filter duplicates.
      if (IsDuplicate (hdr, originator))
        {
          NS_LOG_DEBUG ("duplicate from=" << hdr->GetAddr2 () <<
                        ", seq=" << hdr->GetSequenceNumber () <<
                        ", frag=" << hdr->GetFragmentNumber ());
          return;
        }
      Ptr<Packet> agregate = HandleFragments (packet, hdr, originator);
      if (agregate == 0)
        {
          return;
        }
      NS_LOG_DEBUG ("forwarding data from=" << hdr->GetAddr2 () <<
                    ", seq=" << hdr->GetSequenceNumber () <<
                    ", frag=" << hdr->GetFragmentNumber ());
      if (!hdr->GetAddr1 ().IsGroup ())
        {
          originator->SetSequenceControl (hdr->GetSequenceControl ());
        }
      m_callback (agregate, hdr);
    }
    

    MacRxMiddle::Receive方法通过Mac头找到对应的OriginatorRxStatus 对象,比较上一次接收的序列控制号与本次接收到的packet的序列控制号是否是有序的。

    然后通过IsDuplicate 方法判断接收的packet是否是重复的,如果重复,直接返回。

    然后通过HandleFragments 方法判断是否需要重组packet,以及完成packet的重组。

    如果返回的agregate 对象为空,直接返回。

    如果返回的agregate 对象不空,则通过上面的MacRxMiddle::SetForwardCallback方法设置的回调函数地址调用相对应的回调函数。

    综上来看,上面的MacRxMiddle::Receive设计到三个重要的方法:Lookup IsDuplicate HandleFragments 。一个个来看。

    首先看Lookup 方法:

    OriginatorRxStatus *
    MacRxMiddle::Lookup (const WifiMacHeader *hdr)
    {
      NS_LOG_FUNCTION (hdr);
      OriginatorRxStatus *originator;
      Mac48Address source = hdr->GetAddr2 ();
      if (hdr->IsQosData ()
          && !hdr->GetAddr2 ().IsGroup ())
        {
          /* only for qos data non-broadcast frames */
          originator = m_qosOriginatorStatus[std::make_pair (source, hdr->GetQosTid ())];
          if (originator == 0)
            {
              originator = new OriginatorRxStatus ();
              m_qosOriginatorStatus[std::make_pair (source, hdr->GetQosTid ())] = originator;
            }
        }
      else
        {
          originator = m_originatorStatus[source];
          if (originator == 0)
            {
              originator = new OriginatorRxStatus ();
              m_originatorStatus[source] = originator;
            }
        }
      return originator;
    }
    

    MacRxMiddle::Lookup 方法完成的功能就是通过Mac头找到对应的OriginatorRxStatus 对象,如果没有,则创建一个对应的OriginatorRxStatus 对象。

    OriginatorRxStatus 类功能也比较简单:

    class OriginatorRxStatus
    {
    private:
      //list列表,保存接收的每个分片packet,当接收到最后一个分片的时候,组合为完成的一个packet。
      typedef std::list<Ptr<const Packet> > Fragments;
      //迭代器
      typedef std::list<Ptr<const Packet> >::const_iterator FragmentsCI;
      //标记位,标记接收的packet是否为分片
      bool m_defragmenting;
      //记录上一次接收的packet的序列控制号
      uint16_t m_lastSequenceControl;
      //list对象
      Fragments m_fragments;
    
    
    public:
      //默认构造器,初始序列控制号全是1,并标记不是分片。
      OriginatorRxStatus ()
      {
        m_lastSequenceControl = 0xffff;
        m_defragmenting = false;
      }
      ~OriginatorRxStatus ()
      {
        m_fragments.clear ();
      }
      //返回是否是分片标记位
      bool IsDeFragmenting (void)
      {
        return m_defragmenting;
      }
      //当接收到第一个分片的时候,设置标记位,并保存第一个分片packet。
      void AccumulateFirstFragment (Ptr<const Packet> packet)
      {
        NS_ASSERT (!m_defragmenting);
        m_defragmenting = true;
        m_fragments.push_back (packet);
      }
     
      //当接收到最后一个分片的时候,重置标记位,并通过m_fragments对象保存的每一个分片,重新生成一个完成的packet对象,并返回。
      Ptr<Packet> AccumulateLastFragment (Ptr<const Packet> packet)
      {
        NS_ASSERT (m_defragmenting);
        m_fragments.push_back (packet);
        m_defragmenting = false;
        Ptr<Packet> full = Create<Packet> ();
        for (FragmentsCI i = m_fragments.begin (); i != m_fragments.end (); i++)
          {
            full->AddAtEnd (*i);
          }
        m_fragments.erase (m_fragments.begin (), m_fragments.end ());
        return full;
      }
      
      //当接收的分片既不是第一个,又不是最后一个分片的时候,保存在list列表中.
      void AccumulateFragment (Ptr<const Packet> packet)
      {
        NS_ASSERT (m_defragmenting);
        m_fragments.push_back (packet);
      }
     
      //该方法判断接收的分片是否是上一个分片的序列控制号m_lastSequenceControl 的下一个序列控制号
      bool IsNextFragment (uint16_t sequenceControl)
      {
        if ((sequenceControl >> 4) == (m_lastSequenceControl >> 4)
            && (sequenceControl & 0x0f) == ((m_lastSequenceControl & 0x0f) + 1))
          {
            return true;
          }
        else
          {
            return false;
          }
      }
    
      uint16_t GetLastSequenceControl (void)
      {
        return m_lastSequenceControl;
      }
    
      void SetSequenceControl (uint16_t sequenceControl)
      {
        m_lastSequenceControl = sequenceControl;
      }
    };
    

    MacRxMiddle::Lookup 方法完成的功能就是通过Mac头找到对应的OriginatorRxStatus 对象,有了OriginatorRxStatus 对象就可以完成分片的一些判断了。

    MacRxMiddle::IsDuplicate 方法就通过Mac头和上面的MacRxMiddle::Lookup 方法返回的OriginatorRxStatus 对象来判断接收的分片是否是重复的:

    bool
    MacRxMiddle::IsDuplicate (const WifiMacHeader* hdr,
                              OriginatorRxStatus *originator) const
    {
      NS_LOG_FUNCTION (hdr << originator);
      if (hdr->IsRetry ()
          && originator->GetLastSequenceControl () == hdr->GetSequenceControl ())
        {
          return true;
        }
      return false;
    }
    

    如果上一次接收的序列控制号与本次接收的序列控制号相等,那就是重复的。

    MacRxMiddle::HandleFragments方法完成对接收到的分片进行处理,也同样通过利用MacRxMiddle::Lookup 方法返回的OriginatorRxStatus 对象。

    Ptr<Packet>
    MacRxMiddle::HandleFragments (Ptr<Packet> packet, const WifiMacHeader *hdr,
                                  OriginatorRxStatus *originator)
    {
      NS_LOG_FUNCTION (packet << hdr << originator);
      if (originator->IsDeFragmenting ())
        {
          if (hdr->IsMoreFragments ())
            {
              if (originator->IsNextFragment (hdr->GetSequenceControl ()))
                {
                  NS_LOG_DEBUG ("accumulate fragment seq=" << hdr->GetSequenceNumber () <<
                                ", frag=" << hdr->GetFragmentNumber () <<
                                ", size=" << packet->GetSize ());
                  originator->AccumulateFragment (packet);
                  originator->SetSequenceControl (hdr->GetSequenceControl ());
                }
              else
                {
                  NS_LOG_DEBUG ("non-ordered fragment");
                }
              return 0;
            }
          else
            {
              if (originator->IsNextFragment (hdr->GetSequenceControl ()))
                {
                  NS_LOG_DEBUG ("accumulate last fragment seq=" << hdr->GetSequenceNumber () <<
                                ", frag=" << hdr->GetFragmentNumber () <<
                                ", size=" << hdr->GetSize ());
                  Ptr<Packet> p = originator->AccumulateLastFragment (packet);
                  originator->SetSequenceControl (hdr->GetSequenceControl ());
                  return p;
                }
              else
                {
                  NS_LOG_DEBUG ("non-ordered fragment");
                  return 0;
                }
            }
        }
      else
        {
          if (hdr->IsMoreFragments ())
            {
              NS_LOG_DEBUG ("accumulate first fragment seq=" << hdr->GetSequenceNumber () <<
                            ", frag=" << hdr->GetFragmentNumber () <<
                            ", size=" << packet->GetSize ());
              originator->AccumulateFirstFragment (packet);
              originator->SetSequenceControl (hdr->GetSequenceControl ());
              return 0;
            }
          else
            {
              return packet;
            }
        }
    }
    

    1、如果接收的Mac头对应的packet是分片,即originator->IsDeFragmenting ()返回true,并且Mac头还有分片,即hdr->IsMoreFragments ()返回true,且当前接收的packet就是上一次接收的分片的下一个,序列控制号没有出错,则通过originator对象完成分片的缓存,并重置序列控制号,为下一次接收的分片做准备。

    2、如果接收的Mac头对应的packet是分片,即originator->IsDeFragmenting ()返回true,并且Mac头还有分片,即hdr->IsMoreFragments ()返回true,但是当前接收的packet不是上一次接收的分片的下一个,则NS_LOG_DEBUG ("non-ordered fragment");

    3、如果接收的Mac头对应的packet是分片,即originator->IsDeFragmenting ()返回true,并且Mac头没有分片,即hdr->IsMoreFragments ()返回false,且当前接收的packet就是上一次接收的分片的下一个,说明接收到了最后一个分片,则通过originator对象的AccumulateLastFragment 方法完成分片的重组,返回一个完成的packet:

    Ptr<Packet> p = originator->AccumulateLastFragment (packet);
    originator->SetSequenceControl (hdr->GetSequenceControl ());
    return p;
    

    4、如果接收的Mac头对应的packet不是分片,即originator->IsDeFragmenting ()返回false,并且Mac头还有分片,即hdr->IsMoreFragments ()返回true,说明接收到的packet是第一个分片,则通过originator的AccumulateFirstFragment 方法处理第一个分片,并设置标记位和序列控制号,为下一个分片做准备。

    5、如果接收的Mac头对应的packet不是分片,即originator->IsDeFragmenting ()返回false,并且Mac头没有分片,即hdr->IsMoreFragments ()返回false,即接收的packet是一个独立的数据帧,不是分片,则直接返回该packet对象。

    至此,MacRxMiddle类的方法基本说明完毕。


    另外,需要说明MacRxMiddle类的Receive 的调用,同样是在RegularWifiMac::RegularWifiMac ()构造器函数中设置的。代码如下:

    RegularWifiMac::RegularWifiMac () :
      m_htSupported (0),
      m_vhtSupported (0),
      m_erpSupported (0),
      m_dsssSupported (0)
    {
      NS_LOG_FUNCTION (this);
      //创建MacRxMiddle 对象。
      m_rxMiddle = new MacRxMiddle ();
      //设置MacRxMiddle 对象中回调地址
      m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));
    
      m_txMiddle = new MacTxMiddle ();
    
      m_low = CreateObject<MacLow> ();
      //设置MacRxMiddle 对象的Receive方法的回调
      m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle));
    
     。。。。
    }
    

    也就是说MacLow对象中有一个回调地址,设置为MacRxMiddle::Receive,该回调地址调用MacRxMiddle::Receive方法,而MacRxMiddle::Receive方法中,又回调RegularWifiMac::Receive方法,这样一层层传递的。

    相关文章

      网友评论

        本文标题:NS3 MacRxMiddle类说明

        本文链接:https://www.haomeiwen.com/subject/eablattx.html