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狀態的入口代碼:
/* This function initializes its state variables and registers itself in the process registry*/
eth_mac_higher_layer_intf_init (); //調用該函數初始化,包括初始化狀態變量 和注冊進程
/* Set up an interface control information (ICI) structure to */
/* communicate parameters to the MAC layer process. We will */
/* leave this ICI installed for the entire simulation. */
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接收進程)。
/* Schedules a self interrrupt */
op_intrpt_schedule_self (op_sim_time (), 0); //自中斷,時間為當前時間
二,分析該模塊的初始化函數eth_mac_higher_layer_intf_init ():
static void eth_mac_higher_layer_intf_init ()
{
/** Initializes the state variables for this process model and registers itself in the model-wide reigtry*/
FIN (eth_mac_higher_layer_intf_init ());
/* Gets its own id */
my_id = op_id_self (); //獲得自己模塊的objid。
/* Gets the object id of the node to which this module belongs */
own_node_objid = op_topo_parent (my_id); //獲得自己模塊所在節點的objid。
/* Gets the objid of its subnet */
subnet_objid = op_topo_parent (own_node_objid); //獲得自己模塊所在節點的子網的objid。
/* Gets a handle to its process */
own_prohandle = op_pro_self (); //獲得當前運行進程的句柄,有何用處???(可以獲取進程模型的各種屬性)
/* Gets the name of its process model */
op_ima_obj_attr_get (my_id, "process model", proc_model_name); //通過objid獲得當前進程模型的process model屬性,送到proc_model_name,注意proc_model_name是char[20]。
/* Gets a process record handle to record its process in the registry */
//在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
/* Sets the required attributes in the process registry */
//利用返回的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 numbers to the mac layer and from the mac layer which */
/* which will be set in the exit execs of the wait state */
//進出的stream index,這兩個量會在wait狀態的出口代碼中被賦值,這里被設置為無效值。
outstrm_to_mac = OPC_INT_UNDEF;
instrm_from_mac = OPC_INT_UNDEF;
FOUT;
}
三,init2狀態的入口代碼:
/* Schedule a self interrupt to wait for lower layer Ethernet MAC process*/
/* to initialize and register itself in the model-wide process registry.*/
op_intrpt_schedule_self (op_sim_time (), 0); //自中斷,時間為當前時間,目的是等待底層的MAC進程初始化并注冊,目的是用于一些系統的初始化配置,比如你的網絡開始運行之前,你需要為每一個節點分配適當的地址,并且你必須保證每一個節點配置了初始節點網絡才能夠開始運行。這就是用兩個unforced init模塊模塊的原因。
四,wait狀態的入口代碼:同上。
出口代碼:(要從節點內的進程登記庫中提取MAC的流信息,所以必須等待所有底層的進程完成初始化才開始)
/* Obtain the MAC layer information for the local MACprocess from the model-wide registry.*/
proc_record_handle_list_ptr = op_prg_list_create (); //功能是分配一個新的空表
oms_pr_process_discover (my_id, proc_record_handle_list_ptr,"node objid", OMSC_PR_OBJID, own_node_objid,
"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))
/* If the MAC process registered itself, then there must be a valid match*/
record_handle_list_size = op_prg_list_size (proc_record_handle_list_ptr); //判斷是否是正好一個match的進程
if (record_handle_list_size != 1)
{
/* An error should be created if there are more than one Ethernet-MAC process in the local node, or if no match is found. */
op_sim_end ("Error: either zero or several Ethernet MAC processes found in the interface", "", "", ""); //多于一個,出錯了
}
else
{
/* Obtain a handle on the process record. */ //正確,只有一個,通過在進程登記庫中的位置,獲得MAC進程的handle,并送到process_record_handle
process_record_handle = (OmsT_Pr_Handle) op_prg_list_access (proc_record_handle_list_ptr, OPC_LISTPOS_HEAD);
/* Obtain the module objid for the Ethernet MAC module. */ //獲得MAC模塊的objid并記錄到變量mac_module_objid中,注意mac模塊應登記了objid
oms_pr_attr_get (process_record_handle, "module objid", OMSC_PR_OBJID, &mac_module_objid);
//pr就是process record
/* Obtain the address handle maintained by the MAC process. */ //獲得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);
/* Set the variable to indicate the MAC address of the associated MAC layer process.*/
mac_address = ne_address; //得到mac地址
/* Obtain the stream numbers connected to and from the Ethernet MAC layer process. */
//獲得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)
{
/* This is a unconnected node. Do nothing */
}
else
{
/* Determine address range for destination assignment. */
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);
}
/* If any single address is specified as broadcast, indicate this as an error */
/* Both the low and high destination addresses together can be specified as broadcast */ //注意-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);
}
/* Check whether highest destination address is not lower than the lowest destination */
/* address (also check it is not a broadcast address or MAX_DEST_ADDR). */
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);
/* If so, then set the lowest destination address to the minimum destination address */
/* and the highest destination address to the highest destination address. */
low_dest_addr = MIN_DEST_ADDR;
high_dest_addr = MAX_DEST_ADDR;
}
/* Determine our destination or destination range. Start by initializing the range indices, which are used if a range is specified.*/
//確定目的地址的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)) //前面判斷地址范圍有問題時
{
/* We randomly pick our destination from universal address set. */
destination_address = OMSC_AA_AUTO_ASSIGN;
}
else if (low_dest_addr == high_dest_addr)
{
/* We have a unique destination address specified. Check its validity. */
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
{
/* We randomly pick our destination addresses from a subset of the */
/* universal address set. Determine the lower and upper indices of this */
/* subset in the global address array. */
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);
/* Check validity of the lower bound. */
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.");
}
}
/* Now determine the upper bound. */
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);
/* Check validity of the upper bound. */
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中斷,其它為應用層中斷。
/* Definition for the transition conditions */
#define MAC_LAYER_PKT_ARRVL (intrpt_type == OPC_INTRPT_STRM && intrpt_strm == instrm_from_mac)
#define APPL_LAYER_PKT_ARRVL (intrpt_type == OPC_INTRPT_STRM && intrpt_strm != instrm_from_mac)
首先執行出口代碼:
/* The only interrupt expected in this state is a stream interrupt. It can be either from the MAC*/
/* layer for a packet destined for this node or from the application layer for a packet destined for some other node.*/
intrpt_type = op_intrpt_type (); //首先得到中斷類型和stream index
intrpt_strm = op_intrpt_strm ();
/*Get the packet from the appropriate stream */
pkptr = op_pk_get (intrpt_strm); //得到包指針,注意由于包需要在不同的狀態處理,所以pkpt是state variable,始終有效
五,appl layer arrival狀態,由于該狀態是強制狀態,執行入口代碼后馬上跳回idle:這里只是分配了mac地址和ICI信息。
/* A packet has arrived from the application layer.Pick a random*/
/* destination, unless an explicit destination is specified. Don't tryinfinite times.*/
num_tries = 0;
do
{
/* Increment the try counter. This will prevent an infinite loop.*/ //不能無窮的嘗試發送
num_tries++;
/* Pick a random destination address unless the destination addressis already set to a specific value.*/
if (low_dest_index + high_dest_index > 0) //地址沒有設定,可能的最高加最低地址大于零,即非廣播地址,
{
oms_aa_dest_addr_from_range_get (oms_aa_handle, &integer_mac_address, low_dest_index, high_dest_index); //用該函數隨機獲取地址范圍內的一個地址,并送到integer_mac_address。
curr_dest_addr = integer_mac_address;
}
else
{
integer_mac_address = destination_address; //地址已經確定
oms_aa_dest_addr_get (oms_aa_handle, &integer_mac_address); //獲取一個隨機地址從address list
curr_dest_addr = integer_mac_address;
}
} while ((curr_dest_addr == mac_address) && (num_tries < TRY_THRESH)); //目的地址不能是自己,也不能無限循環
if (curr_dest_addr == mac_address)
eth_mac_higher_layer_intf_error ("Unable to choose remote address.", OPC_NIL, OPC_NIL);
if (curr_dest_addr == OMSC_AA_UNINIT_ADDR)
{
op_pk_destroy (pkptr);
}
else
{
/* Set this information in the interface controlinformation to be sent to the MAC layer.*/
op_ici_attr_set_int64 (intf_mac_req_iciptr, "dest_addr", curr_dest_addr); //向MAC層提交ICI信息,內容是mac地址
/* Send the packet to the lower layer */
op_pk_send (pkptr, outstrm_to_mac); //發送包,注意op_pk_send()函數會默認銷毀包
}
六,maclayer arr狀態,對于mac層的包,直接發送給應用層,由于本模型應用層是sink模塊,所以直接發送即可。
/* A packet arrived from the MAC layer. Since the MAClayer would have forwarded this only if it were*/
/* destined for this node, forward this packet to theapplication layer.*/
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()系列函數。
總結
以上是生活随笔為你收集整理的OPNET学习笔记之eth_mac_intf模块(ethcoax_station_adv节点模型)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unity手游之路四3d旋转-四元数,欧
- 下一篇: 如何通过经纬度获取地址信息?