本例程将仿真一个简单的包交换网络,它包括四个周边节点和一个中心节点,周边节点用来产生业务,而中心节点将这些业务转交给相应的目的节点(周边节点中的一个),网络拓扑结构如下图所示。
上面的拓扑结构包含两种类型节点模型,即周边节点和中心交换节点。本例程的目的是仿真一个周边节点发出的业务能够通过中心交换节点路由至另一个目的周边节点。从中心交换节点中看,假设包是以随机的方式来自四个周边节点,每个包包含目的地址,目的地址可以用一个整数来表示不同的目的周边节点,中心节点接收到包后通过对目的地址的解析最后选择一个合适的发信机将包送往目的地。
网络的物理通信机制如下图所示。
每个节点至少包含一对点对点收发机,并且通过一条有线双工链路和另一对点对点收发机构成一个收发机组。每个这样的收发机组可以支持数据的双向传输,在中心交换节点中,配置了四对点对点收发机,从而在物理上能够支持与四个周边节点互联互通。
中心交换节点在OPNET中的节点模型如下图所示。
中心交换节点如何实现寻址和包交换呢?每个有向包流(以某个进程模型为参考,某个包流进入该进程或者离开该进程,因此称之为有向包流)有一个唯一的索引号,这个索引号总是和某个收信机(对应进入包流)或者某个发信机(对应离开包流)唯一对应,而收信机和发信机又和某个周边节点唯一对应,因此可以直接用流索引号作为交换包的依据。当然为了增强网络的稳健性,我们也可以建立一个目的地址和流索引(可以看作是物理地址)的映射表。为了简单起见,本例程将采用前一种方法实现寻址和包交换。
周边节点在OPNET中的节点模型如下图所示。
周边节点作为网络的业务源,其产生包,然后为每个包分配一个目的地址并且通过点对点发信机传输出去。周边节点同时也作为网络的业务终端,周边节点接收包并且统计其端对端延时。
OPNET Modeler 的精髓之一就是层次化建模的思想,在构建本网络时,将采用如下的层次化建模的步骤:定义包格式——>定义链路模型——>创建中心交换节点模型——>创建周边节点模型——>建立网络模型——>配置并仿真。
创建一个新的包格式,打开包格式编辑器,按照下图设置包域的属性。
设置完成后命名这个包格式并保存,关闭当前的编辑器。
接下来创建一个新的链路模型,打开链路模型编辑器,支持的链路类型按照下图进行设置。
支持的链路类型选择 ptdup,表示该链路只支持点对点双工连接。
各项属性值的设置如下图所示,包格式选择前面自己创建的那个。
ecc model是错误纠错模式,这里选择ecc_zero_err,即取消链路的纠错功能;error model是链路的干扰模式,这里选择error_zero_err,即链路无干扰;prodel model是传播延时计算模式,这里选择dpt_prodel,即计算点对点传播延时;txdel model是传输延时计算模式,这里选择dpt_txdel,即计算点对点传输延时。
这里还要申明一下外部函数link_delay,对于OPNET9.0以上的版本,如果不申明该外部函数的话,在编译dpt_prodel时会因为找不到该函数而出现错误。
在File——>Declared External Files下找打外部函数link_delay,在其前面打勾即可,如下图所示。
点击OK,然后保存该链路模型。
前面已经提到,中心交换节点包含四对发信机和收信机,一个中心交换处理进程,该进程用来按地址转交包。
首先创建一个节点模型,按照下图所示放置并命名各个对象。
在hub进程模块上右键选择显示连接即可查看各包流与hub的连接情况。
接下来需要定义收发信机的模型属性,按住Shift键,依次以鼠标左键单击所有的收发信机,注意不要选中包流线。选中后,在其中的一个收信机或发信机模块上单击鼠标右键,编辑其属性。
按照下图的标注依次设置数据速率为9600(与前面链路模型的设置保持一致),包格式选择前面新建的那一个,点击OK按钮即可,如下图所示。
在编辑完其中一个的属性之后,在Apply to selected objects前面打勾,将前面选中的8个收发信机都设置成这样,点击OK按钮。
接下来定义节点模型的界面属性,在Interfaces菜单中选择Node Interfaces,将该节点设置为固定节点,如下图所示进行设置。
然后保存该中心交换节点模型。
接下来为中心交换节点创建进程模型。
新建一个进程模型,打开进程编辑器,按照下图创建状态和转移线,并编辑转移线的条件设定,executive属性设置为route_pk()。
定义宏的代码如下。
#define PK_ARRVL (op_intrpt_type () == OPC_INTRPT_STRM)
PK_ARRVL条件判断 hub 进程接收的中断类型是否时流中端,在OPNET中以常量OPC_INTRPT_STRM表示流中端,如果进程异常的接收到其他类型的中断则状态会因为找不到转移条件而出错,因此为idle状态创建了一个指向自身的default的转移线,即其他条件不满足则该条件满足。
点击工具栏的函数块按钮,在其中键入下面的代码并保存。
static void route_pk(void)
{
int dest_address;
Packet* pkptr;
FIN(route_pk()); //函数开始
pkptr = op_pk_get (op_intrpt_strm ()); //从合适的输入流中取得包
op_pk_nfd_get (pkptr, "dest_address", &dest_address); //析取包中的目的域,目的地址就是输出流索引
op_pk_send (pkptr, dest_address); //将包发送给相应的收信机
FOUT; //函数结束
}
在编写函数时必须使用FIN(function begin)、FOUT(function out)、FRET(function return)等界定函数范围的标识符,而且必须使它们配对。
接下来更改进程属性,在Interfaces菜单中选择 Process Interfaces,按照下图设置属性值。
点击OK,保存该进程模型然后编译该进程,编译成功如下图所示。
下面需要把该进程模块指定给中心交换节点模型,在节点模型中的 hub 进程上右键编辑属性,将上面创建的进程模型指配给 hub 进程,如下图所示。
以上工作完成后保存该节点模型。
当周边节点生成一个包时,它必须给这个包指定一个目的地址,然后将它发往中心节点。如果周边节点接收到一个包时,它必须计算该包的端对端延时。 因此周边节点必须包括一个业务生成模块、一个进程模块和一对点对点收发信机来完成这些任务。
周边节点模型按照下图所示放置并命名各个对象。
src模块的属性设置如下图所示。
接下来,需要改变收发信机的信道速率和支持的包格式,以匹配指定的链路模型。
按住Shift键,在周边节点模型中单击收信机和发信机,编辑其属性,过程与中心节点模型的类似,如下图所示。
在Interfaces菜单中选择Node Interfaces,将该节点设置为固定节点,如下图所示进行设置。
也可以对一些属性进行重命名操作,属性重命名可以简化复杂属性名称,或者扩展过于简化的名称,总之就是可以帮我们更好的理解该属性的作用或功能。
属性重命名的过程如下图所示。
此外,我们还可以指定一系列预定值给某个属性,这样属性的设置可以通过界面来选择,这将给用户提供方便。
为属性指定预定值有这样几个好处:限制属性取值的范围;用户可以直观地根据预定值的名称来选择相应的参数;用户不需要输入具体值,从下拉列表中选择即可。
下面为刚才更名的 source interarrival time 属性指定一些预定值,Symbol的Status变为suppress,添加四个预定值,如下图所示。
周边节点的许多属性与仿真无关,这里隐藏其他的属性,如下图所示。
设置完成后保存该周边节点模型。
周边节点进程模块的功能是:为包分配目的地址并且发送出去;计算包的端对端延时。
创建一个新的进程模型,打开进程编辑器,按照下图创建状态和转移线,并编辑转移线的条件设定。
在init状态中,进程模型将加载一个从0-3的均匀分布概率函数。
xmt()转移执行函数产生将调用概率函数随即产生目的地址,并将其分配给来自业务生成模块的包,然后再将它发送出去。rcv()转移执行函数作用是在接收到包时计算其端对端延时,并且将结果写入全局统计量。
该进程模型中,定义宏的代码如下。
/* 定义包流 */
#define RCV_IN_STRM 0
#define SRC_IN_STRM 1
#define XMT_OUT_STRM 0
/* 条件宏定义 */
#define SRC_ARRVL (op_intrpt_type () == OPC_INTRPT_STRM && op_intrpt_strm () == SRC_IN_STRM)
#define RCV_ARRVL (op_intrpt_type () == OPC_INTRPT_STRM && op_intrpt_strm () == RCV_IN_STRM)
RCV_IN_STRM 和 SRC_IN_STRM 对应数据包的输入流索引号,而 XMT_OUT_STRM 为输出流索引号,输入输出都是相对当前进程模块(proc)而言的,它们对应与proc模块相连的某条包流,连接关系一旦确定,它们的索引号是常数。
点击工具栏的SV按钮定义状态变量,在对话框中输入下面的内容。
下面创建一个全局统计探针收集包的端对端延时的结果。
在进程模块中的 Interfaces——>Global Statistics 下按照下图所示声明一个全局统计量。
init 状态的入口执行代码如下。
address_dist = op_dist_load ("uniform_int", 0, 3);
ete_gsh = op_stat_reg ("ETE Delay", OPC_STAT_INDEX_NONE, OPC_STAT_GLOBAL);
点击工具栏FB按钮打开函数块编辑器,在其中键入下面的代码。
static void xmt (void)
{
Packet* pkptr;
FIN (xmt());
pkptr = op_pk_get (SRC_IN_STRM); //从包流的输入流索引号获取数据包
op_pk_nfd_set_int32 (pkptr, "dest_address", (int)op_dist_outcome (address_dist));
//通过调用均匀概率分布函数指针(address_dist,在上面的init状态下定义),产生一个随机值,并将该值设置为包的"dest_address"域
op_pk_send (pkptr, XMT_OUT_STRM); //从包流的输出流索引号将包发送出去
FOUT;
}
static void rcv (void)
{
Packet* pkptr;
double ete_delay;
FIN (rcv());
pkptr = op_pk_get (RCV_IN_STRM); //获取包指针
ete_delay = op_sim_time() - op_pk_creation_time_get (pkptr); //当前仿真时间减去包的创建时间得到包的端对端延时
op_stat_write (ete_gsh, ete_delay); //将计算的延时写入矢量结果文件中
op_pk_destroy (pkptr); //销毁包
FOUT;
}
xmt()转移执行函数当SRC_ARRVL条件满足时(即包从业务生成模块到达proc模块)才执行,该函数在将包发送之前要为它分配一个目的地址。
rcv()转移执行函数当RCV_ARRVL条件满足时(即包从收信机到达proc模块)时执行,主要目的是计算端对端延时并写入全局统计探针。
按照下图设置进程界面的属性值。
保存该进程模型,回到周边节点模型编辑下,右键proc模块并为其指定刚才创建完成的周边节点的进程模块,如下图所示。
前面已经建好了包模型、链路模型、中心交换节点模型、中心交换节点的进程模型、周边节点模型和周边节点的进程模型,接下来就是构建网络模型了。
File——>New——>Project 新建网络模型,首先在按照 Topology——>Subnets——>Create Fixed Subnets… 在项目编辑窗口中放置一个subnet的模型并给其命名,如下图所示。
双击这个子网模块进入它的内部,打开对象面板,搜索前面自己创建的中心交换节点模块和周边节点模块,按照下图依次放置节点模块。
搜索前面自己前面新建的链路模型,找到后依次把周边节点 0,1,2,3 和中心交换节点 hub 相连(按照顺序连接),如下图所示。
连接完成后需要先验证链路的连接是否正确,点击 Topology——>Verify Links,或者直接用 Ctrl+L 快捷键调出链路检查窗口,选择 Verify links,点击 OK 验证,如果线路上有叉,就说明链路不通,连接有问题,如下图所示。
这个时候就要检查是自己做的过程中哪步出错了,我就是没有给节点模型指配相应的进程模型,从而在验证链路的连接性时出现了错误。
接下来收集统计量,在工程窗口的空白处右键选择Choose Individual DES Statistics,勾选全局统计量ETE Delay,如下图所示。
在 node_0 和 hub 间的链路上右键,选择Choose Individual DES Statistics,按照下图勾选的选择上行和下行链路的利用率。
保存项目文件。
在这个例程中,包的大小和收发信机的速率都是恒定的,因此期望端对端延时也应该固定不变。然而,如果包的产生速率足够快,就会导致部分包在发信机队列中堆积,这时包的端对端延时加大。如果包的产生速率不定,有可能造成业务突发,因此端对端延时也会受影响。为了模拟这些行为,需要配置 source interarrival time 仿真属性,下面将给它指定两个值。
在菜单栏的 DES——>Configure/Run Discrete Event Simulation (Advanced) 下配置仿真,打开窗口按下图所示配置仿真参数。
给 source interarrival time 属性赋值为4,这里的数值选择就是在前面创建周边节点模型时预设的四个值,即4,8,40,80。
复制这个仿真序列,并在该窗口下粘贴,将这个新粘贴的仿真序列 source interarrival time 属性赋值为40,其他的参数保持不变,如下图所示。
保存这两个配置的仿真序列,接下来就运行仿真,点击下图中仿真按钮,仿真完成会出现下面的窗口,说明仿真过程没有出错。
点击 View Results 按钮查看结果,先以 time_average 显示模式看上行链路的利用率,如下图所示。
下行链路的利用率如下图所示。
可以看出由于包的产生速率过小导致链路利用率很低。
下面查看全局统计量 ETE Delay 的情况,仿真序列1的结果如下图所示。
以离散的方式绘制仿真序列1的结果如下。
仿真序列2的结果如下。
以离散的方式绘制仿真序列2的结果如下。
通过对比发现仿真序列2的延迟相对仿真序列1来说好一点。
以上就是 OPNET Modeler 实例——创建一个包交换网络的所有内容了,希望本文对你学习 OPNET Modeler 软件有一定的帮助!
本文参考书目:OPNET 网络仿真/陈敏编著. - 北京:清华大学出版社,2004