Skip to content

Commit a39350c

Browse files
[aclshow] enhance ACL counters to work with FC infrastructure (sonic-net#1858)
#### What I did Made a change for aclshow and counterpoll that adds support for ACL flex counters. DEPENDS ON: sonic-net/sonic-swss-common#533 sonic-net/sonic-sairedis#953 sonic-net/sonic-swss#1943 HLD: sonic-net/SONiC#857 #### How I did it Modified aclshow and counterpoll and UT. #### How to verify it Together with depends PRs. Run ACL/Everflow test suite.
1 parent ed88013 commit a39350c

File tree

11 files changed

+379
-159
lines changed

11 files changed

+379
-159
lines changed

counterpoll/main.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
BUFFER_POOL_WATERMARK = "BUFFER_POOL_WATERMARK"
77
PORT_BUFFER_DROP = "PORT_BUFFER_DROP"
88
PG_DROP = "PG_DROP"
9+
ACL = "ACL"
910
DISABLE = "disable"
1011
ENABLE = "enable"
1112
DEFLT_60_SEC= "default (60000)"
@@ -241,6 +242,45 @@ def disable():
241242
configdb.mod_entry("FLEX_COUNTER_TABLE", "PG_WATERMARK", fc_info)
242243
configdb.mod_entry("FLEX_COUNTER_TABLE", BUFFER_POOL_WATERMARK, fc_info)
243244

245+
# ACL counter commands
246+
@cli.group()
247+
@click.pass_context
248+
def acl(ctx):
249+
""" ACL counter commands """
250+
ctx.obj = ConfigDBConnector()
251+
ctx.obj.connect()
252+
253+
@acl.command()
254+
@click.argument('poll_interval', type=click.IntRange(1000, 30000))
255+
@click.pass_context
256+
def interval(ctx, poll_interval):
257+
"""
258+
Set ACL counters query interval
259+
interval is between 1s and 30s.
260+
"""
261+
262+
fc_group_cfg = {}
263+
fc_group_cfg['POLL_INTERVAL'] = poll_interval
264+
ctx.obj.mod_entry("FLEX_COUNTER_TABLE", ACL, fc_group_cfg)
265+
266+
@acl.command()
267+
@click.pass_context
268+
def enable(ctx):
269+
""" Enable ACL counter query """
270+
271+
fc_group_cfg = {}
272+
fc_group_cfg['FLEX_COUNTER_STATUS'] = ENABLE
273+
ctx.obj.mod_entry("FLEX_COUNTER_TABLE", ACL, fc_group_cfg)
274+
275+
@acl.command()
276+
@click.pass_context
277+
def disable(ctx):
278+
""" Disable ACL counter query """
279+
280+
fc_group_cfg = {}
281+
fc_group_cfg['FLEX_COUNTER_STATUS'] = DISABLE
282+
ctx.obj.mod_entry("FLEX_COUNTER_TABLE", ACL, fc_group_cfg)
283+
244284
# Tunnel counter commands
245285
@cli.group()
246286
def tunnel():
@@ -287,8 +327,9 @@ def show():
287327
pg_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'PG_WATERMARK')
288328
pg_drop_info = configdb.get_entry('FLEX_COUNTER_TABLE', PG_DROP)
289329
buffer_pool_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', BUFFER_POOL_WATERMARK)
330+
acl_info = configdb.get_entry('FLEX_COUNTER_TABLE', ACL)
290331
tunnel_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'TUNNEL')
291-
332+
292333
header = ("Type", "Interval (in ms)", "Status")
293334
data = []
294335
if queue_info:
@@ -307,6 +348,8 @@ def show():
307348
data.append(['PG_DROP_STAT', pg_drop_info.get("POLL_INTERVAL", DEFLT_10_SEC), pg_drop_info.get("FLEX_COUNTER_STATUS", DISABLE)])
308349
if buffer_pool_wm_info:
309350
data.append(["BUFFER_POOL_WATERMARK_STAT", buffer_pool_wm_info.get("POLL_INTERVAL", DEFLT_10_SEC), buffer_pool_wm_info.get("FLEX_COUNTER_STATUS", DISABLE)])
351+
if acl_info:
352+
data.append([ACL, pg_drop_info.get("POLL_INTERVAL", DEFLT_10_SEC), acl_info.get("FLEX_COUNTER_STATUS", DISABLE)])
310353
if tunnel_info:
311354
data.append(["TUNNEL_STAT", rif_info.get("POLL_INTERVAL", DEFLT_10_SEC), rif_info.get("FLEX_COUNTER_STATUS", DISABLE)])
312355

