————————————————
版权:本文转自cnblogs 刘超的通俗云计算

原文链接:
https://www.cnblogs.com/popsuper1982/p/5870181.html
https://www.cnblogs.com/popsuper1982/p/5886819.html
发布于:2016-9-13

四、内核态网络包处理

Openvswitch的内核模块openvswitch.ko会在网卡上注册一个函数netdev_frame_hook,每当有网络包到达网卡的时候,这个函数就会被调用。

static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
{if (unlikely(skb->pkt_type == PACKET_LOOPBACK))return skb;port_receive(skb);return NULL;
}
//上面的port_receive() 等价于netdev_port_receive()函数
#define port_receive(skb) netdev_port_receive(skb, NULL)void netdev_port_receive(struct sk_buff *skb, struct ip_tunnel_info *tun_info)
{struct vport *vport;vport = ovs_netdev_get_vport(skb->dev);
……skb_push(skb, ETH_HLEN);ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);ovs_vport_receive(vport, skb, tun_info);return;
error:kfree_skb(skb);
}

函数int ovs_vport_receive(struct vport vport, struct sk_buff skb, const struct ip_tunnel_info *tun_info)实现如下

int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,const struct ip_tunnel_info *tun_info)
{struct sw_flow_key key;....../* Extract flow from 'skb' into 'key'. */error = ovs_flow_key_extract(tun_info, skb, &key);if (unlikely(error)) {kfree_skb(skb);return error;}ovs_dp_process_packet(skb, &key);return 0;
}

ovs_vport_receive() 这个函数里面,首先声明了变量struct sw_flow_key key;
如果我们看这个key的定义,可见这个key里面是一个大杂烩,数据包里面的几乎任何部分都可以作为key来查找flow表:

struct sw_flow_key {u8 tun_opts[255];u8 tun_opts_len;struct ip_tunnel_key tun_key; /* Encapsulating tunnel key. */struct {u32 priority; /* Packet QoS priority. */u32 skb_mark; /* SKB mark. */u16 in_port; /* Input switch port (or DP_MAX_PORTS). */} __packed phy; /* Safe when right after 'tun_key'. */u32 ovs_flow_hash; /* Datapath computed hash value. */u32 recirc_id; /* Recirculation ID. */struct {u8 src[ETH_ALEN]; /* Ethernet source address. */u8 dst[ETH_ALEN]; /* Ethernet destination address. */__be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */__be16 type; /* Ethernet frame type. */} eth;union {struct {__be32 top_lse; /* top label stack entry */} mpls;struct {u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */u8 tos; /* IP ToS. */u8 ttl; /* IP TTL/hop limit. */u8 frag; /* One of OVS_FRAG_TYPE_*. */} ip;};struct {__be16 src; /* TCP/UDP/SCTP source port. */__be16 dst; /* TCP/UDP/SCTP destination port. */__be16 flags; /* TCP flags. */} tp;union {struct {struct {__be32 src; /* IP source address. */__be32 dst; /* IP destination address. */} addr;struct {u8 sha[ETH_ALEN]; /* ARP source hardware address. */u8 tha[ETH_ALEN]; /* ARP target hardware address. */} arp;} ipv4;struct {struct {struct in6_addr src; /* IPv6 source address. */struct in6_addr dst; /* IPv6 destination address. */} addr;__be32 label; /* IPv6 flow label. */struct {struct in6_addr target; /* ND target address. */u8 sll[ETH_ALEN]; /* ND source link layer address. */u8 tll[ETH_ALEN]; /* ND target link layer address. */} nd;} ipv6;};struct {/* Connection tracking fields. */u16 zone;u32 mark;u8 state;struct ovs_key_ct_labels labels;} ct;} __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */

可见这个key里面是一个大杂烩,数据包里面的几乎任何部分都可以作为key来查找flow表

  • tunnel可以作为key
  • 在物理层,in_port即包进入的网口的ID
  • 在MAC层,源和目的MAC地址
  • 在IP层,源和目的IP地址
  • 在传输层,源和目的端口号
  • IPV6

所以,要在内核态匹配流表,首先需要调用ovs_flow_key_extract,从包的正文中提取key的值。


接下来

调用ovs_dp_process_packet()

