1. 自定义包格式 ”Custom_IP”:
在节点编辑器的 Interfaces 菜单中选择 Model Attribute,添加节点属性“ Addr_IP”,它
是 string 型的属性,标记节点的 IP 地址,格式为"xxx.xxx.xxx.xxx"
2. IP包的创建和高层数据包的封装
Packet* ip_pkptr, ip_pkptr_tmp;
char addr_ip[32];
unsigned long int src_ip_addr,dest_ip_addr;
//创建自定义格式的IP包
ip_pkptr = op_pk_create_fmt("Custom_IP");
//得到本节点的IP地址
op_ima_obj_attr_get(op_id_self(),"Addr_IP",addr_ip);
/*将字符串型的 IP 地址转成整型 IP 地址,这样符合标准 IP 协议的
IP 地址读写规范*/
src_ip_addr = prg_ip_address_string_to_value(addr_ip);
//设置IP源地址,IP样本包制作完成
op_pk_nfd_set(ip_pkptr,"Source address",src_ip_addr);
//得到高层数据包
app_layer_pkptr = op_pk_get(op_intrpt_strm());
//拷贝样本包
ip_pkptr_tmp = op_pk_copy(ip_pkptr);
//设置IP目的地址
op_pk_nfd_set(ip_pkptr_tmp,"Destination address",dest_ip_addr);
//封装高层数据包
op_pk_nfd_set(ip_pkptr_tmp,"Extended packet",app_layer_pkptr);
//最后将创建好的IP包发往低层
op_pk_send(ip_pkptr,IP_LAYER_OUT_STRM);
3. IP 路由表初始化
struct route{
unsigned long int netprefix;
int MAC_addr;
struct route *nextunit;
}
//定义状态变量 route_table_ptr
struct route *route_table_ptr;
//路由表初始化所必需的变量
struct route *table_item1 = route_table_ptr;
struct route *table_item2;
//路由发现所必需的变量
Objid self_if;
Objid IP_rte_id;
Objid xmt_id;
Objid remote_rcv_id;
Objid remote_node_id;
//IP 地址读取所必需的变量
char addr_ip[32];
unsigned long int addr;
//初始化路由表,这里我们假设与路由器有线相连的节点为 2 个
table_item1->nextunit = table_item1 + 1 ;
table_item2 = table_item1->nextunit ;
table_item2->nextunit = NULL ;
接下来我们要根据每个有线发射机的连接关系自适应地查找到与之相连节点的 IP地址前缀
首先查找与名称为"xmt0"有线发信机相连节点 Objid。
//得到进程模块 Objid
self_id = op_id_self ();
//得到路由器节点 Objid
IP_rte_id = op_topo_parent (self_id);
//得到名称为"xmt0"有线发信机的 Objid
xmt_id = op_id_from_name(IP_rte_id,OPC_OBJTYPE_PTTX, "xmt0");
//得到与"xmt0"相连的有线收信机的 Objid
remote_rcv_id = op_topo_assoc
(xmt_id, OPC_TOPO_ASSOC_OUT, OPC_OBJMTYPE_RECV, 0);
//得到与"xmt0"相连节点的 Objid
remote_node_id = op_topo_parent(remote_rcv_id);
接下来就可以根据这个 remote_node_id 得到其 IP 地址信息,我们假设节点 IP 信息已经存在节点的"Addr_IP"属性中。
//得到节点的 IP 地址
op_ima_obj_attr_get(remote_node_id, "Addr_IP" , addr_ip);
//得到节点的名称
op_ima_obj_attr_get(remote_node_id,"name",node_name);
//将字符串型的 IP 地址转换成长整型以便存储
addr=prg_ip_address_string_to_value(addr_ip);
if (op_prg_odb_ltrace_active("ip_discover")==OPC_TRUE)
{
printf("IP address of Node %s is %s\n",name,addr_ip);
}
最后将 IP 地址前缀以及与"xmt0"相对应的流索引号写入链表元素 table_item1 中
//将 addr 以二进制的方式向右偏移 8 位,取得 IP 地址前缀,
//它由 IP 地址前面三个字段组成
addr=(addr)>>8;
table_item1->netprefix = addr;
table_item1->MAC_addr = XMT0_STRM_INDEX;
4. 路由表的查找
当路由器收到 IP 包时,必须根据其目的IP 地址前缀查找路由表,从而将其路由至相应的子网。
Packet* pkptr;
unsigned long int dest_ip_addr;
int MAC_addr;
//得到 IP 包
pkptr = op_pk_get ( op_intrpt_strm() );
//获取 IP 包的目的地址
op_pk_nfd_get (pkptr,"Destination address",&dest_ip_addr);
/*for debug*/
addr_ip = str;
prg_ip_address_value_to_string(dst_ip_addr,addr_ip);
//得到 IP 地址前缀
net_prefix = ( dest_ip_addr ) >> 8 ;
//假设路由表的大小 RTE_TABLE_SIZE,搜索路由表找到与 IP 地址前缀对应的物理地址
for ( i = 0 ; i <= RTE_TABLE_SIZE - 1 ; i++ )
{
if ( route_table_ptr->netprefix == net_prefix )
{
MAC_addr = route_table_ptr->MAC_addr ;
break ;
}
route_table_ptr = route_table_ptr->nextunit ;
}
//将 IP 包发送至下一跳节点
op_pk_send (pkptr, MAC_addr) ;