中子分类器和QoS DSCP集成

https://bugs.launchpad.net/neutron/+bug/1476527

中子分类器(NC)是一个服务插件,它提供了一个API来定义流量类,供其他中子服务使用。

服务质量(QoS)是OpenStack Neutron的一个扩展,它为管理员提供了一个服务,用于在端口级别指定和强制执行SLA,基于丢弃优先级、带宽控制和带宽保证。

通过将NC的分类组资源引入到QoS的规则资源中,我们可以实现更具针对性的SLA,允许管理员基于流量类而不是中子端口级别来限制、优先处理或保证流量。本规范将重点关注基于每个端口的流量类的丢弃优先级。

问题描述

中子的服务质量扩展允许在Neutron端口级别强制执行SLA,但它没有提供一个资源来允许管理员为进入或离开端口的不同流量类定义SLA。

这导致了一种针对流量类SLA的“全有或全无”的方法,要么离开端口的所有流量都接收相同的DSCP标记,要么流量保留由工作负载分配的默认DSCP标记。

示例用例

  • 为离开TCP端口YY的流量分配比离开中子端口的其他流量更高的丢弃优先级。

  • 覆盖实例分配给IPv6地址XX和UDP端口YY的现有DSCP标记。

提议的变更

为了以不涉及在中子中引入外部依赖关系的方式消耗中子分类器的分类资源,中子分类器服务插件需要将其迁移到核心中子存储库中。

资源模型和API的详细信息可以在这里找到‘NC API规范’_

对中子QoS扩展所需的修改是最小的,它涉及在DSCP标记规则中引入两个变量。第一个变量获取分类组的ID(一组单独的分类),QoS后端可以将其用于将DSCP标记定向到流量类,而不是标记离开端口的所有流量。

另一个变量,优先级值,将是一个范围从0-1000的正整数,优先级递增。这将允许管理员决定在2个DSPC规则分类重叠的情况下应应用哪些DSCP标记规则。例如

openstack network qos policy create example_policy

openstack network qos rule create example_policy --type dscp-marking \
    --dscp-mark 22

openstack network classification create ethernet --ethertype 0x0800 \
    eth_ipv4
openstack network classification create ipv4 --protocol 6 \
    ipv4_tcp
openstack network classification create tcp --dst-port-max 80 \
    tcp_80
openstack network classification group create class_1 \
    --classification tcp_80 ipv4_tcp eth_ipv4

openstack network qos rule create example_policy --type dscp-marking \
    --dscp-mark 28 --classification-group-id class_1 \
    --classification-priority 100

openstack network classification create ipv4 --dst-addr 10.0.0.5 \
    ipv4_dst
openstack network classification group create class_2 \
    --classification ipv4_dst eth_ipv4

openstack network qos rule create example_policy --type dscp-marking \
    --dscp-mark 24 --classification-group-id class_2 \
    --classification-priority 600

openstack network classification create ethernet --ethertype 0x86DD \
    eth_ipv6
openstack network classification create ipv6 --next-header 17 \
    --dst-addr 0:0:0:0:0:ffff:a00:5 ipv6_dst
openstack network classification create udp --dst-port-max 21 \
    udp_21
openstack network classification group create class_3 \
    --classification eth_ipv6 ipv6_dst udp_21

openstack network qos rule create example_policy --type dscp-marking \
    --dscp-mark 8 --classification-group-id class_3 \
    --classification-priority 158

openstack network classification create ethernet --ethertype 0x0806 \
    eth_arp
openstack network classification group create class_4 \
    --classification eth_arp

openstack network qos rule create example_policy --type dscp-marking \
    --dscp-mark 40 --classification-group-id class_4 \
    --classification-priority 999

