diff --git a/fdbsyncd/Makefile.am b/fdbsyncd/Makefile.am index 0ad7d67df4df..06beefaf2206 100644 --- a/fdbsyncd/Makefile.am +++ b/fdbsyncd/Makefile.am @@ -1,16 +1,16 @@ -INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/warmrestart - -bin_PROGRAMS = fdbsyncd - -if DEBUG -DBGFLAGS = -ggdb -DDEBUG -else -DBGFLAGS = -g -endif - -fdbsyncd_SOURCES = fdbsyncd.cpp fdbsync.cpp $(top_srcdir)/warmrestart/warmRestartAssist.cpp - -fdbsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) -fdbsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) -fdbsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) - +INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/warmrestart + +bin_PROGRAMS = fdbsyncd + +if DEBUG +DBGFLAGS = -ggdb -DDEBUG +else +DBGFLAGS = -g +endif + +fdbsyncd_SOURCES = fdbsyncd.cpp fdbsync.cpp $(top_srcdir)/warmrestart/warmRestartAssist.cpp + +fdbsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) +fdbsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) +fdbsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) + diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 30c9e2d54cd6..5a5caf5a8992 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -1,721 +1,721 @@ -#include -#include -#include -#include -#include -#include - -#include "logger.h" -#include "dbconnector.h" -#include "producerstatetable.h" -#include "ipaddress.h" -#include "netmsg.h" -#include "macaddress.h" -#include "exec.h" -#include "fdbsync.h" -#include "warm_restart.h" -#include "errno.h" - -using namespace std; -using namespace swss; - -#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" - -FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : - m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), - m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), - m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), - m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) -{ - m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); - if (m_AppRestartAssist) - { - m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); - m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); - } -} - -FdbSync::~FdbSync() -{ - if (m_AppRestartAssist) - { - delete m_AppRestartAssist; - } -} - - -// Check if interface entries are restored in kernel -bool FdbSync::isIntfRestoreDone() -{ - vector required_modules = { - "vxlanmgrd", - "intfmgrd", - "vlanmgrd", - "vrfmgrd" - }; - - for (string& module : required_modules) - { - WarmStart::WarmStartState state; - - WarmStart::getWarmStartState(module, state); - if (state == WarmStart::REPLAYED || state == WarmStart::RECONCILED) - { - SWSS_LOG_INFO("Module %s Replayed or Reconciled %d",module.c_str(), (int) state); - } - else - { - SWSS_LOG_INFO("Module %s NOT Replayed or Reconciled %d",module.c_str(), (int) state); - return false; - } - } - - return true; -} - -void FdbSync::processCfgEvpnNvo() -{ - std::deque entries; - m_cfgEvpnNvoTable.pops(entries); - bool lastNvoState = m_isEvpnNvoExist; - - for (auto entry: entries) - { - std::string op = kfvOp(entry); - - if (op == SET_COMMAND) - { - m_isEvpnNvoExist = true; - } - else if (op == DEL_COMMAND) - { - m_isEvpnNvoExist = false; - } - - if (lastNvoState != m_isEvpnNvoExist) - { - updateAllLocalMac(); - } - } - return; -} - -void FdbSync::updateAllLocalMac() -{ - for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) - { - if (m_isEvpnNvoExist) - { - /* Add the Local FDB entry into Kernel */ - addLocalMac(it->first, "replace"); - } - else - { - /* Delete the Local FDB entry from Kernel */ - addLocalMac(it->first, "del"); - } - } -} - -void FdbSync::processStateFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_fdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - info.mac = mac_address; - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - info.port_name = fvValue(i); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateLocalMac(&info); - } -} - -void FdbSync::macUpdateCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_fdb_mac[key].port_name = info->port_name; - m_fdb_mac[key].type = info->type; - - return; -} - -bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - if (m_fdb_mac.find(key) != m_fdb_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); - return true; - } - - return false; -} - -void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) -{ - std::string vtep = m_mac[auxkey].vtep; - - const std::string cmds = std::string("") - + " bridge fdb del " + info->mac + " dev " - + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::updateLocalMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ - if (m_mac.find(key) != m_mac.end()) - { - macDelVxlanEntry(key, info); - SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); - macDelVxlan(key); - } - } - else - { - op = "del"; - port_name = m_fdb_mac[key].port_name; - fdb_type = m_fdb_mac[key].type; - m_fdb_mac.erase(key); - } - - if (!m_isEvpnNvoExist) - { - SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); - return; - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::addLocalMac(string key, string op) -{ - char *type; - string port_name = ""; - string mac = ""; - string vlan = ""; - size_t str_loc = string::npos; - - str_loc = key.find(":"); - if (str_loc == string::npos) - { - SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); - return; - } - vlan = key.substr(4, str_loc-4); - mac = key.substr(str_loc+1, std::string::npos); - - SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + mac + " dev " - + port_name + " master " + type + " vlan " + vlan; - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -/* - * This is a special case handling where mac is learned in the ASIC. - * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel - * This MAC will age out, when MAC delete is received from the Kernel. - * If MAC is still present in the state DB cache then fdbsyncd will be - * re-programmed with MAC in the Kernel - */ -void FdbSync::macRefreshStateDB(int vlan, string kmac) -{ - string key = "Vlan" + to_string(vlan) + ":" + kmac; - char *type; - string port_name = ""; - - SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + "replace" + " " + kmac + " dev " - + port_name + " master " + type + " vlan " + to_string(vlan); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -bool FdbSync::checkImetExist(string key, uint32_t vni) -{ - if (m_imet_route.find(key) != m_imet_route.end()) - { - SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); - return false; - } - m_imet_route[key].vni = vni; - return true; -} - -bool FdbSync::checkDelImet(string key, uint32_t vni) -{ - int ret = false; - - SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); - if (m_imet_route.find(key) != m_imet_route.end()) - { - ret = true; - m_imet_route.erase(key); - } - return ret; -} - -void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkImetExist(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); - return; - } - - m_imetTable.set(key, fvVector); - return; -} - -void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkDelImet(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); - return; - } - - m_imetTable.del(key); - return; -} - -void FdbSync::macDelVxlanDB(string key) -{ - string vtep = m_mac[key].vtep; - string type; - string vni = to_string(m_mac[key].vni); - type = m_mac[key].type; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", vtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", vni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - SWSS_LOG_NOTICE("%sVXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "" , - key.c_str(), vtep.c_str(), type.c_str()); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); - return; - } - - m_fdbTable.del(key); - return; - -} - -void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) -{ - string svtep = inet_ntoa(vtep); - string svni = to_string(vni); - - /* Update the DB with Vxlan MAC */ - m_mac[key] = {svtep, type, vni, intf_name}; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", svtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", svni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - SWSS_LOG_INFO("%sVXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "" , - key.c_str(), svtep.c_str(), type.c_str()); - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); - return; - } - - m_fdbTable.set(key, fvVector); - - return; -} - -void FdbSync::macDelVxlan(string key) -{ - if (m_mac.find(key) != m_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); - macDelVxlanDB(key); - m_mac.erase(key); - } - return; -} - -void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) -{ - char macStr[MAX_ADDR_SIZE + 1] = {0}; - struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; - struct in_addr vtep = {0}; - int vlan = 0, ifindex = 0; - uint32_t vni = 0; - nl_addr *vtep_addr; - string ifname; - string key; - bool delete_key = false; - size_t str_loc = string::npos; - string type = ""; - string vlan_id = ""; - bool isVxlanIntf = false; - - if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && - (nlmsg_type != RTM_DELNEIGH)) - { - return; - } - - /* Only MAC route is to be supported */ - if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) - { - return; - } - ifindex = rtnl_neigh_get_ifindex(neigh); - if (m_intf_info.find(ifindex) != m_intf_info.end()) - { - isVxlanIntf = true; - ifname = m_intf_info[ifindex].ifname; - } - - nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); - - if (isVxlanIntf == false) - { - if (nlmsg_type != RTM_DELNEIGH) - { - return; - } - } - else - { - /* If this is for vnet bridge vxlan interface, then return */ - if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) - { - return; - } - - /* VxLan netdevice should be in - format */ - str_loc = ifname.rfind("-"); - if (str_loc == string::npos) - { - return; - } - - vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); - vni = m_intf_info[ifindex].vni; - } - - - if (isVxlanIntf == false) - { - vlan = rtnl_neigh_get_vlan(neigh); - if (m_isEvpnNvoExist) - { - macRefreshStateDB(vlan, macStr); - } - return; - } - - vtep_addr = rtnl_neigh_get_dst(neigh); - if (vtep_addr == NULL) - { - return; - } - else - { - /* Currently we only support ipv4 tunnel endpoints */ - vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); - SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); - } - - int state = rtnl_neigh_get_state(neigh); - if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || - (state == NUD_FAILED)) - { - delete_key = true; - } - - if (state & NUD_NOARP) - { - /* This is a static route */ - type = "static"; - } - else - { - type = "dynamic"; - } - - /* Handling IMET routes */ - if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) - { - if (vtep.s_addr) - { - string vlan_str = ifname.substr(str_loc+1, string::npos); - - if (!delete_key) - { - imetAddRoute(vtep, vlan_str, vni); - } - else - { - imetDelRoute(vtep, vlan_str, vni); - } - } - return; - } - - key+= vlan_id; - key+= ":"; - key+= macStr; - - if (!delete_key) - { - macAddVxlan(key, vtep, type, vni, ifname); - } - else - { - macDelVxlan(key); - } - return; -} - -void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) -{ - struct rtnl_link *link; - char *ifname = NULL; - char *nil = "NULL"; - int ifindex; - unsigned int vni; - - link = (struct rtnl_link *)obj; - ifname = rtnl_link_get_name(link); - ifindex = rtnl_link_get_ifindex(link); - if (rtnl_link_is_vxlan(link) == 0) - { - return; - } - - if (rtnl_link_vxlan_get_id(link, &vni) != 0) - { - SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); - return; - } - SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); - if (nlmsg_type == RTM_NEWLINK) - { - m_intf_info[ifindex].vni = vni; - m_intf_info[ifindex].ifname = ifname; - } - return; -} - -void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) -{ - if ((nlmsg_type != RTM_NEWLINK) && - (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) - { - SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); - return; - } - if (nlmsg_type == RTM_NEWLINK) - { - onMsgLink(nlmsg_type, obj); - } - else - { - onMsgNbr(nlmsg_type, obj); - } -} - +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "ipaddress.h" +#include "netmsg.h" +#include "macaddress.h" +#include "exec.h" +#include "fdbsync.h" +#include "warm_restart.h" +#include "errno.h" + +using namespace std; +using namespace swss; + +#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" + +FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : + m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), + m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), + m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), + m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) +{ + m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); + if (m_AppRestartAssist) + { + m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); + m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); + } +} + +FdbSync::~FdbSync() +{ + if (m_AppRestartAssist) + { + delete m_AppRestartAssist; + } +} + + +// Check if interface entries are restored in kernel +bool FdbSync::isIntfRestoreDone() +{ + vector required_modules = { + "vxlanmgrd", + "intfmgrd", + "vlanmgrd", + "vrfmgrd" + }; + + for (string& module : required_modules) + { + WarmStart::WarmStartState state; + + WarmStart::getWarmStartState(module, state); + if (state == WarmStart::REPLAYED || state == WarmStart::RECONCILED) + { + SWSS_LOG_INFO("Module %s Replayed or Reconciled %d",module.c_str(), (int) state); + } + else + { + SWSS_LOG_INFO("Module %s NOT Replayed or Reconciled %d",module.c_str(), (int) state); + return false; + } + } + + return true; +} + +void FdbSync::processCfgEvpnNvo() +{ + std::deque entries; + m_cfgEvpnNvoTable.pops(entries); + bool lastNvoState = m_isEvpnNvoExist; + + for (auto entry: entries) + { + std::string op = kfvOp(entry); + + if (op == SET_COMMAND) + { + m_isEvpnNvoExist = true; + } + else if (op == DEL_COMMAND) + { + m_isEvpnNvoExist = false; + } + + if (lastNvoState != m_isEvpnNvoExist) + { + updateAllLocalMac(); + } + } + return; +} + +void FdbSync::updateAllLocalMac() +{ + for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) + { + if (m_isEvpnNvoExist) + { + /* Add the Local FDB entry into Kernel */ + addLocalMac(it->first, "replace"); + } + else + { + /* Delete the Local FDB entry from Kernel */ + addLocalMac(it->first, "del"); + } + } +} + +void FdbSync::processStateFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_fdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + info.mac = mac_address; + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + info.port_name = fvValue(i); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateLocalMac(&info); + } +} + +void FdbSync::macUpdateCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_fdb_mac[key].port_name = info->port_name; + m_fdb_mac[key].type = info->type; + + return; +} + +bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + if (m_fdb_mac.find(key) != m_fdb_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); + return true; + } + + return false; +} + +void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) +{ + std::string vtep = m_mac[auxkey].vtep; + + const std::string cmds = std::string("") + + " bridge fdb del " + info->mac + " dev " + + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::updateLocalMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ + if (m_mac.find(key) != m_mac.end()) + { + macDelVxlanEntry(key, info); + SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); + macDelVxlan(key); + } + } + else + { + op = "del"; + port_name = m_fdb_mac[key].port_name; + fdb_type = m_fdb_mac[key].type; + m_fdb_mac.erase(key); + } + + if (!m_isEvpnNvoExist) + { + SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); + return; + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::addLocalMac(string key, string op) +{ + char *type; + string port_name = ""; + string mac = ""; + string vlan = ""; + size_t str_loc = string::npos; + + str_loc = key.find(":"); + if (str_loc == string::npos) + { + SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); + return; + } + vlan = key.substr(4, str_loc-4); + mac = key.substr(str_loc+1, std::string::npos); + + SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + mac + " dev " + + port_name + " master " + type + " vlan " + vlan; + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +/* + * This is a special case handling where mac is learned in the ASIC. + * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel + * This MAC will age out, when MAC delete is received from the Kernel. + * If MAC is still present in the state DB cache then fdbsyncd will be + * re-programmed with MAC in the Kernel + */ +void FdbSync::macRefreshStateDB(int vlan, string kmac) +{ + string key = "Vlan" + to_string(vlan) + ":" + kmac; + char *type; + string port_name = ""; + + SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + kmac + " dev " + + port_name + " master " + type + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +bool FdbSync::checkImetExist(string key, uint32_t vni) +{ + if (m_imet_route.find(key) != m_imet_route.end()) + { + SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); + return false; + } + m_imet_route[key].vni = vni; + return true; +} + +bool FdbSync::checkDelImet(string key, uint32_t vni) +{ + int ret = false; + + SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); + if (m_imet_route.find(key) != m_imet_route.end()) + { + ret = true; + m_imet_route.erase(key); + } + return ret; +} + +void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkImetExist(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); + return; + } + + m_imetTable.set(key, fvVector); + return; +} + +void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkDelImet(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); + return; + } + + m_imetTable.del(key); + return; +} + +void FdbSync::macDelVxlanDB(string key) +{ + string vtep = m_mac[key].vtep; + string type; + string vni = to_string(m_mac[key].vni); + type = m_mac[key].type; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", vtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", vni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + SWSS_LOG_NOTICE("%sVXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "" , + key.c_str(), vtep.c_str(), type.c_str()); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); + return; + } + + m_fdbTable.del(key); + return; + +} + +void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) +{ + string svtep = inet_ntoa(vtep); + string svni = to_string(vni); + + /* Update the DB with Vxlan MAC */ + m_mac[key] = {svtep, type, vni, intf_name}; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", svtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", svni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + SWSS_LOG_INFO("%sVXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "" , + key.c_str(), svtep.c_str(), type.c_str()); + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); + return; + } + + m_fdbTable.set(key, fvVector); + + return; +} + +void FdbSync::macDelVxlan(string key) +{ + if (m_mac.find(key) != m_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); + macDelVxlanDB(key); + m_mac.erase(key); + } + return; +} + +void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) +{ + char macStr[MAX_ADDR_SIZE + 1] = {0}; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + struct in_addr vtep = {0}; + int vlan = 0, ifindex = 0; + uint32_t vni = 0; + nl_addr *vtep_addr; + string ifname; + string key; + bool delete_key = false; + size_t str_loc = string::npos; + string type = ""; + string vlan_id = ""; + bool isVxlanIntf = false; + + if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && + (nlmsg_type != RTM_DELNEIGH)) + { + return; + } + + /* Only MAC route is to be supported */ + if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) + { + return; + } + ifindex = rtnl_neigh_get_ifindex(neigh); + if (m_intf_info.find(ifindex) != m_intf_info.end()) + { + isVxlanIntf = true; + ifname = m_intf_info[ifindex].ifname; + } + + nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); + + if (isVxlanIntf == false) + { + if (nlmsg_type != RTM_DELNEIGH) + { + return; + } + } + else + { + /* If this is for vnet bridge vxlan interface, then return */ + if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) + { + return; + } + + /* VxLan netdevice should be in - format */ + str_loc = ifname.rfind("-"); + if (str_loc == string::npos) + { + return; + } + + vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); + vni = m_intf_info[ifindex].vni; + } + + + if (isVxlanIntf == false) + { + vlan = rtnl_neigh_get_vlan(neigh); + if (m_isEvpnNvoExist) + { + macRefreshStateDB(vlan, macStr); + } + return; + } + + vtep_addr = rtnl_neigh_get_dst(neigh); + if (vtep_addr == NULL) + { + return; + } + else + { + /* Currently we only support ipv4 tunnel endpoints */ + vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); + SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); + } + + int state = rtnl_neigh_get_state(neigh); + if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || + (state == NUD_FAILED)) + { + delete_key = true; + } + + if (state & NUD_NOARP) + { + /* This is a static route */ + type = "static"; + } + else + { + type = "dynamic"; + } + + /* Handling IMET routes */ + if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) + { + if (vtep.s_addr) + { + string vlan_str = ifname.substr(str_loc+1, string::npos); + + if (!delete_key) + { + imetAddRoute(vtep, vlan_str, vni); + } + else + { + imetDelRoute(vtep, vlan_str, vni); + } + } + return; + } + + key+= vlan_id; + key+= ":"; + key+= macStr; + + if (!delete_key) + { + macAddVxlan(key, vtep, type, vni, ifname); + } + else + { + macDelVxlan(key); + } + return; +} + +void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_link *link; + char *ifname = NULL; + char *nil = "NULL"; + int ifindex; + unsigned int vni; + + link = (struct rtnl_link *)obj; + ifname = rtnl_link_get_name(link); + ifindex = rtnl_link_get_ifindex(link); + if (rtnl_link_is_vxlan(link) == 0) + { + return; + } + + if (rtnl_link_vxlan_get_id(link, &vni) != 0) + { + SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); + return; + } + SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); + if (nlmsg_type == RTM_NEWLINK) + { + m_intf_info[ifindex].vni = vni; + m_intf_info[ifindex].ifname = ifname; + } + return; +} + +void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) +{ + if ((nlmsg_type != RTM_NEWLINK) && + (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) + { + SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); + return; + } + if (nlmsg_type == RTM_NEWLINK) + { + onMsgLink(nlmsg_type, obj); + } + else + { + onMsgNbr(nlmsg_type, obj); + } +} + diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h index ee6aa0845b7d..927b95dd0bfe 100644 --- a/fdbsyncd/fdbsync.h +++ b/fdbsyncd/fdbsync.h @@ -1,145 +1,145 @@ -#ifndef __FDBSYNC__ -#define __FDBSYNC__ - -#include -#include -#include "dbconnector.h" -#include "producerstatetable.h" -#include "subscriberstatetable.h" -#include "netmsg.h" -#include "warmRestartAssist.h" - -/* - * Default timer interval for fdbsyncd reconcillation - */ -#define DEFAULT_FDBSYNC_WARMSTART_TIMER 120 - -/* - * This is the MAX time in seconds, fdbsyncd will wait after warm-reboot - * for the interface entries to be recreated in kernel before attempting to - * write the FDB data to kernel - */ -#define INTF_RESTORE_MAX_WAIT_TIME 180 - -namespace swss { - -enum FDB_OP_TYPE { - FDB_OPER_ADD =1, - FDB_OPER_DEL = 2, -}; - -enum FDB_TYPE { - FDB_TYPE_STATIC = 1, - FDB_TYPE_DYNAMIC = 2, -}; - -struct m_fdb_info -{ - std::string mac; - std::string vid; /*Store as Vlan */ - std::string port_name; - short type; /*dynamic or static*/ - short op_type; /*add or del*/ -}; - -class FdbSync : public NetMsg -{ -public: - enum { MAX_ADDR_SIZE = 64 }; - - FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); - ~FdbSync(); - - virtual void onMsg(int nlmsg_type, struct nl_object *obj); - - bool isIntfRestoreDone(); - - AppRestartAssist *getRestartAssist() - { - return m_AppRestartAssist; - } - - SubscriberStateTable *getFdbStateTable() - { - return &m_fdbStateTable; - } - - SubscriberStateTable *getCfgEvpnNvoTable() - { - return &m_cfgEvpnNvoTable; - } - - void processStateFdb(); - - void processCfgEvpnNvo(); - - bool m_reconcileDone = false; - - bool m_isEvpnNvoExist = false; - -private: - ProducerStateTable m_fdbTable; - ProducerStateTable m_imetTable; - SubscriberStateTable m_fdbStateTable; - AppRestartAssist *m_AppRestartAssist; - SubscriberStateTable m_cfgEvpnNvoTable; - - struct m_local_fdb_info - { - std::string port_name; - short type;/*dynamic or static*/ - }; - std::unordered_map m_fdb_mac; - - void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); - - void macUpdateCache(struct m_fdb_info *info); - - bool macCheckSrcDB(struct m_fdb_info *info); - - void updateLocalMac(struct m_fdb_info *info); - - void updateAllLocalMac(); - - void macRefreshStateDB(int vlan, std::string kmac); - - bool checkImetExist(std::string key, uint32_t vni); - - bool checkDelImet(std::string key, uint32_t vni); - - struct m_mac_info - { - std::string vtep; - std::string type; - unsigned int vni; - std::string ifname; - }; - std::unordered_map m_mac; - - struct m_imet_info - { - unsigned int vni; - }; - std::unordered_map m_imet_route; - - struct intf - { - std::string ifname; - unsigned int vni; - }; - std::unordered_map m_intf_info; - - void addLocalMac(std::string key, std::string op); - void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); - void macDelVxlan(std::string auxkey); - void macDelVxlanDB(std::string key); - void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void onMsgNbr(int nlmsg_type, struct nl_object *obj); - void onMsgLink(int nlmsg_type, struct nl_object *obj); -}; - -} - -#endif - +#ifndef __FDBSYNC__ +#define __FDBSYNC__ + +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "subscriberstatetable.h" +#include "netmsg.h" +#include "warmRestartAssist.h" + +/* + * Default timer interval for fdbsyncd reconcillation + */ +#define DEFAULT_FDBSYNC_WARMSTART_TIMER 120 + +/* + * This is the MAX time in seconds, fdbsyncd will wait after warm-reboot + * for the interface entries to be recreated in kernel before attempting to + * write the FDB data to kernel + */ +#define INTF_RESTORE_MAX_WAIT_TIME 180 + +namespace swss { + +enum FDB_OP_TYPE { + FDB_OPER_ADD =1, + FDB_OPER_DEL = 2, +}; + +enum FDB_TYPE { + FDB_TYPE_STATIC = 1, + FDB_TYPE_DYNAMIC = 2, +}; + +struct m_fdb_info +{ + std::string mac; + std::string vid; /*Store as Vlan */ + std::string port_name; + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +class FdbSync : public NetMsg +{ +public: + enum { MAX_ADDR_SIZE = 64 }; + + FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); + ~FdbSync(); + + virtual void onMsg(int nlmsg_type, struct nl_object *obj); + + bool isIntfRestoreDone(); + + AppRestartAssist *getRestartAssist() + { + return m_AppRestartAssist; + } + + SubscriberStateTable *getFdbStateTable() + { + return &m_fdbStateTable; + } + + SubscriberStateTable *getCfgEvpnNvoTable() + { + return &m_cfgEvpnNvoTable; + } + + void processStateFdb(); + + void processCfgEvpnNvo(); + + bool m_reconcileDone = false; + + bool m_isEvpnNvoExist = false; + +private: + ProducerStateTable m_fdbTable; + ProducerStateTable m_imetTable; + SubscriberStateTable m_fdbStateTable; + AppRestartAssist *m_AppRestartAssist; + SubscriberStateTable m_cfgEvpnNvoTable; + + struct m_local_fdb_info + { + std::string port_name; + short type;/*dynamic or static*/ + }; + std::unordered_map m_fdb_mac; + + void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); + + void macUpdateCache(struct m_fdb_info *info); + + bool macCheckSrcDB(struct m_fdb_info *info); + + void updateLocalMac(struct m_fdb_info *info); + + void updateAllLocalMac(); + + void macRefreshStateDB(int vlan, std::string kmac); + + bool checkImetExist(std::string key, uint32_t vni); + + bool checkDelImet(std::string key, uint32_t vni); + + struct m_mac_info + { + std::string vtep; + std::string type; + unsigned int vni; + std::string ifname; + }; + std::unordered_map m_mac; + + struct m_imet_info + { + unsigned int vni; + }; + std::unordered_map m_imet_route; + + struct intf + { + std::string ifname; + unsigned int vni; + }; + std::unordered_map m_intf_info; + + void addLocalMac(std::string key, std::string op); + void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); + void macDelVxlan(std::string auxkey); + void macDelVxlanDB(std::string key); + void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void onMsgNbr(int nlmsg_type, struct nl_object *obj); + void onMsgLink(int nlmsg_type, struct nl_object *obj); +}; + +} + +#endif + diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index dac4bb85e5ff..6b9724d89ef5 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -1,156 +1,156 @@ -#include -#include -#include -#include -#include "logger.h" -#include "select.h" -#include "netdispatcher.h" -#include "netlink.h" -#include "fdbsyncd/fdbsync.h" -#include "warm_restart.h" - -using namespace std; -using namespace swss; - -int main(int argc, char **argv) -{ - Logger::linkToDbNative("fdbsyncd"); - - DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - RedisPipeline pipelineAppDB(&appDb); - DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - - FdbSync sync(&pipelineAppDB, &stateDb, &config_db); - - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); - - while (1) - { - try - { - NetLink netlink; - Selectable *temps; - int ret; - Select s; - SelectableTimer replayCheckTimer(timespec{0, 0}); - - using namespace std::chrono; - - /* - * If WarmStart is enabled, restore the VXLAN-FDB and VNI - * tables and start a reconcillation timer - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - sync.getRestartAssist()->readTablesToMap(); - - steady_clock::time_point starttime = steady_clock::now(); - while (!sync.isIntfRestoreDone()) - { - duration time_span = - duration_cast>(steady_clock::now() - starttime); - int pasttime = int(time_span.count()); - - if (pasttime > INTF_RESTORE_MAX_WAIT_TIME) - { - SWSS_LOG_INFO("timed-out before all interface data was replayed to kernel!!!"); - throw runtime_error("fdbsyncd: timedout on interface data replay"); - } - sleep(1); - } - replayCheckTimer.setInterval(timespec{1, 0}); - replayCheckTimer.start(); - s.addSelectable(&replayCheckTimer); - } - else - { - sync.getRestartAssist()->warmStartDisabled(); - sync.m_reconcileDone = true; - } - - netlink.registerGroup(RTNLGRP_LINK); - netlink.registerGroup(RTNLGRP_NEIGH); - SWSS_LOG_NOTICE("Listens to link and neigh messages..."); - netlink.dumpRequest(RTM_GETLINK); - s.addSelectable(&netlink); - ret = s.select(&temps, 1); - if (ret == Select::ERROR) - { - SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); - } - - netlink.dumpRequest(RTM_GETNEIGH); - - s.addSelectable(sync.getFdbStateTable()); - s.addSelectable(sync.getCfgEvpnNvoTable()); - while (true) - { - s.select(&temps); - - if (temps == (Selectable *)sync.getFdbStateTable()) - { - sync.processStateFdb(); - } - else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) - { - sync.processCfgEvpnNvo(); - } - else if (temps == &replayCheckTimer) - { - if (sync.getFdbStateTable()->empty() && sync.getCfgEvpnNvoTable()->empty()) - { - sync.getRestartAssist()->appDataReplayed(); - SWSS_LOG_NOTICE("FDB Replay Complete"); - s.removeSelectable(&replayCheckTimer); - - /* Obtain warm-restart timer defined for routing application */ - uint32_t warmRestartIval = WarmStart::getWarmStartTimer("bgp","bgp"); - if (warmRestartIval) - { - sync.getRestartAssist()->setReconcileInterval(warmRestartIval); - } - //Else the interval is already set to default value - - //TODO: Optimise the reconcillation time using eoiu - issue#1657 - SWSS_LOG_NOTICE("Starting ReconcileTimer"); - sync.getRestartAssist()->startReconcileTimer(s); - } - else - { - replayCheckTimer.setInterval(timespec{1, 0}); - // re-start replay check timer - replayCheckTimer.start(); - } - } - else - { - /* - * If warmstart is in progress, we check the reconcile timer, - * if timer expired, we stop the timer and start the reconcile process - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - if (sync.getRestartAssist()->checkReconcileTimer(temps)) - { - sync.m_reconcileDone = true; - sync.getRestartAssist()->stopReconcileTimer(s); - sync.getRestartAssist()->reconcile(); - SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete"); - } - } - } - } - } - catch (const std::exception& e) - { - cout << "Exception \"" << e.what() << "\" had been thrown in daemon" << endl; - return 0; - } - } - - return 1; -} +#include +#include +#include +#include +#include "logger.h" +#include "select.h" +#include "netdispatcher.h" +#include "netlink.h" +#include "fdbsyncd/fdbsync.h" +#include "warm_restart.h" + +using namespace std; +using namespace swss; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fdbsyncd"); + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + RedisPipeline pipelineAppDB(&appDb); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + FdbSync sync(&pipelineAppDB, &stateDb, &config_db); + + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); + + while (1) + { + try + { + NetLink netlink; + Selectable *temps; + int ret; + Select s; + SelectableTimer replayCheckTimer(timespec{0, 0}); + + using namespace std::chrono; + + /* + * If WarmStart is enabled, restore the VXLAN-FDB and VNI + * tables and start a reconcillation timer + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + sync.getRestartAssist()->readTablesToMap(); + + steady_clock::time_point starttime = steady_clock::now(); + while (!sync.isIntfRestoreDone()) + { + duration time_span = + duration_cast>(steady_clock::now() - starttime); + int pasttime = int(time_span.count()); + + if (pasttime > INTF_RESTORE_MAX_WAIT_TIME) + { + SWSS_LOG_INFO("timed-out before all interface data was replayed to kernel!!!"); + throw runtime_error("fdbsyncd: timedout on interface data replay"); + } + sleep(1); + } + replayCheckTimer.setInterval(timespec{1, 0}); + replayCheckTimer.start(); + s.addSelectable(&replayCheckTimer); + } + else + { + sync.getRestartAssist()->warmStartDisabled(); + sync.m_reconcileDone = true; + } + + netlink.registerGroup(RTNLGRP_LINK); + netlink.registerGroup(RTNLGRP_NEIGH); + SWSS_LOG_NOTICE("Listens to link and neigh messages..."); + netlink.dumpRequest(RTM_GETLINK); + s.addSelectable(&netlink); + ret = s.select(&temps, 1); + if (ret == Select::ERROR) + { + SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); + } + + netlink.dumpRequest(RTM_GETNEIGH); + + s.addSelectable(sync.getFdbStateTable()); + s.addSelectable(sync.getCfgEvpnNvoTable()); + while (true) + { + s.select(&temps); + + if (temps == (Selectable *)sync.getFdbStateTable()) + { + sync.processStateFdb(); + } + else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) + { + sync.processCfgEvpnNvo(); + } + else if (temps == &replayCheckTimer) + { + if (sync.getFdbStateTable()->empty() && sync.getCfgEvpnNvoTable()->empty()) + { + sync.getRestartAssist()->appDataReplayed(); + SWSS_LOG_NOTICE("FDB Replay Complete"); + s.removeSelectable(&replayCheckTimer); + + /* Obtain warm-restart timer defined for routing application */ + uint32_t warmRestartIval = WarmStart::getWarmStartTimer("bgp","bgp"); + if (warmRestartIval) + { + sync.getRestartAssist()->setReconcileInterval(warmRestartIval); + } + //Else the interval is already set to default value + + //TODO: Optimise the reconcillation time using eoiu - issue#1657 + SWSS_LOG_NOTICE("Starting ReconcileTimer"); + sync.getRestartAssist()->startReconcileTimer(s); + } + else + { + replayCheckTimer.setInterval(timespec{1, 0}); + // re-start replay check timer + replayCheckTimer.start(); + } + } + else + { + /* + * If warmstart is in progress, we check the reconcile timer, + * if timer expired, we stop the timer and start the reconcile process + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + if (sync.getRestartAssist()->checkReconcileTimer(temps)) + { + sync.m_reconcileDone = true; + sync.getRestartAssist()->stopReconcileTimer(s); + sync.getRestartAssist()->reconcile(); + SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete"); + } + } + } + } + } + catch (const std::exception& e) + { + cout << "Exception \"" << e.what() << "\" had been thrown in daemon" << endl; + return 0; + } + } + + return 1; +}