scripts/aclshow

+27-10
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ from tabulate import tabulate
2929
### if we could have a SAI command to clear counters will be better, so no need to maintain
3030
### counters in temp loaction for clear conter action
3131
COUNTER_POSITION = '/tmp/.counters_acl.p'
32+
COUNTERS = "COUNTERS"
33+
ACL_COUNTER_RULE_MAP = "ACL_COUNTER_RULE_MAP"
3234

3335
### acl display header
3436
ACL_HEADER = ["RULE NAME", "TABLE NAME", "PRIO", "PACKETS COUNT", "BYTES COUNT"]
3537

36-
# some constants for rule properties
37-
PACKETS_COUNTER = "packets counter"
38-
BYTES_COUNTER = "bytes counter"
38+
COUNTER_PACKETS_ATTR = "SAI_ACL_COUNTER_ATTR_PACKETS"
39+
COUNTER_BYTES_ATTR = "SAI_ACL_COUNTER_ATTR_BYTES"
40+
3941

4042
class AclStat(object):
4143
"""
@@ -91,8 +93,13 @@ class AclStat(object):
9193
read redis database for acl counters
9294
"""
9395

94-
def lowercase_keys(dictionary):
95-
return dict((k.lower(), v) for k, v in dictionary.items()) if dictionary else None
96+
def get_acl_rule_counter_map():
97+
"""
98+
Return ACL_COUNTER_RULE_MAP
99+
"""
100+
if self.db.exists(self.db.COUNTERS_DB, ACL_COUNTER_RULE_MAP):
101+
return self.db.get_all(self.db.COUNTERS_DB, ACL_COUNTER_RULE_MAP)
102+
return {}
96103

