519 lines
18 KiB
C
519 lines
18 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>
|
||
|
||
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;
|
||
}
|