ns-3手册

Release ns-3.26,ns-3 project, 未严格逐字翻译

ns-3手册

1 介绍

2 资源

3 入门(Getting Started )

本节主要介绍ns-3的安装,包含支持的平台,先决条件,获取ns-3的方式,建 构ns-3的方式以及验证构建出来的ns-3二进制文件和运行简单的程序。

3.1 Overview

ns-3被构建成一组系统软件包,相互之间可以一起工作。用户程序可以通过 链接这些库来使用它们。用户程序一般使用C++或者Python语言编写。

ns-3是以源码的方式发布的,意味着目标系统首先需要具体一个软件工发环境来 编译ns-3,然后才能编译用户程序。ns-3原则上可以为一些系统分布事先编 译好的库,未来也许会以这种方式来发布,但是目前,许多用户通过自己编 辑ns-3本身来生成发布软件,因此拥有源码在旁边去重新编译库是很有用的。 如果有人想承担为一些操作制作pre-built库和包的工作,请联系 ns-developers的邮件列表。

在接下来的部分,我们来看如何使用两种不同的方式来下载和编译ns-3。第 一种方式就是从主站点下载和编译官方发布的源码。第二种方式就是获取和 编译ns-3的开发版拷贝。由于两种方式使用的工具完全不同,我们会分别介 绍这两种方式。

3.2 Downloading ns-3

ns-3系统总体上是一个相当复杂的系统,拥有许多其他的依赖组件。除了你 每天需要处理的系统(如GNU工具链,Mercurial,一个文本编辑器)外,你 需要确保一些额外的库已经安装好,才能进入下一步。ns-3提供了一个wiki 页面,包含了许多有用的提示与技巧。其中有一页是"安装“页面, http://www.nsnam.org/wiki/Installation.

该wiki页面中的"先决条件”部分解释了需要哪些安装包以支持ns-3的通用选 项。同时也提供了不同Linux版本中的命令来安装它们 。Cygwin用户则必须 使用Cygwin installer。

你也许想利用这个机会探索一下ns-3的wiki,因为那确实有大量的信息。

从现在开始,我们将假设读者正工作在Linux或一个类似Linux的环境中,并 且GNU工具链和上面提到的一些先决条件已经安装好。同时,我们也假设你 已经安装好了Mercurial和Waf,并在目标系统中运行。

ns-3代码在Mercurial仓库中,服务器为:http://code.nsnam.org。 你也 可以从 http://www.nsnam.org/release/ 下载一个tarball,或者可以使用 Mercurial从仓库中下载代码。我们建议使用Mercurial。在本部分最后,可 以看到如何获取tarball的指令。

开始使用Mercurial仓库最简单的方式是使用ns-3-allinone环境。这是一组 脚本,用于管理下载和编译ns-3中各自子系统。我们建议你在这个环境中开 始ns-3相关的工作。

一处实践方式是在自己的主目录下创建一个称为 workspace 的目录,在该目 录下,我们可以保存一份本地的 Mercurial 仓库。其他任何目录名称当然也 可以,但接下来我们会假定目录名为 workspace.

3.2.1 Downloading ns-3 Using a Tarball

Tarball是一种软件归档的特殊格式,包含许多文件,且可能被压缩过。 ns-3软件发布是通过一个可下载的tarball。通过tarball下载的过程很简 单;你只需要选择一个发布版本,然后下载它并解压它。

让我们假定,你作为一个用户,想在一个称为 workspace 的本地目录下 编译 ns-3。 如果你接受了 workspace 目录的方法,你可以输入如下命 令来获取一份发布版本的拷贝。

cd
mkdir workspace
cd workspace
wget  http://www.nsnam.org/release/ns-allinone-3.26.tar.bz2
tar xjf ns-allinone-3.26.tar.bz2

如果你切换到目录 ns-allinone-3.26 下,你会看到如下文件和目录。

ls
bake  build.py  constants.py  netanim-3.107  ns-3.26
pybindgen-0.17.0.post57+nga6376f2  README  util.py

你现在就可以编译基本的 ns-3 的发布版本,可以直接跳到编译 ns-3 部 分。

3.2.2 Downloading ns-3 Using Bake

3.3 Building ns-3

3.3.1 Building with build.py

当从一个发布的tarball开始时,第一次编译 ns-3 项目可以使用一个非常 方便的程序来编译,该程序就在 allinone目录下。 该程序称为 build.py。 该程序为你默认配置大部分情况下都适用的选项。但是,如果需要使用更 高级的配置项来使用ns-3源码,则通常需要使用本地的 ns-3 编译系统, Waf,在本手册的后面会介绍到。

