From c913ceb6783fb94f680397cf4134e45b3a24f4f0 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Fri, 29 May 2020 12:20:22 +0800 Subject: [PATCH 01/13] [config] Add configurations for dynamically buffer calculation Signed-off-by: Stephen Sun --- config/main.py | 281 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 280 insertions(+), 1 deletion(-) mode change 100755 => 100644 config/main.py diff --git a/config/main.py b/config/main.py old mode 100755 new mode 100644 index 731043a668..0e94440a40 --- a/config/main.py +++ b/config/main.py @@ -2122,6 +2122,202 @@ def remove(ctx, interface_name, ip_addr): except ValueError: ctx.fail("'ip_addr' is not valid.") + +def pgmaps_check_legality(ctx, interface_name, new_pg, profile = None): + """ + Tool function to check whether new_pg is legal. + Three checking performed: + 1. Whether the new_pg is legal: pgs are in range [0-7] + 2. Whether the new_pg overlaps an existing pg in the port + 3. Whether there is any other PG on the interface refering other lossless profiles + """ + config_db = ctx.obj["config_db"] + + try: + lower = int(new_pg[0]) + upper = int(new_pg[-1]) + + if upper < lower or lower < 0 or upper > 7: + ctx.fail("PG {} is not valid.".format(new_pg)) + except: + ctx.fail("PG {} is not valid.".format(new_pg)) + + # Check overlapping. + # To configure a new PG which is overlapping an existing one is not allowed + # For example, to add '5-6' while '3-5' existing is illegal + existing_pgs = config_db.get_table("BUFFER_PG") + for k, v in existing_pgs.iteritems(): + port, existing_pg = k + if port == interface_name: + existing_lower = int(existing_pg[0]) + existing_upper = int(existing_pg[-1]) + if existing_upper < lower or existing_lower > upper: + # new and existing pgs disjoint, legal + pass + else: + ctx.fail("PG {} overlaps with existing PG {}".format(new_pg, existing_pg)) + + if 'profile' in v.keys(): + existing_profile_name = v['profile'][1:-1] + pure_profile_name = existing_profile_name.split('|')[1] + if existing_profile_name != profile: + existing_profile_entry = config_db.get_entry("BUFFER_PROFILE", pure_profile_name) + if not 'xoff' in existing_profile_entry.keys(): + # We don't care about non lossless profile + continue + else: + ctx.fail("Existing lossless PG {} references a different profile {}".format(existing_pg, existing_profile_name)) + elif profile: + ctx.fail("Existing lossless PG {} is dynamically calculated and should be removed first") + +def remove_pg_on_port(ctx, interface_name, pg_map, profile = None): + config_db = ctx.obj["config_db"] + + # Check whether port is legal + ports = config_db.get_entry("PORT", interface_name) + if not ports: + ctx.fail("Port {} doesn't exist".format(interface_name)) + + # Remvoe all dynamic lossless PGs on the port + existing_pgs = config_db.get_table("BUFFER_PG") + for k, v in existing_pgs.iteritems(): + port, existing_pg = k + if port == interface_name and (not pg_map or pg_map == existing_pg): + need_to_remove = False + referenced_profile = v.get('profile') + if referenced_profile and referenced_profile[1:-1] == profile: + # Remove headroom override + need_to_remove = True + elif not profile and not v: + # Remove dynamic lossless PG + need_to_remove = True + if need_to_remove: + config_db.set_entry("BUFFER_PG", (interface_name, existing_pg), None) + + +# +# 'headroom_override' subgroup ('config interface headroom_override ...') +# + +@interface.group(cls=AbbreviationGroup) +@click.pass_context +def headroom_override(ctx): + """Set or Clear headroom override""" + pass + +# +# 'add' command ('config interface headroom_override add ...') +# +@headroom_override.command() +@click.argument('interface_name', metavar='', required=True) +@click.argument('profile', metavar='', required=True) +@click.argument('pg_map', metavar='', required=True) +@click.pass_context +def add(ctx, interface_name, profile, pg_map): + """Set headroom_override for the interface""" + config_db = ctx.obj["config_db"] + + if not pg_map: + pg_map = '3-4' + + if not config_db.get_entry("BUFFER_PROFILE", profile): + ctx.fail("Profile {} doesn't exist".format(profile)) + + profile_full_name = "BUFFER_PROFILE|{}".format(profile) + + # Check whether pg_map is legal + # Check whether there is other lossless profiles configured on the interface + pgmaps_check_legality(ctx, interface_name, pg_map, profile_full_name) + + # All checking passed + config_db.set_entry("BUFFER_PG", (interface_name, pg_map), {"profile": "[{}]".format(profile_full_name)}) + +# +# 'remove' command ('config interface headroom_override remove ...') +# +@headroom_override.command() +@click.argument('interface_name', metavar='', required=True) +@click.argument('profile', metavar='', required=True) +@click.argument('pg_map', metavar='', required=False) +@click.pass_context +def remove(ctx, interface_name, profile, pg_map): + """Set headroom_override for the interface""" + remove_pg_on_port(ctx, interface_name, pg_map, "BUFFER_PROFILE|{}".format(profile)) + +# +# 'lossless_pg' subgroup ('config interface lossless_pg ...') +# + +@interface.group(cls=AbbreviationGroup) +@click.pass_context +def lossless_pg(ctx): + """Set or clear lossless PGs""" + pass + +# +# 'add' subcommand +# + +@lossless_pg.command() +@click.argument('interface_name', metavar='', required=True) +@click.argument('pg_map', metavar='', required=True) +@click.pass_context +def add(ctx, interface_name, pg_map): + """Set lossless PGs for the interface""" + config_db = ctx.obj["config_db"] + + # Check whether port is legal + ports = config_db.get_entry("PORT", interface_name) + if not ports: + ctx.fail("Port {} doesn't exist".format(interface_name)) + + # Check whether pg_map is legal + # Check whether there is other lossless profiles configured on the interface + pgmaps_check_legality(ctx, interface_name, pg_map) + + # All checking passed + config_db.set_entry("BUFFER_PG", (interface_name, pg_map), {"NULL": "NULL"}) + +# +# 'remove' subcommand +# +@lossless_pg.command() +@click.argument('interface_name', metavar='', required=True) +@click.argument('pg_map', metavar='m, like 300m".format(cable_length)) + + keys = config_db.get_keys("CABLE_LENGTH") + + cable_length_set = {} + cable_length_set[interface_name] = length + config_db.mod_entry("CABLE_LENGTH", keys[0], cable_length_set) + # # 'transceiver' subgroup ('config interface transceiver ...') # @@ -2682,7 +2878,90 @@ def priority(ctx, interface_name, priority, status): ctx.fail("'interface_name' is None!") run_command("pfc config priority {0} {1} {2}".format(status, interface_name, priority)) - + +# +# 'buffer_profile' group ('config buffer_profile +# + +@config.group(cls=AbbreviationGroup) +@click.pass_context +def buffer_profile(ctx): + """Configure buffer_profile""" + +@buffer_profile.command('add') +@click.option('-profile', metavar='', type=str, help="Profile name") +@click.option('-xon', metavar='', type=int, help="Set xon threshold") +@click.option('-xoff', metavar='', type=int, help="Set xoff threshold") +@click.option('-headroom', metavar='', type=int, help="Set reserved headroom size") +@click.option('-dynamic_th', metavar='', type=str, help="Set dynamic threshold") +@click.option('-pool', metavar='', type=str, help="Buffer pool") +@click.pass_context +def add(ctx, profile, xon, xoff, headroom, dynamic_th, pool): + """Add or modify a buffer profile""" + config_db = ConfigDBConnector() + config_db.connect() + params = {} + dynamic_calculate = True + + if not pool: + pool = 'ingress_lossless_pool' + params['pool'] = '[BUFFER_POOL|' + pool + ']' + if not config_db.get_entry('BUFFER_POOL', pool): + ctx.fail("Pool {} doesn't exist".format(pool)) + + if xon: + params['xon'] = xon + dynamic_calculate = False + + if xoff: + params['xoff'] = xoff + dynamic_calculate = False + + if headroom: + params['size'] = headroom + dynamic_calculate = False + elif not dynamic_calculate: + headroom = xon + xoff + params['size'] = headroom + + if dynamic_th: + params['dynamic_th'] = dynamic_th + else: + # Fetch all the keys of default_lossless_buffer_parameter table + # and then get the default_dynamic_th from that entry (should be only one) + keys = config_db.get_keys('DEFAULT_LOSSLESS_BUFFER_PARAMETER') + if len(keys) > 1 or len(keys) == 0: + ctx.fail("Multiple or no entry in DEFAULT_LOSSLESS_BUFFER_PARAMETER found while no dynamic_th specified") + + default_lossless_param = config_db.get_entry('DEFAULT_LOSSLESS_BUFFER_PARAMETER', keys[0]) + if 'default_dynamic_th' in default_lossless_param.keys(): + params['dynamic_th'] = default_lossless_param['default_dynamic_th'] + else: + ctx.fail("No dynamic_th defined in DEFAULT_LOSSLESS_BUFFER_PARAMETER") + + if dynamic_calculate: + params['headroom_type'] = 'dynamic' + + keys = config_db.get_keys("BUFFER_PROFILE") + if len(keys) > 0: + config_needs_updated = {"BUFFER_PROFILE" : { profile : params } } + else: + config_db.mod_entry("BUFFER_PROFILE", config_needs_updated) + config_db.set_entry("BUFFER_PROFILE", (profile), params) + +@buffer_profile.command('remove') +@click.argument('profile', metavar='', required=True) +@click.pass_context +def remove(ctx, profile): + """Delete a buffer profile""" + config_db = ConfigDBConnector() + config_db.connect() + entry = config_db.get_entry("BUFFER_PROFILE", profile) + if entry: + config_db.set_entry("BUFFER_PROFILE", profile, None) + else: + ctx.fail("Profile {} doesn't exist".format(profile)) + # # 'platform' group ('config platform ...') # From a5e0d69bbad61dda35564fa2884a4d7ff87608f2 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Sun, 7 Jun 2020 15:44:55 +0800 Subject: [PATCH 02/13] Support checking buffer states from STATE_DB Signed-off-by: Stephen Sun --- scripts/buffershow | 1 + scripts/mmuconfig | 59 +++++++++++++++++++++++++++++++++------------- setup.py | 1 + 3 files changed, 45 insertions(+), 16 deletions(-) create mode 120000 scripts/buffershow mode change 100644 => 100755 scripts/mmuconfig diff --git a/scripts/buffershow b/scripts/buffershow new file mode 120000 index 0000000000..e223bf79ce --- /dev/null +++ b/scripts/buffershow @@ -0,0 +1 @@ +mmuconfig \ No newline at end of file diff --git a/scripts/mmuconfig b/scripts/mmuconfig old mode 100644 new mode 100755 index 2ae7770178..0d5fa3295b --- a/scripts/mmuconfig +++ b/scripts/mmuconfig @@ -1,4 +1,4 @@ -#!/usr/bin/python +#! /usr/bin/python2 """ mmuconfig is the utility to show and change mmu configuration @@ -32,15 +32,31 @@ BUFFER_PROFILE_FIELDS = { class MmuConfig(object): - def __init__(self, verbose): + def __init__(self, verbose, config): self.verbose = verbose + self.config = config # Set up db connections - self.db = swsssdk.ConfigDBConnector() - self.db.connect() + if self.config: + self.db = swsssdk.ConfigDBConnector() + self.db.connect() + else: + self.db = swsssdk.SonicV2Connector(host='127.0.0.1') + self.db.connect(self.db.STATE_DB, False) + + def get_table(self, tablename): + if self.config: + return self.db.get_table(tablename) + + entries = {} + keys = self.db.keys(self.db.STATE_DB, tablename + '*') + for key in keys: + entries[key.split('|')[1]] = self.db.get_all(self.db.STATE_DB, key) + + return entries def list(self): - buf_pools = self.db.get_table(BUFFER_POOL_TABLE_NAME) + buf_pools = self.get_table(BUFFER_POOL_TABLE_NAME) for pool_name, pool_data in buf_pools.items(): config = [] @@ -51,7 +67,7 @@ class MmuConfig(object): if self.verbose: print("Total pools: %d\n\n" % len(buf_pools)) - buf_profs = self.db.get_table(BUFFER_PROFILE_TABLE_NAME) + buf_profs = self.get_table(BUFFER_PROFILE_TABLE_NAME) for prof_name, prof_data in buf_profs.items(): config = [] @@ -83,23 +99,31 @@ class MmuConfig(object): self.db.mod_entry(BUFFER_PROFILE_TABLE_NAME, profile, {field: value}) -def main(): - parser = argparse.ArgumentParser(description='Show and change: mmu configuration', - version='1.0.0', - formatter_class=argparse.RawTextHelpFormatter) +def main(config): + if config: + parser = argparse.ArgumentParser(description='Show and change: mmu configuration', + version='1.0.0', + formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument('-l', '--list', action='store_true', help='show mmu configuration') + parser.add_argument('-p', '--profile', type=str, help='specify buffer profile name', default=None) + parser.add_argument('-a', '--alpha', type=str, help='set n for dyanmic threshold alpha 2^(n)', default=None) + else: + parser = argparse.ArgumentParser(description='Show buffer state', + version='1.0.0', + formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument('-l', '--list', action='store_true', help='show buffer state') - parser.add_argument('-l', '--list', action='store_true', help='show mmu configuration') - parser.add_argument('-p', '--profile', type=str, help='specify buffer profile name', default=None) - parser.add_argument('-a', '--alpha', type=str, help='set n for dyanmic threshold alpha 2^(n)', default=None) parser.add_argument('-vv', '--verbose', action='store_true', help='verbose output', default=False) args = parser.parse_args() try: - mmu_cfg = MmuConfig(args.verbose) + mmu_cfg = MmuConfig(args.verbose, config) if args.list: mmu_cfg.list() - elif args.profile: + elif config and args.profile: if args.alpha: mmu_cfg.set(args.profile, "alpha", args.alpha) else: @@ -111,4 +135,7 @@ def main(): sys.exit(1) if __name__ == "__main__": - main() + if sys.argv[0].split('/')[-1] == "mmuconfig": + main(True) + else: + main(False) diff --git a/setup.py b/setup.py index edffa77cd0..4d9ca5648a 100644 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ 'scripts/aclshow', 'scripts/asic_config_check', 'scripts/boot_part', + 'scripts/buffershow', 'scripts/coredump-compress', 'scripts/configlet', 'scripts/db_migrator.py', From 3315fb7dcc1f6fcbbb54c419f9e42aea02c0962a Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Mon, 8 Jun 2020 15:22:22 +0800 Subject: [PATCH 03/13] Fix issue: if no buffer related data in STATE_DB mmuconfig will fail Signed-off-by: Stephen Sun --- scripts/mmuconfig | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/scripts/mmuconfig b/scripts/mmuconfig index 0d5fa3295b..bbf638e923 100755 --- a/scripts/mmuconfig +++ b/scripts/mmuconfig @@ -50,6 +50,10 @@ class MmuConfig(object): entries = {} keys = self.db.keys(self.db.STATE_DB, tablename + '*') + + if not keys: + return None + for key in keys: entries[key.split('|')[1]] = self.db.get_all(self.db.STATE_DB, key) @@ -57,26 +61,32 @@ class MmuConfig(object): def list(self): buf_pools = self.get_table(BUFFER_POOL_TABLE_NAME) - for pool_name, pool_data in buf_pools.items(): - config = [] - - print("Pool: " + pool_name) - for field, value in pool_data.items(): - config.append([field, value]) - print(tabulate.tabulate(config) + "\n") - if self.verbose: - print("Total pools: %d\n\n" % len(buf_pools)) + if buf_pools: + for pool_name, pool_data in buf_pools.items(): + config = [] + + print("Pool: " + pool_name) + for field, value in pool_data.items(): + config.append([field, value]) + print(tabulate.tabulate(config) + "\n") + if self.verbose: + print("Total pools: %d\n\n" % len(buf_pools)) + else: + print("No buffer pool information available") buf_profs = self.get_table(BUFFER_PROFILE_TABLE_NAME) - for prof_name, prof_data in buf_profs.items(): - config = [] - - print("Profile: " + prof_name) - for field, value in prof_data.items(): - config.append([field, value]) - print(tabulate.tabulate(config) + "\n") - if self.verbose: - print("Total profiles: %d" % len(buf_profs)) + if buf_profs: + for prof_name, prof_data in buf_profs.items(): + config = [] + + print("Profile: " + prof_name) + for field, value in prof_data.items(): + config.append([field, value]) + print(tabulate.tabulate(config) + "\n") + if self.verbose: + print("Total profiles: %d" % len(buf_profs)) + else: + print("No buffer profile information available") def set(self, profile, field_alias, value): if os.geteuid() != 0: From 8509c4126fcd56f5dd45e32a3ce2fa9d447d066d Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Tue, 9 Jun 2020 15:08:00 +0800 Subject: [PATCH 04/13] Add CLI reference for buffer management Signed-off-by: Stephen Sun --- doc/Command-Reference.md | 266 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 4 deletions(-) diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 9ee91a88cd..caed1ae380 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -40,6 +40,9 @@ * [Drop Counter show commands](#drop-counters-show-commands) * [Drop Counter config commands](#drop-counters-config-commands) * [Drop Counter clear commands](#drop-counters-clear-commands) +* [Dynamic Buffer Management](#dynamic-buffer-management) + * [Configuration commands](#configuration-commands) + * [Show commands](#show-commands) * [ECN](#ecn) * [ECN show commands](#ecn-show-commands) * [ECN config commands](#ecn-config-commands) @@ -2002,7 +2005,7 @@ This command is used to delete a configured DHCP Relay Destination IP address fr Go Back To [Beginning of the document](#) or [Beginning of this section](#dhcp-relay) -# Drop Counters +## Drop Counters This section explains all the Configurable Drop Counters show commands and configuration options that are supported in SONiC. @@ -2184,8 +2187,240 @@ This comnmand is used to clear drop counters. This is done on a per-user basis. Cleared drop counters ``` -Go Back To [Beginning of the document](#) or [Beginning of this section](#drop-counters) +Go Back To [Beginning of the document](#) or [Beginning of this section](##drop-counters) +## Dynamic Buffer Management + +This section explains all the show and configuration commands regarding the dynamic buffer management. + +Dynamic buffer management is responsible for calculating buffer size according to the ports' configured speed and administrative state. In order to enable dynamic buffer management feature, the ports' speed must be configured. For this please refer [Interface naming mode config commands](#interface-naming-mode-config-commands) + +### Configuration commands + +**configure a lossless buffer profile** + +This command is used to configure a lossless buffer profile. + +- Usage: + + ``` + config buffer_profile add -profile -xon -xoff [-headroom ] [-dynamic_th ] [-pool ] + config buffer_profile remove + ``` + + The parameters `headroom_size`, `dynamic_th` and `pool` are optional. If they aren't provided, the following default values will be taken: + + - headroom size will take the quantity of xon plus xoff + - dynamic_th will take the default value according to platform + - pool will be `ingress_lossless_pool` + +- Example: + + ``` + admin@sonic:~$ sudo config buffer_profile add -profile profile1 -xon 18432 -xoff 18432 + admin@sonic:~$ sudo config buffer_profile remove profile1 + ``` + +**config interface cable_length** + +This command is used to configure the length of the cable connected to a port. The cable_length is in unit of meters and must be suffixed with "m". + +- Usage: + + ``` + config interface cable_length + ``` + +- Example: + + ``` + admin@sonic:~$ sudo config interface cable_length Ethernet0 40m + ``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#dynamic-buffer-management) + +**config interface lossless_pg** + +This command is used to configure the priority groups on which lossless traffic runs. + +- Usage: + + ``` + config interface lossless_pg add + config interface lossless_pg remove [] + ``` + + The can be in one of the following two forms: + + - For a range of priorities, the lower bound and upper bound connected by a dash, like `3-4` + - For a single priority, the number, like `6` + +- Example: + + To configure lossless_pg on a port: + + ``` + admin@sonic:~$ sudo config interface lossless_pg add Ethernet0 3-4 + ``` + + To remove one lossless priority from a port: + + ``` + admin@sonic:~$ sudo config interface lossless_pg remove Ethernet0 6 + ``` + + To remove all lossless priorities from a port: + + ``` + admin@sonic:~$ sudo config interface lossless_pg remove Ethernet0 + ``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#dynamic-buffer-management) + +**config interface headroom_override** + +This command is used to configure a static buffer profile on a port's lossless priorities. There shouldn't be any `lossless_pg` configured on the port when configuring `headroom_override`. The port's headroom won't be updated after `headroom_override` has been configured on the port. + +- Usage: + + ``` + config interface headroom_override add + config interface headroom_override remove [] + ``` + + Hints: + + - The profile must be configured in advance. + - The pg_map has the same format of that in `config interface lossless_pg` command. + +- Example: + + To configure headroom override: + + ``` + admin@sonic:~$ sudo config interface headroom_override add Ethernet0 profile1 3-4 + ``` + + To remove headroom override from a priority of a port: + + ``` + admin@sonic:~$ sudo config interface headroom_override remove Ethernet0 profile1 3-4 + ``` + + To remove headroom override from all priorities of a port: + + ``` + admin@sonic:~$ sudo config interface headroom_override remove Ethernet0 profile1 + ``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#dynamic-buffer-management) + +### Show commands + +**buffershow** + +This command is used to display the status of buffer pools and profiles. + +- Usage: + + ``` + buffershow -l + ``` + +- Example: + + ``` + admin@sonic:~$ buffershow -l + Pool: ingress_lossless_pool + ---- -------- + type ingress + mode dynamic + size 17170432 + ---- -------- + + Pool: egress_lossless_pool + ---- -------- + type egress + mode dynamic + size 34340822 + ---- -------- + + Pool: ingress_lossy_pool + ---- -------- + type ingress + mode dynamic + size 17170432 + ---- -------- + + Pool: egress_lossy_pool + ---- -------- + type egress + mode dynamic + size 17170432 + ---- -------- + + Profile: pg_lossless_100000_5m_profile + ---------- ----------------------------------- + xon 18432 + dynamic_th 0 + xoff 18432 + pool [BUFFER_POOL:ingress_lossless_pool] + size 36864 + ---------- ----------------------------------- + + Profile: q_lossy_profile + ---------- ------------------------------- + dynamic_th 3 + pool [BUFFER_POOL:egress_lossy_pool] + size 0 + ---------- ------------------------------- + + Profile: egress_lossy_profile + ---------- ------------------------------- + dynamic_th 3 + pool [BUFFER_POOL:egress_lossy_pool] + size 4096 + ---------- ------------------------------- + + Profile: egress_lossless_profile + ---------- ---------------------------------- + dynamic_th 7 + pool [BUFFER_POOL:egress_lossless_pool] + size 0 + ---------- ---------------------------------- + + Profile: ingress_lossless_profile + ---------- ----------------------------------- + dynamic_th 0 + pool [BUFFER_POOL:ingress_lossless_pool] + size 0 + ---------- ----------------------------------- + + Profile: pg_lossless_100000_79m_profile + ---------- ----------------------------------- + xon 18432 + dynamic_th 0 + xoff 60416 + pool [BUFFER_POOL:ingress_lossless_pool] + size 78848 + ---------- ----------------------------------- + + Profile: pg_lossless_100000_40m_profile + ---------- ----------------------------------- + xon 18432 + dynamic_th 0 + xoff 38912 + pool [BUFFER_POOL:ingress_lossless_pool] + size 57344 + ---------- ----------------------------------- + + Profile: ingress_lossy_profile + ---------- -------------------------------- + dynamic_th 3 + pool [BUFFER_POOL:ingress_lossy_pool] + size 0 + ---------- -------------------------------- + ``` ## ECN @@ -2399,7 +2634,7 @@ The "errors" subcommand is used to display the interface errors. Ethernet4 U 0 0 0 0 0 0 Ethernet8 U 0 1 0 0 0 0 Ethernet12 U 0 0 0 0 0 0 -``` + ``` The "rates" subcommand is used to disply only the interface rates. @@ -2412,7 +2647,7 @@ The "rates" subcommand is used to disply only the interface rates. Ethernet4 U 469679 N/A N/A N/A 469245 N/A N/A N/A Ethernet8 U 466660 N/A N/A N/A 465982 N/A N/A N/A Ethernet12 U 466579 N/A N/A N/A 466318 N/A N/A N/A -``` + ``` The "rif" subcommand is used to display l3 interface counters. Layer 3 interfaces include router interfaces, portchannels and vlan interfaces. @@ -2913,6 +3148,29 @@ This command is used to configure the mtu for the Physical interface. Use the va Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces) +**config interface cable_length (Versions >= 202006)** + +This command is used to configure the length of the cable connected to a port. The cable_length is in unit of meters and must be suffixed with "m". + +For details please refer [dynamic buffer management](#dynamic-buffer-management) + +Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces) + +**config interface lossless_pg (Versions >= 202006)** + +This command is used to configure the priority groups on which lossless traffic runs. + +For details please refer [dynamic buffer management](#dynamic-buffer-management) + +Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces) + +**config interface headroom_override (Versions >= 202006)** + +This command is used to configure a static buffer profile on a port's lossless priorities. There shouldn't be any `lossless_pg` configured on the port when configuring `headroom_override`. The port's headroom won't be updated after `headroom_override` has been configured on the port. + +For details please refer [dynamic buffer management](#dynamic-buffer-management) + +Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces) ## Interface Naming Mode From 7bdada2106649642153413c6e70799fc5d381315 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Wed, 17 Jun 2020 15:13:09 +0800 Subject: [PATCH 05/13] [db_migrator] Support db_migrator Signed-off-by: Stephen Sun --- scripts/db_migrator.py | 411 ++++++++++++++++++++++++++++++++++------- 1 file changed, 346 insertions(+), 65 deletions(-) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index 4ea89e0bff..f75843200f 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -4,6 +4,7 @@ import sys import argparse import syslog +import re from swsssdk import ConfigDBConnector, SonicDBConfig import sonic_device_util @@ -36,7 +37,7 @@ def __init__(self, namespace, socket=None): none-zero values. build: sequentially increase within a minor version domain. """ - self.CURRENT_VERSION = 'version_1_0_3' + self.CURRENT_VERSION = 'version_1_0_5' self.TABLE_NAME = 'VERSIONS' self.TABLE_KEY = 'DATABASE' @@ -99,50 +100,146 @@ def migrate_interface_table(self): self.configDB.set_entry(table, key[0], data[key]) if_db.append(key[0]) - def mlnx_migrate_buffer_pool_size(self): + def mlnx_default_buffer_parameters(self, db_version, table): + """ + We extract buffer configurations to a common function + so that it can be reused among different migration + """ + mellanox_default_parameter = { + "version_1_0_2": { + "buffer_pool_list" : ['ingress_lossless_pool', 'egress_lossless_pool', 'ingress_lossy_pool', 'egress_lossy_pool'], + "spc1_t0_pool": {"ingress_lossless_pool": { "size": "4194304", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "7340032", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "16777152", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "7340032", "type": "egress", "mode": "dynamic" } }, + "spc1_t1_pool": {"ingress_lossless_pool": { "size": "2097152", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "5242880", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "16777152", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "5242880", "type": "egress", "mode": "dynamic" } }, + "spc2_t0_pool": {"ingress_lossless_pool": { "size": "8224768", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "8224768", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "35966016", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "8224768", "type": "egress", "mode": "dynamic" } }, + "spc2_t1_pool": {"ingress_lossless_pool": { "size": "12042240", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "12042240", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "35966016", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "12042240", "type": "egress", "mode": "dynamic" } } + }, + "version_1_0_3": { + "buffer_pool_list" : ['ingress_lossless_pool', 'egress_lossless_pool', 'ingress_lossy_pool', 'egress_lossy_pool'], + "spc1_t0_pool": {"ingress_lossless_pool": { "size": "5029836", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "5029836", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "5029836", "type": "egress", "mode": "dynamic" } }, + "spc1_t1_pool": {"ingress_lossless_pool": { "size": "2097100", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "2097100", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "2097100", "type": "egress", "mode": "dynamic" } }, + + "spc2_t0_pool": {"ingress_lossless_pool": { "size": "14983147", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "14983147", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340822", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "14983147", "type": "egress", "mode": "dynamic" } }, + "spc2_t1_pool": {"ingress_lossless_pool": { "size": "9158635", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "9158635", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340822", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "9158635", "type": "egress", "mode": "dynamic" } }, + + # 3800 platform has gearbox installed so the buffer pool size is different with other Spectrum2 platform + "spc2_3800_t0_pool": {"ingress_lossless_pool": { "size": "28196784", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "28196784", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "28196784", "type": "egress", "mode": "dynamic" } }, + "spc2_3800_t1_pool": {"ingress_lossless_pool": { "size": "17891280", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "17891280", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "17891280", "type": "egress", "mode": "dynamic" } }, + + # spc3 configurations are for old configuration only + "spc3_t0_pool": {"ingress_lossless_pool": { "size": "56623104", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "56623104", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "60817392", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "56623104", "type": "egress", "mode": "dynamic" } }, + "spc3_t1_pool": {"ingress_lossless_pool": { "size": "36011952", "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "size": "36011952", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "60817392", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "36011952", "type": "egress", "mode": "dynamic" } }, + + "profiles": {"ingress_lossless_profile": {"dynamic_th": "0", "pool": "[BUFFER_POOL|ingress_lossless_pool]", "size": "0"}, + "ingress_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|ingress_lossy_pool]", "size": "0"}, + "egress_lossless_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|egress_lossless_pool]", "size": "0"}, + "egress_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|egress_lossy_pool]", "size": "4096"}, + "q_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|egress_lossy_pool]", "size": "0"}} + }, + "version_1_0_4": { + "buffer_pool_list" : ['ingress_lossless_pool', 'egress_lossless_pool', 'egress_lossy_pool'], + "spc1_t0_pool": {"ingress_lossless_pool": { "size": "10706880", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "10706880", "type": "egress", "mode": "dynamic" } }, + "spc1_t1_pool": {"ingress_lossless_pool": { "size": "5570496", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "5570496", "type": "egress", "mode": "dynamic" } }, + + "spc2_3800_t0_pool": {"ingress_lossless_pool": { "size": "28196784", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "28196784", "type": "egress", "mode": "dynamic" } }, + "spc2_3800_t1_pool": {"ingress_lossless_pool": { "size": "17891280", "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"size": "17891280", "type": "egress", "mode": "dynamic" } }, + + "profiles": {"ingress_lossless_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|ingress_lossless_pool]", "size": "0"}, + "ingress_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|ingress_lossless_pool]", "size": "0"}, + "egress_lossless_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|egress_lossless_pool]", "size": "0"}, + "egress_lossy_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|egress_lossy_pool]", "size": "9216"}, + "q_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|egress_lossy_pool]", "size": "0"}} + }, + "version_1_0_5": { + "buffer_pool_list" : ['ingress_lossless_pool', 'egress_lossless_pool', 'ingress_lossy_pool', 'egress_lossy_pool'], + "spc1_pool": {"ingress_lossless_pool": {"type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"type": "egress", "mode": "dynamic" }}, + "spc2_pool": {"ingress_lossless_pool": {"type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": {"type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340822", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"type": "egress", "mode": "dynamic" } }, + "spc2_3800_pool": {"ingress_lossless_pool": { "type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": { "type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": { "type": "egress", "mode": "dynamic" } }, + "spc3_pool": {"ingress_lossless_pool": {"type": "ingress", "mode": "dynamic" }, + "ingress_lossy_pool": {"type": "ingress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "60817392", "type": "egress", "mode": "dynamic" }, + "egress_lossy_pool": {"type": "egress", "mode": "dynamic" } }, + + "profiles": {"ingress_lossless_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|ingress_lossless_pool]", "size": "0"}, + "ingress_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|ingress_lossy_pool]", "size": "0"}, + "egress_lossless_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|egress_lossless_pool]", "size": "0"}, + "egress_lossy_profile": {"dynamic_th": "7", "pool": "[BUFFER_POOL|egress_lossy_pool]", "size": "9216"}, + "q_lossy_profile": {"dynamic_th": "3", "pool": "[BUFFER_POOL|egress_lossy_pool]", "size": "0"}} + } + } + + if (db_version == "version_1_0_5"): + keysmap = {"spc1_t0_pool": "spc1_pool", "spc1_t1_pool": "spc1_pool", + "spc2_t0_pool": "spc2_pool", "spc2_t1_pool": "spc2_pool", + "spc2_3800_t0_pool": "spc2_3800_pool", "spc2_3800_t1_pool": "spc2_3800_pool", + "spc3_t0_pool": "spc3_pool", "spc3_t1_pool": "spc3_pool"} + if table in keysmap.keys(): + table = keysmap[table] + + if table in mellanox_default_parameter[db_version].keys(): + return mellanox_default_parameter[db_version][table] + else: + return None + + def mlnx_migrate_buffer_pool_size(self, old_version, new_version): """ On Mellanox platform the buffer pool size changed since version with new SDK 4.3.3052, SONiC to SONiC update from version with old SDK will be broken without migration. - This migration is specifically for Mellanox platform. + This migration is specifically for Mellanox platform. """ - # Buffer pools defined in version 1_0_2 - buffer_pools = ['ingress_lossless_pool', 'egress_lossless_pool', 'ingress_lossy_pool', 'egress_lossy_pool'] - - # Old default buffer pool values on Mellanox platform - spc1_t0_default_value = [{'ingress_lossless_pool': '4194304'}, {'egress_lossless_pool': '16777152'}, {'ingress_lossy_pool': '7340032'}, {'egress_lossy_pool': '7340032'}] - spc1_t1_default_value = [{'ingress_lossless_pool': '2097152'}, {'egress_lossless_pool': '16777152'}, {'ingress_lossy_pool': '5242880'}, {'egress_lossy_pool': '5242880'}] - spc2_t0_default_value = [{'ingress_lossless_pool': '8224768'}, {'egress_lossless_pool': '35966016'}, {'ingress_lossy_pool': '8224768'}, {'egress_lossy_pool': '8224768'}] - spc2_t1_default_value = [{'ingress_lossless_pool': '12042240'}, {'egress_lossless_pool': '35966016'}, {'ingress_lossy_pool': '12042240'}, {'egress_lossy_pool': '12042240'}] - - # New default buffer pool configuration on Mellanox platform - spc1_t0_default_config = {"ingress_lossless_pool": { "size": "5029836", "type": "ingress", "mode": "dynamic" }, - "ingress_lossy_pool": { "size": "5029836", "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, - "egress_lossy_pool": {"size": "5029836", "type": "egress", "mode": "dynamic" } } - spc1_t1_default_config = {"ingress_lossless_pool": { "size": "2097100", "type": "ingress", "mode": "dynamic" }, - "ingress_lossy_pool": { "size": "2097100", "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, - "egress_lossy_pool": {"size": "2097100", "type": "egress", "mode": "dynamic" } } - spc2_t0_default_config = {"ingress_lossless_pool": { "size": "14983147", "type": "ingress", "mode": "dynamic" }, - "ingress_lossy_pool": { "size": "14983147", "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "34340822", "type": "egress", "mode": "dynamic" }, - "egress_lossy_pool": {"size": "14983147", "type": "egress", "mode": "dynamic" } } - spc2_t1_default_config = {"ingress_lossless_pool": { "size": "9158635", "type": "ingress", "mode": "dynamic" }, - "ingress_lossy_pool": { "size": "9158635", "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "34340822", "type": "egress", "mode": "dynamic" }, - "egress_lossy_pool": {"size": "9158635", "type": "egress", "mode": "dynamic" } } - # 3800 platform has gearbox installed so the buffer pool size is different with other Spectrum2 platform - spc2_3800_t0_default_config = {"ingress_lossless_pool": { "size": "28196784", "type": "ingress", "mode": "dynamic" }, - "ingress_lossy_pool": { "size": "28196784", "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, - "egress_lossy_pool": {"size": "28196784", "type": "egress", "mode": "dynamic" } } - spc2_3800_t1_default_config = {"ingress_lossless_pool": { "size": "17891280", "type": "ingress", "mode": "dynamic" }, - "ingress_lossy_pool": { "size": "17891280", "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, - "egress_lossy_pool": {"size": "17891280", "type": "egress", "mode": "dynamic" } } - - # Try to get related info from DB buffer_pool_conf = {} device_data = self.configDB.get_table('DEVICE_METADATA') if 'localhost' in device_data.keys(): @@ -151,47 +248,199 @@ def mlnx_migrate_buffer_pool_size(self): else: log_error("Trying to get DEVICE_METADATA from DB but doesn't exist, skip migration") return False + + # SKUs that have single ingress buffer pool + single_ingress_pool_skus = ['Mellanox-SN2700-C28D8', 'Mellanox-SN2700-D48C8', 'Mellanox-SN3800-D112C8'] + if not hwsku in single_ingress_pool_skus: + if new_version == "version_1_0_4": + return True + if old_version == "version_1_0_4": + old_version = "version_1_0_3" + + # Buffer pools defined in old version + old_buffer_pools = self.mlnx_default_buffer_parameters(old_version, "buffer_pool_list") + + # Old default buffer pool values on Mellanox platform + spc1_t0_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc1_t0_pool") + spc1_t1_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc1_t1_pool") + spc2_t0_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc2_t0_pool") + spc2_t1_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc2_t1_pool") + + # New default buffer pool configuration on Mellanox platform + spc1_t0_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc1_t0_pool") + spc1_t1_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc1_t1_pool") + + spc2_t0_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc2_t0_pool") + spc2_t1_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc2_t1_pool") + + # 3800 platform has gearbox installed so the buffer pool size is different with other Spectrum2 platform + spc2_3800_t0_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc2_3800_t0_pool") + spc2_3800_t1_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc2_3800_t1_pool") + + # Try to get related info from DB buffer_pool_conf = self.configDB.get_table('BUFFER_POOL') # Get current buffer pool configuration, only migrate configuration which # with default values, if it's not default, leave it as is. - pool_size_in_db_list = [] + config_of_default_pools_in_db = {} pools_in_db = buffer_pool_conf.keys() # Buffer pool numbers is different with default, don't need migrate - if len(pools_in_db) != len(buffer_pools): + if len(pools_in_db) != len(old_buffer_pools): return True # If some buffer pool is not default ones, don't need migrate - for buffer_pool in buffer_pools: + for buffer_pool in old_buffer_pools: if buffer_pool not in pools_in_db: return True - pool_size_in_db_list.append({buffer_pool: buffer_pool_conf[buffer_pool]['size']}) - + config_of_default_pools_in_db[buffer_pool] = buffer_pool_conf[buffer_pool] + # To check if the buffer pool size is equal to old default values new_buffer_pool_conf = None - if pool_size_in_db_list == spc1_t0_default_value: - new_buffer_pool_conf = spc1_t0_default_config - elif pool_size_in_db_list == spc1_t1_default_value: - new_buffer_pool_conf = spc1_t1_default_config - elif pool_size_in_db_list == spc2_t0_default_value: + if config_of_default_pools_in_db == spc1_t0_old_default_config: + new_buffer_pool_conf = spc1_t0_new_default_config + elif config_of_default_pools_in_db == spc1_t1_old_default_config: + new_buffer_pool_conf = spc1_t1_new_default_config + elif config_of_default_pools_in_db == spc2_t0_old_default_config: if platform == 'x86_64-mlnx_msn3800-r0': - new_buffer_pool_conf = spc2_3800_t0_default_config + new_buffer_pool_conf = spc2_3800_t0_new_default_config else: - new_buffer_pool_conf = spc2_t0_default_config - elif pool_size_in_db_list == spc2_t1_default_value: + new_buffer_pool_conf = spc2_t0_new_default_config + elif config_of_default_pools_in_db == spc2_t1_old_default_config: if platform == 'x86_64-mlnx_msn3800-r0': - new_buffer_pool_conf = spc2_3800_t1_default_config + new_buffer_pool_conf = spc2_3800_t1_new_default_config else: - new_buffer_pool_conf = spc2_t1_default_config + new_buffer_pool_conf = spc2_t1_new_default_config else: - # It's not using default buffer pool configuration, no migration needed. - log_info("buffer pool size is not old default value, no need to migrate") - return True + spc2_3800_t0_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc2_3800_t0_pool") + spc2_3800_t1_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc2_3800_t1_pool") + spc3_t0_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc3_t0_pool") + spc3_t1_old_default_config = self.mlnx_default_buffer_parameters(old_version, "spc3_t1_pool") + spc3_t0_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc3_t0_pool") + spc3_t1_new_default_config = self.mlnx_default_buffer_parameters(new_version, "spc3_t1_pool") + if config_of_default_pools_in_db == spc2_3800_t0_old_default_config: + new_buffer_pool_conf = spc2_3800_t0_new_default_config + elif config_of_default_pools_in_db == spc2_3800_t1_old_default_config: + new_buffer_pool_conf = spc2_3800_t1_new_default_config + elif config_of_default_pools_in_db == spc3_t0_old_default_config: + new_buffer_pool_conf = spc3_t0_new_default_config + elif config_of_default_pools_in_db == spc3_t1_old_default_config: + new_buffer_pool_conf = spc3_t1_new_default_config + else: + # It's not using default buffer pool configuration, no migration needed. + log_info("buffer pool size is not old default value, no need to migrate") + return True + # Migrate old buffer conf to latest. - for pool in buffer_pools: - self.configDB.set_entry('BUFFER_POOL', pool, new_buffer_pool_conf[pool]) - log_info("Successfully migrate mlnx buffer pool size to the latest.") + for pool in old_buffer_pools: + if pool in new_buffer_pool_conf.keys(): + self.configDB.set_entry('BUFFER_POOL', pool, new_buffer_pool_conf[pool]) + else: + self.configDB.set_entry('BUFFER_POOL', pool, None) + log_info("Successfully migrate mlnx buffer pool size to the latest.") + return True + + def mlnx_migrate_buffer_profile(self, single_pool): + """ + This is to migrate BUFFER_PROFILE and BUFFER_PORT_INGRESS_PROFILE_LIST tables + to single ingress pool mode for Mellanox SKU. + """ + device_data = self.configDB.get_table('DEVICE_METADATA') + if 'localhost' in device_data.keys(): + hwsku = device_data['localhost']['hwsku'] + platform = device_data['localhost']['platform'] + else: + log_error("Trying to get DEVICE_METADATA from DB but doesn't exist, skip migration") + return False + + # SKUs that have single ingress buffer pool + single_ingress_pool_skus = ['Mellanox-SN2700-C28D8', 'Mellanox-SN2700-D48C8', 'Mellanox-SN3800-D112C8'] + + if single_pool and not hwsku in single_ingress_pool_skus: + return True + + # old buffer profile configurations + buffer_profile_old_configure = self.mlnx_default_buffer_parameters("version_1_0_3", "profiles") + # old port ingress buffer list configurations + buffer_port_ingress_profile_list_old = "[BUFFER_PROFILE|ingress_lossless_profile],[BUFFER_PROFILE|ingress_lossy_profile]" + + # new buffer profile configurations + if single_pool: + buffer_profile_new_configure = self.mlnx_default_buffer_parameters("version_1_0_4", "profiles") + else: + buffer_profile_new_configure = self.mlnx_default_buffer_parameters("version_1_0_5", "profiles") + # new port ingress buffer list configurations + buffer_port_ingress_profile_list_new = "[BUFFER_PROFILE|ingress_lossless_profile]" + + buffer_profile_conf = self.configDB.get_table('BUFFER_PROFILE') + for name, profile in buffer_profile_old_configure.iteritems(): + if name in buffer_profile_conf.keys() and profile == buffer_profile_old_configure[name]: + continue + # return if any default profile isn't in cofiguration + return True + + for name, profile in buffer_profile_new_configure.iteritems(): + self.configDB.set_entry('BUFFER_PROFILE', name, profile) + + if single_pool: + buffer_port_ingress_profile_list_conf = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST') + for profile_list, profiles in buffer_port_ingress_profile_list_conf.iteritems(): + if profiles['profile_list'] == buffer_port_ingress_profile_list_old: + continue + # return if any port's profile list isn't default + return True + + for name in buffer_port_ingress_profile_list_conf.keys(): + self.configDB.set_entry('BUFFER_PORT_INGRESS_PROFILE_LIST', name, + {'profile_list': buffer_port_ingress_profile_list_new}) + + return True + + def mlnx_migrate_buffer_dynamic_calculation(self): + """ + """ + # Migrate BUFFER_PROFILEs, removing dynamically generated profiles + dynamic_profile = self.configDB.get_table('BUFFER_PROFILE') + profile_pattern = 'pg_lossless_([0-9]*000)_([0-9]*m)_profile' + speed_list = ['1000', '10000', '25000', '40000', '50000', '100000', '200000', '400000'] + cable_len_list = ['5m', '40m', '300m'] + for name, info in dynamic_profile.iteritems(): + m = re.search(profile_pattern, name) + if not m: + continue + speed = m.group(1) + cable_length = m.group(2) + if speed in speed_list and cable_length in cable_len_list: + self.configDB.set_entry('BUFFER_PROFILE', name, None) + + # Migrate BUFFER_PGs, removing the explicit designated profiles + buffer_pgs = self.configDB.get_table('BUFFER_PG') + ports = self.configDB.get_table('PORT') + all_cable_lengths = self.configDB.get_table('CABLE_LENGTH') + cable_lengths = all_cable_lengths[all_cable_lengths.keys()[0]] + for name, profile in buffer_pgs.iteritems(): + port, pg = name + if pg != '3-4': + continue + try: + m = re.search(profile_pattern, profile['profile'][1:-1].split('|')[1]) + except: + continue + if not m: + continue + speed = m.group(1) + cable_length = m.group(2) + try: + if speed == ports[port]["speed"] and cable_length == cable_lengths[port]: + self.configDB.set_entry('BUFFER_PG', name, {'NULL': 'NULL'}) + except: + continue + + # Insert other tables required for dynamic buffer calculation + self.configDB.set_entry('DEFAULT_LOSSLESS_BUFFER_PARAMETER', 'AZURE', {"default_dynamic_th": "0"}) + self.configDB.set_entry('LOSSLESS_TRAFFIC_PATTERN', 'AZURE', { + 'mtu': '1500', 'small_packet_percentage': '100'}) + return True def version_unknown(self): @@ -234,19 +483,51 @@ def version_1_0_2(self): # Check ASIC type, if Mellanox platform then need DB migration version_info = sonic_device_util.get_sonic_version_info() if version_info['asic_type'] == "mellanox": - if self.mlnx_migrate_buffer_pool_size(): + if self.mlnx_migrate_buffer_pool_size('version_1_0_2', 'version_1_0_3'): self.set_version('version_1_0_3') else: self.set_version('version_1_0_3') - return None + return 'version_1_0_3' def version_1_0_3(self): """ - Current latest version. Nothing to do here. + Version 1_0_3. """ log_info('Handling version_1_0_3') - return None + # Check ASIC type, if Mellanox platform then need DB migration + version_info = sonic_device_util.get_sonic_version_info() + if version_info['asic_type'] == "mellanox": + if self.mlnx_migrate_buffer_pool_size('version_1_0_3', 'version_1_0_4') \ + and self.mlnx_migrate_buffer_profile(True): + self.set_version('version_1_0_4') + else: + self.set_version('version_1_0_4') + + return 'version_1_0_4' + + def version_1_0_4(self): + """ + Version 1_0_4 + """ + log_info('Handling version_1_0_4') + + version_info = sonic_device_util.get_sonic_version_info() + if version_info['asic_type'] == "mellanox": + if self.mlnx_migrate_buffer_pool_size('version_1_0_4', 'version_1_0_5') \ + and self.mlnx_migrate_buffer_profile(False) \ + and self.mlnx_migrate_buffer_dynamic_calculation(): + self.set_version('version_1_0_5') + else: + self.set_version('version_1_0_5') + + return 'version_1_0_5' + + def version_1_0_5(self): + """ + Current latest version. Nothing to do here. + """ + log_info('Handling version_1_0_5') def get_version(self): version = self.configDB.get_entry(self.TABLE_NAME, self.TABLE_KEY) From 3f532d1b1fa88b8b75202078ed121af8618609b1 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Fri, 19 Jun 2020 12:31:20 +0000 Subject: [PATCH 06/13] Fix issue: Update PORT_QOS_MAP.pfc_enable when changing lossless pg Signed-off-by: Stephen Sun --- config/main.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/config/main.py b/config/main.py index 0e94440a40..44f4da88eb 100644 --- a/config/main.py +++ b/config/main.py @@ -2193,7 +2193,37 @@ def remove_pg_on_port(ctx, interface_name, pg_map, profile = None): need_to_remove = True if need_to_remove: config_db.set_entry("BUFFER_PG", (interface_name, existing_pg), None) + adjust_pfc_enable(ctx, interface_name, pg_map, False) +def adjust_pfc_enable(ctx, interface_name, pg_map, add): + config_db = ctx.obj["config_db"] + + # Fetch the original pfc_enable + qosmap = config_db.get_entry("PORT_QOS_MAP", interface_name) + pfc_enable = qosmap["pfc_enable"] + + pfc_set = set() + if pfc_enable: + for priority in pfc_enable.split(","): + pfc_set.add(int(priority)) + + lower_bound = int(pg_map[0]) + upper_bound = int(pg_map[-1]) + + for priority in range(lower_bound, upper_bound + 1): + if add: + pfc_set.add(priority) + elif priority in pfc_set: + pfc_set.remove(priority) + + empty_set = set() + pfc_enable = "" + if not pfc_set.issubset(empty_set): + for priority in pfc_set: + pfc_enable += str(priority) + "," + + qosmap["pfc_enable"] = pfc_enable[:-1] + config_db.set_entry("PORT_QOS_MAP", interface_name, qosmap) # # 'headroom_override' subgroup ('config interface headroom_override ...') @@ -2231,6 +2261,7 @@ def add(ctx, interface_name, profile, pg_map): # All checking passed config_db.set_entry("BUFFER_PG", (interface_name, pg_map), {"profile": "[{}]".format(profile_full_name)}) + adjust_pfc_enable(ctx, interface_name, pg_map, True) # # 'remove' command ('config interface headroom_override remove ...') @@ -2277,6 +2308,7 @@ def add(ctx, interface_name, pg_map): # All checking passed config_db.set_entry("BUFFER_PG", (interface_name, pg_map), {"NULL": "NULL"}) + adjust_pfc_enable(ctx, interface_name, pg_map, True) # # 'remove' subcommand From 2b65bb07a957409881a571ed977a88f578620025 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Sun, 21 Jun 2020 11:59:44 +0000 Subject: [PATCH 07/13] Fix issue: adjust_pfc_enable fails when removing all priorities Signed-off-by: Stephen Sun --- config/main.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/config/main.py b/config/main.py index 44f4da88eb..8973fdb6f0 100644 --- a/config/main.py +++ b/config/main.py @@ -2207,20 +2207,26 @@ def adjust_pfc_enable(ctx, interface_name, pg_map, add): for priority in pfc_enable.split(","): pfc_set.add(int(priority)) - lower_bound = int(pg_map[0]) - upper_bound = int(pg_map[-1]) - - for priority in range(lower_bound, upper_bound + 1): - if add: - pfc_set.add(priority) - elif priority in pfc_set: - pfc_set.remove(priority) - - empty_set = set() - pfc_enable = "" - if not pfc_set.issubset(empty_set): - for priority in pfc_set: - pfc_enable += str(priority) + "," + if pg_map: + lower_bound = int(pg_map[0]) + upper_bound = int(pg_map[-1]) + + for priority in range(lower_bound, upper_bound + 1): + if add: + pfc_set.add(priority) + elif priority in pfc_set: + pfc_set.remove(priority) + + empty_set = set() + pfc_enable = "" + if not pfc_set.issubset(empty_set): + for priority in pfc_set: + pfc_enable += str(priority) + "," + elif not add: + # Remove all + pfc_enable = "" + else: + ctx.fail("Try to add empty priorities") qosmap["pfc_enable"] = pfc_enable[:-1] config_db.set_entry("PORT_QOS_MAP", interface_name, qosmap) From 5e2f3fe1635ac05cd3ac97c51d54bdc166120f0c Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Mon, 22 Jun 2020 14:44:38 +0800 Subject: [PATCH 08/13] [db_migrator] Accumulative update 1. Fix issue that db_migrator crashes if CABLE_LENGTH table doesn't exist 2. Don't treat BUFFER_PROFILE entries as default if their dynamic_th aren't 0. Signed-off-by: Stephen Sun --- scripts/db_migrator.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index f75843200f..36d594ee52 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -410,13 +410,21 @@ def mlnx_migrate_buffer_dynamic_calculation(self): continue speed = m.group(1) cable_length = m.group(2) - if speed in speed_list and cable_length in cable_len_list: + if speed in speed_list and cable_length in cable_len_list and info["dynamic_th"] == "0": self.configDB.set_entry('BUFFER_PROFILE', name, None) + # Insert other tables required for dynamic buffer calculation + self.configDB.set_entry('DEFAULT_LOSSLESS_BUFFER_PARAMETER', 'AZURE', {"default_dynamic_th": "0"}) + self.configDB.set_entry('LOSSLESS_TRAFFIC_PATTERN', 'AZURE', { + 'mtu': '1500', 'small_packet_percentage': '100'}) + # Migrate BUFFER_PGs, removing the explicit designated profiles buffer_pgs = self.configDB.get_table('BUFFER_PG') ports = self.configDB.get_table('PORT') all_cable_lengths = self.configDB.get_table('CABLE_LENGTH') + if not buffer_pgs or not ports or not all_cable_lengths: + return True + cable_lengths = all_cable_lengths[all_cable_lengths.keys()[0]] for name, profile in buffer_pgs.iteritems(): port, pg = name @@ -436,11 +444,6 @@ def mlnx_migrate_buffer_dynamic_calculation(self): except: continue - # Insert other tables required for dynamic buffer calculation - self.configDB.set_entry('DEFAULT_LOSSLESS_BUFFER_PARAMETER', 'AZURE', {"default_dynamic_th": "0"}) - self.configDB.set_entry('LOSSLESS_TRAFFIC_PATTERN', 'AZURE', { - 'mtu': '1500', 'small_packet_percentage': '100'}) - return True def version_unknown(self): From 57a99c29085407d2eb47d0d7c707d5f9bb7a03b2 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Wed, 24 Jun 2020 03:10:16 +0000 Subject: [PATCH 09/13] Prepare required tables in APPL_DB and STATE_DB for dynamic headroom including: BUFFER_POOL BUFFER_PROFILE Signed-off-by: Stephen Sun --- scripts/db_migrator.py | 93 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index 36d594ee52..dcd2e27e6e 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -49,9 +49,15 @@ def __init__(self, namespace, socket=None): if namespace is None: self.configDB = ConfigDBConnector(**db_kwargs) + self.applDB = ConfigDBConnector(**db_kwargs) + self.stateDB = ConfigDBConnector(**db_kwargs) else: self.configDB = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **db_kwargs) + self.applDB = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **db_kwargs) + self.stateDB = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **db_kwargs) self.configDB.db_connect('CONFIG_DB') + self.applDB.db_connect('APPL_DB') + self.stateDB.db_connect('STATE_DB') def migrate_pfc_wd_table(self): ''' @@ -249,6 +255,11 @@ def mlnx_migrate_buffer_pool_size(self, old_version, new_version): log_error("Trying to get DEVICE_METADATA from DB but doesn't exist, skip migration") return False + if new_version == "version_1_0_5": + copy_to_appldb = True + else: + copy_to_appldb = False + # SKUs that have single ingress buffer pool single_ingress_pool_skus = ['Mellanox-SN2700-C28D8', 'Mellanox-SN2700-D48C8', 'Mellanox-SN3800-D112C8'] if not hwsku in single_ingress_pool_skus: @@ -280,6 +291,11 @@ def mlnx_migrate_buffer_pool_size(self, old_version, new_version): # Try to get related info from DB buffer_pool_conf = self.configDB.get_table('BUFFER_POOL') + # Copy buffer pools to APPL_DB + if copy_to_appldb: + for name, pool in buffer_pool_conf.iteritems(): + self.applDB.set_entry('BUFFER_POOL', name, pool) + # Get current buffer pool configuration, only migrate configuration which # with default values, if it's not default, leave it as is. config_of_default_pools_in_db = {} @@ -340,10 +356,29 @@ def mlnx_migrate_buffer_pool_size(self, old_version, new_version): log_info("Successfully migrate mlnx buffer pool size to the latest.") return True - def mlnx_migrate_buffer_profile(self, single_pool): + + def mlnx_migrate_buffer_table_to_appl_db(self, entries, table_name, reference_field_name): + """ + tool function: copy tables from config db to appl db + """ + for key, items in entries.iteritems(): + # copy items to appl db + confdb_profile_ref = items[reference_field_name] + items[reference_field_name] = confdb_profile_ref.replace('|', ':') + if type(key) is tuple: + appl_db_key = ':'.join(key) + else: + appl_db_key = key + self.applDB.set_entry(table_name, appl_db_key, items) + + + def mlnx_migrate_buffer_profile(self, single_pool, warmreboot_to_dynamic_headroom): """ - This is to migrate BUFFER_PROFILE and BUFFER_PORT_INGRESS_PROFILE_LIST tables + from v_1_0_2 to v_1_0_3 + to migrate BUFFER_PROFILE and BUFFER_PORT_INGRESS_PROFILE_LIST tables to single ingress pool mode for Mellanox SKU. + from v_1_0_3 to v_1_0_4 + to migrate BUFFER_PROFILE to dynamic calculation mode """ device_data = self.configDB.get_table('DEVICE_METADATA') if 'localhost' in device_data.keys(): @@ -373,14 +408,26 @@ def mlnx_migrate_buffer_profile(self, single_pool): buffer_port_ingress_profile_list_new = "[BUFFER_PROFILE|ingress_lossless_profile]" buffer_profile_conf = self.configDB.get_table('BUFFER_PROFILE') + + copy_to_appl_only = False for name, profile in buffer_profile_old_configure.iteritems(): if name in buffer_profile_conf.keys() and profile == buffer_profile_old_configure[name]: continue # return if any default profile isn't in cofiguration - return True + if warmreboot_to_dynamic_headroom: + copy_to_appl_only = True + else: + return True - for name, profile in buffer_profile_new_configure.iteritems(): - self.configDB.set_entry('BUFFER_PROFILE', name, profile) + if copy_to_appl_only: + # don't migrate buffer profile configuration, just copy them to appl db + self.mlnx_migrate_buffer_table_to_appl_db(buffer_profile_conf, 'BUFFER_PROFILE', 'pool') + return True + else: + for name, profile in buffer_profile_new_configure.iteritems(): + self.configDB.set_entry('BUFFER_PROFILE', name, profile) + buffer_profile_conf = self.configDB.get_table('BUFFER_PROFILE') + self.mlnx_migrate_buffer_table_to_appl_db(buffer_profile_conf, 'BUFFER_PROFILE', 'pool') if single_pool: buffer_port_ingress_profile_list_conf = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST') @@ -396,8 +443,15 @@ def mlnx_migrate_buffer_profile(self, single_pool): return True - def mlnx_migrate_buffer_dynamic_calculation(self): + + def mlnx_migrate_buffer_dynamic_calculation(self, is_warmreboot): """ + Migrate buffer tables to dynamic calculation mode + 1. Remove the profiles generated according to pg_headroom_lookup.ini + unless there alpha isn't the default value (0 for mellanox) + 2. Insert tables required for dynamic buffer calculation + 3. For lossless dynamic PGs, remove the explicit referencing buffer profiles + 4. Copy all other tables to the application db """ # Migrate BUFFER_PROFILEs, removing dynamically generated profiles dynamic_profile = self.configDB.get_table('BUFFER_PROFILE') @@ -427,6 +481,7 @@ def mlnx_migrate_buffer_dynamic_calculation(self): cable_lengths = all_cable_lengths[all_cable_lengths.keys()[0]] for name, profile in buffer_pgs.iteritems(): + # do the db migration port, pg = name if pg != '3-4': continue @@ -444,6 +499,16 @@ def mlnx_migrate_buffer_dynamic_calculation(self): except: continue + # copy BUFFER_QUEUE, BUFFER_PORT_INGRESS_PROFILE_LIST and BUFFER_PORT_EGRESS_PROFILE_LIST to appl db + if is_warmreboot: + self.mlnx_migrate_buffer_table_to_appl_db(buffer_pgs, 'BUFFER_PG', 'profile') + buffer_queues = self.configDB.get_table('BUFFER_QUEUE') + self.mlnx_migrate_buffer_table_to_appl_db(buffer_queues, 'BUFFER_QUEUE', 'profile') + buffer_port_ingress_profile_list = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST') + self.mlnx_migrate_buffer_table_to_appl_db(buffer_port_ingress_profile_list, 'BUFFER_PORT_INGRESS_PROFILE_LIST', 'profile_list') + buffer_port_egress_profile_list = self.configDB.get_table('BUFFER_PORT_EGRESS_PROFILE_LIST') + self.mlnx_migrate_buffer_table_to_appl_db(buffer_port_egress_profile_list, 'BUFFER_PORT_EGRESS_PROFILE_LIST', 'profile_list') + return True def version_unknown(self): @@ -486,6 +551,7 @@ def version_1_0_2(self): # Check ASIC type, if Mellanox platform then need DB migration version_info = sonic_device_util.get_sonic_version_info() if version_info['asic_type'] == "mellanox": + # This is to migrate the buffer size according to the sdk update if self.mlnx_migrate_buffer_pool_size('version_1_0_2', 'version_1_0_3'): self.set_version('version_1_0_3') else: @@ -501,8 +567,9 @@ def version_1_0_3(self): # Check ASIC type, if Mellanox platform then need DB migration version_info = sonic_device_util.get_sonic_version_info() if version_info['asic_type'] == "mellanox": + # This is to migrate the buffer settings to single ingress pool mode if self.mlnx_migrate_buffer_pool_size('version_1_0_3', 'version_1_0_4') \ - and self.mlnx_migrate_buffer_profile(True): + and self.mlnx_migrate_buffer_profile(True, False): self.set_version('version_1_0_4') else: self.set_version('version_1_0_4') @@ -517,9 +584,17 @@ def version_1_0_4(self): version_info = sonic_device_util.get_sonic_version_info() if version_info['asic_type'] == "mellanox": + # This is to migrate to dynamic buffer calculation + warmreboot_state = self.stateDB.get_entry('WARM_RESTART_ENABLE_TABLE', 'system') + if 'enable' in warmreboot_state.keys(): + is_warmreboot = warmreboot_state['enable'] == 'true' + else: + is_warmreboot = False + if is_warmreboot: + self.stateDB.set_entry('WARM_RESTART_TABLE', 'buffermgrd', {'restore_count': '0'}) if self.mlnx_migrate_buffer_pool_size('version_1_0_4', 'version_1_0_5') \ - and self.mlnx_migrate_buffer_profile(False) \ - and self.mlnx_migrate_buffer_dynamic_calculation(): + and self.mlnx_migrate_buffer_profile(False, is_warmreboot) \ + and self.mlnx_migrate_buffer_dynamic_calculation(is_warmreboot): self.set_version('version_1_0_5') else: self.set_version('version_1_0_5') From aab9288f092d35aa8117290cabf4557e308df665 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Wed, 24 Jun 2020 12:48:17 +0000 Subject: [PATCH 10/13] Warm reboot enhancement support copy buffer tables from config db to appl db in old mode Signed-off-by: Stephen Sun --- scripts/db_migrator.py | 51 ++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index dcd2e27e6e..aa3dd8ce1c 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -357,14 +357,15 @@ def mlnx_migrate_buffer_pool_size(self, old_version, new_version): return True - def mlnx_migrate_buffer_table_to_appl_db(self, entries, table_name, reference_field_name): + def migrate_buffer_table_to_appl_db(self, entries, table_name, reference_field_name = None): """ tool function: copy tables from config db to appl db """ for key, items in entries.iteritems(): # copy items to appl db - confdb_profile_ref = items[reference_field_name] - items[reference_field_name] = confdb_profile_ref.replace('|', ':') + if reference_field_name: + confdb_profile_ref = items[reference_field_name] + items[reference_field_name] = confdb_profile_ref.replace('|', ':') if type(key) is tuple: appl_db_key = ':'.join(key) else: @@ -404,6 +405,8 @@ def mlnx_migrate_buffer_profile(self, single_pool, warmreboot_to_dynamic_headroo buffer_profile_new_configure = self.mlnx_default_buffer_parameters("version_1_0_4", "profiles") else: buffer_profile_new_configure = self.mlnx_default_buffer_parameters("version_1_0_5", "profiles") + if hwsku in single_ingress_pool_skus: + buffer_profile_new_configure["ingress_lossy_profile"]["pool"] = "[BUFFER_POOL|ingress_lossless_pool]" # new port ingress buffer list configurations buffer_port_ingress_profile_list_new = "[BUFFER_PROFILE|ingress_lossless_profile]" @@ -421,13 +424,13 @@ def mlnx_migrate_buffer_profile(self, single_pool, warmreboot_to_dynamic_headroo if copy_to_appl_only: # don't migrate buffer profile configuration, just copy them to appl db - self.mlnx_migrate_buffer_table_to_appl_db(buffer_profile_conf, 'BUFFER_PROFILE', 'pool') + self.migrate_buffer_table_to_appl_db(buffer_profile_conf, 'BUFFER_PROFILE', 'pool') return True else: for name, profile in buffer_profile_new_configure.iteritems(): self.configDB.set_entry('BUFFER_PROFILE', name, profile) buffer_profile_conf = self.configDB.get_table('BUFFER_PROFILE') - self.mlnx_migrate_buffer_table_to_appl_db(buffer_profile_conf, 'BUFFER_PROFILE', 'pool') + self.migrate_buffer_table_to_appl_db(buffer_profile_conf, 'BUFFER_PROFILE', 'pool') if single_pool: buffer_port_ingress_profile_list_conf = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST') @@ -501,16 +504,33 @@ def mlnx_migrate_buffer_dynamic_calculation(self, is_warmreboot): # copy BUFFER_QUEUE, BUFFER_PORT_INGRESS_PROFILE_LIST and BUFFER_PORT_EGRESS_PROFILE_LIST to appl db if is_warmreboot: - self.mlnx_migrate_buffer_table_to_appl_db(buffer_pgs, 'BUFFER_PG', 'profile') + self.migrate_buffer_table_to_appl_db(buffer_pgs, 'BUFFER_PG', 'profile') buffer_queues = self.configDB.get_table('BUFFER_QUEUE') - self.mlnx_migrate_buffer_table_to_appl_db(buffer_queues, 'BUFFER_QUEUE', 'profile') + self.migrate_buffer_table_to_appl_db(buffer_queues, 'BUFFER_QUEUE', 'profile') buffer_port_ingress_profile_list = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST') - self.mlnx_migrate_buffer_table_to_appl_db(buffer_port_ingress_profile_list, 'BUFFER_PORT_INGRESS_PROFILE_LIST', 'profile_list') + self.migrate_buffer_table_to_appl_db(buffer_port_ingress_profile_list, 'BUFFER_PORT_INGRESS_PROFILE_LIST', 'profile_list') buffer_port_egress_profile_list = self.configDB.get_table('BUFFER_PORT_EGRESS_PROFILE_LIST') - self.mlnx_migrate_buffer_table_to_appl_db(buffer_port_egress_profile_list, 'BUFFER_PORT_EGRESS_PROFILE_LIST', 'profile_list') + self.migrate_buffer_table_to_appl_db(buffer_port_egress_profile_list, 'BUFFER_PORT_EGRESS_PROFILE_LIST', 'profile_list') return True + + def copy_buffer_table_to_appl_db(self, is_warmreboot): + if is_warmreboot: + buffer_pools = self.configDB.get_table('BUFFER_POOL') + self.migrate_buffer_table_to_appl_db(buffer_pools, 'BUFFER_POOL') + buffer_profiles = self.configDB.get_table('BUFFER_PROFILE') + self.migrate_buffer_table_to_appl_db(buffer_profiles, 'BUFFER_PROFILE', 'pool') + buffer_pgs = self.configDB.get_table('BUFFER_PG') + self.migrate_buffer_table_to_appl_db(buffer_pgs, 'BUFFER_PG', 'profile') + buffer_queues = self.configDB.get_table('BUFFER_QUEUE') + self.migrate_buffer_table_to_appl_db(buffer_queues, 'BUFFER_QUEUE', 'profile') + buffer_port_ingress_profile_list = self.configDB.get_table('BUFFER_PORT_INGRESS_PROFILE_LIST') + self.migrate_buffer_table_to_appl_db(buffer_port_ingress_profile_list, 'BUFFER_PORT_INGRESS_PROFILE_LIST', 'profile_list') + buffer_port_egress_profile_list = self.configDB.get_table('BUFFER_PORT_EGRESS_PROFILE_LIST') + self.migrate_buffer_table_to_appl_db(buffer_port_egress_profile_list, 'BUFFER_PORT_EGRESS_PROFILE_LIST', 'profile_list') + + def version_unknown(self): """ version_unknown tracks all SONiC versions that doesn't have a version @@ -583,13 +603,15 @@ def version_1_0_4(self): log_info('Handling version_1_0_4') version_info = sonic_device_util.get_sonic_version_info() + + warmreboot_state = self.stateDB.get_entry('WARM_RESTART_ENABLE_TABLE', 'system') + if 'enable' in warmreboot_state.keys(): + is_warmreboot = warmreboot_state['enable'] == 'true' + else: + is_warmreboot = False + if version_info['asic_type'] == "mellanox": # This is to migrate to dynamic buffer calculation - warmreboot_state = self.stateDB.get_entry('WARM_RESTART_ENABLE_TABLE', 'system') - if 'enable' in warmreboot_state.keys(): - is_warmreboot = warmreboot_state['enable'] == 'true' - else: - is_warmreboot = False if is_warmreboot: self.stateDB.set_entry('WARM_RESTART_TABLE', 'buffermgrd', {'restore_count': '0'}) if self.mlnx_migrate_buffer_pool_size('version_1_0_4', 'version_1_0_5') \ @@ -597,6 +619,7 @@ def version_1_0_4(self): and self.mlnx_migrate_buffer_dynamic_calculation(is_warmreboot): self.set_version('version_1_0_5') else: + self.copy_buffer_table_to_appl_db(is_warmreboot) self.set_version('version_1_0_5') return 'version_1_0_5' From 5fb0ef3676e1785998b40f43f38742c4cff3527a Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Fri, 26 Jun 2020 01:10:28 +0000 Subject: [PATCH 11/13] Don't clear STATE_DB.BUFFER_MAX_PARAM parameters before warmreboot Signed-off-by: Stephen Sun --- scripts/fast-reboot | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/fast-reboot b/scripts/fast-reboot index d251246776..535210c0ca 100755 --- a/scripts/fast-reboot +++ b/scripts/fast-reboot @@ -239,7 +239,8 @@ function backup_database() for _, k in ipairs(redis.call('keys', '*')) do if not string.match(k, 'FDB_TABLE|') and not string.match(k, 'WARM_RESTART_TABLE|') \ and not string.match(k, 'MIRROR_SESSION_TABLE|') \ - and not string.match(k, 'WARM_RESTART_ENABLE_TABLE|') then + and not string.match(k, 'WARM_RESTART_ENABLE_TABLE|') \ + and not string.match(k, 'BUFFER_MAX_PARAM|') then redis.call('del', k) end end From 2e2cc6e5d6931e77ff1fd59c8a6fbf34120f9400 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Mon, 29 Jun 2020 13:10:28 +0800 Subject: [PATCH 12/13] Correct the egress lossless pool size for SPC1/2 Make the size cell-boundary-aligned Signed-off-by: Stephen Sun --- scripts/db_migrator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index aa3dd8ce1c..7b9fdcde15 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -203,11 +203,11 @@ def mlnx_default_buffer_parameters(self, db_version, table): "buffer_pool_list" : ['ingress_lossless_pool', 'egress_lossless_pool', 'ingress_lossy_pool', 'egress_lossy_pool'], "spc1_pool": {"ingress_lossless_pool": {"type": "ingress", "mode": "dynamic" }, "ingress_lossy_pool": { "type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "14024599", "type": "egress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "14024640", "type": "egress", "mode": "dynamic" }, "egress_lossy_pool": {"type": "egress", "mode": "dynamic" }}, "spc2_pool": {"ingress_lossless_pool": {"type": "ingress", "mode": "dynamic" }, "ingress_lossy_pool": {"type": "ingress", "mode": "dynamic" }, - "egress_lossless_pool": { "size": "34340822", "type": "egress", "mode": "dynamic" }, + "egress_lossless_pool": { "size": "34340832", "type": "egress", "mode": "dynamic" }, "egress_lossy_pool": {"type": "egress", "mode": "dynamic" } }, "spc2_3800_pool": {"ingress_lossless_pool": { "type": "ingress", "mode": "dynamic" }, "ingress_lossy_pool": { "type": "ingress", "mode": "dynamic" }, From c07621741cdfef8b9f70cfb188d741c5e3761a42 Mon Sep 17 00:00:00 2001 From: stephens Date: Wed, 1 Jul 2020 02:17:57 +0000 Subject: [PATCH 13/13] Add log message during db migrating Signed-off-by: stephens --- scripts/db_migrator.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index 7b9fdcde15..843cfa755f 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -241,10 +241,14 @@ def mlnx_default_buffer_parameters(self, db_version, table): def mlnx_migrate_buffer_pool_size(self, old_version, new_version): """ + v1.0.3: On Mellanox platform the buffer pool size changed since version with new SDK 4.3.3052, SONiC to SONiC update from version with old SDK will be broken without migration. This migration is specifically for Mellanox platform. + v1.0.4: + Single ingress buffer is supported, which also affects the + buffer pool settings on some SKUs """ buffer_pool_conf = {} device_data = self.configDB.get_table('DEVICE_METADATA') @@ -361,6 +365,7 @@ def migrate_buffer_table_to_appl_db(self, entries, table_name, reference_field_n """ tool function: copy tables from config db to appl db """ + log_info('Table {} is copied from CONFIG_DB to APPL_DB'.format(table_name)) for key, items in entries.iteritems(): # copy items to appl db if reference_field_name: @@ -417,8 +422,10 @@ def mlnx_migrate_buffer_profile(self, single_pool, warmreboot_to_dynamic_headroo if name in buffer_profile_conf.keys() and profile == buffer_profile_old_configure[name]: continue # return if any default profile isn't in cofiguration + log_info("BUFFER_PROFILE {} doesn't match the default configuration, won't migrate buffer profiles".format(name)) if warmreboot_to_dynamic_headroom: copy_to_appl_only = True + log_info("will copy them to APPL_DB only") else: return True @@ -457,6 +464,8 @@ def mlnx_migrate_buffer_dynamic_calculation(self, is_warmreboot): 4. Copy all other tables to the application db """ # Migrate BUFFER_PROFILEs, removing dynamically generated profiles + log_info('Migrate BUFFER tables for dynamic buffer calculation') + dynamic_profile = self.configDB.get_table('BUFFER_PROFILE') profile_pattern = 'pg_lossless_([0-9]*000)_([0-9]*m)_profile' speed_list = ['1000', '10000', '25000', '40000', '50000', '100000', '200000', '400000'] @@ -469,6 +478,7 @@ def mlnx_migrate_buffer_dynamic_calculation(self, is_warmreboot): cable_length = m.group(2) if speed in speed_list and cable_length in cable_len_list and info["dynamic_th"] == "0": self.configDB.set_entry('BUFFER_PROFILE', name, None) + log_info('BUFFER_PROFILE: Remove dynamic calculated profile {} from database'.format(name)) # Insert other tables required for dynamic buffer calculation self.configDB.set_entry('DEFAULT_LOSSLESS_BUFFER_PARAMETER', 'AZURE', {"default_dynamic_th": "0"}) @@ -480,6 +490,7 @@ def mlnx_migrate_buffer_dynamic_calculation(self, is_warmreboot): ports = self.configDB.get_table('PORT') all_cable_lengths = self.configDB.get_table('CABLE_LENGTH') if not buffer_pgs or not ports or not all_cable_lengths: + log_info('BUFFER_PG or PORT or CABLE_LENGTH is not configured, skip migration for dynamic buffer calculation') return True cable_lengths = all_cable_lengths[all_cable_lengths.keys()[0]] @@ -499,6 +510,7 @@ def mlnx_migrate_buffer_dynamic_calculation(self, is_warmreboot): try: if speed == ports[port]["speed"] and cable_length == cable_lengths[port]: self.configDB.set_entry('BUFFER_PG', name, {'NULL': 'NULL'}) + log_info('BUFFER_PG: Migrate BUFFER_PG|{}'.format(name)) except: continue @@ -614,6 +626,7 @@ def version_1_0_4(self): # This is to migrate to dynamic buffer calculation if is_warmreboot: self.stateDB.set_entry('WARM_RESTART_TABLE', 'buffermgrd', {'restore_count': '0'}) + log_info('Handle warm reboot') if self.mlnx_migrate_buffer_pool_size('version_1_0_4', 'version_1_0_5') \ and self.mlnx_migrate_buffer_profile(False, is_warmreboot) \ and self.mlnx_migrate_buffer_dynamic_calculation(is_warmreboot):