From cd97c60a2a6dcb112f60ada41894ac195989ae5f Mon Sep 17 00:00:00 2001 From: Kamil Cudnik Date: Mon, 3 Dec 2018 08:44:51 +0100 Subject: [PATCH] Add support for recreate host interfaces tap devices on warm start (#392) --- vslib/inc/sai_vs_state.h | 12 +++ vslib/src/sai_vs_generic_create.cpp | 33 +++++++- vslib/src/sai_vs_generic_get.cpp | 7 ++ vslib/src/sai_vs_generic_remove.cpp | 15 ++++ vslib/src/sai_vs_hostintf.cpp | 120 +++++++++++++++++++++++++--- vslib/src/sai_vs_interfacequery.cpp | 3 + vslib/src/sai_vs_switch.cpp | 2 - 7 files changed, 176 insertions(+), 16 deletions(-) diff --git a/vslib/inc/sai_vs_state.h b/vslib/inc/sai_vs_state.h index e9d95ad82e6e..0e66aa567bfd 100644 --- a/vslib/inc/sai_vs_state.h +++ b/vslib/inc/sai_vs_state.h @@ -135,6 +135,15 @@ typedef struct _fdb_info_t } fdb_info_t; +extern std::string sai_vs_serialize_fdb_info( + _In_ const fdb_info_t& fdb_info); + +extern void sai_vs_deserialize_fdb_info( + _In_ const std::string& data, + _Out_ fdb_info_t& fdb_info); + +#define SAI_VS_FDB_INFO "SAI_VS_FDB_INFO" + extern std::set g_fdb_info_set; class SwitchState @@ -268,6 +277,9 @@ void vs_clear_switch_ids(); void vs_free_real_object_id( _In_ sai_object_id_t switch_id); +sai_status_t vs_recreate_hostif_tap_interfaces( + _In_ sai_object_id_t switch_id); + sai_object_id_t vs_create_real_object_id( _In_ sai_object_type_t object_type, _In_ sai_object_id_t switch_id); diff --git a/vslib/src/sai_vs_generic_create.cpp b/vslib/src/sai_vs_generic_create.cpp index 2c91110f6a76..0070d0a5f63a 100644 --- a/vslib/src/sai_vs_generic_create.cpp +++ b/vslib/src/sai_vs_generic_create.cpp @@ -304,7 +304,28 @@ std::shared_ptr vs_read_switch_database_for_warm_restart( std::string str_attr_id; std::string str_attr_value; - iss >> str_object_type >> str_object_id >> str_attr_id >> str_attr_value; + iss >> str_object_type >> str_object_id; + + if (str_object_type == SAI_VS_FDB_INFO) + { + /* + * If we read line from fdb info set and use tap device is enabled + * just parse line and repopulate fdb info set. + */ + + if (g_vs_hostif_use_tap_device) + { + fdb_info_t fi; + + sai_vs_deserialize_fdb_info(str_object_id, fi); + + g_fdb_info_set.insert(fi); + } + + continue; + } + + iss >> str_attr_id >> str_attr_value; sai_object_meta_key_t meta_key; @@ -362,6 +383,11 @@ std::shared_ptr vs_read_switch_database_for_warm_restart( dumpFile.close(); + if (g_vs_hostif_use_tap_device) + { + SWSS_LOG_NOTICE("loaded %zu fdb infos", g_fdb_info_set.size()); + } + SWSS_LOG_NOTICE("loaded %zu objects from: %s", count, g_warm_boot_read_file); return ss; @@ -580,6 +606,11 @@ sai_status_t internal_vs_generic_create( vs_update_real_object_ids(warmBootState); vs_update_local_metadata(switch_id); + + if (g_vs_hostif_use_tap_device) + { + vs_recreate_hostif_tap_interfaces(switch_id); + } } } diff --git a/vslib/src/sai_vs_generic_get.cpp b/vslib/src/sai_vs_generic_get.cpp index a57d485ed26f..ddfd52f50755 100644 --- a/vslib/src/sai_vs_generic_get.cpp +++ b/vslib/src/sai_vs_generic_get.cpp @@ -41,6 +41,13 @@ sai_status_t internal_vs_generic_get( { SWSS_LOG_ENTER(); + if (g_switch_state_map.find(switch_id) == g_switch_state_map.end()) + { + SWSS_LOG_ERROR("failed to find switch %s in switch state map", sai_serialize_object_id(switch_id).c_str()); + + return SAI_STATUS_FAILURE; + } + auto &objectHash = g_switch_state_map.at(switch_id)->objectHash.at(object_type); auto it = objectHash.find(serialized_object_id); diff --git a/vslib/src/sai_vs_generic_remove.cpp b/vslib/src/sai_vs_generic_remove.cpp index 476454fca528..b42b9cdc6025 100644 --- a/vslib/src/sai_vs_generic_remove.cpp +++ b/vslib/src/sai_vs_generic_remove.cpp @@ -95,6 +95,21 @@ void vs_dump_switch_database_for_warm_restart( } } + if (g_vs_hostif_use_tap_device) + { + /* + * If user is using tap devices we also need to dump local fdb info + * data and restore it on warm start. + */ + + for (auto fi: g_fdb_info_set) + { + dumpFile << SAI_VS_FDB_INFO << " " << sai_vs_serialize_fdb_info(fi) << std::endl; + } + + SWSS_LOG_NOTICE("dumped %zu fdb infos", g_fdb_info_set.size()); + } + dumpFile.close(); SWSS_LOG_NOTICE("dumped %zu objects to %s", count, g_warm_boot_write_file); diff --git a/vslib/src/sai_vs_hostintf.cpp b/vslib/src/sai_vs_hostintf.cpp index 5346aadac188..940877931f22 100644 --- a/vslib/src/sai_vs_hostintf.cpp +++ b/vslib/src/sai_vs_hostintf.cpp @@ -21,6 +21,10 @@ #include #include +#include "swss/json.hpp" + +using json = nlohmann::json; + // TODO on hostif remove we should stop threads typedef struct _hostif_info_t @@ -45,6 +49,43 @@ std::map> hostif_info_map; std::set g_fdb_info_set; +std::string sai_vs_serialize_fdb_info( + _In_ const fdb_info_t& fi) +{ + SWSS_LOG_ENTER(); + + json j; + + j["port_id"] = sai_serialize_object_id(fi.port_id); + j["vlan_id"] = sai_serialize_vlan_id(fi.vlan_id); + j["bridge_port_id"] = sai_serialize_object_id(fi.bridge_port_id); + j["fdb_entry"] = sai_serialize_fdb_entry(fi.fdb_entry); + j["timestamp"] = sai_serialize_number(fi.timestamp); + + SWSS_LOG_INFO("item: %s", j.dump().c_str()); + + return j.dump(); +} + +void sai_vs_deserialize_fdb_info( + _In_ const std::string& data, + _Out_ fdb_info_t& fi) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_INFO("item: %s", data.c_str()); + + const json& j = json::parse(data); + + memset(&fi, 0, sizeof(fi)); + + sai_deserialize_object_id(j["port_id"], fi.port_id); + sai_deserialize_vlan_id(j["vlan_id"], fi.vlan_id); + sai_deserialize_object_id(j["bridge_port_id"], fi.bridge_port_id); + sai_deserialize_fdb_entry(j["fdb_entry"], fi.fdb_entry); + sai_deserialize_number(j["timestamp"], fi.timestamp); +} + void updateLocalDB( _In_ const sai_fdb_event_notification_data_t &data, _In_ sai_fdb_event_t fdb_event) @@ -961,24 +1002,13 @@ bool hostif_create_tap_veth_forwarding( return true; } -sai_status_t vs_create_hostif_int( - _In_ sai_object_type_t object_type, - _Out_ sai_object_id_t *hostif_id, +sai_status_t vs_create_hostif_tap_interface( _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); - if (g_vs_hostif_use_tap_device == false) - { - return vs_generic_create(object_type, - hostif_id, - switch_id, - attr_count, - attr_list); - } - // validate SAI_HOSTIF_ATTR_TYPE auto attr_type = sai_metadata_get_attr_by_id(SAI_HOSTIF_ATTR_TYPE, attr_count, attr_list); @@ -1061,6 +1091,8 @@ sai_status_t vs_create_hostif_int( sai_attribute_t attr; + memset(&attr, 0, sizeof(attr)); + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; sai_status_t status = vs_generic_get(SAI_OBJECT_TYPE_SWITCH, switch_id, 1, &attr); @@ -1105,7 +1137,69 @@ sai_status_t vs_create_hostif_int( SWSS_LOG_INFO("created tap interface %s", name.c_str()); - return vs_generic_create(object_type, + return SAI_STATUS_SUCCESS; +} + +sai_status_t vs_recreate_hostif_tap_interfaces( + _In_ sai_object_id_t switch_id) +{ + SWSS_LOG_ENTER(); + + if (g_vs_hostif_use_tap_device == false) + { + return SAI_STATUS_SUCCESS; + } + + if (g_switch_state_map.find(switch_id) == g_switch_state_map.end()) + { + SWSS_LOG_ERROR("failed to find switch %s in switch state map", sai_serialize_object_id(switch_id).c_str()); + + return SAI_STATUS_FAILURE; + } + + auto &objectHash = g_switch_state_map.at(switch_id)->objectHash.at(SAI_OBJECT_TYPE_HOSTIF); + + SWSS_LOG_NOTICE("attempt to recreate %zu tap devices for host interfaces", objectHash.size()); + + for (auto okvp: objectHash) + { + std::vector attrs; + + for (auto akvp: okvp.second) + { + attrs.push_back(*akvp.second->getAttr()); + } + + vs_create_hostif_tap_interface(switch_id, (uint32_t)attrs.size(), attrs.data()); + } + + return SAI_STATUS_SUCCESS; +} + +sai_status_t vs_create_hostif_int( + _In_ sai_object_type_t object_type, + _Out_ sai_object_id_t *hostif_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + SWSS_LOG_ENTER(); + + if (g_vs_hostif_use_tap_device == true) + { + sai_status_t status = vs_create_hostif_tap_interface( + switch_id, + attr_count, + attr_list); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + } + + return vs_generic_create( + object_type, hostif_id, switch_id, attr_count, diff --git a/vslib/src/sai_vs_interfacequery.cpp b/vslib/src/sai_vs_interfacequery.cpp index f1e3eb9f2f5f..20e33a3f7798 100644 --- a/vslib/src/sai_vs_interfacequery.cpp +++ b/vslib/src/sai_vs_interfacequery.cpp @@ -387,6 +387,8 @@ void processFdbEntriesForAging() return; } + SWSS_LOG_INFO("fdb infos to process: %zu", g_fdb_info_set.size()); + uint32_t current = (uint32_t)time(NULL); // find aged fdb entries @@ -716,6 +718,7 @@ sai_status_t sai_api_initialize( g_fdbAgingThreadRun = true; + // TODO should this be moved to create switch and SwitchState? g_fdbAgingThread = std::make_shared(std::thread(fdbAgingThreadProc)); g_api_initialized = true; diff --git a/vslib/src/sai_vs_switch.cpp b/vslib/src/sai_vs_switch.cpp index 326d73be413c..ae2204e30888 100644 --- a/vslib/src/sai_vs_switch.cpp +++ b/vslib/src/sai_vs_switch.cpp @@ -253,8 +253,6 @@ void vs_create_netlink_message_listener( std::shared_ptr linkThread = std::make_shared(linkmsg_thread, switch_id); - linkThread->detach(); - sw->setLinkThread(linkThread); }