Пример #1
0
def showPfcAsym(interface):
    """
    PFC handler to display asymmetric PFC information.
    """
    header = ('Interface', 'Asymmetric')

    configdb = ConfigDBConnector()
    configdb.connect()

    if interface:
        db_keys = configdb.keys(configdb.CONFIG_DB, 'PORT|{0}'.format(interface))
    else:
        db_keys = configdb.keys(configdb.CONFIG_DB, 'PORT|*')

    table = []
        
    for i in db_keys or [None]:
        key = None 
        if i:
            key = i.split('|')[-1]

        if key and key.startswith('Ethernet'):
            entry = configdb.get_entry('PORT', key)
            table.append([key, entry.get('pfc_asym', 'N/A')])

    sorted_table = natsorted(table)

    click.echo()
    click.echo(tabulate(sorted_table, headers=header, tablefmt="simple", missingval=""))
    click.echo()
Пример #2
0
def tunnel():
    """Show vxlan tunnel information"""
    config_db = ConfigDBConnector()
    config_db.connect()
    header = [
        'vxlan tunnel name', 'source ip', 'destination ip', 'tunnel map name',
        'tunnel map mapping(vni -> vlan)'
    ]

    # Fetching data from config_db for VXLAN TUNNEL
    vxlan_data = config_db.get_table('VXLAN_TUNNEL')
    vxlan_keys = natsorted(list(vxlan_data.keys()))

    table = []
    for k in vxlan_keys:
        r = []
        r.append(k)
        r.append(vxlan_data[k].get('src_ip'))
        r.append(vxlan_data[k].get('dst_ip'))
        vxlan_map_keys = config_db.keys(
            config_db.CONFIG_DB,
            'VXLAN_TUNNEL_MAP{}{}{}*'.format(config_db.KEY_SEPARATOR, k,
                                             config_db.KEY_SEPARATOR))
        if vxlan_map_keys:
            vxlan_map_mapping = config_db.get_all(config_db.CONFIG_DB,
                                                  vxlan_map_keys[0])
            r.append(vxlan_map_keys[0].split(config_db.KEY_SEPARATOR, 2)[2])
            r.append("{} -> {}".format(vxlan_map_mapping.get('vni'),
                                       vxlan_map_mapping.get('vlan')))
        table.append(r)

    click.echo(tabulate(table, header))
Пример #3
0
def vlanvnimap(count):
    """Show VLAN VNI Mapping Information"""

    header = ['VLAN', 'VNI']
    body = []

    config_db = ConfigDBConnector()
    config_db.connect()

    if count is not None:
        vxlan_keys = config_db.keys('CONFIG_DB', "VXLAN_TUNNEL_MAP|*")

        if not vxlan_keys:
            vxlan_count = 0
        else:
            vxlan_count = len(vxlan_keys)

        output = 'Total count : '
        output += ('%s \n' % (str(vxlan_count)))
        click.echo(output)
    else:
        vxlan_table = config_db.get_table('VXLAN_TUNNEL_MAP')
        vxlan_keys = vxlan_table.keys()
        num = 0
        if vxlan_keys is not None:
            for key in natsorted(vxlan_keys):
                body.append(
                    [vxlan_table[key]['vlan'], vxlan_table[key]['vni']])
                num += 1
        click.echo(tabulate(body, header, tablefmt="grid"))
        output = 'Total count : '
        output += ('%s \n' % (str(num)))
        click.echo(output)
