diff --git a/orchagent/muxorch.cpp b/orchagent/muxorch.cpp index 124a1cda7ce2..61ee046f191f 100644 --- a/orchagent/muxorch.cpp +++ b/orchagent/muxorch.cpp @@ -19,6 +19,7 @@ #include "portsorch.h" #include "aclorch.h" #include "routeorch.h" +#include "fdborch.h" /* Global variables */ extern Directory gDirectory; @@ -27,6 +28,7 @@ extern NeighOrch *gNeighOrch; extern RouteOrch *gRouteOrch; extern AclOrch *gAclOrch; extern PortsOrch *gPortsOrch; +extern FdbOrch *gFdbOrch; extern sai_object_id_t gVirtualRouterId; extern sai_object_id_t gUnderlayIfId; @@ -196,6 +198,10 @@ static sai_object_id_t create_tunnel(const IpAddress* p_dst_ip, const IpAddress* attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2P; tunnel_attrs.push_back(attr); + attr.id = SAI_TUNNEL_ATTR_ENCAP_TTL_MODE; + attr.value.s32 = SAI_TUNNEL_TTL_MODE_PIPE_MODEL; + tunnel_attrs.push_back(attr); + if (p_src_ip != nullptr) { attr.id = SAI_TUNNEL_ATTR_ENCAP_SRC_IP; @@ -474,7 +480,7 @@ void MuxCable::updateNeighbor(NextHopKey nh, bool add) { mux_orch_->addNexthop(nh, mux_name_); } - else + else if (mux_name_ == mux_orch_->getNexthopMuxName(nh)) { mux_orch_->removeNexthop(nh); } @@ -507,9 +513,11 @@ void MuxNbrHandler::update(NextHopKey nh, sai_object_id_t tunnelId, bool add, Mu break; case MuxState::MUX_STATE_ACTIVE: neighbors_[nh.ip_address] = gNeighOrch->getLocalNextHopId(nh); + gNeighOrch->enableNeighbor(nh); break; case MuxState::MUX_STATE_STANDBY: neighbors_[nh.ip_address] = tunnelId; + gNeighOrch->disableNeighbor(nh); mux_cb_orch->addTunnelRoute(nh); create_route(pfx, tunnelId); break; @@ -806,7 +814,6 @@ sai_object_id_t MuxOrch::getNextHopTunnelId(std::string tunnelKey, IpAddress& ip return it->second.nh_id; } - MuxCable* MuxOrch::findMuxCableInSubnet(IpAddress ip) { for (auto it = mux_cable_tb_.begin(); it != mux_cable_tb_.end(); it++) @@ -821,8 +828,13 @@ MuxCable* MuxOrch::findMuxCableInSubnet(IpAddress ip) return nullptr; } -bool MuxOrch::isNeighborActive(IpAddress nbr, string alias) +bool MuxOrch::isNeighborActive(const IpAddress& nbr, const MacAddress& mac, string& alias) { + if (mux_cable_tb_.empty()) + { + return true; + } + MuxCable* ptr = findMuxCableInSubnet(nbr); if (ptr) @@ -830,19 +842,145 @@ bool MuxOrch::isNeighborActive(IpAddress nbr, string alias) return ptr->isActive(); } + string port; + if (!getMuxPort(mac, alias, port)) + { + SWSS_LOG_INFO("Mux get port from FDB failed for '%s' mac '%s'", + nbr.to_string().c_str(), mac.to_string().c_str()); + return true; + } + + if (!port.empty() && isMuxExists(port)) + { + MuxCable* ptr = getMuxCable(port); + return ptr->isActive(); + } + + return true; +} + +bool MuxOrch::getMuxPort(const MacAddress& mac, const string& alias, string& portName) +{ + portName = std::string(); + Port rif, port; + + if (!gPortsOrch->getPort(alias, rif)) + { + SWSS_LOG_ERROR("Interface '%s' not found in port table", alias.c_str()); + return false; + } + + if (rif.m_type != Port::VLAN) + { + SWSS_LOG_DEBUG("Interface type for '%s' is not Vlan, type %d", alias.c_str(), rif.m_type); + return false; + } + + if (!gFdbOrch->getPort(mac, rif.m_vlan_info.vlan_id, port)) + { + SWSS_LOG_INFO("FDB entry not found: Vlan %s, mac %s", alias.c_str(), mac.to_string().c_str()); + return true; + } + + portName = port.m_alias; return true; } +void MuxOrch::updateFdb(const FdbUpdate& update) +{ + if (!update.add) + { + /* + * For Mac aging, flush events, skip updating mux neighbors. + * Instead, wait for neighbor update events + */ + return; + } + + NeighborEntry neigh; + MacAddress mac; + MuxCable* ptr; + for (auto nh = mux_nexthop_tb_.begin(); nh != mux_nexthop_tb_.end(); ++nh) + { + auto res = neigh_orch_->getNeighborEntry(nh->first, neigh, mac); + if (!res || update.entry.mac != mac) + { + continue; + } + + if (nh->second != update.entry.port_name) + { + if (!nh->second.empty() && isMuxExists(nh->second)) + { + ptr = getMuxCable(nh->second); + if (ptr->isIpInSubnet(nh->first.ip_address)) + { + continue; + } + nh->second = update.entry.port_name; + ptr->updateNeighbor(nh->first, false); + } + + if (isMuxExists(update.entry.port_name)) + { + ptr = getMuxCable(update.entry.port_name); + ptr->updateNeighbor(nh->first, true); + } + } + } +} + void MuxOrch::updateNeighbor(const NeighborUpdate& update) { + if (mux_cable_tb_.empty()) + { + return; + } + for (auto it = mux_cable_tb_.begin(); it != mux_cable_tb_.end(); it++) { MuxCable* ptr = it->second.get(); if (ptr->isIpInSubnet(update.entry.ip_address)) { ptr->updateNeighbor(update.entry, update.add); + return; + } + } + + string port, old_port; + if (update.add && !getMuxPort(update.mac, update.entry.alias, port)) + { + return; + } + else if (update.add) + { + /* Check if the neighbor already exists */ + old_port = getNexthopMuxName(update.entry); + addNexthop(update.entry); + } + else + { + auto it = mux_nexthop_tb_.find(update.entry); + if (it != mux_nexthop_tb_.end()) + { + port = it->second; + removeNexthop(update.entry); } } + + MuxCable* ptr; + if (!old_port.empty() && old_port != port && isMuxExists(old_port)) + { + ptr = getMuxCable(old_port); + ptr->updateNeighbor(update.entry, false); + addNexthop(update.entry); + } + + if (!port.empty() && isMuxExists(port)) + { + ptr = getMuxCable(port); + ptr->updateNeighbor(update.entry, update.add); + } } void MuxOrch::addNexthop(NextHopKey nh, string muxName) @@ -855,6 +993,16 @@ void MuxOrch::removeNexthop(NextHopKey nh) mux_nexthop_tb_.erase(nh); } +string MuxOrch::getNexthopMuxName(NextHopKey nh) +{ + if (mux_nexthop_tb_.find(nh) == mux_nexthop_tb_.end()) + { + return std::string(); + } + + return mux_nexthop_tb_[nh]; +} + sai_object_id_t MuxOrch::getNextHopId(const NextHopKey &nh) { if (mux_nexthop_tb_.find(nh) == mux_nexthop_tb_.end()) @@ -865,7 +1013,8 @@ sai_object_id_t MuxOrch::getNextHopId(const NextHopKey &nh) auto mux_name = mux_nexthop_tb_[nh]; if (!isMuxExists(mux_name)) { - SWSS_LOG_WARN("Mux entry for port '%s' doesn't exist", mux_name.c_str()); + SWSS_LOG_INFO("Mux entry for nh '%s' port '%s' doesn't exist", + nh.ip_address.to_string().c_str(), mux_name.c_str()); return SAI_NULL_OBJECT_ID; } @@ -888,6 +1037,12 @@ void MuxOrch::update(SubjectType type, void *cntx) updateNeighbor(*update); break; } + case SUBJECT_TYPE_FDB_CHANGE: + { + FdbUpdate *update = static_cast(cntx); + updateFdb(*update); + break; + } default: /* Received update in which we are not interested * Ignore it @@ -896,15 +1051,18 @@ void MuxOrch::update(SubjectType type, void *cntx) } } -MuxOrch::MuxOrch(DBConnector *db, const std::vector &tables, TunnelDecapOrch* decapOrch, NeighOrch* neighOrch) : +MuxOrch::MuxOrch(DBConnector *db, const std::vector &tables, + TunnelDecapOrch* decapOrch, NeighOrch* neighOrch, FdbOrch* fdbOrch) : Orch2(db, tables, request_), decap_orch_(decapOrch), - neigh_orch_(neighOrch) + neigh_orch_(neighOrch), + fdb_orch_(fdbOrch) { handler_map_.insert(handler_pair(CFG_MUX_CABLE_TABLE_NAME, &MuxOrch::handleMuxCfg)); handler_map_.insert(handler_pair(CFG_PEER_SWITCH_TABLE_NAME, &MuxOrch::handlePeerSwitch)); neigh_orch_->attach(this); + fdb_orch_->attach(this); } bool MuxOrch::handleMuxCfg(const Request& request) @@ -921,13 +1079,13 @@ bool MuxOrch::handleMuxCfg(const Request& request) { if(isMuxExists(port_name)) { - SWSS_LOG_ERROR("Mux for port '%s' already exists", port_name.c_str()); + SWSS_LOG_INFO("Mux for port '%s' already exists", port_name.c_str()); return true; } if (mux_peer_switch_.isZero()) { - SWSS_LOG_ERROR("Peer switch addr not yet configured, port '%s'", port_name.c_str()); + SWSS_LOG_INFO("Mux Peer switch addr not yet configured, port '%s'", port_name.c_str()); return false; } @@ -998,7 +1156,7 @@ bool MuxOrch::addOperation(const Request& request) auto& tn = request.getTableName(); if (handler_map_.find(tn) == handler_map_.end()) { - SWSS_LOG_ERROR(" %s handler is not initialized", tn.c_str()); + SWSS_LOG_ERROR("Mux %s handler is not initialized", tn.c_str()); return true; } @@ -1022,7 +1180,7 @@ bool MuxOrch::delOperation(const Request& request) auto& tn = request.getTableName(); if (handler_map_.find(tn) == handler_map_.end()) { - SWSS_LOG_ERROR(" %s handler is not initialized", tn.c_str()); + SWSS_LOG_ERROR("Mux %s handler is not initialized", tn.c_str()); return true; } @@ -1099,7 +1257,7 @@ bool MuxCableOrch::addOperation(const Request& request) MuxOrch* mux_orch = gDirectory.get(); if (!mux_orch->isMuxExists(port_name)) { - SWSS_LOG_WARN("Mux entry for port '%s' doesn't exist", port_name.c_str()); + SWSS_LOG_INFO("Mux entry for port '%s' doesn't exist", port_name.c_str()); return false; } @@ -1112,7 +1270,7 @@ bool MuxCableOrch::addOperation(const Request& request) } catch(const std::runtime_error& error) { - SWSS_LOG_ERROR("Error setting state %s for port %s. Error: %s", + SWSS_LOG_ERROR("Mux Error setting state %s for port %s. Error: %s", state.c_str(), port_name.c_str(), error.what()); return false; } @@ -1171,13 +1329,13 @@ bool MuxStateOrch::addOperation(const Request& request) } catch(const std::runtime_error& error) { - SWSS_LOG_ERROR("Error getting state for port %s Error: %s", port_name.c_str(), error.what()); + SWSS_LOG_ERROR("Mux error getting state for port %s Error: %s", port_name.c_str(), error.what()); return false; } if (mux_obj->isStateChangeInProgress()) { - SWSS_LOG_NOTICE("Mux state change for port '%s' is in-progress", port_name.c_str()); + SWSS_LOG_INFO("Mux state change for port '%s' is in-progress", port_name.c_str()); return false; } @@ -1186,7 +1344,7 @@ bool MuxStateOrch::addOperation(const Request& request) mux_state = MUX_HW_STATE_UNKNOWN; } - SWSS_LOG_NOTICE("Setting State DB entry (hw state %s, mux state %s) for port %s", + SWSS_LOG_NOTICE("Mux setting State DB entry (hw state %s, mux state %s) for port %s", hw_state.c_str(), mux_state.c_str(), port_name.c_str()); updateMuxState(port_name, mux_state); diff --git a/orchagent/muxorch.h b/orchagent/muxorch.h index 2e97c5b6097a..f52343f22ce0 100644 --- a/orchagent/muxorch.h +++ b/orchagent/muxorch.h @@ -152,7 +152,7 @@ class MuxCfgRequest : public Request class MuxOrch : public Orch2, public Observer, public Subject { public: - MuxOrch(DBConnector *db, const std::vector &tables, TunnelDecapOrch*, NeighOrch*); + MuxOrch(DBConnector *db, const std::vector &tables, TunnelDecapOrch*, NeighOrch*, FdbOrch*); using handler_pair = pair; using handler_map = map; @@ -168,12 +168,12 @@ class MuxOrch : public Orch2, public Observer, public Subject } MuxCable* findMuxCableInSubnet(IpAddress); - bool isNeighborActive(IpAddress nbr, string alias); + bool isNeighborActive(const IpAddress&, const MacAddress&, string&); void update(SubjectType, void *); - void updateNeighbor(const NeighborUpdate&); - void addNexthop(NextHopKey, string); + void addNexthop(NextHopKey, string = ""); void removeNexthop(NextHopKey); + string getNexthopMuxName(NextHopKey); sai_object_id_t getNextHopId(const NextHopKey&); sai_object_id_t createNextHopTunnel(std::string tunnelKey, IpAddress& ipAddr); @@ -187,8 +187,13 @@ class MuxOrch : public Orch2, public Observer, public Subject bool handleMuxCfg(const Request&); bool handlePeerSwitch(const Request&); + void updateNeighbor(const NeighborUpdate&); + void updateFdb(const FdbUpdate&); + + bool getMuxPort(const MacAddress&, const string&, string&); + IpAddress mux_peer_switch_ = 0x0; - sai_object_id_t mux_tunnel_id_; + sai_object_id_t mux_tunnel_id_ = SAI_NULL_OBJECT_ID; MuxCableTb mux_cable_tb_; MuxTunnelNHs mux_tunnel_nh_; @@ -198,6 +203,7 @@ class MuxOrch : public Orch2, public Observer, public Subject TunnelDecapOrch *decap_orch_; NeighOrch *neigh_orch_; + FdbOrch *fdb_orch_; MuxCfgRequest request_; }; diff --git a/orchagent/neighorch.cpp b/orchagent/neighorch.cpp index 267e51544a98..ef10d8764dcf 100644 --- a/orchagent/neighorch.cpp +++ b/orchagent/neighorch.cpp @@ -653,9 +653,8 @@ bool NeighOrch::addNeighbor(const NeighborEntry &neighborEntry, const MacAddress MuxOrch* mux_orch = gDirectory.get(); bool hw_config = isHwConfigured(neighborEntry); - if (!hw_config && mux_orch->isNeighborActive(ip_address, alias)) + if (!hw_config && mux_orch->isNeighborActive(ip_address, macAddress, alias)) { - if (gMySwitchType == "voq") { if (!addVoqEncapIndex(alias, ip_address, neighbor_attrs)) @@ -769,7 +768,7 @@ bool NeighOrch::removeNeighbor(const NeighborEntry &neighborEntry, bool disable) return true; } - if (m_syncdNextHops[nexthop].ref_count > 0) + if (m_syncdNextHops.find(nexthop) != m_syncdNextHops.end() && m_syncdNextHops[nexthop].ref_count > 0) { SWSS_LOG_INFO("Failed to remove still referenced neighbor %s on %s", m_syncdNeighbors[neighborEntry].mac.to_string().c_str(), alias.c_str()); diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 638115f631fb..c2246be280b6 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -253,7 +253,7 @@ bool OrchDaemon::init() CFG_MUX_CABLE_TABLE_NAME, CFG_PEER_SWITCH_TABLE_NAME }; - MuxOrch *mux_orch = new MuxOrch(m_configDb, mux_tables, tunnel_decap_orch, gNeighOrch); + MuxOrch *mux_orch = new MuxOrch(m_configDb, mux_tables, tunnel_decap_orch, gNeighOrch, gFdbOrch); gDirectory.set(mux_orch); MuxCableOrch *mux_cb_orch = new MuxCableOrch(m_applDb, APP_MUX_CABLE_TABLE_NAME); diff --git a/tests/test_mux.py b/tests/test_mux.py index c0a0aa1db873..659c686e1908 100644 --- a/tests/test_mux.py +++ b/tests/test_mux.py @@ -104,6 +104,8 @@ def create_and_test_peer(self, db, asicdb, peer_name, peer_ip, src_ip): assert self.check_interface_exists_in_asicdb(asicdb, value) elif field == "SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE": assert self.check_interface_exists_in_asicdb(asicdb, value) + elif field == "SAI_TUNNEL_ATTR_ENCAP_TTL_MODE": + assert value == "SAI_TUNNEL_TTL_MODE_PIPE_MODEL" else: assert False, "Field %s is not tested" % field