OPNET学习笔记之eth_mac_intf模块(ethcoax_station_adv节点模型)
前面已经描述了ethcoax_station_adv节点模型的基本结构,其中burstry_gen模块产生无格式包,发送给eth_mac_intf模块处理,本文分析其处理过程。
首先注意该模块上的包流:
stream : eth_mac_intf [0] -> sink [1]
stream : eth_mac_intf [1] -> mac [1]
stream : bursty_gen [0] -> eth_mac_intf [1]
stream : mac [1] -> eth_mac_intf [0]
该模块的进程模型为ethernet_mac_interface,状态机如下:
该模块没有local/global statistic,但是有两个attribute,分别为high dest address和low dest address,表示dest address的最大值和最小值。状态机中只有两个强制状态,其它为非强制状态。
一,init状态的入口代码:
eth_mac_higher_layer_intf_init (); //调用该函数初始化,包括初始化状态变量 和注册进程
intf_mac_req_iciptr = op_ici_create ("mac_request"); //创建一个ICI结构体,以便与MAC层通信,注意返回值类型为Ici*,而"mac_request"是预定义好的结构体(在哪里定义???)(syntax:op_ici_create(fmt_name);)
op_ici_install (intf_mac_req_iciptr); //绑定????,这个ICI被自动绑定到被唤醒进程向外发送的中断,注意ICI指针可以由op_ici_create()和op_intrpt_ici()返回,其中前者返回一个新创建的ICI(在ICI发送进程),后者返回一个与即将到来的中断关联的ICI(在ICI接收进程)。
op_intrpt_schedule_self (op_sim_time (), 0); //自中断,时间为当前时间
二,分析该模块的初始化函数eth_mac_higher_layer_intf_init ():
static void eth_mac_higher_layer_intf_init ()
{
FIN (eth_mac_higher_layer_intf_init ());
my_id = op_id_self (); //获得自己模块的objid。
own_node_objid = op_topo_parent (my_id); //获得自己模块所在节点的objid。
subnet_objid = op_topo_parent (own_node_objid); //获得自己模块所在节点的子网的objid。
own_prohandle = op_pro_self (); //获得当前运行进程的句柄,有何用处???(可以获取进程模型的各种属性)
op_ima_obj_attr_get (my_id, "process model", proc_model_name); //通过objid获得当前进程模型的process model属性,送到proc_model_name,注意proc_model_name是char[20]。
//在model registry(进程登记库)中注册进程,并返回handle,注意model registry是进程注册的一个表,通过返回的handle操作,可以注册、查询、设置等。
//model registry的目的是在各层协议模块间共享数据,具体见《大解密》P286,
//进程登记库的目的是:(1)为仿真中所有进程提供全局的信息注册机制,(2)允许进程在节点内共享信息,进程可以设置多种类型的属性(3)进程注册后,可以用多种查询参数找到并访问其公开信息。相关文件为oms_pr.h和oms_pr.ex.c
own_process_record_handle = (OmsT_Pr_Handle) oms_pr_process_register (own_node_objid, my_id,
own_prohandle, proc_model_name); //注意返回值类型是OmsT_Pr_Handle
//利用返回的handle,设置进程在process registry的属性
oms_pr_attr_set (own_process_record_handle, "location", OMSC_PR_STRING, "mac_if",
"subnet", OMSC_PR_OBJID, subnet_objid, OPC_NIL); //syntax:oms_pr_attr_set(pr_handle,attr0_name,attr0_type,attr0_value,……,OPC_NIL);,最后一个常量表示结束。登记了两个属性,分别为location 和subnet
//进出的stream index,这两个量会在wait状态的出口代码中被赋值,这里被设置为无效值。
outstrm_to_mac = OPC_INT_UNDEF;
instrm_from_mac = OPC_INT_UNDEF;
FOUT;
}
三,init2状态的入口代码:
op_intrpt_schedule_self (op_sim_time (), 0); //自中断,时间为当前时间,目的是等待底层的MAC进程初始化并注册,目的是用于一些系统的初始化配置,比如你的网络开始运行之前,你需要为每一个节点分配适当的地址,并且你必须保证每一个节点配置了初始节点网络才能够开始运行。这就是用两个unforced init模块模块的原因。
四,wait状态的入口代码:同上。
出口代码:(要从节点内的进程登记库中提取MAC的流信息,所以必须等待所有底层的进程完成初始化才开始)
proc_record_handle_list_ptr = op_prg_list_create (); //功能是分配一个新的空表
oms_pr_process_discover (my_id, proc_record_handle_list_ptr,
"protocol", OMSC_PR_STRING, "mac",OPC_NIL); //在进程登记库中发现符合条件的进程,这里是本节点内部的协议为“mac”的进程,(syntax:oms_pr_process_discover(neighber_objid,pr_handle_lptr, attr0_name, attr0_type, attr0_value,...., OPC_NIL))
record_handle_list_size = op_prg_list_size (proc_record_handle_list_ptr); //判断是否是正好一个match的进程
if (record_handle_list_size != 1)
{
}
else
{
//正确,只有一个,通过在进程登记库中的位置,获得MAC进程的handle,并送到process_record_handle
process_record_handle = (OmsT_Pr_Handle) op_prg_list_access (proc_record_handle_list_ptr, OPC_LISTPOS_HEAD);
//获得MAC模块的objid并记录到变量mac_module_objid中,注意mac模块应登记了objid
oms_pr_attr_get (process_record_handle, "module objid", OMSC_PR_OBJID, &mac_module_objid);
//获得MAC模块的属性,包括mac地址和auto address handle???
oms_pr_attr_get (process_record_handle, "address", OMSC_PR_INT64, &ne_address);
oms_pr_attr_get (process_record_handle, "auto address handle", OMSC_PR_POINTER, &oms_aa_handle);
//获得MAC模块连接的stream index,并送到instrm_from_mac和outstrm_to_mac。
oms_tan_neighbor_streams_find (my_id, mac_module_objid, &instrm_from_mac, &outstrm_to_mac);
}
//---------------------------------------------------------------------------下面是获取目的地址,可以是设定或随机选择的
if (oms_aa_handle == OPC_NIL)
{
}
else
{
if ((op_ima_obj_attr_get (my_id, "low dest address", &low_dest_addr) == OPC_COMPCODE_FAILURE) || //从属性中获取地址范围
(op_ima_obj_attr_get (my_id, "high dest address", &high_dest_addr) == OPC_COMPCODE_FAILURE))
{
eth_mac_higher_layer_intf_error ("Unable to read destination address range.", OPC_NIL, OPC_NIL);
}
//注意-1是广播地址???
if (((low_dest_addr == -1) && (high_dest_addr != -1)) ||
((high_dest_addr == -1) && (low_dest_addr != -1)))
{
eth_mac_higher_layer_intf_error ("Both the Lowest and Highest Destination addresses must be specified as Broadcast", "Any one attribute cannot be Broadcast", OPC_NIL);
}
if ((high_dest_addr < low_dest_addr) && (high_dest_addr >= 0))
{
eth_mac_higher_layer_intf_warn ("Specified lowest destination address is greater than specified highest destination address.",
"Setting the lowest destination address to Minimum Dest Address, and the highest to Maximum Dest Address.", OPC_NIL);
low_dest_addr = MIN_DEST_ADDR;
high_dest_addr = MAX_DEST_ADDR;
}
//确定目的地址的range
low_dest_index = OMSC_AA_UNINIT_ADDR;
high_dest_index = OMSC_AA_UNINIT_ADDR;
if ((low_dest_addr == MIN_DEST_ADDR) && (high_dest_addr == MAX_DEST_ADDR)) //前面判断地址范围有问题时
{
destination_address = OMSC_AA_AUTO_ASSIGN;
}
else if (low_dest_addr == high_dest_addr)
{
if (low_dest_addr == -1)
destination_address = OMSC_AA_BROADCAST;
else if (oms_aa_dest_addr_check (oms_aa_handle, low_dest_addr) == OPC_TRUE)
destination_address = low_dest_addr; //正确的唯一地址
else
{
sprintf (err_msg, "%d", low_dest_addr);
eth_mac_higher_layer_intf_error ("Invalid destination MAC address.", "No MAC was found with the address:",err_msg);
}
}
else
{
if (low_dest_addr == MIN_DEST_ADDR)
low_dest_index = 0;
else
{
low_dest_index = oms_aa_address_find (oms_aa_handle, low_dest_addr);
if (low_dest_index < 0)
{
sprintf (err_msg, "%d", low_dest_addr);
eth_mac_higher_layer_intf_error ("Invalid destination MAC address.", "No MAC was found with the address:", err_msg);
}
else if (oms_aa_dest_addr_check (oms_aa_handle, low_dest_addr) == OPC_FALSE)
{
sprintf (err_msg, "MAC address specified as the lowest destination address (%d)", low_dest_addr);
eth_mac_higher_layer_intf_error (err_msg, "is not configured as a valid destination address.",
"Most probably that MAC belongs to a switch or bridge node.");
}
}
if (high_dest_addr == MAX_DEST_ADDR)
high_dest_index = oms_aa_max_addr_index_get (oms_aa_handle);
else
{
high_dest_index = oms_aa_address_find (oms_aa_handle, high_dest_addr);
if (high_dest_index < 0)
{
sprintf (err_msg, "%d", high_dest_addr);
eth_mac_higher_layer_intf_error ("Invalid destination MAC address.", "No MAC was found with the address:", err_msg);
}
else if (oms_aa_dest_addr_check (oms_aa_handle, high_dest_addr) == OPC_FALSE)
{
sprintf (err_msg, "MAC address specified as the highest destination address (%d)", high_dest_addr);
eth_mac_higher_layer_intf_error (err_msg, "is not configured as a valid destination address.",
"Most probably that MAC belongs to a switch or bridge node.");
}
}
}
}
五,idle状态的入口代码为空,当收到中断时,根据条件执行出口代码:
注意在header block中定义的条件:当stream index是从mac来时为MAC中断,其它为应用层中断。
#define MAC_LAYER_PKT_ARRVL
#define APPL_LAYER_PKT_ARRVL (intrpt_type == OPC_INTRPT_STRM && intrpt_strm != instrm_from_mac)
首先执行出口代码:
intrpt_type = op_intrpt_type (); //首先得到中断类型和stream index
intrpt_strm = op_intrpt_strm ();
pkptr = op_pk_get (intrpt_strm); //得到包指针,注意由于包需要在不同的状态处理,所以pkpt是state variable,始终有效
五,appl layer arrival状态,由于该状态是强制状态,执行入口代码后马上跳回idle:这里只是分配了mac地址和ICI信息。
num_tries = 0;
do
if (curr_dest_addr == mac_address)
if (curr_dest_addr == OMSC_AA_UNINIT_ADDR)
else
六,mac
op_pk_send (pkptr, 0); //默认的stream index为0的是连接到sink模块
总结:eth_mac_intf模块是在应用层与mac层之间的接口,功能是(1)从上层传递的包,随机(或指定)一个mac地址,然后发送给mac层,其中地址作为ICI信息发送。(2)mac层传过来的包直接发给上层,因为上层是sink模块,直接把包销毁,所以不需要做其它的工作了。
注意的:(1)自中断等待其它进程完成初始化。(2)进程登记库及相关函数(pr),用于得到本节点内其它模块的属性,共享信息。(3)用ICI在层间传递信息,这里是传递mac地址到mac层。(4)自动分配地址,oms_aa_dest_addr_from_range_get()系列函数。
转载地址:http://blog.sina.com.cn/s/blog_b14ce4cd01017o71.html