POF技术分享(二):POF交换机源码结构

前言:

华为基于POF协议已经开发了相应的软件交换机,并且具备POF的一些基本功能。上一节对POF基本原理进行阐述,为了透彻理解POF原理,并能在其上进行相应研究与SDN应用开发,本文将对POF交换机源码进行解读。

一:函数调用关系图

POF交换机先会进行基本配置的初始化、交换机资源初始化等,然后开启交换机与控制器通信进程,建立连接进行通信,最后开启基于流表的数据包匹配与处理的进程(主要位于POF/datapath中)进入正常工作状态。

以上是基本流程,为了对交换机源码的整个脉络有一个清楚了解,特意按照执行流程绘制了函数关系调用图,以供解读源码时候参考对照。

图注:蓝色块为主函数;紫色块是main函数中调用的主要函数,会相应进行不同服务;淡蓝色为被调用的函数;粉色理解为开启的线程,会进行数据包接收、发送等,其中深红色为两个重要线程服务(和控制器交互、数据包匹配处理),之后会着重分析,这里面包括绿色块。蓝色线条上序号标记函数调用顺序,紫色线是逻辑顺序。

二:源码结构:

POF源码文件结构较OVS清楚简单许多,主要有五个文件夹目录:common/datapath/include/local_resource/switch_control。根据上图的函数调用关系图,这里基于文件结构对图中涉及到的主要函数分别做简单分析:

1 switch_control目录:包含主函数,并含有与控制器交互的主要文件。

1.1 pof_switch_control.c:一个重要的文件,包含主函数,和各种初始化工作等。
main():主函数

  • pof交换机的配置初始化(pof_set_init_config函数)
  • 资源初始化(pof_localresource_init函数)
  • 建立与控制器的通信(pofsc_init函数)
  • datapath初始化(pof_datapath_init函数)等。

poflr_init():建立与控制器的通信

  • 设置ipport等连接信息
  • 创建给控制器发送消息的发送队列,即待发送的消息都会先写入这个发送队列中(pofbf_queue_create函数)
  • 开启线程,通过状态机来处理OF消息(pofsc_main_task函数)
  • 开启线程,非同步的从发送队列中取出消息发送给controller(pofsc_send_msg_task函数)
  • 开启线程, 在状态下POFCS_CHANNEL_RUN进行echo消息保活

pofsc_main_task(): 根据状态转移与controller保持消息交互

  • conn_desc_ptr维护交换机和控制器交互阶段的状态,根据这些状态不同,while循环会进行不同的处理。
  • POFCS_CHANNEL_INVALID状态时,创建socket客户端,但此时还没开始建立连接,pofsc_create_socket函数)
  • POFCS_CHANNEL_CONNECTING状态会进行尝试建立TCP socket连接(pofsc_connect函数)。建立成功,则设置状态为POFCS_CHANNEL_CONNECTED
  • POFCS_CHANNEL_CONNECTED状态时,交换机则会发送hello消息。发送成功,则设置状态为POFCS
    _HELLO
  • POFCS_HELLO状态时,则从socket缓存中读取消息。消息类型是控制器发来的hello,则设置状态为POFCS_REQUEST_FEATURE,否则设置状态为POFCS_CHANNEL_INVALID,重新建立连接。
  • 依次经过feature和config等阶段状态,然后进入关键阶段POFCS_CHANNEL_RUN
  • POFCS_CHANNEL_RUN状态时,即进入和控制器正常的交互状态。从socket接收缓存中读取消息内容,根据消息类型进行处理(pofsc_run_process函数)

pofsc_run_process():POFCS_CHANNEL_RUN状态下接收处理controller发来的消息

  • POFT_ECHO_REPLY消息只更新最新echo时间
  • 其他消息类型则进行具体处理,如flowmod处理(pof_parse_msg_from_controller函数)
  • pofsc_send_msg_task():异步取出发送队列消息发送给控制器
  • 检测是否为config/feature/Run状态,是则从发送队列中读取消息进行发送。
  • - 调用和控制器建立的socket接口,通过write函数进行发送。
  • 发送成功则while循环中继续读取发送,发送失败则把消息写回入发送队列,设置连接状态为POFCS_CHANNEL_INVALID,跳出while循环,意味着需要重新和控制器建立连接。
  • pofsc_echo_timer():在POFCS_CHANNEL_RUN状态下进行echo消息发送。

1.2 pof_config.c:一些交换机配置函数

  • pof_set_init_config()
  • 对g_states(pof_state结构体)的默认初始化(pof_set_init_states)
  • 通过pof交换机开启参数进行初始化配置(如设置controller ip,port,pof_set_init_config_by_command函数);
  • 通过文件进行初始化配置(pof_set_init_config_by_file函数)

