Skip to content

Commit 71cf3ee

Browse files
stephenxsabdosi
authored andcommitted
[Reclaim buffer] [Mellanox] Db migrator support reclaiming reserved buffer for unused ports (#1822)
Signed-off-by: Stephen Sun [email protected] What I did Db migrator support reclaiming reserved buffer for unused ports How I did it For admin down ports, if the buffer objects configuration aligns with default configuration, set the buffer objects configuration as: Dynamic model: all normal buffer objects are configured on admin down ports. Buffer manager will apply zero profiles on admin down ports. Static model: zero buffer objects are configured on admin down ports. How to verify it Unit test. Manually test.
1 parent e699b49 commit 71cf3ee

File tree

194 files changed

+16815
-4293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+16815
-4293
lines changed

scripts/db_migrator.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(self, namespace, socket=None):
4444
none-zero values.
4545
build: sequentially increase within a minor version domain.
4646
"""
47-
self.CURRENT_VERSION = 'version_2_0_3'
47+
self.CURRENT_VERSION = 'version_2_0_4'
4848

4949
self.TABLE_NAME = 'VERSIONS'
5050
self.TABLE_KEY = 'DATABASE'
@@ -76,7 +76,7 @@ def __init__(self, namespace, socket=None):
7676

7777
if asic_type == "mellanox":
7878
from mellanox_buffer_migrator import MellanoxBufferMigrator
79-
self.mellanox_buffer_migrator = MellanoxBufferMigrator(self.configDB)
79+
self.mellanox_buffer_migrator = MellanoxBufferMigrator(self.configDB, self.appDB, self.stateDB)
8080

8181
def migrate_pfc_wd_table(self):
8282
'''
@@ -617,9 +617,19 @@ def version_2_0_2(self):
617617

618618
def version_2_0_3(self):
619619
"""
620-
Current latest version. Nothing to do here.
620+
Version 2_0_3
621621
"""
622622
log.log_info('Handling version_2_0_3')
623+
if self.asic_type == "mellanox":
624+
self.mellanox_buffer_migrator.mlnx_reclaiming_unused_buffer()
625+
self.set_version('version_2_0_4')
626+
return 'version_2_0_4'
627+
628+
def version_2_0_4(self):
629+
"""
630+
Current latest version. Nothing to do here.
631+
"""
632+
log.log_info('Handling version_2_0_4')
623633
return None
624634

625635
def get_version(self):

scripts/mellanox_buffer_migrator.py

+260-1
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,18 @@
7979
Not providing it means no buffer profile migration required.
8080
"""
8181
from sonic_py_common import logger
82+
import re
8283

8384
SYSLOG_IDENTIFIER = 'mellanox_buffer_migrator'
8485

8586
# Global logger instance
8687
log = logger.Logger(SYSLOG_IDENTIFIER)
8788

8889
class MellanoxBufferMigrator():
89-
def __init__(self, configDB):
90+
def __init__(self, configDB, appDB, stateDB):
9091
self.configDB = configDB
92+
self.appDB = appDB
93+
self.stateDB = stateDB
9194

9295
self.platform = None
9396
self.sku = None
@@ -834,3 +837,259 @@ def mlnx_flush_new_buffer_configuration(self):
834837

835838
def mlnx_is_buffer_model_dynamic(self):
836839
return self.is_buffer_config_default and not self.is_msft_sku
840+
841+
def mlnx_reorganize_buffer_tables(self, buffer_table, name):
842+
"""
843+
This is to reorganize the BUFFER_PG and BUFFER_QUEUE tables from single tier index to double tiers index.
844+
Originally, the index is like <port>|<ids>. However, we need to check all the items with respect to a port,
845+
which requires two tiers index, <port> and then <ids>
846+
Eg.
847+
Before reorganize:
848+
{
849+
"Ethernet0|0": {"profile" : "ingress_lossy_profile"},
850+
"Ethernet0|3-4": {"profile": "pg_lossless_100000_5m_profile"},
851+
"Ethernet4|0": {"profile" : "ingress_lossy_profile"},
852+
"Ethernet4|3-4": {"profile": "pg_lossless_50000_5m_profile"}
853+
}
854+
After reorganize:
855+
{
856+
"Ethernet0": {
857+
"0": {"profile" : "ingress_lossy_profile"},
858+
"3-4": {"profile": "pg_lossless_100000_5m_profile"}
859+
},
860+
"Ethernet4": {
861+
"0": {"profile" : "ingress_lossy_profile"},
862+
"3-4": {"profile": "pg_lossless_50000_5m_profile"}
863+
}
864+
}
865+
"""
866+
result = {}
867+
for key, item in buffer_table.items():
868+
if len(key) != 2:
869+
log.log_error('Table {} contains invalid key {}, skip this item'.format(name, key))
870+
continue
871+
port, ids = key
872+
if not port in result:
873+
result[port] = {}
874+
result[port][ids] = item
875+
876+
return result
877+
878+
def mlnx_reclaiming_unused_buffer(self):
879+
cable_length_key = self.configDB.get_keys('CABLE_LENGTH')
880+
if not cable_length_key:
881+
log.log_notice("No cable length table defined, do not migrate buffer objects for reclaiming buffer")
882+
return;
883+
884+
log.log_info("Migrate buffer objects for reclaiming buffer based on 'CABLE_LENGTH|{}'".format(cable_length_key[0]))
885+
886+
device_metadata = self.configDB.get_entry('DEVICE_METADATA', 'localhost')
887+
is_dynamic = (device_metadata.get('buffer_model') == 'dynamic')
888+
889+
port_table = self.configDB.get_table('PORT')
890+
buffer_pool_table = self.configDB.get_table('BUFFER_POOL')
891+
buffer_profile_table = self.configDB.get_table('BUFFER_PROFILE')
892+
buffer_pg_table = self.configDB.get_table('BUFFER_PG')
893+
buffer_queue_table = self.configDB.get_table('BUFFER_QUEUE')
894+
buffer_ingress_profile_list_table = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST')
895+
buffer_egress_profile_list_table = self.configDB.get_table('BUFFER_PORT_EGRESS_PROFILE_LIST')
896+
cable_length_entries = self.configDB.get_entry('CABLE_LENGTH', cable_length_key[0])
897+
898+
buffer_pg_items = self.mlnx_reorganize_buffer_tables(buffer_pg_table, 'BUFFER_PG')
899+
buffer_queue_items = self.mlnx_reorganize_buffer_tables(buffer_queue_table, 'BUFFER_QUEUE')
900+
901+
single_pool = True
902+
if 'ingress_lossy_pool' in buffer_pool_table:
903+
ingress_lossy_profile = buffer_profile_table.get('ingress_lossy_profile')
904+
if ingress_lossy_profile:
905+
if 'ingress_lossy_pool' == ingress_lossy_profile.get('pool'):
906+
single_pool = False
907+
908+
# Construct buffer items to be applied to admin down ports
909+
if is_dynamic:
910+
# For dynamic model, we just need to add the default buffer objects to admin down ports
911+
# Buffer manager will apply zero profiles automatically when a port is shutdown
912+
lossy_pg_item = {'profile': 'ingress_lossy_profile'} if 'ingress_lossy_profile' in buffer_profile_table else None
913+
lossy_queue_item = {'profile': 'q_lossy_profile'} if 'q_lossy_profile' in buffer_profile_table else None
914+
lossless_queue_item = {'profile': 'egress_lossless_profile'} if 'egress_lossless_profile' in buffer_profile_table else None
915+
916+
queue_items_to_apply = {'0-2': lossy_queue_item,
917+
'3-4': lossless_queue_item,
918+
'5-6': lossy_queue_item}
919+
920+
if single_pool:
921+
if 'ingress_lossless_profile' in buffer_profile_table:
922+
ingress_profile_list_item = {'profile_list': 'ingress_lossless_profile'}
923+
else:
924+
ingress_profile_list_item = None
925+
else:
926+
if 'ingress_lossless_profile' in buffer_profile_table and 'ingress_lossy_profile' in buffer_profile_table:
927+
ingress_profile_list_item = {'profile_list': 'ingress_lossless_profile,ingress_lossy_profile'}
928+
else:
929+
ingress_profile_list_item = None
930+
931+
if 'egress_lossless_profile' in buffer_profile_table and 'egress_lossy_profile' in buffer_profile_table:
932+
egress_profile_list_item = {'profile_list': 'egress_lossless_profile,egress_lossy_profile'}
933+
else:
934+
egress_profile_list_item = None
935+
936+
pools_to_insert = None
937+
profiles_to_insert = None
938+
939+
else:
940+
# For static model, we need more.
941+
# Define zero buffer pools and profiles
942+
ingress_zero_pool = {'size': '0', 'mode': 'static', 'type': 'ingress'}
943+
ingress_lossy_pg_zero_profile = {
944+
"pool":"ingress_zero_pool",
945+
"size":"0",
946+
"static_th":"0"
947+
}
948+
lossy_pg_item = {'profile': 'ingress_lossy_pg_zero_profile'}
949+
950+
ingress_lossless_zero_profile = {
951+
"pool":"ingress_lossless_pool",
952+
"size":"0",
953+
"dynamic_th":"-8"
954+
}
955+
956+
if single_pool:
957+
ingress_profile_list_item = {'profile_list': 'ingress_lossless_zero_profile'}
958+
else:
959+
ingress_lossy_zero_profile = {
960+
"pool":"ingress_lossy_pool",
961+
"size":"0",
962+
"dynamic_th":"-8"
963+
}
964+
ingress_profile_list_item = {'profile_list': 'ingress_lossless_zero_profile,ingress_lossy_zero_profile'}
965+
966+
egress_lossless_zero_profile = {
967+
"pool":"egress_lossless_pool",
968+
"size":"0",
969+
"dynamic_th":"-8"
970+
}
971+
lossless_queue_item = {'profile': 'egress_lossless_zero_profile'}
972+
973+
egress_lossy_zero_profile = {
974+
"pool":"egress_lossy_pool",
975+
"size":"0",
976+
"dynamic_th":"-8"
977+
}
978+
lossy_queue_item = {'profile': 'egress_lossy_zero_profile'}
979+
egress_profile_list_item = {'profile_list': 'egress_lossless_zero_profile,egress_lossy_zero_profile'}
980+
981+
queue_items_to_apply = {'0-2': lossy_queue_item,
982+
'3-4': lossless_queue_item,
983+
'5-6': lossy_queue_item}
984+
985+
pools_to_insert = {'ingress_zero_pool': ingress_zero_pool}
986+
profiles_to_insert = {'ingress_lossy_pg_zero_profile': ingress_lossy_pg_zero_profile,
987+
'ingress_lossless_zero_profile': ingress_lossless_zero_profile,
988+
'egress_lossless_zero_profile': egress_lossless_zero_profile,
989+
'egress_lossy_zero_profile': egress_lossy_zero_profile}
990+
if not single_pool:
991+
profiles_to_insert['ingress_lossy_zero_profile'] = ingress_lossy_zero_profile
992+
993+
lossless_profile_pattern = 'pg_lossless_([1-9][0-9]*000)_([1-9][0-9]*m)_profile'
994+
zero_item_count = 0
995+
reclaimed_ports = set()
996+
for port_name, port_info in port_table.items():
997+
if port_info.get('admin_status') == 'up':
998+
# Handles admin down ports only
999+
continue
1000+
1001+
# If items to be applied to admin down port of BUFFER_PG table have been generated,
1002+
# Check whether the BUFFER_PG items with respect to the port align with the default one,
1003+
# and insert the items to BUFFER_PG
1004+
# The same logic for BUFFER_QUEUE, BUFFER_PORT_INGRESS_PROFILE_LIST and BUFFER_PORT_EGRESS_PROFILE_LIST
1005+
if lossy_pg_item:
1006+
port_pgs = buffer_pg_items.get(port_name)
1007+
is_default = False
1008+
if not port_pgs:
1009+
is_default = True
1010+
else:
1011+
if set(port_pgs.keys()) == set(['3-4']):
1012+
if is_dynamic:
1013+
reclaimed_ports.add(port_name)
1014+
if port_pgs['3-4']['profile'] == 'NULL':
1015+
is_default = True
1016+
else:
1017+
match = re.search(lossless_profile_pattern, port_pgs['3-4']['profile'])
1018+
if match:
1019+
speed = match.group(1)
1020+
cable_length = match.group(2)
1021+
if speed == port_info.get('speed') and cable_length == cable_length_entries.get(port_name):
1022+
is_default = True
1023+
1024+
if is_default:
1025+
lossy_pg_key = '{}|0'.format(port_name)
1026+
lossless_pg_key = '{}|3-4'.format(port_name)
1027+
self.configDB.set_entry('BUFFER_PG', lossy_pg_key, lossy_pg_item)
1028+
if is_dynamic:
1029+
self.configDB.set_entry('BUFFER_PG', lossless_pg_key, {'profile': 'NULL'})
1030+
# For traditional model, we must NOT remove the default lossless PG
1031+
# because it has been popagated to APPL_DB during db_migrator
1032+
# Leaving it untouched in CONFIG_DB enables traditional buffer manager to
1033+
# remove it from CONFIG_DB as well as APPL_DB
1034+
# However, removing it from CONFIG_DB causes it left in APPL_DB
1035+
zero_item_count += 1
1036+
1037+
if lossy_queue_item and lossless_queue_item:
1038+
port_queues = buffer_queue_items.get(port_name)
1039+
if not port_queues:
1040+
for ids, item in queue_items_to_apply.items():
1041+
self.configDB.set_entry('BUFFER_QUEUE', port_name + '|' + ids, item)
1042+
zero_item_count += 1
1043+
1044+
if ingress_profile_list_item:
1045+
port_ingress_profile_list = buffer_ingress_profile_list_table.get(port_name)
1046+
if not port_ingress_profile_list:
1047+
self.configDB.set_entry('BUFFER_PORT_INGRESS_PROFILE_LIST', port_name, ingress_profile_list_item)
1048+
zero_item_count += 1
1049+
1050+
if egress_profile_list_item:
1051+
port_egress_profile_list = buffer_egress_profile_list_table.get(port_name)
1052+
if not port_egress_profile_list:
1053+
self.configDB.set_entry('BUFFER_PORT_EGRESS_PROFILE_LIST', port_name, egress_profile_list_item)
1054+
zero_item_count += 1
1055+
1056+
if zero_item_count > 0:
1057+
if pools_to_insert:
1058+
for name, pool in pools_to_insert.items():
1059+
self.configDB.set_entry('BUFFER_POOL', name, pool)
1060+
1061+
if profiles_to_insert:
1062+
for name, profile in profiles_to_insert.items():
1063+
self.configDB.set_entry('BUFFER_PROFILE', name, profile)
1064+
1065+
# We need to remove BUFFER_PG table items for admin down ports from APPL_DB
1066+
# and then remove the buffer profiles which are no longer referenced
1067+
# We do it here because
1068+
# - The buffer profiles were copied from CONFIG_DB by db_migrator when the database was being migrated from 1.0.6 to 2.0.0
1069+
# - In this migrator the buffer priority-groups have been removed from CONFIG_DB.BUFFER_PG table
1070+
# - The dynamic buffer manager will not generate buffer profile by those buffer PG items
1071+
# In case a buffer profile was referenced by an admin down port only, the dynamic buffer manager won't create it after starting
1072+
# This kind of buffer profiles will be left in APPL_DB and can not be removed.
1073+
if not is_dynamic:
1074+
return
1075+
1076+
warmreboot_state = self.stateDB.get(self.stateDB.STATE_DB, 'WARM_RESTART_ENABLE_TABLE|system', 'enable')
1077+
if warmreboot_state == 'true':
1078+
referenced_profiles = set()
1079+
keys = self.appDB.keys(self.appDB.APPL_DB, "BUFFER_PG_TABLE:*")
1080+
if keys is None:
1081+
return
1082+
for buffer_pg_key in keys:
1083+
port, pg = buffer_pg_key.split(':')[1:]
1084+
if port in reclaimed_ports:
1085+
self.appDB.delete(self.appDB.APPL_DB, buffer_pg_key)
1086+
else:
1087+
buffer_pg_items = self.appDB.get_all(self.appDB.APPL_DB, buffer_pg_key)
1088+
profile = buffer_pg_items.get('profile')
1089+
if profile:
1090+
referenced_profiles.add(profile)
1091+
keys = self.appDB.keys(self.appDB.APPL_DB, "BUFFER_PROFILE_TABLE:*")
1092+
for buffer_profile_key in keys:
1093+
profile = buffer_profile_key.split(':')[1]
1094+
if profile not in referenced_profiles and profile not in buffer_profile_table.keys():
1095+
self.appDB.delete(self.appDB.APPL_DB, buffer_profile_key)

tests/db_migrator_input/appl_db/acs-msn4700-t1-version_2_0_0.json

-7
Original file line numberDiff line numberDiff line change
@@ -712,13 +712,6 @@
712712
"pool": "[BUFFER_POOL_TABLE:ingress_lossless_pool]",
713713
"size": "124928"
714714
},
715-
"BUFFER_PROFILE_TABLE:pg_lossless_400000_300m_profile": {
716-
"xon": "37888",
717-
"dynamic_th": "0",
718-
"xoff": "373760",
719-
"pool": "[BUFFER_POOL_TABLE:ingress_lossless_pool]",
720-
"size": "420864"
721-
},
722715
"BUFFER_PROFILE_TABLE:q_lossy_profile": {
723716
"dynamic_th": "3",
724717
"pool": "[BUFFER_POOL_TABLE:egress_lossy_pool]",

tests/db_migrator_input/appl_db/acs-msn4700-t1-version_2_0_3.json

-7
Original file line numberDiff line numberDiff line change
@@ -712,13 +712,6 @@
712712
"pool": "ingress_lossless_pool",
713713
"size": "124928"
714714
},
715-
"BUFFER_PROFILE_TABLE:pg_lossless_400000_300m_profile": {
716-
"xon": "37888",
717-
"dynamic_th": "0",
718-
"xoff": "373760",
719-
"pool": "ingress_lossless_pool",
720-
"size": "420864"
721-
},
722715
"BUFFER_PROFILE_TABLE:q_lossy_profile": {
723716
"dynamic_th": "3",
724717
"pool": "egress_lossy_pool",

0 commit comments

Comments
 (0)