ovs-vswitchd的启动分析

news2025/1/12 2:51:40

ovs-vswitchd的启动分析(无修改源码)

(一)主要数据结构和概念了解

1.概念

在 OVS 中, 有几个非常重要的概念:

Bridge: Bridge 代表一个以太网交换机(Switch),一个主机中可以创建一个或者多个 Bridge 设备。

Port: 端口与物理交换机的端口概念类似,每个 Port 都隶属于一个 Bridge。

Interface: 连接到 Port 的网络接口设备。在通常情况下,Port 和 Interface 是一对一的关系, 只有在配置 Port 为 bond 模式后,Port 和 Interface 是一对多的关系。

当我们创建了一个交换机(网桥)以后,此时网络功能不受影响,但是会产生一个虚拟网卡,名字就是brname,之所以会产生一个虚拟网卡,是为了实现接下来的网桥(交换机)功能。

有了这个交换机以后,我还需要为这个交换机增加端口(port),一个端口,就是一个物理网卡,当网卡加入到这个交换机之后,其工作方式就和普通交换机的一个端口的工作方式类似了

这里要特别注意,网卡加入网桥以后,要按照网桥的工作标准工作,那么加入的一个端口就必须是以混杂模式工作,工作在链路层,处理2层的帧,所以这个port就不需要配置IP了。(你没见过哪个交换的端口有IP的吧)

那么接下来你可能会问,通常的交换机不都是有一个管理接口,可以telnet到交换机上进行配置吧,那么在OVS中创建的虚拟交换机有木有这种呢,有的!上面既然创建交换机brname的时候产生了一个虚拟网口brname,那么,你给这个虚拟网卡配置了IP以后,就相当于给交换机的管理接口配置了IP,此时一个正常的虚拟交换机就搞定了。

2.数据结构

在ofproto-provider.h中注释里是这样说的。

这里定义了四类数据结构:

Struct ofproto表示一个交换机

Struct ofport表示交换机上的一个端口

Struct rule表示交换机上的一条flow规则

Struct ofgroup表示一个flow规则组

(二)main主函数分析

在文件openvswitch-2.11.4/vswitchd/ovs-vswitchd.c中!

Openvswitch主要管理两种类型的设备,一个是创建的拟网桥,一个是连接到虚拟网桥上的设备

int
main(int argc, char *argv[])
{
    ...   
    线程开启、网桥初始化等等
    ...

    while (!exiting) {
        memory_run();
        if (memory_should_report()) {
            struct simap usage;

            simap_init(&usage);
            bridge_get_memory_usage(&usage);
            memory_report(&usage);
            simap_destroy(&usage);
        }
        bridge_run();  //其中bridge_run就是初始化数据库中已经创建的虚拟网桥。
        unixctl_server_run(unixctl);
        netdev_run();  //在内核中添加虚拟网卡

        memory_wait();
        bridge_wait();
        unixctl_server_wait(unixctl);
        netdev_wait();
        if (exiting) {
            poll_immediate_wake();
        }
        poll_block();
        if (should_service_stop()) {
            exiting = true;
        }
    }
    
    ...
    退出和销毁操作
    ...

    return 0;
}

(三)虚拟网桥的初始化bridge_run

OVS源码--openflow(四) - 程序员大本营

在文件openvswitch-2.11.4/vswitchd/bridge.c中!

bridge_run --调用--> 

void
bridge_run(void)
{

    bridge_run__();
  if (ovsdb_idl_get_seqno(idl) != idl_seqno ||
        if_notifier_changed(ifnotifier)) {
      ...
        bridge_reconfigure(cfg ? cfg : &null_cfg);
      ...
    }
}

分支(一):主要会用到

bridge_run__ --调用--> ofproto_run让每一个网桥去执行他对应的功能

static void
bridge_run__(void)
{
    ......
    其他操作
    ......

    /* Let each bridge do the work that it needs to do. */
    HMAP_FOR_EACH (br, node, &all_bridges) {
        ofproto_run(br->ofproto);
    }
}

在文件openvswitch-2.11.4/ofproto/ofproto-dpif.c中!

ofproto_run --回调--> run方法

const struct ofproto_class ofproto_dpif_class = {
    ...
    run,
    ...
  port_add,
   ...
};

int
ofproto_run(struct ofproto *p)  //--------------重点
{
    error = p->ofproto_class->run(p);

    ......

    connmgr_run(p->connmgr, handle_openflow);

    return error;
}

