总体概览如下:

假设upcall handler线程有两个,vport有四个,那么每个vport下都将持有两个NetLink连接的信息,这两个NetLink连接将被用来上送upcall消息。
每个NetLink连接被对应的upcall handler线程接管,多个vport在同一线程中的NetLink连接被epoll管理。
1:每个vport下都挂多个NetLink连接,数量等同于upcall处理线程的数量
2:线程中routine函数为udpif_upcall_handler,伪码如下:
     routine {
          while(线程不设自杀标记) {
               if(从epoll中收到了一些upcall消息,则进一步处理upcall) {
                    continue; 
               } else {
                    注册poll:当epoll_fd有骚动时解除当前线程的block
               }
               block当前线程
          }
     }
3:每个NetLink连接被称为一个upcall channel
 
1:upcall处理线程的创建
upcall处理线程随着vswitchd进程的启动而被创建,概览如下:

最终所有线程信息会被记录在 ofproto_dpif->backer->udpif下
 
2:vport的创建与channels的创建
在基于本机内核的datapath实现的openflow交换机场景下,用户态的datapath接口将采用dpif_netlink_***系列函数。vport的创建在用户态最终将调用到dpif_netlink_port_add,这是dpif_netlink_port_add__的包裹函数。
 
先说一点我对NetLink连接的理解
     1:创建socket
     2:可选的bind步骤,在这一步,应当在本端地址结构中赋值nl_pid为当前进程ID,并bind之。
     3:建立连接connect,这一步对端地址结构的nl_pid值如果为非0值 ,那么连接的就是一个用户态进程。如果nl_pid值为0,则连接的是内核。
     如果没有第2步,那么在connect之后,内核会为这个NetLink连接的本端bind地址结构自动指定一个nl_pid值,以标识该连接。此时通过getsockname取到的本端地址结构中的nl_pid字段将不是发起连接一方的进程ID。

3:内核cache miss
内核cache miss后,会发送upcall消息,
 
netdev_frame_hook(pskb)
    |
    \-> netdev_port_receive(skb, NULL/skb_tunnel_info(skb))
        |
        \-> ovs_vport_receive(ovs_netdev_get_vport(skb->dev), skb, tun_info = NULL/skb_tunnel_info(skb))
            |
            \-> error = ovs_flow_key_extract(tun_info, skb, &key)
            |
            \-> ovs_dp_process_packet(skb, &key)
                |
                \-> flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb), &n_mask_hit)
                    if(unlikely(!flow)) {
                        ...
                        upcall.cmd = OVS_PACKET_CMD_MISS;
                        upcall.portid = ovs_vport_find_upcall_portid(p, skb);
                        |
                        \-> 在vport下的upcall_portids里钦定一个port号,作为NetLink的目的地
                        ...
                        error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
                    }
即是从upcall的vport下挂的socksp中选择一个nl_pid,以这个nl_pid做为upcall消息发送的目的地址
由上面的图能看出来,在vport下选择不同的socksp中的nl_pid,会导致消息被发往不同的epoll
 
 
4:dpif_handler[]->epoll_fd与用户态线程间的关联

那么在udpif_upcall_handler() -> recv_upcalls() -> dpif_recv() -> dpif_netlink_recv() -> dpif_netlink_recv__()中有以下代码:
 

这里的参数handler_id来自于线程routine函数的入参handler实例下的handler_id。
即对于x号线程,它会取dpif_handler[]数组中的x号元素下的epoll_fd去处理。

body,td { font-family: Consolas; font-size: 10pt }

OVS 中的 upcall 线程的更多相关文章

  1. 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法

    [源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...

  2. Java中的守护线程和非守护线程(转载)

    <什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...

  3. springmvc中request的线程安全问题

    SpringMvc学习心得(四)springmvc中request的线程安全问题 标签: springspring mvc框架线程安全 2016-03-19 11:25 611人阅读 评论(1) 收藏 ...

  4. Unity 中 使用c#线程

    使用条件   天下没有免费的午餐,在我使用unity的那一刻,我就感觉到不自在,因为开源所以不知道底层实现,如果只是简单的做点简单游戏,那就无所谓的了,但真正用到实际地方的时候,就会发现一个挨着一个坑 ...

  5. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  6. HttpApplication中的异步线程

    一.Asp.net中的线程池设置 在Asp.net的服务处理中,每当服务器收到一个请求,HttpRuntime将从HttpApplication池中获取一个HttpApplication对象处理此请求 ...

  7. c#中如何跨线程调用windows窗体控件

    c#中如何跨线程调用windows窗体控件?   我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首 ...

  8. c#中如何跨线程调用windows窗体控件?

    我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首先来看传统方法: public partial c ...

  9. C#如何判断线程池中所有的线程是否已经完成之Demo

    start: System.Threading.RegisteredWaitHandle rhw = null; new Action(() => { ; i < ; i++) { new ...

随机推荐

  1. 一个简单的jquery左右列表内容切换应用

    选中左边某个选项点击添加,即可将选中项添加到右边文本框中,点击选中全部即可将全部选项移到右边,移除按钮功能相同. html代码: <div id="main"> < ...

  2. 【C和指针】笔记1

    数据 基本数据类型 整型家族:包含字符,短整型,整型和长整型 整型相互之间大小规定如下: 长整型至少和整型一样长,而整型至少应该和短整型一样长. short int至少16位,long int至少32 ...

  3. 对百度WebUploader的二次封装,精简前端代码之图片预览上传(两句代码搞定上传)

    前言 本篇文章上一篇: 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传) 此篇是在上面的基础上扩展出来专门上传图片的控件封装. 首先我们看看效果: 正文 使用方式同 ...

  4. MAC Mysql 重置密码

    使用mac电脑,当mysql登录密码忘记时,需要重置密码.步骤如下: 1. 关闭当前正在运行的mysql进程. A.进入"偏好设置",选择mysql, 再选"stop m ...

  5. 点击按钮,缩放图片(img.width、img.style.width、img.offsetWidth)

    前几天在慕课网上看到一个关于图片缩放的教学视频,因为当时对老师使用img.width,而不是使用img.style.width而感到奇怪,所以周末得空了,想来自己试着写出来,相关视频网址如下:http ...

  6. PHP原生DOM对象操作XML'代码'

    对于操作XML类型文件,PHP内置有一套DOM对象可以进行处理.对XML的操作,从创建.添加到修改.删除都可以使用DOM对象中的函数来进行. 创建 创建一个新的XML文件,并且写入一些数据到这个XML ...

  7. Struts2框架的基本使用

         前面已经介绍过了MVC思想,Struts2是一个优秀的MVC框架,大大降低了各个层之间的耦合度,具有很好的扩展性.从本篇开始我们学习Struts2的基本用法,本篇主要包括以下内容: Stru ...

  8. 【整理】hash算法原理及常见函数

    简介 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.        散列表 ...

  9. Composer 安装(一)

    一.简介 Composer 是 PHP 用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件. ...

  10. 用java实现大文件分割、排序、合并

    import java.io.BufferedReader;   import java.io.BufferedWriter;   import java.io.FileNotFoundExcepti ...