Open vSwitch 中 vswitchd 事件上报

2024-06-16 13:20

本文主要是介绍Open vSwitch 中 vswitchd 事件上报,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 一、数据包转发流程与 vswitchd 事件上报

        Open vSwitch 的数据包转发流程如下图所示:

        在数据包的转发流程中,提到过慢速路径的概念:即当数据包在内核空间无法完全处理时,会产生 upcall 调用,将数据包从内核空间转发到用户空间进行处理,对应上图中的步骤(1→2→3→4→5→6→7)。

        这里图中的步骤(3)对应的是 vswitchd 守护进程与控制器的通信过程,可以细分为两个部分:vswitchd 事件上报和 OpenFlow 流表下发。所谓的 vswitchd 事件上报指的是 vswitchd 守护进程也无法完全处理数据包,需要将信息上报给控制器进行决策;所谓的 OpenFlow 流表下发指的是控制器在收到  vswitchd 上报的信息之后,将相应流表传输到 vswitchd 守护进程的过程。

Tips:对于 OpenFlow 流表下发这个过程而言,Open vSwitch 或者说是整个领域有一套广泛约定的流程,即 OpenFlow 协议,这里不做展开。本文重点关注 vswitchd 事件上报的过程。

二、vswitchd 事件上报的应用场景

        按照数据包的处理流程,当 Datapath 模块无法完全处理数据包时,会产生 upcall 调用,将数据包交给 vswitchd 守护进程。于是这里就存在一个问题:

vswitchd 守护进程在收到数据包后一定会上报给控制器吗?

答:不一定。原因如下:

        在 Open vSwitch 守护进程的 upcall 处理 和 Open vSwitch 中 upcall 消息的类型 这两篇文章中详细讨论过:

  • 对于 upcall 消息而言,只有 MISS 和 ACTION 这两种主要类型,而其他类型都是这两种基本类型的细化。
  • 对于不同的 upcall 类型,vswitchd 守护进程中的 upcall 消息处理函数 process_upcall() 会执行不同的处理逻辑。

        其中,当内核空间的 Datapath 模块匹配不到流表项时,将会产生 MISS 类型的 upcall 消息,在处理过程中相应地调用 upcall_xlate(),并不涉及和控制器通信的部分。

        当消息类型为 CONTROLLER_UPCALL 类型时(注意这是 ACTION 类型的细化),则 vswitchd 守护进程会与控制器进行通信。

        

Tips:细心的你可能早就注意到了,在数据包转发的流程图中,所有步骤的数字,只有第三步是带括号的,而其他步骤是不带括号的。这就是因为并不是所有的 upcall 调用都会产生 vswitchd 守护进程与控制器的通信,而是根据需要或者说是设定的规则来进行的。

三、vswitchd 事件上报机制实现

        在 Open vSwitch 守护进程的 upcall 处理 中讨论过 process_upcall() 对于 CONTROLLER_UPCALL 类型 upcall 消息的处理:

    case CONTROLLER_UPCALL:{struct user_action_cookie *cookie = &upcall->cookie;......const struct frozen_state *state = &recirc_node->state;struct ofproto_async_msg *am = xmalloc(sizeof *am);*am = (struct ofproto_async_msg) {.controller_id = cookie->controller.controller_id,.oam = OAM_PACKET_IN,.pin = {.up = {.base = {.packet = xmemdup(dp_packet_data(packet), dp_packet_size(packet)),.packet_len = dp_packet_size(packet),.reason = cookie->controller.reason,.table_id = state->table_id,.cookie = get_32aligned_be64(&cookie->controller.rule_cookie),.userdata = (recirc_node->state.userdata_len ? xmemdup(recirc_node->state.userdata, recirc_node->state.userdata_len) : NULL),.userdata_len = recirc_node->state.userdata_len,},},.max_len = cookie->controller.max_len,},};if (cookie->controller.continuation) {am->pin.up.stack = (state->stack_size ? xmemdup(state->stack, state->stack_size) : NULL),am->pin.up.stack_size = state->stack_size,am->pin.up.mirrors = state->mirrors,am->pin.up.conntracked = state->conntracked,am->pin.up.actions = (state->ofpacts_len ? xmemdup(state->ofpacts, state->ofpacts_len) : NULL),am->pin.up.actions_len = state->ofpacts_len,am->pin.up.action_set = (state->action_set_len ? xmemdup(state->action_set, state->action_set_len) : NULL),am->pin.up.action_set_len = state->action_set_len,am->pin.up.bridge = upcall->ofproto->uuid;am->pin.up.odp_port = upcall->packet->md.in_port.odp_port;}......ofproto_dpif_send_async_msg(upcall->ofproto, am);}break;

        这段代码主要用于构造 ofproto_async_msg 信息,并通过 ofproto_dpif_send_async_msg(upcall->ofproto, am) 函数将构造好的 ofproto_async_msg 消息发送给控制器。其中 ofproto_dpif_send_async_msg() 函数存储在 ovs-main/ofproto/ofproto-dpif.c 文件中:

/* Appends 'am' to the queue of asynchronous messages to be sent to the controller. * Takes ownership of 'am' and any data it points to. */
void ofproto_dpif_send_async_msg(struct ofproto_dpif *ofproto, struct ofproto_async_msg *am) {if (!guarded_list_push_back(&ofproto->ams, &am->list_node, 1024)) {COVERAGE_INC(packet_in_overflow);ofproto_async_msg_free(am);}/* Wakes up main thread for packet-in I/O. */seq_change(ofproto->ams_seq);
}

        通过观察可以发现,这个函数主要用于向异步消息队列中添加消息,并唤醒主线程进行处理。函数首先使用 guarded_list_push_back() 函数将 am->list_node 添加到 ofproto->ams 中,相应的 guarded_list_push_back() 函数存储在 ovs-main/lib/guarded-list.c 文件中:

