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; } } }
[[ 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(); }
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++); } }
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; }
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); } }
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; } } }