ndnSIM仿真平台使用之示例文件结构介绍

 

本文介绍示例文件(即example内文件)的结构,包括定义拓扑、选择缓存替换策略、选择转发策略、安装用户Consumer与服务器Producer等,自定义的示例文件可参考于此进行编写。

此外,NDN官网上提供了很多示例文件的介绍https://ndnsim.net/2.1/examples.html,强烈建议对其进行完整阅读,本文仅综合这些示例文件(/ndnSIM/examples)作出通用性的总结。

版本信息如下:

操作系统:Ubuntu 16.04
ndnSIM:ndnSIM-2.1
ns-3-dev:ns-3.23-dev-ndnSIM-2.1

定义拓扑

示例文件内直接定义

此种方式适合于简单拓扑,用来检验实验代码的运行效果、自定义的策略是否正确实现等。

1. 定义链路

一般在示例文件开头对示例中拓扑链路信息进行说明,包括传输速率、链路延时、链路最大传输包数等,可以看出用此种方式生成的拓扑中,所有链路的基本信息均一致,无法分别定义。

Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps")); // 传输速率
Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms")); // 链路延时
Config::SetDefault("ns3::DropTailQueue::MaxPackets", StringValue("20")); // 链路最大传输包数

2. 定义节点

首先创建一定数量的节点,然后根据拓扑形状将每个节点连接起来即可。

// Creating nodes
NodeContainer nodes;
nodes.Create(4);

// Connecting nodes using two links
PointToPointHelper p2p;
p2p.Install(nodes.Get(0), nodes.Get(1));
p2p.Install(nodes.Get(1), nodes.Get(2));
p2p.Install(nodes.Get(2), nodes.Get(3));

示例文件外生成与导入

一般进行仿真实验时需要用到较大规模的网络拓扑,如果在示例文件中直接定义,那么代码量会非常巨大。幸运的是ndnSIM支持从外部导入拓扑文件,我们仅需通过拓扑生成器创建拓扑文档,然后在示例文件中引入即可。

1. 拓扑文件格式

标准的拓扑文件包括路由节点router与链路link两部分,格式如下:

router
# node  comment     yPos    xPos
Src1   NA        1       3
Src2   NA        3       3
Rtr1   NA        2       5
Rtr2   NA        2       7
Dst1   NA        1       9
Dst2   NA        3       9

link
# srcNode   dstNode     bandwidth   metric  delay   queue
Src1        Rtr1        10Mbps      1        10ms    20
Src2        Rtr1        10Mbps      1        10ms    20
Rtr1        Rtr2        1Mbps       1        10ms    20
Dst1        Rtr2        10Mbps      1        10ms    20
Dst2        Rtr2        10Mbps      1        10ms    20

在router部分中,需要分别定义节点名称、介绍、y坐标和x坐标,其中后两个坐标是为了便于在可视化程序中显示,不影响实验结果,所以如果拓扑过大或者不需要使用可视化程序,这两个坐标可不用定义。

在link部分中,需要分别定义链路两端的节点、链路带宽、链路度量(用于路由选择,一般值为1)、链路延时和链路最大传输包数。

以上信息为通用信息,基本满足绝大部分的仿真实验需要,其他特定信息可参考源码示例中提供的拓扑文件。

2. 拓扑文件生成

这部分可参照ndnSIM仿真平台使用之拓扑生成器Brite介绍

3. 拓扑文件导入

通过拓扑生成器与拓扑文件格式转换,我们可以得到适用于ndnSIM的拓扑文件,以test.txt为例,将其复制到topologies目录中,然后在示例文件中读取:

AnnotatedTopologyReader topologyReader("", 25);
topologyReader.SetFileName("src/ndnSIM/examples/topologies/test.txt");
topologyReader.Read();

通过可视化程序可以看到该拓扑结构(500个节点):

image

选择缓存替换策略

2.1版本的ndnSIM提供新旧两种Content Store实现:一种只包括FIFO策略,仅能设置缓存大小;另一种是1.0版本中的CS实现,可选缓存策略较多,详细介绍请参考官网Content Store

新版CS使用

ndn::StackHelper ndnHelper;
ndnHelper.setCsSize(<max-size-in-packets>); // 例:ndnHelper.setCsSize(100);
ndnHelper.InstallAll(); // 或使用ndnHelper.Install(nodes);可以安装到指定nodes上

旧版CS使用

ndn::StackHelper ndnHelper;
ndnHelper.SetOldContentStore("<content store implementation>",
                            ["<optional parameter>", 
                             "<optional parameter's value>" [, ...]]);
// 例:ndnHelper.SetOldContentStore("ns3::ndn::cs::Lru", "MaxSize", "100");
ndnHelper.InstallAll();

其中<content store implementation>有很多类型,基本类型包括:ns3::ndn::cs::Lruns3::ndn::cs::Fifons3::ndn::cs::Lfuns3::ndn::cs::Randomns3::ndn::cs::Nocache。此外,官网还提供扩展类型,以LRU为例,包括:可以记录副本在缓存中驻留时间的ns3::ndn::cs::Stats::Lru、可以设置副本过期时间的ns3::ndn::cs::Freshness::Lru、可以按概率缓存副本ns3::ndn::cs::Probability::Lru

  • 使用Stats时的规范:
void
CacheEntryRemoved(std::string context, Ptr<const ndn::cs::Entry> entry, Time lifetime){
    std::cout << entry->GetName() << " " << lifetime.ToDouble(Time::S) << "s" << std::endl;
}
...
ndnHelper.SetOldContentStore("ns3::ndn::cs::Stats::Lru", "MaxSize", "100");
...
ndnHelper.Install(nodes);
// connect to lifetime trace
Config::Connect("/NodeList/*/$ns3::ndn::cs::Stats::Lru/WillRemoveEntry", 		  MakeCallback(CacheEntryRemoved));
  • 使用Freshness时的规范:
ndnHelper.SetOldContentStore("ns3::ndn::cs::Freshness::Lru", "MaxSize", "100"); 
···
// 在producer中设置Freshness的值
producerHelper.SetAttribute("Freshness", TimeValue(Seconds(2.0))); 
  • 使用Probability时的规范:
ndnHelper.SetOldContentStore("ns3::ndn::cs::Probability::Lru", "MaxSize", "100", "CacheProbability", DoubleValue(p)); // p的取值范围[0,1]

选择路由策略

配置路由是为了告知节点该如何路由兴趣包,ndnSIM提供默认、手动和自动三种方式来配置路由,由于手动方式不常用,在此仅介绍默认和自动两种方式。

默认配置

默认配置是在选择CS时同时设置路由。(官网并不推荐这种方式)

ndn::StackHelper ndnHelper;
ndnHelper.SetDefaultRoutes(true);
ndnHelper.InstallAll();

自动配置

ndnSIM提供自动配置“最短路径”的路由策略,一共分为三步(这里主要参考官网https://ndnsim.net/2.1/helpers.html):

1. 在所有节点上安装全局路由方法

NodeContainer nodes;
...
GlobalRoutingHelper ndnGlobalRoutingHelper;
ndnGlobalRoutingHelper.Install(nodes); // 也可使用ndnGlobalRoutingHelper.InstallAll(); 

2. 设置路由目的地

Ptr<Node> producer; // producer node that exports prefix
std::string prefix; // exported prefix
...
ndnGlobalRoutingHelper.AddOrigins(prefix, producer);

3. 计算路径并在所有节点上安装FIB表

GlobalRoutingHelper::CalculateRoutes();

选择转发策略

ndnSIM提供两种转发策略(源码中还有另外三种,但是官网未提及,ndnSIM/NFD/daemon/fw):BestRouteStrategy与MulticastStrategy,使用方式如下:

StrategyChoiceHelper::InstallAll(prefix, /localhost/nfd/strategy/best-route);

StrategyChoiceHelper::InstallAll(prefix, /localhost/nfd/strategy/multicast);

在规模比较大的网络拓扑中,推荐使用BestRouteStrategy。

安装AppHelper(Consumer与Producer)

用户Consumer

ndnSIM提供多种类型的用户类,可以按不同的规律产生兴趣包,详细可参照ndnSIM仿真平台使用之用户Consumer类,这里仅介绍如何在示例文件中安装。

ConsumerCbr为例,这个用户类可以按固定频率发出不重复的兴趣包:

ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
// Consumer will request /prefix/0, /prefix/1, ...
consumerHelper.SetPrefix("/prefix"); // 设置内容名称前缀
consumerHelper.SetAttribute("Frequency", StringValue("10")); // 每秒发送10个兴趣包
consumerHelper.Install(nodes);  // 在指定节点上安装用户,也可使用InstallAll()在所有节点上安装用户

服务器Producer

同样,详细的Producer类介绍可参照ndnSIM仿真平台使用之服务器Producer类

Producer用以响应特定前缀的兴趣包并返回数据包,注意一个Producer只能响应一种前缀:

ndn::AppHelper producerHelper("ns3::ndn::Producer");
producerHelper.SetPrefix("/prefix"); // 设置响应前缀
producerHelper.SetAttribute("PayloadSize", StringValue("1024")); // 设置数据包大小
producerHelper.Install(nodes); // 在指定节点上安装服务器

Consumer与Producer更多的参数设置SetAttribute()将在上述两个文档中详细介绍。

运行

这一部分比较简单,代码如下:

Simulator::Stop(Seconds(20.0)); // 设置仿真时长

// 仿真输出程序在此设置,详见“ndnSIM仿真平台使用之仿真数据获取与处理”
ndn::CsTracer::InstallAll("cs-trace.txt", Seconds(1.0)); // 缓存命中率
ndn::L3RateTracer::InstallAll("rate-trace.txt", Seconds(1.0)); // 节点流量

Simulator::Run();
Simulator::Destroy();

此外,如果需要使用链路断开的场景,则相关代码在Simulator::Stop(Seconds(20.0));之前设置,比如10秒时断开链路,15秒时连通链路:

Simulator::Schedule(Seconds(10.0), ndn::LinkControlHelper::FailLink, node0, node1);
Simulator::Schedule(Seconds(15.0), ndn::LinkControlHelper::UpLink, node0, node1);
Simulator::Stop(Seconds(20.0)); 
···