函数ovs_dp_process_packet()首先在内核里面的流表中查找符合key的flow,也即ovs_flow_tbl_lookup_stats,如果找到了,很好说明用户态的流表已经放入内核,则走fast path就可了。于是直接调用ovs_execute_actions,执行这个key对应的action。

如果不能找到,则只好调用ovs_dp_upcall,让用户态去查找流表。会调用static int queue_userspace_packet(struct datapath dp, struct sk_buff skb, const struct sw_flow_key key, const struct dp_upcall_info upcall_info)

它会调用err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);通过netlink将消息发送给用户态。在用户态,有线程监听消息,一旦有消息,则触发udpif_upcall_handler。

  1. 从Device接收Packet交给事先注册的event handler进行处理;
  2. 接收Packet后识别是否是unknown packet,是则交由upcall处理;
  3. vswitchd对unknown packet找到flow rule进行处理;
  4. 将Flow rule发送给datapath.

也就是说OVS处理数据包首先会看有没有事先订阅的事件,如果有直接转交给该对应的处理函数,然后匹配流表,最后按照传统网络协议栈进行处理。

void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
{const struct vport *p = OVS_CB(skb)->input_vport;struct datapath *dp = p->dp;struct sw_flow *flow;struct sw_flow_actions *sf_acts;struct dp_stats_percpu *stats;u64 *stats_counter;u32 n_mask_hit;stats = this_cpu_ptr(dp->stats_percpu);/* Look up flow. */flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb),&n_mask_hit);if (unlikely(!flow)) {struct dp_upcall_info upcall;int error;memset(&upcall, 0, sizeof(upcall));upcall.cmd = OVS_PACKET_CMD_MISS;upcall.portid = ovs_vport_find_upcall_portid(p, skb);upcall.mru = OVS_CB(skb)->mru;error = ovs_dp_upcall(dp, skb, key, &upcall);if (unlikely(error))kfree_skb(skb);elseconsume_skb(skb);stats_counter = &stats->n_missed;goto out;}ovs_flow_stats_update(flow, key->tp.flags, skb);sf_acts = rcu_dereference(flow->sf_acts);ovs_execute_actions(dp, skb, sf_acts, key);stats_counter = &stats->n_hit;out:/* Update datapath statistics. */u64_stats_update_begin(&stats->syncp);(*stats_counter)++;stats->n_mask_hit += n_mask_hit;u64_stats_update_end(&stats->syncp);
}

————————————————
版权:本文转自cnblogs 刘超的通俗云计算
原文链接:https://www.cnblogs.com/popsuper1982/p/5870181.html
发布于:2016-9-13

image.png

函数ovs_flow_tbl_lookup()利用OVS流表精确匹配TCP/IP报头五元组,并执行action do_output或consume_skb

  • OVS定义的流表结构体struct flow_table;
  • 流表索引key: struct sw_flow_key; 掩码: struct sw_flow_mask
  • 流表元素: struct sw_flow
  • 执行体struct sw_flow_actions

在内核中,flow table的数据结构如下图所示:

每个虚拟交换机对应一个datapath,每个datapath有一个flow table,每个flow table分成N个桶bucket,根据key进行哈希,不同的key分布在不同的桶里面。

每个桶的大小是一个内存页的大小,在内存页的头部保存了保存了多少个元素,每个元素的大小。每个元素都是sw_flow,里面有key,也有action

OVS流表结构示意图
https://www.cnblogs.com/popsuper1982/p/5886819.html
  1. 调用ovs_flow_key_extract()取出TCP/IP报头5元组作为key
  2. 调用ovs_dp_process_packet()
    • ovs_flow_tbl_lookup_stats()查询流表
    • ovs_execute_actions() 执行ACTION

