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