sai_status_t Sai::apiInitialize()

in vslib/Sai.cpp [60:282]


sai_status_t Sai::apiInitialize(
        _In_ uint64_t flags,
        _In_ const sai_service_method_table_t *service_method_table)
{
    MUTEX();

    SWSS_LOG_ENTER();

    if (m_apiInitialized)
    {
        SWSS_LOG_ERROR("%s: api already initialized", __PRETTY_FUNCTION__);

        return SAI_STATUS_FAILURE;
    }

    if (flags != 0)
    {
        SWSS_LOG_ERROR("invalid flags passed to SAI API initialize");

        return SAI_STATUS_INVALID_PARAMETER;
    }

    if ((service_method_table == NULL) ||
            (service_method_table->profile_get_next_value == NULL) ||
            (service_method_table->profile_get_value == NULL))
    {
        SWSS_LOG_ERROR("invalid service_method_table handle passed to SAI API initialize");

        return SAI_STATUS_INVALID_PARAMETER;
    }

    memcpy(&m_service_method_table, service_method_table, sizeof(m_service_method_table));

    auto switch_type = service_method_table->profile_get_value(0, SAI_KEY_VS_SWITCH_TYPE);

    if (switch_type == NULL)
    {
        SWSS_LOG_ERROR("failed to obtain service method table value: %s", SAI_KEY_VS_SWITCH_TYPE);

        return SAI_STATUS_FAILURE;
    }

    auto sai_switch_type = service_method_table->profile_get_value(0, SAI_KEY_VS_SAI_SWITCH_TYPE);
    sai_switch_type_t saiSwitchType;

    if (sai_switch_type == NULL)
    {
        SWSS_LOG_NOTICE("failed to obtain service method table value: %s", SAI_KEY_VS_SAI_SWITCH_TYPE);
        saiSwitchType = SAI_SWITCH_TYPE_NPU;
    }
    else if (!SwitchConfig::parseSaiSwitchType(sai_switch_type, saiSwitchType))
    {
        return SAI_STATUS_FAILURE;
    }

    auto *laneMapFile = service_method_table->profile_get_value(0, SAI_KEY_VS_INTERFACE_LANE_MAP_FILE);

    m_laneMapContainer = LaneMapFileParser::parseLaneMapFile(laneMapFile);

    auto *fabricLaneMapFile = service_method_table->profile_get_value(0, SAI_KEY_VS_INTERFACE_FABRIC_LANE_MAP_FILE);
    if (fabricLaneMapFile)
    {
        m_fabricLaneMapContainer = LaneMapFileParser::parseLaneMapFile(fabricLaneMapFile);
    }

    auto *corePortIndexMapFile = service_method_table->profile_get_value(0, SAI_KEY_VS_CORE_PORT_INDEX_MAP_FILE);

    m_corePortIndexMapContainer = CorePortIndexMapFileParser::parseCorePortIndexMapFile(corePortIndexMapFile);

    auto *resourceLimiterFile = service_method_table->profile_get_value(0, SAI_KEY_VS_RESOURCE_LIMITER_FILE);

    m_resourceLimiterContainer = ResourceLimiterParser::parseFromFile(resourceLimiterFile);

    auto boot_type          = service_method_table->profile_get_value(0, SAI_KEY_BOOT_TYPE);
    m_warm_boot_read_file   = service_method_table->profile_get_value(0, SAI_KEY_WARM_BOOT_READ_FILE);
    m_warm_boot_write_file  = service_method_table->profile_get_value(0, SAI_KEY_WARM_BOOT_WRITE_FILE);

    sai_vs_boot_type_t bootType;

    if (!SwitchConfig::parseBootType(boot_type, bootType))
    {
        return SAI_STATUS_FAILURE;
    }

    sai_vs_switch_type_t switchType;

    if (!SwitchConfig::parseSwitchType(switch_type, switchType))
    {
        return SAI_STATUS_FAILURE;
    }

    const char *use_tap_dev = service_method_table->profile_get_value(0, SAI_KEY_VS_HOSTIF_USE_TAP_DEVICE);

    auto useTapDevice = SwitchConfig::parseBool(use_tap_dev);

    SWSS_LOG_NOTICE("hostif use TAP device: %s", (useTapDevice ? "true" : "false"));

    const char *use_configured_speed_as_oper_speed = service_method_table->profile_get_value(0, SAI_KEY_VS_USE_CONFIGURED_SPEED_AS_OPER_SPEED);

    auto useConfiguredSpeedAsOperSpeed = SwitchConfig::parseBool(use_configured_speed_as_oper_speed);

    SWSS_LOG_NOTICE("use configured speed as oper speed: %s", (useConfiguredSpeedAsOperSpeed ? "true" : "false"));

    auto cstrGlobalContext = service_method_table->profile_get_value(0, SAI_KEY_VS_GLOBAL_CONTEXT);

    m_globalContext = 0;

    if (cstrGlobalContext != nullptr)
    {
        if (sscanf(cstrGlobalContext, "%u", &m_globalContext) != 1)
        {
            SWSS_LOG_WARN("failed to parse '%s' as uint32 using default globalContext", cstrGlobalContext);

            m_globalContext = 0;
        }
    }

    SWSS_LOG_NOTICE("using globalContext = %u", m_globalContext);

    auto cstrContextConfig = service_method_table->profile_get_value(0, SAI_KEY_VS_CONTEXT_CONFIG);

    auto ccc = ContextConfigContainer::loadFromFile(cstrContextConfig);

    for (auto& cc: ccc->getAllContextConfigs())
    {
        auto context = std::make_shared<Context>(cc);

        m_contextMap[cc->m_guid] = context;
    }

    auto context = getContext(m_globalContext);

    if (context == nullptr)
    {
        SWSS_LOG_ERROR("no context defined for global context %u", m_globalContext);

        return SAI_STATUS_FAILURE;
    }

    auto contextConfig = context->getContextConfig();

    auto scc = contextConfig->m_scc;

    if (scc->getSwitchConfigs().size() == 0)
    {
        SWSS_LOG_WARN("no switch configs defined, using default switch config");

        auto sc = std::make_shared<SwitchConfig>(0, "");

        scc->insert(sc);
    }

    // TODO currently switch configuration will share signal and event queue
    // but it should be moved to Context class

    m_signal = std::make_shared<Signal>();

    m_eventQueue = std::make_shared<EventQueue>(m_signal);

    for (auto& sc: scc->getSwitchConfigs())
    {
        // NOTE: switch index and hardware info is already populated

        sc->m_saiSwitchType = saiSwitchType;
        sc->m_switchType = switchType;
        sc->m_bootType = bootType;
        sc->m_useTapDevice = useTapDevice;
        sc->m_useConfiguredSpeedAsOperSpeed = useConfiguredSpeedAsOperSpeed;
        sc->m_laneMap = m_laneMapContainer->getLaneMap(sc->m_switchIndex);

        if (sc->m_laneMap == nullptr)
        {
            SWSS_LOG_WARN("lane map for switch index %u is empty, loading default map (may have ifname conflict)", sc->m_switchIndex);

            sc->m_laneMap = LaneMap::getDefaultLaneMap(sc->m_switchIndex);
        }

        if (m_fabricLaneMapContainer)
        {
            sc->m_fabricLaneMap = m_fabricLaneMapContainer->getLaneMap(sc->m_switchIndex);
        }

        sc->m_eventQueue = m_eventQueue;
        sc->m_resourceLimiter = m_resourceLimiterContainer->getResourceLimiter(sc->m_switchIndex);
        sc->m_corePortIndexMap = m_corePortIndexMapContainer->getCorePortIndexMap(sc->m_switchIndex);
    }

    // most important

    // TODO move to Context class

    m_vsSai = std::make_shared<VirtualSwitchSaiInterface>(contextConfig);

    m_meta = std::make_shared<saimeta::Meta>(m_vsSai);

    m_vsSai->setMeta(m_meta);

    if (bootType == SAI_VS_BOOT_TYPE_WARM)
    {
        if (!m_vsSai->readWarmBootFile(m_warm_boot_read_file))
        {
            SWSS_LOG_WARN("failed to read warm boot read file, switching to COLD BOOT");

            for (auto& sc: scc->getSwitchConfigs())
            {
                sc->m_bootType = SAI_VS_BOOT_TYPE_COLD;
            }
        }
    }

    startEventQueueThread();

    startUnittestThread();

    if (saiSwitchType == SAI_SWITCH_TYPE_NPU)
    {
        startFdbAgingThread();
    }

    m_apiInitialized = true;

    return SAI_STATUS_SUCCESS;
}