/*************************************************************************** * main_opfmsg.c * * 2017/02/28 15:52:34 星期二 * Copyright 2017 XuDongLai * ****************************************************************************/ /* * 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 . */ #include #include #include #include extern void nms_exec_action(u32 inport,u32 outport,struct eth_header *eth,int len,int hit_idx); extern void pkt_print(u8 *data, u16 len); extern uintptr_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_opfmsg_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 = htonll(0x1234ULL << 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_opfmsg_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_opfmsg_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] != 0) { 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_opfmsg_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] != 0) { memcpy(current_flow_stats, (void *)(uintptr_t)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_opfmsg_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] != 0) { ((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 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_opfmsg_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++) // 关于为什么写成1,见line 114 { 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_opfmsg_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;iofpmp_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_opfmsg_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_opfmsg_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;iofpmp_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_opfmsg_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 返回处理状态码 */ int 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