From 8dcd74334d041820ae47d9d2f5ea7f783a1c574c Mon Sep 17 00:00:00 2001 From: pttch Date: Mon, 20 Dec 2021 12:09:36 +0800 Subject: [PATCH 1/7] Add VLAN Stacking HLD --- doc/vlan_stacking/images/QinQ_usecase.png | Bin 0 -> 29427 bytes .../images/VlanStack config flow.png | Bin 0 -> 34009 bytes .../images/vlan_xlate_usecase.png | Bin 0 -> 6865 bytes doc/vlan_stacking/vlan_stacking_HLD.md | 635 ++++++++++++++++++ 4 files changed, 635 insertions(+) create mode 100644 doc/vlan_stacking/images/QinQ_usecase.png create mode 100644 doc/vlan_stacking/images/VlanStack config flow.png create mode 100644 doc/vlan_stacking/images/vlan_xlate_usecase.png create mode 100644 doc/vlan_stacking/vlan_stacking_HLD.md diff --git a/doc/vlan_stacking/images/QinQ_usecase.png b/doc/vlan_stacking/images/QinQ_usecase.png new file mode 100644 index 0000000000000000000000000000000000000000..266bb45299e77fd61903fb24bd1596e1d506c168 GIT binary patch literal 29427 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 literal 0 HcmV?d00001 diff --git a/doc/vlan_stacking/images/VlanStack config flow.png b/doc/vlan_stacking/images/VlanStack config flow.png new file mode 100644 index 0000000000000000000000000000000000000000..b56f5383137ae6816222b708f124b4c16c43b56e GIT binary patch literal 34009 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 McEH(Jz>mfK4;GPI!~g&Q literal 0 HcmV?d00001 diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md new file mode 100644 index 0000000000..ff7d459ae8 --- /dev/null +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -0,0 +1,635 @@ + ### Rev 0.1 + +# Table of Contents + +- [List of Tables](#list-of-tables) +- [Revision](#revision) +- [Scope](#scope) +- [Definitions/Abbreviations](#definitionsabbreviations) +- [Overview](#overview) + - [VLAN Stacking Deployment Use Cases](#vlan-stacking-deployment-use-cases) + - [QinQ Use Case](#qinq-use-case) + - [VLAN Translation Use Case](#vlan-translation-use-case) +- [Architecture Design](#architecture-design) +- [Requirements](#requirements) + - [Configuration](#configuration) +- [High-Level Design](#high-level-design) + - [VlanMgr](#vlanmgr) + - [DB](#db) + - [CONFIG_DB](#config_db) + - [APPL_DB](#appl_db) + - [SAI API](#sai-api) +- [Configuration and management](#configuration-and-management) + - [CLI/YANG model Enhancements](#cliyang-model-enhancements) + - [CLI](#cli) + - [Yang model](#yang-model) + - [Examples](#examples) + - [Examples of QinQ Configuration](#examples-of-qinq-configuration) + - [Examples of VLAN Translation Configuration](#examples-of-vlan-translation-configuration) +- [Warmboot and Fastboot Design Impact](#warmboot-and-fastboot-design-impact) +- [Restrictions/Limitations](#restrictionslimitations) +- [Testing Requirements/Design](#testing-requirementsdesign) + - [System Test Cases](#system-test-cases) + +# List of Tables + +* [Table 1: Revision](#revision) +* [Table 2: Definitions/Abbreviations](#definitionsabbreviations) +* [Table 3: SAI attributes related to VLAN stacking](#sai-api) + +# Revision + +###### Table 1: Revision + +| Rev | Date | Author | Change Description | +|:-----:|:----------:|:-------------:|--------------------| +| 0.1 | 8-Oct-2020 | Tommy Tseng | Initial version | + +# Scope + +This document describes the high level design of VLAN stacking feature. + +# Definitions/Abbreviations + +###### Table 2: Definitions/Abbreviations + +| Abbreviation | Full form | +|--------------|------------------------| +| VID | Virtual LAN Identifier | +| S-VLAN | Service Provider VLAN | +| C-VLAN | Customer VLAN | +| S-TAG | S-VLAN tag | +| C-TAG | C-VLAN tag | + +# Overview + +This document describes the design details of the VLAN stacking feature. VLAN stacking is a feature designed for service providers who carry traffic of multiple customers across  their networks and are required to maintain the VLAN and Layer 2 protocol configurations of each customer without impacting the traffic of other customers. VLAN stacking include QinQ feature and VLAN Translation feature. + +IEEE 802.1Q tunneling (QinQ tunneling) uses a single Service Provider VLAN (SPVLAN) for customers who have multiple VLANs. Customer VLAN IDs are preserved and traffic from different customers is segregated within the service provider’s network even when they use the same customer-specific VLAN IDs. QinQ tunneling expands VLAN space by using a VLAN-in-VLAN hierarchy, preserving the customer’s original tagged packets, and adding SPVLAN tags to each frame (also called double tagging). + +QinQ tunneling uses double tagging to preserve the customer’s VLAN tags on traffic crossing the service provider’s network. However, if any switch in the path crossing the service provider’s network does not support this feature, then the switches directly connected to that device can be configured to swap the customer’s VLAN ID with the service provider’s VLAN ID for upstream traffic, or the service provider’s VLAN ID with the customer’s VLAN ID for downstream traffic. + +## VLAN Stacking Deployment Use Cases + +### QinQ Use Case + +The following example maps C-VLAN 10 to S-VLAN 100, C-VLAN 20 to S-VLAN 200 and C-VLAN 30 to S-VLAN 300 for ingress traffic on port 1 of Switches A and B. + +Figure 1. Mapping QinQ Service VLAN to Customer VLAN + +![QinQ use case](./images/QinQ_usecase.png) + +### VLAN Translation Use Case + +For example, assume that the upstream switch does not support QinQ tunneling. Select Port 1, and set the Old VLAN to 10 and the New VLAN to 100 to map VLAN 10 to VLAN 100 for upstream traffic entering port 1, and VLAN 100 to VLAN 10 for downstream traffic leaving port 1 as shown below. + +Figure 2. Configuring VLAN Translation + +![VLNA translate use case](./images/vlan_xlate_usecase.png) + +# Architecture Design + +The overall SONiC architecture will not be changed and no new sub-modules will be introduced. + +# Requirements + +* User **_shall_** be able to configure VLAN stacking on each Ethernet port and and channel port interface. +* A VLAN stacking configuration describes how to determine the service that the specific traffic belongs to and what rewrite action **_will_** be done for the frames. Each configuration include the following: + * Service - A VLAN ID that the specified traffic **_will_** be applied to. Range 1 ~ 4094. + * Direction - Traffic direction. + * Action - The rewrite action for the frames, support the following actions: + * push + * Apply for all tagged frames, single or double tagged frames, at ingress direction. + * Add an outer VLAN with TPID=8100, COS=0, VLAN= (range 1 ~ 4094). + * If the ingress frames (including untagged frames) not match the criteria, the frames **_will_** be forwarded using port VLAN (or call default VLAN, PVID). + * pop + * Apply for all tagged frames, single or double tagged frames, at egress direction. + * Remove outer VLAN. + * swap + * Apply for all tagged frames, single or double tagged frames. + * Replace the outer VLAN ID to (range 1 ~ 4094). The TPID and COS are not changed. + * If the ingress frames not match the criteria, + * the untagged frames **_will_** be forwarded using port VLAN. + * the tagged frames (including double tagged frames) **_will_** be forwarded using its outer VLAN. + + The summary of rewrite action support on service interface as shown in the following table: + + | Rewrite | Ingress Direction | Egress Direction | + |---------|-------------------|------------------| + | push | Supported | Not supported | + | pop | Not supported | Supported | + | swap | Supported | Supported | + +* Swap rewrite action **_will_** become invalid if configured (push, swap) at ingress direction or (pop, swap) at egress direction on the specified interface at the same time. +* Only outer TPID 8100 is supported. The frames with TPID = 8100 **_will_** be taken as tagged (single or double) frames. +* For egress direction on channel port, each match criteria **_will_** use one hardware entry per member port. + +## Configuration + +* It is able to configure VLAN stacking by modifying CONFIG_DB or reload configuration by "config load" CLI command. +* Invalid configuration with **_will_** be ignored and written an error in syslog. E.g., port is not exist. + +# High-Level Design + +## VlanMgr + +VlanMgr is used for check user configuration by DB schema, the VlanStack **_will_** parsing user configuration to SAI attributes and call SAI API. + +![VLAN Stacking create flow](./images/VlanStack%20config%20flow.png) + +VlanStack defined in Orch agent is used for all VLAN stacking related operations and keep the user configurations. + +* addEntry is used for add a C-VLAN ↔ S-VLAN mapping on the specified interface by user configuration. It function is used for updating the exist mapped, too. The update operation is implemented by remove old and then add new one, so it **_will_** effect the forwarding traffic when an entry be updating. +* removeEntry is used to remove a C-VLAN ↔ S-VLAN mapping on the specified interface. + +```c++ +struct VlanStack +{ +    std::map vlan_stack_map; + +    void addEntry(const VlanStackCfg& cfg); +    void deleteEntry(const VlanStackKey& entry_key); +}; +``` + +## DB + +### CONFIG_DB + +A new table `VLAN_STACKING` is added in Config DB. + +``` +VLAN_STACKING|{{interface_name}}|{{stage}}|{{vlanid}} +"action":  {{action}} +"s_vlanid":  {{s_vlanid}}  (optional) +``` + +``` +`interface_name`  Ethernet port and and channel port name +`stage`           Traffic direction + ingress - ingress direction + egress - egress direction +`vlanid`      Service VLAN ID + C-VLAN for ingress direction + S-VLAN for egress direction +`action`          Rewrite action + push - Adds a s_vlanid tag to an ingress packet. + pop - Pop (remove) the outermost tag. + swap - Swap outermost tag by s_vlanid. +`s_vlanid` S-VLAN ID for push and swap action +``` + +DB schema of VLAN_STACKING table: + +``` +; Defines schema for VLAN_STACKING configuration attributes +key               = VLAN_STACKING:interface_name:stage:vlanid +interface_name    =  +stage             = ingress/egress +vlanid            = 1*4DIGIT ; a number between 1 and 4094 +; field           = value +action            = push/pop/swap +s_vlanid     = 1*4DIGIT ; a number between 1 and 4094 +``` + +### APPL_DB + +A new table `VLAN_STACKING` is added in APP DB. + +``` +VLAN_STACKING_TABLE:{{interface-name}}:{{stage}}:{{vlanid}} +"action": {{action}} +"s_vlanid":  {{s_vlanid}}  (optional) +``` + +``` +`interface_name`  Ethernet port and and channel port name +`stage`           Traffic direction + ingress - ingress direction + egress - egress direction +`vlanid`      Service VLAN ID + C-VLAN for ingress direction + S-VLAN for egress direction +`action`          Rewrite action + push - Adds a s_vlanid tag to an ingress packet. + pop - Pop (remove) the outermost tag. + swap - Swap outermost tag by s_vlanid. +`s_vlanid` S-VLAN ID for push and swap action +``` + +DB schema of VLAN_STACKING table: + +```json +; Defines schema for VLAN_STACKING_TABLE configuration attributes +key                        = VLAN_STACKING_TABLE:interface_name:stage:vlanid +interface_name             =  +stage                      = ingress/egress +vlanid              = 1*4DIGIT ; a number between 1 and 4094 +; field                    = value +action                     = push/pop/swap +s_vlanid     = 1*4DIGIT ; a number between 1 and 4094 +``` + +## SAI API + +Table shown below represents the SAI attributes which **_shall_** be used for VLAN stacking. + +###### Table 3: SAI attributes related to VLAN stacking + +| VLAN Stacking Component | SAI attribute | Description | +| ----------------------- | ---------------------------------------------------------- | ------------------------------- | +| VLAN Stacking entry | SAI_VLAN_STACK_ATTR_STAGE | VLAN Stack stage | +| | SAI_VLAN_STACK_ATTR_ACTION | VLAN Stack action | +| | SAI_VLAN_STACK_ATTR_MATCH_TYPE | VLAN Stack match type | +| | SAI_VLAN_STACK_ATTR_VLAN_APPLIED_PRI | COS of the vlan tag | +| | SAI_VLAN_STACK_ATTR_ORIGINAL_VLAN_ID | Original Vlan ID | +| | SAI_VLAN_STACK_ATTR_PORT | Port ID | +| | SAI_VLAN_STACK_ATTR_APPLIED_VLAN_ID | Applied Vlan ID | + + +For example, to create a ingress VLAN stacking push entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: + +```json +"VLAN_STACKING": { + "Ethernet10|ingress|21": { +        "action": "push", +        "s_vlanid": "22" +} +``` + +```c++ +/* Create a ingress VLAN Stacking push entry object: + * ------------------------------------------ */ +sai_object_id_t vlan_stacking_oid; +sai_attribute_t attr; +vector vlan_stacking_entry_attrs; + +attr.id = SAI_VLAN_STACK_ATTR_STAGE; +attr.value.s32 = SAI_VLAN_STACK_STAGE_INGRESS; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ACTION; +attr.value.s32 = SAI_VLAN_STACK_ACTION_PUSH +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_MATCH_TYPE; +attr.value.s32 = SAI_VLAN_STACK_MATCH_TYPE_INNER; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ORIGINAL_VLAN_ID; +attr.value.u16 = 21; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_PORT; +attr.value.oid = 10; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_APPLIED_VLAN_ID; +attr.value.u16 = 22; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_VLAN_APPLIED_PRI; +attr.value.u8 = 0; +vlan_stacking_entry_attrs.push(attr); + +sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); +``` + +For example, to create a egress VLAN stacking pop entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: + +```json +"VLAN_STACKING": { +    "Ethernet10|egress|22": { +        "action": "pop" +} +``` + +```c++ +/* Create a egress VLAN Stacking pop entry object: + * ------------------------------------------ */ +sai_object_id_t vlan_stacking_oid; +sai_attribute_t attr; +vector vlan_stacking_entry_attrs; + +attr.id = SAI_VLAN_STACK_ATTR_STAGE; +attr.value.s32 = SAI_VLAN_STACK_STAGE_EGRESS; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ACTION; +attr.value.s32 = SAI_VLAN_STACK_ACTION_POP +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_MATCH_TYPE; +attr.value.s32 = SAI_VLAN_STACK_MATCH_TYPE_OUTER; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ORIGINAL_VLAN_ID; +attr.value.u16 = 22; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_PORT; +attr.value.oid = 10; +vlan_stacking_entry_attrs.push(attr); + +sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); +``` + +For example, to create a ingress VLAN stacking swap entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: + +```json +"VLAN_STACKING": { +    "Ethernet30|ingress|10": { +      "action": "swap", +        "s_vlanid": "20" +}  +``` + +```c++ +/* Create a ingress VLAN Stacking swap entry object: + * ------------------------------------------ */ +sai_object_id_t vlan_stacking_oid; +sai_attribute_t attr; +vector vlan_stacking_entry_attrs; + +attr.id = SAI_VLAN_STACK_ATTR_STAGE; +attr.value.s32 = SAI_VLAN_STACK_STAGE_INGRESS; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ACTION; +attr.value.s32 = SAI_VLAN_STACK_ACTION_SWAP +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_MATCH_TYPE; +attr.value.s32 = SAI_VLAN_STACK_MATCH_TYPE_OUTER; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ORIGINAL_VLAN_ID; +attr.value.u16 = 10; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_PORT; +attr.value.oid = 30; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_APPLIED_VLAN_ID; +attr.value.u16 = 20; +vlan_stacking_entry_attrs.push(attr); + +sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); +``` + +For example, to create a egress VLAN stacking swap entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: + +```json +"VLAN_STACKING": { +    "Ethernet30|egress|20": { +        "action": "swap", +        "s_vlanid": "10" +} +``` + +```c++ +/* Create a egress VLAN Stacking swap entry object: + * ------------------------------------------ */ +sai_object_id_t vlan_stacking_oid; +sai_attribute_t attr; +vector vlan_stack_entry_attrs; + +attr.id = SAI_VLAN_STACK_ATTR_STAGE; +attr.value.s32 = SAI_VLAN_STACK_STAGE_EGRESS; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ACTION; +attr.value.s32 = SAI_VLAN_STACK_ACTION_SWAP +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_MATCH_TYPE; +attr.value.s32 = SAI_VLAN_STACK_MATCH_TYPE_OUTER; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_ORIGINAL_VLAN_ID; +attr.value.u16 = 20; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_PORT; +attr.value.oid = 30; +vlan_stacking_entry_attrs.push(attr); + +attr.id = SAI_VLAN_STACK_ATTR_APPLIED_VLAN_ID; +attr.value.u16 = 10; +vlan_stacking_entry_attrs.push(attr); + +sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); +``` + +# Configuration and management + +## CLI/YANG model Enhancements + +### CLI + +CLI commands for VLAN stacking are not supported yet. + +### Yang model + +New yang model `sonic-vlan-stacking.yang` is defined to describe VLAN stacking configuration. + +```json +module sonic-vlan-stacking { + + yang-version 1.0; + + namespace "http://github.com/Azure/sonic-vlan-stacking"; + prefix vlan-stacking; + + import sonic-extension { + prefix ext; + revision-date 2019-07-01; + } + + import sonic-port { + prefix port; + revision-date 2019-07-01; + } + + import sonic-portchannel { + prefix lag; + revision-date 2019-07-01; + } + + import sonic-vlan { + prefix vlan; + revision-date 2019-07-01; + } + + description "VLAN Stacking YANG Module for SONiC OS"; + + revision 2021-12-15 { + description "First Revision"; + } + + container sonic-vlan-stacking { + container VLAN_STACKING { + description "VLAN_STACKING part of config_db.json"; + + list VLAN_STACKING_LIST { + key "INTERFACE_NAME STAGE VLAN_ID"; + + ext:key-regex-configdb-to-yang "^([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+)|([0-9]+)$"; + + ext:key-regex-yang-to-configdb "||"; + + leaf INTERFACE_NAME { + type union { + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + type leafref { + path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:portchannel_name; + } + } + } + + leaf STAGE { + type string { + pattern 'ingress|egress'; + } + } + + leaf VLAN_ID { + type leafref { + path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; + } + } + + leaf action { + type string { + pattern 'push|pop|swap'; + } + } + + leaf s_vlanid { + type leafref { + path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; + } + } + } + } + } +} +``` + +## Examples + +### Examples of QinQ Configuration + +The following configuration example shows C-VLAN 10 to S-VLAN 100 and C-VLAN 50 to S-VLAN 500 for ingress traffic on Ethernet1. And strips S-VLAN 100 and S-VLAN 500 for egress traffic on Ethernet1. + +```json +"VLAN_STACKING": { +    "Ethernet1|ingress|10": { +        "action": "push", +        "s_vlanid": "100" +    }, +    "Ethernet1|ingress|50": { +        "action": "push", +        "s_vlanid": "500" +    }, + "Ethernet1|egress|100": { +        "action": "pop" +    }, +    "Ethernet1|egress|500": { +        "action": "pop" +    } +} +``` + +For port channel, the following configuration example shows C-VLAN 20 to S-VLAN 200 and C-VLAN 60 to S-VLAN 600 for ingress traffic on PortChannel01. And strips S-VLAN 200 and S-VLAN 600 for egress traffic on PortChannel01. + +```json +"VLAN_STACKING": { +    "PortChannel01|ingress|20": { +        "action": "push", +        "s_vlanid": "200" +    }, +    "PortChannel01|ingress|60": { +        "action": "push", +        "s_vlanid": "600" +    }, + "PortChannel01|egress|200": { +        "action": "pop" +    }, +    "PortChannel01|egress|600": { +        "action": "pop" +    } +} +``` + +### Examples of VLAN Translation Configuration + +For example, assume that the upstream switch does not support QinQ tunneling. As the following configuration example, select Ethernet1, and set the Old VLAN to 10 and the New VLAN to 510 to map VLAN 10 to VLAN 510 for upstream traffic entering Ethernet1, and VLAN 510 to VLAN 10 for downstream traffic leaving Ethernet1. + +```json +"VLAN_STACKING": { +    "Ethernet1|ingress|10": { +        "action": "swap", +        "s_vlanid": "510" +    }, + "Ethernet1|egress|510": { +        "action": "swap", +        "s_vlanid": "10" +    } +} +``` + +As the following configuration example for port channel, select PortChannel01, and set the Old VLAN to 20 and the New VLAN to 620 to map VLAN 20 to VLAN 620 for upstream traffic entering PortChannel01, and VLAN 620 to VLAN 20 for downstream traffic leaving PortChannel01. + + ```json +"VLAN_STACKING": { +    "PortChannel01|ingress|20": { +        "action": "swap", +        "s_vlanid": "620" +    }, + "PortChannel01|egress|620": { +        "action": "swap", +        "s_vlanid": "20" +    } +} +``` + +# Warmboot and Fastboot Design Impact + +Not impacted by the changes. + +# Restrictions/Limitations + +There is no restriction or limitation. + +# Testing Requirements/Design + +## System Test Cases + +* Verify that the max N / M mapping for ingress / egress frames are able to configure. +* Verify that the max number of VLAN stacking configuration are able to configure. +* Verify that the configuration is working on only Ethernet and port channel interfaces. +* Verify that the invalid configuration doesn't take effect and an error is logged in syslog. (e.g., the port is not exist) +* Verify the rewrite action **_will_** be done if match C-VLAN, + * push action for ingress frames + * pop action for egress frames + * swap action for ingress and egress frames + + | Inject frames on edge interface | push | pop | swap (ingress) | swap (egress) | + | --------------------------------------------------- | --------------------------- | ---------------- | ---------------------------- | ------------------------ | + | untagged | Forward using port VLAN | N/A | Forward using port VLAN | N/A | + | single tagged (with non-supported TPID, e.g., 9100) | Forward using port VLAN | noop | Forward using port VLAN | noop | + | single tagged (not match the mapping) | Forward using port VLAN | noop | Forward using pkt outer VLAN | noop | + | double tagged (not match the mapping) | Forward using port VLAN | noop | Forward using pkt outer VLAN | noop | + | single tagged (matched the mapping) | Add S-VLAN tag | Remove outer tag | Replace C-VLAN as S-VLAN | Replace S-VLAN as C-VLAN | + | double tagged (matched the mapping) | Add S-VLAN tag (triple tag) | Remove outer tag | Replace C-VLAN AS S-VLAN | Replace S-VLAN as C-VLAN | + +* Verify that the double frame will be L2/L3 forwarded on any not enable interface (Ethernet and port channel interfaces). Outer TPID = 8100, others **_will_** be drop. +* Verify multiple mappings of different C-VLAN to separate S-VLANs per port. Include the combinations: + * C-VLAN: One and multiple C-VLANs + * S-VLAN: One and multiple S-VLANs + * Interface for C-VLAN and S-VLAN as Ethernet port and channel port. + \ No newline at end of file From f7920604b77525bd8a13432214fd8d4a5423933c Mon Sep 17 00:00:00 2001 From: pttch Date: Wed, 12 Jan 2022 12:25:47 +0800 Subject: [PATCH 2/7] modify the yang field to lower case and add the future work for tpid option --- doc/vlan_stacking/vlan_stacking_HLD.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md index ff7d459ae8..c58be1e363 100644 --- a/doc/vlan_stacking/vlan_stacking_HLD.md +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -30,6 +30,7 @@ - [Restrictions/Limitations](#restrictionslimitations) - [Testing Requirements/Design](#testing-requirementsdesign) - [System Test Cases](#system-test-cases) +- [Future Work](#future-work) # List of Tables @@ -479,7 +480,7 @@ module sonic-vlan-stacking { ext:key-regex-yang-to-configdb "||"; - leaf INTERFACE_NAME { + leaf interface_name { type union { type leafref { path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; @@ -490,25 +491,27 @@ module sonic-vlan-stacking { } } - leaf STAGE { + leaf stage { type string { pattern 'ingress|egress'; } } - leaf VLAN_ID { + leaf vlan_id { type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } } leaf action { + mandatory true; type string { pattern 'push|pop|swap'; } } leaf s_vlanid { + /* S-VLAN ID for push and swap action */ type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } @@ -632,4 +635,8 @@ There is no restriction or limitation. * C-VLAN: One and multiple C-VLANs * S-VLAN: One and multiple S-VLANs * Interface for C-VLAN and S-VLAN as Ethernet port and channel port. + +# Future Work + +The values of TPID and COS in the adding outer VLAN are configurable. For example, TPID may be configured as 0x88a8 which is defined in IEEE or other values. For the COS value, it may be able to configure to extract from the COS value of the original VLAN. \ No newline at end of file From 9b7d258854ab841eadc513e1bfb640ae0618fb4a Mon Sep 17 00:00:00 2001 From: pttch Date: Wed, 26 Jan 2022 11:03:21 +0800 Subject: [PATCH 3/7] Update the Connamd Line interface for VLAN Stacking feature --- doc/vlan_stacking/vlan_stacking_HLD.md | 74 ++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md index c58be1e363..9d1e5e2294 100644 --- a/doc/vlan_stacking/vlan_stacking_HLD.md +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -1,4 +1,4 @@ - ### Rev 0.1 + ### Rev 0.2 # Table of Contents @@ -44,8 +44,8 @@ | Rev | Date | Author | Change Description | |:-----:|:----------:|:-------------:|--------------------| -| 0.1 | 8-Oct-2020 | Tommy Tseng | Initial version | - +| 0.1 |20-Dec-2021 | Tommy Tseng | Initial version | +| 0.2 |26-Jan-2022 | Tommy Tseng | Update CLI command | # Scope This document describes the high level design of VLAN stacking feature. @@ -429,7 +429,73 @@ sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_st ### CLI -CLI commands for VLAN stacking are not supported yet. +Add VLAN stacking rule on a physical interface or PortChannel + +```json +config vlan-stacking add + * interface_name: The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". + * stage : The traffic direction of the packet, e.g. "ingress" or "egress". + * match_vlan : The VLAN ID on the packet which expected to match the rule(The range is from 1 to 4094). + * action : The action applied to the packet when it matched the rule, e.g. "push", "pop" or "swap". + * apply_vlan : The VLAN ID applied to the packet according to the action field(The range is from 1 to 4094). +``` + +The format is in the following + +```json +admin@sonic:~$ sudo config vlan-stacking add -h +Usage: config vlan-stacking add [OPTIONS] + + Add vlan stacking rule, examples: + - config vlan-stacking add Ethernet0 ingress 100 push 200 + - config vlan-stacking add Ethernet0 egress 100 pop + - config vlan-stacking add Ethernet0 ingress 100 swap 200 + - config vlan-stacking add Ethernet0 egress 100 swap 200 + +Options: + -?, -h, --help Show this message and exit. +``` + +Delete VLAN stacking rule from a physical interface or PortChannel + +```json +config vlan-stacking del + * interface_name: The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". + * stage : The traffic direction of the packet, e.g. "ingress" or "egress". + * match_vlan : The VLAN ID on the packet which expected to match the rule(The range is from 1 to 4094). +``` + +The format is in the following + +```json +admin@sonic:~$ sudo config vlan-stacking del -h +Usage: config vlan-stacking del [OPTIONS] + + Delete vlan stacking rule, examples: + - config vlan-stacking del Ethernet0 ingress 100 + - config vlan-stacking del Ethernet0 egress 100 + +Options: + -?, -h, --help Show this message and exit. +``` + +Display VLAN stacking rule configuration + +```json +show vlan-stacking +``` + +The display format is in the following + +```json +admin@root:~# show vlan-stacking +Interface Stage Match VLAN Action Apply VLAN +----------- ------- ------------ -------- ------------ +Ethernet0 egress 200 pop +Ethernet0 ingress 100 push 200 +Ethernet4 egress 200 swap 100 +Ethernet4 ingress 100 swap 200 +``` ### Yang model From d37c61d0c1644af1a77946e176980ddd1a0ee076 Mon Sep 17 00:00:00 2001 From: pttch Date: Wed, 23 Feb 2022 13:32:35 +0800 Subject: [PATCH 4/7] Modify the DB schema for VLAN Stacking feature --- doc/vlan_stacking/vlan_stacking_HLD.md | 163 ++++++++++++++++++------- 1 file changed, 116 insertions(+), 47 deletions(-) diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md index 9d1e5e2294..ba1a4827dc 100644 --- a/doc/vlan_stacking/vlan_stacking_HLD.md +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -1,4 +1,4 @@ - ### Rev 0.2 + ### Rev 0.3 # Table of Contents @@ -46,6 +46,7 @@ |:-----:|:----------:|:-------------:|--------------------| | 0.1 |20-Dec-2021 | Tommy Tseng | Initial version | | 0.2 |26-Jan-2022 | Tommy Tseng | Update CLI command | +| 0.2 |23-Feb-2022 | Tommy Tseng | Modify DB schema | # Scope This document describes the high level design of VLAN stacking feature. @@ -160,37 +161,71 @@ struct VlanStack A new table `VLAN_STACKING` is added in Config DB. ``` -VLAN_STACKING|{{interface_name}}|{{stage}}|{{vlanid}} -"action":  {{action}} -"s_vlanid":  {{s_vlanid}}  (optional) +VLAN_STACKING|{{interface_name}}|{{s_vlanid}} +"c_vlanids": {{c_vlanids}} +"s_vlan_priority": {{s_vlan_priority}} ``` ``` -`interface_name`  Ethernet port and and channel port name -`stage`           Traffic direction - ingress - ingress direction - egress - egress direction -`vlanid`      Service VLAN ID - C-VLAN for ingress direction - S-VLAN for egress direction -`action`          Rewrite action - push - Adds a s_vlanid tag to an ingress packet. - pop - Pop (remove) the outermost tag. - swap - Swap outermost tag by s_vlanid. -`s_vlanid` S-VLAN ID for push and swap action +`interface_name` Ethernet port and channel port name +`s_vlanid` Service VLAN ID + push VLAN for ingress direction + pop (remove) VLAN for egress direction +`c_vlanids` match VLAN IDs on ingress direction of interface +`s_vlan_priority` VLAN priority of Service VLAN ``` DB schema of VLAN_STACKING table: ``` ; Defines schema for VLAN_STACKING configuration attributes -key               = VLAN_STACKING:interface_name:stage:vlanid -interface_name    =  -stage             = ingress/egress -vlanid            = 1*4DIGIT ; a number between 1 and 4094 -; field           = value -action            = push/pop/swap -s_vlanid     = 1*4DIGIT ; a number between 1 and 4094 +key = VLAN_STACKING:interface_name:s_vlanid +interface_name = +s_vlanid = vlan_id        ; a number between 1 and 4094 +; field = value +c_vlanids = vlan_id-or-range[,vlan_id-or-range]*  ; list of VLAN IDs +s_vlan_priority = %x30-37                   ; a number between 0 and 7 +vlan_id = %x31-39 ; 1-9 + / %x31-39 DIGIT ; 10-99 +                 / %x31-39 2DIGIT ; 100-999 + / "1" 3DIGIT ; 1000-1999 + / "2" 3DIGIT ; 2000-2999 + / "3" 3DIGIT ; 3000-3999 + / "40" DIGIT %x30-34     ; 4000-4094 +range = vlan_id..vlan_id +``` + +A new table `VLAN_TRANSLATION` is added in Config DB. + +``` +VLAN_TRANSLATION|{{interface_name}}|{{s_vlanid}} +"c_vlanid": {{c_vlanid}} +``` + +``` +`interface_name` Ethernet port and channel port name +`s_vlanid` Service VLAN ID, + swap c_vlanid to s_vlanid for ingress direction + swap s_vlanid to c_vlanid for egress direction +`c_vlanid` Customer VLAN ID +``` + +DB schema of VLAN_TRANSLATION table: + +``` +; Defines schema for VLAN_TRANSLATION configuration attributes +key = VLAN_TRANSLATION:interface_name:s_vlanid +interface_name = +s_vlanid = vlan_id ; a number between 1 and 4094 +; field = value +c_vlanid = vlan_id ; a number between 1 and 4094 +vlan_id = %x31-39 ; 1-9 + / %x31-39 DIGIT ; 10-99 + / %x31-39 2DIGIT ; 100-999 + / "1" 3DIGIT ; 1000-1999 + / "2" 3DIGIT ; 2000-2999 + / "3" 3DIGIT ; 3000-3999 + / "40" DIGIT %x30-34 ; 4000-4094 ``` ### APPL_DB @@ -198,37 +233,71 @@ s_vlanid     = 1*4DIGIT ; a number between 1 and 4094 A new table `VLAN_STACKING` is added in APP DB. ``` -VLAN_STACKING_TABLE:{{interface-name}}:{{stage}}:{{vlanid}} -"action": {{action}} -"s_vlanid":  {{s_vlanid}}  (optional) +VLAN_STACKING_TABLE:{{interface-name}}:{{s_vlanid}} +"c_vlanids":  {{c_vlanids}} +"s_vlan_priority": {{s_vlan_priority}} ``` -``` -`interface_name`  Ethernet port and and channel port name -`stage`           Traffic direction - ingress - ingress direction - egress - egress direction -`vlanid`      Service VLAN ID - C-VLAN for ingress direction - S-VLAN for egress direction -`action`          Rewrite action - push - Adds a s_vlanid tag to an ingress packet. - pop - Pop (remove) the outermost tag. - swap - Swap outermost tag by s_vlanid. -`s_vlanid` S-VLAN ID for push and swap action +```json +`interface_name` Ethernet port and channel port name +`s_vlanid` Service VLAN ID + push VLAN for ingress direction + pop (remove) VLAN for egress direction +`c_vlanids` match VLAN IDs on ingress direction of interface +`s_vlan_priority` VLAN priority of Service VLAN ``` DB schema of VLAN_STACKING table: +``` +; Defines schema for VLAN_STACKING configuration attributes +key = VLAN_STACKING_TABLE:interface_name:s_vlanid +interface_name = +s_vlanid = vlan_id ; a number between 1 and 4094 +; field = value +c_vlanids = vlan_id-or-range[,vlan_id-or-range]*  ; list of VLAN IDs +s_vlan_priority = %x30-37 ; a number between 0 and 7 +vlan_id = %x31-39 ; 1-9 + / %x31-39 DIGIT ; 10-99 + / %x31-39 2DIGIT ; 100-999 + / "1" 3DIGIT ; 1000-1999 + / "2" 3DIGIT ; 2000-2999 + / "3" 3DIGIT ; 3000-3999 + / "40" DIGIT %x30-34 ; 4000-4094 +range = vlan_id..vlan_id +``` + +A new table `VLAN_TRANSLATION` is added in APP DB. + +``` +VLAN_TRANSLATION_TABLE:{{interface_name}}:{{s_vlanid}} +"c_vlanid": {{c_vlanid}} +``` + ```json -; Defines schema for VLAN_STACKING_TABLE configuration attributes -key                        = VLAN_STACKING_TABLE:interface_name:stage:vlanid -interface_name             =  -stage                      = ingress/egress -vlanid              = 1*4DIGIT ; a number between 1 and 4094 -; field                    = value -action                     = push/pop/swap -s_vlanid     = 1*4DIGIT ; a number between 1 and 4094 +`interface_name` Ethernet port and channel port name +`s_vlanid` Service VLAN ID, + swap c_vlanid to s_vlanid for ingress direction + swap s_vlanid to c_vlanid for egress direction +`c_vlanid` Customer VLAN ID +``` + +DB schema of VLAN_TRANSLATION table: + +``` +; Defines schema for VLAN_TRANSLATION configuration attributes +key = VLAN_TRANSLATION_TABLE:interface_name:s_vlanid +interface_name = +s_vlanid = vlan_id ; a number between 1 and 4094 +; field = value +c_vlanid = vlan_id ; a number between 1 and 4094 +vlan_id = %x31-39 ; 1-9 + / %x31-39 DIGIT ; 10-99 + / %x31-39 2DIGIT ; 100-999 + / "1" 3DIGIT ; 1000-1999 + / "2" 3DIGIT ; 2000-2999 + / "3" 3DIGIT ; 3000-3999 + / "40" DIGIT %x30-34 ; 4000-4094 ``` ## SAI API From 2c419e1d3661c64714b99f32a53358f3461d5e83 Mon Sep 17 00:00:00 2001 From: Yeh Jun-ying Date: Fri, 25 Feb 2022 14:14:24 +0800 Subject: [PATCH 5/7] Update example, Yang model and CLI. --- doc/vlan_stacking/vlan_stacking_HLD.md | 365 +++++++++++++++---------- 1 file changed, 225 insertions(+), 140 deletions(-) diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md index ba1a4827dc..7791bfdd49 100644 --- a/doc/vlan_stacking/vlan_stacking_HLD.md +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -42,11 +42,12 @@ ###### Table 1: Revision -| Rev | Date | Author | Change Description | -|:-----:|:----------:|:-------------:|--------------------| -| 0.1 |20-Dec-2021 | Tommy Tseng | Initial version | -| 0.2 |26-Jan-2022 | Tommy Tseng | Update CLI command | -| 0.2 |23-Feb-2022 | Tommy Tseng | Modify DB schema | +| Rev | Date | Author | Change Description | +|:-----:|:----------:|:-------------:|------------------------------------| +| 0.1 |20-Dec-2021 | Tommy Tseng | Initial version | +| 0.2 |26-Jan-2022 | Tommy Tseng | Update CLI command | +| 0.2 |23-Feb-2022 | Tommy Tseng | Modify DB schema | +| 0.3 |25-Feb-2022 | Yeh Jun-ying | Update example, Yang model and CLI | # Scope This document describes the high level design of VLAN stacking feature. @@ -317,13 +318,13 @@ Table shown below represents the SAI attributes which **_shall_** be used for VL | | SAI_VLAN_STACK_ATTR_APPLIED_VLAN_ID | Applied Vlan ID | -For example, to create a ingress VLAN stacking push entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: +For example, to create a VLAN stacking entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: ```json "VLAN_STACKING": { - "Ethernet10|ingress|21": { -        "action": "push", -        "s_vlanid": "22" + "Ethernet10|21": { +        "s_vlan_priority": "0", +        "c_vlanids": ["22"] } ``` @@ -365,15 +366,6 @@ vlan_stacking_entry_attrs.push(attr); sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); ``` -For example, to create a egress VLAN stacking pop entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: - -```json -"VLAN_STACKING": { -    "Ethernet10|egress|22": { -        "action": "pop" -} -``` - ```c++ /* Create a egress VLAN Stacking pop entry object: * ------------------------------------------ */ @@ -404,13 +396,12 @@ vlan_stacking_entry_attrs.push(attr); sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); ``` -For example, to create a ingress VLAN stacking swap entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: +For example, to create a VLAN translation entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: ```json -"VLAN_STACKING": { -    "Ethernet30|ingress|10": { -      "action": "swap", -        "s_vlanid": "20" +"VLAN_TRANSLATION": { +    "Ethernet30|20": { +        "c_vlanid": "10" }  ``` @@ -448,16 +439,6 @@ vlan_stacking_entry_attrs.push(attr); sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_stacking_entry_attrs.size(), vlan_stacking_entry_attrs.data()); ``` -For example, to create a egress VLAN stacking swap entry, Ports orchagent invokes the following SAI APIs with the necessary SAI attributes: - -```json -"VLAN_STACKING": { -    "Ethernet30|egress|20": { -        "action": "swap", -        "s_vlanid": "10" -} -``` - ```c++ /* Create a egress VLAN Stacking swap entry object: * ------------------------------------------ */ @@ -500,49 +481,47 @@ sai_vlan_api->create_vlan_stack(&vlan_stacking_oid, gSwitchId, (uint32_t)vlan_st Add VLAN stacking rule on a physical interface or PortChannel -```json -config vlan-stacking add - * interface_name: The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". - * stage : The traffic direction of the packet, e.g. "ingress" or "egress". - * match_vlan : The VLAN ID on the packet which expected to match the rule(The range is from 1 to 4094). - * action : The action applied to the packet when it matched the rule, e.g. "push", "pop" or "swap". - * apply_vlan : The VLAN ID applied to the packet according to the action field(The range is from 1 to 4094). +``` +config vlan-stacking add + * Append service vlan id with priority for ingress packet when matched customor vlan id. + Strip service vlan id for egress packet. + * interface_name : The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". + * s_vlanid : The VLAN ID which will be pushed for ingress direction and popped for egress direction(The range is from 1 to 4094). + * c_vlanids : The VLAN ID list which is used to match on ingress direction(The range is from 1 to 4094). + * s_vlan_priority : The priority of Service VLAN.(The range is from 0 to 7). ``` The format is in the following -```json +``` admin@sonic:~$ sudo config vlan-stacking add -h -Usage: config vlan-stacking add [OPTIONS] +Usage: config vlan-stacking add [OPTIONS] Add vlan stacking rule, examples: - - config vlan-stacking add Ethernet0 ingress 100 push 200 - - config vlan-stacking add Ethernet0 egress 100 pop - - config vlan-stacking add Ethernet0 ingress 100 swap 200 - - config vlan-stacking add Ethernet0 egress 100 swap 200 + - config vlan-stacking add Ethernet0 200 100 0 + - config vlan-stacking add Ethernet0 200 100,110-120 1 Options: -?, -h, --help Show this message and exit. ``` - Delete VLAN stacking rule from a physical interface or PortChannel -```json -config vlan-stacking del +``` +config vlan-stacking del [] * interface_name: The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". - * stage : The traffic direction of the packet, e.g. "ingress" or "egress". - * match_vlan : The VLAN ID on the packet which expected to match the rule(The range is from 1 to 4094). + * s_vlanid : The VLAN ID which will be pushed for ingress direction and popped for egress direction(The range is from 1 to 4094). + * c_vlanids : The VLAN ID list which is used to match on ingress packet(The range is from 1 to 4094). ``` The format is in the following -```json +``` admin@sonic:~$ sudo config vlan-stacking del -h -Usage: config vlan-stacking del [OPTIONS] +Usage: config vlan-stacking del [OPTIONS] [] Delete vlan stacking rule, examples: - - config vlan-stacking del Ethernet0 ingress 100 - - config vlan-stacking del Ethernet0 egress 100 + - config vlan-stacking del Ethernet0 200 + - config vlan-stacking del Ethernet0 200 115-120 Options: -?, -h, --help Show this message and exit. @@ -550,20 +529,75 @@ Options: Display VLAN stacking rule configuration -```json +``` show vlan-stacking ``` - The display format is in the following -```json +``` admin@root:~# show vlan-stacking -Interface Stage Match VLAN Action Apply VLAN ------------ ------- ------------ -------- ------------ -Ethernet0 egress 200 pop -Ethernet0 ingress 100 push 200 -Ethernet4 egress 200 swap 100 -Ethernet4 ingress 100 swap 200 +Interface s_vlanid c_vlanids s_vlan_priority +----------- -------- ----------- ---------------- +Ethernet0 200 100 0 +Ethernet4 200 100,110-120 1 +``` + +Add VLAN translation rule on a physical interface or PortChannel + +``` +config vlan-translation add + * Swap the VLAN ID from customer vlan id to service vlan id for ingress direction. + Swap the VLAN ID from service vlan id to customer vlan id for egress direction. + * interface_name: The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". + * s_vlanid : The VLAN ID will be replaced by c_vlanid for egress direction(The range is from 1 to 4094). + * c_vlanid : The VLAN ID will be replaced by s_vlanid for ingress direction(The range is from 1 to 4094). +``` + +The format is in the following + +``` +admin@sonic:~$ sudo config vlan-translation add -h +Usage: config vlan-translation add [OPTIONS] + + Add vlan stacking rule, examples: + - config vlan-translation add Ethernet0 200 100 + +Options: + -?, -h, --help Show this message and exit. +``` +Delete VLAN translation rule from a physical interface or PortChannel + +``` +config vlan-translation del + * interface_name: The name of physical interface or PortChannel, e.g. "Ethernet0" or "PortChannel0001". + * s_vlanid : The VLAN ID will be replaced by c_vlanid for egress direction(The range is from 1 to 4094). +``` + +The format is in the following + +``` +admin@sonic:~$ sudo config vlan-translation del -h +Usage: config vlan-translation del [OPTIONS] + + Delete vlan stacking rule, examples: + - config vlan-stacking del Ethernet0 200 + +Options: + -?, -h, --help Show this message and exit. +``` + +Display VLAN translation rule configuration + +``` +show vlan-translation +``` +The display format is in the following + +``` +admin@root:~# show vlan-translation +Interface s_vlanid c_vlanid +----------- -------- -------- +Ethernet0 100 200 ``` ### Yang model @@ -573,7 +607,7 @@ New yang model `sonic-vlan-stacking.yang` is defined to describe VLAN stacking c ```json module sonic-vlan-stacking { - yang-version 1.0; + yang-version 1.1; namespace "http://github.com/Azure/sonic-vlan-stacking"; prefix vlan-stacking; @@ -609,11 +643,11 @@ module sonic-vlan-stacking { description "VLAN_STACKING part of config_db.json"; list VLAN_STACKING_LIST { - key "INTERFACE_NAME STAGE VLAN_ID"; + key "interface_name s_vlanid"; ext:key-regex-configdb-to-yang "^([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+)|([0-9]+)$"; - ext:key-regex-yang-to-configdb "||"; + ext:key-regex-yang-to-configdb "|"; leaf interface_name { type union { @@ -626,27 +660,100 @@ module sonic-vlan-stacking { } } - leaf stage { - type string { - pattern 'ingress|egress'; + leaf s_vlanid { + type leafref { + path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } } - leaf vlan_id { - type leafref { - path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; +                leaf-list c_vlanids { + type union { + type leafref { + path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; + } + type string { + length 1..10; + pattern '[0-9]{1,4}..[0-9]{1,4}'; + } + } + } + +                leaf s_vlan_priority { + type uint8 { + range 0..7; } } +             } + } + } +} +``` + +New yang model `sonic-vlan-translation.yang` is defined to describe VLAN translation configuration. + +``` +module sonic-vlan-translation { + + yang-version 1.0; + + namespace "http://github.com/Azure/sonic-vlan-translation"; + prefix vlan-translation; + + import sonic-extension { + prefix ext; + revision-date 2019-07-01; + } + + import sonic-port { + prefix port; + revision-date 2019-07-01; + } + + import sonic-portchannel { + prefix lag; + revision-date 2019-07-01; + } - leaf action { - mandatory true; - type string { - pattern 'push|pop|swap'; + import sonic-vlan { + prefix vlan; + revision-date 2019-07-01; + } + + description "VLAN Translation YANG Module for SONiC OS"; + + revision 2021-12-15 { + description "First Revision"; + } + + container sonic-vlan-translation { + container VLAN_TRANSLATION { + description "VLAN_TRANSLATION part of config_db.json"; + + list VLAN_TRANSLATION_LIST { + key "interface_name s_vlanid"; + + ext:key-regex-configdb-to-yang "^([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+)|([0-9]+)$"; + + ext:key-regex-yang-to-configdb "|"; + + leaf interface_name { + type union { + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + type leafref { + path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:portchannel_name; + } } } leaf s_vlanid { - /* S-VLAN ID for push and swap action */ + type leafref { + path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; + } + } + + leaf c_vlanid { type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } @@ -661,45 +768,25 @@ module sonic-vlan-stacking { ### Examples of QinQ Configuration -The following configuration example shows C-VLAN 10 to S-VLAN 100 and C-VLAN 50 to S-VLAN 500 for ingress traffic on Ethernet1. And strips S-VLAN 100 and S-VLAN 500 for egress traffic on Ethernet1. +The following configuration example shows C-VLAN 101, 102, 103 and 150 to S-VLAN 100 with VLAN priority 0 for ingress traffic on Ethernet1. And strips S-VLAN 100 for egress traffic on Ethernet1. ```json "VLAN_STACKING": { -    "Ethernet1|ingress|10": { -        "action": "push", -        "s_vlanid": "100" -    }, -    "Ethernet1|ingress|50": { -        "action": "push", -        "s_vlanid": "500" -    }, - "Ethernet1|egress|100": { -        "action": "pop" -    }, -    "Ethernet1|egress|500": { -        "action": "pop" -    } + "Ethernet1|100": { + "c_vlanids": ["101..103", "150"], + "s_vlan_priority": "0" + } } ``` -For port channel, the following configuration example shows C-VLAN 20 to S-VLAN 200 and C-VLAN 60 to S-VLAN 600 for ingress traffic on PortChannel01. And strips S-VLAN 200 and S-VLAN 600 for egress traffic on PortChannel01. +For port channel, the following configuration example shows C-VLAN 201, 202, and 203 to S-VLAN with VLAN priority 1 for ingress traffic on PortChannel01. And strips S-VLAN 200 for egress traffic on PortChannel01. ```json "VLAN_STACKING": { -    "PortChannel01|ingress|20": { -        "action": "push", -        "s_vlanid": "200" -    }, -    "PortChannel01|ingress|60": { -        "action": "push", -        "s_vlanid": "600" -    }, - "PortChannel01|egress|200": { -        "action": "pop" -    }, -    "PortChannel01|egress|600": { -        "action": "pop" -    } + "PortChannel01|200": { + "c_vlanids": ["201..203"], + "s_vlan_priority": "1" + } } ``` @@ -708,30 +795,20 @@ For port channel, the following configuration example shows C-VLAN 20 to S-VLAN For example, assume that the upstream switch does not support QinQ tunneling. As the following configuration example, select Ethernet1, and set the Old VLAN to 10 and the New VLAN to 510 to map VLAN 10 to VLAN 510 for upstream traffic entering Ethernet1, and VLAN 510 to VLAN 10 for downstream traffic leaving Ethernet1. ```json -"VLAN_STACKING": { -    "Ethernet1|ingress|10": { -        "action": "swap", -        "s_vlanid": "510" -    }, - "Ethernet1|egress|510": { -        "action": "swap", -        "s_vlanid": "10" -    } +"VLAN_TRANSLATION": { + "Ethernet1|10": { + "c_vlanid": "510" + } } ``` As the following configuration example for port channel, select PortChannel01, and set the Old VLAN to 20 and the New VLAN to 620 to map VLAN 20 to VLAN 620 for upstream traffic entering PortChannel01, and VLAN 620 to VLAN 20 for downstream traffic leaving PortChannel01. ```json -"VLAN_STACKING": { -    "PortChannel01|ingress|20": { -        "action": "swap", -        "s_vlanid": "620" -    }, - "PortChannel01|egress|620": { -        "action": "swap", -        "s_vlanid": "20" -    } +"VLAN_TRANSLATION": { + "PortChannel01|20": { + "c_vlanid": "620" + } } ``` @@ -747,23 +824,31 @@ There is no restriction or limitation. ## System Test Cases -* Verify that the max N / M mapping for ingress / egress frames are able to configure. -* Verify that the max number of VLAN stacking configuration are able to configure. +* Verify that the max number of VLAN stacking and VLAN translation configuration are able to configure. * Verify that the configuration is working on only Ethernet and port channel interfaces. * Verify that the invalid configuration doesn't take effect and an error is logged in syslog. (e.g., the port is not exist) * Verify the rewrite action **_will_** be done if match C-VLAN, - * push action for ingress frames - * pop action for egress frames - * swap action for ingress and egress frames - - | Inject frames on edge interface | push | pop | swap (ingress) | swap (egress) | - | --------------------------------------------------- | --------------------------- | ---------------- | ---------------------------- | ------------------------ | - | untagged | Forward using port VLAN | N/A | Forward using port VLAN | N/A | - | single tagged (with non-supported TPID, e.g., 9100) | Forward using port VLAN | noop | Forward using port VLAN | noop | - | single tagged (not match the mapping) | Forward using port VLAN | noop | Forward using pkt outer VLAN | noop | - | double tagged (not match the mapping) | Forward using port VLAN | noop | Forward using pkt outer VLAN | noop | - | single tagged (matched the mapping) | Add S-VLAN tag | Remove outer tag | Replace C-VLAN as S-VLAN | Replace S-VLAN as C-VLAN | - | double tagged (matched the mapping) | Add S-VLAN tag (triple tag) | Remove outer tag | Replace C-VLAN AS S-VLAN | Replace S-VLAN as C-VLAN | + * VLAN stacking action for ingress and egress frames on edge interface + + | Frames on edge interface | Ingress frames | Egress frames | + | --------------------------------------------------- | --------------------------- | ------------------| + | untagged | Forward using port VLAN | N/A | + | single tagged (with non-supported TPID, e.g., 9100) | Forward using port VLAN | noop | + | single tagged (not match the mapping) | Forward using port VLAN | noop | + | double tagged (not match the mapping) | Forward using port VLAN | noop | + | single tagged (matched the mapping) | Add S-VLAN tag | Remove S-VLAN tag | + | double tagged (matched the mapping) | Add S-VLAN tag (triple tag) | Remove S-VLAN tag | + + * VLAN translation action for ingress and egress frames on edge interface + + | Frames on edge interface             | Ingress frames | Egress frames | + | --------------------------------------------------- | ---------------------------- | ------------------------ | + | untagged | Forward using port VLAN | N/A | + | single tagged (with non-supported TPID, e.g., 9100) | Forward using port VLAN | noop | + | single tagged (not match the mapping) | Forward using pkt outer VLAN | noop | + | double tagged (not match the mapping) | Forward using pkt outer VLAN | noop | + | single tagged (matched the mapping) | Replace C-VLAN as S-VLAN | Replace S-VLAN as C-VLAN | + | double tagged (matched the mapping) | Replace C-VLAN AS S-VLAN | Replace S-VLAN as C-VLAN | * Verify that the double frame will be L2/L3 forwarded on any not enable interface (Ethernet and port channel interfaces). Outer TPID = 8100, others **_will_** be drop. * Verify multiple mappings of different C-VLAN to separate S-VLANs per port. Include the combinations: From 74e55e4e1d0bee7b8eb9cfdc6e9de078e04aa4fc Mon Sep 17 00:00:00 2001 From: ecsonic Date: Wed, 9 Mar 2022 09:57:03 +0800 Subject: [PATCH 6/7] update the yang model and spec --- doc/vlan_stacking/vlan_stacking_HLD.md | 55 +++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md index 7791bfdd49..293cca9223 100644 --- a/doc/vlan_stacking/vlan_stacking_HLD.md +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -1,4 +1,4 @@ - ### Rev 0.3 + ### Rev 0.4 # Table of Contents @@ -48,6 +48,7 @@ | 0.2 |26-Jan-2022 | Tommy Tseng | Update CLI command | | 0.2 |23-Feb-2022 | Tommy Tseng | Modify DB schema | | 0.3 |25-Feb-2022 | Yeh Jun-ying | Update example, Yang model and CLI | +| 0.4 |23-Feb-2022 | Tommy Tseng | Update Yang model and spec | # Scope This document describes the high level design of VLAN stacking feature. @@ -124,6 +125,7 @@ The overall SONiC architecture will not be changed and no new sub-modules will b | swap | Supported | Supported | * Swap rewrite action **_will_** become invalid if configured (push, swap) at ingress direction or (pop, swap) at egress direction on the specified interface at the same time. +* Swap rewrite action at egress direction **_is not_** expected on the interface which is configured as untagged port member in specified VLAN. * Only outer TPID 8100 is supported. The frames with TPID = 8100 **_will_** be taken as tagged (single or double) frames. * For egress direction on channel port, each match criteria **_will_** use one hardware entry per member port. @@ -186,6 +188,8 @@ s_vlanid = vlan_id        ; a number between ; field = value c_vlanids = vlan_id-or-range[,vlan_id-or-range]*  ; list of VLAN IDs s_vlan_priority = %x30-37                   ; a number between 0 and 7 + +; value annotations vlan_id = %x31-39 ; 1-9 / %x31-39 DIGIT ; 10-99                 / %x31-39 2DIGIT ; 100-999 @@ -220,6 +224,8 @@ interface_name = s_vlanid = vlan_id ; a number between 1 and 4094 ; field = value c_vlanid = vlan_id ; a number between 1 and 4094 + +; value annotations vlan_id = %x31-39 ; 1-9 / %x31-39 DIGIT ; 10-99 / %x31-39 2DIGIT ; 100-999 @@ -258,6 +264,8 @@ s_vlanid = vlan_id ; a number between 1 a ; field = value c_vlanids = vlan_id-or-range[,vlan_id-or-range]*  ; list of VLAN IDs s_vlan_priority = %x30-37 ; a number between 0 and 7 + +; value annotations vlan_id = %x31-39 ; 1-9 / %x31-39 DIGIT ; 10-99 / %x31-39 2DIGIT ; 100-999 @@ -292,6 +300,8 @@ interface_name = s_vlanid = vlan_id ; a number between 1 and 4094 ; field = value c_vlanid = vlan_id ; a number between 1 and 4094 + +; value annotations vlan_id = %x31-39 ; 1-9 / %x31-39 DIGIT ; 10-99 / %x31-39 2DIGIT ; 100-999 @@ -614,22 +624,18 @@ module sonic-vlan-stacking { import sonic-extension { prefix ext; - revision-date 2019-07-01; } import sonic-port { prefix port; - revision-date 2019-07-01; } import sonic-portchannel { prefix lag; - revision-date 2019-07-01; } import sonic-vlan { prefix vlan; - revision-date 2019-07-01; } description "VLAN Stacking YANG Module for SONiC OS"; @@ -645,28 +651,26 @@ module sonic-vlan-stacking { list VLAN_STACKING_LIST { key "interface_name s_vlanid"; - ext:key-regex-configdb-to-yang "^([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+)|([0-9]+)$"; - - ext:key-regex-yang-to-configdb "|"; - leaf interface_name { type union { type leafref { - path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + path /port:sonic-port/port:PORT/port:PORT_LIST/port:name; } type leafref { - path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:portchannel_name; + path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:name; } } + description "Interface name"; } leaf s_vlanid { type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } + description "Service VLAN ID"; } -                leaf-list c_vlanids { + leaf-list c_vlanids { type union { type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; @@ -676,14 +680,16 @@ module sonic-vlan-stacking { pattern '[0-9]{1,4}..[0-9]{1,4}'; } } + description "Customer VLAN ID"; } -                leaf s_vlan_priority { + leaf s_vlan_priority { type uint8 { range 0..7; } + description "VLAN priority of Service VLAN"; } -             } + } } } } @@ -692,31 +698,27 @@ module sonic-vlan-stacking { New yang model `sonic-vlan-translation.yang` is defined to describe VLAN translation configuration. ``` -module sonic-vlan-translation { +sonic-vlan-translation { - yang-version 1.0; + yang-version 1.1; namespace "http://github.com/Azure/sonic-vlan-translation"; prefix vlan-translation; import sonic-extension { prefix ext; - revision-date 2019-07-01; } import sonic-port { prefix port; - revision-date 2019-07-01; } import sonic-portchannel { prefix lag; - revision-date 2019-07-01; } import sonic-vlan { prefix vlan; - revision-date 2019-07-01; } description "VLAN Translation YANG Module for SONiC OS"; @@ -732,31 +734,30 @@ module sonic-vlan-translation { list VLAN_TRANSLATION_LIST { key "interface_name s_vlanid"; - ext:key-regex-configdb-to-yang "^([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+)|([0-9]+)$"; - - ext:key-regex-yang-to-configdb "|"; - leaf interface_name { type union { type leafref { - path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + path /port:sonic-port/port:PORT/port:PORT_LIST/port:name; } type leafref { - path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:portchannel_name; + path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:name; } } + description "Interface name"; } leaf s_vlanid { type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } + description "Service VLAN ID"; } leaf c_vlanid { type leafref { path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlanid; } + description "Customer VLAN ID"; } } } @@ -859,4 +860,4 @@ There is no restriction or limitation. # Future Work The values of TPID and COS in the adding outer VLAN are configurable. For example, TPID may be configured as 0x88a8 which is defined in IEEE or other values. For the COS value, it may be able to configure to extract from the COS value of the original VLAN. - \ No newline at end of file + From 656ce8e1d280ddf5754c3764488f7120059149e4 Mon Sep 17 00:00:00 2001 From: ecsonic Date: Wed, 9 Mar 2022 15:03:41 +0800 Subject: [PATCH 7/7] remove unnessery statement --- doc/vlan_stacking/vlan_stacking_HLD.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/vlan_stacking/vlan_stacking_HLD.md b/doc/vlan_stacking/vlan_stacking_HLD.md index 293cca9223..f44de21b09 100644 --- a/doc/vlan_stacking/vlan_stacking_HLD.md +++ b/doc/vlan_stacking/vlan_stacking_HLD.md @@ -125,7 +125,6 @@ The overall SONiC architecture will not be changed and no new sub-modules will b | swap | Supported | Supported | * Swap rewrite action **_will_** become invalid if configured (push, swap) at ingress direction or (pop, swap) at egress direction on the specified interface at the same time. -* Swap rewrite action at egress direction **_is not_** expected on the interface which is configured as untagged port member in specified VLAN. * Only outer TPID 8100 is supported. The frames with TPID = 8100 **_will_** be taken as tagged (single or double) frames. * For egress direction on channel port, each match criteria **_will_** use one hardware entry per member port.