NS3 MacRxMiddle类说明

官方文档说明

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

也就是说该类的功能主要是检测节点接收到的分组是否重复,以及是否是分片,如果是分片的话,缓存分片。并且等待接收到最后一个分片的情况下,重新组合接收到的分片成为一个完整的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方法,这样一层层传递的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,503评论 6 13
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,293评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者...
    保川阅读 5,903评论 1 13
  • FreakZ学习笔记:路由发现机制 路由发现机制只有在发送通信包的过程中会被调用,而接收过程因为发送时候已经进行了...
    zplodge阅读 770评论 0 0