openstack network qos rule list example_policy
+--------------------------------------+--------------------------------------+--------------+----------+-----------------+----------+-----------+-----------+--------------------------------------+----------+
| ID                                   | QoS Policy ID                        | Type         | Max Kbps | Max Burst Kbits | Min Kbps | DSCP mark | Direction | Classification Group                 | Priority |
+--------------------------------------+--------------------------------------+--------------+----------+-----------------+----------+-----------+-----------+--------------------------------------+----------+
| 153e4957-5c50-47f5-b934-c30eb3ada180 | 812c3e2e-cc86-4842-b41b-6b69419a123b | dscp_marking |          |                 |          |        40 |           | ae0de79d-c26a-4090-8ec2-0d1ae62797f2 |      999 |
| 184d7156-ab93-444e-96eb-f91cf8c9160e | 812c3e2e-cc86-4842-b41b-6b69419a123b | dscp_marking |          |                 |          |         8 |           | b0fd0ca7-8596-4053-b69b-630016acfd28 |      158 |
| 385970f8-9a6c-4fe2-a328-95630138c9ca | 812c3e2e-cc86-4842-b41b-6b69419a123b | dscp_marking |          |                 |          |        28 |           | 6adb4199-e42f-4fa9-8ab6-2bf64e2ea68d |      100 |
| 7fa581ac-8b82-4d64-9032-52b1ce9f3509 | 812c3e2e-cc86-4842-b41b-6b69419a123b | dscp_marking |          |                 |          |        22 |           |                                      |        0 |
| d1c5268b-302c-498b-bfd7-484e19fd28af | 812c3e2e-cc86-4842-b41b-6b69419a123b | dscp_marking |          |                 |          |        24 |           | cd0a1ea2-0cdf-42b0-a4fc-7f581d4a4be2 |      600 |
+--------------------------------------+--------------------------------------+--------------+----------+-----------------+----------+-----------+-----------+--------------------------------------+----------+

在上述类之间没有明确的优先级,则类class_1、class_3、class_4和class_5也会匹配class_2。根据后端,这可能会导致没有明确优先级机制的情况下出现不可预测的行为。

为了适应这些更改,需要在后端进行修改,以允许驱动程序从服务插件检索分类定义。这将通过扩展代理扩展API来实现。通过扩展此API,所有扩展都将可以访问分类,而无需引入任何其他资源。

数据模型影响

为了在升级时提供一致的功能,classification_group_id默认为None,这意味着DSCP标记规则的行为将与引入此功能之前的方式相同。

拟议的更改将导致模型如下所示

属性名称

类型

访问

默认值

验证/转换

描述

id

字符串 (UUID)

RO,全部

N/A

uuid

QoSRule 标识符

qos_policy_id

字符串 (UUID)

RO,全部

N/A

uuid

QoSPolicy 引用 UUID

dscp_mark

整数 (枚举)

RW, tenant

N/A

0 和 56,除了 2-6、42、44 和 50-54

DSCP 标记

classification_group_id

字符串 (UUID)

RW, tenant

uuid

分类组引用 UUID

classification_priority

integer

RW, tenant

0

一个正整数

正整数表示此规则的优先级

另一个修改是取消了qos_policy_id上的唯一约束。它已被qos_policy_id和classification_group_id的元组上的唯一约束所取代。这是为了允许在同一策略中具有不同的分类的多个DSCP规则,包括classification_group_id为None时。因此,一个QosPolicy只能有一个classification_group_id设置为None的DSCPMarkingRule。

中子数据库表:QosDSCPMarkingRule

  • id:主键

  • qos_policy_id:QosPolicy.id的外键

  • dscp_mark:定义集合内的整数。

  • classification_group_id:ClassificationGroup.id的外键

  • classification_priority:0到1000之间的正整数

在深入研究数据模型、API以及分类的使用方式的更多细节之前,需要澄清几点

  • 1 分类是单一类型,例如,以太网、IP、HTTP或特定CCF版本支持的另一种类型。定义,即匹配的字段,取决于指定的类型。

  • 为了澄清,分类类型定义了分类的可能字段和值的集合(本质上,该类型的实例)。分类类型在代码中定义,而分类通过REST API作为这些类型的实例创建。

  • 并非所有受支持的字段都需要定义 - 仅由消耗服务需要并应在消耗时进行验证的字段。

  • 还有分类组,它们允许使用布尔运算符将分类或其他分类组组合在一起。CG是最终将被消耗服务消耗的资源。

  • 从消耗服务的角度来看,只能读取分类,不能创建或删除。它们需要在用户面临的分类API中使用之前创建。

  • 由于中子分类器无法强制其消费者进行更新操作,并且用户可能不知道分类的所有消费者,因此分类的“定义”和“类型”字段以及分类组的“分类”、“分类组”和“运算符”字段在创建后无法更新。例如,分类同时被QoS和安全组消耗,而用户只知道QoS消耗该分类。

