NS-3源码学习(七)追踪和Probe

发布时间 2023-12-20 20:06:18作者: PolarisZg

追踪框架和WiFi的STA接入AP时使用的Probe Request帧、Probe Response帧没有关系。

追踪

NS-3的追踪框架主要用于追踪一个对象当中某个属性的变更、或者某个事件的发生。NS-3初始规定了一些追踪源,一般在一个model的GetTypeId()方法中定义了这些追踪源(和这个model的属性),我们可以使用两种方法(Config或model自带的Connect方法)为这些追踪源添加两种回调函数(带有上下文和不带上下文):

  1. 对于一个自定义的回调函数,它的形式和我们写的普通的函数没有什么不同。需要注意的一点是传入回调函数的参数的个数和顺序需要和追踪源模板的顺序相同

    1. 另外的一点是,若回调函数有“上下文”的需要,上下文参数作为传入的第一个参数

    2. 例如我们追踪WifiNetDevice的phy层状态的变化,在其TypeId中有如下定义:

      .AddTraceSource("State",
                      "The state of the PHY layer",
                      MakeTraceSourceAccessor(&WifiPhyStateHelper::m_stateLogger),
                      "ns3::WifiPhyStateHelper::StateTracedCallback")
                      
      /**
      * The trace source fired when state is changed.
      */
      TracedCallback<Time, Time, WifiPhyState> m_stateLogger;
      
      1. 其模板使用了三个参数,那我们带有上下文的回调函数可以进行如下定义,其中第一个参数为上下文字符串。然后使用makecallback将其转化为回调函数

        void
        WifiStateTrace(std::string context, Time start, Time duration, WifiPhyState state)
        {}
        
        
        std::string context
        wifi_phy_state->TraceConnect("State",
                                    context + std::to_string(phyid),
                                    MakeCallback(&WifiStateTrace));
        
  2. 利用Config模块连接追踪源与回调函数

    bool ConnectWithoutContextFailSafe(std::string path, const ns3::CallbackBase &cb)
    
    1. 这种方法适用于为同一种示例批量批量添加回调函数,使用这种方法时只需要知道目标路径,然后使用MakeCallback方法将一个函数转化为回调函数即可

    2. 可以从ns-3的官方文档中得到一个追踪源的路径,文档中model描述页面的Detailed Description章节中写明了该model通过Config的路径,追踪源的路径为:<model的路径>/<追踪源名称>

      1. 例如我想要追踪所有WifiNetDevice的物理层变化,可以使用下述方式添加一个无上下文字符串的回调函数;这种无上下文的连接方法的弊端是对于某些追踪源,他返回的参数中没有写明自身是谁,这就导致我们只知道“物理层发生了改变”,但是并不知道“谁的物理层发生了改变”;

        Config::ConnectWithoutContextFailSafe(
                "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/*/State/State",
                MakeCallback(&WifiStateTrace));
        
      2. 并不是说Config的方式添加追踪函数就无法添加上下文,Config应该也提供了添加带上下文的回调函数的方案,不过我暂时不太清楚,而且既然Config的特色是可以批量添加,那这个上下文确实能发挥什么作用吗?

  3. 利用模块自带的Connect之类的方法添加回调函数

    1. 这种添加回调函数的方法更精细,也就能精准的为每一个回调函数添加不同的上下文,还是用上面的“追踪物理层的变化”举例,使用该方法添加回调函数:

      /**
      * Connects the trace for the state of each WifiPhy to the given context.
      *
      * @param wifi_dev The WifiNetDevice to connect the trace to.
      * @param context The context string to be appended to the trace name.
      */
      void
      ConnectContextTrace2Mac(Ptr<WifiNetDevice> wifi_dev, std::string context)
      {
          Ptr<WifiMac> wifi_mac = wifi_dev->GetMac();
          int phyid = 0;
          for (Ptr<WifiPhy> wifi_phy : wifi_dev->GetPhys())
          {
              Ptr<WifiPhyStateHelper> wifi_phy_state = wifi_phy->GetState();
              wifi_phy_state->TraceConnect("State",
                                          context + std::to_string(phyid),
                                          MakeCallback(&WifiStateTrace));
              phyid++;
          }
      }
      
    2. 也就是说,这个方法需要逐层拿到我们的追踪源所在的model

Probe

WLAN有两种探测机制:一种为无线终端被动的侦听Beacon帧之后,根据获取的无线网络情况,选择AP建立连接;另外一种为无线终端主动发送Probe request探测周围的无线网络,然后根据获取的Probe Response报文获取周围的无线网络,之后选择AP建立连接。

NS-3在EHT的示例文件中并没有设置对Probe机制开启的选项,不过在mac层中拥有一个开启该探测机制的属性:

.AddAttribute(
                "ActiveProbing",
                "If true, we send probe requests. If false, we don't."
                "NOTE: if more than one STA in your simulation is using active probing, "
                "you should enable it at a different simulation time for each STA, "
                "otherwise all the STAs will start sending probes at the same time resulting in "
                "collisions. "
                "See bug 1060 for more info.",
                BooleanValue(false),
                MakeBooleanAccessor(&StaWifiMac::SetActiveProbing, &StaWifiMac::GetActiveProbing),
                MakeBooleanChecker())

另外还有一个属性和探测属性相关,即仿真开始后多长时间STA节点开始发送Probe Request帧,这个属性和一个随机数生成绑定,因为若所有STA节点同时发送Probe Request帧会导致碰撞。

随机数不是一个适合用于仿真的量,因为我们做仿真的目的就是要完全的掌控所有环境变量。因此我们需要设置随机数的种子来保证每次仿真生成的随机数都是一致的。

有趣的是,NS-3的示例文件中虽然没有对Probe机制是否开启的设定,但是设置了mac层发送Probe Request的延迟的随机数种子,代码如下所示,当然,这段设置种子的代码不仅仅设置了Probe的delay时间随机数

streamNumber += wifiHelper.AssignStreams(apDevice, streamNumber);
streamNumber += wifiHelper.AssignStreams(
        staDevices,
        streamNumber); // 既为不同种类的device分配了不同的随机数种子,又保证了在不同的仿真实验中,随机数种子相同,从而保证了实验的可重复性。

开启该机制后,明明我没有设置发送CTS\RTS的选项,却依然在pcap文件中看到了到了相应的管理帧(CTS),而且没看到RTS帧,至于为什么会出现这种情况,还需要进一步的分析。

通过在实际的WiFi系统中抓包并没有在Probe Request和Probe Response之后路由器发送CTS帧hold住信道不允许其他设备发送数据帧的情况,而是直接就开始Association过程,然后Authentication四次握手。