Openvswitch原理与代码分析(2): ovs-vswitchd的启动-程序员宅基地

技术标签: 数据结构与算法  数据库  

ovs-vswitchd.c的main函数最终会进入一个while循环,在这个无限循环中,里面最重要的两个函数是bridge_run()和netdev_run()。

 

 

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

 

其中bridge_run就是初始化数据库中已经创建的虚拟网桥。

 

一、虚拟网桥的初始化bridge_run

 

bridge_run会调用bridge_run__,bridge_run__中最重要的是对于所有的网桥,都调用ofproto_run

 

  1. static void
  2. bridge_run__(void)
  3. {
  4. ……
  5.     /* Let each bridge do the work that it needs to do. */
  6.     HMAP_FOR_EACH (br, node, &all_bridges) {
  7.         ofproto_run(br->ofproto);
  8.     }
  9. }

 

Int ofproto_run(struct ofproto *p)会调用error = p->ofproto_class->run(p);

 

ofproto_class的定义在ofproto-provider.h中,它的实现定义在ofproto-dpif.c中,这里面的所有的函数,在这个文件中都有定义。

 

  1. const struct ofproto_class ofproto_dpif_class = {
  2.     init,
  3.     enumerate_types,
  4.     enumerate_names,
  5.     del,
  6.     port_open_type,
  7.     type_run,
  8.     type_wait,
  9.     alloc,
  10.     construct,
  11.     destruct,
  12.     dealloc,
  13.     run,
  14.     wait,
  15.     NULL, /* get_memory_usage. */
  16.     type_get_memory_usage,
  17.     flush,
  18.     query_tables,
  19.     set_tables_version,
  20.     port_alloc,
  21.     port_construct,
  22.     port_destruct,
  23.     port_dealloc,
  24.     port_modified,
  25.     port_reconfigured,
  26.     port_query_by_name,
  27.     port_add,
  28.     port_del,
  29.     port_get_stats,
  30.     port_dump_start,
  31.     port_dump_next,
  32.     port_dump_done,
  33.     port_poll,
  34.     port_poll_wait,
  35.     port_is_lacp_current,
  36.     port_get_lacp_stats,
  37.     NULL, /* rule_choose_table */
  38.     rule_alloc,
  39.     rule_construct,
  40.     rule_insert,
  41.     rule_delete,
  42.     rule_destruct,
  43.     rule_dealloc,
  44.     rule_get_stats,
  45.     rule_execute,
  46.     set_frag_handling,
  47.     packet_out,
  48.     set_netflow,
  49.     get_netflow_ids,
  50.     set_sflow,
  51.     set_ipfix,
  52.     set_cfm,
  53.     cfm_status_changed,
  54.     get_cfm_status,
  55.     set_lldp,
  56.     get_lldp_status,
  57.     set_aa,
  58.     aa_mapping_set,
  59.     aa_mapping_unset,
  60.     aa_vlan_get_queued,
  61.     aa_vlan_get_queue_size,
  62.     set_bfd,
  63.     bfd_status_changed,
  64.     get_bfd_status,
  65.     set_stp,
  66.     get_stp_status,
  67.     set_stp_port,
  68.     get_stp_port_status,
  69.     get_stp_port_stats,
  70.     set_rstp,
  71.     get_rstp_status,
  72.     set_rstp_port,
  73.     get_rstp_port_status,
  74.     set_queues,
  75.     bundle_set,
  76.     bundle_remove,
  77.     mirror_set__,
  78.     mirror_get_stats__,
  79.     set_flood_vlans,
  80.     is_mirror_output_bundle,
  81.     forward_bpdu_changed,
  82.     set_mac_table_config,
  83.     set_mcast_snooping,
  84.     set_mcast_snooping_port,
  85.     set_realdev,
  86.     NULL, /* meter_get_features */
  87.     NULL, /* meter_set */
  88.     NULL, /* meter_get */
  89.     NULL, /* meter_del */
  90.     group_alloc, /* group_alloc */
  91.     group_construct, /* group_construct */
  92.     group_destruct, /* group_destruct */
  93.     group_dealloc, /* group_dealloc */
  94.     group_modify, /* group_modify */
  95.     group_get_stats, /* group_get_stats */
  96.     get_datapath_version, /* get_datapath_version */
  97. };

 

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

