原文链接: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

https://blueprints.launchpad.net/neutron/+spec/service-registration-and-integration-for-service-chaining

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) - 底层原理的更多相关文章

  1. OpenStack 业务链networking-sfc介绍 (1) - 概述

    原文链接:https://blog.csdn.net/bc_vnetwork/article/details/65630355 1.  Service Function Chain概述 Neutron ...

  2. Docker底层原理介绍

    1.docker介绍 1.1什么是docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻 ...

  3. 最简单的HashMap底层原理介绍

    HashMap 底层原理  1.HashMap底层概述 2.JDK1.7实现方式 3.JDK1.8实现方式 4.关键名词 5.相关问题 1.HashMap底层概述 在JDK1.7中HashMap采用的 ...

  4. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

  5. 拜托!面试请不要再问我Spring Cloud底层原理

    概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...

  6. 深入源码分析SpringMVC底层原理(二)

    原文链接:深入源码分析SpringMVC底层原理(二) 文章目录 深入分析SpringMVC请求处理过程 1. DispatcherServlet处理请求 1.1 寻找Handler 1.2 没有找到 ...

  7. 《React Native 精解与实战》书籍连载「React Native 底层原理」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  8. 并发之volatile底层原理

    15.深入分析Volatile的实现原理 14.java多线程编程底层原理剖析以及volatile原理 13.Java中Volatile底层原理与应用 12.Java多线程-java.util.con ...

  9. 拜托!面试请不要再问我Spring Cloud底层原理[z]

    [z]https://juejin.im/post/5be13b83f265da6116393fc7 拜托!面试请不要再问我Spring Cloud底层原理 欢迎关注微信公众号:石杉的架构笔记(id: ...

随机推荐

  1. 利用MemoryAnalyzer进行OutOfMemoryError的诊断分析

    这篇帖子只介绍利用MemoryAnalyzer进行简单的JVM的堆的分析,至于JVM的内部结构是怎么样的,这里不进行分析.好吧,废话不多说:首先如果我们要分析JVM某个时刻的Heap的对象分配情况,我 ...

  2. Timer控件的使用限制和注意事项

    Timer的Interval 属性当编写 Timer 组件时,需要考虑 Interval 属性的几点限制:1. 如果应用程序或另一个应用程序对系统需求很大(如长循环.大量的计算或驱动程序.网络或端口访 ...

  3. 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 因为身在酒店设备有限,只能尽量把文字 ...

  4. django中文件下载(HttpResponse)

    最近一个用django开发的web项目要进行数据的导入导出,所以有必要了解下. django中主要用HttpResponse将请求结果返回给浏览器,所以文件的下载也是通过改对象进行处理的,具体的一个列 ...

  5. MyEclipse10.0 采用插件方式安装 SVN(转)

    原文:http://blog.sina.com.cn/s/blog_a5f093b401015uzl.html 一.到官方上下载svn1.8.3,下载后的文件名叫site-1.8.3.zip 地址:h ...

  6. go_接口

    duck typeing 隐式的实现接口的方法就等于实现了接口 main函数 package main import ( "fmt" "learngo/retriever ...

  7. freemaker在表格中遍历数据

    Controller层如下所示: @RequestMapping(value = "/test", method = RequestMethod.GET) public Strin ...

  8. 27.Remove Element(Array)

    Given an array and a value, remove all instances of that value in place and return the new length. T ...

  9. MVC数据注解

    数据注解 using System.ComponentModel.DataAnnotations; KeyAttribute 唯一主键StringLengthAttribute 字符串长度约束MaxL ...

  10. Windows10远程桌面连接配置

    被控电脑在TP-Link路由器 1.基本设置 被控端电脑设置:1)被控端的电脑系统需要是Windows专业版或者企业版,家庭中文版的系统是不支持远程访问功能的: 2)被控端打开远程桌面功能,在系统的设 ...