Пример #4
0
def interface():
    """Show VXLAN VTEP Information"""

    config_db = ConfigDBConnector()
    config_db.connect()

    # Fetching VTEP keys from config DB
    click.secho('VTEP Information:\n', bold=True, underline=True)
    vxlan_table = config_db.get_table('VXLAN_TUNNEL')
    vxlan_keys = vxlan_table.keys()
    vtep_sip = '0.0.0.0'
    if vxlan_keys is not None:
        for key in natsorted(vxlan_keys):
            key1 = key.split('|', 1)
            vtepname = key1.pop()
            if 'src_ip' in vxlan_table[key]:
                vtep_sip = vxlan_table[key]['src_ip']
            if vtep_sip is not '0.0.0.0':
                output = '\tVTEP Name : ' + vtepname + ', SIP  : ' + vxlan_table[
                    key]['src_ip']
            else:
                output = '\tVTEP Name : ' + vtepname

            click.echo(output)

    if vtep_sip is not '0.0.0.0':
        vxlan_table = config_db.get_table('VXLAN_EVPN_NVO')
        vxlan_keys = vxlan_table.keys()
        if vxlan_keys is not None:
            for key in natsorted(vxlan_keys):
                key1 = key.split('|', 1)
                vtepname = key1.pop()
                output = '\tNVO Name  : ' + vtepname + ',  VTEP : ' + vxlan_table[
                    key]['source_vtep']
                click.echo(output)

        vxlan_keys = config_db.keys('CONFIG_DB', "LOOPBACK_INTERFACE|*")
        loopback = 'Not Configured'
        if vxlan_keys is not None:
            for key in natsorted(vxlan_keys):
                key1 = key.split('|', 2)
                if len(key1) == 3 and key1[2] == vtep_sip + '/32':
                    loopback = key1[1]
                    break
            output = '\tSource interface  : ' + loopback
            if vtep_sip != '0.0.0.0':
                click.echo(output)