这里定义了四类数据结构

Struct ofproto表示一个交换机

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

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

Struct ofgroup表示一个flow规则组

 

上面说到启动的过程中,会调用ofproto_class->run,也即会调用ofproto-dpif.c中的static int run(struct ofproto *ofproto_)函数。

 

在这个函数中,会初始化netflow, sflow, ipfix,stp, rstp, mac address learning等一系列操作。

 

bridge_run还会调用static void bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg),其中ovs_cfg是从ovsdb-server里面读取出来的配置。

 

在这个函数里面,对于每一个网桥,将网卡添加进去

  1. HMAP_FOR_EACH (br, node, &all_bridges) {
  2.     bridge_add_ports(br, &br->wanted_ports);
  3.     shash_destroy(&br->wanted_ports);
  4. }

 

  1. static void
  2. bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
  3. {
  4.     /* First add interfaces that request a particular port number. */
  5.     bridge_add_ports__(br, wanted_ports, true);
  6.  
  7.     /* Then add interfaces that want automatic port number assignment.
  8.      * We add these afterward to avoid accidentally taking a specifically
  9.      * requested port number. */
  10.     bridge_add_ports__(br, wanted_ports, false);
  11. }

 

static void bridge_add_ports__(struct bridge *br, const struct shash *wanted_ports, bool with_requested_port)会调用

static bool iface_create(struct bridge *br, const struct ovsrec_interface *iface_cfg, const struct ovsrec_port *port_cfg)会调用

static int iface_do_create(const struct bridge *br, const struct ovsrec_interface *iface_cfg, const struct ovsrec_port *port_cfg, ofp_port_t *ofp_portp, struct netdev **netdevp, char **errp)会调用

int ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev, ofp_port_t *ofp_portp)会调用

 

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

 

会调用ofproto-dpif.c中的ofproto_dpif_class的static int port_add(struct ofproto *ofproto_, struct netdev *netdev)函数。

 

会调用int dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop)会调用

 

  1. error = dpif->dpif_class->port_add(dpif, netdev, &port_no);

 

会调用dpif_netlink_class的port_add函数,也即dpif_netlink_port_add,也即

static int dpif_netlink_port_add(struct dpif *dpif_, struct netdev *netdev,odp_port_t *port_nop)会调用

static int dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev, odp_port_t *port_nop)

 

在这个函数里面,会调用netlink的API,命令为OVS_VPORT_CMD_NEW

 

  1. const char *name = netdev_vport_get_dpif_port(netdev,
  2.                                                   namebuf, sizeof namebuf);
  3. struct dpif_netlink_vport request, reply;
  4. struct nl_sock **socksp = NULL;
  5.  
  6. if (dpif->handlers) {
  7.     socksp = vport_create_socksp(dpif, &error);
  8.     if (!socksp) {
  9.         return error;
  10.     }
  11. }
  12.  
  13. dpif_netlink_vport_init(&request);
  14. request.cmd = OVS_VPORT_CMD_NEW;
  15. request.dp_ifindex = dpif->dp_ifindex;
  16. request.type = netdev_to_ovs_vport_type(netdev);
  17.  
  18. request.name = name;
  19.  
  20. upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
  21. request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
  22. request.upcall_pids = upcall_pids;
  23. error = dpif_netlink_vport_transact(&request, &reply, &buf);

 

这里会调用内核模块openvswitch.ko,在内核中添加虚拟网卡。这部分详细的过程将在下一节分析。

二、虚拟网卡的初始化netdev_run()

 

  1. void
  2. netdev_run(void)
  3.     OVS_EXCLUDED(netdev_class_mutex, netdev_mutex)
  4. {
  5.     struct netdev_registered_class *rc;
  6.  
  7.     netdev_initialize();
  8.     ovs_mutex_lock(&netdev_class_mutex);
  9.     HMAP_FOR_EACH (rc, hmap_node, &netdev_classes) {
  10.         if (rc->class->run) {
  11.             rc->class->run();
  12.         }
  13.     }
  14.     ovs_mutex_unlock(&netdev_class_mutex);
  15. }

 

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

 

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

 