97104
def fetch_acl_tables():
98105
"""
@@ -124,8 +131,18 @@ class AclStat(object):
124131
"""
125132
Get ACL counters from the DB
126133
"""
134+
counters_db_separator = self.db.get_db_separator(self.db.COUNTERS_DB)
135+
rule_to_counter_map = get_acl_rule_counter_map()
127136
for table, rule in self.acl_rules:
128-
cnt_props = lowercase_keys(self.db.get_all(self.db.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule)))
137+
self.acl_counters[table, rule] = {}
138+
rule_identifier = table + counters_db_separator + rule
139+
if not rule_to_counter_map:
140+
continue
141+
counter_oid = rule_to_counter_map.get(rule_identifier)
142+
if not counter_oid:
143+
continue
144+
counters_db_key = COUNTERS + counters_db_separator + counter_oid
145+
cnt_props = self.db.get_all(self.db.COUNTERS_DB, counters_db_key)
129146
self.acl_counters[table, rule] = cnt_props
130147

131148
if verboseflag:
@@ -164,8 +181,8 @@ class AclStat(object):
164181
header = ACL_HEADER
165182
aclstat = []
166183
for rule_key in self.acl_rules:
167-
if not display_all and (self.get_counter_value(rule_key, 'packets') == '0' or \
168-
self.get_counter_value(rule_key, 'packets') == 'N/A'):
184+
if not display_all and (self.get_counter_value(rule_key, COUNTER_PACKETS_ATTR) == '0' or \
185+
self.get_counter_value(rule_key, COUNTER_PACKETS_ATTR) == 'N/A'):
169186
continue
170187
rule = self.acl_rules[rule_key]
171188
rule_priority = -1
@@ -174,8 +191,8 @@ class AclStat(object):
174191
rule_priority = val
175192
line = [rule_key[1], rule_key[0],
176193
rule_priority,
177-
self.get_counter_value(rule_key, 'packets'),
178-
self.get_counter_value(rule_key, 'bytes')]
194+
self.get_counter_value(rule_key, COUNTER_PACKETS_ATTR),
195+
self.get_counter_value(rule_key, COUNTER_BYTES_ATTR)]
179196
aclstat.append(line)
180197

181198
# sort the list with table name first and then descending priority

show/plugins/pbh.py

+25-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616

1717
PBH_COUNTERS_LOCATION = '/tmp/.pbh_counters.txt'
1818

19+
COUNTER_PACKETS_ATTR = "SAI_ACL_COUNTER_ATTR_PACKETS"
20+
COUNTER_BYTES_ATTR = "SAI_ACL_COUNTER_ATTR_BYTES"
21+
22+
COUNTERS = "COUNTERS"
23+
ACL_COUNTER_RULE_MAP = "ACL_COUNTER_RULE_MAP"
24+
1925
pbh_hash_field_tbl_name = 'PBH_HASH_FIELD'
2026
pbh_hash_tbl_name = 'PBH_HASH'
2127
pbh_table_tbl_name = 'PBH_TABLE'
@@ -377,8 +383,8 @@ def PBH_STATISTICS(db):
377383
row = [
378384
key[0],
379385
key[1],
380-
get_counter_value(pbh_counters, saved_pbh_counters, key, 'packets'),
381-
get_counter_value(pbh_counters, saved_pbh_counters, key, 'bytes'),
386+
get_counter_value(pbh_counters, saved_pbh_counters, key, COUNTER_PACKETS_ATTR),
387+
get_counter_value(pbh_counters, saved_pbh_counters, key, COUNTER_BYTES_ATTR),
382388
]
383389
body.append(row)
384390

@@ -415,14 +421,30 @@ def read_saved_pbh_counters():
415421
return {}
416422

417423

424+
def read_acl_rule_counter_map(db_connector):
425+
if db_connector.exists(db_connector.COUNTERS_DB, ACL_COUNTER_RULE_MAP):
426+
return db_connector.get_all(db_connector.COUNTERS_DB, ACL_COUNTER_RULE_MAP)
427+
return {}
428+
429+
418430
def read_pbh_counters(pbh_rules) -> dict:
419431
pbh_counters = {}
420432

421433
db_connector = SonicV2Connector(use_unix_socket_path=False)
422434
db_connector.connect(db_connector.COUNTERS_DB)
435+
counters_db_separator = db_connector.get_db_separator(db_connector.COUNTERS_DB)
436+
rule_to_counter_map = read_acl_rule_counter_map(db_connector)
423437

424438
for table, rule in natsort.natsorted(pbh_rules):
425-
counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule)))
439+
pbh_counters[table, rule] = {}
440+
rule_identifier = table + counters_db_separator + rule
441+
if not rule_to_counter_map:
442+
continue
443+
counter_oid = rule_to_counter_map.get(rule_identifier)
444+
if not counter_oid:
445+
continue
446+
counters_db_key = COUNTERS + counters_db_separator + counter_oid
447+
counter_props = db_connector.get_all(db_connector.COUNTERS_DB, counters_db_key)
426448
if counter_props:
427449
pbh_counters[table, rule] = counter_props
428450

@@ -457,10 +479,6 @@ def inject_symmetric_field(obj_list):
457479
counter = 0
458480

459481

460-
def lowercase_keys(dictionary):
461-
return dict((k.lower(), v) for k, v in dictionary.items()) if dictionary else None
462-
463-
464482
def register(cli):
465483
cli_node = PBH
466484
if cli_node.name in cli.commands:

tests/counterpoll_test.py

+34
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
QUEUE_WATERMARK_STAT 10000 enable
2727
PG_WATERMARK_STAT 10000 enable
2828
PG_DROP_STAT 10000 enable
29+
ACL 10000 enable
2930
"""
3031

3132
class TestCounterpoll(object):
@@ -63,6 +64,15 @@ def test_pg_drop_interval_too_long(self):
6364
assert result.exit_code == 2
6465
assert expected in result.output
6566

