Files
NE_YuR/openflow/main_user_openflow.c
2025-11-06 00:01:42 +08:00

519 lines
18 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************************
* 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;
}