Пример #5
0
class DBMigrator():
    def __init__(self, namespace, socket=None):
        """
        Version string format:
           version_<major>_<minor>_<build>
              major: starting from 1, sequentially incrementing in master
                     branch.
              minor: in github branches, minor version stays in 0. This minor
                     version creates space for private branches derived from
                     github public branches. These private branches shall use
                     none-zero values.
              build: sequentially increase within a minor version domain.
        """
        self.CURRENT_VERSION = 'version_2_0_4'

        self.TABLE_NAME = 'VERSIONS'
        self.TABLE_KEY = 'DATABASE'
        self.TABLE_FIELD = 'VERSION'

        db_kwargs = {}
        if socket:
            db_kwargs['unix_socket_path'] = socket

        if namespace is None:
            self.configDB = ConfigDBConnector(**db_kwargs)
        else:
            self.configDB = ConfigDBConnector(use_unix_socket_path=True,
                                              namespace=namespace,
                                              **db_kwargs)
        self.configDB.db_connect('CONFIG_DB')

        if namespace is None:
            self.appDB = ConfigDBConnector(**db_kwargs)
        else:
            self.appDB = ConfigDBConnector(use_unix_socket_path=True,
                                           namespace=namespace,
                                           **db_kwargs)
        self.appDB.db_connect('APPL_DB')

        self.stateDB = SonicV2Connector(host='127.0.0.1')
        if self.stateDB is not None:
            self.stateDB.connect(self.stateDB.STATE_DB)

        version_info = device_info.get_sonic_version_info()
        asic_type = version_info.get('asic_type')
        self.asic_type = asic_type

        if asic_type == "mellanox":
            from mellanox_buffer_migrator import MellanoxBufferMigrator
            self.mellanox_buffer_migrator = MellanoxBufferMigrator(
                self.configDB, self.appDB, self.stateDB)

    def migrate_pfc_wd_table(self):
        '''
        Migrate all data entries from table PFC_WD_TABLE to PFC_WD
        '''
        data = self.configDB.get_table('PFC_WD_TABLE')
        for key in data:
            self.configDB.set_entry('PFC_WD', key, data[key])
        self.configDB.delete_table('PFC_WD_TABLE')

    def is_ip_prefix_in_key(self, key):
        '''
        Function to check if IP address is present in the key. If it
        is present, then the key would be a tuple or else, it shall be
        be string
        '''
        return (isinstance(key, tuple))

    def migrate_interface_table(self):
        '''
        Migrate all data from existing INTERFACE table with IP Prefix
        to have an additional ONE entry without IP Prefix. For. e.g, for an entry
        "Vlan1000|192.168.0.1/21": {}", this function shall add an entry without
        IP prefix as ""Vlan1000": {}". This is for VRF compatibility.
        '''
        if_db = []
        if_tables = {
            'INTERFACE', 'PORTCHANNEL_INTERFACE', 'VLAN_INTERFACE',
            'LOOPBACK_INTERFACE'
        }
        for table in if_tables:
            data = self.configDB.get_table(table)
            for key in data:
                if not self.is_ip_prefix_in_key(key):
                    if_db.append(key)
                    continue

        for table in if_tables:
            data = self.configDB.get_table(table)
            for key in data:
                if not self.is_ip_prefix_in_key(key) or key[0] in if_db:
                    continue
                log.log_info('Migrating interface table for ' + key[0])
                self.configDB.set_entry(table, key[0], data[key])
                if_db.append(key[0])

    def migrate_intf_table(self):
        '''
        Migrate all data from existing INTF table in APP DB during warmboot with IP Prefix
        to have an additional ONE entry without IP Prefix. For. e.g, for an entry
        "Vlan1000:192.168.0.1/21": {}", this function shall add an entry without
        IP prefix as ""Vlan1000": {}". This also migrates 'lo' to 'Loopback0' interface
        '''
        if self.appDB is None:
            return

        data = self.appDB.keys(self.appDB.APPL_DB, "INTF_TABLE:*")

        if data is None:
            return

        if_db = []
        for key in data:
            if_name = key.split(":")[1]
            if if_name == "lo":
                self.appDB.delete(self.appDB.APPL_DB, key)
                key = key.replace(if_name, "Loopback0")
                log.log_info('Migrating lo entry to ' + key)
                self.appDB.set(self.appDB.APPL_DB, key, 'NULL', 'NULL')

            if '/' not in key:
                if_db.append(key.split(":")[1])
                continue

        data = self.appDB.keys(self.appDB.APPL_DB, "INTF_TABLE:*")
        for key in data:
            if_name = key.split(":")[1]
            if if_name in if_db:
                continue
            log.log_info('Migrating intf table for ' + if_name)
            table = "INTF_TABLE:" + if_name
            self.appDB.set(self.appDB.APPL_DB, table, 'NULL', 'NULL')
            if_db.append(if_name)

    def migrate_copp_table(self):
        '''
        Delete the existing COPP table
        '''
        if self.appDB is None:
            return

        keys = self.appDB.keys(self.appDB.APPL_DB, "COPP_TABLE:*")
        if keys is None:
            return
        for copp_key in keys:
            self.appDB.delete(self.appDB.APPL_DB, copp_key)

    def migrate_feature_table(self):
        '''
        Combine CONTAINER_FEATURE and FEATURE tables into FEATURE table.
        '''
        feature_table = self.configDB.get_table('FEATURE')
        for feature, config in feature_table.items():
            state = config.get('status')
            if state is not None:
                config['state'] = state
                config.pop('status')
                self.configDB.set_entry('FEATURE', feature, config)

        container_feature_table = self.configDB.get_table('CONTAINER_FEATURE')
        for feature, config in container_feature_table.items():
            self.configDB.mod_entry('FEATURE', feature, config)
            self.configDB.set_entry('CONTAINER_FEATURE', feature, None)

    def migrate_config_db_buffer_tables_for_dynamic_calculation(
            self, speed_list, cable_len_list, default_dynamic_th,
            abandon_method, append_item_method):
        '''
        Migrate buffer tables to dynamic calculation mode
        parameters
        @speed_list - list of speed supported
        @cable_len_list - list of cable length supported
        @default_dynamic_th - default dynamic th
        @abandon_method - a function which is called to abandon the migration and keep the current configuration
                          if the current one doesn't match the default one
        @append_item_method - a function which is called to append an item to the list of pending commit items
                              any update to buffer configuration will be pended and won't be applied until
                              all configuration is checked and aligns with the default one

        1. Buffer profiles for lossless PGs in BUFFER_PROFILE table will be removed
           if their names have the convention of pg_lossless_<speed>_<cable_length>_profile
           where the speed and cable_length belongs speed_list and cable_len_list respectively
           and the dynamic_th is equal to default_dynamic_th
        2. Insert tables required for dynamic buffer calculation
           - DEFAULT_LOSSLESS_BUFFER_PARAMETER|AZURE: {'default_dynamic_th': default_dynamic_th}
           - LOSSLESS_TRAFFIC_PATTERN|AZURE: {'mtu': '1024', 'small_packet_percentage': '100'}
        3. For lossless dynamic PGs, remove the explicit referencing buffer profiles
           Before: BUFFER_PG|<port>|3-4: {'profile': 'BUFFER_PROFILE|pg_lossless_<speed>_<cable_length>_profile'}
           After:  BUFFER_PG|<port>|3-4: {'profile': 'NULL'}
        '''
        # Migrate BUFFER_PROFILEs, removing dynamically generated profiles
        dynamic_profile = self.configDB.get_table('BUFFER_PROFILE')
        profile_pattern = 'pg_lossless_([1-9][0-9]*000)_([1-9][0-9]*m)_profile'
        for name, info in dynamic_profile.items():
            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:
                append_item_method(('BUFFER_PROFILE', name, None))
                log.log_info(
                    "Lossless profile {} has been removed".format(name))

        # 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.log_notice(
                "At lease one of tables BUFFER_PG, PORT and CABLE_LENGTH hasn't been defined, skip following migration"
            )
            abandon_method()
            return True

        cable_lengths = all_cable_lengths[list(all_cable_lengths.keys())[0]]
        for name, profile in buffer_pgs.items():
            # do the db migration
            try:
                port, pg = name
                profile_name = profile['profile'][1:-1].split('|')[1]
                if pg == '0':
                    if profile_name != 'ingress_lossy_profile':
                        log.log_notice(
                            "BUFFER_PG table entry {} has non default profile {} configured"
                            .format(name, profile_name))
                        abandon_method()
                        return True
                    else:
                        continue
                elif pg != '3-4':
                    log.log_notice(
                        "BUFFER_PG table entry {} isn't default PG(0 or 3-4)".
                        format(name))
                    abandon_method()
                    return True
                m = re.search(profile_pattern, profile_name)
                if not m:
                    log.log_notice(
                        "BUFFER_PG table entry {} has non-default profile name {}"
                        .format(name, profile_name))
                    abandon_method()
                    return True
                speed = m.group(1)
                cable_length = m.group(2)

                if speed == ports[port][
                        'speed'] and cable_length == cable_lengths[port]:
                    append_item_method(('BUFFER_PG', name, {
                        'profile': 'NULL'
                    }))
                else:
                    log.log_notice(
                        "Lossless PG profile {} for port {} doesn't match its speed {} or cable length {}, keep using traditional buffer calculation mode"
                        .format(profile_name, port, speed, cable_length))
                    abandon_method()
                    return True
            except Exception:
                log.log_notice("Exception occured during parsing the profiles")
                abandon_method()
                return True

        # Insert other tables required for dynamic buffer calculation
        metadata = self.configDB.get_entry('DEVICE_METADATA', 'localhost')
        metadata['buffer_model'] = 'dynamic'
        append_item_method(('DEVICE_METADATA', 'localhost', metadata))
        append_item_method(('DEFAULT_LOSSLESS_BUFFER_PARAMETER', 'AZURE', {
            'default_dynamic_th': default_dynamic_th
        }))
        append_item_method(('LOSSLESS_TRAFFIC_PATTERN', 'AZURE', {
            'mtu': '1024',
            'small_packet_percentage': '100'
        }))

        return True

    def prepare_dynamic_buffer_for_warm_reboot(self,
                                               buffer_pools=None,
                                               buffer_profiles=None,
                                               buffer_pgs=None):
        '''
        This is the very first warm reboot of buffermgrd (dynamic) if the system reboot from old image by warm-reboot
        In this case steps need to be taken to get buffermgrd prepared (for warm reboot)

        During warm reboot, buffer tables should be installed in the first place.
        However, it isn't able to achieve that when system is warm-rebooted from an old image
        without dynamic buffer supported, because the buffer info wasn't in the APPL_DB in the old image.
        The solution is to copy that info from CONFIG_DB into APPL_DB in db_migrator.
        During warm-reboot, db_migrator adjusts buffer info in CONFIG_DB by removing some fields
        according to requirement from dynamic buffer calculation.
        The buffer info before that adjustment needs to be copied to APPL_DB.

        1. set WARM_RESTART_TABLE|buffermgrd as {restore_count: 0}
        2. Copy the following tables from CONFIG_DB into APPL_DB in case of warm reboot
           The separator in fields that reference objects in other table needs to be updated from '|' to ':'
           - BUFFER_POOL
           - BUFFER_PROFILE, separator updated for field 'pool'
           - BUFFER_PG, separator updated for field 'profile'
           - BUFFER_QUEUE, separator updated for field 'profile
           - BUFFER_PORT_INGRESS_PROFILE_LIST, separator updated for field 'profile_list'
           - BUFFER_PORT_EGRESS_PROFILE_LIST, separator updated for field 'profile_list'

        '''
        warmreboot_state = self.stateDB.get(
            self.stateDB.STATE_DB, 'WARM_RESTART_ENABLE_TABLE|system',
            'enable')
        mmu_size = self.stateDB.get(self.stateDB.STATE_DB,
                                    'BUFFER_MAX_PARAM_TABLE|global',
                                    'mmu_size')
        if warmreboot_state == 'true' and not mmu_size:
            log.log_notice(
                "This is the very first run of buffermgrd (dynamic), prepare info required from warm reboot"
            )
        else:
            return True

        buffer_table_list = [
            ('BUFFER_POOL', buffer_pools, None),
            ('BUFFER_PROFILE', buffer_profiles, 'pool'),
            ('BUFFER_PG', buffer_pgs, 'profile'),
            ('BUFFER_QUEUE', None, 'profile'),
            ('BUFFER_PORT_INGRESS_PROFILE_LIST', None, 'profile_list'),
            ('BUFFER_PORT_EGRESS_PROFILE_LIST', None, 'profile_list')
        ]

        for pair in buffer_table_list:
            keys_copied = []
            keys_ignored = []
            table_name, entries, reference_field_name = pair
            app_table_name = table_name + "_TABLE"
            if not entries:
                entries = self.configDB.get_table(table_name)
            for key, items in entries.items():
                # copy items to appl db
                if reference_field_name:
                    confdb_ref = items.get(reference_field_name)
                    if not confdb_ref or confdb_ref == "NULL":
                        keys_ignored.append(key)
                        continue
                    items_referenced = confdb_ref.split(',')
                    appdb_ref = ""
                    first_item = True
                    for item in items_referenced:
                        if first_item:
                            first_item = False
                        else:
                            appdb_ref += ','
                        subitems = item.split('|')
                        first_key = True
                        for subitem in subitems:
                            if first_key:
                                appdb_ref += subitem + '_TABLE'
                                first_key = False
                            else:
                                appdb_ref += ':' + subitem

                    items[reference_field_name] = appdb_ref
                keys_copied.append(key)
                if type(key) is tuple:
                    appl_db_key = app_table_name + ':' + ':'.join(key)
                else:
                    appl_db_key = app_table_name + ':' + key
                for field, data in items.items():
                    self.appDB.set(self.appDB.APPL_DB, appl_db_key, field,
                                   data)

            if keys_copied:
                log.log_info(
                    "The following items in table {} in CONFIG_DB have been copied to APPL_DB: {}"
                    .format(table_name, keys_copied))
            if keys_ignored:
                log.log_info(
                    "The following items in table {} in CONFIG_DB have been ignored: {}"
                    .format(table_name, keys_copied))

        return True

    def migrate_config_db_port_table_for_auto_neg(self):
        table_name = 'PORT'
        port_table = self.configDB.get_table(table_name)
        for key, value in port_table.items():
            if 'autoneg' in value:
                if value['autoneg'] == '1':
                    self.configDB.set(self.configDB.CONFIG_DB,
                                      '{}|{}'.format(table_name,
                                                     key), 'autoneg', 'on')
                    if 'speed' in value and 'adv_speeds' not in value:
                        self.configDB.set(self.configDB.CONFIG_DB,
                                          '{}|{}'.format(table_name, key),
                                          'adv_speeds', value['speed'])
                elif value['autoneg'] == '0':
                    self.configDB.set(self.configDB.CONFIG_DB,
                                      '{}|{}'.format(table_name,
                                                     key), 'autoneg', 'off')

    def migrate_qos_db_fieldval_reference_remove(self, table_list, db, db_num,
                                                 db_delimeter):
        for pair in table_list:
            table_name, fields_list = pair
            qos_table = db.get_table(table_name)
            for key, value in qos_table.items():
                if type(key) is tuple:
                    db_key = table_name + db_delimeter + db_delimeter.join(key)
                else:
                    db_key = table_name + db_delimeter + key

                for field in fields_list:
                    if field in value:
                        fieldVal = value.get(field)
                        if not fieldVal or fieldVal == "NULL":
                            continue
                        newFiledVal = ""
                        # Check for ABNF format presence and convert ABNF to string
                        if "[" in fieldVal and db_delimeter in fieldVal and "]" in fieldVal:
                            log.log_info(
                                "Found ABNF format field value in table {} key {} field {} val {}"
                                .format(table_name, db_key, field, fieldVal))
                            value_list = fieldVal.split(",")
                            for item in value_list:
                                if "[" != item[
                                        0] or db_delimeter not in item or "]" != item[
                                            -1]:
                                    continue
                                newFiledVal = newFiledVal + item[1:-1].split(
                                    db_delimeter)[1] + ','
                            newFiledVal = newFiledVal[:-1]
                            db.set(db_num, db_key, field, newFiledVal)
                            log.log_info(
                                "Modified ABNF format field value to string in table {} key {} field {} val {}"
                                .format(table_name, db_key, field,
                                        newFiledVal))
        return True

    def migrate_qos_fieldval_reference_format(self):
        '''
        This is to change for first time to remove field refernces of ABNF format
        in APPL DB for warm boot.
        i.e "[Tabale_name:name]" to string in APPL_DB. Reasons for doing this
         - To consistent with all other SoNIC CONFIG_DB/APPL_DB tables and fields
         - References in DB is not required, this will be taken care by YANG model leafref.
        '''
        qos_app_table_list = [
            ('BUFFER_PG_TABLE', ['profile']),
            ('BUFFER_QUEUE_TABLE', ['profile']),
            ('BUFFER_PROFILE_TABLE', ['pool']),
            ('BUFFER_PORT_INGRESS_PROFILE_LIST_TABLE', ['profile_list']),
            ('BUFFER_PORT_EGRESS_PROFILE_LIST_TABLE', ['profile_list'])
        ]

        log.log_info("Remove APPL_DB QOS tables field reference ABNF format")
        self.migrate_qos_db_fieldval_reference_remove(qos_app_table_list,
                                                      self.appDB,
                                                      self.appDB.APPL_DB, ':')

        qos_table_list = [
            ('QUEUE', ['scheduler', 'wred_profile']),
            ('PORT_QOS_MAP', [
                'dscp_to_tc_map', 'dot1p_to_tc_map', 'pfc_to_queue_map',
                'tc_to_pg_map', 'tc_to_queue_map', 'pfc_to_pg_map'
            ]), ('BUFFER_PG', ['profile']), ('BUFFER_QUEUE', ['profile']),
            ('BUFFER_PROFILE', ['pool']),
            ('BUFFER_PORT_INGRESS_PROFILE_LIST', ['profile_list']),
            ('BUFFER_PORT_EGRESS_PROFILE_LIST', ['profile_list'])
        ]
        log.log_info("Remove CONFIG_DB QOS tables field reference ABNF format")
        self.migrate_qos_db_fieldval_reference_remove(qos_table_list,
                                                      self.configDB,
                                                      self.configDB.CONFIG_DB,
                                                      '|')
        return True

    def version_unknown(self):
        """
        version_unknown tracks all SONiC versions that doesn't have a version
        string defined in config_DB.
        Nothing can be assumped when migrating from this version to the next
        version.
        Any migration operation needs to test if the DB is in expected format
        before migrating date to the next version.
        """

        log.log_info('Handling version_unknown')

        # NOTE: Uncomment next 3 lines of code when the migration code is in
        #       place. Note that returning specific string is intentional,
        #       here we only intended to migrade to DB version 1.0.1.
        #       If new DB version is added in the future, the incremental
        #       upgrade will take care of the subsequent migrations.
        self.migrate_pfc_wd_table()
        self.migrate_interface_table()
        self.migrate_intf_table()
        self.set_version('version_1_0_2')
        return 'version_1_0_2'

    def version_1_0_1(self):
        """
        Version 1_0_1.
        """
        log.log_info('Handling version_1_0_1')

        self.migrate_interface_table()
        self.migrate_intf_table()
        self.set_version('version_1_0_2')
        return 'version_1_0_2'

    def version_1_0_2(self):
        """
        Version 1_0_2.
        """
        log.log_info('Handling version_1_0_2')
        # Check ASIC type, if Mellanox platform then need DB migration
        if self.asic_type == "mellanox":
            if self.mellanox_buffer_migrator.mlnx_migrate_buffer_pool_size('version_1_0_2', 'version_1_0_3') \
               and self.mellanox_buffer_migrator.mlnx_flush_new_buffer_configuration():
                self.set_version('version_1_0_3')
        else:
            self.set_version('version_1_0_3')
        return 'version_1_0_3'

    def version_1_0_3(self):
        """
        Version 1_0_3.
        """
        log.log_info('Handling version_1_0_3')

        self.migrate_feature_table()

        # Check ASIC type, if Mellanox platform then need DB migration
        if self.asic_type == "mellanox":
            if self.mellanox_buffer_migrator.mlnx_migrate_buffer_pool_size('version_1_0_3', 'version_1_0_4') \
               and self.mellanox_buffer_migrator.mlnx_migrate_buffer_profile('version_1_0_3', 'version_1_0_4') \
               and self.mellanox_buffer_migrator.mlnx_flush_new_buffer_configuration():
                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.log_info('Handling version_1_0_4')

        # Check ASIC type, if Mellanox platform then need DB migration
        if self.asic_type == "mellanox":
            if self.mellanox_buffer_migrator.mlnx_migrate_buffer_pool_size('version_1_0_4', 'version_1_0_5') \
               and self.mellanox_buffer_migrator.mlnx_migrate_buffer_profile('version_1_0_4', 'version_1_0_5') \
               and self.mellanox_buffer_migrator.mlnx_flush_new_buffer_configuration():
                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):
        """
        Version 1_0_5.
        """
        log.log_info('Handling version_1_0_5')

        # Check ASIC type, if Mellanox platform then need DB migration
        if self.asic_type == "mellanox":
            if self.mellanox_buffer_migrator.mlnx_migrate_buffer_pool_size('version_1_0_5', 'version_1_0_6') \
               and self.mellanox_buffer_migrator.mlnx_migrate_buffer_profile('version_1_0_5', 'version_1_0_6') \
               and self.mellanox_buffer_migrator.mlnx_flush_new_buffer_configuration():
                self.set_version('version_1_0_6')
        else:
            self.set_version('version_1_0_6')

        return 'version_1_0_6'

    def version_1_0_6(self):
        """
        Version 1_0_6.
        """
        log.log_info('Handling version_1_0_6')
        if self.asic_type == "mellanox":
            speed_list = self.mellanox_buffer_migrator.default_speed_list
            cable_len_list = self.mellanox_buffer_migrator.default_cable_len_list
            buffer_pools = self.configDB.get_table('BUFFER_POOL')
            buffer_profiles = self.configDB.get_table('BUFFER_PROFILE')
            buffer_pgs = self.configDB.get_table('BUFFER_PG')
            abandon_method = self.mellanox_buffer_migrator.mlnx_abandon_pending_buffer_configuration
            append_method = self.mellanox_buffer_migrator.mlnx_append_item_on_pending_configuration_list

            if self.mellanox_buffer_migrator.mlnx_migrate_buffer_pool_size('version_1_0_6', 'version_2_0_0') \
               and self.mellanox_buffer_migrator.mlnx_migrate_buffer_profile('version_1_0_6', 'version_2_0_0') \
               and (not self.mellanox_buffer_migrator.mlnx_is_buffer_model_dynamic() or \
                    self.migrate_config_db_buffer_tables_for_dynamic_calculation(speed_list, cable_len_list, '0', abandon_method, append_method)) \
               and self.mellanox_buffer_migrator.mlnx_flush_new_buffer_configuration() \
               and self.prepare_dynamic_buffer_for_warm_reboot(buffer_pools, buffer_profiles, buffer_pgs):
                self.set_version('version_2_0_0')
        else:
            self.prepare_dynamic_buffer_for_warm_reboot()

            metadata = self.configDB.get_entry('DEVICE_METADATA', 'localhost')
            metadata['buffer_model'] = 'traditional'
            self.configDB.set_entry('DEVICE_METADATA', 'localhost', metadata)
            log.log_notice('Setting buffer_model to traditional')

            self.set_version('version_2_0_0')

        return 'version_2_0_0'

    def version_2_0_0(self):
        """
        Version 2_0_0.
        """
        log.log_info('Handling version_2_0_0')
        self.migrate_config_db_port_table_for_auto_neg()
        self.set_version('version_2_0_1')
        return 'version_2_0_1'

    def version_2_0_1(self):
        """
        Version 2_0_1.
        """
        log.log_info('Handling version_2_0_1')
        warmreboot_state = self.stateDB.get(
            self.stateDB.STATE_DB, 'WARM_RESTART_ENABLE_TABLE|system',
            'enable')

        if warmreboot_state != 'true':
            portchannel_table = self.configDB.get_table('PORTCHANNEL')
            for name, data in portchannel_table.items():
                data['lacp_key'] = 'auto'
                self.configDB.set_entry('PORTCHANNEL', name, data)
        self.set_version('version_2_0_2')
        return 'version_2_0_2'

    def version_2_0_2(self):
        """
        Version 2_0_2.
        """
        log.log_info('Handling version_2_0_2')
        self.migrate_qos_fieldval_reference_format()
        self.set_version('version_2_0_3')
        return 'version_2_0_3'

    def version_2_0_3(self):
        """
        Version 2_0_3
        """
        log.log_info('Handling version_2_0_3')
        if self.asic_type == "mellanox":
            self.mellanox_buffer_migrator.mlnx_reclaiming_unused_buffer()
        self.set_version('version_2_0_4')
        return 'version_2_0_4'

    def version_2_0_4(self):
        """
        Current latest version. Nothing to do here.
        """
        log.log_info('Handling version_2_0_4')
        return None

    def get_version(self):
        version = self.configDB.get_entry(self.TABLE_NAME, self.TABLE_KEY)
        if version and version[self.TABLE_FIELD]:
            return version[self.TABLE_FIELD]

        return 'version_unknown'

    def set_version(self, version=None):
        if not version:
            version = self.CURRENT_VERSION
        log.log_info('Setting version to ' + version)
        entry = {self.TABLE_FIELD: version}
        self.configDB.set_entry(self.TABLE_NAME, self.TABLE_KEY, entry)

    def common_migration_ops(self):
        try:
            with open(INIT_CFG_FILE) as f:
                init_db = json.load(f)
        except Exception as e:
            raise Exception(str(e))

        for init_cfg_table, table_val in init_db.items():
            log.log_info(
                "Migrating table {} from INIT_CFG to config_db".format(
                    init_cfg_table))
            for key in table_val:
                curr_cfg = self.configDB.get_entry(init_cfg_table, key)
                init_cfg = table_val[key]

                # Override init config with current config.
                # This will leave new fields from init_config
                # in new_config, but not override existing configuration.
                new_cfg = {**init_cfg, **curr_cfg}
                self.configDB.set_entry(init_cfg_table, key, new_cfg)

        self.migrate_copp_table()

    def migrate(self):
        version = self.get_version()
        log.log_info('Upgrading from version ' + version)
        while version:
            next_version = getattr(self, version)()
            if next_version == version:
                raise Exception(
                    'Version migrate from %s stuck in same version' % version)
            version = next_version
        # Perform common migration ops
        self.common_migration_ops()