diff --git a/.azure-pipelines/build-template.yml b/.azure-pipelines/build-template.yml index 013286267e..4f6b4fa01f 100644 --- a/.azure-pipelines/build-template.yml +++ b/.azure-pipelines/build-template.yml @@ -66,6 +66,7 @@ jobs: clean: true submodules: true - script: | + sudo apt-get update sudo apt-get install -y libhiredis0.14 libhiredis-dev sudo apt-get install -y libzmq5 libzmq3-dev sudo apt-get install -qq -y \ diff --git a/doc/swss-schema.md b/doc/swss-schema.md index ec28eb6c0f..74bfd687b8 100644 --- a/doc/swss-schema.md +++ b/doc/swss-schema.md @@ -233,6 +233,7 @@ and reflects the LAG ports into the redis under: `LAG_TABLE::port` key = ROUTE_TABLE:segment ; SRV6 segment name ; field = value path = STRING ; Comma-separated list of IPV6 prefixes for a SRV6 segment + type = STRING ; SRV6 segment list type like "insert", "encaps.red"; If not provided, default type will be "encaps.red" --------------------------------------------- ### SRV6_MY_SID_TABLE diff --git a/orchagent/aclorch.cpp b/orchagent/aclorch.cpp index 5be81efd79..5780ae4683 100644 --- a/orchagent/aclorch.cpp +++ b/orchagent/aclorch.cpp @@ -3188,6 +3188,7 @@ void AclOrch::initDefaultTableTypes() builder.withName(TABLE_TYPE_DROP) .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TC)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS)) .build() ); diff --git a/orchagent/aclorch.h b/orchagent/aclorch.h index c62a68991a..d9dd292785 100644 --- a/orchagent/aclorch.h +++ b/orchagent/aclorch.h @@ -95,6 +95,7 @@ #define MLNX_MAX_RANGES_COUNT 16 #define INGRESS_TABLE_DROP "IngressTableDrop" +#define EGRESS_TABLE_DROP "EgressTableDrop" #define RULE_OPER_ADD 0 #define RULE_OPER_DELETE 1 diff --git a/orchagent/bfdorch.cpp b/orchagent/bfdorch.cpp index f242645b35..25c6c20cf2 100644 --- a/orchagent/bfdorch.cpp +++ b/orchagent/bfdorch.cpp @@ -14,6 +14,8 @@ using namespace swss; #define BFD_SESSION_DEFAULT_TX_INTERVAL 1000 #define BFD_SESSION_DEFAULT_RX_INTERVAL 1000 #define BFD_SESSION_DEFAULT_DETECT_MULTIPLIER 10 +// TOS: default 6-bit DSCP value 48, default 2-bit ecn value 0. 48<<2 = 192 +#define BFD_SESSION_DEFAULT_TOS 192 #define BFD_SESSION_MILLISECOND_TO_MICROSECOND 1000 #define BFD_SRCPORTINIT 49152 #define BFD_SRCPORTMAX 65536 @@ -243,6 +245,7 @@ bool BfdOrch::create_bfd_session(const string& key, const vector(value); + } else SWSS_LOG_ERROR("Unsupported BFD attribute %s\n", fvField(i).c_str()); } @@ -352,6 +359,10 @@ bool BfdOrch::create_bfd_session(const string& key, const vectorsecond.type != "static" && (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) + if (curr->second.sai_fdb_type == sai_fdb_type && + (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) { clearFdbEntry(curr->first); } @@ -233,7 +233,8 @@ void FdbOrch::handleSyncdFlushNotif(const sai_object_id_t& bv_id, auto curr = itr++; if (curr->second.bridge_port_id == bridge_port_id) { - if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) + if (curr->second.sai_fdb_type == sai_fdb_type && + (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) { clearFdbEntry(curr->first); } @@ -248,7 +249,8 @@ void FdbOrch::handleSyncdFlushNotif(const sai_object_id_t& bv_id, auto curr = itr++; if (curr->first.bv_id == bv_id) { - if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) + if (curr->second.sai_fdb_type == sai_fdb_type && + (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) { clearFdbEntry(curr->first); } @@ -263,7 +265,8 @@ void FdbOrch::handleSyncdFlushNotif(const sai_object_id_t& bv_id, auto curr = itr++; if (curr->first.bv_id == bv_id && curr->second.bridge_port_id == bridge_port_id) { - if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) + if (curr->second.sai_fdb_type == sai_fdb_type && + (curr->first.mac == mac || mac == flush_mac) && curr->second.is_flush_pending) { clearFdbEntry(curr->first); } @@ -274,7 +277,8 @@ void FdbOrch::handleSyncdFlushNotif(const sai_object_id_t& bv_id, void FdbOrch::update(sai_fdb_event_t type, const sai_fdb_entry_t* entry, - sai_object_id_t bridge_port_id) + sai_object_id_t bridge_port_id, + const sai_fdb_entry_type_t &sai_fdb_type) { SWSS_LOG_ENTER(); @@ -365,6 +369,7 @@ void FdbOrch::update(sai_fdb_event_t type, attr.id = SAI_FDB_ENTRY_ATTR_TYPE; attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; + update.sai_fdb_type = SAI_FDB_ENTRY_TYPE_DYNAMIC; attrs.push_back(attr); attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; @@ -399,6 +404,7 @@ void FdbOrch::update(sai_fdb_event_t type, update.add = true; update.entry.port_name = update.port.m_alias; + update.sai_fdb_type = SAI_FDB_ENTRY_TYPE_DYNAMIC; update.type = "dynamic"; update.port.m_fdb_count++; m_portsOrch->setPort(update.port.m_alias, update.port); @@ -569,6 +575,7 @@ void FdbOrch::update(sai_fdb_event_t type, } update.port.m_fdb_count++; m_portsOrch->setPort(update.port.m_alias, update.port); + update.sai_fdb_type = SAI_FDB_ENTRY_TYPE_DYNAMIC; storeFdbEntryState(update); notify(SUBJECT_TYPE_FDB_CHANGE, &update); @@ -592,7 +599,7 @@ void FdbOrch::update(sai_fdb_event_t type, SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: %s }", update.entry.mac.to_string().c_str(), vlanName.c_str(), update.port.m_alias.c_str()); - handleSyncdFlushNotif(entry->bv_id, bridge_port_id, update.entry.mac); + handleSyncdFlushNotif(entry->bv_id, bridge_port_id, update.entry.mac, sai_fdb_type); break; } @@ -636,29 +643,23 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) return false; } - sai_fdb_entry_t entry; - entry.switch_id = gSwitchId; - memcpy(entry.mac_address, mac.getMac(), sizeof(sai_mac_t)); + FdbEntry entry; + entry.mac = mac; entry.bv_id = port.m_vlan_info.vlan_oid; - sai_attribute_t attr; - attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; - - sai_status_t status = sai_fdb_api->get_fdb_entry_attribute(&entry, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + auto it = m_entries.find(entry); + if (it == m_entries.end()) { - SWSS_LOG_ERROR("Failed to get bridge port ID for FDB entry %s, rv:%d", - mac.to_string().c_str(), status); - task_process_status handle_status = handleSaiGetStatus(SAI_API_FDB, status); - if (handle_status != task_process_status::task_success) - { - return false; - } + // This message is now expected in many cases since orchagent will process events such as + // learning new neighbor entries prior to updating the m_entries FDB cache. + SWSS_LOG_INFO("Failed to get cached bridge port ID for FDB entry %s", + mac.to_string().c_str()); + return false; } - if (!m_portsOrch->getPortByBridgePortId(attr.value.oid, port)) + if (!m_portsOrch->getPortByBridgePortId(it->second.bridge_port_id, port)) { - SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, attr.value.oid); + SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, it->second.bridge_port_id); return false; } @@ -1002,6 +1003,7 @@ void FdbOrch::doTask(NotificationConsumer& consumer) { uint32_t count; sai_fdb_event_notification_data_t *fdbevent = nullptr; + sai_fdb_entry_type_t sai_fdb_type = SAI_FDB_ENTRY_TYPE_DYNAMIC; sai_deserialize_fdb_event_ntf(data, count, &fdbevent); @@ -1014,11 +1016,14 @@ void FdbOrch::doTask(NotificationConsumer& consumer) if (fdbevent[i].attr[j].id == SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID) { oid = fdbevent[i].attr[j].value.oid; - break; + } + else if (fdbevent[i].attr[j].id == SAI_FDB_ENTRY_ATTR_TYPE) + { + sai_fdb_type = (sai_fdb_entry_type_t)fdbevent[i].attr[j].value.s32; } } - this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid); + this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid, sai_fdb_type); } sai_deserialize_free_fdb_event_ntf(count, fdbevent); @@ -1346,6 +1351,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, { attr.value.s32 = (fdbData.type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; } + fdbData.sai_fdb_type = (sai_fdb_entry_type_t)attr.value.s32; attrs.push_back(attr); diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index d9f7398237..09bc6dcc69 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -36,6 +36,7 @@ struct FdbUpdate Port port; string type; bool add; + sai_fdb_entry_type_t sai_fdb_type; }; struct FdbFlushUpdate @@ -63,6 +64,7 @@ struct FdbData string remote_ip; string esi; unsigned int vni; + sai_fdb_entry_type_t sai_fdb_type; }; struct SavedFdbEntry @@ -91,7 +93,7 @@ class FdbOrch: public Orch, public Subject, public Observer } bool bake() override; - void update(sai_fdb_event_t, const sai_fdb_entry_t *, sai_object_id_t); + void update(sai_fdb_event_t, const sai_fdb_entry_t *, sai_object_id_t, const sai_fdb_entry_type_t &); void update(SubjectType type, void *cntx); bool getPort(const MacAddress&, uint16_t, Port&); @@ -125,7 +127,8 @@ class FdbOrch: public Orch, public Subject, public Observer void notifyTunnelOrch(Port& port); void clearFdbEntry(const FdbEntry&); - void handleSyncdFlushNotif(const sai_object_id_t&, const sai_object_id_t&, const MacAddress& ); + void handleSyncdFlushNotif(const sai_object_id_t&, const sai_object_id_t&, const MacAddress&, + const sai_fdb_entry_type_t&); }; #endif /* SWSS_FDBORCH_H */ diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index adc2aac9f4..29ea4102bb 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -470,6 +470,11 @@ bool IntfsOrch::setIntf(const string& alias, sai_object_id_t vrf_id, const IpPre { SWSS_LOG_ENTER(); + if (m_removingIntfses.find(alias) != m_removingIntfses.end()) + { + return false; + } + Port port; gPortsOrch->getPort(alias, port); @@ -1076,10 +1081,12 @@ void IntfsOrch::doTask(Consumer &consumer) { if (removeIntf(alias, port.m_vr_id, ip_prefix_in_key ? &ip_prefix : nullptr)) { + m_removingIntfses.erase(alias); it = consumer.m_toSync.erase(it); } else { + m_removingIntfses.insert(alias); it++; continue; } diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index 6b4942897e..ea15ada14b 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -92,6 +92,8 @@ class IntfsOrch : public Orch unique_ptr m_flexCounterTable; unique_ptr m_flexCounterGroupTable; + std::set m_removingIntfses; + std::string getRifFlexCounterTableKey(std::string s); bool addRouterIntfs(sai_object_id_t vrf_id, Port &port, string loopbackAction); diff --git a/orchagent/muxorch.cpp b/orchagent/muxorch.cpp index 368acb553d..b6d91e2587 100644 --- a/orchagent/muxorch.cpp +++ b/orchagent/muxorch.cpp @@ -563,6 +563,8 @@ bool MuxCable::isIpInSubnet(IpAddress ip) bool MuxCable::nbrHandler(bool enable, bool update_rt) { bool ret; + SWSS_LOG_NOTICE("Processing neighbors for mux %s, enable %d, state %d", + mux_name_.c_str(), enable, state_); if (enable) { ret = nbr_handler_->enable(update_rt); @@ -584,6 +586,8 @@ bool MuxCable::nbrHandler(bool enable, bool update_rt) void MuxCable::updateNeighbor(NextHopKey nh, bool add) { + SWSS_LOG_NOTICE("Processing update on neighbor %s for mux %s, add %d, state %d", + nh.ip_address.to_string().c_str(), mux_name_.c_str(), add, state_); sai_object_id_t tnh = mux_orch_->getNextHopTunnelId(MUX_TUNNEL, peer_ip4_); nbr_handler_->update(nh, tnh, add, state_); if (add) @@ -880,8 +884,14 @@ MuxAclHandler::MuxAclHandler(sai_object_id_t port, string alias) { SWSS_LOG_ENTER(); + string value; + shared_ptr m_config_db = shared_ptr(new DBConnector("CONFIG_DB", 0)); + unique_ptr m_systemDefaultsTable = unique_ptr
(new Table(m_config_db.get(), "SYSTEM_DEFAULTS")); + m_systemDefaultsTable->hget("mux_tunnel_egress_acl", "status", value); + is_ingress_acl_ = value != "enabled"; + // There is one handler instance per MUX port - string table_name = MUX_ACL_TABLE_NAME; + string table_name = is_ingress_acl_ ? MUX_ACL_TABLE_NAME : EGRESS_TABLE_DROP; string rule_name = MUX_ACL_RULE_NAME; port_ = port; @@ -919,7 +929,7 @@ MuxAclHandler::MuxAclHandler(sai_object_id_t port, string alias) MuxAclHandler::~MuxAclHandler(void) { SWSS_LOG_ENTER(); - string table_name = MUX_ACL_TABLE_NAME; + string table_name = is_ingress_acl_ ? MUX_ACL_TABLE_NAME : EGRESS_TABLE_DROP; string rule_name = MUX_ACL_RULE_NAME; SWSS_LOG_NOTICE("Un-Binding port %" PRIx64 "", port_); @@ -965,7 +975,7 @@ void MuxAclHandler::createMuxAclTable(sai_object_id_t port, string strTable) auto dropType = gAclOrch->getAclTableType(TABLE_TYPE_DROP); assert(dropType); acl_table.validateAddType(*dropType); - acl_table.stage = ACL_STAGE_INGRESS; + acl_table.stage = is_ingress_acl_ ? ACL_STAGE_INGRESS : ACL_STAGE_EGRESS; gAclOrch->addAclTable(acl_table); bindAllPorts(acl_table); } @@ -1282,7 +1292,7 @@ void MuxOrch::updateNeighbor(const NeighborUpdate& update) return; } - auto standalone_tunnel_neigh_it = standalone_tunnel_neighbors_.find(update.entry.ip_address); + bool is_tunnel_route_installed = isStandaloneTunnelRouteInstalled(update.entry.ip_address); // Handling zero MAC neighbor updates if (!update.mac) { @@ -1293,7 +1303,7 @@ void MuxOrch::updateNeighbor(const NeighborUpdate& update) if (update.add) { - if (standalone_tunnel_neigh_it == standalone_tunnel_neighbors_.end()) + if (!is_tunnel_route_installed) { createStandaloneTunnelRoute(update.entry.ip_address); } @@ -1308,7 +1318,7 @@ void MuxOrch::updateNeighbor(const NeighborUpdate& update) * make sure to remove any existing tunnel routes to prevent conflicts. * This block also covers the case of neighbor deletion. */ - if (standalone_tunnel_neigh_it != standalone_tunnel_neighbors_.end()) + if (is_tunnel_route_installed) { removeStandaloneTunnelRoute(update.entry.ip_address); } @@ -1681,6 +1691,11 @@ void MuxOrch::removeStandaloneTunnelRoute(IpAddress neighborIp) standalone_tunnel_neighbors_.erase(neighborIp); } +bool MuxOrch::isStandaloneTunnelRouteInstalled(const IpAddress& neighborIp) +{ + return standalone_tunnel_neighbors_.find(neighborIp) != standalone_tunnel_neighbors_.end(); +} + MuxCableOrch::MuxCableOrch(DBConnector *db, DBConnector *sdb, const std::string& tableName): Orch2(db, tableName, request_), app_tunnel_route_table_(db, APP_TUNNEL_ROUTE_TABLE_NAME), diff --git a/orchagent/muxorch.h b/orchagent/muxorch.h index 41362fc2e8..33d9baf281 100644 --- a/orchagent/muxorch.h +++ b/orchagent/muxorch.h @@ -55,6 +55,7 @@ class MuxAclHandler // class shared dict: ACL table name -> ACL table static std::map acl_table_; sai_object_id_t port_ = SAI_NULL_OBJECT_ID; + bool is_ingress_acl_ = true; string alias_; }; @@ -211,6 +212,7 @@ class MuxOrch : public Orch2, public Observer, public Subject sai_object_id_t getNextHopTunnelId(std::string tunnelKey, IpAddress& ipAddr); void updateRoute(const IpPrefix &pfx, bool remove); + bool isStandaloneTunnelRouteInstalled(const IpAddress& neighborIp); private: virtual bool addOperation(const Request& request); diff --git a/orchagent/neighorch.cpp b/orchagent/neighorch.cpp index 5207b2430c..8e4c668a57 100644 --- a/orchagent/neighorch.cpp +++ b/orchagent/neighorch.cpp @@ -739,17 +739,33 @@ void NeighOrch::doTask(Consumer &consumer) mac_address = MacAddress(fvValue(*i)); } - if (m_syncdNeighbors.find(neighbor_entry) == m_syncdNeighbors.end() - || m_syncdNeighbors[neighbor_entry].mac != mac_address) + bool nbr_not_found = (m_syncdNeighbors.find(neighbor_entry) == m_syncdNeighbors.end()); + if (nbr_not_found || m_syncdNeighbors[neighbor_entry].mac != mac_address) { - // only for unresolvable neighbors that are new - if (!mac_address) + if (!mac_address) { - if (m_syncdNeighbors.find(neighbor_entry) == m_syncdNeighbors.end()) + if (nbr_not_found) { - addZeroMacTunnelRoute(neighbor_entry, mac_address); + // only for unresolvable neighbors that are new + if (addZeroMacTunnelRoute(neighbor_entry, mac_address)) + { + it = consumer.m_toSync.erase(it); + } + else + { + it++; + continue; + } + } + else + { + /* + * For neighbors that were previously resolvable but are now unresolvable, + * we expect such neighbor entries to be deleted prior to a zero MAC update + * arriving for that same neighbor. + */ + it = consumer.m_toSync.erase(it); } - it = consumer.m_toSync.erase(it); } else if (addNeighbor(neighbor_entry, mac_address)) { @@ -1755,12 +1771,18 @@ void NeighOrch::updateSrv6Nexthop(const NextHopKey &nh, const sai_object_id_t &n m_syncdNextHops.erase(nh); } } -void NeighOrch::addZeroMacTunnelRoute(const NeighborEntry& entry, const MacAddress& mac) + +bool NeighOrch::addZeroMacTunnelRoute(const NeighborEntry& entry, const MacAddress& mac) { SWSS_LOG_INFO("Creating tunnel route for neighbor %s", entry.ip_address.to_string().c_str()); MuxOrch* mux_orch = gDirectory.get(); NeighborUpdate update = {entry, mac, true}; mux_orch->update(SUBJECT_TYPE_NEIGH_CHANGE, static_cast(&update)); - m_syncdNeighbors[entry] = { mac, false }; -} + if (mux_orch->isStandaloneTunnelRouteInstalled(entry.ip_address)) + { + m_syncdNeighbors[entry] = { mac, false }; + return true; + } + return false; +} diff --git a/orchagent/neighorch.h b/orchagent/neighorch.h index 727797757f..7dc5d386b4 100644 --- a/orchagent/neighorch.h +++ b/orchagent/neighorch.h @@ -116,7 +116,7 @@ class NeighOrch : public Orch, public Subject, public Observer bool resolveNeighborEntry(const NeighborEntry &, const MacAddress &); void clearResolvedNeighborEntry(const NeighborEntry &); - void addZeroMacTunnelRoute(const NeighborEntry &, const MacAddress &); + bool addZeroMacTunnelRoute(const NeighborEntry &, const MacAddress &); }; #endif /* SWSS_NEIGHORCH_H */ diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 5f43250256..2b7564fc07 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -235,6 +235,7 @@ bool OrchDaemon::init() CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, CFG_DSCP_TO_FC_MAP_TABLE_NAME, CFG_EXP_TO_FC_MAP_TABLE_NAME, + CFG_TC_TO_DOT1P_MAP_TABLE_NAME, CFG_TC_TO_DSCP_MAP_TABLE_NAME }; gQosOrch = new QosOrch(m_configDb, qos_tables); diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 744f4c35b7..5dd63129f1 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -4886,6 +4886,12 @@ bool PortsOrch::addBridgePort(Port &port) return true; } + if (port.m_rif_id != 0) + { + SWSS_LOG_NOTICE("Cannot create bridge port, interface %s is a router port", port.m_alias.c_str()); + return false; + } + sai_attribute_t attr; vector attrs; @@ -6163,6 +6169,10 @@ void PortsOrch::generateQueueMapPerPort(const Port& port, FlexCounterQueueStates queueVector.emplace_back(name.str(), id); if (voq) { + // Install a flex counter for this voq to track stats. Voq counters do + // not have buffer queue config. So it does not get enabled through the + // flexcounter orch logic. Always enabled voq counters. + addQueueFlexCountersPerPortPerQueueIndex(port, queueIndex, true); queuePortVector.emplace_back(id, sai_serialize_object_id(port.m_system_port_oid)); } else @@ -6178,12 +6188,12 @@ void PortsOrch::generateQueueMapPerPort(const Port& port, FlexCounterQueueStates else { m_queueTable->set("", queueVector); + CounterCheckOrch::getInstance().addPort(port); } m_queuePortTable->set("", queuePortVector); m_queueIndexTable->set("", queueIndexVector); m_queueTypeTable->set("", queueTypeVector); - CounterCheckOrch::getInstance().addPort(port); } void PortsOrch::addQueueFlexCounters(map queuesStateVector) @@ -6224,19 +6234,30 @@ void PortsOrch::addQueueFlexCountersPerPort(const Port& port, FlexCounterQueueSt continue; } // Install a flex counter for this queue to track stats - addQueueFlexCountersPerPortPerQueueIndex(port, queueIndex); + addQueueFlexCountersPerPortPerQueueIndex(port, queueIndex, false); } } } -void PortsOrch::addQueueFlexCountersPerPortPerQueueIndex(const Port& port, size_t queueIndex) +void PortsOrch::addQueueFlexCountersPerPortPerQueueIndex(const Port& port, size_t queueIndex, bool voq) { std::unordered_set counter_stats; + std::vector queue_ids; + for (const auto& it: queue_stat_ids) { counter_stats.emplace(sai_serialize_queue_stat(it)); } - queue_stat_manager.setCounterIdList(port.m_queue_ids[queueIndex], CounterType::QUEUE, counter_stats); + if (voq) + { + queue_ids = m_port_voq_ids[port.m_alias]; + } + else + { + queue_ids = port.m_queue_ids; + } + + queue_stat_manager.setCounterIdList(queue_ids[queueIndex], CounterType::QUEUE, counter_stats); } @@ -6344,7 +6365,7 @@ void PortsOrch::createPortBufferQueueCounters(const Port &port, string queues) if (flexCounterOrch->getQueueCountersState()) { // Install a flex counter for this queue to track stats - addQueueFlexCountersPerPortPerQueueIndex(port, queueIndex); + addQueueFlexCountersPerPortPerQueueIndex(port, queueIndex, false); } if (flexCounterOrch->getQueueWatermarkCountersState()) { diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index a5982debd7..9d376d3ae7 100644 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -387,7 +387,7 @@ class PortsOrch : public Orch, public Subject void generateQueueMapPerPort(const Port& port, FlexCounterQueueStates& queuesState, bool voq); bool m_isQueueFlexCountersAdded = false; void addQueueFlexCountersPerPort(const Port& port, FlexCounterQueueStates& queuesState); - void addQueueFlexCountersPerPortPerQueueIndex(const Port& port, size_t queueIndex); + void addQueueFlexCountersPerPortPerQueueIndex(const Port& port, size_t queueIndex, bool voq); bool m_isQueueWatermarkFlexCountersAdded = false; void addQueueWatermarkFlexCountersPerPort(const Port& port, FlexCounterQueueStates& queuesState); diff --git a/orchagent/qosorch.cpp b/orchagent/qosorch.cpp index 515d591e00..f10b44f58c 100644 --- a/orchagent/qosorch.cpp +++ b/orchagent/qosorch.cpp @@ -58,6 +58,8 @@ map qos_to_attr_map = { {mpls_tc_to_tc_field_name, SAI_PORT_ATTR_QOS_MPLS_EXP_TO_TC_MAP}, {dot1p_to_tc_field_name, SAI_PORT_ATTR_QOS_DOT1P_TO_TC_MAP}, {tc_to_queue_field_name, SAI_PORT_ATTR_QOS_TC_TO_QUEUE_MAP}, + {tc_to_dot1p_field_name, SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DOT1P_MAP}, + {tc_to_dscp_field_name, SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DSCP_MAP}, {tc_to_pg_map_field_name, SAI_PORT_ATTR_QOS_TC_TO_PRIORITY_GROUP_MAP}, {pfc_to_pg_map_name, SAI_PORT_ATTR_QOS_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP}, {pfc_to_queue_map_name, SAI_PORT_ATTR_QOS_PFC_PRIORITY_TO_QUEUE_MAP}, @@ -85,6 +87,7 @@ type_map QosOrch::m_qos_maps = { {CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, new object_reference_map()}, {CFG_DSCP_TO_FC_MAP_TABLE_NAME, new object_reference_map()}, {CFG_EXP_TO_FC_MAP_TABLE_NAME, new object_reference_map()}, + {CFG_TC_TO_DOT1P_MAP_TABLE_NAME, new object_reference_map()}, {CFG_TC_TO_DSCP_MAP_TABLE_NAME, new object_reference_map()}, {APP_TUNNEL_DECAP_TABLE_NAME, new object_reference_map()} }; @@ -94,6 +97,8 @@ map qos_to_ref_table_map = { {mpls_tc_to_tc_field_name, CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME}, {dot1p_to_tc_field_name, CFG_DOT1P_TO_TC_MAP_TABLE_NAME}, {tc_to_queue_field_name, CFG_TC_TO_QUEUE_MAP_TABLE_NAME}, + {tc_to_dot1p_field_name, CFG_TC_TO_DOT1P_MAP_TABLE_NAME}, + {tc_to_dscp_field_name, CFG_TC_TO_DSCP_MAP_TABLE_NAME}, {tc_to_pg_map_field_name, CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME}, {pfc_to_pg_map_name, CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME}, {pfc_to_queue_map_name, CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME}, @@ -178,7 +183,7 @@ task_process_status QosMapHandler::processWorkItem(Consumer& consumer, KeyOpFiel } if (!removeQosItem(sai_object)) { - SWSS_LOG_ERROR("Failed to remove dscp_to_tc map. db name:%s sai object:%" PRIx64, qos_object_name.c_str(), sai_object); + SWSS_LOG_ERROR("Failed to remove QoS map. db name:%s sai object:%" PRIx64, qos_object_name.c_str(), sai_object); return task_process_status::task_failed; } auto it_to_delete = (QosOrch::getTypeMap()[qos_map_type_name])->find(qos_object_name); @@ -470,6 +475,60 @@ task_process_status QosOrch::handleTcToQueueTable(Consumer& consumer, KeyOpField return tc_queue_handler.processWorkItem(consumer, tuple); } +//Functions for TC-to-DOT1P qos map handling +bool TcToDot1pMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_attribute_t list_attr; + sai_qos_map_list_t tc_map_list; + tc_map_list.count = (uint32_t)kfvFieldsValues(tuple).size(); + tc_map_list.list = new sai_qos_map_t[tc_map_list.count](); + uint32_t ind = 0; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++, ind++) + { + tc_map_list.list[ind].key.tc = (uint8_t)stoi(fvField(*i)); + tc_map_list.list[ind].value.dot1p = (uint8_t)stoi(fvValue(*i)); + } + list_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + list_attr.value.qosmap.count = tc_map_list.count; + list_attr.value.qosmap.list = tc_map_list.list; + attributes.push_back(list_attr); + return true; +} + +sai_object_id_t TcToDot1pMapHandler::addQosItem(const vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object; + vector qos_map_attrs; + sai_attribute_t qos_map_attr; + + qos_map_attr.id = SAI_QOS_MAP_ATTR_TYPE; + qos_map_attr.value.s32 = SAI_QOS_MAP_TYPE_TC_AND_COLOR_TO_DOT1P; + qos_map_attrs.push_back(qos_map_attr); + + qos_map_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + qos_map_attr.value.qosmap.count = attributes[0].value.qosmap.count; + qos_map_attr.value.qosmap.list = attributes[0].value.qosmap.list; + qos_map_attrs.push_back(qos_map_attr); + + sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create tc_to_dot1p qos map. status:%d", sai_status); + return SAI_NULL_OBJECT_ID; + } + return sai_object; +} + +task_process_status QosOrch::handleTcToDot1pTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple) +{ + SWSS_LOG_ENTER(); + TcToDot1pMapHandler tc_dot1p_handler; + return tc_dot1p_handler.processWorkItem(consumer, tuple); +} + void WredMapHandler::freeAttribResources(vector &attributes) { SWSS_LOG_ENTER(); @@ -857,7 +916,7 @@ sai_object_id_t TcToPgHandler::addQosItem(const vector &attribu sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); if (SAI_STATUS_SUCCESS != sai_status) { - SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + SWSS_LOG_ERROR("Failed to create tc_to_pg map. status:%d", sai_status); return SAI_NULL_OBJECT_ID; } return sai_object; @@ -911,7 +970,7 @@ sai_object_id_t PfcPrioToPgHandler::addQosItem(const vector &at sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); if (SAI_STATUS_SUCCESS != sai_status) { - SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + SWSS_LOG_ERROR("Failed to create pfc_priority_to_queue map. status:%d", sai_status); return SAI_NULL_OBJECT_ID; } return sai_object; @@ -966,7 +1025,7 @@ sai_object_id_t PfcToQueueHandler::addQosItem(const vector &att sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); if (SAI_STATUS_SUCCESS != sai_status) { - SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + SWSS_LOG_ERROR("Failed to create pfc_priority_to_queue map. status:%d", sai_status); return SAI_NULL_OBJECT_ID; } return sai_object; @@ -1274,6 +1333,7 @@ void QosOrch::initTableHandlers() m_qos_handler_map.insert(qos_handler_pair(CFG_DSCP_TO_FC_MAP_TABLE_NAME, &QosOrch::handleDscpToFcTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_EXP_TO_FC_MAP_TABLE_NAME, &QosOrch::handleExpToFcTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_DSCP_MAP_TABLE_NAME, &QosOrch::handleTcToDscpTable)); + m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_DOT1P_MAP_TABLE_NAME, &QosOrch::handleTcToDot1pTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, &QosOrch::handleTcToPgTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME, &QosOrch::handlePfcPrioToPgTable)); diff --git a/orchagent/qosorch.h b/orchagent/qosorch.h index f677e68a01..8079e45bc0 100644 --- a/orchagent/qosorch.h +++ b/orchagent/qosorch.h @@ -17,6 +17,8 @@ const string pfc_enable_name = "pfc_enable"; const string pfcwd_sw_enable_name = "pfcwd_sw_enable"; const string tc_to_pg_map_field_name = "tc_to_pg_map"; const string tc_to_queue_field_name = "tc_to_queue_map"; +const string tc_to_dot1p_field_name = "tc_to_dot1p_map"; +const string tc_to_dscp_field_name = "tc_to_dscp_map"; const string scheduler_field_name = "scheduler"; const string red_max_threshold_field_name = "red_max_threshold"; const string red_min_threshold_field_name = "red_min_threshold"; @@ -175,6 +177,13 @@ class TcToDscpMapHandler : public QosMapHandler sai_object_id_t addQosItem(const vector &attributes) override; }; +class TcToDot1pMapHandler : public QosMapHandler +{ +public: + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes); + sai_object_id_t addQosItem(const vector &attributes); +}; + class QosOrch : public Orch { public: @@ -209,6 +218,7 @@ class QosOrch : public Orch task_process_status handleDscpToFcTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); task_process_status handleExpToFcTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); task_process_status handleTcToDscpTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); + task_process_status handleTcToDot1pTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); task_process_status handleGlobalQosMap(const string &op, KeyOpFieldsValuesTuple &tuple); diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index e92cbb51b1..f4b92e60ae 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -684,6 +684,8 @@ void RouteOrch::doTask(Consumer& consumer) NextHopGroupKey& nhg = ctx.nhg; vector srv6_segv; vector srv6_src; + bool l3Vni = true; + uint32_t vni = 0; /* Check if the next hop group is owned by the NhgOrch. */ if (nhg_index.empty()) @@ -715,6 +717,23 @@ void RouteOrch::doTask(Consumer& consumer) ipv.resize(alsv.size()); } + for (auto &vni_str: vni_labelv) + { + vni = static_cast(std::stoul(vni_str)); + if (!m_vrfOrch->isL3VniVlan(vni)) + { + SWSS_LOG_WARN("Route %s is received on non L3 VNI %s", key.c_str(), vni_str.c_str()); + l3Vni = false; + break; + } + } + + if (!l3Vni) + { + it++; + continue; + } + /* Set the empty ip(s) to zero * as IpAddress("") will construct a incorrect ip. */ for (auto &ip : ipv) diff --git a/orchagent/srv6orch.cpp b/orchagent/srv6orch.cpp index 3d81163b2a..7aced45d27 100644 --- a/orchagent/srv6orch.cpp +++ b/orchagent/srv6orch.cpp @@ -52,6 +52,14 @@ const map end_flavor_map = {"ua", SAI_MY_SID_ENTRY_ENDPOINT_BEHAVIOR_FLAVOR_PSP_AND_USD} }; +const map sidlist_type_map = +{ + {"insert", SAI_SRV6_SIDLIST_TYPE_INSERT}, + {"insert.red", SAI_SRV6_SIDLIST_TYPE_INSERT_RED}, + {"encaps", SAI_SRV6_SIDLIST_TYPE_ENCAPS}, + {"encaps.red", SAI_SRV6_SIDLIST_TYPE_ENCAPS_RED} +}; + void Srv6Orch::srv6TunnelUpdateNexthops(const string srv6_source, const NextHopKey nhkey, bool insert) { if (insert) @@ -267,7 +275,7 @@ bool Srv6Orch::srv6Nexthops(const NextHopGroupKey &nhgKey, sai_object_id_t &next return true; } -bool Srv6Orch::createUpdateSidList(const string sid_name, const string sid_list) +bool Srv6Orch::createUpdateSidList(const string sid_name, const string sid_list, const string sidlist_type) { SWSS_LOG_ENTER(); bool exists = (sid_table_.find(sid_name) != sid_table_.end()); @@ -303,7 +311,16 @@ bool Srv6Orch::createUpdateSidList(const string sid_name, const string sid_list) attributes.push_back(attr); attr.id = SAI_SRV6_SIDLIST_ATTR_TYPE; - attr.value.s32 = SAI_SRV6_SIDLIST_TYPE_ENCAPS_RED; + if (sidlist_type_map.find(sidlist_type) == sidlist_type_map.end()) + { + SWSS_LOG_INFO("Use default sidlist type: ENCAPS_RED"); + attr.value.s32 = SAI_SRV6_SIDLIST_TYPE_ENCAPS_RED; + } + else + { + SWSS_LOG_INFO("sidlist type: %s", sidlist_type.c_str()); + attr.value.s32 = sidlist_type_map.at(sidlist_type); + } attributes.push_back(attr); status = sai_srv6_api->create_srv6_sidlist(&segment_oid, gSwitchId, (uint32_t) attributes.size(), attributes.data()); if (status != SAI_STATUS_SUCCESS) @@ -365,7 +382,7 @@ void Srv6Orch::doTaskSidTable(const KeyOpFieldsValuesTuple & tuple) SWSS_LOG_ENTER(); string sid_name = kfvKey(tuple); string op = kfvOp(tuple); - string sid_list; + string sid_list, sidlist_type; for (auto i : kfvFieldsValues(tuple)) { @@ -373,10 +390,14 @@ void Srv6Orch::doTaskSidTable(const KeyOpFieldsValuesTuple & tuple) { sid_list = fvValue(i); } + if (fvField(i) == "type") + { + sidlist_type = fvValue(i); + } } if (op == SET_COMMAND) { - if (!createUpdateSidList(sid_name, sid_list)) + if (!createUpdateSidList(sid_name, sid_list, sidlist_type)) { SWSS_LOG_ERROR("Failed to process sid %s", sid_name.c_str()); } diff --git a/orchagent/srv6orch.h b/orchagent/srv6orch.h index 989737a998..e24f5e00f5 100644 --- a/orchagent/srv6orch.h +++ b/orchagent/srv6orch.h @@ -76,7 +76,7 @@ class Srv6Orch : public Orch void doTask(Consumer &consumer); void doTaskSidTable(const KeyOpFieldsValuesTuple &tuple); void doTaskMySidTable(const KeyOpFieldsValuesTuple &tuple); - bool createUpdateSidList(const string seg_name, const string ips); + bool createUpdateSidList(const string seg_name, const string ips, const string sidlist_type); bool deleteSidList(const string seg_name); bool createSrv6Tunnel(const string srv6_source); bool createSrv6Nexthop(const NextHopKey &nh); diff --git a/orchagent/vxlanorch.cpp b/orchagent/vxlanorch.cpp index ab8e10c512..1983cf7286 100644 --- a/orchagent/vxlanorch.cpp +++ b/orchagent/vxlanorch.cpp @@ -2376,6 +2376,13 @@ bool EvpnRemoteVnip2pOrch::addOperation(const Request& request) return false; } + VRFOrch* vrf_orch = gDirectory.get(); + if (vrf_orch->isL3VniVlan(vni_id)) + { + SWSS_LOG_WARN("Ignoring remote VNI add for L3 VNI:%d, remote:%s", vni_id, remote_vtep.c_str()); + return false; + } + if (tunnel_orch->getTunnelPort(remote_vtep,tunnelPort)) { SWSS_LOG_INFO("Vxlan tunnelPort exists: %s", remote_vtep.c_str()); @@ -2531,6 +2538,13 @@ bool EvpnRemoteVnip2mpOrch::addOperation(const Request& request) return false; } + VRFOrch* vrf_orch = gDirectory.get(); + if (vrf_orch->isL3VniVlan(vni_id)) + { + SWSS_LOG_WARN("Ignoring remote VNI add for L3 VNI:%d, remote:%s", vni_id, end_point_ip.c_str()); + return false; + } + auto src_vtep = vtep_ptr->getSrcIP().to_string(); if (tunnel_orch->getTunnelPort(src_vtep,tunnelPort, true)) { diff --git a/tests/evpn_tunnel.py b/tests/evpn_tunnel.py index 774a3b3960..90ddde6279 100644 --- a/tests/evpn_tunnel.py +++ b/tests/evpn_tunnel.py @@ -723,6 +723,17 @@ def check_vlan_extension_delete_p2mp(self, dvs, vlan_name, sip, dip): status, fvs = tbl.get(self.l2mcgroup_member_map[dip+vlan_name]) assert status == False, "L2MC Group Member entry not deleted" + def check_vlan_obj(self, dvs, vlan_name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + expected_vlan_attributes = { + 'SAI_VLAN_ATTR_VLAN_ID': vlan_name, + } + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN', expected_vlan_attributes) + assert len(ret) > 0, "VLAN entry not created" + assert len(ret) == 1, "More than 1 VLAN entry created" + + self.vlan_id_map[vlan_name] = ret[0] + def check_vlan_extension(self, dvs, vlan_name, dip): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) expected_vlan_attributes = { @@ -743,6 +754,25 @@ def check_vlan_extension(self, dvs, vlan_name, dip): assert len(ret) == 1, "More than 1 VLAN member created" self.vlan_member_map[dip+vlan_name] = ret[0] + def check_vlan_extension_not_created(self, dvs, vlan_name, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + expected_vlan_attributes = { + 'SAI_VLAN_ATTR_VLAN_ID': vlan_name, + } + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN', expected_vlan_attributes) + assert len(ret) > 0, "VLAN entry not created" + assert len(ret) == 1, "More than 1 VLAN entry created" + + self.vlan_id_map[vlan_name] = ret[0] + + if dip in self.bridgeport_map: + expected_vlan_member_attributes = { + 'SAI_VLAN_MEMBER_ATTR_VLAN_ID': self.vlan_id_map[vlan_name], + 'SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID': self.bridgeport_map[dip], + } + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER', expected_vlan_member_attributes) + assert len(ret) == 0, "VLAN member created" + def check_vlan_extension_p2mp(self, dvs, vlan_name, sip, dip): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN') @@ -986,6 +1016,27 @@ def check_vrf_routes(self, dvs, prefix, vrf_name, endpoint, tunnel, mac="", vni= return True + def check_vrf_routes_absence(self, dvs, prefix, vrf_name, endpoint, tunnel, mac="", vni=0, no_update=0): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + vr_ids = self.vrf_route_ids(dvs, vrf_name) + count = len(vr_ids) + + # Check routes in ingress VRF + expected_attr = { + "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", + "SAI_NEXT_HOP_ATTR_IP": endpoint, + "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], + } + + if vni: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni}) + + if mac: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac}) + + self.helper.get_created_entries(asic_db, self.ASIC_NEXT_HOP, self.nhops, 0) + def check_vrf_routes_ecmp(self, dvs, prefix, vrf_name, tunnel, nh_count, no_update=0): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 8adda0be11..ed996b098c 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -49,6 +49,7 @@ tests_SOURCES = aclorch_ut.cpp \ swssnet_ut.cpp \ flowcounterrouteorch_ut.cpp \ orchdaemon_ut.cpp \ + intfsorch_ut.cpp \ warmrestartassist_ut.cpp \ test_failure_handling.cpp \ $(top_srcdir)/lib/gearboxutils.cpp \ diff --git a/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp b/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp index d0f8954fd8..e6bd8bea1c 100644 --- a/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp +++ b/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp @@ -10,6 +10,7 @@ #define ETH0 "Ethernet0" #define VLAN40 "Vlan40" +#define VXLAN_REMOTE "Vxlan_1.1.1.1" extern redisReply *mockReply; extern CrmOrch* gCrmOrch; @@ -19,6 +20,28 @@ Test Fixture */ namespace fdb_syncd_flush_test { + + sai_fdb_api_t ut_sai_fdb_api; + sai_fdb_api_t *pold_sai_fdb_api; + + sai_status_t _ut_stub_sai_create_fdb_entry ( + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) + { + return SAI_STATUS_SUCCESS; + } + void _hook_sai_fdb_api() + { + ut_sai_fdb_api = *sai_fdb_api; + pold_sai_fdb_api = sai_fdb_api; + ut_sai_fdb_api.create_fdb_entry = _ut_stub_sai_create_fdb_entry; + sai_fdb_api = &ut_sai_fdb_api; + } + void _unhook_sai_fdb_api() + { + sai_fdb_api = pold_sai_fdb_api; + } struct FdbOrchTest : public ::testing::Test { std::shared_ptr m_config_db; @@ -40,7 +63,7 @@ namespace fdb_syncd_flush_test }; ut_helper::initSaiApi(profile); - + /* Create Switch */ sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; @@ -70,6 +93,8 @@ namespace fdb_syncd_flush_test // 2) Crmorch ASSERT_EQ(gCrmOrch, nullptr); gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); + VxlanTunnelOrch *vxlan_tunnel_orch_1 = new VxlanTunnelOrch(m_state_db.get(), m_app_db.get(), APP_VXLAN_TUNNEL_TABLE_NAME); + gDirectory.set(vxlan_tunnel_orch_1); // Construct fdborch vector app_fdb_tables = { @@ -91,7 +116,7 @@ namespace fdb_syncd_flush_test virtual void TearDown() override { delete gCrmOrch; gCrmOrch = nullptr; - + gDirectory.m_values.clear(); ut_helper::uninitSaiApi(); } }; @@ -126,6 +151,17 @@ namespace fdb_syncd_flush_test m_portsOrch->saiOidToAlias[oid] = alias; } + void setUpVxlanPort(PortsOrch* m_portsOrch){ + /* Updates portsOrch internal cache for Ethernet0 */ + std::string alias = VXLAN_REMOTE; + sai_object_id_t oid = 0x10000000004a5; + + Port port(alias, Port::PHY); + m_portsOrch->m_portList[alias] = port; + m_portsOrch->saiOidToAlias[oid] = alias; + } + + void setUpVlanMember(PortsOrch* m_portsOrch){ /* Updates portsOrch internal cache for adding Ethernet0 into Vlan40 */ sai_object_id_t bridge_port_id = 0x3a000000002c33; @@ -136,6 +172,16 @@ namespace fdb_syncd_flush_test m_portsOrch->m_portList[VLAN40].m_members.insert(ETH0); } + void setUpVxlanMember(PortsOrch* m_portsOrch){ + /* Updates portsOrch internal cache for adding Ethernet0 into Vlan40 */ + sai_object_id_t bridge_port_id = 0x3a000000002c34; + + /* Add Bridge Port */ + m_portsOrch->m_portList[VXLAN_REMOTE].m_bridge_port_id = bridge_port_id; + m_portsOrch->saiOidToAlias[bridge_port_id] = VXLAN_REMOTE; + m_portsOrch->m_portList[VLAN40].m_members.insert(VXLAN_REMOTE); + } + void triggerUpdate(FdbOrch* m_fdborch, sai_fdb_event_t type, vector mac_addr, @@ -146,7 +192,7 @@ namespace fdb_syncd_flush_test *(entry.mac_address+i) = mac_addr[i]; } entry.bv_id = bv_id; - m_fdborch->update(type, &entry, bridge_port_id); + m_fdborch->update(type, &entry, bridge_port_id, SAI_FDB_ENTRY_TYPE_DYNAMIC); } } @@ -445,4 +491,46 @@ namespace fdb_syncd_flush_test ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); } + + /* Test Consolidated Flush with origin VXLAN */ + TEST_F(FdbOrchTest, ConsolidatedFlushAllVxLAN) + { + _hook_sai_fdb_api(); + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpVxlanPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(VXLAN_REMOTE), m_portsOrch->m_portList.end()); + setUpVxlanMember(m_portsOrch.get()); + + FdbData fdbData; + fdbData.bridge_port_id = SAI_NULL_OBJECT_ID; + fdbData.type = "dynamic"; + fdbData.origin = FDB_ORIGIN_VXLAN_ADVERTIZED; + fdbData.remote_ip = "1.1.1.1"; + fdbData.esi = ""; + fdbData.vni = 100; + FdbEntry entry; + + MacAddress mac1 = MacAddress("52:54:00:ac:3a:99"); + entry.mac = mac1; + entry.port_name = VXLAN_REMOTE; + + entry.bv_id = m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid; + m_fdborch->addFdbEntry(entry, VXLAN_REMOTE, fdbData); + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[VXLAN_REMOTE].m_fdb_count, 1); + + /* Event2: Send a Consolidated Flush response from syncd */ + vector flush_mac_addr = {0, 0, 0, 0, 0, 0}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, SAI_NULL_OBJECT_ID, + SAI_NULL_OBJECT_ID); + + /* make sure fdb_counters are decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[VXLAN_REMOTE].m_fdb_count, 1); + _unhook_sai_fdb_api(); + } } diff --git a/tests/mock_tests/intfsorch_ut.cpp b/tests/mock_tests/intfsorch_ut.cpp new file mode 100644 index 0000000000..60041520bd --- /dev/null +++ b/tests/mock_tests/intfsorch_ut.cpp @@ -0,0 +1,330 @@ +#define private public // make Directory::m_values available to clean it. +#include "directory.h" +#undef private +#include "gtest/gtest.h" +#include "ut_helper.h" +#include "mock_orchagent_main.h" +#include "mock_table.h" +#include +#include + + + +namespace intfsorch_test +{ + using namespace std; + + int create_rif_count = 0; + int remove_rif_count = 0; + sai_router_interface_api_t *pold_sai_rif_api; + sai_router_interface_api_t ut_sai_rif_api; + + sai_status_t _ut_create_router_interface( + _Out_ sai_object_id_t *router_interface_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) + { + ++create_rif_count; + return SAI_STATUS_SUCCESS; + } + + sai_status_t _ut_remove_router_interface( + _In_ sai_object_id_t router_interface_id) + { + ++remove_rif_count; + return SAI_STATUS_SUCCESS; + } + + struct IntfsOrchTest : public ::testing::Test + { + shared_ptr m_app_db; + shared_ptr m_config_db; + shared_ptr m_state_db; + shared_ptr m_chassis_app_db; + + //sai_router_interface_api_t *old_sai_rif_api_ptr; + + //sai_create_router_interface_fn old_create_rif; + //sai_remove_router_interface_fn old_remove_rif; + void SetUp() override + { + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + ut_helper::initSaiApi(profile); + pold_sai_rif_api = sai_router_intfs_api; + ut_sai_rif_api = *sai_router_intfs_api; + sai_router_intfs_api = &ut_sai_rif_api; + + sai_router_intfs_api->create_router_interface = _ut_create_router_interface; + sai_router_intfs_api->remove_router_interface = _ut_remove_router_interface; + + m_app_db = make_shared("APPL_DB", 0); + m_config_db = make_shared("CONFIG_DB", 0); + m_state_db = make_shared("STATE_DB", 0); + m_chassis_app_db = make_shared("CHASSIS_APP_DB", 0); + + sai_attribute_t attr; + + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + auto status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + + + ASSERT_EQ(gCrmOrch, nullptr); + gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); + + TableConnector stateDbSwitchTable(m_state_db.get(), "SWITCH_CAPABILITY"); + TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME); + TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); + + vector switch_tables = { + conf_asic_sensors, + app_switch_table + }; + + ASSERT_EQ(gSwitchOrch, nullptr); + gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable); + + // Create dependencies ... + TableConnector stateDbBfdSessionTable(m_state_db.get(), STATE_BFD_SESSION_TABLE_NAME); + gBfdOrch = new BfdOrch(m_app_db.get(), APP_BFD_SESSION_TABLE_NAME, stateDbBfdSessionTable); + + const int portsorch_base_pri = 40; + vector ports_tables = { + { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } + }; + + vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + auto* flexCounterOrch = new FlexCounterOrch(m_config_db.get(), flex_counter_tables); + gDirectory.set(flexCounterOrch); + + ASSERT_EQ(gPortsOrch, nullptr); + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); + + vector vnet_tables = { + APP_VNET_RT_TABLE_NAME, + APP_VNET_RT_TUNNEL_TABLE_NAME + }; + + vector cfg_vnet_tables = { + CFG_VNET_RT_TABLE_NAME, + CFG_VNET_RT_TUNNEL_TABLE_NAME + }; + + auto* vnet_orch = new VNetOrch(m_app_db.get(), APP_VNET_TABLE_NAME); + gDirectory.set(vnet_orch); + auto* cfg_vnet_rt_orch = new VNetCfgRouteOrch(m_config_db.get(), m_app_db.get(), cfg_vnet_tables); + gDirectory.set(cfg_vnet_rt_orch); + auto* vnet_rt_orch = new VNetRouteOrch(m_app_db.get(), vnet_tables, vnet_orch); + gDirectory.set(vnet_rt_orch); + ASSERT_EQ(gVrfOrch, nullptr); + gVrfOrch = new VRFOrch(m_app_db.get(), APP_VRF_TABLE_NAME, m_state_db.get(), STATE_VRF_OBJECT_TABLE_NAME); + gDirectory.set(gVrfOrch); + + ASSERT_EQ(gIntfsOrch, nullptr); + gIntfsOrch = new IntfsOrch(m_app_db.get(), APP_INTF_TABLE_NAME, gVrfOrch, m_chassis_app_db.get()); + + const int fdborch_pri = 20; + + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} + }; + + TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + TableConnector stateMclagDbFdb(m_state_db.get(), STATE_MCLAG_REMOTE_FDB_TABLE_NAME); + ASSERT_EQ(gFdbOrch, nullptr); + gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); + + ASSERT_EQ(gNeighOrch, nullptr); + gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch, m_chassis_app_db.get()); + + auto* tunnel_decap_orch = new TunnelDecapOrch(m_app_db.get(), APP_TUNNEL_DECAP_TABLE_NAME); + vector mux_tables = { + CFG_MUX_CABLE_TABLE_NAME, + CFG_PEER_SWITCH_TABLE_NAME + }; + auto* mux_orch = new MuxOrch(m_config_db.get(), mux_tables, tunnel_decap_orch, gNeighOrch, gFdbOrch); + gDirectory.set(mux_orch); + + ASSERT_EQ(gFgNhgOrch, nullptr); + const int fgnhgorch_pri = 15; + + vector fgnhg_tables = { + { CFG_FG_NHG, fgnhgorch_pri }, + { CFG_FG_NHG_PREFIX, fgnhgorch_pri }, + { CFG_FG_NHG_MEMBER, fgnhgorch_pri } + }; + gFgNhgOrch = new FgNhgOrch(m_config_db.get(), m_app_db.get(), m_state_db.get(), fgnhg_tables, gNeighOrch, gIntfsOrch, gVrfOrch); + + ASSERT_EQ(gSrv6Orch, nullptr); + vector srv6_tables = { + APP_SRV6_SID_LIST_TABLE_NAME, + APP_SRV6_MY_SID_TABLE_NAME + }; + gSrv6Orch = new Srv6Orch(m_app_db.get(), srv6_tables, gSwitchOrch, gVrfOrch, gNeighOrch); + + // Start FlowCounterRouteOrch + static const vector route_pattern_tables = { + CFG_FLOW_COUNTER_ROUTE_PATTERN_TABLE_NAME, + }; + gFlowCounterRouteOrch = new FlowCounterRouteOrch(m_config_db.get(), route_pattern_tables); + + ASSERT_EQ(gRouteOrch, nullptr); + const int routeorch_pri = 5; + vector route_tables = { + { APP_ROUTE_TABLE_NAME, routeorch_pri }, + { APP_LABEL_ROUTE_TABLE_NAME, routeorch_pri } + }; + gRouteOrch = new RouteOrch(m_app_db.get(), route_tables, gSwitchOrch, gNeighOrch, gIntfsOrch, gVrfOrch, gFgNhgOrch, gSrv6Orch); + gNhgOrch = new NhgOrch(m_app_db.get(), APP_NEXTHOP_GROUP_TABLE_NAME); + + // Recreate buffer orch to read populated data + vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME }; + + gBufferOrch = new BufferOrch(m_app_db.get(), m_config_db.get(), m_state_db.get(), buffer_tables); + + Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate pot table with SAI ports + for (const auto &it : ports) + { + portTable.set(it.first, it.second); + } + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + } + + void TearDown() override + { + gDirectory.m_values.clear(); + + delete gCrmOrch; + gCrmOrch = nullptr; + + delete gSwitchOrch; + gSwitchOrch = nullptr; + + delete gBfdOrch; + gBfdOrch = nullptr; + + delete gNeighOrch; + gNeighOrch = nullptr; + + delete gFdbOrch; + gFdbOrch = nullptr; + + delete gPortsOrch; + gPortsOrch = nullptr; + + delete gIntfsOrch; + gIntfsOrch = nullptr; + + delete gFgNhgOrch; + gFgNhgOrch = nullptr; + + delete gSrv6Orch; + gSrv6Orch = nullptr; + + delete gRouteOrch; + gRouteOrch = nullptr; + + delete gNhgOrch; + gNhgOrch = nullptr; + + delete gBufferOrch; + gBufferOrch = nullptr; + + delete gVrfOrch; + gVrfOrch = nullptr; + + delete gFlowCounterRouteOrch; + gFlowCounterRouteOrch = nullptr; + + sai_router_intfs_api = pold_sai_rif_api; + ut_helper::uninitSaiApi(); + } + }; + + TEST_F(IntfsOrchTest, IntfsOrchDeleteCreateRetry) + { + // create a interface + std::deque entries; + entries.push_back({"Ethernet0", "SET", { {"mtu", "9100"}}}); + auto consumer = dynamic_cast(gIntfsOrch->getExecutor(APP_INTF_TABLE_NAME)); + consumer->addToSync(entries); + auto current_create_count = create_rif_count; + static_cast(gIntfsOrch)->doTask(); + ASSERT_EQ(current_create_count + 1, create_rif_count); + + // create dependency to the interface + gIntfsOrch->increaseRouterIntfsRefCount("Ethernet0"); + + // delete the interface, expect retry because dependency exists + entries.clear(); + entries.push_back({"Ethernet0", "DEL", { {} }}); + consumer = dynamic_cast(gIntfsOrch->getExecutor(APP_INTF_TABLE_NAME)); + consumer->addToSync(entries); + auto current_remove_count = remove_rif_count; + static_cast(gIntfsOrch)->doTask(); + ASSERT_EQ(current_remove_count, remove_rif_count); + + // create the interface again, expect retry because interface is in removing + entries.clear(); + entries.push_back({"Ethernet0", "SET", { {"mtu", "9100"}}}); + consumer = dynamic_cast(gIntfsOrch->getExecutor(APP_INTF_TABLE_NAME)); + consumer->addToSync(entries); + current_create_count = create_rif_count; + static_cast(gIntfsOrch)->doTask(); + ASSERT_EQ(current_create_count, create_rif_count); + + // remove the dependency, expect delete and create a new one + gIntfsOrch->decreaseRouterIntfsRefCount("Ethernet0"); + current_create_count = create_rif_count; + current_remove_count = remove_rif_count; + static_cast(gIntfsOrch)->doTask(); + ASSERT_EQ(current_create_count + 1, create_rif_count); + ASSERT_EQ(current_remove_count + 1, remove_rif_count); + } +} \ No newline at end of file diff --git a/tests/mock_tests/mock_orchagent_main.h b/tests/mock_tests/mock_orchagent_main.h index f378a53de8..0d4865ac3d 100644 --- a/tests/mock_tests/mock_orchagent_main.h +++ b/tests/mock_tests/mock_orchagent_main.h @@ -82,3 +82,4 @@ extern sai_udf_api_t* sai_udf_api; extern sai_mpls_api_t* sai_mpls_api; extern sai_counter_api_t* sai_counter_api; extern sai_samplepacket_api_t *sai_samplepacket_api; +extern sai_fdb_api_t* sai_fdb_api; diff --git a/tests/mock_tests/mock_sai_bridge.h b/tests/mock_tests/mock_sai_bridge.h new file mode 100644 index 0000000000..8141ca66bb --- /dev/null +++ b/tests/mock_tests/mock_sai_bridge.h @@ -0,0 +1,34 @@ +// Define classes and functions to mock SAI bridge functions. +#pragma once + +#include + +extern "C" +{ +#include "sai.h" +} + +// Mock class including mock functions mapping to SAI bridge functions. +class MockSaiBridge +{ + public: + MOCK_METHOD4(create_bridge_port, sai_status_t(sai_object_id_t *bridge_port_id, + sai_object_id_t switch_id, + uint32_t attr_count, + const sai_attribute_t *attr_list)); +}; + +// Note that before mock functions below are used, mock_sai_bridge must be +// initialized to point to an instance of MockSaiBridge. +MockSaiBridge *mock_sai_bridge; + +sai_status_t mock_create_bridge_port(sai_object_id_t *bridge_port_id, + sai_object_id_t switch_id, + uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_bridge->create_bridge_port(bridge_port_id, switch_id, attr_count, attr_list); +} + + + diff --git a/tests/mock_tests/orchdaemon_ut.cpp b/tests/mock_tests/orchdaemon_ut.cpp index ab3e4a226c..3a2d2169f8 100644 --- a/tests/mock_tests/orchdaemon_ut.cpp +++ b/tests/mock_tests/orchdaemon_ut.cpp @@ -39,7 +39,7 @@ namespace orchdaemon_test ~OrchDaemonTest() { - + sai_switch_api = nullptr; }; }; diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index 740744df51..6700bb1caa 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -7,6 +7,7 @@ #include "mock_orchagent_main.h" #include "mock_table.h" #include "notifier.h" +#include "mock_sai_bridge.h" #define private public #include "pfcactionhandler.h" #include @@ -15,6 +16,8 @@ #include extern redisReply *mockReply; +using ::testing::_; +using ::testing::StrictMock; namespace portsorch_test { @@ -151,6 +154,21 @@ namespace portsorch_test sai_queue_api = pold_sai_queue_api; } + sai_bridge_api_t ut_sai_bridge_api; + sai_bridge_api_t *org_sai_bridge_api; + + void _hook_sai_bridge_api() + { + ut_sai_bridge_api = *sai_bridge_api; + org_sai_bridge_api = sai_bridge_api; + sai_bridge_api = &ut_sai_bridge_api; + } + + void _unhook_sai_bridge_api() + { + sai_bridge_api = org_sai_bridge_api; + } + struct PortsOrchTest : public ::testing::Test { shared_ptr m_app_db; @@ -345,6 +363,48 @@ namespace portsorch_test ASSERT_FALSE(gPortsOrch->getPort(port.m_port_id, port)); } + /** + * Test case: PortsOrch::addBridgePort() does not add router port to .1Q bridge + */ + TEST_F(PortsOrchTest, addBridgePortOnRouterPort) + { + _hook_sai_bridge_api(); + + StrictMock mock_sai_bridge_; + mock_sai_bridge = &mock_sai_bridge_; + sai_bridge_api->create_bridge_port = mock_create_bridge_port; + + Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate port table with SAI ports + for (const auto &it : ports) + { + portTable.set(it.first, it.second); + } + + // Set PortConfigDone, PortInitDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + portTable.set("PortInitDone", { { "lanes", "0" } }); + + // refill consumer + gPortsOrch->addExistingData(&portTable); + // Apply configuration : create ports + static_cast(gPortsOrch)->doTask(); + + // Get first port and set its rif id to simulate it is router port + Port port; + gPortsOrch->getPort("Ethernet0", port); + port.m_rif_id = 1; + + ASSERT_FALSE(gPortsOrch->addBridgePort(port)); + EXPECT_CALL(mock_sai_bridge_, create_bridge_port(_, _, _, _)).Times(0); + + _unhook_sai_bridge_api(); + } + TEST_F(PortsOrchTest, PortSupportedFecModes) { _hook_sai_port_api(); diff --git a/tests/mock_tests/test_failure_handling.cpp b/tests/mock_tests/test_failure_handling.cpp index be53e0fd5f..7381f4015e 100644 --- a/tests/mock_tests/test_failure_handling.cpp +++ b/tests/mock_tests/test_failure_handling.cpp @@ -28,8 +28,15 @@ namespace saifailure_test void _hook_sai_switch_api() { + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + ut_helper::initSaiApi(profile); ut_sai_switch_api = *sai_switch_api; pold_sai_switch_api = sai_switch_api; + ut_sai_switch_api.set_switch_attribute = _ut_stub_sai_set_switch_attribute; sai_switch_api = &ut_sai_switch_api; } @@ -37,6 +44,7 @@ namespace saifailure_test void _unhook_sai_switch_api() { sai_switch_api = pold_sai_switch_api; + ut_helper::uninitSaiApi(); } TEST_F(SaiFailureTest, handleSaiFailure) @@ -44,6 +52,7 @@ namespace saifailure_test _hook_sai_switch_api(); _sai_syncd_notifications_count = (uint32_t*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + _sai_syncd_notification_event = (int32_t*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *_sai_syncd_notifications_count = 0; diff --git a/tests/mock_tests/ut_saihelper.cpp b/tests/mock_tests/ut_saihelper.cpp index 40594cc32c..b871a2c137 100644 --- a/tests/mock_tests/ut_saihelper.cpp +++ b/tests/mock_tests/ut_saihelper.cpp @@ -86,6 +86,7 @@ namespace ut_helper sai_api_query(SAI_API_QUEUE, (void **)&sai_queue_api); sai_api_query(SAI_API_MPLS, (void**)&sai_mpls_api); sai_api_query(SAI_API_COUNTER, (void**)&sai_counter_api); + sai_api_query(SAI_API_FDB, (void**)&sai_fdb_api); return SAI_STATUS_SUCCESS; } diff --git a/tests/test_bfd.py b/tests/test_bfd.py index 3a087e2011..5add329278 100644 --- a/tests/test_bfd.py +++ b/tests/test_bfd.py @@ -49,7 +49,7 @@ def test_addRemoveBfdSession(self, dvs): bfdSessions = self.get_exist_bfd_session() # Create BFD session - fieldValues = {"local_addr": "10.0.0.1"} + fieldValues = {"local_addr": "10.0.0.1","tos":"64"} self.create_bfd_session("default:default:10.0.0.2", fieldValues) self.adb.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_BFD_SESSION", len(bfdSessions) + 1) @@ -62,6 +62,7 @@ def test_addRemoveBfdSession(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "64", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4" } self.check_asic_bfd_session_value(session, expected_adb_values) @@ -102,6 +103,7 @@ def test_addRemoveBfdSession_ipv6(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "2000::1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "2000::2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "6" } self.check_asic_bfd_session_value(session, expected_adb_values) @@ -142,6 +144,7 @@ def test_addRemoveBfdSession_interface(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4", "SAI_BFD_SESSION_ATTR_HW_LOOKUP_VALID": "false", "SAI_BFD_SESSION_ATTR_DST_MAC_ADDRESS": "00:02:03:04:05:06" @@ -184,6 +187,7 @@ def test_addRemoveBfdSession_txrx_interval(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4", "SAI_BFD_SESSION_ATTR_MIN_TX": "300000", "SAI_BFD_SESSION_ATTR_MIN_RX": "500000", @@ -226,6 +230,7 @@ def test_addRemoveBfdSession_multiplier(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4", "SAI_BFD_SESSION_ATTR_MULTIPLIER": "5" } @@ -267,6 +272,7 @@ def test_addRemoveBfdSession_multihop(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4", "SAI_BFD_SESSION_ATTR_MULTIHOP": "true" } @@ -308,6 +314,7 @@ def test_addRemoveBfdSession_type(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_DEMAND_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4" } self.check_asic_bfd_session_value(session, expected_adb_values) @@ -350,6 +357,7 @@ def test_multipleBfdSessions(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.0.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4" } self.check_asic_bfd_session_value(session1, expected_adb_values) @@ -376,6 +384,7 @@ def test_multipleBfdSessions(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "10.0.0.1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "10.0.1.2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "4", "SAI_BFD_SESSION_ATTR_MIN_TX": "300000", "SAI_BFD_SESSION_ATTR_MIN_RX": "500000", @@ -404,6 +413,7 @@ def test_multipleBfdSessions(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "2000::1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "2000::2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_DEMAND_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "6" } self.check_asic_bfd_session_value(session3, expected_adb_values) @@ -430,6 +440,7 @@ def test_multipleBfdSessions(self, dvs): "SAI_BFD_SESSION_ATTR_SRC_IP_ADDRESS": "3000::1", "SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS": "3000::2", "SAI_BFD_SESSION_ATTR_TYPE": "SAI_BFD_SESSION_TYPE_ASYNC_ACTIVE", + "SAI_BFD_SESSION_ATTR_TOS": "192", "SAI_BFD_SESSION_ATTR_IPHDR_VERSION": "6" } self.check_asic_bfd_session_value(session4, expected_adb_values) diff --git a/tests/test_evpn_l3_vxlan.py b/tests/test_evpn_l3_vxlan.py index deb5f00fbd..be5e1791d4 100644 --- a/tests/test_evpn_l3_vxlan.py +++ b/tests/test_evpn_l3_vxlan.py @@ -35,6 +35,7 @@ def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): print ("\n\nTesting Create and Delete SIP Tunnel and VRF VNI Map entries") print ("\tCreate SIP Tunnel") vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.check_vlan_obj(dvs, "100") vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) @@ -97,7 +98,7 @@ def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): # Test 2 - Create and Delete DIP Tunnel on adding and removing prefix route # @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") # @pytest.mark.dev_sanity - def test_prefix_route_create_dip_tunnel(self, dvs, testlog): + def test_prefix_route_create_tunnel(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() helper = self.get_vxlan_helper() @@ -161,17 +162,11 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') - print ("\tTesting DIP tunnel 7.7.7.7 creation") - vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') - print ("\tTest VRF IPv4 Route with Tunnel Nexthop Delete") vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') - print ("\tTesting DIP tunnel 7.7.7.7 deletion") - vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') - print ("\tTesting Tunnel Vrf Map Entry removal") vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') @@ -198,7 +193,7 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): # Test 3 - Create and Delete DIP Tunnel and Test IPv4 route and overlay nexthop add and delete # @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") # @pytest.mark.dev_sanity - def test_dip_tunnel_ipv4_routes(self, dvs, testlog): + def test_tunnel_ipv4_routes(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() helper = self.get_vxlan_helper() @@ -211,6 +206,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\n\nTesting IPv4 Route and Overlay Nexthop Add and Delete") print ("\tCreate SIP Tunnel") vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.check_vlan_obj(dvs, "100") vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) @@ -252,21 +248,6 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting First DIP tunnel creation to 7.7.7.7") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') - vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') - - print ("\tTesting VLAN 100 extension") - vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') - - print ("\tTesting Second DIP tunnel creation to 8.8.8.8") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') - vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '8.8.8.8') - - print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") - vxlan_obj.check_vlan_extension(dvs, '100', '8.8.8.8') - vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') - print ("\tTesting VLAN 100 interface creation") vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vxlan_obj.vlan_id_map['100'], 2) @@ -373,16 +354,6 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting LastVlan removal and DIP tunnel delete for 7.7.7.7") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') - vxlan_obj.check_vlan_extension_delete(dvs, '100', '7.7.7.7') - vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') - - print ("\tTesting LastVlan removal and DIP tunnel delete for 8.8.8.8") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') - vxlan_obj.check_vlan_extension_delete(dvs, '100', '8.8.8.8') - vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '8.8.8.8') - print ("\tTesting Vlan 100 interface delete") vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") vxlan_obj.check_del_router_interface(dvs, "Vlan100") @@ -405,7 +376,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): # Test 4 - Create and Delete DIP Tunnel and Test IPv6 route and overlay nexthop add and delete # @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") # @pytest.mark.dev_sanity - def test_dip_tunnel_ipv6_routes(self, dvs, testlog): + def test_tunnel_ipv6_routes(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() helper = self.get_vxlan_helper() @@ -418,6 +389,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\n\nTesting IPv6 Route and Overlay Nexthop Add and Delete") print ("\tCreate SIP Tunnel") vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.check_vlan_obj(dvs, "100") vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) @@ -460,20 +432,6 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting First DIP tunnel creation to 7.7.7.7") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') - vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') - - print ("\tTesting VLAN 100 extension") - vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') - - print ("\tTesting Second DIP tunnel creation to 8.8.8.8") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') - vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '8.8.8.8') - - print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") - vxlan_obj.check_vlan_extension(dvs, '100', '8.8.8.8') - vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') vxlan_obj.fetch_exist_entries(dvs) print ("\tTesting VLAN 100 interface creation") @@ -582,16 +540,6 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting LastVlan removal and DIP tunnel delete for 7.7.7.7") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') - vxlan_obj.check_vlan_extension_delete(dvs, '100', '7.7.7.7') - vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') - - print ("\tTesting LastVlan removal and DIP tunnel delete for 8.8.8.8") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') - vxlan_obj.check_vlan_extension_delete(dvs, '100', '8.8.8.8') - vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '8.8.8.8') - print ("\tTesting Vlan 100 interface delete") vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "2001::8/64") vxlan_obj.check_del_router_interface(dvs, "Vlan100") diff --git a/tests/test_evpn_l3_vxlan_p2mp.py b/tests/test_evpn_l3_vxlan_p2mp.py index 47f0dcba27..f3041979eb 100644 --- a/tests/test_evpn_l3_vxlan_p2mp.py +++ b/tests/test_evpn_l3_vxlan_p2mp.py @@ -202,6 +202,7 @@ def test_remote_ipv4_routes(self, dvs, testlog): print ("\n\nTesting IPv4 Route and Overlay Nexthop Add and Delete") print ("\tCreate SIP Tunnel") vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.check_vlan_obj(dvs, "100") vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) @@ -243,19 +244,6 @@ def test_remote_ipv4_routes(self, dvs, testlog): print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting First Remote end point to 7.7.7.7") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') - - print ("\tTesting VLAN 100 extension") - vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') - - print ("\tTesting Second remote end point to 8.8.8.8") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') - - print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") - vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') - vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') - print ("\tTesting VLAN 100 interface creation") vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vxlan_obj.vlan_id_map['100'], 2) @@ -362,14 +350,6 @@ def test_remote_ipv4_routes(self, dvs, testlog): vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting LastVlan removal and remote end point delete for 7.7.7.7") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') - vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') - - print ("\tTesting LastVlan removal and remote end point delete for 8.8.8.8") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') - vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') - print ("\tTesting Vlan 100 interface delete") vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") vxlan_obj.check_del_router_interface(dvs, "Vlan100") @@ -405,6 +385,7 @@ def test_remote_ipv6_routes(self, dvs, testlog): print ("\n\nTesting IPv6 Route and Overlay Nexthop Add and Delete") print ("\tCreate SIP Tunnel") vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.check_vlan_obj(dvs, "100") vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) @@ -447,19 +428,6 @@ def test_remote_ipv6_routes(self, dvs, testlog): print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting First remote endpoint creation to 7.7.7.7") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') - - print ("\tTesting VLAN 100 extension") - vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') - - print ("\tTesting Second remote endpoint creation to 8.8.8.8") - vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') - - print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") - vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') - vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') - vxlan_obj.fetch_exist_entries(dvs) print ("\tTesting VLAN 100 interface creation") vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "2001::8/64") @@ -567,14 +535,6 @@ def test_remote_ipv6_routes(self, dvs, testlog): vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') - print ("\tTesting LastVlan removal and remote endpoint delete for 7.7.7.7") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') - vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') - - print ("\tTesting LastVlan removal and remote endpoint delete for 8.8.8.8") - vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') - vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') - print ("\tTesting Vlan 100 interface delete") vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "2001::8/64") vxlan_obj.check_del_router_interface(dvs, "Vlan100") @@ -593,6 +553,95 @@ def test_remote_ipv6_routes(self, dvs, testlog): vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") vxlan_obj.remove_vlan(dvs, "100") + def test_prefix_route_create_on_l2_vni(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() + + self.setup_db(dvs) + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + vrf_map_name = 'evpn_map_1000_Vrf-RED' + vxlan_obj.fetch_exist_entries(dvs) + + print ("\tCreate SIP Tunnel") + vlan_ids = vxlan_obj.helper.get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + vlan_oid = vxlan_obj.create_vlan(dvs,"Vlan100", vlan_ids) + vxlan_obj.check_vlan_obj(dvs, "100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + print ("\tCreate Vlan-VNI map") + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + print ("\tTesting VRF-VNI map in APP DB") + vxlan_obj.create_vrf(dvs, "Vrf-RED") + + vlanlist = ['100'] + vnilist = ['1000'] + + print ("\tTesting SIP Tunnel Creation") + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist, ignore_bp=False, tunnel_map_entry_count=1) + + print ("\tTesting VLAN 100 interface creation") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") + vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vlan_oid, 2) + + print ("\tTest if IPv4 Route with Tunnel Nexthop Add is not created") + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes_absence(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tCreate Vlan-VNI map and VRF-VNI map") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + exp_attrs = [ + ("vni", "1000"), + ] + exp_attr = {} + for an in range(len(exp_attrs)): + exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] + + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + + exp_attrs1 = [ + ("vni", "1000"), + ("vlan", "Vlan100"), + ] + exp_attr1 = {} + for an in range(len(exp_attrs1)): + exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] + + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + vxlan_obj.check_vxlan_tunnel_map_entry_removed(dvs, tunnel_name, vlanlist, vnilist) + vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') + print ("\tTest VRF IPv4 Route with Tunnel Nexthop Add") + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv4 Route with Tunnel Nexthop Delete") + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + + print ("\tTesting Tunnel Vrf Map Entry removal") + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting Vlan 100 interface delete") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") + vxlan_obj.check_del_router_interface(dvs, "Vlan100") + + print ("\tTesting Tunnel Map entry removal") + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting SIP Tunnel Deletion") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6', ignore_bp=False) + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying diff --git a/tests/test_evpn_tunnel.py b/tests/test_evpn_tunnel.py index 21313a6c93..86f5ad53f6 100644 --- a/tests/test_evpn_tunnel.py +++ b/tests/test_evpn_tunnel.py @@ -164,6 +164,9 @@ def test_p2mp_tunnel_with_dip(self, dvs, testlog): print("Testing SIP Tunnel Deletion") vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vlan(dvs, "100") + vxlan_obj.remove_vlan(dvs, "101") + vxlan_obj.remove_vlan(dvs, "102") def test_delayed_vlan_vni_map(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() @@ -207,3 +210,49 @@ def test_delayed_vlan_vni_map(self, dvs, testlog): vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vlan(dvs, "100") + vxlan_obj.remove_vlan(dvs, "101") + + def test_invalid_vlan_extension(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + map_name_1 = 'map_1001_101' + vlanlist = ['100'] + vnilist = ['1000'] + + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vlan1(dvs,"Vlan100") + + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist, tunnel_map_entry_count = 1) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + vxlan_obj.check_vlan_extension_not_created(dvs, '100', '7.7.7.7') + + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') + print("Testing VLAN 100 extension") + vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') + + print("Testing Vlan Extension removal") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete(dvs, '100', '7.7.7.7') + + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print("Testing SIP Tunnel Deletion") + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') diff --git a/tests/test_evpn_tunnel_p2mp.py b/tests/test_evpn_tunnel_p2mp.py index 4b52d69e20..bbbb786f9a 100644 --- a/tests/test_evpn_tunnel_p2mp.py +++ b/tests/test_evpn_tunnel_p2mp.py @@ -125,6 +125,9 @@ def test_vlan_extension(self, dvs, testlog): vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6', ignore_bp=False) + vxlan_obj.remove_vlan(dvs, "100") + vxlan_obj.remove_vlan(dvs, "101") + vxlan_obj.remove_vlan(dvs, "102") def test_delayed_vlan_vni_map(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() @@ -166,3 +169,48 @@ def test_delayed_vlan_vni_map(self, dvs, testlog): vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6', ignore_bp=False) + vxlan_obj.remove_vlan(dvs, "100") + vxlan_obj.remove_vlan(dvs, "101") + + def test_invalid_vlan_extension(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + map_name_1 = 'map_1001_101' + vlanlist = ['100'] + vnilist = ['1000'] + + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vlan1(dvs,"Vlan100") + + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist, ignore_bp=False, tunnel_map_entry_count = 1) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + vxlan_obj.check_vlan_extension_not_created_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + print("Testing VLAN 100 extension") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print("Testing Vlan Extension removal") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print("Testing SIP Tunnel Deletion") + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6', ignore_bp=False) diff --git a/tests/test_mux.py b/tests/test_mux.py index 6eda6af7e3..e0b7469877 100644 --- a/tests/test_mux.py +++ b/tests/test_mux.py @@ -1349,12 +1349,16 @@ def test_Route(self, dvs, dvs_route, testlog): self.create_and_test_route(appdb, asicdb, dvs, dvs_route) - def test_NH(self, dvs, dvs_route, intf_fdb_map, setup_peer_switch, setup_tunnel, testlog): + def test_NH(self, dvs, dvs_route, intf_fdb_map, setup, setup_mux_cable, + setup_peer_switch, setup_tunnel, testlog): """ test NH routes and mux state change """ appdb = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) asicdb = dvs.get_asic_db() mac = intf_fdb_map["Ethernet0"] + # get tunnel nexthop + self.check_tnl_nexthop_in_asic_db(asicdb) + self.create_and_test_NH_routes(appdb, asicdb, dvs, dvs_route, mac) def test_multi_nexthop(self, dvs, dvs_route, intf_fdb_map, neighbor_cleanup, testlog): @@ -1409,6 +1413,37 @@ def test_neighbor_miss( expected_mac=mac if exp_result[REAL_MAC] else '00:00:00:00:00:00' ) + def test_neighbor_miss_no_mux( + self, dvs, dvs_route, setup_vlan, setup_tunnel, setup, + setup_peer_switch, neighbor_cleanup, testlog + ): + config_db = dvs.get_config_db() + appdb = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + test_ip = self.SERV1_SOC_IPV4 + self.ping_ip(dvs, test_ip) + + # no mux present, no standalone tunnel route installed + self.check_neighbor_state(dvs, dvs_route, test_ip, expect_route=False) + + # setup the mux + config_db = dvs.get_config_db() + self.create_mux_cable(config_db) + # tunnel route should be installed immediately after mux setup + self.check_neighbor_state(dvs, dvs_route, test_ip, expect_route=True) + + # set port state as standby + self.set_mux_state(appdb, "Ethernet0", "standby") + self.check_neighbor_state(dvs, dvs_route, test_ip, expect_route=True) + + # set port state as active + self.set_mux_state(appdb, "Ethernet0", "active") + self.check_neighbor_state(dvs, dvs_route, test_ip, expect_route=True) + + # clear the FAILED neighbor + self.clear_neighbors(dvs) + self.check_neighbor_state(dvs, dvs_route, test_ip, expect_route=False) + def test_neighbor_miss_no_peer( self, dvs, dvs_route, setup_vlan, setup_mux_cable, setup_tunnel, remove_peer_switch, neighbor_cleanup, testlog diff --git a/tests/test_qos_map.py b/tests/test_qos_map.py index 39c6c717ca..905b0dacaa 100644 --- a/tests/test_qos_map.py +++ b/tests/test_qos_map.py @@ -3,6 +3,32 @@ from swsscommon import swsscommon +CFG_TC_TO_DSCP_MAP_TABLE_NAME = "TC_TO_DSCP_MAP" +CFG_TC_TO_DSCP_MAP_KEY = "AZURE" +TC_TO_DSCP_MAP = { + "0": "20", + "1": "16", + "2": "5", + "3": "43", + "4": "34", + "5": "52", + "6": "61", + "7": "17", +} + +CFG_TC_TO_DOT1P_MAP_TABLE_NAME = "TC_TO_DOT1P_MAP" +CFG_TC_TO_DOT1P_MAP_KEY = "AZURE" +TC_TO_DOT1P_MAP = { + "0": "0", + "1": "6", + "2": "5", + "3": "3", + "4": "4", + "5": "2", + "6": "1", + "7": "7", +} + CFG_DOT1P_TO_TC_MAP_TABLE_NAME = "DOT1P_TO_TC_MAP" CFG_DOT1P_TO_TC_MAP_KEY = "AZURE" DOT1P_TO_TC_MAP = { @@ -32,9 +58,166 @@ CFG_PORT_QOS_MAP_TABLE_NAME = "PORT_QOS_MAP" CFG_PORT_QOS_DOT1P_MAP_FIELD = "dot1p_to_tc_map" CFG_PORT_QOS_MPLS_TC_MAP_FIELD = "mpls_tc_to_tc_map" +CFG_PORT_QOS_TC_DOT1P_MAP_FIELD = "tc_to_dot1p_map" +CFG_PORT_QOS_TC_DSCP_MAP_FIELD = "tc_to_dscp_map" CFG_PORT_TABLE_NAME = "PORT" +#Tests for TC-to-DSCP qos map configuration +class TestTcDscp(object): + def connect_dbs(self, dvs): + self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.config_db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + def create_tc_dscp_profile(self): + tbl = swsscommon.Table(self.config_db, CFG_TC_TO_DSCP_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs(list(TC_TO_DSCP_MAP.items())) + tbl.set(CFG_TC_TO_DSCP_MAP_KEY, fvs) + time.sleep(1) + + def find_tc_dscp_profile(self): + found = False + tc_dscp_map_raw = None + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST": + tc_dscp_map_raw = fv[1] + elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_TC_AND_COLOR_TO_DSCP": + found = True + + if found: + break + + assert found == True + + return (key, tc_dscp_map_raw) + + def apply_tc_dscp_profile_on_all_ports(self): + tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_TC_DSCP_MAP_FIELD, CFG_TC_TO_DSCP_MAP_KEY)]) + ports = swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys() + for port in ports: + tbl.set(port, fvs) + + time.sleep(1) + + + def test_tc_dscp_cfg(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dscp_profile() + _, tc_dscp_map_raw = self.find_tc_dscp_profile() + + tc_dscp_map = json.loads(tc_dscp_map_raw) + for tc2dscp in tc_dscp_map['list']: + tc_val = str(tc2dscp['key']['tc']) + dscp_val = str(tc2dscp['value']['dscp']) + assert dscp_val == TC_TO_DSCP_MAP[tc_val] + + def test_port_tc_dscp(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dscp_profile() + oid, _ = self.find_tc_dscp_profile() + + self.apply_tc_dscp_profile_on_all_ports() + + cnt = 0 + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DSCP_MAP": + cnt += 1 + assert fv[1] == oid + + port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()) + assert port_cnt == cnt + + +#Tests for TC-to-Dot1p qos map configuration +class TestTcDot1p(object): + def connect_dbs(self, dvs): + self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.config_db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + def create_tc_dot1p_profile(self): + tbl = swsscommon.Table(self.config_db, CFG_TC_TO_DOT1P_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs(list(TC_TO_DOT1P_MAP.items())) + tbl.set(CFG_TC_TO_DOT1P_MAP_KEY, fvs) + time.sleep(1) + + def find_tc_dot1p_profile(self): + found = False + tc_dot1p_map_raw = None + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST": + tc_dot1p_map_raw = fv[1] + elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_TC_AND_COLOR_TO_DOT1P": + found = True + + if found: + break + + assert found == True + + return (key, tc_dot1p_map_raw) + + def apply_tc_dot1p_profile_on_all_ports(self): + tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_TC_DOT1P_MAP_FIELD, CFG_TC_TO_DOT1P_MAP_KEY)]) + ports = swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys() + for port in ports: + tbl.set(port, fvs) + + time.sleep(1) + + + def test_tc_dot1p_cfg(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dot1p_profile() + _, tc_dot1p_map_raw = self.find_tc_dot1p_profile() + + tc_dot1p_map = json.loads(tc_dot1p_map_raw) + for tc2dot1p in tc_dot1p_map['list']: + tc_val = str(tc2dot1p['key']['tc']) + dot1p_val = str(tc2dot1p['value']['dot1p']) + assert dot1p_val == TC_TO_DOT1P_MAP[tc_val] + + def test_port_tc_dot1p(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dot1p_profile() + oid, _ = self.find_tc_dot1p_profile() + + self.apply_tc_dot1p_profile_on_all_ports() + + cnt = 0 + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DOT1P_MAP": + cnt += 1 + assert fv[1] == oid + + port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()) + assert port_cnt == cnt +#Tests for Dot1p-to-TC qos map configuration class TestDot1p(object): def connect_dbs(self, dvs): self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0) diff --git a/tests/test_srv6.py b/tests/test_srv6.py index dddb10153b..29d498780f 100644 --- a/tests/test_srv6.py +++ b/tests/test_srv6.py @@ -121,11 +121,14 @@ def setup_db(self, dvs): self.adb = dvs.get_asic_db() self.cdb = dvs.get_config_db() - def create_sidlist(self, segname, ips): + def create_sidlist(self, segname, ips, type=None): table = "ASIC_STATE:SAI_OBJECT_TYPE_SRV6_SIDLIST" existed_entries = get_exist_entries(self.adb.db_connection, table) - fvs=swsscommon.FieldValuePairs([('path', ips)]) + if type is None: + fvs=swsscommon.FieldValuePairs([('path', ips)]) + else: + fvs=swsscommon.FieldValuePairs([('path', ips), ('type', type)]) segtbl = swsscommon.ProducerStateTable(self.pdb.db_connection, "SRV6_SID_LIST_TABLE") segtbl.set(segname, fvs) @@ -239,9 +242,30 @@ def test_srv6(self, dvs, testlog): # create 2nd seg lists - self.create_sidlist('seg2', 'baba:2002:10::,baba:2002:20::') - # create 3rd seg lists - self.create_sidlist('seg3', 'baba:2003:10::,baba:2003:20::') + sidlist_id = self.create_sidlist('seg2', 'baba:2002:10::,baba:2002:20::', 'insert.red') + + # check ASIC SAI_OBJECT_TYPE_SRV6_SIDLIST database + tbl = swsscommon.Table(self.adb.db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_SRV6_SIDLIST") + (status, fvs) = tbl.get(sidlist_id) + assert status == True + for fv in fvs: + if fv[0] == "SAI_SRV6_SIDLIST_ATTR_SEGMENT_LIST": + assert fv[1] == "2:baba:2002:10::,baba:2002:20::" + elif fv[0] == "SAI_SRV6_SIDLIST_ATTR_TYPE": + assert fv[1] == "SAI_SRV6_SIDLIST_TYPE_INSERT_RED" + + # create 3rd seg lists with unsupported or wrong naming of sid list type, for this case, it will use default type: ENCAPS_RED + sidlist_id = self.create_sidlist('seg3', 'baba:2003:10::,baba:2003:20::', 'reduced') + + # check ASIC SAI_OBJECT_TYPE_SRV6_SIDLIST database + tbl = swsscommon.Table(self.adb.db_connection, "ASIC_STATE:SAI_OBJECT_TYPE_SRV6_SIDLIST") + (status, fvs) = tbl.get(sidlist_id) + assert status == True + for fv in fvs: + if fv[0] == "SAI_SRV6_SIDLIST_ATTR_SEGMENT_LIST": + assert fv[1] == "2:baba:2003:10::,baba:2003:20::" + elif fv[0] == "SAI_SRV6_SIDLIST_ATTR_TYPE": + assert fv[1] == "SAI_SRV6_SIDLIST_TYPE_ENCAPS_RED" # create 2nd v4 route with single sidlists self.create_srv6_route('20.20.20.21/32','seg2','1001:2000::1')