原文链接: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. email 解析 ,发送 邮件

    email 来源:https://blog.csdn.net/xyang81/article/details/7675160     详见此人其它mail 篇 参考2:http://lib.csdn. ...

  2. 串口通信,帧与帧之间的时间间隔问题?9600波特率,帧将各在20ms以上

  3. mac使用备注

    快捷键: 掌握好多手势和快捷键可以有效的提高工作效率,触控板和快捷键基本让你可以脱离鼠标. Command+Tab                   任意情况下切换应用程序 - 向前循环 Shift ...

  4. 在 springboot 中如何整合 shiro 应用 ?

     Shiro是Apache下的一个开源项目,我们称之为Apache Shiro. 它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与spring Security 一样都是 ...

  5. javascript的构造函数和实例对象、prototype和__proto__的区别,原型对象及构造器的理解

    一.前言 我们先通过代码来分别打印出实例对象.构造函数,以及修改了原型对象的构造函数,通过对比内部结构来看看他们之间的区别. //定义构造函数 function Person(name, age){ ...

  6. VMTurbo采用红帽企业虚拟化软件

    VMTurbo公司正处于虚拟化的开始阶段,并将继续向虚拟世界迈进.该公司已宣布官方支持Red Hat 公司的Enterprise Virtualization 3.1.VMTurbo公司采用Red H ...

  7. php 共享内存学习(APC扩展)

    问题:希望可以在进程间共享变量,为共享数据提供快速访问 解决方案:使用APC扩展的数据存储功能 (cli模式下没有作用) //获取原来的值 $population = apc_fetch('popul ...

  8. DSOFramer 控件修改成功

    1.Html电子印章.手写签名系统演示:http://www.dianju.com.cn/video.htm 在线试用: http://www.dianju.com.cn/websignpiaoju/ ...

  9. gen_empty_obj算子的作用

    gen_empty_obj 算子解释: Create an empty object tuple. 其算子签名为: gen_empty_obj( : EmptyObject : : ) 那么有人要问: ...

  10. springboot2.0整合jpa

    在整合的遇到各种坑,以下是我整合的流程 1.pom.xml文件 <dependencies> <dependency> <groupId>org.springfra ...