OpenStack 业务链networking-sfc介绍 (2) - 底层原理
原文链接:https://blog.csdn.net/bc_vnetwork/article/details/65630475
1. SFC底层实现原理
port chain和ovs driver/agent
Port Chain插件架构图:
SFC Port Chain Plugin +-------------------------------+ | +-------------------------+ | | | Port Chain API | | | +-------------------------+ | | | Port Chain Database | | | +-------------------------+ | | | Driver Manager | | | +-------------------------+ | | | Common Driver API | | | +-------------------------+ | | | | | +-------------------------+ | | | OVS Driver | | | +-------------------------+ | +---------------|--------------+ | rpc +----------------+ | OVS Agent | | ext sfc driver | +----------------+ |
目前networking-sfc项目中的基于ovs的sfc实现还是用的mpls, nsh可能要Pike版本才能支持。
以下下列配置为例, 创建业务链串联sf1, sf2, sf3 三台nfv虚拟机, 并从VM1处发包进入业务链:
+------+ +------+ +------+ | SF1 | | SF2 | | SF3 | +------+ +------+ +------+ p1| |p2 p3| |p4 p5| |p6 | | | | | | VM 1-->----+ +--------+ +-----------+ +----> 根据代码中的一些限制(参考后面"限制"章节), p1必须和logical-source-port在一个子网中, p2、p3必须在一个子网中, p4、p5必须在一个子网中。 所以, 本示例中, 我们定义p1的子网为: 1.0.0.0/24, p2的子网为: 2.0.0.0/24, p3的子网为: 2.0.0.0/24, p4的子网为: 3.0.0.0/24, p5的子网为: 3.0.0.0/24, p6子网为4.0.0.0/24。 $ openstack network create sfc-net-1 $ openstack network create sfc-net-2 $ openstack network create sfc-net-3 $ openstack network create sfc-net-4 $ openstack network create sfc-net-5 $ openstack network create sfc-net-6 $ openstack subnet create --network sfc-net-1 --subnet-range 1.0.0.0/24 sfc-subnet-1 $ openstack subnet create --network sfc-net-2 --subnet-range 2.0.0.0/24 sfc-subnet-2 $ openstack subnet create --network sfc-net-3 --subnet-range 3.0.0.0/24 sfc-subnet-3 $ openstack subnet create --network sfc-net-4 --subnet-range 4.0.0.0/24 sfc-subnet-4 # 创建虚拟机, 命名为sfc-vm-1, 加入2个网络: sfc-net-1, sfc-net-2 # 创建虚拟机, 命名为sfc-vm-2, 加入2个网络: sfc-net-2, sfc-net-3 # 创建虚拟机, 命名为sfc-vm-3, 加入2个网络: sfc-net-3, sfc-net-4 # 修改虚拟机sfc-vm-1的nova port名字为: p1, p2 # 修改虚拟机sfc-vm-2的nova port名字为: p3, p4 # 修改虚拟机sfc-vm-3的nova port名字为: p5, p6 $ openstack sfc port pair create --ingress p1 --egress p2 port-pair-1 $ openstack sfc port pair create --ingress p3 --egress p4 port-pair-2 $ openstack sfc port pair create --ingress p5 --egress p6 port-pair-3 $ openstack sfc port pair group create --port-pair port-pair-1 port-pair-group-1 $ openstack sfc port pair group create --port-pair port-pair-2 port-pair-group-2 $ openstack sfc port pair group create --port-pair port-pair-3 port-pair-group-3 $ openstack sfc flow classifier create --source-ip-prefix 1.0.0.0/24 --logical-source-port p1 sfc-flow-class-1 $ openstack sfc port chain create --flow-classifier sfc-flow-class-1 --port-pair-group port-pair-group-1 --port-pair-group port-pair-group-2 --port-pair-group port-pair-group-3 sfc-port-chain-1 |
和以前的代码有区别, 现在sfc分为2大模块: 流分类(flow classifier)和sfc(业务链), 2大模块各自可以配置独立的驱动, 目前都只是通过ovs实现。按照官方想法, 以后流分类(sg,fw, qos, sfc等模块均包含流分类)这个功能会抽象出来统一维护。
核心流程代码流程在/services/sfc/drivers/ovs/driver.py中, 其中最核心的create_port_chain()作用如下: 通过用户输入的port-pair, port-group, port-chain信息, 生成path_nodes列表, path_nodes包括: 状态, 业务链中位置nsi (nsh index), 节点类型(src_node, sf_node, dst_node), 下一跳信息(port-pair列表和加权信息, 可以看出这里能做负载均衡),业务链id(分配的nsp id) 等等。
[ { "status": "building", "nsi": 255, "portpair_details": [ "524c85b9-7038-43ac-bb29-7a90e62900fd" ], "node_type": "src_node", "next_hop": "[{\"portpair_id\": \"5197be46-cc98-4ac6-93a6-1759e963b1fe\", \"weight\": 1}]", "next_group_id": 1, "nsp": 1, "fwd_path": true, "id": "fd1b1ba6-01d7-4905-94f4-aa3bd8e6dc6d", "tenant_id": "1af813712bdf42789fc90832dc5ce8be", "portchain_id": "350fb8b7-cc89-49f7-888b-f80f8a0248a6", "project_id": "1af813712bdf42789fc90832dc5ce8be" }, { "status": "building", "nsi": 251, "portpair_details": [], "node_type": "dst_node", "next_hop": null, "next_group_id": null, "nsp": 1, "fwd_path": true, "id": "5e34e41c-9db5-4ab4-8c94-e5e68092773f", "tenant_id": "1af813712bdf42789fc90832dc5ce8be", "portchain_id": "350fb8b7-cc89-49f7-888b-f80f8a0248a6", "project_id": "1af813712bdf42789fc90832dc5ce8be" }, { "status": "building", "nsi": 254, "portpair_details": [ "5197be46-cc98-4ac6-93a6-1759e963b1fe" ], "node_type": "sf_node", "next_hop": "[{\"portpair_id\": \"018c8bf0-b93e-4732-9c50-23be5422bdb9\", \"weight\": 1}]", "next_group_id": 2, "nsp": 1, "fwd_path": true, "id": "d63f0bcf-2743-401f-85bc-41dea3ab7ed6", "tenant_id": "1af813712bdf42789fc90832dc5ce8be", "portchain_id": "350fb8b7-cc89-49f7-888b-f80f8a0248a6", "project_id": "1af813712bdf42789fc90832dc5ce8be" }, { "status": "building", "nsi": 253, "portpair_details": [ "018c8bf0-b93e-4732-9c50-23be5422bdb9" ], "node_type": "sf_node", "next_hop": "[{\"portpair_id\": \"64bb88a2-1390-4c8f-b78f-011e9857e2b4\", \"weight\": 1}]", "next_group_id": 3, "nsp": 1, "fwd_path": true, "id": "6d864f84-bd8b-415b-8b15-0137057cc15a", "tenant_id": "1af813712bdf42789fc90832dc5ce8be", "portchain_id": "350fb8b7-cc89-49f7-888b-f80f8a0248a6", "project_id": "1af813712bdf42789fc90832dc5ce8be" }, { "status": "building", "nsi": 252, "portpair_details": [ "64bb88a2-1390-4c8f-b78f-011e9857e2b4" ], "node_type": "sf_node", "next_hop": null, "next_group_id": null, "nsp": 1, "fwd_path": true, "id": "099da96f-01b0-4f3b-9aab-1281960aeb4f", "tenant_id": "1af813712bdf42789fc90832dc5ce8be", "portchain_id": "350fb8b7-cc89-49f7-888b-f80f8a0248a6", "project_id": "1af813712bdf42789fc90832dc5ce8be" } ] |
如果用户创建的是非对称链(单向), 那么就创建出一条path_nodes。如果用户创建的是对称链(双向), 那么就创建出一条fwd_path_nodes和一条rev_path_nodes。
然后根据path_nodes里的信息, 调用_update_path_nodes()-> _update_path_node_flowrules(), RPC调用ovs-agent上的sfc extension driver方法 :update_flow_rules(), 最终下流表配置到ovs上。
现有的OVS Driver/agent都会被改造和扩展支持service chain。
OVS agent会在br-int和br-tun网桥上下发一些额外流表:
1. 流量分类流表: 会在br-int集成网桥中, 下发流表, 用来做流量分类(即flow-classifier)。
2. Service Function转发流表: 会在br-tun网桥上下发流表, 使需要走service chain的流量通过tunnel走到下一个port chain 端口。而br-int也会用来终结Service Function Path.
这里, ovs-agent会通过封装mpls header来标示chain path。其中, mpls label用来表示chain path id, mpls ttl表示chain hop index(指下一跳, 是该chain上的第几个port).
MPLS报文头封装结构如下:
在这里mpls用于模拟nsh协议报文:
mpls_label字段定义为: nsp<<8 | nsi
mpls_ttl定义为: nsi
nsp即NSH Path ID
nsi即NSH index
511: 即0001 | 11111111 意义为: 业务链ID: 1, 节点位置为255
510: 即0001 | 11111110 意义为: 业务链ID: 1, 节点位置为254
509: 即0001 | 11111101 意义为: 业务链ID: 1, 节点位置为253
port信息:
p1: 997(qvof5ea457f-b7): addr: fa:16:3e:4d:10:37 p2: 998(qvo28855064-04): addr:92:8c:c8:c6:41:22 p3: 999(qvo84b4cdbb-af): addr:fe:ae:86:22:eb:cc p4: 1000(qvo68434f35-f6): addr:0e:d7:5d:60:e2:ad p5: 1001(qvofdaf5c1c-01): addr:16:29:4f:32:40:1b p6: 1002(qvo704baa4f-59): addr:ba:9c:5e:a4:36:4b |
br-int flow信息:
每一跳入口的sfc flow匹配和负载均衡, 在table:0中实现: table=0, priority=30,ip,in_port=997 ,nw_src=1.0.0.0/24 actions=group:1【匹配p1端口和流分类规则, 转发到group:1,做第1跳的出口负载均衡,并转发给第1个NFV虚拟机】 table=0, priority=30,ip,in_port=998 ,nw_src=1.0.0.0/24 actions=group:2【匹配p2端口和流分类规则, 转发到group:2,做第2跳的出口负载均衡,并转发给第2个NFV虚拟机】 table=0, priority=30,ip,in_port=1000 ,nw_src=1.0.0.0/24 actions=group:3【匹配p4端口和流分类规则, 转发到group:2,做第3跳的出口负载均衡,并转发给第3个NFV虚拟机】 table=0, priority=30,ip,in_port=1002 ,nw_src=1.0.0.0/24 actions=NORMAL 【匹配p6(即业务链出端口), 然后走正常转发流程】 每一跳出口的sfc报头封装, 在table:5中实现: table=5, priority=0,ip,dl_dst=fa:16:3e:4d:10:37 actions=push_mpls:0x8847,set_field:511->mpls_label,set_mpls_ttl(255),push_vlan:0x8100,set_field:4150->vlan_vid,resubmit(,10) 【匹配发往p1 tap的报文,封装sfc头(这里是mpls),并打上本地vlan, 发往远端计算节点或发给本地table:10】 table=5, priority=0,ip,dl_dst=fa:16:3e:b5:64:7e actions=push_mpls:0x8847,set_field:510->mpls_label,set_mpls_ttl(254),push_vlan:0x8100,set_field:4128->vlan_vid,resubmit(,10) 【匹配发往p3 tap的报文,封装sfc头(这里是mpls),并打上本地vlan, 发往远端计算节点或发给本地table:10】 table=5, priority=0,ip,dl_dst=fa:16:3e:51:39:b6 actions=push_mpls:0x8847,set_field:509->mpls_label,set_mpls_ttl(253),push_vlan:0x8100,set_field:4169->vlan_vid,resubmit(,10) 【匹配发往p5 tap的报文,封装sfc头(这里是mpls),并打上本地vlan, 发往远端计算节点或发给本地table:10】 本地sfc报头解封装,并发往nfv虚拟机, 在table:10中实现: table=10, priority=1,mpls,dl_vlan=54,dl_dst=fa:16:3e:4d:10:37,mpls_label=511 actions=pop_vlan,pop_mpls:0x0800,output:997【p1在本地, 匹配目的mac为p1的业务链1报文, mpls解封装, 并发送p1】 table=10, priority=1,mpls,dl_vlan=32,dl_dst=fa:16:3e:b5:64:7e,mpls_label=510 actions=pop_vlan,pop_mpls:0x0800,output:999【p3在本地, 匹配目的mac为p1的业务链1报文, mpls解封装, 并发送p3】 table=10, priority=1,mpls,dl_vlan=73,dl_dst=fa:16:3e:51:39:b6,mpls_label=509 actions=pop_vlan,pop_mpls:0x0800,output:1001【p5在本地, 匹配目的mac为p5的业务链1报文, mpls解封装, 并发送p5】 |
br-int group信息, 这里主要是用来在每个sf出口处做负载均衡的:
group_id=1,type=select,bucket=actions=set_field:fa:16:3e:4d:10:37->eth_dst,resubmit(,5)【修改目的mac为p1 tap口,并转发到table 5】 group_id=2,type=select,bucket=actions=set_field:fa:16:3e:b5:64:7e->eth_dst,resubmit(,5)【修改目的mac为p3 tap口,并转发到table 5】 group_id=3,type=select,bucket=actions=set_field:fa:16:3e:51:39:b6->eth_dst,resubmit(,5)【修改目的mac为p5 tap口,并转发到table 5】 |
发包验证:
为了减少安全组和port-security对实验的影响, 放开所有NFV虚拟机的安全组, 关闭port-security。 # neutron port-update 68434f35-f6fc-4c64-bbd3-55aca8f7b6ef --no-security-groups # neutron port-update 68434f35-f6fc-4c64-bbd3-55aca8f7b6ef --port_security_enabled=True ... 在目的主机sfc-vm-3上开启sshd服务: # systemctl start sshd 在sfc-vm-1上配置ARP: # arp -s 2.0.0.1 fa:16:3e:ee:ee:ee 在sfc-vm-2上配置路由转发, 把eth0的流量转发到eth1上去: # echo 1 > /proc/sys/net/ipv4/ip_forward # ip route add 10.0.0.0/24 dev eth1 # arp -s 4.0.0.8 fa:16:3e:ee:ee:dd |
在sfc-vm-1上ssh 4.0.0.8(即sfc-vm-3的p6端口):
SFC-VM-1抓图:
sfc-vm-2中间节点报文抓取截图:
sfc-vm-2 eth0口:
sfc-vm-2 eth1口:
sfc-vm-3上抓图, 能够正确抓到从sfc-vm-2发过来的报文:
计算节点上br-int的流表信息, 可以发现报文确实走的相应流表, 流表统计上
总结如下:
OVS agent在br-int中加了以下流用来实现sfc portchain:
1. table:0 增加sfc流表用来匹配流分类规则, 然后转发给group表做负载均衡
2. table:5 封装sfc头部, 并转发给下一跳nfv虚拟机, 可能在远端节点走br-tun或本地节点走table:10
3. table:10做sfc报头解封装, 并转发给nfv虚拟机
2. 限制
1. 目前不支持nsh头。
networking-sfc项目底层ovs驱动暂时是借用了mpls来实现sfc报文封装的, 其最终目标会通过使用标准nsh报文头来封装sfc。目前底层的openvswitch官方组件还不支持nsh解析、处理, 不过有人fork了ovs的代码自己实现了nsh标准:
https://github.com/pritesh/ovs/tree/nsh-v8
2. 业务链上的logical_source_port必须和整条链上第一个port-pair group中的所有port_pair上的ingress port在一个subnet中, 否则会报"Cross-subnetchain not supported"
3. 业务链上的相邻的2个port-pair group中, 前一个port-pair group中的所有port-pair上的egress port必须和后一个port-pair group上的所有port-pair上的ingress port在一个subnet中, 否则会报"Cross-subnetchain not supported"
4. 命令openstack sfc flow classifier create, 中必须指定logicalsource port, 文档中没有指出。
5. symmetric链中, 必须指定logicaldestination port
6. flow classifier中只能指定ethertype=IPv6或者IPv4,
3. 参考资料
Neutron SFC
Wiki
https://wiki.openstack.org/wiki/Neutron/ServiceInsertionAndChaining
Blueprints
https://blueprints.launchpad.net/neutron/+spec/openstack-service-chain-framework
https://blueprints.launchpad.net/neutron/+spec/intent-based-service-chaining
https://blueprints.launchpad.net/neutron/+spec/neutron-api-extension-for-service-chaining
https://blueprints.launchpad.net/neutron/+spec/common-service-chaining-driver-api
API Spec
https://docs.openstack.org/developer/networking-sfc/
https://github.com/openstack/networking-sfc/blob/master/doc/source/api.rst
https://review.openstack.org/#/c/208663/8/doc/source/portchain-ovs-driver-agent.rst
代码review
https://review.openstack.org/#/q/topic:networking-sfc,n,z
OpenStack cli
https://review.openstack.org/#/c/344920/
OVS NSH
http://openvswitch.org/support/ovscon2015/16/1040-elzur.pdf
OpenStack 业务链networking-sfc介绍 (2) - 底层原理的更多相关文章
- OpenStack 业务链networking-sfc介绍 (1) - 概述
原文链接:https://blog.csdn.net/bc_vnetwork/article/details/65630355 1. Service Function Chain概述 Neutron ...
- Docker底层原理介绍
1.docker介绍 1.1什么是docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻 ...
- 最简单的HashMap底层原理介绍
HashMap 底层原理 1.HashMap底层概述 2.JDK1.7实现方式 3.JDK1.8实现方式 4.关键名词 5.相关问题 1.HashMap底层概述 在JDK1.7中HashMap采用的 ...
- JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能
摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...
- 拜托!面试请不要再问我Spring Cloud底层原理
概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...
- 深入源码分析SpringMVC底层原理(二)
原文链接:深入源码分析SpringMVC底层原理(二) 文章目录 深入分析SpringMVC请求处理过程 1. DispatcherServlet处理请求 1.1 寻找Handler 1.2 没有找到 ...
- 《React Native 精解与实战》书籍连载「React Native 底层原理」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
- 并发之volatile底层原理
15.深入分析Volatile的实现原理 14.java多线程编程底层原理剖析以及volatile原理 13.Java中Volatile底层原理与应用 12.Java多线程-java.util.con ...
- 拜托!面试请不要再问我Spring Cloud底层原理[z]
[z]https://juejin.im/post/5be13b83f265da6116393fc7 拜托!面试请不要再问我Spring Cloud底层原理 欢迎关注微信公众号:石杉的架构笔记(id: ...
随机推荐
- 利用MemoryAnalyzer进行OutOfMemoryError的诊断分析
这篇帖子只介绍利用MemoryAnalyzer进行简单的JVM的堆的分析,至于JVM的内部结构是怎么样的,这里不进行分析.好吧,废话不多说:首先如果我们要分析JVM某个时刻的Heap的对象分配情况,我 ...
- Timer控件的使用限制和注意事项
Timer的Interval 属性当编写 Timer 组件时,需要考虑 Interval 属性的几点限制:1. 如果应用程序或另一个应用程序对系统需求很大(如长循环.大量的计算或驱动程序.网络或端口访 ...
- http://www.5xcg.com/bbs/forum.php?mod=viewthread&tid=51143&extra=page%3D1
http://www.5xcg.com/bbs/forum.php?mod=viewthread&tid=51143&extra=page%3D1 因为身在酒店设备有限,只能尽量把文字 ...
- django中文件下载(HttpResponse)
最近一个用django开发的web项目要进行数据的导入导出,所以有必要了解下. django中主要用HttpResponse将请求结果返回给浏览器,所以文件的下载也是通过改对象进行处理的,具体的一个列 ...
- MyEclipse10.0 采用插件方式安装 SVN(转)
原文:http://blog.sina.com.cn/s/blog_a5f093b401015uzl.html 一.到官方上下载svn1.8.3,下载后的文件名叫site-1.8.3.zip 地址:h ...
- go_接口
duck typeing 隐式的实现接口的方法就等于实现了接口 main函数 package main import ( "fmt" "learngo/retriever ...
- freemaker在表格中遍历数据
Controller层如下所示: @RequestMapping(value = "/test", method = RequestMethod.GET) public Strin ...
- 27.Remove Element(Array)
Given an array and a value, remove all instances of that value in place and return the new length. T ...
- MVC数据注解
数据注解 using System.ComponentModel.DataAnnotations; KeyAttribute 唯一主键StringLengthAttribute 字符串长度约束MaxL ...
- Windows10远程桌面连接配置
被控电脑在TP-Link路由器 1.基本设置 被控端电脑设置:1)被控端的电脑系统需要是Windows专业版或者企业版,家庭中文版的系统是不支持远程访问功能的: 2)被控端打开远程桌面功能,在系统的设 ...