openbox lab report initialized
This commit is contained in:
463
openbox/openbox_1.txt
Normal file
463
openbox/openbox_1.txt
Normal file
@ -0,0 +1,463 @@
|
||||
|
||||
|
||||
#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[
|
||||
本次实验中有三个小实验:
|
||||
+ 基于Openbox-S4测试SDN交换功能
|
||||
+ 基于SDN 交换机源码处理openflow协议消息
|
||||
+ 实验三 使用 REST API 接口查询交换机的相关功能数据
|
||||
本实验报告重点分析第二个小实验的实现细节。
|
||||
]
|
||||
== 实验要求
|
||||
#para[
|
||||
1. 熟悉Openbox-S4的基本功能
|
||||
2. 熟悉OpenFlow协议的基本消息格式
|
||||
3. 熟悉OpenFlow协议的基本消息处理流程
|
||||
4. 熟悉REST API接口的基本使用
|
||||
]
|
||||
// Display inline code in a small box
|
||||
// that retains the correct baseline.
|
||||
#show raw.where(block: false): it => box(
|
||||
text(font: ("Consolas","FangSong_GB2312"), 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 => block(
|
||||
text(font: ("Consolas","FangSong_GB2312"), 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协议中的大部分消息处理功能。实验代码涵盖了从交换机特性查询到流表统计、端口统计等多种消息类型的处理。以下是实验编写协议的总结。
|
||||
]
|
||||
=== 实现的协议
|
||||
#para[
|
||||
- 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[
|
||||
本次实验由组内成员共同完成,每个成员负责不同的消息处理函数。以下是每个成员负责的函数列表。
|
||||
#align(center)[#table(
|
||||
columns: (55pt, auto),
|
||||
rows: 15pt,
|
||||
inset: 3pt,
|
||||
align: horizon+center,
|
||||
table.header(
|
||||
[分工], [函数]
|
||||
),
|
||||
table.cell(rowspan: 7)[王李烜],
|
||||
"handle_opfmsg_features_request",
|
||||
"handle_ofpmsg_desc",
|
||||
"handle_ofpmsg_flow_stats",
|
||||
"handle_ofpmsg_aggregate",
|
||||
"handle_ofpmsg_table",
|
||||
"handle_ofpmsg_port_desc",
|
||||
"handle_opfmsg_role_request",
|
||||
table.cell(rowspan: 2)[廖中煜],
|
||||
"handle_ofpmsg_get_config_request",
|
||||
"handle_ofpmsg_packet_out",
|
||||
table.cell(rowspan: 2)[王誉潞],
|
||||
"handle_ofpmsg_port_stats",
|
||||
"handle_ofpmsg_group_features",
|
||||
)]
|
||||
]
|
||||
== 相关数据结构
|
||||
|
||||
#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;
|
||||
}
|
||||
```
|
||||
]
|
||||
== 实验结果
|
||||
#para[
|
||||
在控制器与交换机之间进行抓包,分析报文的交互过程。控制器发送不同类型的OpenFlow消息给交换机,交换机接收并处理消息,并返回相应的回复消息。通过抓包分析,可以看到消息的交互过程,包括消息头、消息类型、消息长度等字段的解析和处理。用这种方式来验证协议编写的正确性。
|
||||
|
||||
实现的子协议种类较多,这里只展示部分报文内容。
|
||||
]
|
||||
=== OFPT_ROLE_REPLY
|
||||
#para[
|
||||
+ OFPT_ROLE_REPLY类型消息。此消息用于配置交换机的角色(如主控制器、从控制器等)。下面的@slave_request 是控制器发送的Role Request消息。
|
||||
#figure(image("slave.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REQUEST消息",)<slave_request>
|
||||
如图@slave_reply 所示,交换机接收并处理后返回的Role Reply消息。
|
||||
#figure(image("slave_reply.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REPLY消息",)<slave_reply>
|
||||
这说明交换机已经接收到了控制器发送的Role Request消息,并返回了Role Reply消息。
|
||||
]
|
||||
=== OFPT_MULTIPART_REPLY
|
||||
#para[
|
||||
+ OFPMP_DESC类型消息。此消息用于查询交换机的描述信息,包括制造商、硬件版本、软件版本、序列号和数据路径描述等。
|
||||
#figure(image("lixuanwang.png",fit:"stretch",format:"png"),caption:"OFPMP_DESC消息",)
|
||||
可以看到图中的消息包含了制造商、硬件版本、软件版本、序列号和数据路径描述等信息(此处使用了自己的信息进行标记与区分)。
|
||||
+ OFPMP_TABLE类型消息。此消息用于查询交换机的流表统计信息,包括匹配计数、查找计数等。
|
||||
#figure(image("table.png",fit:"stretch",format:"png"),caption:"OFPMP_TABLE消息",)
|
||||
可以看到图中的消息包含了匹配计数、查找计数等信息(此处修改为了自己设置的值)。
|
||||
]
|
||||
= 实验总结
|
||||
#para[
|
||||
|
||||
]
|
||||
#show heading: it => box(width: 100%)[
|
||||
#v(0.50em)
|
||||
#set text(font: hei)
|
||||
// #counter(heading).display()
|
||||
// #h(0.5em)
|
||||
#it.body
|
||||
]
|
||||
#pagebreak()
|
||||
#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
|
||||
*/
|
||||
Reference in New Issue
Block a user