1.3 pof_parse.c:只含有一个函数,即对controller发送的消息进行类型解析并回复等处理

  • pof_parse_msg_from_controller():对echo消息、flowmod、tablemod等消息进行具体处理。

2 local_resource目录:交换机资源管控,如流表、端口资源等

2.1 pof_local_resource.c:

pof_local_resource_init(): 端口和流表资源的初始化

  • 物理端口信息初始化(poflr_init_port函数)
  • 流表资源(包括组表和meter表等)初始化,如各种表空间分配等操作(poflr_init_table_resource函数)

2.2 剩下的几个文件实现meter表、group表、端口port等相关资源初始化等

3 datapath目录:端口接收packet并进行流表匹配处理

3.1 pof_datapath.c

pof_datapath_init():初始化datapath模块,创建packet的接收与发送队列,创建datapath线程、端口packet接收线程和端口packet发送线程

  • 创建packet的接收队列g_pofdp_recv_q_id
  • 创建packet的发送队列g_pofdp_send_q_id
  • 创建datapath线程(pofdp_main_task函数)
  • 创建端口packet发送线程(pofdp_send_raw_task函数)
  • 创建每个端口的packet接收线程(pofdp_create_port_listen_task函数)
  • 创建端口检测线程,端口改变则上报controller(poflr_port_detect_task函数)

pofdp_main_task():循环接收端口的packet进行转发处理,前一个包结束转发处理后才处理下一个包

  • 设定第一个默认instruction,即goto第一个表(set_goto_first_table_instruction),然后进入循环处理
  • 从端口packet接收队列中读取packet数据(pofdp_recv_raw)
  • packet长度检测、第一个表存在性检测,检测出错则释放此packet缓存
  • packet转发处理(pofdp_forward函数)

pofdp_forward():对packet进行流表匹配查找,并进行instruction处理,直到发送或是丢弃。

  • 初始化元数据(init_packet_metadata函数)
  • 第一个instruction的执行,即goto表1,然后继续流表匹配处理(pofdp_instruction_execute函数)

pofdp_send_raw_task():创建线程,循环读取端口发送队列的packet,进行发送

  • 创建发送socket,进入while循环
  • 从端口发送队列中读取packet内容(pofbf_queue_read函数)
  • 通过与物理端口绑定的socket进行packet发送(sendto函数)

pofdp_create_port_listen_task():设置端口的packet接收线程

pofdp_recv_raw_task():创建线程,循环读取端口packet,并放入端口接收队列中

  • 创建并绑定端口的socket,保持实时监听状态(socket,bind)。然后进入循环处理
  • 通过socket接收端口消息,存入buf
  • 检测端口的openflow使能、包长度,并根据规则过滤包
  • 将当前端口接受的packet放入端口接收队列中(pofbf_queue_write函数)

3.2 pof_instruction.c

pofdp_instruction_execute():循环读取packet的instructions,逐一执行。

  • while检测packet的instruction是否执行完
  • 对packet执行instruction(excute_##INSTRUCTIONS_NAME()函数)

excute_##INSTRUCTIONS_NAME():一些instruction的执行函数

  • execute_METER():速率限制
  • execute_WRITE_METADATA():将instruction中value字段数据写入matadata中。
  • excute_WRITE_METADATA():将packet中相应字段数据写入matadata中。
  • execute_GOTO_DIRECT_TABLE():根据全局table_id跳转到指定表,并且不需要匹配,直接得到跳转表中的指定的相应表项,执行表项动作。
  • execute_GOTO_TABLE():跳转表前先通过packet计算出key,跳转后直接用key进行匹配。
  • execute_APPLY_ACTIONS():包含不同action,如OUTPUT、ADD字段等。
  • execute_WRITE_ACTIONS(): 目前无,待开发。
  • execute_CLEAR_ACTIONS():待开发
  • execute_EXPERIMENTER():待开发

4 include目录:存放POF交换机的全部自定义的头文件,供其他文件调用。

5 common目录:最主要是action和Instruction相关的函数定义在这里。

  • pof_byte_trans:主要存放一些action和Instruction相关的函数等。
  • pof_log_print:和log打印相关函数。

后记:

本文对POF交换机源码执行的主要流程进行总结,并绘制成函数关系调用图,可以供大家分析源码时候参考,此外,基于文件结构,对调用图中涉及到的主要函数进行简单的功能分析。有了以上代码了解,后文将会对POF交换机如何与控制器通信、数据包如何根据POF进行匹配与action处理等做进一步学习分析。

作者简介:

晏思宇,2014/09-至今,北京邮电大学信息与通信工程学院未来网络理论与应用实验室(FNL实验室)攻读硕士研究生,主要研究方向为SDN、Open vSwtich、Ryu等。
个人博客www.yansy.xyz


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/15686.html
分享到:
相关文章
条评论

登录后才可以评论

晏思宇 发表于16-01-21
1