|
79 | 79 | Not providing it means no buffer profile migration required.
|
80 | 80 | """
|
81 | 81 | from sonic_py_common import logger
|
| 82 | +import re |
82 | 83 |
|
83 | 84 | SYSLOG_IDENTIFIER = 'mellanox_buffer_migrator'
|
84 | 85 |
|
85 | 86 | # Global logger instance
|
86 | 87 | log = logger.Logger(SYSLOG_IDENTIFIER)
|
87 | 88 |
|
88 | 89 | class MellanoxBufferMigrator():
|
89 |
| - def __init__(self, configDB): |
| 90 | + def __init__(self, configDB, appDB, stateDB): |
90 | 91 | self.configDB = configDB
|
| 92 | + self.appDB = appDB |
| 93 | + self.stateDB = stateDB |
91 | 94 |
|
92 | 95 | self.platform = None
|
93 | 96 | self.sku = None
|
@@ -834,3 +837,259 @@ def mlnx_flush_new_buffer_configuration(self):
|
834 | 837 |
|
835 | 838 | def mlnx_is_buffer_model_dynamic(self):
|
836 | 839 | 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) |
0 commit comments