在文件openvswitch-2.11.4/ofproto/ofproto-dpif.c中!

run方法会初始化netflow, sflow, ipfix,stp, rstp, mac address learning等一系列操作。

同时也会去校验流表项规则是否过期!!!

static int
run(struct ofproto *ofproto_)
{
    stp_run(ofproto);
    rstp_run(ofproto);

    new_dump_seq = seq_read(udpif_dump_seq(ofproto->backer->udpif));

    if (ofproto->dump_seq != new_dump_seq) {
        struct rule *rule, *next_rule;
if (ofproto->dump_seq != new_dump_seq) {
        struct rule *rule, *next_rule;
        long long now = time_msec();
        /* We know stats are relatively fresh, so now is a good time to do some
         * periodic work. */
        ofproto->dump_seq = new_dump_seq;

        ovs_mutex_lock(&ofproto_mutex);
        LIST_FOR_EACH_SAFE (rule, next_rule, expirable,
                            &ofproto->up.expirable) {
            rule_expire(rule_dpif_cast(rule), now); //-------这里校验是否超时
        }
        ovs_mutex_unlock(&ofproto_mutex);

    }
    return 0;
}

分支(二):不会被用到,了解即可

bridge_reconfigure(从ovsdb-server里面读取出来的配置) --调用--> bridge_add_ports对于每一个网桥,将网卡添加进去

static void
bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
{

    HMAP_FOR_EACH (br, node, &all_bridges) {
        bridge_add_ports(br, &br->wanted_ports);
        shash_destroy(&br->wanted_ports);
    }

    bridge_run__();
}

bridge_add_ports --调用--> bridge_add_ports__ --调用--> iface_create --调用--> iface_do_create --调用--> netdev_open和ofproto_port_add

int
ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev,
                 ofp_port_t *ofp_portp)
{

    error = ofproto->ofproto_class->port_add(ofproto, netdev);

}

ofproto_port_add --回调--> port_add --调用--> dpif_port_add

int
dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop)
{
    error = dpif->dpif_class->port_add(dpif, netdev, &port_no);
}

dpif_port_add --回调--> port_add/dpif_netdev_port_add

const struct dpif_class dpif_netdev_class = {
    "netdev",
    .... 
  dpif_netdev_port_add,
   ....
};

dpif_netdev_port_add --调用-->  do_add_port

static int
dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
                     odp_port_t *port_nop)
{
    struct dp_netdev *dp = get_dp_netdev(dpif);

    ovs_mutex_lock(&dp->port_mutex);
    dpif_port = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
if (!error) {
        *port_nop = port_no;
        error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
    }
    ovs_mutex_unlock(&dp->port_mutex);

    return error;
}

do_add_port这里会调用内核模块openvswitch.ko,在内核中添加虚拟网卡。

static int
do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
            odp_port_t port_no)
    OVS_REQUIRES(dp->port_mutex)
{
    struct dp_netdev_port *port;
    int error;

    /* Reject devices already in 'dp'. */
    if (!get_port_by_name(dp, devname, &port)) {
        return EEXIST;
    }

    error = port_create(devname, type, port_no, &port);
    if (error) {
        return error;
    }

    hmap_insert(&dp->ports, &port->node, hash_port_no(port_no));
    seq_change(dp->port_seq);

    reconfigure_datapath(dp);

    return 0;
}

(四)虚拟网卡的初始化(与设备关联)netdev_run

在文件openvswitch-2.11.4/lib/netdev.c:中!

void netdev_run(void)
    OVS_EXCLUDED(netdev_mutex)
{
    netdev_initialize();

    struct netdev_registered_class *rc;
    CMAP_FOR_EACH (rc, cmap_node, &netdev_classes) {
        if (rc->class->run) {
            rc->class->run(rc->class);
        }
    }
}

依次循环调用netdev_classes中的每一个run。

对于不同类型的虚拟网卡,都有对应的netdev_class。

#define NETDEV_LINUX_CLASS_COMMON                               \
    .run = netdev_linux_run,                                    \
   ...

NETDEV_LINUX_CLASS_COMMON

const struct netdev_class netdev_linux_class = {
    NETDEV_LINUX_CLASS_COMMON,
    LINUX_FLOW_OFFLOAD_API,
    .type = "system",
    .construct = netdev_linux_construct,
    .get_stats = netdev_linux_get_stats,
    .get_features = netdev_linux_get_features,
    .get_status = netdev_linux_get_status,
    .get_block_id = netdev_linux_get_block_id
};

