void bulk_nhgm_consumer_worker()
{
    std::string tableName = ASIC_STATE_TABLE;
    swss::DBConnector db(ASIC_DB, "localhost", 6379, 0);
    swss::ConsumerTable c(&db, tableName);
    swss::Select cs;
    swss::Selectable *selectcs;
    int tmpfd;
    int ret = 0;

    cs.addSelectable(&c);
    while ((ret = cs.select(&selectcs, &tmpfd)) == swss::Select::OBJECT)
    {
        swss::KeyOpFieldsValuesTuple kco;
        c.pop(kco);

        auto& key = kfvKey(kco);
        auto& op = kfvOp(kco);

        if (starts_with(key, "SAI_OBJECT_TYPE_SWITCH")) continue;

        if (op == "bulkcreate")
        {
            sai_status_t status = processBulkEvent((sai_common_api_t)SAI_COMMON_API_BULK_CREATE, kco);
            ASSERT_SUCCESS("Failed to processBulkEvent");
            break;
        }

    }
}
Beispiel #2
0
[[ noreturn ]] void Logger::settingThread()
{
    Select select;
    DBConnector db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
    std::vector<std::shared_ptr<ConsumerStateTable>> selectables(m_settingChangeObservers.size());

    for (const auto& i : m_settingChangeObservers)
    {
        std::shared_ptr<ConsumerStateTable> table = std::make_shared<ConsumerStateTable>(&db, i.first);
        selectables.push_back(table);
        select.addSelectable(table.get());
    }

    while(true)
    {
        Selectable *selectable = nullptr;

        int ret = select.select(&selectable);

        if (ret == Select::ERROR)
        {
            SWSS_LOG_NOTICE("%s select error %s", __PRETTY_FUNCTION__, strerror(errno));
            continue;
        }

        KeyOpFieldsValuesTuple koValues;
        dynamic_cast<ConsumerStateTable *>(selectable)->pop(koValues);
        std::string key = kfvKey(koValues), op = kfvOp(koValues);

        if ((op != SET_COMMAND) || (m_settingChangeObservers.find(key) == m_settingChangeObservers.end()))
        {
            continue;
        }

        auto values = kfvFieldsValues(koValues);
        for (const auto& i : values)
        {
            const std::string &field = fvField(i), &value = fvValue(i);
            if ((field == DAEMON_LOGLEVEL) && (value != m_currentPrios[key]))
            {
                m_currentPrios[key] = value;
                m_settingChangeObservers[key].first(key, value);
            }
            else if ((field == DAEMON_LOGOUTPUT) && (value != m_currentOutputs[key]))
            {
                m_currentOutputs[key] = value;
                m_settingChangeObservers[key].second(key, value);
            }

            break;
        }
    }
}
void ConsumerStateTable::pop(KeyOpFieldsValuesTuple &kco, std::string prefix)
{
    if (m_buffer.empty())
    {
        pops(m_buffer, prefix);
    }

    if (m_buffer.empty())
    {
        auto& values = kfvFieldsValues(kco);
        values.clear();
        kfvKey(kco).clear();
        kfvOp(kco).clear();
        return;
    }

    kco = m_buffer.front();
    m_buffer.pop_front();
}
Beispiel #4
0
WatermarkOrch::WatermarkOrch(DBConnector *db, const string tableName):
    Orch(db, tableName)
{
    SWSS_LOG_ENTER();

    m_countersDb = make_shared<DBConnector>(COUNTERS_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
    m_appDb = make_shared<DBConnector>(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
    m_countersTable = make_shared<Table>(m_countersDb.get(), COUNTERS_TABLE);
    m_periodicWatermarkTable = make_shared<Table>(m_countersDb.get(), PERIODIC_WATERMARKS_TABLE);
    m_persistentWatermarkTable = make_shared<Table>(m_countersDb.get(), PERSISTENT_WATERMARKS_TABLE);
    m_userWatermarkTable = make_shared<Table>(m_countersDb.get(), USER_WATERMARKS_TABLE);

    m_clearNotificationConsumer = new swss::NotificationConsumer(
            m_appDb.get(),
            "WATERMARK_CLEAR_REQUEST");
    auto clearNotifier = new Notifier(m_clearNotificationConsumer, this, "WM_CLEAR_NOTIFIER");
    Orch::addExecutor(clearNotifier);

    auto intervT = timespec { .tv_sec = DEFAULT_TELEMETRY_INTERVAL , .tv_nsec = 0 };
    m_telemetryTimer = new SelectableTimer(intervT);
    auto executorT = new ExecutableTimer(m_telemetryTimer, this, "WM_TELEMETRY_TIMER");
    Orch::addExecutor(executorT);
    m_telemetryTimer->start();

    m_telemetryInterval = DEFAULT_TELEMETRY_INTERVAL;
}

WatermarkOrch::~WatermarkOrch()
{
    SWSS_LOG_ENTER();
}

void WatermarkOrch::doTask(Consumer &consumer)
{
    SWSS_LOG_ENTER();

    if (!gPortsOrch->isPortReady())
    {
        return;
    }

    auto it = consumer.m_toSync.begin();
    while (it != consumer.m_toSync.end())
    {
        KeyOpFieldsValuesTuple t = it->second;

        string key = kfvKey(t);
        string op = kfvOp(t);
        std::vector<FieldValueTuple> fvt = kfvFieldsValues(t);

        if (op == SET_COMMAND)
        {
            if (key == "TELEMETRY_INTERVAL")
            {
                for (std::pair<std::basic_string<char>, std::basic_string<char> > i: fvt)
                {
                    if (i.first == "interval")
                    {
                        m_telemetryInterval = to_uint<uint32_t>(i.second.c_str());
                    }
                    else
                    {
                        SWSS_LOG_WARN("Unsupported key: %s", i.first.c_str());
                    }
                }
            }
        }
        else if (op == DEL_COMMAND)
        {
            SWSS_LOG_WARN("Unsupported op %s", op.c_str());
        }
        else
        {
            SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str());
        }

        consumer.m_toSync.erase(it++);
    }
}
Beispiel #5
0
sai_status_t processEvent(swss::ConsumerTable &consumer)
{
    std::lock_guard<std::mutex> lock(g_mutex);

    SWSS_LOG_ENTER();

    swss::KeyOpFieldsValuesTuple kco;
    consumer.pop(kco);

    const std::string &key = kfvKey(kco);
    const std::string &op = kfvOp(kco);

    std::string str_object_type = key.substr(0, key.find(":"));
    std::string str_object_id = key.substr(key.find(":")+1);

    SWSS_LOG_INFO("key: %s op: %s", key.c_str(), op.c_str());

    sai_common_api_t api = SAI_COMMON_API_MAX;

    if (op == "create")
        api = SAI_COMMON_API_CREATE;
    else if (op == "remove")
        api = SAI_COMMON_API_REMOVE;
    else if (op == "set")
        api = SAI_COMMON_API_SET;
    else if (op == "get")
        api = SAI_COMMON_API_GET;
    else
    {
        if (op != "delget")
            SWSS_LOG_ERROR("api %s is not implemented", op.c_str());

        return SAI_STATUS_NOT_SUPPORTED;
    }

    std::stringstream ss;

    int index = 0;
    sai_object_type_t object_type;
    sai_deserialize_primitive(str_object_type, index, object_type);

    if (object_type >= SAI_OBJECT_TYPE_MAX)
    {
        SWSS_LOG_ERROR("undefined object type %d", object_type);
        return SAI_STATUS_NOT_SUPPORTED;
    }

    const std::vector<swss::FieldValueTuple> &values = kfvFieldsValues(kco);

    SaiAttributeList list(object_type, values, false);

    if (api != SAI_COMMON_API_GET)
        translate_vid_to_rid_list(object_type, list.get_attr_count(), list.get_attr_list());

    sai_attribute_t *attr_list = list.get_attr_list();
    uint32_t attr_count = list.get_attr_count();

    sai_status_t status;
    switch (object_type)
    {
        case SAI_OBJECT_TYPE_FDB:
            status = handle_fdb(str_object_id, api, attr_count, attr_list);
            break;

        case SAI_OBJECT_TYPE_SWITCH:
            status = handle_switch(str_object_id, api, attr_count, attr_list);
            break;

        case SAI_OBJECT_TYPE_NEIGHBOR:
            status = handle_neighbor(str_object_id, api, attr_count, attr_list);
            break;

        case SAI_OBJECT_TYPE_ROUTE:
            status = handle_route(str_object_id, api, attr_count, attr_list);
            break;

        case SAI_OBJECT_TYPE_VLAN:
            status = handle_vlan(str_object_id, api, attr_count, attr_list);
            break;

        case SAI_OBJECT_TYPE_TRAP:
            status = handle_trap(str_object_id, api, attr_count, attr_list);
            break;

        default:
            status = handle_generic(object_type, str_object_id, api, attr_count, attr_list);
            break;
    }

    if (api == SAI_COMMON_API_GET)
    {
        internal_syncd_get_send(object_type, status, attr_count, attr_list);
    }
    else if (status != SAI_STATUS_SUCCESS)
    {
        SWSS_LOG_ERROR("failed to execute api: %s: %d", op.c_str(), status);

        exit(EXIT_FAILURE);
    }

    return status;
}
sai_status_t internal_redis_generic_get_stats(
        _In_ sai_object_type_t object_type,
        _In_ const std::string &serialized_object_id,
        _In_ const sai_enum_metadata_t *stats_enum,
        _In_ uint32_t count,
        _In_ const int32_t *counter_id_list,
        _Out_ uint64_t *counter_list)
{
    SWSS_LOG_ENTER();

    std::vector<swss::FieldValueTuple> entry = serialize_counter_id_list(
            stats_enum,
            count,
            counter_id_list);

    std::string str_object_type = sai_serialize_object_type(object_type);

    std::string key = str_object_type + ":" + serialized_object_id;

    SWSS_LOG_DEBUG("generic get stats key: %s, fields: %lu", key.c_str(), entry.size());

    if (g_record)
    {
        recordLine("m|" + key + "|" + joinFieldValues(entry));
    }

    // get is special, it will not put data
    // into asic view, only to message queue
    g_asicState->set(key, entry, "get_stats");

    // wait for response

    swss::Select s;

    s.addSelectable(g_redisGetConsumer.get());

    while (true)
    {
        SWSS_LOG_DEBUG("wait for get_stats response");

        swss::Selectable *sel;

        int result = s.select(&sel, GET_RESPONSE_TIMEOUT);

        if (result == swss::Select::OBJECT)
        {
            swss::KeyOpFieldsValuesTuple kco;

            g_redisGetConsumer->pop(kco);

            const std::string &op = kfvOp(kco);
            const std::string &opkey = kfvKey(kco);

            SWSS_LOG_DEBUG("response: op = %s, key = %s", opkey.c_str(), op.c_str());

            if (op != "getresponse") // ignore non response messages
            {
                continue;
            }

            sai_status_t status = internal_redis_get_stats_process(
                    object_type,
                    count,
                    counter_list,
                    kco);

            if (g_record)
            {
                const auto &str_status = kfvKey(kco);
                const auto &values = kfvFieldsValues(kco);

                // first serialized is status
                recordLine("M|" + str_status + "|" + joinFieldValues(values));
            }

            SWSS_LOG_DEBUG("generic get status: %d", status);

            return status;
        }

        SWSS_LOG_ERROR("generic get failed due to SELECT operation result");
        break;
    }

    if (g_record)
    {
        recordLine("M|SAI_STATUS_FAILURE");
    }

    SWSS_LOG_ERROR("generic get stats failed to get response");

    return SAI_STATUS_FAILURE;
}
Beispiel #7
0
void TunnelDecapOrch::doTask(Consumer& consumer)
{
    SWSS_LOG_ENTER();

    if (!gPortsOrch->isInitDone())
    {
        return;
    }

    auto it = consumer.m_toSync.begin();
    while (it != consumer.m_toSync.end())
    {
        KeyOpFieldsValuesTuple t = it->second;

        string key = kfvKey(t);
        string op = kfvOp(t);

        IpAddresses ip_addresses;
        IpAddress src_ip;
        string tunnel_type;
        string dscp_mode;
        string ecn_mode;
        string ttl_mode;
        bool valid = true;

        // checking to see if the tunnel already exists
        bool exists = (tunnelTable.find(key) != tunnelTable.end());

        if (op == SET_COMMAND)
        {

            for (auto i : kfvFieldsValues(t))
            {
                if (fvField(i) == "tunnel_type")
                {
                    tunnel_type = fvValue(i);
                    if (tunnel_type != "IPINIP")
                    {
                        SWSS_LOG_ERROR("Invalid tunnel type %s", tunnel_type.c_str());
                        valid = false;
                        break;
                    }
                }
                else if (fvField(i) == "dst_ip")
                {
                    try
                    {
                        ip_addresses = IpAddresses(fvValue(i));
                    }
                    catch (const std::invalid_argument &e)
                    {
                        SWSS_LOG_ERROR("%s", e.what());
                        valid = false;
                        break;
                    }
                    if (exists)
                    {
                        setIpAttribute(key, ip_addresses, tunnelTable.find(key)->second.tunnel_id);
                    }
                }
                else if (fvField(i) == "src_ip")
                {
                    try
                    {
                        src_ip = IpAddress(fvValue(i));
                    }
                    catch (const std::invalid_argument &e)
                    {
                        SWSS_LOG_ERROR("%s", e.what());
                        valid = false;
                        break;
                    }
                    if (exists)
                    {
                        SWSS_LOG_ERROR("cannot modify src ip for existing tunnel");
                    }
                }
                else if (fvField(i) == "dscp_mode")
                {
                    dscp_mode = fvValue(i);
                    if (dscp_mode != "uniform" && dscp_mode != "pipe")
                    {
                        SWSS_LOG_ERROR("Invalid dscp mode %s\n", dscp_mode.c_str());
                        valid = false;
                        break;
                    }
                    if (exists)
                    {
                        setTunnelAttribute(fvField(i), dscp_mode, tunnelTable.find(key)->second.tunnel_id);
                    }
                }
                else if (fvField(i) == "ecn_mode")
                {
                    ecn_mode = fvValue(i);
                    if (ecn_mode != "copy_from_outer" && ecn_mode != "standard")
                    {
                        SWSS_LOG_ERROR("Invalid ecn mode %s\n", ecn_mode.c_str());
                        valid = false;
                        break;
                    }
                    if (exists)
                    {
                        setTunnelAttribute(fvField(i), ecn_mode, tunnelTable.find(key)->second.tunnel_id);
                    }
                }
                else if (fvField(i) == "ttl_mode")
                {
                    ttl_mode = fvValue(i);
                    if (ttl_mode != "uniform" && ttl_mode != "pipe")
                    {
                        SWSS_LOG_ERROR("Invalid ttl mode %s\n", ttl_mode.c_str());
                        valid = false;
                        break;
                    }
                    if (exists)
                    {
                        setTunnelAttribute(fvField(i), ttl_mode, tunnelTable.find(key)->second.tunnel_id);
                    }
                }
            }

            // create new tunnel if it doesn't exists already
            if (valid && !exists)
            {
                if (addDecapTunnel(key, tunnel_type, ip_addresses, src_ip, dscp_mode, ecn_mode, ttl_mode))
                {
                    SWSS_LOG_NOTICE("Tunnel(s) added to ASIC_DB.");
                }
                else
                {
                    SWSS_LOG_ERROR("Failed to add tunnels to ASIC_DB.");
                }
            }
        }

        if (op == DEL_COMMAND)
        {
            if (exists)
            {
                removeDecapTunnel(key);
            }
            else
            {
                SWSS_LOG_ERROR("Tunnel cannot be removed since it doesn't exist.");
            }
        }

        it = consumer.m_toSync.erase(it);
    }
}
Beispiel #8
0
void IntfsOrch::doTask(Consumer &consumer)
{
    SWSS_LOG_ENTER();

    if (consumer.m_toSync.empty())
        return;

    if (!m_portsOrch->isInitDone())
        return;

    auto it = consumer.m_toSync.begin();
    while (it != consumer.m_toSync.end())
    {
        KeyOpFieldsValuesTuple t = it->second;

        string key = kfvKey(t);
        size_t found = key.find(':');
        if (found == string::npos)
        {
            SWSS_LOG_ERROR("Failed to parse task key %s\n", key.c_str());
            it = consumer.m_toSync.erase(it);
            continue;
        }
        string alias = key.substr(0, found);

        IpPrefix ip_prefix(key.substr(found+1));
        if (!ip_prefix.isV4())
        {
            it = consumer.m_toSync.erase(it);
            continue;
        }

        string op = kfvOp(t);

        if (op == SET_COMMAND)
        {
            /* Duplicate entry */
            if (m_intfs.find(alias) != m_intfs.end() && m_intfs[alias] == ip_prefix.getIp())
            {
                it = consumer.m_toSync.erase(it);
                continue;
            }

            Port p;
            if (!m_portsOrch->getPort(alias, p))
            {
                SWSS_LOG_ERROR("Failed to locate interface %s\n", alias.c_str());
                it = consumer.m_toSync.erase(it);
                continue;
            }

            sai_unicast_route_entry_t unicast_route_entry;
            unicast_route_entry.vr_id = gVirtualRouterId;
            unicast_route_entry.destination.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
            unicast_route_entry.destination.addr.ip4 = ip_prefix.getIp().getV4Addr() & ip_prefix.getMask().getV4Addr();
            unicast_route_entry.destination.mask.ip4 = ip_prefix.getMask().getV4Addr();

            sai_attribute_t attr;
            vector<sai_attribute_t> attrs;

            attr.id = SAI_ROUTE_ATTR_PACKET_ACTION;
            attr.value.s32 = SAI_PACKET_ACTION_FORWARD;
            attrs.push_back(attr);

            attr.id = SAI_ROUTE_ATTR_NEXT_HOP_ID;
            attr.value.oid = p.m_rif_id;
            attrs.push_back(attr);

            sai_status_t status = sai_route_api->create_route(&unicast_route_entry, attrs.size(), attrs.data());
            if (status != SAI_STATUS_SUCCESS)
            {
                SWSS_LOG_ERROR("Failed to create subnet route pre:%s %d\n", ip_prefix.to_string().c_str(), status);
                it++;
                continue;
            }
            else
            {
                SWSS_LOG_NOTICE("Create subnet route pre:%s\n", ip_prefix.to_string().c_str());
            }

            unicast_route_entry.vr_id = gVirtualRouterId;
            unicast_route_entry.destination.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
            unicast_route_entry.destination.addr.ip4 = ip_prefix.getIp().getV4Addr();
            unicast_route_entry.destination.mask.ip4 = 0xFFFFFFFF;

            attr.id = SAI_ROUTE_ATTR_PACKET_ACTION;
            attr.value.s32 = SAI_PACKET_ACTION_TRAP;
            status = sai_route_api->create_route(&unicast_route_entry, 1, &attr);
            if (status != SAI_STATUS_SUCCESS)
            {
                SWSS_LOG_ERROR("Failed to create packet action trap route ip:%s %d\n", ip_prefix.getIp().to_string().c_str(), status);
                it++;
            }
            else
            {
                SWSS_LOG_NOTICE("Create packet action trap route ip:%s\n", ip_prefix.getIp().to_string().c_str());
                m_intfs[alias] = ip_prefix.getIp();
                it = consumer.m_toSync.erase(it);
            }
        }
        else if (op == DEL_COMMAND)
        {
            Port p;
            if (!m_portsOrch->getPort(alias, p))
            {
                SWSS_LOG_ERROR("Failed to locate interface %s\n", alias.c_str());
                it = consumer.m_toSync.erase(it);
                continue;
            }

            sai_unicast_route_entry_t unicast_route_entry;
            unicast_route_entry.vr_id = gVirtualRouterId;
            unicast_route_entry.destination.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
            unicast_route_entry.destination.addr.ip4 = ip_prefix.getIp().getV4Addr() & ip_prefix.getMask().getV4Addr();
            unicast_route_entry.destination.mask.ip4 = ip_prefix.getMask().getV4Addr();

            sai_status_t status = sai_route_api->remove_route(&unicast_route_entry);
            if (status != SAI_STATUS_SUCCESS)
            {
                SWSS_LOG_ERROR("Failed to remove subnet route pre:%s %d\n", ip_prefix.to_string().c_str(), status);
                it++;
                continue;
            }

            unicast_route_entry.vr_id = gVirtualRouterId;
            unicast_route_entry.destination.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
            unicast_route_entry.destination.addr.ip4 = ip_prefix.getIp().getV4Addr();
            unicast_route_entry.destination.mask.ip4 = 0xFFFFFFFF;

            status = sai_route_api->remove_route(&unicast_route_entry);
            if (status != SAI_STATUS_SUCCESS)
            {
                SWSS_LOG_ERROR("Failed to remove action trap route ip:%s %d\n", ip_prefix.getIp().to_string().c_str(), status);
                it++;
            }
            else
            {
                SWSS_LOG_NOTICE("Remove packet action trap route ip:%s\n", ip_prefix.getIp().to_string().c_str());
                m_intfs.erase(alias);
                it = consumer.m_toSync.erase(it);
            }
        }
    }
}
void ConsumerStateTable::pops(std::deque<KeyOpFieldsValuesTuple> &vkco, std::string /*prefix*/)
{
    static std::string luaScript =
        "local ret = {}\n"
        "local keys = redis.call('SPOP', KEYS[1], ARGV[1])\n"
        "local n = table.getn(keys)\n"
        "for i = 1, n do\n"
            "local key = keys[i]\n"
            "local values = redis.call('HGETALL', KEYS[2] .. key)\n"
            "table.insert(ret, {key, values})\n"
        "end\n"
        "return ret\n";

    static std::string sha = loadRedisScript(m_db, luaScript);

    RedisCommand command;
    command.format(
        "EVALSHA %s 2 %s %s: %d ''",
        sha.c_str(),
        getKeySetName().c_str(),
        getTableName().c_str(),
        POP_BATCH_SIZE);

    RedisReply r(m_db, command);
    auto ctx0 = r.getContext();
    vkco.clear();

    // if the set is empty, return an empty kco object
    if (ctx0->type == REDIS_REPLY_NIL)
    {
        return;
    }

    assert(ctx0->type == REDIS_REPLY_ARRAY);
    size_t n = ctx0->elements;
    vkco.resize(n);
    for (size_t ie = 0; ie < n; ie++)
    {
        auto& kco = vkco[ie];
        auto& values = kfvFieldsValues(kco);
        assert(values.empty());

        auto& ctx = ctx0->element[ie];
        assert(ctx->elements == 2);
        assert(ctx->element[0]->type == REDIS_REPLY_STRING);
        std::string key = ctx->element[0]->str;
        kfvKey(kco) = key;

        assert(ctx->element[1]->type == REDIS_REPLY_ARRAY);
        auto ctx1 = ctx->element[1];
        for (size_t i = 0; i < ctx1->elements / 2; i++)
        {
            FieldValueTuple e;
            fvField(e) = ctx1->element[i * 2]->str;
            fvValue(e) = ctx1->element[i * 2 + 1]->str;
            values.push_back(e);
        }

        // if there is no field-value pair, the key is already deleted
        if (values.empty())
        {
            kfvOp(kco) = DEL_COMMAND;
        }
        else
        {
            kfvOp(kco) = SET_COMMAND;
        }
    }
}