Files
NE_YuR/openflow/main_user_openflow_analysis.md
2025-11-12 09:01:03 +08:00

314 lines
14 KiB
Markdown
Raw Permalink 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_user_openflow.c` 函数功能详解
本文档详细介绍了 `main_user_openflow.c` 文件中每个函数的功能、参数和实现逻辑。该文件主要负责处理和响应来自控制器的各种 OpenFlow 1.3 (OFP13) 消息。
---
## 目录
- [`main_user_openflow.c` 函数功能详解](#main_user_openflowc-函数功能详解)
- [目录](#目录)
- [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)
- [5. 已实现的协议类型总结](#5-已实现的协议类型总结)
- [A. `handle_openflow_callback` 中处理的类型](#a-handle_openflow_callback-中处理的类型)
- [B. 与 `README.txt` 的比较](#b-与-readmetxt-的比较)
---
## 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. 程序将在此处循环等待和处理消息,直到被终止。
---
## 5. 已实现的协议类型总结
### A. `handle_openflow_callback` 中处理的类型
`main_user_openflow.c` 文件中的 `handle_openflow_callback` 函数是主要的消息分发器。它直接处理以下消息类型:
- **`OFPT_HELLO`**: 管理与控制器的初始握手过程。
- **`OFPT_FEATURES_REQUEST`**: 响应控制器,提供交换机的功能特性。
- **`OFPT_GET_CONFIG_REQUEST`**: 响应控制器,提供交换机的当前配置。
- **`OFPT_PACKET_OUT`**: 处理控制器下发的数据包,并从交换机指定端口发出。
- **`OFPT_ROLE_REQUEST`**: 处理控制器的角色变更请求(如 Master/Slave
- **`OFPT_MULTIPART_REQUEST`**: 用于请求各种统计和状态信息的复合类型。已实现的子类型包括:
- **`OFPMP_DESC`**: 交换机的硬件/软件描述信息。
- **`OFPMP_FLOW`**: 单个流的统计信息。
- **`OFPMP_AGGREGATE`**: 聚合统计信息(总流数、包数、字节数)。
- **`OFPMP_TABLE`**: 流表的统计信息。
- **`OFPMP_PORT_STATS`**: 物理或逻辑端口的统计信息。
- **`OFPMP_GROUP_FEATURES`**: 组表的特性。
- **`OFPMP_PORT_DESC`**: 端口的描述信息。
### B. 与 `README.txt` 的比较
`README.txt` 文件提供了一个相似的列表,但存在一个显著差异:
- **`OFPT_FLOW_MOD` (类型 14)**: `README.txt` 文件列出了用于添加流规则的 `OFPT_FLOW_MOD`(记录为 `OFPT_FLOW=14`)。虽然 `README` 提到了用于此目的的 `fast_add_rule` 函数,但在 `main_user_openflow.c``handle_openflow_callback` 函数中**并无**直接处理 `OFPT_FLOW_MOD` 消息的 `case` 分支。这表明该功能可能未完全实现、在其他地方处理,或者 `README.txt` 中的文档领先于当前文件中的具体实现。
根据 `main_user_openflow.c` 中的可执行代码路径,只有 A 部分列出的消息类型被主回调循环主动处理。