67+
@pytest.mark.parametrize("interval", [100, 50000])
68+
def test_acl_interval_range(self, interval):
69+
runner = CliRunner()
70+
result = runner.invoke(counterpoll.cli.commands["acl"].commands["interval"], [str(interval)])
71+
print(result.output)
72+
expected = "Invalid value for \"POLL_INTERVAL\": {} is not in the valid range of 1000 to 30000.".format(interval)
73+
assert result.exit_code == 2
74+
assert expected in result.output
75+
6676
@pytest.fixture(scope='class')
6777
def _get_config_db_file(self):
6878
sample_config_db_file = os.path.join(test_path, "counterpoll_input", "config_db.json")
@@ -109,6 +119,30 @@ def test_update_pg_drop_interval(self):
109119
table = db.cfgdb.get_table('FLEX_COUNTER_TABLE')
110120
assert test_interval == table["PG_DROP"]["POLL_INTERVAL"]
111121

122+
@pytest.mark.parametrize("status", ["disable", "enable"])
123+
def test_update_acl_status(self, status):
124+
runner = CliRunner()
125+
db = Db()
126+
127+
result = runner.invoke(counterpoll.cli.commands["acl"].commands[status], [], obj=db.cfgdb)
128+
print(result.exit_code, result.output)
129+
assert result.exit_code == 0
130+
131+
table = db.cfgdb.get_table("FLEX_COUNTER_TABLE")
132+
assert status == table["ACL"]["FLEX_COUNTER_STATUS"]
133+
134+
def test_update_acl_interval(self):
135+
runner = CliRunner()
136+
db = Db()
137+
test_interval = "20000"
138+
139+
result = runner.invoke(counterpoll.cli.commands["acl"].commands["interval"], [test_interval], obj=db.cfgdb)
140+
print(result.exit_code, result.output)
141+
assert result.exit_code == 0
142+
143+
table = db.cfgdb.get_table("FLEX_COUNTER_TABLE")
144+
assert test_interval == table["ACL"]["POLL_INTERVAL"]
145+
112146
@classmethod
113147
def teardown_class(cls):
114148
print("TEARDOWN")

tests/mock_tables/asic0/counters_db.json