CCF的初始模型将包括以下分类类型:以太网、IPv4、IPv6、TCP和UDP,这些类型组合起来足以提供任何5元组分类。

下表显示了分类组的属性(RW上的星号表示该属性不可更新)

属性名称

类型

访问 CRUD

默认值

验证/转换

描述

id

字符串 (UUID)

RO,全部

生成

uuid

Identity

project_id

字符串 (UUID)

RO,项目

从身份验证令牌

uuid

项目ID

name

string

RW,项目

string

分类组名称

description

string

RW,项目

string

人类可读的描述

共享

bool

RW,项目

False

布尔值

与其他项目共享

operator

字符串 (值)

RW*,项目

“and”

[“and”,

“or”]

布尔连接词:AND/OR

classification_groups

list

RW*,项目

[]

包含的分类组列表

classifications

list

RW* 项目

[]

包含的分类列表

消耗服务将消耗分类组,而不是原子分类,任何分类都需要分组到分类组中才能单独消耗。因此,“operator”字段对于仅包含1个分类的分类组将被忽略。

下表显示了本规范中提到的任何类型的分类的属性(RW上的星号表示该属性不可更新)

属性名称

类型

访问

默认值

验证/转换

描述

id

字符串 (UUID)

RO,全部

生成

uuid

Identity

project_id

字符串 (UUID)

RO,项目

从身份验证令牌

uuid

项目ID

name

string

RW,项目

string

分类名称

description

string

RW,项目

string

人类可读的描述

type

string

RW*,项目

来自类型的枚举

分类的类型

definition

类型特定的属性将放在这里,鉴于它们的数量,除非要求,否则我不会详细说明它们。