例如对于dpdk的网卡有

 

  1. static const struct netdev_class dpdk_class =
  2.     NETDEV_DPDK_CLASS(
  3.         "dpdk",
  4.         NULL,
  5.         netdev_dpdk_construct,
  6.         netdev_dpdk_destruct,
  7.         netdev_dpdk_set_multiq,
  8.         netdev_dpdk_eth_send,
  9.         netdev_dpdk_get_carrier,
  10.         netdev_dpdk_get_stats,
  11.         netdev_dpdk_get_features,
  12.         netdev_dpdk_get_status,
  13.         netdev_dpdk_rxq_recv);

 

对于物理网卡,也需要有相应的netdev_class

 

  1. const struct netdev_class netdev_linux_class =
  2.     NETDEV_LINUX_CLASS(
  3.         "system",
  4.         netdev_linux_construct,
  5.         netdev_linux_get_stats,
  6.         netdev_linux_get_features,
  7.         netdev_linux_get_status);

 

对于连接到KVM的tap网卡

  1. const struct netdev_class netdev_tap_class =
  2.     NETDEV_LINUX_CLASS(
  3.         "tap",
  4.         netdev_linux_construct_tap,
  5.         netdev_tap_get_stats,
  6.         netdev_linux_get_features,
  7.         netdev_linux_get_status);

 

对于虚拟的软网卡,比如veth pair

  1. const struct netdev_class netdev_internal_class =
  2.     NETDEV_LINUX_CLASS(
  3.         "internal",
  4.         netdev_linux_construct,
  5.         netdev_internal_get_stats,
  6.         NULL, /* get_features */
  7.         netdev_internal_get_status);

 

其中NETDEV_LINUX_CLASS是一个宏,不是所有的参数都需要全部填写。

  1. #define NETDEV_LINUX_CLASS(NAME, CONSTRUCT, GET_STATS, \
  2.                            GET_FEATURES, GET_STATUS) \
  3. { \
  4.     NAME, \
  5.                                                                 \
  6.     NULL, \
  7.     netdev_linux_run, \
  8.     netdev_linux_wait, \
  9.                                                                 \
  10.     netdev_linux_alloc, \
  11.     CONSTRUCT, \
  12.     netdev_linux_destruct, \
  13.     netdev_linux_dealloc, \
  14.     NULL, /* get_config */ \
  15.     NULL, /* set_config */ \
  16.     NULL, /* get_tunnel_config */ \
  17.     NULL, /* build header */ \
  18.     NULL, /* push header */ \
  19.     NULL, /* pop header */ \
  20.     NULL, /* get_numa_id */ \
  21.     NULL, /* set_multiq */ \
  22.                                                                 \
  23.     netdev_linux_send, \
  24.     netdev_linux_send_wait, \
  25.                                                                 \
  26.     netdev_linux_set_etheraddr, \
  27.     netdev_linux_get_etheraddr, \
  28.     netdev_linux_get_mtu, \
  29.     netdev_linux_set_mtu, \
  30.     netdev_linux_get_ifindex, \
  31.     netdev_linux_get_carrier, \
  32.     netdev_linux_get_carrier_resets, \
  33.     netdev_linux_set_miimon_interval, \
  34.     GET_STATS, \
  35.                                                                 \
  36.     GET_FEATURES, \
  37.     netdev_linux_set_advertisements, \
  38.                                                                 \
  39.     netdev_linux_set_policing, \
  40.     netdev_linux_get_qos_types, \
  41.     netdev_linux_get_qos_capabilities, \
  42.     netdev_linux_get_qos, \
  43.     netdev_linux_set_qos, \
  44.     netdev_linux_get_queue, \
  45.     netdev_linux_set_queue, \
  46.     netdev_linux_delete_queue, \
  47.     netdev_linux_get_queue_stats, \
  48.     netdev_linux_queue_dump_start, \
  49.     netdev_linux_queue_dump_next, \
  50.     netdev_linux_queue_dump_done, \
  51.     netdev_linux_dump_queue_stats, \
  52.                                                                 \
  53.     netdev_linux_get_in4, \
  54.     netdev_linux_set_in4, \
  55.     netdev_linux_get_in6, \
  56.     netdev_linux_add_router, \
  57.     netdev_linux_get_next_hop, \
  58.     GET_STATUS, \
  59.     netdev_linux_arp_lookup, \
  60.                                                                 \
  61.     netdev_linux_update_flags, \
  62.                                                                 \
  63.     netdev_linux_rxq_alloc, \
  64.     netdev_linux_rxq_construct, \
  65.     netdev_linux_rxq_destruct, \
  66.     netdev_linux_rxq_dealloc, \
  67.     netdev_linux_rxq_recv, \
  68.     netdev_linux_rxq_wait, \
  69.     netdev_linux_rxq_drain, \
  70. }

 

