From 3c3d723a73423a0c364350d85a0aaf1aded2a92c Mon Sep 17 00:00:00 2001 From: bingwang Date: Thu, 24 Feb 2022 13:11:30 +0000 Subject: [PATCH 1/3] HLD for dynamic ACL rule Signed-off-by: bingwang --- doc/acl/Dynamic-ACL-Design.md | 191 +++++++++++++++++++++++++ doc/acl/img/dynamic_acl_creation.png | Bin 0 -> 7259 bytes doc/acl/img/dynamic_acl_expiration.png | Bin 0 -> 8117 bytes doc/acl/img/dynamic_acl_refresh.png | Bin 0 -> 3950 bytes 4 files changed, 191 insertions(+) create mode 100644 doc/acl/Dynamic-ACL-Design.md create mode 100644 doc/acl/img/dynamic_acl_creation.png create mode 100644 doc/acl/img/dynamic_acl_expiration.png create mode 100644 doc/acl/img/dynamic_acl_refresh.png diff --git a/doc/acl/Dynamic-ACL-Design.md b/doc/acl/Dynamic-ACL-Design.md new file mode 100644 index 00000000000..8d29e4a4e94 --- /dev/null +++ b/doc/acl/Dynamic-ACL-Design.md @@ -0,0 +1,191 @@ + +# Dynamic ACL # + + +## Table of Content + +- [Revision](#revision) +- [Scope](#scope) +- [Definitions/Abbreviations](#definitionsabbreviations) +- [Overview](#overview) +- [Requirements](#requirements) +- [Architecture Design](#architecture-design) +- [High-Level Design](#high-level-design) + - [db schema](#db-schema) + - [CONFIG DB](#config-db) + - [STATE DB](#state-db) + - [acl-loader](#acl-loader) + - [acl_ttl_checker](#aclttlchecker) + -[Work flow](#work-flow) + - [Add dynamic ACL rule](#add-dynamic-acl-rule) + - [Refresh TTL of existing ACL rule](#refresh-ttl-of-existing-acl-rule) + - [Remove ACL rule when TTL expires](#remove-acl-rule-when-ttl-expires) + - [Testing Requirements/Design](#testing-requirementsdesign) + - [Unit Test cases](#unit-test-cases) + - [System Test cases](#system-test-cases) +- [Open questions](#open-questions) + + +## Revision + +| Rev | Date | Author | Change Description | +|:---:|:-----------:|:------------------:|-----------------------------------| +| 0.1 | | Bing Wang | Initial version | + +## Scope + +The scope of this document covers the design of dynamic data plane ACL, which assigns a TTL to ACL rule, and removes the expired rule. Control plane ACL is not covered in this document. + +## Definitions/Abbreviations + +| Definitions/Abbreviation | Description | +|--------------------------|--------------------------------------------| +| ACL | Access Control List | + + +## Overview + +The current design of data plane ACL supports only persistent rules, that is, once the rule is applied to SONiC, it will be there until manually removed or config reload. + +This doc proposes an enhancement to current ACL, which add a TTL to ACL rules and the rules are deleted after TTL expires. + +## Requirements + +- ACL rules are removed when TTL expired +- The precision of TTL is no more than 10 seconds +- Support TTL refreshment +- The count down of TTL keeps going after warm-boot + +## Architecture Design + +No SONiC architecture change is required to support dynamic ACL. + +## High-Level Design + +### db schema + +#### CONFIG DB +Add a `dynamic` flag to current `ACL_RULE` table +``` +key: ACL_RULE_TABLE:table_name:seq ; key of the rule entry in the table, seq is the order of the rules + ; when the packet is filtered by the ACL "policy_name". + ; A rule is always assocaited with a policy. + +;field = value +is_dynamic = true/false ; Boolean; Optional. There will be a TTL assigned to this rule if is_dynamic is true, the + ;rule will be removed from CONFIG DB. + ;If is_dynamic is false or absent, the rule will be persistent +...... +``` +A sample config for ACL rule +```json +{ + "ACL_RULE|DATAACL|RULE_1":{ + "DST_IP":"192.168.0.3/32", + "ETHER_TYPE":"2048", + "PACKET_ACTION":"FORWARD", + "PRIORITY":"9999", + "SRC_IP":"192.168.0.2/32", + "is_dynamic":"true" + } +} +``` +A sample json config for ACL rule +```json +{ + "acl":{ + "acl-sets":{ + "acl-set":{ + "DATAACL":{ + "acl-entries":{ + "acl-entry":{ + "1":{ + "actions":{ + "config":{ + "forwarding-action":"ACCEPT" + } + }, + "config":{ + "sequence-id":1 + }, + "ip":{ + "config":{ + "source-ip-address":"192.168.0.2/32", + "destination-ip-address":"192.168.0.3/32" + } + }, + "ttl":"300" + } + } + } + } + } + } + } +} +``` +The YANG of ACL_RULE is required to be updated to accept new field `is_dynamic` + +Orchagent (actually `aclorch`) won't consume the value of `is_dynamic`. So no change is required to `orchagent`. +#### STATE DB +A new table is introduced to state_db to record the timestamp of creation, expiration and TTL of an ACL rule. +``` + key = ACL_TTL_TABLE:acl_rule_name ; acl_rule_name specifies the corresponding ACL rule name, must be unique + ;field = value + creation_time = Integer ; timestamp when the rule is created or refreshed + expiration_time = Integer ; timestamp when the rule will expire + ttl = Integer ; the ttl, in second +``` +A sample +```json +{ + "ACL_TTL_TABLE|DATAACL|RULE_1":{ + "creation_time":1645686213, + "expiration_time":1645686513, + "ttl":300 + } +} +``` +#### acl-loader + +Update `acl-loader` script to parse new field `is_dynamic`. The entry will be created in `ACL_TTL_TABLE` in `state_db` if `ttl` is present for certain an ACL rule in `acl.json`. Please find more details in workflow diagram. + +#### acl_ttl_checker + +A helper script managed by `Monit` service. The checker is triggered every 10 seconds by default. It will walk through all entries in `ACL_TTL_TABLE` and delete the corresponding `ACL_RULE` from `config_db` if + +- Current timestamp is larger than the `expiration_time` in the entry +- The corresponding ACL rule is marked as dynamic + +### Work flow +#### Add dynamic ACL rule +