OVS流表精确匹配TCP/IP报头五元组相关推荐

  1. TCP/IP的五元组

    五元组:源IP地址,目的IP地址,协议号,源端口,目的端口 协议号:存在于IP头部协议号字段(比如:6=tcp,17=udp)

  2. Mellanox CX-5网卡支持OVS流表加速功能的调研

    女主宣言 本文主要对Mellanox CX-5网卡支持OVS流表加速功能进行了调研,简单介绍了配套软件的版本要求,并描述了整体测试的步骤,另外对其支持VF热迁移也进行了初步的调研,希望对有相同需求的同 ...

  3. ovs 流表version

    插入分类器的流表有一个version字段,类型为struct versions,用来标记此流表在哪个version添加到分类器,如果流表被删除后标记在哪个version被删除. typedef uin ...

  4. OVS 流表轨迹入门及典型场景举例【ovs-appctl ofproto/trace】

    OVS 流表轨迹入门及典型场景举例 一. 流表轨迹入门 二. 典型场景举例 三. 小技巧 一. 流表轨迹入门 在数据中心网络中,SDN控制器通过向OVS交换机下发OpenFlow流表,指导报文转发.在 ...

  5. TCP/IP(五)传输层之细说TCP的三次握手和四次挥手

    前言 这一篇我将介绍的是大家面试经常被会问到的,三次握手四次挥手的过程.以前我听到这个是什么意思呀?听的我一脸蒙逼,但是学习之后就原来就那么回事! 一.运输层概述 1.1.运输层简介 这一层的功能也挺 ...

  6. TCP/IP(五):UDP 报文格式详解

    1.概述 UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连 ...

  7. TCP/IP(五):TCP 协议详解

    上一节 中讲过,TCP 协议是面向有连接的协议,它具有丢包重发和流量控制的功能,这是它区别于 UDP 协议最大的特点.本文就主要讨论这两个功能. 数据包重发 数据发送 丢包重发的前提是发送方能够知道接 ...

  8. Openlab实验平台实验--使用Postman下发流表

    任务目的 1.掌握OpenFlow流表相关知识,理解SDN网络中L2,L3,L4层流表的概念. 2.学习并熟练掌握Postman工具下发L2,L3,L4层流表. 任务环境 注:系统默认的账户为root ...

  9. OpenDayLight+Mininet+Postman下发流表实验

    OpenDayLight+Mininet+Postman下发流表实验 VM实验环境 笔记本环境 Tips1 Tips2 任务目的 任务内容 实验原理 一. 流表结构 二. 匹配域解析流程 三. Ope ...

最新文章

  1. char和byte的区别
  2. 最新!压缩为rar格式方法,目前只能用:WinRAR压缩工具-rar压缩格式的版权所有者。
  3. insert时调用本身字段_「技术篇」ETL工具Kettle数据对比同步以及Java程序中调用
  4. php使用redis做缓存,php使用redis做缓存和使用redis保存session
  5. PHP通过CURL或file_get_contents请求第三方地址
  6. 中查出所有姓张的学生为啥查不出来_只有笔试成绩没有面试成绩是什么原因 教师资格面试成绩怎么查...
  7. 手写 new 操作符
  8. aix系统输入oracle命令,aix 简单的系统命令
  9. 这个高仿真框架AI2-THOR,想让让强化学习快速走进现实世界
  10. Postman自动化接口测试实战详解
  11. Linux搭建SVN 服务器(转)
  12. ERROR Error: Highcharts error #13
  13. win10无法使用内置管理员账户打开
  14. 数字IC后端真的不如前端设计和验证吗?
  15. 论珊瑚虫并不光彩的历史
  16. 如何获取Certificate fingerprint (SHA1) key 以及 MD5 certification key
  17. 推荐系统4--AutoRec与Deep Crossing(改变神经网络的复杂程度)
  18. FinClip | 2022 年 10月产品大事记
  19. 第三周铁人战队学习总结
  20. 南阳理工学院ACM语言入门题目1的思考

热门文章

  1. Responder 嗅探/欺骗工具
  2. HBase 宽表和高表
  3. 艺术核心素养如何在课程中实现
  4. DRF框架之serializer序列化
  5. Mr. Cappuccino的第19杯咖啡——金三银四面试题之JVM性能调优篇
  6. Go语言工具包之gomock
  7. PHP显示的时间与服务器上时间不同
  8. 程雷被机器人_搞笑:一台活泼可爱的机器人,爆笑全场,主持人程雷都被整了!一位活泼可爱的机器人管家...
  9. nebular 引入iconfont 字体图标,图标渲染成了框框
  10. OpenCV-Python 图像二值化