+56-43
Original file line numberDiff line numberDiff line change
@@ -1419,49 +1419,62 @@
14191419
"oid:0x600000000063d": "SAI_ROUTER_INTERFACE_TYPE_PORT",
14201420
"oid:0x600000000065f": "SAI_ROUTER_INTERFACE_TYPE_PORT"
14211421
},
1422-
"COUNTERS:DATAACL:DEFAULT_RULE": {
1423-
"Bytes": "1",
1424-
"Packets": "2"
1425-
},
1426-
"COUNTERS:DATAACL:RULE_1": {
1427-
"Bytes": "100",
1428-
"Packets": "101"
1429-
},
1430-
"COUNTERS:DATAACL:RULE_2": {
1431-
"Bytes": "200",
1432-
"Packets": "201"
1433-
},
1434-
"COUNTERS:DATAACL:RULE_3": {
1435-
"Bytes": "300",
1436-
"Packets": "301"
1437-
},
1438-
"COUNTERS:DATAACL:RULE_4": {
1439-
"Bytes": "400",
1440-
"Packets": "401"
1441-
},
1442-
"COUNTERS:DATAACL:RULE_05": {
1443-
"Bytes": "0",
1444-
"Packets": "0"
1445-
},
1446-
"COUNTERS:EVERFLOW:RULE_6": {
1447-
"Bytes": "600",
1448-
"Packets": "601"
1449-
},
1450-
"COUNTERS:DATAACL:RULE_7":{
1451-
"Bytes": "700",
1452-
"Packets": "701"
1453-
},
1454-
"COUNTERS:EVERFLOW:RULE_08": {
1455-
"Bytes": "0",
1456-
"Packets": "0"
1457-
},
1458-
"COUNTERS:DATAACL:RULE_9": {
1459-
"Bytes": "900",
1460-
"Packets": "901"
1461-
},
1462-
"COUNTERS:DATAACL:RULE_10": {
1463-
"Bytes": "1000",
1464-
"Packets": "1001"
1422+
"COUNTERS:oid:0x9000000000000": {
1423+
"SAI_ACL_COUNTER_ATTR_PACKETS": "2",
1424+
"SAI_ACL_COUNTER_ATTR_BYTES": "1"
1425+
},
1426+
"COUNTERS:oid:0x9000000000001": {
1427+
"SAI_ACL_COUNTER_ATTR_PACKETS": "101",
1428+
"SAI_ACL_COUNTER_ATTR_BYTES": "100"
1429+
},
1430+
"COUNTERS:oid:0x9000000000002": {
1431+
"SAI_ACL_COUNTER_ATTR_PACKETS": "201",
1432+
"SAI_ACL_COUNTER_ATTR_BYTES": "200"
1433+
},
1434+
"COUNTERS:oid:0x9000000000003": {
1435+
"SAI_ACL_COUNTER_ATTR_PACKETS": "301",
1436+
"SAI_ACL_COUNTER_ATTR_BYTES": "300"
1437+
},
1438+
"COUNTERS:oid:0x9000000000004": {
1439+
"SAI_ACL_COUNTER_ATTR_PACKETS": "401",
1440+
"SAI_ACL_COUNTER_ATTR_BYTES": "400"
1441+
},
1442+
"COUNTERS:oid:0x9000000000005": {
1443+
"SAI_ACL_COUNTER_ATTR_PACKETS": "0",
1444+
"SAI_ACL_COUNTER_ATTR_BYTES": "0"
1445+
},
1446+
"COUNTERS:oid:0x9000000000006": {
1447+
"SAI_ACL_COUNTER_ATTR_PACKETS": "601",
1448+
"SAI_ACL_COUNTER_ATTR_BYTES": "600"
1449+
},
1450+
"COUNTERS:oid:0x9000000000007":{
1451+
"SAI_ACL_COUNTER_ATTR_PACKETS": "701",
1452+
"SAI_ACL_COUNTER_ATTR_BYTES": "700"
1453+
},
1454+
"COUNTERS:oid:0x9000000000008": {
1455+
"SAI_ACL_COUNTER_ATTR_PACKETS": "0",
1456+
"SAI_ACL_COUNTER_ATTR_BYTES": "0"
1457+
},
1458+
"COUNTERS:oid:0x9000000000009": {
1459+
"SAI_ACL_COUNTER_ATTR_PACKETS": "901",
1460+
"SAI_ACL_COUNTER_ATTR_BYTES": "900"
1461+
},
1462+
"COUNTERS:oid:0x900000000000a": {
1463+
"SAI_ACL_COUNTER_ATTR_PACKETS": "1001",
1464+
"SAI_ACL_COUNTER_ATTR_BYTES": "1000"
1465+
},
1466+
"ACL_COUNTER_RULE_MAP": {
1467+
"DATAACL:DEFAULT_RULE": "oid:0x9000000000000",
1468+
"DATAACL:RULE_1": "oid:0x9000000000001",
1469+
"DATAACL:RULE_2": "oid:0x9000000000002",
1470+
"DATAACL:RULE_3": "oid:0x9000000000003",
1471+
"DATAACL:RULE_4": "oid:0x9000000000004",
1472+
"DATAACL:RULE_05": "oid:0x9000000000005",
1473+
"EVERFLOW:RULE_6": "oid:0x9000000000006",
1474+
"DATAACL:RULE_7": "oid:0x9000000000007",
1475+
"EVERFLOW:RULE_08": "oid:0x9000000000008",
1476+
"DATAACL:RULE_9": "oid:0x9000000000009",
1477+
"DATAACL:RULE_10": "oid:0x900000000000a"
14651478
},
14661479
"COUNTERS:oid:0x1000000000002": {
14671480
"SAI_PORT_STAT_IF_IN_UCAST_PKTS": "8",

0 commit comments

Comments
 (0)