diff --git a/config/main.py b/config/main.py old mode 100755 new mode 100644 index 731043a668..8973fdb6f0 --- a/config/main.py +++ b/config/main.py @@ -2122,6 +2122,240 @@ 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) + 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)) + + 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) + +# +# '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)}) + adjust_pfc_enable(ctx, interface_name, pg_map, True) + +# +# '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"}) + adjust_pfc_enable(ctx, interface_name, pg_map, True) + +# +# '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 +2916,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 ...') # 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 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/db_migrator.py b/scripts/db_migrator.py index 4ea89e0bff..843cfa755f 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' @@ -48,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): ''' @@ -99,50 +106,150 @@ 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": "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": "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" }, + "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): + """ + 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. + 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 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,49 +258,291 @@ 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 + + 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: + 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') + # 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. - 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 migrate_buffer_table_to_appl_db(self, entries, table_name, reference_field_name = None): + """ + 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: + 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): + """ + 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(): + 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") + 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]" + + 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 + 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 + + if copy_to_appl_only: + # don't migrate buffer profile configuration, just copy them to appl db + 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.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') + 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, 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 + 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'] + 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 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"}) + 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: + 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]] + for name, profile in buffer_pgs.iteritems(): + # do the db migration + 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'}) + log_info('BUFFER_PG: Migrate BUFFER_PG|{}'.format(name)) + except: + continue + + # copy BUFFER_QUEUE, BUFFER_PORT_INGRESS_PROFILE_LIST and BUFFER_PORT_EGRESS_PROFILE_LIST to appl db + if is_warmreboot: + 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') + 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 @@ -234,19 +583,65 @@ 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(): + # 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: 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": + # 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, False): + 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() + + 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 + 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): + 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' + + 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) 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 diff --git a/scripts/mmuconfig b/scripts/mmuconfig old mode 100644 new mode 100755 index 2ae7770178..bbf638e923 --- 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,35 +32,61 @@ 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 list(self): - buf_pools = self.db.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)) + def get_table(self, tablename): + if self.config: + return self.db.get_table(tablename) - buf_profs = self.db.get_table(BUFFER_PROFILE_TABLE_NAME) - for prof_name, prof_data in buf_profs.items(): - config = [] + entries = {} + keys = self.db.keys(self.db.STATE_DB, tablename + '*') - 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 not keys: + return None + + 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.get_table(BUFFER_POOL_TABLE_NAME) + 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) + 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: @@ -83,23 +109,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 +145,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',