rc->class->run()调用的是netdev-linux.c下的netdev_linux_run

 

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

 

  1. error = nl_sock_recv(sock, &buf, false);
  2. if (!error) {
  3.     struct rtnetlink_change change;
  4.     if (rtnetlink_parse(&buf, &change)) {
  5.         struct netdev *netdev_ = netdev_from_name(change.ifname);
  6.         if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
  7.            struct netdev_linux *netdev = netdev_linux_cast(netdev_);
  8.            ovs_mutex_lock(&netdev->mutex);
  9.            netdev_linux_update(netdev, &change);
  10.            ovs_mutex_unlock(&netdev->mutex);
  11.         }
  12.         netdev_close(netdev_);
  13.      }
  14. }

转载于:https://www.cnblogs.com/popsuper1982/p/5851603.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30469895/article/details/97606988

智能推荐

域名--泛解析-程序员宅基地

文章浏览阅读78次。背景:主域名下多数子域名访问后直接跳转至www域名的服务。百度百科--域名泛解析:在域名前添加任何子域名,均可访问到所指向的WEB地址。也就是客户的域名#.com之下所设的*.#.com全部。泛域名解析:利用通配符* (星号)来做次级域名以实现所有的次级域名均指向同一IP地址。子域名挖掘: 泛解析这个问题的解决方法很简单,向DNS请求*记录,然后把枚举子域名回来的..._dns枚举泛解析

基于对赋值为随机数的数组实现打印、求和及最大值、平均值的计算,排序问题_编写一个方法,对数组的元素用[0,100)之间的随机数进行初始化,初始化之后对数组进-程序员宅基地

文章浏览阅读206次。我们先定义一个数组x并为其分配储存空间,如下:int[] x=new x[100] 想要对数组中的每一个元素进行随机数赋值,需要用到循环控制语句,这里以for循环为例:定义一个变量i并赋值为0,作为for循环的起始条件;需要注意的是,数组的下标是从0开始的,比如x[0]到x[99],代表数组的长度为100。所以再写入判断语句的时候,不能写成a<=x.length;控制变量语句应写入自加语句。在循环体里,对x[a]进行随机数赋值,以0到100为例如图: 完成对x[a]的赋值之后,开始写入打印代_编写一个方法,对数组的元素用[0,100)之间的随机数进行初始化,初始化之后对数组进

为什么eMule总是未连接到服务器-程序员宅基地

文章浏览阅读1k次。<一>安装和版本问题1) eMule对Windows有什么要求?eMule能在Windows 95版本以上的Windows操作系统下运行。1个好的P2P软件需要好的拨号网络的支持,所以Windows 98和Windows ME的比较差网络运行情况可能会影响eMule的发挥;相对来说Windows 2000和Windows XP更适合使用eMule。2) 弹出错误信息说oleacc.dl..._emule v0.50b 最新服务器未连接

14 种编程语言书写关机脚本,真香_如何写强制关机脚本-程序员宅基地

文章浏览阅读2w次,点赞19次,收藏49次。批处理版本C 语言版本C++ 语言版本JAVA 语言版本C# 语言版本Python 语言版本NodeJS 语言版本PHP 语言版本Perl 语言版本Go 语言版本VB 语言版本SQL 语言版本树莓派 版本易语言 版本期待评论区故事的起源,有个家伙发来一个 BAT 的关机脚本,我顺手给改成了 八种语言的。_如何写强制关机脚本