+Figure 1. Create dynamic ACL rule workflow +

+ +#### Refresh TTL of existing ACL rule +

+Figure 2. Refresh dynamic ACL rule workflow +

+ +#### Remove ACL rule when TTL expires +

+Figure 1. Create dynamic ACL rule workflow +

+ +### Testing Requirements/Design + +#### Unit Test cases + +1. Enhance unit test for `acl-loader` to verify ACL rule with TTL is created as expected; verify `ACL_TTL_TABLE` entry is created as expected. +2. Add unit test for `acl_ttl_checker` to verify expired ACL entries are cleared. + + +#### System Test cases + +1. Test case 1 Verify dynamic ACL rule is created as expected +2. Test case 2 Verify dynamic ACL rule can be refreshed +3. Test case 3 Verify expired dynamic ACL rule can be removed + +## Open questions +- diff --git a/doc/acl/img/dynamic_acl_creation.png b/doc/acl/img/dynamic_acl_creation.png new file mode 100644 index 0000000000000000000000000000000000000000..1916a0c665d96a0d3df1dbff46d50d03ac95f060 GIT binary patch literal 7259 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 CwqASy literal 0 HcmV?d00001 diff --git a/doc/acl/img/dynamic_acl_expiration.png b/doc/acl/img/dynamic_acl_expiration.png new file mode 100644 index 0000000000000000000000000000000000000000..10a5c78a9598a27620de3b179c34a8cd7a7545e9 GIT binary patch literal 8117 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 Vr6ftJm3~Kt7@xN=sM2@8{TFTAjcEV? literal 0 HcmV?d00001 From e2ace32c4cb7a8bfaad39783a4dcee527f4c874f Mon Sep 17 00:00:00 2001 From: bingwang Date: Fri, 25 Feb 2022 07:46:42 +0000 Subject: [PATCH 2/3] HLD for dynamic ACL rule Signed-off-by: bingwang --- doc/acl/Dynamic-ACL-Design.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/acl/Dynamic-ACL-Design.md b/doc/acl/Dynamic-ACL-Design.md index 8d29e4a4e94..9ecf2e50bc4 100644 --- a/doc/acl/Dynamic-ACL-Design.md +++ b/doc/acl/Dynamic-ACL-Design.md @@ -52,7 +52,7 @@ This doc proposes an enhancement to current ACL, which add a TTL to ACL rules an ## Requirements - ACL rules are removed when TTL expired -- The precision of TTL is no more than 10 seconds +- The precision of TTL is no more than 1 minute - Support TTL refreshment - The count down of TTL keeps going after warm-boot @@ -152,7 +152,7 @@ Update `acl-loader` script to parse new field `is_dynamic`. The entry will be cr #### acl_ttl_checker -A helper script managed by `Monit` service. The checker is triggered every 10 seconds by default. It will walk through all entries in `ACL_TTL_TABLE` and delete the corresponding `ACL_RULE` from `config_db` if +A helper script managed by `Monit` service. The checker is triggered every 60 seconds by default. It will walk through all entries in `ACL_TTL_TABLE` and delete the corresponding `ACL_RULE` from `config_db` if - Current timestamp is larger than the `expiration_time` in the entry - The corresponding ACL rule is marked as dynamic @@ -188,4 +188,4 @@ A helper script managed by `Monit` service. The checker is triggered every 10 se 3. Test case 3 Verify expired dynamic ACL rule can be removed ## Open questions -- +1. `monit` service is delay started(5 minutes) after reboot or reload. So there will be no expiration at the first 5 minutes after reboot or reload. From e7716da92cf2114bfe6f6ca3d1038fef5bb54326 Mon Sep 17 00:00:00 2001 From: bingwang Date: Mon, 28 Feb 2022 21:58:09 -0800 Subject: [PATCH 3/3] Change from monit to supervisord Signed-off-by: bingwang --- doc/acl/Dynamic-ACL-Design.md | 5 ++--- doc/acl/img/dynamic_acl_expiration.png | Bin 8117 -> 21737 bytes 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/acl/Dynamic-ACL-Design.md b/doc/acl/Dynamic-ACL-Design.md index 9ecf2e50bc4..03869a1e84e 100644 --- a/doc/acl/Dynamic-ACL-Design.md +++ b/doc/acl/Dynamic-ACL-Design.md @@ -52,7 +52,6 @@ This doc proposes an enhancement to current ACL, which add a TTL to ACL rules an ## Requirements - ACL rules are removed when TTL expired -- The precision of TTL is no more than 1 minute - Support TTL refreshment - The count down of TTL keeps going after warm-boot @@ -152,7 +151,7 @@ Update `acl-loader` script to parse new field `is_dynamic`. The entry will be cr #### acl_ttl_checker -A helper script managed by `Monit` service. The checker is triggered every 60 seconds by default. It will walk through all entries in `ACL_TTL_TABLE` and delete the corresponding `ACL_RULE` from `config_db` if +A helper script will be added to `swss` container. The checker is started after `orchagent` and check the TTL of dynamic ACL rules every 10 seconds by default. It will walk through all entries in `ACL_TTL_TABLE` and delete the corresponding `ACL_RULE` from `config_db` if - Current timestamp is larger than the `expiration_time` in the entry - The corresponding ACL rule is marked as dynamic @@ -188,4 +187,4 @@ A helper script managed by `Monit` service. The checker is triggered every 60 se 3. Test case 3 Verify expired dynamic ACL rule can be removed ## Open questions -1. `monit` service is delay started(5 minutes) after reboot or reload. So there will be no expiration at the first 5 minutes after reboot or reload. +1. memory leak issue detection and validation. diff --git a/doc/acl/img/dynamic_acl_expiration.png b/doc/acl/img/dynamic_acl_expiration.png index 10a5c78a9598a27620de3b179c34a8cd7a7545e9..32d89b7d027f6f85168eb3d9824cf6e3375e8d4f 100644 GIT binary patch literal 21737 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

LTrfii@uKD&Y!S#jiSUBU%wDh$nIgOq16qfUQ$y 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 b^`KnBiXGadQ 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