const struct netdev_class netdev_tap_class = {
    NETDEV_LINUX_CLASS_COMMON,
    .type = "tap",
    .construct = netdev_linux_construct_tap,
    .get_stats = netdev_tap_get_stats,
    .get_features = netdev_linux_get_features,
    .get_status = netdev_linux_get_status,
};

const struct netdev_class netdev_internal_class = {
    NETDEV_LINUX_CLASS_COMMON,
    .type = "internal",
    .construct = netdev_linux_construct,
    .get_stats = netdev_internal_get_stats,
    .get_status = netdev_internal_get_status,
};

netdev_run --调用--> netdev_linux_run 会调用netlink的sock得到虚拟网卡的状态,并且更新状态。

static void
netdev_linux_run(const struct netdev_class *netdev_class OVS_UNUSED)
{
    struct nl_sock *sock;
    sock = netdev_linux_notify_sock();do {
        ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
        error = nl_sock_recv(sock, &buf, &nsid, false);
        if (!error) {
            struct rtnetlink_change change;

            if (rtnetlink_parse(&buf, &change)) {
                struct netdev *netdev_ = NULL;
                char dev_name[IFNAMSIZ];

                if (!change.ifname) {
                     change.ifname = if_indextoname(change.if_index, dev_name);
                }

                if (change.ifname) {
                    netdev_ = netdev_from_name(change.ifname);
                }
                if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
                    struct netdev_linux *netdev = netdev_linux_cast(netdev_);

                    ovs_mutex_lock(&netdev->mutex);
                    netdev_linux_update(netdev, nsid, &change);
                    ovs_mutex_unlock(&netdev->mutex);
                }

                if (change.ifname &&
                    rtnetlink_type_is_rtnlgrp_link(change.nlmsg_type)) {

                    /* Need to try updating the LAG information. */
                    ovs_mutex_lock(&lag_mutex);
                    netdev_linux_update_lag(&change);
                    ovs_mutex_unlock(&lag_mutex);
                }
                netdev_close(netdev_);
            }
        } 
    } while (!error);
} 

(免费订阅,永久学习)学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂

更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,永久学习,或点击这里加qun免费
领取,关注我持续更新哦! !  

原文链接:https://www.cnblogs.com/ssyfj/p/14767851.html 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Metabase学习教程:提问-4

Metabase中的表连接 如何在简单和自定义问题中使用查询编辑器连接Metabase中的表。 当涉及到分析数据时,必须要使用连接是一个事实,在Metabase,我们试图使您的问题的答案尽可能简单,即使这需要一些更复杂的策略。在本文中&#…

Spring中拦截器重复注册的问题排查

注册器JpushInterceptor 功能:新版的Java推送服务,将部分请求转发到老版node 查看日志发现拦截器日志重复 同一个链路,发现,经过同一个拦截器两次 debug发现注册器重复注册 第一个通过registry.addInterceptor注册 是通过We…

组合数学总结

文章目录三、递推关系3.1 常系数线性递推关系特征根法1.齐次递推关系2.非齐次方程母函数方法三、递推关系 3.1 常系数线性递推关系 k阶齐次递推关系:anc1an−1c2an−2...ckan−k0,ck≠0(3.1.1)k阶非齐次递推关系:anc1an−1c2an−2...ckan−kf…

SpringCloud微服务(四)——Nacos服务注册和配置中心

SpringCloud Alibaba Nacos服务注册和配置中心 Spring Cloud Netflix Projects Entering Mainterance Mode SpringCloud Alibaba: 服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 Rocke…

在 UltraEdit v15.00 及更高版本中添加用于语法高亮的 wordfile丨使用教程

UltraEdit原生支持开箱即用的最常用编程和标记语言的语法突出显示。但是,我们也有数百个其他语言的单词文件,而且很容易找到并添加您需要的语言!重要提示:此电源提示适用于运行 UltraEdit v15.00或 UEStudio v09.10及更高版本的用…

rosjava零散

笔者之前想在非ros环境下使用通信,了解到rosjava可以实现,不过后来换成了rosbridge,也搜集了一些rosjava的资料,放在这里供参考(没时间整理了,格式较乱请见谅) 安装方式:sudo apt-get install ros-indigo-…

Blind Backdoors in Deep Learning Models 论文笔记

#论文笔记# 1. 论文信息 论文名称Blind Backdoors in Deep Learning Models作者Eugene Bagdasaryan Vitaly Shmatikov Cornell Tech出版社USENIX Security Symposium 2021 (网安A类会议)pdf论文主页 本地PDF代码pytoch_Backdoors_101 2. introduction …

