/*************************************************************************** * 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 "fast.h" #include #include struct eth_header; void nms_exec_action(u32 inport,u32 outport,struct eth_header *eth,int len,int hit_idx); extern void pkt_print(u8 *pkt, uint16_t len); static struct ofp_buffer *build_opfmsg_reply_ofpbuf(uint8_t type,uint32_t xid,uint16_t len); #ifndef htobe64 #if __BYTE_ORDER == __LITTLE_ENDIAN #define htobe64(x) __builtin_bswap64((u64)(x)) #define be64toh(x) __builtin_bswap64((u64)(x)) #else #define htobe64(x) (x) #define be64toh(x) (x) #endif #endif static inline uint64_t host_to_be64(uint64_t value) { return htobe64(value); } static struct ofp_buffer *build_multipart_reply(struct ofp_buffer *request, uint16_t mp_type, size_t body_len, struct ofp_multipart **mp_out) { size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + body_len; struct ofp_buffer *reply = build_opfmsg_reply_ofpbuf( OFPT_MULTIPART_REPLY, request->header.xid, reply_len); if (!reply) { return NULL; } struct ofp_multipart *mp = (struct ofp_multipart *)reply->data; memset(mp, 0, sizeof(*mp)); mp->type = htons(mp_type); if (mp_out) { *mp_out = mp; } return reply; } static enum opfmsg_hook_ret handle_opfmsg_get_config_request(struct ofp_buffer *ofpbuf); static enum opfmsg_hook_ret handle_opfmsg_multipart_request(struct ofp_buffer *ofpbuf); static enum opfmsg_hook_ret handle_opfmsg_packet_out(struct ofp_buffer *ofpbuf); static enum opfmsg_hook_ret handle_opfmsg_flow_mod(struct ofp_buffer *ofpbuf); static enum opfmsg_hook_ret handle_opfmsg_role_request(struct ofp_buffer *ofpbuf); /** * @brief * * 构建openflow报文头 * */ 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 * * 构建回应报文 * * @return */ static struct ofp_buffer *build_opfmsg_reply_ofpbuf(uint8_t type,uint32_t xid,uint16_t len) { struct ofp_buffer *reply = (struct ofp_buffer *)malloc(len); if (!reply) { return NULL; } memset(reply,0,len); build_opfmsg_header(&reply->header,len,type,xid); printf("ofpbuf_reply,malloc:%p,type:%d,len:%d\n",reply,type,len); return reply; } static enum opfmsg_hook_ret 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 = build_opfmsg_reply_ofpbuf(OFPT_ERROR,ofpbuf->header.xid,reply_len); if (!ofpbuf_reply) { return CONTINUE; } //打印error消息 pkt_print((u8 *)ofpbuf,htons(ofpbuf->header.length)); //发送error消息 send_openflow_message(ofpbuf_reply,reply_len); } //返回已处理状态码 return HANDLE; } static enum opfmsg_hook_ret 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 = build_opfmsg_reply_ofpbuf(OFPT_FEATURES_REPLY, ofpbuf->header.xid,feature_reply_len); if (!ofpbuf_reply) { return CONTINUE; } //获取交换机的功能信息 指针变量 feature_reply_msg struct ofp_switch_features *feature_reply_msg =(struct ofp_switch_features *)ofpbuf_reply->data; //TODO /* 构建feature回应报文,把交换机的功能信息发送给控制器(指针变量feature_reply_msg赋值) */ memset(feature_reply_msg,0,sizeof(*feature_reply_msg)); feature_reply_msg->datapath_id = host_to_be64(0x0100000000000001ULL); feature_reply_msg->n_buffers = htonl(256); feature_reply_msg->n_tables = 4; feature_reply_msg->capabilities = htonl(0); //调用系统发送接口,发送回应报文 send_openflow_message(ofpbuf_reply,feature_reply_len); //返回已处理状态码 return HANDLE; } static enum opfmsg_hook_ret handle_opfmsg_get_config_request(struct ofp_buffer *ofpbuf) { size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_switch_config); struct ofp_buffer *reply = build_opfmsg_reply_ofpbuf( OFPT_GET_CONFIG_REPLY, ofpbuf->header.xid, reply_len); if (!reply) { return CONTINUE; } struct ofp_switch_config *cfg = (struct ofp_switch_config *)reply->data; memset(cfg, 0, sizeof(*cfg)); cfg->flags = htons(0); cfg->miss_send_len = htons(0xffff); send_openflow_message(reply, reply_len); return HANDLE; } static void handle_multipart_desc(struct ofp_buffer *ofpbuf) { struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_DESC, sizeof(struct ofp_desc_stats), &mp_reply); if (!reply || !mp_reply) { return; } struct ofp_desc_stats *desc = mp_reply->ofpmp_desc; memset(desc, 0, sizeof(*desc)); snprintf(desc->mfr_desc, sizeof(desc->mfr_desc), "FAST Reference Switch"); snprintf(desc->hw_desc, sizeof(desc->hw_desc), "FAST Virtual datapath"); snprintf(desc->sw_desc, sizeof(desc->sw_desc), "OF1.3 Example Stack"); snprintf(desc->serial_num, sizeof(desc->serial_num), "FAST-0001"); snprintf(desc->dp_desc, sizeof(desc->dp_desc), "FAST educational datapath"); size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_desc_stats); send_openflow_message(reply, reply_len); } static void handle_multipart_flow(struct ofp_buffer *ofpbuf) { struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_FLOW, 0, &mp_reply); if (!reply) { return; } size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart); send_openflow_message(reply, reply_len); } static void handle_multipart_aggregate(struct ofp_buffer *ofpbuf) { struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_AGGREGATE, sizeof(struct ofp_aggregate_stats_reply), &mp_reply); if (!reply || !mp_reply) { return; } struct ofp_aggregate_stats_reply *body = mp_reply->ofpmp_aggregate_reply; memset(body, 0, sizeof(*body)); body->packet_count = host_to_be64(0); body->byte_count = host_to_be64(0); body->flow_count = htonl(0); size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_aggregate_stats_reply); send_openflow_message(reply, reply_len); } static void handle_multipart_table(struct ofp_buffer *ofpbuf) { struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_TABLE, sizeof(struct ofp_table_stats), &mp_reply); if (!reply || !mp_reply) { return; } struct ofp_table_stats *table = mp_reply->table_stats; memset(table, 0, sizeof(*table)); table->table_id = 0; table->active_count = htonl(0); table->lookup_count = host_to_be64(0); table->matched_count = host_to_be64(0); size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_table_stats); send_openflow_message(reply, reply_len); } static void handle_multipart_port_stats(struct ofp_buffer *ofpbuf) { struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_PORT_STATS, sizeof(struct ofp_port_stats), &mp_reply); if (!reply || !mp_reply) { return; } struct ofp_port_stats *stats = mp_reply->ofpmp_port_stats; memset(stats, 0, sizeof(*stats)); stats->port_no = htonl(1); stats->rx_packets = host_to_be64(0); stats->tx_packets = host_to_be64(0); stats->rx_bytes = host_to_be64(0); stats->tx_bytes = host_to_be64(0); stats->rx_dropped = host_to_be64(0); stats->tx_dropped = host_to_be64(0); stats->rx_errors = host_to_be64(0); stats->tx_errors = host_to_be64(0); stats->rx_frame_err = host_to_be64(0); stats->rx_over_err = host_to_be64(0); stats->rx_crc_err = host_to_be64(0); stats->collisions = host_to_be64(0); stats->duration_sec = htonl(0); stats->duration_nsec = htonl(0); size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_port_stats); send_openflow_message(reply, reply_len); } static void handle_multipart_group_features(struct ofp_buffer *ofpbuf) { struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_GROUP_FEATURES, sizeof(struct ofp_group_features), &mp_reply); if (!reply || !mp_reply) { return; } struct ofp_group_features *features = (struct ofp_group_features *)mp_reply->body; memset(features, 0, sizeof(*features)); features->types = htonl(0); features->capabilities = htonl(0); size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_group_features); send_openflow_message(reply, reply_len); } static void fill_port(struct ofp_port *port, uint32_t port_no, const char *name) { memset(port, 0, sizeof(*port)); port->port_no = htonl(port_no); snprintf(port->name, sizeof(port->name), "%s", name); port->curr_speed = htonl(1000000); port->max_speed = htonl(1000000); } static void handle_multipart_port_desc(struct ofp_buffer *ofpbuf) { size_t ports_count = 2; size_t body_len = ports_count * sizeof(struct ofp_port); struct ofp_multipart *mp_reply = NULL; struct ofp_buffer *reply = build_multipart_reply(ofpbuf, OFPMP_PORT_DESC, body_len, &mp_reply); if (!reply || !mp_reply) { return; } struct ofp_port *ports = mp_reply->ofpmp_port_desc; fill_port(&ports[0], 1, "fast-eth1"); fill_port(&ports[1], 2, "fast-eth2"); size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + body_len; send_openflow_message(reply, reply_len); } static enum opfmsg_hook_ret handle_opfmsg_multipart_request(struct ofp_buffer *ofpbuf) { if (ntohs(ofpbuf->header.length) < sizeof(struct ofp_header) + sizeof(struct ofp_multipart)) { printf("multipart request too short\n"); return HANDLE; } struct ofp_multipart *mp = (struct ofp_multipart *)ofpbuf->data; uint16_t type = ntohs(mp->type); printf("multipart request type=%u\n", type); switch (type) { case OFPMP_DESC: handle_multipart_desc(ofpbuf); break; case OFPMP_FLOW: handle_multipart_flow(ofpbuf); break; case OFPMP_AGGREGATE: handle_multipart_aggregate(ofpbuf); break; case OFPMP_TABLE: handle_multipart_table(ofpbuf); break; case OFPMP_PORT_STATS: handle_multipart_port_stats(ofpbuf); break; case OFPMP_GROUP_FEATURES: handle_multipart_group_features(ofpbuf); break; case OFPMP_PORT_DESC: handle_multipart_port_desc(ofpbuf); break; default: printf("unsupported multipart type %u\n", type); break; } return HANDLE; } static enum opfmsg_hook_ret handle_opfmsg_packet_out(struct ofp_buffer *ofpbuf) { struct ofp_packet_out *pkt_out = (struct ofp_packet_out *)&ofpbuf->header; uint16_t actions_len = ntohs(pkt_out->actions_len); uint16_t total_len = ntohs(ofpbuf->header.length); if (total_len < sizeof(struct ofp_packet_out)) { printf("packet_out length %u shorter than header\n", total_len); return HANDLE; } if (actions_len > total_len - sizeof(struct ofp_packet_out)) { printf("packet_out invalid actions_len=%u total_len=%u\n", actions_len, total_len); return HANDLE; } uint32_t in_port = ntohl(pkt_out->in_port); uint8_t *payload = (uint8_t *)pkt_out->actions + actions_len; int payload_len = total_len - (payload - (uint8_t *)&ofpbuf->header); if (payload_len <= 0) { printf("packet_out without payload\n"); return HANDLE; } uint32_t out_port = 0; if (actions_len >= sizeof(struct ofp_action_output)) { struct ofp_action_output *action = (struct ofp_action_output *)pkt_out->actions; out_port = ntohl(action->port); } printf("packet_out in_port=%u out_port=%u len=%d\n", in_port, out_port, payload_len); nms_exec_action(in_port, out_port, (struct eth_header *)payload, payload_len, -1); return HANDLE; } static enum opfmsg_hook_ret handle_opfmsg_flow_mod(struct ofp_buffer *ofpbuf) { uint16_t total_len = ntohs(ofpbuf->header.length); if (total_len < sizeof(struct ofp_header) + sizeof(struct fast_rule)) { printf("flow_mod payload too small: %u\n", total_len); return HANDLE; } struct fast_rule *rule = (struct fast_rule *)ofpbuf->data; print_user_rule(rule); int idx = fast_add_rule(rule); printf("fast_add_rule result index=%d\n", idx); return HANDLE; } static enum opfmsg_hook_ret handle_opfmsg_role_request(struct ofp_buffer *ofpbuf) { size_t reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_role); struct ofp_buffer *reply = build_opfmsg_reply_ofpbuf( OFPT_ROLE_REPLY, ofpbuf->header.xid, reply_len); if (!reply) { return CONTINUE; } struct ofp_role *req = (struct ofp_role *)ofpbuf->data; struct ofp_role *rsp = (struct ofp_role *)reply->data; memcpy(rsp, req, sizeof(*rsp)); send_openflow_message(reply, reply_len); return HANDLE; } /** * * callback 的返回值必须有且只能存在两种返回值: * * 已处理: HANDLE = 0x1, * 不处理:CONTINUE = 0x2 * */ static 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_opfmsg_get_config_request(ofpbuf); case OFPT_MULTIPART_REQUEST: return handle_opfmsg_multipart_request(ofpbuf); case OFPT_PACKET_OUT: return handle_opfmsg_packet_out(ofpbuf); case OFPT_FLOW_MOD: return handle_opfmsg_flow_mod(ofpbuf); case OFPT_ROLE_REQUEST: return handle_opfmsg_role_request(ofpbuf); default: printf(" --do not handle the message!\n"); } //返回不处理状态码 return CONTINUE; } /** 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); //获取 OFPT_HELLO(0) 和 OFPT_FEATURES_REQUEST (5)消息 mask = (1U << OFPT_HELLO) | (1U << OFPT_FEATURES_REQUEST) | (1U << OFPT_GET_CONFIG_REQUEST) | (1U << OFPT_MULTIPART_REQUEST) | (1U << OFPT_PACKET_OUT) | (1U << OFPT_FLOW_MOD) | (1U << OFPT_ROLE_REQUEST); openflow_hook_init(mask,handle_openflow_callback); pause(); return 0; }