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 源代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/713421.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

XGBoost预测及调参过程(+变量重要性)--血友病计数数据

所使用的数据是血友病数据&#xff0c;如有需要&#xff0c;可在主页资源处获取&#xff0c;数据信息如下&#xff1a; 读取数据及数据集区分 数据预处理及区分数据集代码如下&#xff08;详细预处理说明见上篇文章--随机森林&#xff09;&#xff1a; import pandas as pd im…

RPG游戏完整指南

环境&#xff1a;unity2021urp 本教程教大家如何使用Unity创建一个RPG游戏&#xff0c;玩家可以在城镇场景中进行导航并寻找战斗&#xff0c;并在战斗中遇到不同类型的敌人。玩家可以向敌人施加不同的动作&#xff0c;如&#xff1a;常规攻击和撤离。这会是一个十分有趣的体验。…

AI时代新爬虫:网站自动转LLM数据,firecrawl深度玩法解读

在大模型的时代&#xff0c;爬虫技术也有了很多新的发展&#xff0c;最近出现了专门针对大模型来提取网站信息的爬虫&#xff0c;一键将网页内容转换为LLM-ready的数据。今天我们介绍其中的开源热门代表&#xff1a;firecrawl。 firecrawl 是什么 FireCrawl是一款创新的爬虫工…

数据资产治理与数据质量提升:构建完善的数据治理体系,确保数据资产的高质量与准确性

一、引言 随着信息技术的迅猛发展&#xff0c;数据已经成为企业和社会发展的重要资产。然而&#xff0c;数据资产的有效治理与数据质量的提升&#xff0c;是企业实现数字化转型、提升竞争力的关键。本文旨在探讨数据资产治理与数据质量提升的重要性&#xff0c;并提出构建完善…

开源高效API管理工具:RAP

RAP&#xff1a;简化API开发&#xff0c;提升团队协作效率- 精选真开源&#xff0c;释放新价值。 概览 RAP&#xff08;RESTful API Project&#xff09;是一个开源的API管理工具&#xff0c;由阿里巴巴团队开发并维护。它旨在帮助前后端开发人员通过一个统一的平台来设计、开…

Linux 按键输入实验

Linux 按键输入实验 1、添加 pinctrl 节点 首先修改在设备树里面添加关于按键的节点。I.MX6U-ALPHA 开发板上的 KEY 使用了 UART1_CTS_B 这个 PIN&#xff0c;打开 imx6ull-alientekemmc.dts&#xff0c;在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_key”的子…

华为机考入门python3--(36)牛客36-字符串加密

分类&#xff1a;字符串 知识点&#xff1a; 判断一个元素是否在集合中 if char not in key_set 计算字母差 index ord(char) - ord(a) 题目来自【牛客】 # 生成加密表 def generate_cipher_table(key):key_set set()cipher_table ""# 去重for char in k…

TVBOX 最新版下载+视频源教程

下载链接 wx 搜索 Geek 前端 发送电视资源进行获取 操作教程

经典电源电路基础(变压-整流-滤波-稳压)

1.电源电路的功能和组成 电子电路中的电源一般是低压直流电&#xff0c;先把220v交流电变换成低压直流电&#xff0c;再用整流电路变成脉动的直流电&#xff0c;最后用滤波电路滤除掉脉动直流中的交流成分后才能得到直流电。有的电子设备对电源的质量要求很高&#xff0c;所以…

uniapp中unicloud接入支付宝订阅消息完整教程

经过无数次的尝试,终于还是让我做出来了 准备工作 设置接口加签方式 使用支付宝小程序订阅消息,首先要设置接口加签方式,需要下载支付宝开放平台密钥工具,按照步骤生成秘钥,然后按照支付宝设置密钥加签方式添加接口加签方式。 有一点需要注意的,因为要在云函数中使用,…

Flutter IOS 打包上架踩坑

前言 Flutter 作为一款跨平台的移动应用开发框架&#xff0c;凭借其高效、灵活和美观的特性&#xff0c;受到了越来越多开发者的青睐。 然而&#xff0c;当开发者们倾注心血完成 Flutter iOS 应用开发后&#xff0c;如何将应用成功上架至苹果商店&#xff08;App Store&#…

摄影师在人工智能竞赛中与机器较量并获胜

摄影师在人工智能竞赛中与机器较量并获胜 自从生成式人工智能出现以来&#xff0c;由来已久的人机大战显然呈现出一边倒的态势。但是有一位摄影师&#xff0c;一心想证明用人眼拍摄的照片是有道理的&#xff0c;他向算法驱动的竞争对手发起了挑战&#xff0c;并取得了胜利。 迈…

[大模型]XVERSE-MoE-A4.2B Transformers 部署调用

XVERSE-MoE-A4.2B介绍 XVERSE-MoE-A4.2B 是由深圳元象科技自主研发的支持多语言的大语言模型&#xff08;Large Language Model&#xff09;&#xff0c;使用混合专家模型&#xff08;MoE&#xff0c;Mixture-of-experts&#xff09;架构&#xff0c;模型的总参数规模为 258 亿…

树莓派等Linux开发板上使用 SSD1306 OLED 屏幕,bullseye系统 ubuntu,debian

Raspberry Pi OS Bullseye 最近发布了,随之而来的是许多改进,但其中大部分都在引擎盖下。没有那么多视觉差异,最明显的可能是新的默认桌面背景,现在是大坝或湖泊上的日落。https://www.the-diy-life.com/add-an-oled-stats-display-to-raspberry-pi-os-bullseye/ 通过这次操…

简易开发一个app

即时设计网站 即时设计 - 可实时协作的专业 UI 设计工具 需要先设计好UI界面 上传到codefun 首次需要安装 自动生成代码 打开hb软件 新建项目 打开创建的项目 删除代码 复制代码过去 下载图片 将图片放到文件夹里 改为这种格式 index.vue 如果不需要uni-app导航栏可以修改 …

Vue项目实践:使用滚动下拉分页优化大数据展示页面【通过防抖加标志位进行方案优化】

Vue项目实践&#xff1a;使用滚动下拉分页优化大数据展示页面 前言 传统的分页机制通过点击页码来加载更多内容&#xff0c;虽然直观&#xff0c;但在处理大量数据时可能会导致用户体验不佳。相比之下&#xff0c;滚动下拉分页能够在用户滚动到页面底部时自动加载更多内容&…

C++全栈聊天项目(22) 气泡聊天对话框

气泡聊天框设计 我们期待实现如下绿色的气泡对话框 对于我们自己发出的信息&#xff0c;我们可以实现这样一个网格布局管理 NameLabel用来显示用户的名字&#xff0c;Bubble用来显示聊天信息&#xff0c;Spacer是个弹簧&#xff0c;保证将NameLabel,IconLabel&#xff0c;Bubb…

Android中的Audio系统框架分析(一)

概述 Audio系统是Android 平台重要的组成部分&#xff0c;我们将从以下几个方面来讲解&#xff1a; 一Audio基础知识讲解 二、Android系统中Audio框架 Audio基础知识讲解 我们大家知道声音是由物体振动产生的声波。是通过介质&#xff08;空气或固体、液体&#xff09;传播并…

【C++高阶】C++继承学习手册:全面解析继承的各个方面

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;模板进阶 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 继承 &#x1f4d6;1. 继承的概念及定义…

每日一练——用队列实现栈

225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; Queue.h #pragma once #include<stdlib.h> #include<assert.h> #include<stdbool.h>typedef int QDataType;typedef struct QNode {QDataType data;struct QNode* next; } QNode;typedef struct …