如果你使用一个tarball来下载,你应该会有一个目录称为 ns-allinone-3.26 , 它在你的 ~/workspace 目录下。输入如下命令:

: ./build.py --enable-examples --enable-tests

因为在本手册中,我们会使用一些例子和测试用例,而他们默认情况下, 没有被编译,所以上述参数就是告知 build.py 为我们编译。该程序同时 也会默认编译所有能用的模块。之后,你可以编译ns-3,不要例子和测试, 或者去掉一些与你工作无关的一些模块。

当编译脚本编译你下载的不同模块时,你会看到许多典型的编译器输出的 信息。最终你会看到如下输出:

Waf: Leaving directory `/path/to/workspace/ns-allinone-3.26/ns-3.26/build'
'build' finished successfully (6m25.032s)

Modules built:
antenna aodv applications
bridge buildings config-store
core csma csma-layout
dsdv dsr energy
fd-net-device flow-monitor internet
internet-apps lr-wpan lte
mesh mobility mpi
netanim (no Python) network nix-vector-routing
olsr openflow (no Python) point-to-point
point-to-point-layout propagation sixlowpan
spectrum stats tap-bridge
test (no Python) topology-read traffic-control
uan virtual-net-device visualizer
wave wifi wimax

Modules not built (see ns-3 tutorial for explanation):
brite click

没有编译的部分模块,会显示如下信息:

Modules not built (see ns-3 tutorial for explanation):
brite     click

这仅仅说明一些ns-3模块依赖的一些第三方库没有安装,或者编译配置要 求不要编译他们。这并不意味着模拟器没有编译成功或是它会提供错误的 结果 。

3.3.2 Building with bake

3.3.3 Building with Waf

3.4 Testing ns-3

你可以通过使用 ./test.py -c core 脚本来运行单元测试:

./test.py -c core

这些测试通过 Waf 并发运行。 你应该最终会看到一个报告显示如下:

92 of 92 tests passed (92 passed, 0 failed, 0 crashed, 0
valgrind errors)

这是重要的信息。

你同样也可以从Waf中查看总结信息输出,执行每个测试的测试动作脚本,实 际上看起来类似如下: 001.png 002.png

该命令通常被用户运行来快速验证ns-3是否构建正确。

3.5 Running a Script

我们通常在Waf的控制下运行脚本。这允许构建系统确共享库的路径被正确设 置,且这些库在运行时能够被加载到。要运行一个程序,只要在Waf中使用 –run选项即可。让我们通过输入如下命令来运行一个相当Hello World的 ns-3程序:

./waf --run hello-simulator

Waf首先检查确保程序被正确地构建,然后根据需要执行一次构建过程。Waf 然后运行程序,产生如下输出:

Hello Simulator

祝贺你!你现在是一个ns-3用户了!

What do I do if I don’t see the output?

如果你看到Waf的信息显示构建完成成功了,但是并没有看到 "Hello Simulator"输出,有可能是你在 Building with Waf 这一节中将构建模式切 换到 optimized , 但是忘记切换为 debug 模式。在本手册中的所有控 制台输出使用了一个特别的ns-3日志组件,非常用助于将用户消息打开到控 制台上。当你编译优化版的代码,该组件中的输出会自动地被禁掉——它被“优 化”掉了。如果你并没有看到 "Hello Simulator" 输出,请输入如下命令:

./waf configure --build-profile=debug --enable-examples --enable-tests

告知Waf构建ns-3程序的Debug版本,包含例子和测试程序。你仍然必须通过 输入如下命令来构建代码的实际Debug版本:

./waf

现在,如果你运行 hello-simulator 程序,你应该看到预期的输出。

3.5.1 Program Arguments

为了将命令行中的参数传递给ns-3程序,可以使用如下模式:

./waf --run <ns3-program> --command-template="%s <args>"

替换<ns3-program>为你自己的程序名,<args>为参数。 传给Waf –command-template 参数基本上是一个构造实际命令行参数的方 法, Waf会使用该命令行来执行程序。 Waf检查构建是否完成,设置共享库 的路径,然后使用提供的命令行模板来调用可执行程序,为 %s 点位符插入 程序名。

另一个特别有用的例子是自己运行一个测试用例。让我们假设存在一个 mytest 测试用例。 在上面,我们使用 ./test.py 脚本来同时运行一系列 测试, 通过重复地调用真实的测试程序, test-runner. 为某个单独的测 试直接调用 test-runner :

./waf --run test-runner --command-template="%s --suite=mytest --verbose"

这个命令将参数传递给 test-runner 程序中。因为 mytest不存在,所以会 产生一个错误信息。 要打印 test-runner可用的选项,输入如下命令:

./waf --run test-runner --command-template="%s --help"

3.5.2 Debugging

如果想运行ns-3程序在另一个工具控制下,例如一个调试器(例如:gdb)或 内存检查器(例如,valgrind),你可以使用类似 –command-template="…" 的形式。

例如,在gdb调试器下面运行你的ns-3程序 hello-simulator, 参数为 <args> ,命令如下命令:

./waf --run=hello-simulator --command-template="gdb %s --args <args>"

注意, –run 参数紧随着ns-3程序名,控制工具(gdb)为 –command-template参数的每一个标记。 –args 告诉gdb,如下的参数属 于"inferior"程序。(有些gdb不理解 –args特性)。在这种情况下,从 –command-template 中省略程序参数,使用 gdb的 set args命令。

我们可以结合这个方法以及之前的方法在调试器下运行一个测试:

./waf --run test-runner --command-template="gdb %s --args --suite=mytest --verbose"

3.5.3 Working Directory

Waf需要从它所在位置的ns-3树的顶端开始运行。它成为它的工作目录,输 出文件会被写入到工作目录中。如果你想将这些输出放在ns-3源码树之外? 使用 –cwd 参数:

./waf --cwd=...

也许将你的工作目录作为输入文件的目录更方便,这种情况下,使用如脚本 会更方便:

function waff {
    CWD="$PWD"
    cd $NS3DIR >/dev/null
    ./waf --cwd="$CWD" $*
    cd - >/dev/null
}

4 Conceptual Overview

本部分介绍一些基本的概念,方便之后阅读代码或者编写ns-3程序。

4.1 Key Abstractions

在本节中,我们会审查一些网络中常用的一些术语,但是在ns-3中有着特殊 的意义。

4.1.1 Node

在因特网行语中,连接一个网络的计算设备称为 主机 , 有时也称为 终 端系统 。 由于ns-3是一个网络模拟器,而不是一个特别的因特网模拟器, 所以我们有意地不使用主机这个术语,因为这个术语与因特网及相关的协议 紧密相关。 相反地,我们使用一个更通用的术语,同时也被其他的模拟器 使用,发源于图论中的术语 —— 结点

在ns-3中,基本的计算设备抽象称为结点。该抽象是用C++的类 Node 表示。 Node类提供了一系列方法用于管理模拟场景中的计算设备。

你应该将一个 Node想象成一台计算机,你可以向这台计算机添加功能。 比 如你可以添加类似应用程序,协议栈和外围网卡之类的东西及相关驱动,使 得这台计算机能够做一些有用的工作。在ns-3中,我们使用类似的基本模型。

4.1.2 Application

通常情况下,计算机软件被划分为两个比较大的类别。 系统软件 根据一 些计算模型来组织各种各样的计算资源,例如内存,处理器周期,磁盘,网 络等。系统软件通常并不使用这些资源来完成一些能够直接有利于某个用户 的任务。 一个用户通常会运行一个应用程序,这个应用程序使用由系统软 件控制的资源来完成一些目标。

通常,系统软件与应用软件之间的边界线是在操作系统陷阱的特权级别上做 出的。在ns-3中,没有真实的操作系统概念,特别是没有特权级别或系统调 用的概念。但是,我们确实有应用程序的概念。就像在“真实世界”中执行各 种任务的软件应用程序一样,ns-3应用程序运行在 ns-3 的Nodes上以驱动 模拟世界中的模拟任务。

在 ns-3中,应用程序是一个产生一些被模拟的活动的一个用户程序的基本 抽象。该抽象是由C++中的类 Application来表示的。 Application类提供 了一系列方法来管理模拟世界中的用户层的应用程序。 开发者会在面向对 象编程中,特化Application类来创建新的应用程序。在本手册中,我们会 使用类Application的特化类UdpEchoClientApplication以及 UdpEchoServerApplication。 正如你所想的那样,这些应用程序构建了g 个客户端/服务器应用程序集合用来产生和响应模拟的网络数据包。

4.1.3 Channel

在真实世界中,可以将一台计算机连接到一个网络中。通常,在这些网络中, 数据流动时通过的媒介称为 信道 。 当你将Ethernet线缆插入墙上的插 孔中,你就将你的计算机接入到了一个Ethernet的通信信道。 在ns-3模拟 的世界中,你可以将一个Node连接到一个代表信道的对象中。这里,基本的 通信子网抽象称之为信道,在C++中由类Channel来表示。

Channel类提供了一些方法来管理通信的子网对象以及连接结点到信道上。 Channels也可以按照面向对象编程的理念被特化(派生)。 一个Channel的 特化可以模拟任何对象,甚至是最简单的一根线缆。特化的Channel类也可 以模拟复杂的对象,如一个大型的Ethernet交换机,或是无线网络中,在三 维方向上充满阻碍。

我们会使用特化的Channel版本,称为CsmaChannel, PointToPointChannel 以及WifiChannel。 例如,CsmaChannel模拟了一个实现了载波侦听多路访 问通信媒介的一个通信子网。它给我们提供了像以太网的功能。

4.1.4 Net Device

在过去,通常情况下,如果你想连接一台计算机到一个网络上,你不得不购 买一个特别的网线和一个称之为外部设备卡的硬件设备,这个硬件设备需要 安装到你的计算机中。如果外设卡实现了一些网络功能,它们就被称为网卡。 如今,大部分计算机都内置了一个网络卡。

一个网卡必须需要一个控制硬件的软件驱动才能工作。 在Unix(或Linux) 中,一些外围硬件归类为一个设备。设备是通过设备驱动来控制的。使用网 络设备驱动控制的网络设备总体上称为 net设备。 在Unix和Linux中,你可 以通过 eth0 来指代这些网络设备。

在ns-3中, net设备抽象包含软件驱动和模拟的硬件。一个net设备要安装 在一个Node中,才能使用Node,通过Channels与模拟环境中的其他Nodes进 行通信。如同在一个真实的计算机中,一个Node可以通过多个NetDevices连 接到多个Channel中。

net设备抽象在C++中使用类eNetDevice表示。NetDevice提供了管理Node与 Channel对象连接的方法。开发者也可以利用面向对象编程的思想来特化它。 我们将会使用几个特化的NetDevice版本称为: CsmaNetDevice, PointToPointNetDevice, 以及WifiNetDevice。 如同一个以太网卡设计来 与一个以太网之间进行工作,CsmaNetDevice设计用于一个CsmaChannel, PointToPointNetDevice设计用于一个PointToPointChannel。 一个 WifiNetDevice设计用于一个WifiChannel。

4.1.5 Topology Helpers

在真实网络中,你会找到添加了(内建了)网卡的计算机。在ns-3中,我们 会说你会找到挂载了NetDevices的Nodes。 在大型模拟网络中,你会需要安 排Nodes,NetDevices以及Channels之间的许多连接。

既然连接NetDevices与Nodes,NetDevices与Channels,分配IP地址等操作 在ns-3中是一件很频繁的任务,我们提供了称之为拓扑助手来使这些任务尽 量简单。例如,它可能会花费许多不同的ns-3核心操作来创建一个 NetDevice,添加一个MAC地址,在一个Node上安装net设备,配置结点的协 议栈,然后将NetDevices与一个Channel之间进行连接等。甚至需要更多的 操作来将多个设备连接到多点信道上,然后将这些单个的网络一起连接成一 个互联网。我们提供了拓扑助手对象来将这些许多特别的操作整合成一个简 单使用的模型以方便您的使用。

4.2 A First ns-3 Script

当我们如前面所述的那样下载了系统后,你会在主目录下拥有一份称为repos 的目录,在该目录下会有一份ns-3的发布版本。进入到发布版本的目录下, 你会找下一个类似如下一样的目录结构: 003.png

进入到 examples/tutorial 目录下,你会看到一个名为 first.cc 的文件。 这是一个创建一个简单的点到点网络的脚本,在两个结点之间创建一个点到 点的链路,并在结点之间响应单个数据包。让我们先一行行地看这个脚本, 继续用你喜爱的编辑器打开first.cc文件吧。

4.2.1 Boilerplate

文件中的第一行是emacs模式行。它告诉emacs有关格式规范相关(编码风 格)的信息。

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */

这通常是一个充满争议的主题, 因此我们会马上路过这个主题。在ns-3项 目中,像大部分大型项目,已经采用了一种编码风格,所有的贡献者都必须 遵守。如果你想贡献你的代码到该项目中,你最终必须与文件 doc/codingstd.txt描述的编码风格保持一致。

我们建议你,适用ns-3代码的风格,并任何时候接受这个标准来修改代码。 所有这些开发团队与贡献者都必须这样做。如果你使用emacs编辑器的话, emacs 模型行会使遵守编码风格这件事变得更容易。

ns-3模拟器是用于GNU GPL来声明版本。你会在每个ns-3中的源码的头部看 到如下声明。通常,你会看到如下样式的版权声明:

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

4.2.2 Module Includes

通常代码中包含如下一些声明:

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"

为了方便高级脚本用户处理大量的头文件包含,我们根据相对大点的模块来 将头文件进行分组。我们提供了一个单个包含文件,能递归地加载用于每个 模块中的所有包含文件。这样,我们就给了用户在一个相对大的粒度上加载 一组头文件的能力。这不是最有效率的方法,但通常会使用编写脚本更容易 些。

在编译的过程中,每个ns-3的头文件放在一个称为ns3(在build目录下)的 文件下,避免包含文件之间的名称冲突。 ns3/core-module.h文件对应与 ns-3模块中的core, 代码位于src/core目录下。 在该目录下,你会找到大 量的头文件。当你执行一次build,Waf会将公共头文件放置到build/debug 或build/optimized目录下的ns目录下。 Waf也会自动地产生一个模块包含 文件去加载所有的公共头文件。

之前,我们已经执行了如下命令:

./waf -d debug --enable-examples --enable-tests configure

为了配置项目执行debug build,包含examples和tests,你也会需要执行如 下命令:

./waf

来构建项目。如果你查看目录 ../../build/debug/ns3 ,你会找到上面显 示的4个模块包含文件。你可以看下这些文件的内容,并发现它们确实在对 应的模块中包含了许多公共头文件。

4.2.3 Ns3 Namespace

first.cc脚本中的下一行是一个命名空间的声明。

using namespace ns3;

ns-3项目是实现在C++中的命名空间ns3中。这会将所有ns-3相关的声音组合 到一个全局命名空间之外的一个范围,我们希望有助于与其他代码进行整合。

4.2.4 Logging

脚本的下一行如下:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

我们使用这句话,作为一个方便的地方来与我们的Doxygen文件系统进行交 互。

这行声明了一个日志组件称为FirstScriptExample. 它允许根据名称你使能或禁用控 制台打印信息。

4.2.5 Main Function

脚本的下一行如下:

int
main (int argc, char *argv[])
{

main函数。

下一行设置时间分辨率到一个纳秒,也恰好是默认值:

Time::SetResolution (Time::NS);

分辨率是能表示的最小的时间值。你只能修改一次时间分辨率。一旦显式地 设置了分辨率,我们就会释放内存,阻止进一步的更新。(如果你没有显式 地设置分辨率,它会默认为一个纳秒,当模拟开始的时候会释放内存。)

下面两行脚本用于使能两个日志组件,它被编译到Echo Client和Echco Server应用程序中:

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);

Logging有不同的打印级别,上述代码设置的是INFO级别。

现在我们会直接进入创建一个拓扑的业务逻辑以及运行一个模拟。我们使用 拓扑助手对象来使这个工作更容易。

4.2.6 Topology Helpers

NodeContainer

下面两行实际上是创建了两个ns-3 Node对象,代表模拟环境中的计算机。

NodeContainer nodes;
nodes.Create (2);

Node代表一台计算机,而NodeContainer拓扑助手提供了一种方便的方法创 建,管理和访问任何我们创建的Node对象来运行一次模拟。

PointToPointHelper

我们要创建一个点到点的链路,这种模式我们会很快熟悉。 我们使用了一 个拓扑助手对象来执行所需的底层工作来将链路整合在一起。 PointToPointHelper会配置和连接ns-3 PointToPointNetDevice和 PointToPointChannel对象。

下面三行代码就是做的这些事情:

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

上述代码分别设置了传递速率以及信道的传输延迟。

NetDeviceContainer

在这个点上,我们已经拥有了一个 NodeContainer,它包含两个节点。 下 面要使用PointToPointHelper来创建PointToPointNetDevices并用 PointToPointChannel对象将这些对象连接起来。我们使用 PointToPointHelper来执行包含创建,配置和安装设备的工作。

NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);

上述两行代码会完成配置设备和信道。

当执行了pointToPoint.Install(nodes)后,我们将拥有两个节点,每个都 安装了一个点到点的网络设备以及一个点到点的信道。两个网络设置都配置 为以5M/s的速度传递数据,通过的信道媒介上的延时为2毫秒。

5 Tweaking

6 Building Topologies

7 Tracing

8 Data Collection

9 Conclusion