每种类型的分类组和分类都将存储为以下表和关系(表名带有前缀 ccf_

                          +---------------------+
                          |classification_groups|
                          +---------------------+
                          |id                   |*
                          |cg_id                +--------+
                          |name                 |        |
                          |description          |        |
                          |project_id           |        |
                          |shared               +--------+
                          |operator             |1
                          +---------------------+
                                      |1
                                      |
                                      |*
                      +------------------------------+
                      |classification_groups_mapping |
                      +------------------------------+
                      |cg_id                         |
                      |classification_id             |
                      +------------------------------+
                                      |1
+--------------------+                |                +--------------------+
|ipv4_classifications|                |                |ipv6_classifications|
+--------------------+                |                +--------------------+
|classification_id   |                |                |classification_id   |
|ihl                 |1               |               1|traffic_class       |
|diffserv            +--------+       |       +--------+traffic_class_mask  |
|diffserv_mask       |        |       |       |        |length              |
|length              |        |       |       |        |next_header         |
|flags               |        |       |       |        |hops                |
|flags_mask          |        |       |       |        |src_addr            |
|ttl                 |        |1      |1     1|        |dst_addr            |
|protocol            |     +---------------------+     +--------------------+
|src_addr            |     |classifications      |
|dst_addr            |     +---------------------+
|options             |     |id                   |
|options_mask        |     |name                 |
+--------------------+     |description          |
                           |project_id           |
                           |shared               |     +-------------------+
                           |type                 |     |tcp_classifications|
                           +---------------------+     +-------------------+
                             1|      1|       |1       |classification_id  |
+-------------------+         |       |       |        |src_port           |
|udp_classifications|         |       |       |        |dst_port           |
+-------------------+         |       |       |        |flags              |
|classification_id  |1        |       |       |       1|flags_mask         |
|src_port           +---------+       |       +--------+window             |
|dst_port           |                1|                |data_offset        |
|length             |     +------------------------+   |option_kind        |
|window_size        |     |ethernet_classifications|   +-------------------+
+-------------------+     +------------------------+
                          |classification_id       |
                          |preamble                |
                          |src_addr                |
                          |dst_addr                |
                          |ethertype               |
                          +------------------------+

屏蔽字段允许用户指定在分类期间应查找各自主字段的哪些单独位。

分类类型用于选择分类的适当模型,从而确定它将存储在哪个表中。

分类组存储在单个表中,可以指向其他分类组,以允许混合布尔运算符。

operator 在分类组中:指定用于连接该组的所有子分类和分类组的布尔运算符。可以是AND或OR。

OR:逻辑OR,这些组中的分类在流量类中可以互换,例如ipv4 dst_addr y.y.y.y 或 ipv6 dst_addr Z::ZZZZ。

AND:逻辑AND,分类或分类组用于创建流量类,该分类的组成可以由分类或OR运算的分类组组成。

REST API 影响

拟议属性

SUB_RESOURCE_ATTRIBUTE_MAP = {
   'dscp_marking_rules':{
        'parent': {'collection_name': 'policies',
                   'member_name': 'policy'},
        'parameters': dict(QOS_RULE_COMMON_FIELDS,
            **{'dscp_mark': {
                'allow_post': True, 'allow_put': True,
                'convert_to': attr.convert_to_int,
                'is_visible': True, 'default': None,
                'validate': {'type:values': common_constants.
                            VALID_DSCP_MARKS}
              },
               'classification_group_id': {
                'allow_post': True,
                'allow_put': True,
                'is_visible': True,
                'default': None,
                'validate': {'type:uuid_or_none': None}
              },
               'classification_priority': {
                'allow_post': True,
                'allow_put': True,
                'convert_to': attr.convert_to_int,
                'is_visible': True,
                'default': 0,
                'validate': {'type:values': range(1000)}
        }
}

示例 REST 调用

GET /v2.0/qos/policies

Response:
{
    "policy": {
        "name": "AF32",
        "project_id": "<project-id>",
        "id": "<id>",
        "description": "This policy marks DSCP outgoing AF32 traffic for DTV Control",
        "shared": "False"
     }
}

GET /v2.0/qos/policies/<policy-uuid>

Response:
{
    "policy": {
        "tenant_id": "<tenant-id>",
        "id": "<id>",
        "name": "AF32",
        "description": "This policy marks DSCP outgoing AF32 traffic for DTV Control",
        "shared": False,
        "dscp_marking_rules": [{
            "id": "<id>",
            "policy_id": "<policy-uuid>",
            "dscp_mark": 16,
            "classification_group_id": "<classification_group_id>",
            "classification_priority": 800
        }]
     }
}

POST /v2.0/qos/policies/<policy-uuid>/dscp-marking-rules/
{
    "dscp_marking_rule": {
        "dscp_mark": 16
    }
}

Response:
{
    "dscp_marking_rule":{
        "id": "<id>",
        "policy_id": "<policy-uuid>",
        "dscp_mark": 16,
        "classification_group_id": None,
        "classification_priority": 0
    }
}

GET /v2.0/classification_groups/<classification_group_id>
{
    "classification_group":{
        "id": "<classification_group_id>",
        "project_id": "<project_id>",
        "name": "ipv4-group"
        "description": "",
        "classification": [
            {
                "id":"<classification_id>",
                "name":"ipv4-dscp"
                "project_id":"<project_id>",
                "c_type": "ipv4",
                "description": "",
                "shared":false,
            }
        ],
        "classification_group": [],
        "operator": "AND",
        "shared": false,
    }
}

PUT /v2.0/qos/policies/<policy-uuid>/dscp-marking-rules/<rule-uuid>
{
    "dscp_marking_rule": {
        "dscp_mark": 8,
        "classification_group_id": "<classification_group_id>"
    }
}

Response:
{
    "dscp_marking_rule":{
        "id": "<id>",
        "policy_id": "<policy-uuid>",
        "dscp_mark": 8,
        "classification_group_id": "<classification_group_id>",
        "classification_priority": 0

    }
}

文档影响

用户文档

现有的 网络指南 将为此功能进行更新。

现有的 CLI指南 将为此功能进行更新。

开发人员文档

现有的 QoS devref文档 将为此功能进行更新。还将为Neutron Classifier API起草一份新文档。

API 文档

现有的 QoS API文档 将为此功能进行更新。还将为Neutron Classifier API起草一份新文档。

参考资料