628 lines
21 KiB
C
628 lines
21 KiB
C
/***************************************************************************
|
||
* main_opfmsg.c
|
||
*
|
||
* 2017/02/28 15:52:34 星期二
|
||
* Copyright 2017 XuDongLai
|
||
* <XuDongLai0923@163.com>
|
||
****************************************************************************/
|
||
/*
|
||
* main_opfmsg.c
|
||
*
|
||
* Copyright (C) 2017 - XuDongLai
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* 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, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
#include <fast.h>
|
||
#include <main_libofp.h>
|
||
#include <ofp_v4.h>
|
||
|
||
|
||
|
||
extern uint64_t *flow_stats_addr;
|
||
extern struct timeval flow_stats_time[];
|
||
extern struct nms_ports_info nmps;
|
||
extern struct timeval start_tv;
|
||
|
||
/**
|
||
* @brief
|
||
*
|
||
* @param n
|
||
*
|
||
* @return
|
||
*/
|
||
/*64位主机序转网络序*/
|
||
static inline uint64_t
|
||
htonll(uint64_t n)
|
||
{
|
||
return htonl(1) == 1 ? n : (((uint64_t)htonl(n)) << 32) | htonl(n >> 32);
|
||
}
|
||
|
||
/*64位网络序转主机序*/
|
||
/**
|
||
* @brief
|
||
*
|
||
* @param n
|
||
*
|
||
* @return
|
||
*/
|
||
static inline uint64_t
|
||
ntohll(uint64_t n)
|
||
{
|
||
return htonl(1) == 1 ? n : (((uint64_t)ntohl(n)) << 32) | ntohl(n >> 32);
|
||
}
|
||
|
||
/**
|
||
* @brief 构建OpenFlow报文头
|
||
*
|
||
* 该函数用于填充OpenFlow报文头,包括版本、长度、类型和事务ID。
|
||
*
|
||
* @param ofpbuf_header OpenFlow报文头结构体指针
|
||
* @param len 报文长度
|
||
* @param type 报文类型
|
||
* @param xid 事务ID
|
||
*/
|
||
void build_opfmsg_header(struct ofp_header *ofpbuf_header,uint16_t len,uint8_t type,uint32_t xid)
|
||
{
|
||
|
||
ofpbuf_header->version = OFP13_VERSION;
|
||
ofpbuf_header->length = htons(len);
|
||
ofpbuf_header->type = type;
|
||
ofpbuf_header->xid = xid;
|
||
|
||
printf("ofpbuf_header->length=%d\n",ntohs(ofpbuf_header->length));
|
||
}
|
||
|
||
/**
|
||
* @brief 构建OpenFlow回应报文
|
||
*
|
||
* 该函数用于构建并返回一个OpenFlow回应报文,报文类型和长度由参数指定。
|
||
*
|
||
* @param type 报文类型
|
||
* @param xid 事务ID
|
||
* @param len 报文长度
|
||
*
|
||
* @return 返回构建的报文缓冲区指针
|
||
*/
|
||
u8 *build_opfmsg_reply_ofpbuf(uint8_t type,uint32_t xid,uint16_t len)
|
||
{
|
||
|
||
struct ofp_header *reply = (struct ofp_header *)malloc(len);
|
||
|
||
memset((u8 *)reply,0,len);
|
||
build_opfmsg_header(reply,len,type,xid);
|
||
|
||
printf("ofpbuf_reply,malloc:%p,type:%d,len:%d\n",reply,type,len);
|
||
|
||
return (u8 *)reply;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Hello消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Hello消息。如果协议版本不是1.3,则发送错误消息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_opfmsg_hello(struct ofp_buffer *ofpbuf)
|
||
{
|
||
|
||
printf("header.version:%d\n",ofpbuf->header.version);
|
||
if(ofpbuf->header.version == 0x04)
|
||
{
|
||
printf("RECV HELLO!\n\n\n");
|
||
}else //不是openflow1.3协议,则发送error消息
|
||
{
|
||
int reply_len = sizeof(struct ofp_header);
|
||
//填充openflow协议头,协议类型为OFPT_ERROR
|
||
struct ofp_buffer *ofpbuf_reply =
|
||
(struct ofp_buffer *)build_reply_ofpbuf(OFPT_ERROR,ofpbuf->header.xid,reply_len);
|
||
//打印error消息
|
||
pkt_print((u8 *)ofpbuf,htons(ofpbuf->header.length));
|
||
//发送error消息
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
}
|
||
|
||
//返回已处理状态码
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Features Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Features Request消息,并返回交换机的功能信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_opfmsg_features_request(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int feature_reply_len = sizeof(struct ofp_switch_features)+sizeof(struct ofp_header);
|
||
//填充openflow协议头,协议类型为 OFPT_FEATURES_REPLY
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_opfmsg_reply_ofpbuf(OFPT_FEATURES_REPLY,
|
||
ofpbuf->header.xid,feature_reply_len);
|
||
//获取交换机的功能信息 指针变量 feature_reply_msg
|
||
struct ofp_switch_features *feature_reply_msg =(struct ofp_switch_features *)ofpbuf_reply->data;
|
||
|
||
|
||
//TODO
|
||
/* 构建feature回应报文,把交换机的功能信息发送给控制器(指针变量feature_reply_msg赋值) */
|
||
feature_reply_msg->datapath_id = 0x6655443322110000;
|
||
feature_reply_msg->n_buffers = 0x100;
|
||
feature_reply_msg->n_tables = 0x02;
|
||
feature_reply_msg->auxiliary_id = 0;
|
||
feature_reply_msg->capabilities = htonl(0x0000004f);
|
||
feature_reply_msg->reserved = htonl(0x00000000);
|
||
|
||
|
||
// feature_reply_msg->datapath_id = htonll(0x1234 << 48);
|
||
// feature_reply_msg->n_buffers = 0x100; // 256
|
||
// feature_reply_msg->n_tables = 1;
|
||
// feature_reply_msg->auxiliary_id = 0;
|
||
// feature_reply_msg->capabilities = htonl(0x0007);
|
||
// feature_reply_msg->reserved = htonl(0x0000);
|
||
//调用系统发送接口,发送回应报文
|
||
send_openflow_message(ofpbuf_reply,feature_reply_len);
|
||
|
||
//返回已处理状态码
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Get Config Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Get Config Request消息,并返回交换机的配置信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_get_config_request(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int reply_len = sizeof(struct ofp_switch_config)+sizeof(struct ofp_header);
|
||
//填充openflow协议头,协议类型为 OFPT_GET_CONFIG_REPLY
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_GET_CONFIG_REPLY,
|
||
ofpbuf->header.xid,reply_len);
|
||
struct ofp_switch_config *switch_config_reply =(struct ofp_switch_config *)ofpbuf_reply->data;
|
||
|
||
switch_config_reply->flags = htons(0x0000);
|
||
switch_config_reply->miss_send_len = htons(0xffe5); //65509,基于协议
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Description Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Description Request消息,并返回交换机的描述信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_desc(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int reply_len = sizeof(struct ofp_header)+sizeof(struct ofp_multipart)+sizeof(struct ofp_desc_stats);
|
||
struct ofp_buffer *ofpbuf_reply =
|
||
(struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY,ofpbuf->header.xid,reply_len);
|
||
struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data;
|
||
|
||
static const char *default_mfr_desc = "Chengjingyu_Networks";
|
||
static const char *default_hw_desc = "Jingyu_OpenBox";
|
||
static const char *default_sw_desc = "Jingyu_Driver";
|
||
static const char *default_serial_desc = "Jingyu OpenBox Series";
|
||
static const char *default_dp_desc = "None";
|
||
|
||
ofpmp_reply->type = htons(OFPMP_DESC);
|
||
ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
snprintf(ofpmp_reply->ofpmp_desc[0].mfr_desc, sizeof ofpmp_reply->ofpmp_desc[0].mfr_desc, "%s", default_mfr_desc);
|
||
snprintf(ofpmp_reply->ofpmp_desc[0].hw_desc, sizeof ofpmp_reply->ofpmp_desc[0].hw_desc, "%s", default_hw_desc);
|
||
snprintf(ofpmp_reply->ofpmp_desc[0].sw_desc, sizeof ofpmp_reply->ofpmp_desc[0].sw_desc, "%s", default_sw_desc);
|
||
snprintf(ofpmp_reply->ofpmp_desc[0].serial_num, sizeof ofpmp_reply->ofpmp_desc[0].serial_num, "%s", default_serial_desc);
|
||
snprintf(ofpmp_reply->ofpmp_desc[0].dp_desc, sizeof ofpmp_reply->ofpmp_desc[0].dp_desc, "%s", default_dp_desc);
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Flow Stats Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Flow Stats Request消息,并返回流统计信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_flow_stats(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int i = 0, reply_len = 0, flow_stats_offset;
|
||
struct ofp_flow_stats *current_flow_stats = NULL;
|
||
struct ofp_buffer *reply_buffer = NULL;
|
||
struct ofp_multipart *multipart_reply = NULL;
|
||
|
||
// 计算长度
|
||
for (; i < FAST_RULE_CNT; i++) {
|
||
if (flow_stats_addr[i] != NULL) {
|
||
reply_len += ntohs(((struct ofp_flow_stats *)flow_stats_addr[i])->length);
|
||
}
|
||
}
|
||
reply_len += sizeof(struct ofp_header) + sizeof(struct ofp_multipart);
|
||
|
||
// 构造响应包
|
||
reply_buffer = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len);
|
||
multipart_reply = (struct ofp_multipart *)reply_buffer->data;
|
||
multipart_reply->type = htons(OFPMP_FLOW); // 标识信息
|
||
multipart_reply->flags = htonl(OFPMP_REPLY_MORE_NO); //这条不用回
|
||
|
||
// 填充包体
|
||
flow_stats_offset = sizeof(struct ofp_multipart);
|
||
current_flow_stats = (struct ofp_flow_stats *)&reply_buffer->data[flow_stats_offset];
|
||
|
||
for (i = 0; i < FAST_RULE_CNT; i++) {
|
||
if (flow_stats_addr[i] != NULL) {
|
||
memcpy(current_flow_stats, flow_stats_addr[i], ntohs(((struct ofp_flow_stats *)flow_stats_addr[i])->length));
|
||
flow_stats_offset += ntohs(current_flow_stats->length);
|
||
current_flow_stats = (struct ofp_flow_stats *)&reply_buffer->data[flow_stats_offset];
|
||
}
|
||
}
|
||
|
||
send_openflow_message(reply_buffer, reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Aggregate Stats Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Aggregate Stats Request消息,并返回聚合统计信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_aggregate(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int reply_len = sizeof(struct ofp_header)+ sizeof(struct ofp_multipart)+sizeof(struct ofp_aggregate_stats_reply);
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY,
|
||
ofpbuf->header.xid,reply_len);
|
||
struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data;
|
||
int i = 0,flow_count = 0;
|
||
u64 byte_count = 0,packet_count = 0;
|
||
struct timeval tv;
|
||
|
||
ofpmp_reply->type = htons(OFPMP_AGGREGATE);
|
||
ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
gettimeofday(&tv, NULL);
|
||
|
||
for (; i < FAST_RULE_CNT; i++) {
|
||
if (flow_stats_addr[i] != NULL) {
|
||
((struct ofp_flow_stats *)flow_stats_addr[i])->duration_sec = htonl(tv.tv_sec - flow_stats_time[i].tv_sec);
|
||
((struct ofp_flow_stats *)flow_stats_addr[i])->duration_nsec = htonl(tv.tv_usec - flow_stats_time[i].tv_usec);
|
||
// ((struct ofp_flow_stats *)flow_stats_addr[i])->packet_count = ((uint64_t)0x100); // 涉及硬件地址,拼尽全力无法找到,姑且填充256
|
||
// ((struct ofp_flow_stats *)flow_stats_addr[i])->byte_count = ((uint64_t)0x40000); // 涉及硬件地址,拼尽全力无法找到,姑且填充262144=256*1024
|
||
// 从硬件寄存器读取数据包计数和字节计数
|
||
((struct ofp_flow_stats *)flow_stats_addr[i])->packet_count = fast_reg_rd(FAST_OFP_FLOW_STATS_PKTS + i * sizeof(uint64_t));
|
||
((struct ofp_flow_stats *)flow_stats_addr[i])->byte_count = fast_reg_rd(FAST_OFP_FLOW_STATS_BYTES + i * sizeof(uint64_t));
|
||
|
||
packet_count += ((struct ofp_flow_stats *)flow_stats_addr[i])->packet_count;
|
||
byte_count += ((struct ofp_flow_stats *)flow_stats_addr[i])->byte_count;
|
||
flow_count++;
|
||
}
|
||
}
|
||
ofpmp_reply->ofpmp_aggregate_reply[0].packet_count = packet_count;
|
||
ofpmp_reply->ofpmp_aggregate_reply[0].byte_count = byte_count;
|
||
ofpmp_reply->ofpmp_aggregate_reply[0].flow_count = flow_count;
|
||
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Table Stats Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Table Stats Request消息,并返回表统计信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_table(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int i = 0;
|
||
int reply_len = sizeof(struct ofp_header)+sizeof(struct ofp_multipart)+
|
||
sizeof(struct ofp_table_stats)*1;
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY,
|
||
ofpbuf->header.xid,reply_len);
|
||
struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data;
|
||
|
||
ofpmp_reply->type = htons(OFPMP_TABLE);
|
||
ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
for(i=0;i<1;i++)
|
||
{
|
||
ofpmp_reply->table_stats[i].matched_count = htonll(0);
|
||
ofpmp_reply->table_stats[i].table_id = i;
|
||
ofpmp_reply->table_stats[i].lookup_count = htonll(0);
|
||
ofpmp_reply->table_stats[i].active_count = htonl(1);
|
||
}
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Port Stats Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Port Stats Request消息,并返回端口统计信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_port_stats(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int i = 0;
|
||
int reply_len = sizeof(struct ofp_header)+sizeof(struct ofp_multipart)+
|
||
sizeof(struct ofp_port_stats)*nmps.cnt;
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY,
|
||
ofpbuf->header.xid,reply_len);
|
||
struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data;
|
||
struct timeval tv;
|
||
|
||
ofpmp_reply->type = htons(OFPMP_PORT_STATS);
|
||
ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
|
||
for(i=0;i<nmps.cnt;i++){
|
||
gettimeofday(&tv,NULL);
|
||
ofpmp_reply->ofpmp_port_stats[i] = nmps.ports[i].stats;
|
||
ofpmp_reply->ofpmp_port_stats[i].duration_sec = htonl(start_tv.tv_sec - tv.tv_sec);
|
||
ofpmp_reply->ofpmp_port_stats[i].duration_nsec = htonl(tv.tv_usec);
|
||
}
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Group Features Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Group Features Request消息,并返回组功能信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_group_features(struct ofp_buffer *ofpbuf)
|
||
{
|
||
|
||
int i = 0;
|
||
int reply_len = sizeof(struct ofp_header)+sizeof(struct ofp_group_features)+8;
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY,
|
||
ofpbuf->header.xid,reply_len);
|
||
struct ofp_group_features *group = (struct ofp_group_features *)ofpbuf_reply->data;
|
||
|
||
group->types = htons(OFPMP_GROUP_FEATURES);
|
||
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Port Description Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Port Description Request消息,并返回端口描述信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_port_desc(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int i = 0;
|
||
int reply_len = sizeof(struct ofp_header)+sizeof(struct ofp_multipart)+
|
||
sizeof(struct ofp_port)*nmps.cnt;
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY,
|
||
ofpbuf->header.xid,reply_len);
|
||
struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data;
|
||
|
||
ofpmp_reply->type = htons(OFPMP_PORT_DESC);
|
||
ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
for(i=0;i<nmps.cnt;i++)
|
||
{
|
||
ofpmp_reply->ofpmp_port_desc[i] = nmps.ports[i].state;
|
||
}
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Packet Out消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Packet Out消息,并根据消息中的动作执行相应的操作。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle_ofpmsg_packet_out(struct ofp_buffer *ofpbuf)
|
||
{
|
||
struct ofp_packet_out *out = (struct ofp_packet_out *)ofpbuf;
|
||
struct ofp_action_output *action = (struct ofp_action_output *)&out->actions[0];
|
||
int action_len = ntohs(out->actions_len);
|
||
struct eth_header *eth = (struct eth_header *)&ofpbuf->data[sizeof(struct ofp_packet_out) - sizeof(struct ofp_header) + action_len];
|
||
int i = 0,send_len = ntohs(ofpbuf->header.length) - sizeof(struct ofp_packet_out) - action_len;
|
||
|
||
|
||
if(action_len == 0)
|
||
{
|
||
nms_exec_action(ntohl(out->in_port),OFPP_FLOOD,eth,send_len,-1);
|
||
}
|
||
else
|
||
{
|
||
|
||
while(action_len > 0)
|
||
{
|
||
if(action->type == OFPAT_OUTPUT)
|
||
{
|
||
nms_exec_action(ntohl(out->in_port),ntohl(action->port),eth,send_len,-1);
|
||
}
|
||
action_len -= sizeof(struct ofp_action_output);
|
||
action++;
|
||
}
|
||
}
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理OpenFlow Role Request消息
|
||
*
|
||
* 该函数用于处理接收到的OpenFlow Role Request消息,并返回角色信息。
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
static enum ofperr
|
||
handle__opfmsg_role_request(struct ofp_buffer *ofpbuf)
|
||
{
|
||
int reply_len = sizeof(struct ofp_header)+sizeof(struct ofp_role);
|
||
struct ofp_buffer *ofpbuf_reply =
|
||
(struct ofp_buffer *)build_reply_ofpbuf(OFPT_ROLE_REPLY,ofpbuf->header.xid,reply_len);
|
||
|
||
SHOW_FUN(0);
|
||
memcpy(ofpbuf_reply->data,ofpbuf->data,sizeof(struct ofp_role));
|
||
ofpbuf_reply->header.type = OFPT_ROLE_REPLY;
|
||
send_openflow_message(ofpbuf_reply,reply_len);
|
||
SHOW_FUN(1);
|
||
|
||
return HANDLE;
|
||
}
|
||
|
||
/**
|
||
* @brief OpenFlow消息回调处理函数
|
||
*
|
||
* 该函数根据接收到的OpenFlow消息类型调用相应的处理函数。
|
||
* callback 的返回值必须有且只能存在两种返回值:
|
||
* 已处理: HANDLE = 0x1,
|
||
* 不处理:CONTINUE = 0x2
|
||
*
|
||
* @param ofpbuf 接收到的OpenFlow消息缓冲区
|
||
* @param len 消息长度
|
||
*
|
||
* @return 返回处理状态码
|
||
*/
|
||
enum ofperr handle_openflow_callback(struct ofp_buffer *ofpbuf, int len)
|
||
{
|
||
int oftype = ofpbuf->header.type;
|
||
printf("header.version:%d, type:%d, len:%d\n", ofpbuf->header.version, ofpbuf->header.type, htons(ofpbuf->header.length));
|
||
|
||
switch (oftype) {
|
||
case OFPT_HELLO:
|
||
return handle_opfmsg_hello(ofpbuf);
|
||
case OFPT_FEATURES_REQUEST:
|
||
return handle_opfmsg_features_request(ofpbuf);
|
||
case OFPT_GET_CONFIG_REQUEST:
|
||
return handle_ofpmsg_get_config_request(ofpbuf);
|
||
case OFPT_MULTIPART_REQUEST:
|
||
// 根据 multipart 请求的具体类型进一步处理
|
||
{
|
||
struct ofp_multipart *multipart = (struct ofp_multipart *)ofpbuf->data;
|
||
switch (ntohs(multipart->type)) {
|
||
case OFPMP_DESC:
|
||
return handle_ofpmsg_desc(ofpbuf);
|
||
case OFPMP_FLOW:
|
||
return handle_ofpmsg_flow_stats(ofpbuf);
|
||
case OFPMP_AGGREGATE:
|
||
return handle_ofpmsg_aggregate(ofpbuf);
|
||
case OFPMP_TABLE:
|
||
return handle_ofpmsg_table(ofpbuf);
|
||
case OFPMP_PORT_STATS:
|
||
return handle_ofpmsg_port_stats(ofpbuf);
|
||
case OFPMP_GROUP_FEATURES:
|
||
return handle_ofpmsg_group_features(ofpbuf);
|
||
case OFPMP_PORT_DESC:
|
||
return handle_ofpmsg_port_desc(ofpbuf);
|
||
default:
|
||
printf("Unsupported multipart request type: %d\n", ntohs(multipart->type));
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
case OFPT_PACKET_OUT:
|
||
return handle_ofpmsg_packet_out(ofpbuf);
|
||
case OFPT_ROLE_REQUEST:
|
||
return handle__opfmsg_role_request(ofpbuf);
|
||
default:
|
||
printf(" --do not handle the message!\n");
|
||
}
|
||
|
||
// 返回不处理状态码
|
||
return CONTINUE;
|
||
}
|
||
|
||
|
||
#define MASK_HELLO (1 << OFPT_HELLO) // 1 << 0
|
||
#define MASK_FEATURES_REQUEST (1 << OFPT_FEATURES_REQUEST) // 1 << 5
|
||
#define MASK_GET_CONFIG_REQUEST (1 << OFPT_GET_CONFIG_REQUEST) // 1 << 7
|
||
#define MASK_PACKET_OUT (1 << OFPT_PACKET_OUT) // 1 << 13
|
||
#define MASK_MULTIPART_REQUEST (1 << OFPT_MULTIPART_REQUEST) // 1 << 18
|
||
#define MASK_ROLE_REQUEST (1 << OFPT_ROLE_REQUEST) // 1 << 24
|
||
|
||
|
||
/** mask 为获取openflow消息的bimap掩码,openflow消息枚举见 "enum ofp_type"
|
||
*
|
||
* 如:获取 OFPT_HELLO(0) 和 OFPT_FEATURES_REQUEST(5)消息,
|
||
* mask值设为 mask = 0b'100001 = 0x21
|
||
*
|
||
*/
|
||
int main(int argc,char* argv[])
|
||
{
|
||
int mask = 0;
|
||
|
||
ofp_init(argc,argv);
|
||
|
||
// 使用宏为 mask 赋值,监听以下消息类型:
|
||
// OFPT_HELLO, OFPT_FEATURES_REQUEST, OFPT_GET_CONFIG_REQUEST,
|
||
// OFPT_PACKET_OUT, OFPT_MULTIPART_REQUEST, OFPT_ROLE_REQUEST
|
||
mask = MASK_HELLO | MASK_FEATURES_REQUEST | MASK_GET_CONFIG_REQUEST |
|
||
MASK_PACKET_OUT | MASK_MULTIPART_REQUEST | MASK_ROLE_REQUEST;
|
||
|
||
openflow_hook_init(mask,handle_openflow_callback);
|
||
|
||
pause();
|
||
|
||
return 0;
|
||
}
|
||
// sudo xofp -4 127.0.0.1 -c eth0 -i obx0,obx1,obx2,obx3
|