docker compose搭建elasticsearch7集群_insufficient buffer remaining for aead cipher frag-程序员宅基地

文章浏览阅读4.1k次,点赞2次,收藏7次。一、集群介绍系统环境:Centos7.5服务器节点:主机名 IP hadoop03 192.168.1.153 hadoop04 192.168.1.154 hadoop05 192.168.1.155 二、环境准备1、安装docker:略过2、安装docker compose1)使用官方推荐方式(此方式需服务器翻外网)curl -L "https://github.com/docker/compose/releases/download_insufficient buffer remaining for aead cipher fragment (2). needs to be more

Debian10安装部署DNS服务-正向解析篇_debian10安装powerdns-程序员宅基地

文章浏览阅读6k次,点赞7次,收藏39次。1、服务安装1.1、服务安装执行下面的命令安装apt install -y bind9 dnsutils1.2、配置文件作用服务安装完成之后,执行下面的命令查看配置文件列表ls -l /etc/bind然后得到下面的信息root@debian:~# ls -l /etc/bind总用量 48-rw-r--r-- 1 root root 2761 5月 18 16:02 bind.keys-rw-r--r-- 1 root root 237 5月 18 16:02 db.0_debian10安装powerdns

随便推点

探秘MIP-NeRF:谷歌的实时三维重建新利器-程序员宅基地

文章浏览阅读371次,点赞5次,收藏5次。探秘MIP-NeRF:谷歌的实时三维重建新利器项目地址:https://gitcode.com/google/mipnerf项目简介MIP-NeRF 是由谷歌研究团队推出的一项创新性项目,它基于神经辐射场(NeRF)技术,旨在实现更高效、更真实的3D场景重建和渲染。该项目的目标是将复杂的三维建模过程简化为一个快速、实时的过程,让用户体验到前所未有的视觉效果。技术解析NeRF(神经辐射场...

poj1703 犯罪团伙 并查集_poj 团伙 倍增并查集-程序员宅基地

文章浏览阅读710次,点赞2次,收藏2次。 在讲解这个题目之前, 我不得不狠狠的吐槽cin和cout的效率, 我提交了6遍都是超时, 最后一遍提交时统统把cin和cout改为scanf和printf才过的, 当时心情又高兴又难受. 查看题目点击这里 Find them, Catch them POJ - 1703吐槽完了, 开始讲题. 第一次遇见这种题目是感觉满头痛的, 咦~, 并查集不是将关系是朋..._poj 团伙 倍增并查集

LeetCode-14-最长公共前缀(C)_leetcode最长公共前缀 c-程序员宅基地

文章浏览阅读113次。文章首发及后续更新:http://mwhls.top/617.html新的更新内容请到mwhls.top查看。如果没有图片请到上方的文章首发页面查看。昨天刷题做二阶字符串指针的时候又出问题了,所以今天换了个简单难度的题。结果结果!我又出问题了!可恶!不过解决了:C语言二级字符串指针的使用(函数传参/长度获取/空间分配) 题目编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。示例 1:输入: ["f_leetcode最长公共前缀 c

java/php/node.js/python基于Java的医疗器械销售系统【2024年毕设】-程序员宅基地

文章浏览阅读32次。除了以上作品下面是2023-2024年最新100套计算机专业原创的毕业设计源码+数据库,是近期作品,如果你的题目刚好在下面可以文末领取java源码参考。后台主要是管理员,管理员功能包括首页、个人中心、用户管理、器械分类管理、器械商品管理、留言反馈、系统管理、订单管理等;springboot基于springboot的电子书阅读系统的开发与设计。springboot基于springboot的健康生活管理系统。springboot基于Android的小说阅读与创作的平台。

MySQL 之多表连查_mysql连表查询-程序员宅基地

文章浏览阅读5.8k次。连接是关系数据库模型的主要特点,连接查询是关系数据库中最主要的查询,主要包括内连接、外连接等.通过连接运算符可以实现多个表查询,在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中.当查询数据时,通过连接操作查询出存放在多个表中的不同实体的信息.当两个或多个表中存在相同意义的字段时,便可以通过这些字段对不同的表进行连接查询._mysql连表查询