概述

Neutron的SFC (Service Function Chaining, SFC, 业务链)是由华为主导并开发的一个neutron下的服务框架。
其目的是动态建立服务链使不同租户的流量可以按照不同顺序导向不同的服务功能模块。其概念类似于策略路由, 即SFC使网络报文流量走特定的路径,而不是通过IP目的地址来查看路由表得最终目的地。

Service function chain (SFC) essentially refers to the software-defined networking (SDN) version of policy-based routing (PBR).

需要说明的是,虽然将 SFC 解释为软件定义实现的 PBR ,但其技术实现并不涉及路由行为,是在二层上根据流量特征将流量导向另外一个 port 。

架构

port-chain-architecture-diagram.png
port-chain-diagram.png

OpenStack网络服务和OpenStack计算实例通过端口连接到一个虚拟网络,使得仅使用端口创建服务链的流量转向模型成为可能。 将这些端口包括在端口链中使得能够通过提供服务功能的一个或多个实例来引导流量。

端口链包含:

  • 定义服务功能顺序的一组端口。
  • 一组流分类器,用于指定进入链中的分类流量。

如果一个业务功能涉及一对端口,则第一个端口作为业务功能的入端口,第二个端口作为出端口。如果两个端口使用相同的值,则它们作为单个虚拟双向端口。

端口链是一个单向的服务链。第一个端口作为服务功能链的头部,第二个端口作为服务功能链的尾部。双向服务功能链由两个单向端口链组成。

流分类器只能属于一个端口链,以防止流中的哪个链应该处理分组的歧义。但是,可以将多个流分类器与端口链关联,因为多个流可以请求相同的服务功能路径。

目前,SFC缺乏对多项目服务功能的支持。

端口链插件支持后台服务提供商,包括OVS驱动程序和各种SDN控制器驱动程序。通用驱动程序API使不同的驱动程序能够为服务链路径呈现提供不同的实现。

涉及资源

(资源指SFC功能中需要定义的一些虚拟组件。)

Port pair

端口对表示包括入口(ingress port)和出口(egress port)端口的服务功能实例。 包含双向端口的服务功能使用相同的入口和出口端口。

“service_function_parameters”属性包括一个或多个服务功能的参数。 目前,它仅支持确定分组与链的关联的相关参数。 对于缺少对相关性(如NSH)的支持的传统服务功能,此参数默认为“none”。 如果设置为无,数据面板实现必须提供服务功能代理功能。

Port pair group

端口对组可能包含一个或多个端口对。

多个端口对通过一组功能相当的服务功能实现负载平衡/分配。

Flow classifier

流分类器是比较重要的部分,定义了哪些对应的流量需要处理,因此详细讲解一些其配置参数。

  • id - 流分类器的IP
  • project_id - 流分类器所属项目的ID
  • name - 可视化名称
  • description - 可视化描述
  • ethertype - 以太网协议类型 (IPv4/IPv6)
  • protocol - IP 协议类型
  • source_port_range_min - 协议(TCP/UDP)最小源端口号
  • source_port_range_max - 协议(TCP/UDP)最大源端口号
  • destination_port_range_min - 协议(TCP/UDP)最小目的端口号
  • destination_port_range_max - 协议(TCP/UDP)最大目的端口号
  • source_ip_prefix - 具体源IP地址或子网
  • destination_ip_prefix - 具体目的IP地址或子网
  • logical_source_port - neutron中的port id 或 port name。driver为ovs 时,此项为必填项。
  • logical_destination_port - neutron中的port id 或 port name。
  • l7_parameters - 7层协议的参数字典。

源属性的组合定义了流的来源。 目的地属性的组合定义了流的目的地。

“l7_parameters”属性是一个占位符,可用于支持使用第7层字段(如URL)进行流分类。 如果未指定,则logical_source_port和logical_destination_port属性默认为none。

ethertype属性默认为IPv4,所有其他属性默认为通配符值。

Port chain

实际生效配置,比较重要的三个参数为:

  • port_pair_groups - 端口对组列表
  • flow_classifiers - 流分类器列表
  • chain_parameters - 链属性字典

一个端口链由一系列端口对组组成。每个端口对组都是端口链路中的一跳。 一组端口对代表提供等同功能的服务功能。 例如,一组防火墙服务功能。

一个端口链可以包含多个流分类器。 省略流分类器可以有效地防止通过端口链的流量转向。

“chain_parameters”属性包含一个或多个端口链参数。 目前,它仅支持默认为mpls的关联参数,以便与Open vSwitch(OVS)功能保持一致。 相关参数的未来值可以包括网络服务报头(NSH)。

原理分析

逻辑实现

SFC 分为两大模块: 流分类( flow classifier )和 sfc (业务链) ,2大模块各自可以配置独立的驱动, 目前都只是通过 ovs 实现。按照官方想法,以后流分类( sg、fw,、qos、sfc 等模块均包含流分类)这个功能会抽象出来统一维护。

示例如下,创建业务链串联 sf1, sf2, sf3 三台虚拟机, 并从VM1处发包进入业务链:

1
2
3
4
5
6
         +------+     +------+        +------+
| SF1 | | SF2 | | SF3 |
+------+ +------+ +------+
p1| |p2 p3| |p4 p5| |p6
| | | | | |
VM 1-->----+ +--------+ +-----------+ +---->

  • 流分类
    根据流量特征(详见上文 Flowclassifier)定义需要进行引流的流量,与 port chain 的关系为 n:1。

  • 业务链
    如上图示例所示,每个 SF 拥有一对定义了 ingress 和 egress 的 port pair (可以是同一个端口),它们在二层上依次串联起来。

底层实现

通过在 ovs 上复写 mac 实现引流,具体报文封装和解封装过程如下:

同上文逻辑实现中的示例不一样,上文全是 service function 形成的一条业务链,这里只有 VM4 为 service function ,M2、M3、M5 为宿主机,M1、M6 分别为流量的源、目的虚机。

SFC封装和解封装过程.png

附:
br-int flow 参考信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
每一跳入口的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出口处做负载均衡的:

1
2
3
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】

限制

  • driver 选择为 ovs 时,logical-source-port 为必选项
  • 二层引流,业务链的起始口必须和 logical-source-port 在一个子网中, 两个 service function 相连的 port 也必须在同一个子网中

参考链接

https://docs.openstack.org/neutron/queens/admin/config-sfc.html
https://wiki.openstack.org/wiki/Neutron/ServiceInsertionAndChaining
https://blog.csdn.net/bc_vnetwork/article/details/65630475