《第一行代码》核心知识点:Android简介

前言 自本文开始,我将更新《第一行代码 Android 第2版.pdf》,(提取码:n5ag ) 核心要点系列,通过阅读本系列文章可以帮助有Android基础的开发人员,去除冗余的基础讲解,直击核心知识点…

GEE开发之Modis_ET数据分析和获取

GEE开发之Modis_ET数据获取1 ET(蒸散量)2 MOD16A2(500米/8天)2.1 MOD16A2下的所有指数2.2 ET影像获取和查看3 ET日数据下载(以MOD16A2为例)4 ET月数据下载(以MOD16A2为例)5 ET年数据下载(以MOD16A2为例)前言:主要介绍Modis下的ET数据的获取和下载(日数据…

工厂模式【简单工厂+工厂+抽象工厂】总结

一、简单工厂模式 描述 简单工厂模式是属于创建型模式,又叫做静态工厂方法模式,但不属于23种GOF设计模式之一。简单工厂模式中专门定义一个简单工厂类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。简单工厂类根据传入的参数&a…

wireshark工具详解、数据包抓取分析、使用教程

Wireshark界面 Wireshark查看数据捕获列表 数据包概要信息窗口:描述每个数据包的基本信息。如图,点击某行数据,即可在下方显示该数据包的信息。 1、数据包解析窗口:显示被选中的数据包的解析信息,包含每个数据包的整体…

通过request请求和servlet实现注册跳转界面案例及问题解决

案例:用户登录 * 用户登录案例需求: 1.编写login.html登录页面 username & password 两个输入框 2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表 3.使用JdbcTemplate技术封装JDBC 4.登录成功跳转到Suc…

机器人操作系统ROS(19) 雷达和摄像头融合的资料

搜集的有关雷达和摄像头融合的资料。仅供参考: #1 传感器融合:激光雷达摄像头 摄像头产生的数据是2D图像,对于物体的形状和类别的感知精度较高。深度学习技术的成功起源于计算机视觉任务,很多成功的算法也是基于对图像数据的处理…

图神经网络 | Python基于图卷积的U-Net架构进行交通流量和速度的预测

图神经网络 | Python基于图卷积的U-Net架构进行交通流量和速度的预测 目录 图神经网络 | Python基于图卷积的U-Net架构进行交通流量和速度的预测效果分析基本描述程序实现核心概念参考资料效果分析 基本描述 此版本包含了训练和评估模型的代码,以预测Traffic4Cast挑战数据的交…

ssh-keygen和openssl的区别

OpenSSL OpenSSL是用于应用程序的软件库,该应用程序可保护计算机网络上的通信免遭窃听或需要识别另一方的身份,是SSL和TLS协议的开源实现。采用C语言作为开发语言,具备了跨平台的能力,支持Unix/Linux、Windows、Mac OS等多种平台…

力扣LeatCode算法题第9题-回文数

要求: //给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 //回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 //例如,1…

百世的数智化供应链凭何融入企业生命周期?

在供应链这个词出现前,供应链的本体就已经存在。 萨缪尔森说,现代经济生活的命脉是交换。当不同的物资、资金、信息在产业链上流动起来时,产业才能形成模型,经济才会有活力。然而,供应商增加、活动变多、地理距离拉长…

智慧气象解决方案-最新全套文件

智慧气象解决方案-最新全套文件一、建设背景二、建设架构传统气象所面临的挑战:1、气象数据大幅快速增长,导致计算能力不足2、人工智能应用不足,短临预报精度较低3、气象数据分散,数据融合困难4、气象服务方式单一,体验…

外卖项目04---菜品管理业务开发

效果展示: 目录 一、文件上传下载 50 1.1文件上传 50​编辑 1.2文件下载 1.3文件上传下载---文件上传代码实现1 1.4文件上传下载---文件上传代码实现2 1.5文件上传下载---文件下载代码实现 53 二、新增菜品 54 2.1需求分析 54 2.2数据模型 2.3新增菜品---代码开发--…

uniapp使用nfc功能及详解

公司使用uniapp在android手机端要增加一个nfc识别的功能。在此记录一下实现的过程。 资料查找 我的代码逻辑主要来源于找到的这篇文章: uniapp-安卓NFC读取 - 我要找到我的全世界 - 博客园 文章内附有代码,为防止文章失效代码消失,在这篇文…