本文介绍示例文件(即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个节点):
选择缓存替换策略
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::Lru
、ns3::ndn::cs::Fifo
、ns3::ndn::cs::Lfu
、ns3::ndn::cs::Random
和ns3::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));
···