/* If 'list' has fewer than 'max' elements, adds 'node' at the end of the list and returns the number of elements now on the list.* If 'list' already has at least 'max' elements, returns 0 without modifying the list. */
size_t guarded_list_push_back(struct guarded_list *list, struct ovs_list *node, size_t max) {size_t retval = 0;ovs_mutex_lock(&list->mutex);if (list->n < max) {ovs_list_push_back(&list->list, node);retval = ++list->n;}ovs_mutex_unlock(&list->mutex);return retval;
}

        如果队列已满,则使用 COVERAGE_INC(packet_in_overflow) 维护溢出统计信息,并通过 ofproto_async_msg_free(am) 释放相应资源,相应的 ofproto_async_msg_free() 函数存储在 ovs-main/ofproto/connmgr.c 文件中:

void ofproto_async_msg_free(struct ofproto_async_msg *am) {free(am->pin.up.base.packet);free(am->pin.up.base.userdata);free(am->pin.up.stack);free(am->pin.up.actions);free(am->pin.up.action_set);free(am);
}

        在进行接收后(无论成功与否),都会通过 seq_change(ofproto->ams_seq) 唤醒主线程进行数据包处理,相应的 seq_change() 函数存储在 ovs-main/lib/seq.c 文件中:

/* Increments 'seq''s sequence number, waking up any threads that are waiting on 'seq'. */
void seq_change(struct seq *seq)OVS_EXCLUDED(seq_mutex) {ovs_mutex_lock(&seq_mutex);seq_change_protected(seq);ovs_mutex_unlock(&seq_mutex);
}

Tips:通过上面的讨论,可以发现交换机和控制器的通信过程其实是在 ofproto 层实现的。

总结:

        最后列举一些交换机不需要走控制器的场景:

  • DHCP、DNS 等
  • upcall 调用类型为 sflow 时走 sflow 相应的流程
  • upcall 调用类型为 ipfix 时走 ipfix 相应的流程

总之就是说 vswitchd 事件上报不是数据包转发流程(或者慢速路径)中的必要过程

        由于本人水平有限,以上内容如有不足之处欢迎大家指正(评论区/私信均可)。

参考资料:

Open vSwitch 官网

Open vSwitch 源代码 GitHub

2015 FOSDEM - OVS Stateful Services

Open vSwitch 守护进程的 upcall 处理-CSDN博客

Open vSwitch 中 upcall 消息的类型-CSDN博客

Open vSwitch v2.17.10 LTS 源代码

这篇关于Open vSwitch 中 vswitchd 事件上报的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1066568

相关文章

Ollama整合open-webui的步骤及访问

《Ollama整合open-webui的步骤及访问》:本文主要介绍如何通过源码方式安装OpenWebUI,并详细说明了安装步骤、环境要求以及第一次使用时的账号注册和模型选择过程,需要的朋友可以参考... 目录安装环境要求步骤访问选择PjrIUE模型开始对话总结 安装官方安装地址:https://docs.

Python中的异步:async 和 await以及操作中的事件循环、回调和异常

《Python中的异步:async和await以及操作中的事件循环、回调和异常》在现代编程中,异步操作在处理I/O密集型任务时,可以显著提高程序的性能和响应速度,Python提供了asyn... 目录引言什么是异步操作?python 中的异步编程基础async 和 await 关键字asyncio 模块理论

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

【经验交流】修复系统事件查看器启动不能时出现的4201错误

方法1,取得『%SystemRoot%\LogFiles』文件夹和『%SystemRoot%\System32\wbem』文件夹的权限(包括这两个文件夹的所有子文件夹的权限),简单点说,就是使你当前的帐户拥有这两个文件夹以及它们的子文件夹的绝对控制权限。这是最简单的方法,不少老外说,这样一弄,倒是解决了问题。不过对我的系统,没用; 方法2,以不带网络的安全模式启动,运行命令行,输入“ne

BT天堂网站挂马事件后续:“大灰狼”远控木马分析及幕后真凶调查

9月初安全团队披露bt天堂网站挂马事件,该网站被利用IE神洞CVE-2014-6332挂马,如果用户没有打补丁或开启安全软件防护,电脑会自动下载执行大灰狼远控木马程序。 鉴于bt天堂电影下载网站访问量巨大,此次挂马事件受害者甚众,安全团队专门针对该木马进行严密监控,并对其幕后真凶进行了深入调查。 一、“大灰狼”的伪装 以下是10月30日一天内大灰狼远控的木马样本截图,可以看到该木马变种数量不

Open a folder or workspace... (File -> Open Folder)

问题:vscode Open with Live Server 时 显示Open a folder or workspace... (File -> Open Folder)报错 解决:不可以单独打开文件1.html ; 需要在文件夹里打开 像这样

android java.io.IOException: open failed: ENOENT (No such file or directory)-api23+权限受权

问题描述 在安卓上,清单明明已经受权了读写文件权限,但偏偏就是创建不了目录和文件 调用mkdirs()总是返回false. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_E

react笔记 8-19 事件对象、获取dom元素、双向绑定

1、事件对象event 通过事件的event对象获取它的dom元素 run=(event)=>{event.target.style="background:yellowgreen" //event的父级为他本身event.target.getAttribute("aid") //这样便获取到了它的自定义属性aid}render() {return (<div><h2>{

react笔记 8-18 事件 方法 定义方法 获取/改变数据 传值

1、定义方法并绑定 class News extends React.Component {constructor(props) {super(props)this.state = {msg:'home组件'}}run(){alert("我是一个run") //方法写在类中}render() {return (<div><h2>{this.state.msg}</h2><button onCli