563 lines
28 KiB
Typst
563 lines
28 KiB
Typst
#import "labtemplate.typ": *
|
||
#show: nudtlabpaper.with(title: "SDN可编程网络实验",
|
||
author1: "程景愉",
|
||
id1: "202302723005",
|
||
advisor: " 胡罡",
|
||
jobtitle: "教授",
|
||
lab: "306-707",
|
||
date: "2025.1.2",
|
||
header_str: "《网络工程》实验报告",
|
||
)
|
||
|
||
#set page(header: [
|
||
#set par(spacing: 6pt)
|
||
#align(center)[#text(size: 11pt)[《网络工程》实验报告]]
|
||
#v(-0.3em)
|
||
#line(length: 100%, stroke: (thickness: 1pt))
|
||
],)
|
||
|
||
#show heading: it => box(width: 100%)[
|
||
#v(0.50em)
|
||
#set text(font: hei)
|
||
#it.body
|
||
]
|
||
|
||
#outline(title: "目录",depth: 3, indent: 1em)
|
||
#pagebreak()
|
||
#outline(
|
||
title: [图目录],
|
||
target: figure.where(kind: image),
|
||
)
|
||
|
||
#show heading: it => box(width: 100%)[
|
||
#v(0.50em)
|
||
#set text(font: hei)
|
||
#counter(heading).display()
|
||
// #h(0.5em)
|
||
#it.body
|
||
]
|
||
#set enum(indent: 0.5em,body-indent: 0.5em,)
|
||
#pagebreak()
|
||
|
||
= 实验概述
|
||
== 实验内容
|
||
#para[]
|
||
本次综合实验中分有三个实验:
|
||
|
||
+ 基于 SDN 交换机源码处理openflow协议消息
|
||
+ 虚拟网络拓扑实验
|
||
+ DDoS 网络攻击的 SDN 实验
|
||
#para[
|
||
本实验报告重点分析第一个实验的实现细节,并在最后补充介绍本小组的选做实验。
|
||
]
|
||
== 实验要求
|
||
1. 熟悉Openbox-S4的基本功能
|
||
2. 熟悉OpenFlow协议的基本消息格式
|
||
3. 熟悉OpenFlow协议的基本消息处理流程
|
||
// Display inline code in a small box
|
||
// that retains the correct baseline.
|
||
#show raw.where(block: false): it => box(
|
||
text(font: ("JetBrainsMono NF","Noto Fangsong KSS Rotated"), it),
|
||
fill: luma(240),
|
||
inset: (x: 3pt, y: 0pt),
|
||
outset: (y: 3pt),
|
||
radius: 2pt,
|
||
)
|
||
|
||
// Display block code in a larger block
|
||
// with more padding.
|
||
#show raw.where(block: true): it => box(
|
||
text(font: ("JetBrainsMono NF","Noto Fangsong KSS Rotated"), it),
|
||
fill: luma(240),
|
||
inset: 10pt,
|
||
radius: 4pt,
|
||
width: 100%,
|
||
)
|
||
|
||
= 编写SDN交换机源码处理OpenFlow协议消息
|
||
#para[
|
||
本次实验在`main_user_openflow.c`文件中实现了OpenFlow协议处理逻辑。代码通过多个函数处理不同类型的OpenFlow消息,包括Hello消息、Features Request消息、Flow Stats Request消息等。每个函数都根据消息类型生成相应的回复消息,并通过`send_openflow_message`函数发送给控制器。以下将逐一分析每个函数的实现细节。
|
||
]
|
||
== 本次实验所编写的协议
|
||
|
||
#para[
|
||
本次实验实现了OpenFlow协议中的大部分消息处理功能。实验代码涵盖了从交换机特性查询到流表统计、端口统计等多种消息类型的处理。以下是实验编写协议的总结。
|
||
]
|
||
=== 实现的协议
|
||
- OFPT_FEATURES_REQUEST:用于获取交换机支持的流表数量、缓冲区大小等特性信息。对应的处理函数为`handle_opfmsg_features_request`。
|
||
- OFPT_GET_CONFIG_REQUEST:用于查询交换机的配置信息,如Miss Send Length等。对应的处理函数为`handle_ofpmsg_get_config_request`。
|
||
- OFPT_MULTIPART_REQUEST:用于处理多种统计信息请求,包括交换机描述信息、流表信息、端口统计信息等。对应的处理函数包括:
|
||
- `handle_ofpmsg_desc`
|
||
// - `handle_ofpmsg_flow_stats`
|
||
// - `handle_ofpmsg_aggregate`
|
||
- `handle_ofpmsg_table`
|
||
- `handle_ofpmsg_port_stats`
|
||
- `handle_ofpmsg_group_features`
|
||
- `handle_ofpmsg_port_desc`
|
||
- OFPT_PACKET_OUT:用于处理控制器发送的数据包,并根据动作指示将数据包从指定端口发送出去。对应的处理函数为`handle_ofpmsg_packet_out`。
|
||
- OFPT_ROLE_REQUEST:用于配置交换机的角色(如主控制器、从控制器等)。对应的处理函数为`handle__opfmsg_role_request`。
|
||
|
||
== 相关数据结构
|
||
|
||
#para[
|
||
在`main_user_openflow.c`中,定义了一些关键的数据结构和全局变量,用于处理OpenFlow协议的消息。主要的数据结构包括`ofp_header`、`ofp_switch_features`、`ofp_flow_stats`和`ofp_port_stats`等。这些数据结构用于处理OpenFlow协议中的不同消息类型,如交换机特性请求、流表统计请求、端口统计请求等。
|
||
]
|
||
|
||
#para[
|
||
`ofp_header`结构体用于表示OpenFlow消息头,包含协议版本、消息类型、消息长度和事务ID等字段。`ofp_switch_features`结构体用于表示交换机的特性信息,如数据路径ID、缓冲区数量、流表数量等。`ofp_flow_stats`结构体用于表示流表统计信息,如流表项长度、优先级、数据包计数等。`ofp_port_stats`结构体用于表示端口统计信息,如端口号、接收数据包数、发送数据包数等。
|
||
]
|
||
|
||
== 消息头构建
|
||
|
||
#para[
|
||
在OpenFlow协议中,每个消息都有一个消息头,用于标识消息的版本、类型、长度和事务ID。代码中实现了`build_opfmsg_header`函数,用于构建OpenFlow消息头。该函数接收消息长度、消息类型和事务ID作为参数,并填充消息头的各个字段。通过调用该函数,可以确保消息能够被正确解析和处理。
|
||
]
|
||
|
||
== 消息处理函数
|
||
|
||
#para[
|
||
代码中实现了多个OpenFlow消息处理函数,每个函数对应一种OpenFlow消息类型。以下是每个函数的详细分析。
|
||
]
|
||
|
||
=== 处理Hello消息
|
||
|
||
#para[
|
||
`handle_opfmsg_hello`函数用于处理控制器发送的Hello消息。Hello消息是OpenFlow协议中的基础消息,用于交换控制器和交换机之间的协议版本信息。函数首先检查消息头中的`version`字段,判断协议版本是否为1.3。如果版本匹配,则打印接收到的Hello消息;否则,生成一个错误消息并发送给控制器。函数返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_opfmsg_hello(struct ofp_buffer *ofpbuf) {
|
||
if (ofpbuf->header.version == 0x04) {
|
||
printf("RECV HELLO!\n\n\n");
|
||
} else {
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_ERROR, ofpbuf->header.xid, sizeof(struct ofp_header));
|
||
send_openflow_message(ofpbuf_reply, sizeof(struct ofp_header));
|
||
}
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
=== 处理Features Request消息
|
||
|
||
#para[
|
||
`handle_opfmsg_features_request`函数用于处理控制器发送的Features Request消息。该消息用于查询交换机的特性信息,如支持的流表数量、缓冲区大小等。函数生成一个Features Reply消息,并填充交换机的特性信息,如数据路径ID、缓冲区数量、流表数量等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_opfmsg_features_request(struct ofp_buffer *ofpbuf) {
|
||
int feature_reply_len = sizeof(struct ofp_switch_features) + sizeof(struct ofp_header);
|
||
struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_opfmsg_reply_ofpbuf(OFPT_FEATURES_REPLY, ofpbuf->header.xid, feature_reply_len);
|
||
struct ofp_switch_features *feature_reply_msg = (struct ofp_switch_features *)ofpbuf_reply->data;
|
||
|
||
feature_reply_msg->datapath_id = 0x0100000000000000;
|
||
feature_reply_msg->n_buffers = htonl(46);
|
||
feature_reply_msg->n_tables = 3;
|
||
feature_reply_msg->capabilities = 0x7;
|
||
|
||
send_openflow_message(ofpbuf_reply, feature_reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
=== 处理Get Config Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_get_config_request`函数用于处理控制器发送的Get Config Request消息。该消息用于查询交换机的配置信息,如Miss Send Length等。函数生成一个Get Config Reply消息,并填充交换机的配置信息。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_ofpmsg_get_config_request(struct ofp_buffer *ofpbuf) {
|
||
int reply_len = sizeof(struct ofp_switch_config) + sizeof(struct ofp_header);
|
||
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(32);
|
||
|
||
send_openflow_message(ofpbuf_reply, reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
=== 处理Description Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_desc`函数用于处理控制器发送的Description Request消息。该消息用于查询交换机的描述信息,如制造商、硬件版本等。函数生成一个Multipart Reply消息,并填充交换机的描述信息。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
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 = "Wanglixuan";
|
||
static const char *default_hw_desc = "Lixuan_OpenBox";
|
||
static const char *default_sw_desc = "Lixuan_Driver";
|
||
static const char *default_serial_desc = "Lixuan 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;
|
||
}
|
||
```
|
||
|
||
=== 处理Flow Stats Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_flow_stats`函数用于处理控制器发送的Flow Stats Request消息。该消息用于查询交换机的流表统计信息。函数生成一个Multipart Reply消息,并设置消息类型为Flow Stats。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_ofpmsg_flow_stats(struct ofp_buffer *ofpbuf) {
|
||
int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart);
|
||
struct ofp_buffer *reply_buffer = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len);
|
||
struct ofp_multipart *multipart_reply = (struct ofp_multipart *)reply_buffer->data;
|
||
|
||
multipart_reply->type = htons(OFPMP_FLOW);
|
||
multipart_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
|
||
send_openflow_message(reply_buffer, reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
// === 处理Aggregate Stats Request消息
|
||
|
||
// #para[
|
||
// `handle_ofpmsg_aggregate`函数用于处理控制器发送的Aggregate Stats Request消息。该消息用于查询交换机的聚合统计信息。函数生成一个Multipart Reply消息,并填充聚合统计信息,如数据包计数、字节计数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
// ]
|
||
// ```c
|
||
// 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;
|
||
|
||
// ofpmp_reply->type = htons(OFPMP_AGGREGATE);
|
||
// ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
|
||
// ofpmp_reply->ofpmp_aggregate_reply[0].packet_count = htonll(46);
|
||
// ofpmp_reply->ofpmp_aggregate_reply[0].byte_count = htonll(2025);
|
||
// ofpmp_reply->ofpmp_aggregate_reply[0].flow_count = htonll(200);
|
||
|
||
// send_openflow_message(ofpbuf_reply, reply_len);
|
||
// return HANDLE;
|
||
// }
|
||
// ```
|
||
|
||
=== 处理Table Stats Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_table`函数用于处理控制器发送的Table Stats Request消息。该消息用于查询交换机的流表统计信息。函数生成一个Multipart Reply消息,并填充流表统计信息,如匹配计数、查找计数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_ofpmsg_table(struct ofp_buffer *ofpbuf) {
|
||
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);
|
||
|
||
ofpmp_reply->table_stats[0].matched_count = htonll(2025);
|
||
ofpmp_reply->table_stats[0].table_id = 0;
|
||
ofpmp_reply->table_stats[0].lookup_count = htonll(46);
|
||
ofpmp_reply->table_stats[0].active_count = htonl(1);
|
||
|
||
send_openflow_message(ofpbuf_reply, reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
=== 处理Port Stats Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_port_stats`函数用于处理控制器发送的Port Stats Request消息。该消息用于查询交换机的端口统计信息。函数生成一个Multipart Reply消息,并填充端口统计信息,如持续时间、接收数据包数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_ofpmsg_port_stats(struct ofp_buffer *ofpbuf) {
|
||
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;
|
||
|
||
ofpmp_reply->type = htons(OFPMP_PORT_STATS);
|
||
ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO);
|
||
|
||
for (int i = 0; i < nmps.cnt; i++) {
|
||
ofpmp_reply->ofpmp_port_stats[i] = nmps.ports[i].stats;
|
||
ofpmp_reply->ofpmp_port_stats[i].duration_sec = htonl(2025);
|
||
ofpmp_reply->ofpmp_port_stats[i].duration_nsec = htonl(51);
|
||
}
|
||
|
||
send_openflow_message(ofpbuf_reply, reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
=== 处理Group Features Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_group_features`函数用于处理控制器发送的Group Features Request消息。该消息用于查询交换机的组表特性信息。函数生成一个Multipart Reply消息,并填充组表特性信息,如最大组数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_ofpmsg_group_features(struct ofp_buffer *ofpbuf) {
|
||
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);
|
||
group->max_groups[0] = htonl(0xdeadbeef);
|
||
|
||
send_openflow_message(ofpbuf_reply, reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
|
||
=== 处理Port Description Request消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_port_desc`函数用于处理控制器发送的Port Description Request消息。该消息用于查询交换机的端口描述信息。函数生成一个Multipart Reply消息,并填充端口描述信息,如端口状态等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
static enum ofperr handle_ofpmsg_port_desc(struct ofp_buffer *ofpbuf) {
|
||
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 (int 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;
|
||
}
|
||
```
|
||
|
||
=== 处理Packet Out消息
|
||
|
||
#para[
|
||
`handle_ofpmsg_packet_out`函数用于处理控制器发送的Packet Out消息。该消息用于指示交换机将数据包从指定端口发送出去。函数解析消息中的动作列表,判断动作类型是否为`OFPAT_OUTPUT`,并根据动作指示的端口号调用`nms_exec_action`函数将数据包发送出去。函数返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
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 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;
|
||
}
|
||
```
|
||
|
||
=== 处理Role Request消息
|
||
|
||
#para[
|
||
`handle_opfmsg_role_request`函数用于处理控制器发送的Role Request消息。该消息用于配置交换机的角色(如主控制器、从控制器等)。函数生成一个Role Reply消息,并填充角色配置信息。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。
|
||
]
|
||
```c
|
||
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);
|
||
memcpy(ofpbuf_reply->data, ofpbuf->data, sizeof(struct ofp_role));
|
||
ofpbuf_reply->header.type = OFPT_ROLE_REPLY;
|
||
|
||
send_openflow_message(ofpbuf_reply, reply_len);
|
||
return HANDLE;
|
||
}
|
||
```
|
||
#pagebreak()
|
||
== 实验结果
|
||
#para[
|
||
在控制器与交换机之间进行抓包,分析报文的交互过程。控制器发送不同类型的OpenFlow消息给交换机,交换机接收并处理消息,并返回相应的回复消息。通过抓包分析,可以看到消息的交互过程,包括消息头、消息类型、消息长度等字段的解析和处理。用这种方式来验证协议编写的正确性。
|
||
]
|
||
#para[
|
||
实现的子协议种类较多,这里只展示部分报文内容。
|
||
]
|
||
=== OFPT_ROLE_REPLY
|
||
#para[
|
||
OFPT_ROLE_REPLY类型消息。此消息用于配置交换机的角色(如主控制器、从控制器等)。下面的@slave_request 是控制器发送的Role Request消息。
|
||
]
|
||
#figure(image("master.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REQUEST消息",)<slave_request>
|
||
#para[
|
||
如图@slave_reply 所示,交换机接收并处理后返回的Role Reply消息。
|
||
]
|
||
#figure(image("master_reply.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REPLY消息",)<slave_reply>
|
||
#para[
|
||
这说明交换机已经接收到了控制器发送的Role Request消息,并返回了Role Reply消息。
|
||
]
|
||
=== OFPT_MULTIPART_REPLY
|
||
#para[
|
||
OFPMP_DESC类型消息。此消息用于查询交换机的描述信息,包括制造商、硬件版本、软件版本、序列号和数据路径描述等。
|
||
]
|
||
#figure(image("cjy.png",fit:"stretch",format:"png"),caption:"OFPMP_DESC消息",)
|
||
#para[
|
||
可以看到图中的消息包含了制造商、硬件版本、软件版本、序列号和数据路径描述等信息(此处使用了自己的信息进行标记与区分)。
|
||
]
|
||
#para[
|
||
OFPMP_TABLE类型消息。此消息用于查询交换机的流表统计信息,包括匹配计数、查找计数等。
|
||
]
|
||
#figure(image("cjytable.png",fit:"stretch",format:"png"),caption:"OFPMP_TABLE消息",)
|
||
#para[
|
||
可以看到图中的消息包含了匹配计数、查找计数等信息(此处修改为了自己设置的值)。
|
||
]
|
||
#pagebreak()
|
||
|
||
= 实验总结
|
||
|
||
#para[
|
||
本次实验通过编写SDN交换机源码处理OpenFlow协议消息,深入理解了OpenFlow协议的基本消息格式和处理流程。实验涵盖了从交换机特性查询到流表统计、端口统计等多种消息类型的处理,成功实现了大部分OpenFlow协议的核心功能。通过实验,我不仅掌握了OpenFlow协议的基本工作原理,还熟悉了如何通过代码实现协议消息的解析与响应。
|
||
]
|
||
|
||
#para[
|
||
在实验过程中,我首先熟悉了Openbox-S4的基本功能,并通过编写代码实现了对OpenFlow协议消息的处理。实验代码中,我实现了包括Hello消息、Features Request消息、Flow Stats Request消息等在内的多种消息处理函数。每个函数都根据消息类型生成相应的回复消息,并通过`send_openflow_message`函数发送给控制器。通过抓包分析,我验证了消息的交互过程,确保协议编写的正确性。
|
||
]
|
||
|
||
#para[
|
||
实验中的难点在于如何正确处理不同类型的OpenFlow消息,并确保消息的格式和内容符合协议规范。通过查阅OpenFlow协议规范和参考相关文献,我逐步解决了这些问题,并成功实现了协议的核心功能。
|
||
]
|
||
|
||
#para[
|
||
实验结果表明,我编写的代码能够正确处理控制器发送的OpenFlow消息,并返回相应的回复消息。通过抓包分析,我验证了消息的交互过程,确保协议编写的正确性。实验的成功不仅加深了我对OpenFlow协议的理解,也提升了我的编程能力和网络协议分析能力。
|
||
]
|
||
|
||
#para[
|
||
总的来说,本次实验达到了预期的目标,成功实现了OpenFlow协议的核心功能。通过实验,我不仅掌握了OpenFlow协议的基本工作原理,还熟悉了如何通过代码实现协议消息的解析与响应。未来,我可以在此基础上进一步扩展功能,如实现流表规则的动态添加和删除,以更好地支持SDN网络的灵活性和可扩展性。
|
||
]
|
||
|
||
#pagebreak()
|
||
|
||
= 选做实验介绍
|
||
|
||
#para[
|
||
本小组了解了虚拟网络拓扑实验和DDoS网络攻击的SDN实验的基本内容,但由于时间和精力有限,最终选择只完成DDoS网络攻击的SDN实验。以下是对该实验的简要介绍。
|
||
]
|
||
== 实验原理
|
||
|
||
#para[本实验通过搭建一个基于 SDN 的网络环境,利用 OpenBox-S4 设备启动 OVS 交换机、sFlow-RT 流量监控和 Floodlight 控制器,模拟 DDoS 攻击并实现防御。实验的核心原理是通过 SDN 控制器(Floodlight)动态下发流表规则,检测并阻断异常流量。]
|
||
|
||
#para[在实验中,主机 A 作为攻击者,使用 DDoS 攻击工具向主机 B(靶机)发送大量请求数据包,模拟 DDoS 攻击。sFlow-RT 用于实时监控网络流量,检测异常流量模式。Floodlight 控制器根据 sFlow-RT 的检测结果,下发流表规则到 OVS 交换机,丢弃匹配的异常流量,从而实现对 DDoS 攻击的防御。]
|
||
|
||
#para[实验的关键在于通过 SDN 控制器的集中控制能力,动态调整网络流表,快速响应并阻断攻击流量。这种基于 SDN 的防御机制能够有效应对 DDoS 攻击,减少对网络资源的消耗,并提高网络的整体安全性。]
|
||
#para[
|
||
实验步骤参考《SDN网络-DDOS攻击案例操作手册.pdf》。下面仅列出部分步骤或结果,供参考。
|
||
]
|
||
=== 发起 DDoS 攻击
|
||
#para[
|
||
1.在主机 A 上使用攻击工具或脚本发起 DDoS 攻击,向主机 B 发送大量请求数据包。
|
||
2.监控 sFlow-RT 界面,观察网络流量的变化,检测到异常流量模式。
|
||
]
|
||
#figure(image("遭受DDoS攻击.png",format:"png",width: 100%,fit:"stretch"),caption: "遭受 DDoS 攻击")<being_attacked_by_DDoS>
|
||
#para[
|
||
3.记录攻击开始时间和网络状态。
|
||
4.查看流表项,发现大量异常流量匹配规则。
|
||
]
|
||
#figure(image("flow_entry.png",format:"png",width: 100%,fit:"stretch"),caption: "流表项")<flow_table>
|
||
|
||
=== 防御 DDoS 攻击
|
||
#para[
|
||
1.使用 Floodlight 控制器下发流表规则,阻断异常流量:
|
||
]
|
||
```python
|
||
import httplib
|
||
import json
|
||
|
||
class StaticFlowPusher(object):
|
||
def __init__(self, server):
|
||
self.server = server
|
||
|
||
def get(self, data):
|
||
ret = self.rest_call({}, 'GET')
|
||
return json.loads(ret[2])
|
||
|
||
def set(self, data):
|
||
ret = self.rest_call(data, 'POST')
|
||
return ret[0] == 200
|
||
|
||
def remove(self, objtype, data):
|
||
ret = self.rest_call(data, 'DELETE')
|
||
return ret[0] == 200
|
||
|
||
def rest_call(self, data, action):
|
||
path = '/wm/staticflowpusher/json'
|
||
headers = {
|
||
'Content-type': 'application/json',
|
||
'Accept': 'application/json',
|
||
}
|
||
```
|
||
```python
|
||
body = json.dumps(data)
|
||
conn = httplib.HTTPConnection(self.server, 8080)
|
||
conn.request(action, path, body, headers)
|
||
response = conn.getresponse()
|
||
ret = (response.status, response.reason, response.read())
|
||
print ret
|
||
conn.close()
|
||
return ret
|
||
|
||
pusher = StaticFlowPusher('127.0.0.1')
|
||
|
||
flowbe2 = {
|
||
'switch': "00:00:00:0a:35:00:5f:68",
|
||
"name": "flow-2",
|
||
"cookie": "G0",
|
||
"priority": "100",
|
||
"active": "true",
|
||
"eth_type": "0x800",
|
||
"in_port": "0",
|
||
"ipv4_src": "192.168.2.111",
|
||
"ipv4_dst": "192.168.2.119",
|
||
"actions": "drop"
|
||
}
|
||
|
||
pusher.set(flowbe2)
|
||
```
|
||
#para[
|
||
其中关键部分在于下发流表规则,将匹配的数据包丢弃(```python "actions": "drop"```)。
|
||
2.检查流量图,发现异常流量被丢弃。
|
||
]
|
||
#figure(image("防御DDoS攻击.png",format:"png",width: 100%,fit:"stretch"),caption: "丢弃异常流量")<defend_DDoS>
|
||
#para[
|
||
3.检查流表项,发现异常流量匹配规则消失。
|
||
]
|
||
#figure(image("flow_entry2.png",format:"png",width: 100%,fit:"stretch"),caption: "流表项")<flow_table_defend>
|
||
|
||
== 选做实验总结
|
||
#para[
|
||
本次实验通过搭建基于 OpenBox-S4 设备的 SDN 网络环境,模拟 DDoS 攻击和防御过程。通过实验,我了解了 sFlow-RT 的配置和使用方法,掌握了基于 Floodlight 控制器的 DDoS 防御原理和方法。实验中,我成功模拟了 DDoS 攻击,观察了网络流量的变化,学会了使用 Floodlight 控制器下发流表规则,阻断异常流量。通过实验,我深入理解了 SDN 网络中 DDoS 攻击的特点和防御策略,提高了网络安全意识和实践能力。
|
||
]
|
||
#pagebreak()
|
||
#show heading: it => box(width: 100%)[
|
||
#v(0.50em)
|
||
#set text(font: hei)
|
||
// #counter(heading).display()
|
||
// #h(0.5em)
|
||
#it.body
|
||
]
|
||
#bibliography("ref.yml",full: true,title: "参考文献",style:"gb-7714-2015-numeric")
|
||
/*
|
||
根据这个网站的格式示范https://github.com/typst/hayagriva/blob/main/docs/file-format.md
|
||
为这些网页生成.yml文件
|
||
https://opennetworking.org/wp-content/uploads/2014/10/openflow-spec-v1.3.0.pdf
|
||
https://www.cnblogs.com/goldsunshine/p/7262484.html
|
||
https://www.jianshu.com/p/acfeae1771b3
|
||
https://www.jianshu.com/p/82e238eb8d14
|
||
*/
|