bug fixed
This commit is contained in:
BIN
openflow.pcap
Normal file
BIN
openflow.pcap
Normal file
Binary file not shown.
@ -26,11 +26,11 @@
|
||||
#include <fast.h>
|
||||
#include <main_libofp.h>
|
||||
#include <ofp_v4.h>
|
||||
|
||||
void nms_exec_action(u32 inport,u32 outport,struct eth_header *eth,int len,int hit_idx);
|
||||
void pkt_print(u8 *data, u16 len);
|
||||
#include <stdint.h>
|
||||
|
||||
extern void nms_exec_action(u32 inport,u32 outport,struct eth_header *eth,int len,int hit_idx);
|
||||
extern void pkt_print(u8 *data, u16 len);
|
||||
|
||||
|
||||
|
||||
extern uintptr_t *flow_stats_addr;
|
||||
@ -221,10 +221,10 @@ handle_ofpmsg_desc(struct ofp_buffer *ofpbuf)
|
||||
(struct ofp_buffer *)build_opfmsg_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_mfr_desc = "Chengjingyu_Networks";
|
||||
static const char *default_hw_desc = "Jingyu_OpenBox";
|
||||
static const char *default_sw_desc = "Jingyu_Driver";
|
||||
static const char *default_serial_desc = "Jingyu OpenBox Series";
|
||||
static const char *default_dp_desc = "None";
|
||||
|
||||
ofpmp_reply->type = htons(OFPMP_DESC);
|
||||
|
||||
253
openflow/main_user_openflow_analysis.md
Normal file
253
openflow/main_user_openflow_analysis.md
Normal file
@ -0,0 +1,253 @@
|
||||
# `main_user_openflow.c` 函数功能详解
|
||||
|
||||
本文档详细介绍了 `main_user_openflow.c` 文件中每个函数的功能、参数和实现逻辑。该文件主要负责处理和响应来自控制器的各种 OpenFlow 1.3 (OFP13) 消息。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
1. [辅助函数](#1-辅助函数)
|
||||
- [`htonll`](#htonll)
|
||||
- [`ntohll`](#ntohll)
|
||||
2. [报文构建函数](#2-报文构建函数)
|
||||
- [`build_opfmsg_header`](#build_opfmsg_header)
|
||||
- [`build_opfmsg_reply_ofpbuf`](#build_opfmsg_reply_ofpbuf)
|
||||
3. [OpenFlow 消息处理函数](#3-openflow-消息处理函数)
|
||||
- [`handle_opfmsg_hello`](#handle_opfmsg_hello)
|
||||
- [`handle_opfmsg_features_request`](#handle_opfmsg_features_request)
|
||||
- [`handle_ofpmsg_get_config_request`](#handle_ofpmsg_get_config_request)
|
||||
- [`handle_ofpmsg_desc`](#handle_ofpmsg_desc)
|
||||
- [`handle_ofpmsg_flow_stats`](#handle_ofpmsg_flow_stats)
|
||||
- [`handle_ofpmsg_aggregate`](#handle_ofpmsg_aggregate)
|
||||
- [`handle_ofpmsg_table`](#handle_ofpmsg_table)
|
||||
- [`handle_ofpmsg_port_stats`](#handle_ofpmsg_port_stats)
|
||||
- [`handle_ofpmsg_group_features`](#handle_ofpmsg_group_features)
|
||||
- [`handle_ofpmsg_port_desc`](#handle_ofpmsg_port_desc)
|
||||
- [`handle_ofpmsg_packet_out`](#handle_ofpmsg_packet_out)
|
||||
- [`handle__opfmsg_role_request`](#handle__opfmsg_role_request)
|
||||
4. [核心回调与主函数](#4-核心回调与主函数)
|
||||
- [`handle_openflow_callback`](#handle_openflow_callback)
|
||||
- [`main`](#main)
|
||||
|
||||
---
|
||||
|
||||
## 1. 辅助函数
|
||||
|
||||
### `htonll`
|
||||
```c
|
||||
static inline uint64_t htonll(uint64_t n)
|
||||
```
|
||||
- **功能**: 将64位无符号整数从主机字节序(Host Byte Order)转换网络字节序(Network Byte Order)。
|
||||
- **参数**:
|
||||
- `n`: 需要转换的64位无符号整数。
|
||||
- **返回值**: 转换后的网络字节序64位整数。
|
||||
- **逻辑**: 通过检查 `htonl(1)` 的结果来判断当前系统是否为大端序。如果是小端序,则将高32位和低32位分别转换后交换位置。
|
||||
|
||||
### `ntohll`
|
||||
```c
|
||||
static inline uint64_t ntohll(uint64_t n)
|
||||
```
|
||||
- **功能**: 将64位无符号整数从网络字节序转换为主机字节序。
|
||||
- **参数**:
|
||||
- `n`: 需要转换的64位网络字节序整数。
|
||||
- **返回值**: 转换后的主机字节序64位整数。
|
||||
- **逻辑**: 与 `htonll` 类似,根据系统的大小端情况进行相应的转换。
|
||||
|
||||
---
|
||||
|
||||
## 2. 报文构建函数
|
||||
|
||||
### `build_opfmsg_header`
|
||||
```c
|
||||
void build_opfmsg_header(struct ofp_header *ofpbuf_header, uint16_t len, uint8_t type, uint32_t xid)
|
||||
```
|
||||
- **功能**: 构建一个标准的 OpenFlow 报文头。
|
||||
- **参数**:
|
||||
- `ofpbuf_header`: 指向 `ofp_header` 结构体的指针,用于填充报文头信息。
|
||||
- `len`: 整个 OpenFlow 报文的总长度。
|
||||
- `type`: OpenFlow 报文的类型 (例如 `OFPT_HELLO`, `OFPT_FEATURES_REPLY` 等)。
|
||||
- `xid`: 事务ID (Transaction ID),用于匹配请求和响应。
|
||||
- **逻辑**:
|
||||
1. 设置版本号为 `OFP13_VERSION` (0x04)。
|
||||
2. 使用 `htons` 将长度 `len` 转换网络字节序后填充。
|
||||
3. 设置报文类型 `type`。
|
||||
4. 设置事务ID `xid`。
|
||||
|
||||
### `build_opfmsg_reply_ofpbuf`
|
||||
```c
|
||||
u8 *build_opfmsg_reply_ofpbuf(uint8_t type, uint32_t xid, uint16_t len)
|
||||
```
|
||||
- **功能**: 分配内存并构建一个用于回复的 OpenFlow 报文缓冲区。
|
||||
- **参数**:
|
||||
- `type`: 回复报文的类型。
|
||||
- `xid`: 对应请求报文的事务ID。
|
||||
- `len`: 回复报文的总长度。
|
||||
- **返回值**: 指向新分配和初始化的报文缓冲区的指针 (`u8 *`)。
|
||||
- **逻辑**:
|
||||
1. 使用 `malloc` 分配指定长度 `len` 的内存。
|
||||
2. 使用 `memset` 将分配的内存清零。
|
||||
3. 调用 `build_opfmsg_header` 函数填充报文的头部信息。
|
||||
4. 返回指向该缓冲区的指针。
|
||||
|
||||
---
|
||||
|
||||
## 3. OpenFlow 消息处理函数
|
||||
|
||||
这些函数遵循 `handle_openflow_callback` 的规范,返回 `HANDLE` (0x1) 表示消息已处理,返回 `CONTINUE` (0x2) 表示未处理。
|
||||
|
||||
### `handle_opfmsg_hello`
|
||||
- **对应消息**: `OFPT_HELLO`
|
||||
- **功能**: 处理与控制器建立连接时的 `HELLO` 消息。
|
||||
- **逻辑**:
|
||||
1. 检查接收到的 `HELLO` 消息中的 OpenFlow 版本号。
|
||||
2. 如果版本号是 `0x04` (OpenFlow 1.3),则打印 "RECV HELLO!"。
|
||||
3. 如果版本号不匹配,则构建一个 `OFPT_ERROR` 消息并发送给控制器,表明版本不兼容。
|
||||
4. 返回 `HANDLE` 表示消息已处理。
|
||||
|
||||
### `handle_opfmsg_features_request`
|
||||
- **对应消息**: `OFPT_FEATURES_REQUEST`
|
||||
- **功能**: 响应控制器查询交换机功能的请求。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_FEATURES_REPLY` 类型的回复报文。
|
||||
2. 填充 `ofp_switch_features` 结构体,包含交换机的功能信息,如:
|
||||
- `datapath_id`: 交换机的唯一标识符。
|
||||
- `n_buffers`: 交换机可以缓存的数据包数量。
|
||||
- `n_tables`: 支持的流表数量(此处硬编码为1)。
|
||||
- `capabilities`: 支持的特性(如流统计、端口统计等)。
|
||||
3. 发送该回复报文给控制器。
|
||||
4. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_get_config_request`
|
||||
- **对应消息**: `OFPT_GET_CONFIG_REQUEST`
|
||||
- **功能**: 响应控制器查询交换机配置的请求。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_GET_CONFIG_REPLY` 类型的回复报文。
|
||||
2. 填充 `ofp_switch_config` 结构体,包含交换机的配置信息,如:
|
||||
- `flags`: 配置标志。
|
||||
- `miss_send_len`: 当发生 table-miss 时,发送到控制器的报文最大长度。
|
||||
3. 发送该回复报文。
|
||||
4. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_desc`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_DESC`)
|
||||
- **功能**: 响应控制器查询交换机描述信息的请求。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_MULTIPART_REPLY` 类型的回复报文。
|
||||
2. 设置 multipart 类型为 `OFPMP_DESC`。
|
||||
3. 填充 `ofp_desc_stats` 结构体,包含制造商、硬件、软件、序列号等描述信息(此处使用硬编码的字符串)。
|
||||
4. 发送该回复报文。
|
||||
5. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_flow_stats`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_FLOW`)
|
||||
- **功能**: 响应控制器查询流表统计信息的请求。
|
||||
- **逻辑**:
|
||||
1. 遍历全局流表统计地址数组 `flow_stats_addr`,计算所有有效流表项的总长度。
|
||||
2. 构建一个足够大的 `OFPT_MULTIPART_REPLY` 回复报文。
|
||||
3. 设置 multipart 类型为 `OFPMP_FLOW`。
|
||||
4. 再次遍历 `flow_stats_addr`,将每个有效的流表统计信息 (`ofp_flow_stats`) 拷贝到回复报文中。
|
||||
5. 发送该回复报文。
|
||||
6. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_aggregate`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_AGGREGATE`)
|
||||
- **功能**: 响应控制器查询聚合统计信息(总流数、总包数、总字节数)的请求。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_MULTIPART_REPLY` 回复报文,类型为 `OFPMP_AGGREGATE`。
|
||||
2. 初始化 `flow_count`, `packet_count`, `byte_count` 为 0。
|
||||
3. 遍历 `flow_stats_addr`,累加每个流的包计数和字节计数,并统计流的数量。
|
||||
- **注意**: 此处代码会更新每个流的 `duration_sec` 和 `duration_nsec`,并为 `packet_count` 和 `byte_count` 填充了硬编码的示例值。
|
||||
4. 将聚合统计结果填充到 `ofp_aggregate_stats_reply` 结构体中。
|
||||
5. 发送该回复报文。
|
||||
6. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_table`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_TABLE`)
|
||||
- **功能**: 响应控制器查询流表自身统计信息的请求。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_MULTIPART_REPLY` 回复报文,类型为 `OFPMP_TABLE`。
|
||||
2. 填充 `ofp_table_stats` 结构体,包含活动流表项数量、查询次数、匹配次数等信息(此处硬编码为1个流表,活动数量为1)。
|
||||
3. 发送该回复报文。
|
||||
4. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_port_stats`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_PORT_STATS`)
|
||||
- **功能**: 响应控制器查询端口统计信息的请求。
|
||||
- **逻辑**:
|
||||
1. 根据全局端口信息结构体 `nmps` 中的端口数量 `cnt`,构建一个 `OFPT_MULTIPART_REPLY` 回复报文。
|
||||
2. 设置 multipart 类型为 `OFPMP_PORT_STATS`。
|
||||
3. 遍历所有端口,将每个端口的统计信息 `nmps.ports[i].stats` 拷贝到回复报文中,并计算和填充端口的活动时间。
|
||||
4. 发送该回复报文。
|
||||
5. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_group_features`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_GROUP_FEATURES`)
|
||||
- **功能**: 响应控制器查询交换机组表(Group Table)特性的请求。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_MULTIPART_REPLY` 回复报文。
|
||||
2. 填充 `ofp_group_features` 结构体,设置其类型为 `OFPMP_GROUP_FEATURES`。
|
||||
3. 发送该回复报文。
|
||||
4. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_port_desc`
|
||||
- **对应消息**: `OFPT_MULTIPART_REQUEST` (子类型 `OFPMP_PORT_DESC`)
|
||||
- **功能**: 响应控制器查询端口描述信息的请求。
|
||||
- **逻辑**:
|
||||
1. 根据全局端口信息结构体 `nmps` 中的端口数量 `cnt`,构建一个 `OFPT_MULTIPART_REPLY` 回复报文。
|
||||
2. 设置 multipart 类型为 `OFPMP_PORT_DESC`。
|
||||
3. 遍历所有端口,将每个端口的状态描述信息 `nmps.ports[i].state` 拷贝到回复报文中。
|
||||
4. 发送该回复报文。
|
||||
5. 返回 `HANDLE`。
|
||||
|
||||
### `handle_ofpmsg_packet_out`
|
||||
- **对应消息**: `OFPT_PACKET_OUT`
|
||||
- **功能**: 处理控制器下发的 `Packet Out` 消息,该消息指示交换机将特定数据包通过指定端口发送出去。
|
||||
- **逻辑**:
|
||||
1. 解析 `ofp_packet_out` 消息,提取出 `in_port`(入端口)、`actions_len`(动作列表长度)以及附带的数据包(`eth`)。
|
||||
2. 检查 `actions_len`:
|
||||
- 如果为 0,表示没有指定动作,默认执行泛洪(`OFPP_FLOOD`)。
|
||||
- 如果不为 0,则遍历动作列表。
|
||||
3. 对于 `OFPAT_OUTPUT` 类型的动作,提取 `port`(出端口),并调用 `nms_exec_action` 函数将数据包从指定端口发送出去。
|
||||
4. 返回 `HANDLE`。
|
||||
|
||||
### `handle__opfmsg_role_request`
|
||||
- **对应消息**: `OFPT_ROLE_REQUEST`
|
||||
- **功能**: 处理控制器设置或查询交换机角色的请求(如 Master, Slave)。
|
||||
- **逻辑**:
|
||||
1. 构建一个 `OFPT_ROLE_REPLY` 类型的回复报文。
|
||||
2. 将请求中的角色信息 (`ofp_role`) 直接拷贝到回复报文中。
|
||||
3. 发送该回复报文。
|
||||
4. 返回 `HANDLE`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心回调与主函数
|
||||
|
||||
### `handle_openflow_callback`
|
||||
```c
|
||||
int handle_openflow_callback(struct ofp_buffer *ofpbuf, int len)
|
||||
```
|
||||
- **功能**: 这是注册给 OpenFlow 库的核心回调函数,作为所有进入的 OpenFlow 消息的分发中枢。
|
||||
- **参数**:
|
||||
- `ofpbuf`: 指向包含 OpenFlow 消息的缓冲区的指针。
|
||||
- `len`: 消息的总长度。
|
||||
- **返回值**:
|
||||
- `HANDLE` (0x1): 如果消息被此回调中的某个函数处理了。
|
||||
- `CONTINUE` (0x2): 如果消息类型不被支持或未被处理,交由后续处理。
|
||||
- **逻辑**:
|
||||
1. 从报文头中提取消息类型 `oftype`。
|
||||
2. 使用 `switch` 语句根据 `oftype` 将消息分发给对应的 `handle_...` 函数。
|
||||
3. 对于 `OFPT_MULTIPART_REQUEST` 类型的消息,会进一步检查其子类型(`multipart->type`),并分发给相应的处理函数(如 `handle_ofpmsg_desc`, `handle_ofpmsg_flow_stats` 等)。
|
||||
4. 如果 `switch` 语句中没有匹配的类型,则打印未处理信息并返回 `CONTINUE`。
|
||||
|
||||
### `main`
|
||||
```c
|
||||
int main(int argc, char* argv[])
|
||||
```
|
||||
- **功能**: 程序的主入口点。
|
||||
- **逻辑**:
|
||||
1. 调用 `ofp_init(argc, argv)` 初始化 OpenFlow 环境。
|
||||
2. 定义一个 `mask` 变量,用于指定程序希望监听和处理哪些类型的 OpenFlow 消息。
|
||||
3. 通过位或运算 (`|`) 将多个消息类型的掩码(如 `MASK_HELLO`, `MASK_FEATURES_REQUEST` 等)组合起来,赋值给 `mask`。
|
||||
4. 调用 `openflow_hook_init(mask, handle_openflow_callback)`,将 `mask` 和核心回调函数 `handle_openflow_callback` 注册到 OpenFlow 库。这样,只有 `mask` 中指定类型的消息到达时,`handle_openflow_callback` 才会被调用。
|
||||
5. 调用 `pause()`,使程序进入挂起状态,等待网络事件(即等待 OpenFlow 消息的到来)。
|
||||
6. 程序将在此处循环等待和处理消息,直到被终止。
|
||||
Binary file not shown.
Reference in New Issue
Block a user