From 9767af966fb3367d2c3a202bd53efd6ef30c1f8b Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Thu, 4 Jun 2020 07:16:48 -0700 Subject: [PATCH 1/8] [mirrororch] Port Mirroring implementation Signed-off-by: Rupesh Kumar --- orchagent/mirrororch.cpp | 245 ++++++++++++++++++++++++++++++--------- orchagent/mirrororch.h | 6 + 2 files changed, 195 insertions(+), 56 deletions(-) diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index 0de90a424dd..f36f968f443 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -27,6 +27,10 @@ #define MIRROR_SESSION_ROUTE_PREFIX "route_prefix" #define MIRROR_SESSION_VLAN_ID "vlan_id" #define MIRROR_SESSION_POLICER "policer" +#define MIRROR_SESSION_SRC_PORT "src_port" +#define MIRROR_SESSION_DST_PORT "dst_port" +#define MIRROR_SESSION_DIRECTION "direction" +#define MIRROR_SESSION_TYPE "type" #define MIRROR_SESSION_DEFAULT_VLAN_PRI 0 #define MIRROR_SESSION_DEFAULT_VLAN_CFI 0 @@ -36,6 +40,7 @@ #define MIRROR_SESSION_DSCP_MAX 63 extern sai_mirror_api_t *sai_mirror_api; +extern sai_port_api_t *sai_port_api; extern sai_object_id_t gSwitchId; extern PortsOrch* gPortsOrch; @@ -324,6 +329,22 @@ void MirrorOrch::createEntry(const string& key, const vector& d m_policerOrch->increaseRefCount(fvValue(i)); entry.policer = fvValue(i); } + else if (fvField(i) == MIRROR_SESSION_SRC_PORT) + { + entry.src_port = fvValue(i); + } + else if (fvField(i) == MIRROR_SESSION_DST_PORT) + { + entry.dst_port = fvValue(i); + } + else if (fvField(i) == MIRROR_SESSION_DIRECTION) + { + entry.direction = fvValue(i); + } + else if (fvField(i) == MIRROR_SESSION_TYPE) + { + entry.type = fvValue(i); + } else { SWSS_LOG_ERROR("Failed to parse session %s configuration. Unknown attribute %s.\n", key.c_str(), fvField(i).c_str()); @@ -348,8 +369,16 @@ void MirrorOrch::createEntry(const string& key, const vector& d setSessionState(key, entry); - // Attach the destination IP to the routeOrch - m_routeOrch->attach(this, entry.dstIp); + if (entry.type == "SPAN" && !entry.dst_port.empty()) + { + auto &session1 = m_syncdMirrors.find(key)->second; + activateSession(key, session1); + } + else + { + // Attach the destination IP to the routeOrch + m_routeOrch->attach(this, entry.dstIp); + } } task_process_status MirrorOrch::deleteEntry(const string& name) @@ -375,7 +404,10 @@ task_process_status MirrorOrch::deleteEntry(const string& name) if (session.status) { - m_routeOrch->detach(this, session.dstIp); + if (session.type != "SPAN") + { + m_routeOrch->detach(this, session.dstIp); + } if (!deactivateSession(name, session)) { SWSS_LOG_ERROR("Failed to remove mirror session %s", name.c_str()); @@ -613,6 +645,64 @@ bool MirrorOrch::updateSession(const string& name, MirrorEntry& session) return ret; } +bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& session, bool enable) +{ + sai_status_t status; + sai_attribute_t port_attr; + Port port; + bool rv1 = true , rv2 = true; + + if (enable) + { + port_attr.value.objlist.count = 1; + port_attr.value.objlist.list = (long unsigned int *)calloc(port_attr.value.objlist.count, sizeof(sai_object_id_t)); + port_attr.value.objlist.list[0] = session.sessionId; + } + else + { + port_attr.value.objlist.count = 0; + } + + auto ports = tokenize(session.src_port, ','); + if (ports.size() != 0) + { + for (auto alias : ports) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_ERROR("Failed to locate port %s", alias.c_str()); + return false; + } + if (session.direction == "RX" || session.direction == "BOTH") { + port_attr.id = SAI_PORT_ATTR_INGRESS_MIRROR_SESSION; + status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to configure session %s to port %s, status %d, sessionId %x\n", + name.c_str(), port.m_alias.c_str(), status, session.sessionId); + rv1 = false; + } + } + if (session.direction == "TX" || session.direction == "BOTH") { + port_attr.id = SAI_PORT_ATTR_EGRESS_MIRROR_SESSION; + status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to configure session %s to port %s, status %d, sessionId %x\n", + name.c_str(), port.m_alias.c_str(), status, session.sessionId); + rv2 = false; + } + } + } + } + + if (rv1 == false || rv2 == false) + return false; + + return true; +} + bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) { SWSS_LOG_ENTER(); @@ -632,75 +722,95 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) attrs.push_back(attr); } - attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; - attr.value.oid = session.neighborInfo.portId; - attrs.push_back(attr); + if (session.type == "SPAN") + { + Port dst_port; + if (!m_portsOrch->getPort(session.dst_port, dst_port)) + { + SWSS_LOG_ERROR("Failed to locate Port/LAG %s", session.dst_port.c_str()); + return false; + } - attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; - attr.value.s32 = SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE; - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; + attr.value.oid = dst_port.m_port_id; + attrs.push_back(attr); - // Add the VLAN header when the packet is sent out from a VLAN - if (session.neighborInfo.port.m_type == Port::VLAN) + attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; + attr.value.oid = SAI_MIRROR_SESSION_TYPE_LOCAL; + attrs.push_back(attr); + } + else { - attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID; - attr.value.booldata = true; + attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; + attr.value.oid = session.neighborInfo.portId; attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_TPID; - attr.value.u16 = ETH_P_8021Q; + attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; + attr.value.s32 = SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE; attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_ID; - attr.value.u16 = session.neighborInfo.port.m_vlan_info.vlan_id; - attrs.push_back(attr); + // Add the VLAN header when the packet is sent out from a VLAN + if (session.neighborInfo.port.m_type == Port::VLAN) + { + attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID; + attr.value.booldata = true; + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_PRI; - attr.value.u8 = MIRROR_SESSION_DEFAULT_VLAN_PRI; - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_TPID; + attr.value.u16 = ETH_P_8021Q; + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_CFI; - attr.value.u8 = MIRROR_SESSION_DEFAULT_VLAN_CFI; - attrs.push_back(attr); - } + attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_ID; + attr.value.u16 = session.neighborInfo.port.m_vlan_info.vlan_id; + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE; - attr.value.s32 = SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL; - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_PRI; + attr.value.u8 = MIRROR_SESSION_DEFAULT_VLAN_PRI; + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION; - attr.value.u8 = MIRROR_SESSION_DEFAULT_IP_HDR_VER; - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_VLAN_CFI; + attr.value.u8 = MIRROR_SESSION_DEFAULT_VLAN_CFI; + attrs.push_back(attr); + } + + attr.id = SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE; + attr.value.s32 = SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL; + attrs.push_back(attr); - // TOS value format is the following: - // DSCP 6 bits | ECN 2 bits - attr.id = SAI_MIRROR_SESSION_ATTR_TOS; - attr.value.u16 = (uint16_t)(session.dscp << MIRROR_SESSION_DSCP_SHIFT); - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION; + attr.value.u8 = MIRROR_SESSION_DEFAULT_IP_HDR_VER; + attrs.push_back(attr); + + // TOS value format is the following: + // DSCP 6 bits | ECN 2 bits + attr.id = SAI_MIRROR_SESSION_ATTR_TOS; + attr.value.u16 = (uint16_t)(session.dscp << MIRROR_SESSION_DSCP_SHIFT); + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_TTL; - attr.value.u8 = session.ttl; - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_TTL; + attr.value.u8 = session.ttl; + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; - copy(attr.value.ipaddr, session.srcIp); - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; + copy(attr.value.ipaddr, session.srcIp); + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; - copy(attr.value.ipaddr, session.dstIp); - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; + copy(attr.value.ipaddr, session.dstIp); + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, gMacAddress.getMac(), sizeof(sai_mac_t)); - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, gMacAddress.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; - memcpy(attr.value.mac, session.neighborInfo.mac.getMac(), sizeof(sai_mac_t)); - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; + memcpy(attr.value.mac, session.neighborInfo.mac.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); - attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE; - attr.value.u16 = session.greType; - attrs.push_back(attr); + attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE; + attr.value.u16 = session.greType; + attrs.push_back(attr); + } if (!session.policer.empty()) { @@ -727,6 +837,18 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) } session.status = true; + + if (!session.src_port.empty() && !session.direction.empty()) + { + status = configurePortMirrorSession(name, session, true); + if (status == false) + { + SWSS_LOG_ERROR("Failed to activate port mirror session %s\n", name.c_str()); + session.status = false; + return false; + } + } + setSessionState(name, session); MirrorSessionUpdate update = { name, true }; @@ -740,14 +862,25 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) bool MirrorOrch::deactivateSession(const string& name, MirrorEntry& session) { SWSS_LOG_ENTER(); + sai_status_t status; assert(session.status); MirrorSessionUpdate update = { name, false }; notify(SUBJECT_TYPE_MIRROR_SESSION_CHANGE, static_cast(&update)); - sai_status_t status = sai_mirror_api-> - remove_mirror_session(session.sessionId); + if (!session.src_port.empty() && !session.direction.empty()) + { + status = configurePortMirrorSession(name, session, false); + if (status == false) + { + SWSS_LOG_ERROR("Failed to deactivate port mirror session %s\n", name.c_str()); + return false; + } + } + + status = sai_mirror_api->remove_mirror_session(session.sessionId); + if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to deactivate mirroring session %s\n", name.c_str()); diff --git a/orchagent/mirrororch.h b/orchagent/mirrororch.h index 798eb4583a0..82e2d2b9b8e 100644 --- a/orchagent/mirrororch.h +++ b/orchagent/mirrororch.h @@ -32,6 +32,10 @@ struct MirrorEntry uint8_t ttl; uint8_t queue; string policer; + string dst_port; + string src_port; + string direction; + string type; struct { @@ -118,6 +122,8 @@ class MirrorOrch : public Orch, public Observer, public Subject void updateLagMember(const LagMemberUpdate&); void updateVlanMember(const VlanMemberUpdate&); + bool configurePortMirrorSession(const string&, MirrorEntry&, bool enable); + void doTask(Consumer& consumer); }; From feec6ea48b2123c8bfba5ab6b2b8dbff8a9a4979 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Thu, 11 Jun 2020 06:50:00 -0700 Subject: [PATCH 2/8] Added pytest test cases. Modified to support LAG as source port. --- doc/swss-schema.md | 70 ++- orchagent/mirrororch.cpp | 127 +++-- orchagent/mirrororch.h | 8 + orchagent/portsorch.h | 2 +- tests/test_mirror_port_erspan.py | 951 +++++++++++++++++++++++++++++++ tests/test_mirror_port_span.py | 762 +++++++++++++++++++++++++ 6 files changed, 1886 insertions(+), 34 deletions(-) create mode 100644 tests/test_mirror_port_erspan.py create mode 100644 tests/test_mirror_port_span.py diff --git a/doc/swss-schema.md b/doc/swss-schema.md index 8cb191a2311..7ac0c24d3a3 100644 --- a/doc/swss-schema.md +++ b/doc/swss-schema.md @@ -595,6 +595,10 @@ Stores information about mirror sessions and their properties. ttl = h8 ; Session TTL queue = h8 ; Session output queue policer = policer_name ; Session policer name + dst_port = PORT_TABLE|ifname ; Session destination PORT + src_port = PORT_TABLE|ifname ; Session source PORT/LAG list + direction = "RX"/"TX"/"BOTH" ; Session direction + type = "SPAN"/"ERSPAN" ; Session type. Default is ERSPAN ;value annotations mirror_session_name = 1*255VCHAR @@ -623,6 +627,37 @@ Example: } ] + [ + { + "MIRROR_SESSION_TABLE:session_2": { + "src_ip": "1.1.1.1", + "dst_ip": "2.2.2.2", + "gre_type": "0x6558", + "dscp": "50", + "ttl": "64", + "queue": "0" + "src_port": "Ethernet0,PortChannel001" + "direction": "BOTH" + "type": "ERSPAN" + }, + "OP": "SET" + } + ] + + [ + { + "MIRROR_SESSION_TABLE:session_3": { + "type": "SPAN" + "dst_port": "Ethernet0" + "src_port": "Ethernet4,PortChannel002" + "direction": "BOTH" + }, + "OP": "SET" + } + ] + + + Equivalent RedisDB entry: 127.0.0.1:6379> KEYS *MIRROR* @@ -631,7 +666,7 @@ Equivalent RedisDB entry: 1) "src_ip" 2) "1.1.1.1" 3) "dst_ip" - 4) "2.2.2.2 + 4) "2.2.2.2" 5) "gre_type" 6) "0x6558" 7) "dscp" @@ -641,6 +676,39 @@ Equivalent RedisDB entry: 11) "queue" 12) "0" + 127.0.0.1:6379> KEYS *MIRROR* + 1) "MIRROR_SESSION_TABLE:session_2" + 127.0.0.1:6379> HGETALL MIRROR_SESSION_TABLE:session_2 + 1) "src_ip" + 2) "1.1.1.1" + 3) "dst_ip" + 4) "2.2.2.2" + 5) "gre_type" + 6) "0x6558" + 7) "dscp" + 8) "50" + 9) "ttl" + 10) "64" + 11) "queue" + 12) "0" + 13) "src_port" + 14) "Ethernet0,PortChannel001" + 15) "direction" + 16) "BOTH" + 17) "type" + 18) "ERSPAN" + + 127.0.0.1:6379> KEYS *MIRROR* + 1) "MIRROR_SESSION_TABLE:session_1" + 127.0.0.1:6379> HGETALL MIRROR_SESSION_TABLE:session_3i + 1) "type" + 2) "SPAN" + 3) "dst_port" + 4) "Ethernet0" + 5) "src_port" + 6) "Ethernet4,PortChannel002" + 7) "direction" + 8) "RX" --------------------------------------------- ### POLICER_TABLE diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index f36f968f443..4d01c88c300 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -128,7 +128,7 @@ bool MirrorOrch::bake() key, monitor_port + state_db_key_delimiter + next_hop_ip); } - removeSessionState(key); + removeSessionState(key); } return Orch::bake(); @@ -331,14 +331,40 @@ void MirrorOrch::createEntry(const string& key, const vector& d } else if (fvField(i) == MIRROR_SESSION_SRC_PORT) { + auto ports = tokenize(fvValue(i), ','); + if (ports.size() != 0) + { + for (auto alias : ports) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_ERROR("Failed to locate port/LAG %s", alias.c_str()); + return; + } + } + } entry.src_port = fvValue(i); } else if (fvField(i) == MIRROR_SESSION_DST_PORT) { + Port dst_port; + if (!m_portsOrch->getPort(fvValue(i), dst_port)) + { + SWSS_LOG_ERROR("Failed to locate port %s", fvValue(i).c_str()); + return; + } entry.dst_port = fvValue(i); + } else if (fvField(i) == MIRROR_SESSION_DIRECTION) { + if (!(fvValue(i) == mirror_rx_direction || fvValue(i) == mirror_tx_direction + || fvValue(i) == mirror_both_direction)) + { + SWSS_LOG_ERROR("Failed to get valid direction %s", fvValue(i).c_str()); + return; + } entry.direction = fvValue(i); } else if (fvField(i) == MIRROR_SESSION_TYPE) @@ -369,7 +395,7 @@ void MirrorOrch::createEntry(const string& key, const vector& d setSessionState(key, entry); - if (entry.type == "SPAN" && !entry.dst_port.empty()) + if (entry.type == mirror_session_span && !entry.dst_port.empty()) { auto &session1 = m_syncdMirrors.find(key)->second; activateSession(key, session1); @@ -404,7 +430,7 @@ task_process_status MirrorOrch::deleteEntry(const string& name) if (session.status) { - if (session.type != "SPAN") + if (session.type != mirror_session_span) { m_routeOrch->detach(this, session.dstIp); } @@ -645,24 +671,56 @@ bool MirrorOrch::updateSession(const string& name, MirrorEntry& session) return ret; } -bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& session, bool enable) +bool MirrorOrch::setUnsetPortMirror(Port port, + bool ingress, + bool set, + sai_object_id_t sessionId) { sai_status_t status; sai_attribute_t port_attr; - Port port; - bool rv1 = true , rv2 = true; - - if (enable) + port_attr.id = ingress ? SAI_PORT_ATTR_INGRESS_MIRROR_SESSION: + SAI_PORT_ATTR_EGRESS_MIRROR_SESSION; + if (set) { port_attr.value.objlist.count = 1; port_attr.value.objlist.list = (long unsigned int *)calloc(port_attr.value.objlist.count, sizeof(sai_object_id_t)); - port_attr.value.objlist.list[0] = session.sessionId; + port_attr.value.objlist.list[0] = sessionId; } else { port_attr.value.objlist.count = 0; } + if (port.m_type == Port::LAG) + { + vector portv; + m_portsOrch->getLagMember(port, portv); + for (const auto p : portv) + { + status = sai_port_api->set_port_attribute(p.m_port_id, &port_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to configure mirror session port %s: %s, status %d, sessionId %x\n", + port.m_alias.c_str(), p.m_alias.c_str(), status, sessionId); + return false; + } + } + } + else if (port.m_type == Port::PHY) + { + status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to configure mirror session to port %s, status %d, sessionId %x\n", + port.m_alias.c_str(), status, sessionId); + return false; + } + } + return true; +} + +bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& session, bool set) +{ auto ports = tokenize(session.src_port, ','); if (ports.size() != 0) { @@ -671,35 +729,22 @@ bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& ses Port port; if (!gPortsOrch->getPort(alias, port)) { - SWSS_LOG_ERROR("Failed to locate port %s", alias.c_str()); + SWSS_LOG_ERROR("Failed to locate port/LAG %s", alias.c_str()); return false; } - if (session.direction == "RX" || session.direction == "BOTH") { - port_attr.id = SAI_PORT_ATTR_INGRESS_MIRROR_SESSION; - status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to configure session %s to port %s, status %d, sessionId %x\n", - name.c_str(), port.m_alias.c_str(), status, session.sessionId); - rv1 = false; - } + if (session.direction == mirror_rx_direction || session.direction == mirror_both_direction) + { + if (!setUnsetPortMirror(port, true, set, session.sessionId)) + return false; } - if (session.direction == "TX" || session.direction == "BOTH") { - port_attr.id = SAI_PORT_ATTR_EGRESS_MIRROR_SESSION; - status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to configure session %s to port %s, status %d, sessionId %x\n", - name.c_str(), port.m_alias.c_str(), status, session.sessionId); - rv2 = false; - } + if (session.direction == mirror_tx_direction || session.direction == mirror_both_direction) + { + if (!setUnsetPortMirror(port, false, set, session.sessionId)) + return false; } } } - if (rv1 == false || rv2 == false) - return false; - return true; } @@ -722,7 +767,7 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) attrs.push_back(attr); } - if (session.type == "SPAN") + if (session.type == mirror_session_span) { Port dst_port; if (!m_portsOrch->getPort(session.dst_port, dst_port)) @@ -1177,6 +1222,24 @@ void MirrorOrch::updateLagMember(const LagMemberUpdate& update) const auto& name = it->first; auto& session = it->second; + // Check the following conditions: + // 1) Session is active + // 2) LAG is part of mirror session source ports. + // if the above condition matches then set/unset mirror configuration to new member port. + if (session.status && + !session.src_port.empty() && + session.src_port.find(update.lag.m_alias.c_str()) != std::string::npos) + { + if (session.direction == mirror_rx_direction || session.direction == mirror_both_direction) + { + setUnsetPortMirror(update.member, true, update.add, session.sessionId); + } + if (session.direction == mirror_tx_direction || session.direction == mirror_both_direction) + { + setUnsetPortMirror(update.member, false, update.add, session.sessionId); + } + } + // Check the following two conditions: // 1) the neighbor is LAG // 2) the neighbor LAG matches the update LAG diff --git a/orchagent/mirrororch.h b/orchagent/mirrororch.h index 82e2d2b9b8e..a4e9c73fe7d 100644 --- a/orchagent/mirrororch.h +++ b/orchagent/mirrororch.h @@ -18,6 +18,12 @@ #include #include +const string mirror_rx_direction = "RX"; +const string mirror_tx_direction = "TX"; +const string mirror_both_direction = "BOTH"; +const string mirror_session_span = "SPAN"; +const string mirror_session_erspan = "ERSPAN"; + /* * Contains session data specified by user in config file * and data required for MAC address and port resolution @@ -122,6 +128,8 @@ class MirrorOrch : public Orch, public Observer, public Subject void updateLagMember(const LagMemberUpdate&); void updateVlanMember(const VlanMemberUpdate&); + bool setUnsetPortMirror(Port port, bool ingress, bool set, + sai_object_id_t sessionId); bool configurePortMirrorSession(const string&, MirrorEntry&, bool enable); void doTask(Consumer& consumer); diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 34d7dfd8bf8..9f997b6ab5d 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -106,6 +106,7 @@ class PortsOrch : public Orch, public Subject bool addSubPort(Port &port, const string &alias, const bool &adminUp = true, const uint32_t &mtu = 0); bool removeSubPort(const string &alias); + void getLagMember(Port &lag, vector &portv); private: unique_ptr m_counterTable; unique_ptr
m_counterLagTable; @@ -191,7 +192,6 @@ class PortsOrch : public Orch, public Subject bool removeLagMember(Port &lag, Port &port); bool setCollectionOnLagMember(Port &lagMember, bool enableCollection); bool setDistributionOnLagMember(Port &lagMember, bool enableDistribution); - void getLagMember(Port &lag, vector &portv); bool addPort(const set &lane_set, uint32_t speed, int an=0, string fec=""); sai_status_t removePort(sai_object_id_t port_id); diff --git a/tests/test_mirror_port_erspan.py b/tests/test_mirror_port_erspan.py new file mode 100644 index 00000000000..3a59f594e0f --- /dev/null +++ b/tests/test_mirror_port_erspan.py @@ -0,0 +1,951 @@ +# This test suite covers the functionality of mirror feature in SwSS +import platform +import pytest +import time + +from swsscommon import swsscommon +from distutils.version import StrictVersion + + +class TestMirror(object): + def setup_db(self, dvs): + self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + self.sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) + + def set_interface_status(self, dvs, interface, admin_status): + if interface.startswith("PortChannel"): + tbl_name = "PORTCHANNEL" + elif interface.startswith("Vlan"): + tbl_name = "VLAN" + else: + tbl_name = "PORT" + tbl = swsscommon.Table(self.cdb, tbl_name) + fvs = swsscommon.FieldValuePairs([("admin_status", "up")]) + tbl.set(interface, fvs) + time.sleep(1) + + # when using FRR, route cannot be inserted if the neighbor is not + # connected. thus it is mandatory to force the interface up manually + if interface.startswith("PortChannel"): + dvs.runcmd("bash -c 'echo " + ("1" if admin_status == "up" else "0") +\ + " > /sys/class/net/" + interface + "/carrier'") + + def add_ip_address(self, interface, ip): + if interface.startswith("PortChannel"): + tbl_name = "PORTCHANNEL_INTERFACE" + elif interface.startswith("Vlan"): + tbl_name = "VLAN_INTERFACE" + else: + tbl_name = "INTERFACE" + tbl = swsscommon.Table(self.cdb, tbl_name) + fvs = swsscommon.FieldValuePairs([("NULL", "NULL")]) + tbl.set(interface + "|" + ip, fvs) + tbl.set(interface, fvs) + time.sleep(1) + + def remove_ip_address(self, interface, ip): + if interface.startswith("PortChannel"): + tbl_name = "PORTCHANNEL_INTERFACE" + elif interface.startswith("Vlan"): + tbl_name = "VLAN_INTERFACE" + else: + tbl_name = "INTERFACE" + tbl = swsscommon.Table(self.cdb, tbl_name) + tbl._del(interface + "|" + ip) + tbl._del(interface) + time.sleep(1) + + def add_neighbor(self, interface, ip, mac): + tbl = swsscommon.ProducerStateTable(self.pdb, "NEIGH_TABLE") + fvs = swsscommon.FieldValuePairs([("neigh", mac), + ("family", "IPv4")]) + tbl.set(interface + ":" + ip, fvs) + time.sleep(1) + + def remove_neighbor(self, interface, ip): + tbl = swsscommon.ProducerStateTable(self.pdb, "NEIGH_TABLE") + tbl._del(interface + ":" + ip) + time.sleep(1) + + def add_route(self, dvs, prefix, nexthop): + dvs.runcmd("ip route add " + prefix + " via " + nexthop) + time.sleep(1) + + def remove_route(self, dvs, prefix): + dvs.runcmd("ip route del " + prefix) + time.sleep(1) + + def create_policer(self, name): + tbl = swsscommon.Table(self.cdb, "POLICER") + fvs = swsscommon.FieldValuePairs([("meter_type", "packets"), + ("mode", "sr_tcm"), + ("cir", "600"), + ("cbs", "600"), + ("red_packet_action", "drop")]) + tbl.set(name, fvs) + time.sleep(1) + + def remove_policer(self, name): + tbl = swsscommon.Table(self.cdb, "POLICER") + tbl._del(name) + time.sleep(1) + + def getPortOid(self, dvs, port_name): + + cnt_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) + port_map_tbl = swsscommon.Table(cnt_db, 'COUNTERS_PORT_NAME_MAP') + + for k in port_map_tbl.get('')[1]: + if k[0] == port_name: + return k[1] + + + def getPortAttr(self, dvs, port_oid, port_attr): + + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + port_tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_PORT:{0}'.format(port_oid)) + + for k in port_tbl.get('')[1]: + if k[0] == port_attr: + return k[1] + + def create_mirror_erspan_session(self, name, src, dst, gre, dscp, ttl, queue, policer=None, src_port=None, direction=None): + tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") + if src_port is None and policer is None and direction is None: + fvs = swsscommon.FieldValuePairs([("src_ip", src), + ("dst_ip", dst), + ("gre_type", gre), + ("dscp", dscp), + ("ttl", ttl), + ("queue", queue)]) + elif policer is None: + fvs = swsscommon.FieldValuePairs([("src_ip", src), + ("dst_ip", dst), + ("gre_type", gre), + ("dscp", dscp), + ("ttl", ttl), + ("queue", queue), + ("src_port", src_port), + ("direction", direction)]) + else: + fvs = swsscommon.FieldValuePairs([("src_ip", src), + ("dst_ip", dst), + ("gre_type", gre), + ("dscp", dscp), + ("ttl", ttl), + ("queue", queue), + ("src_port", src_port), + ("direction", direction), + ("policer", policer)]) + tbl.set(name, fvs) + time.sleep(3) + + def remove_mirror_session(self, name): + tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") + tbl._del(name) + time.sleep(2) + + def get_mirror_session_status(self, name): + return self.get_mirror_session_state(name)["status"] + + def get_mirror_session_state(self, name): + tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") + (status, fvs) = tbl.get(name) + assert status == True + assert len(fvs) > 0 + return { fv[0]: fv[1] for fv in fvs } + + def check_mirror_session_state(self, name, status): + tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") + (session_status, fvs) = tbl.get(name) + assert session_status == status + + def test_PortMirrorERSpanAddRemove(self, dvs, testlog): + """ + This test covers the basic mirror session creation and removal operations + Operation flow: + 1. Create mirror session with only dst_port + The session becomes active. + 2. Create mirror session with invalid dst_port, session becomes inactive. + 2. Create mirror session with invalid source port, the session becomes inactive, + 3. Create mirror session with multiple source ports, the session becomes active + 4. Create mirror session with valid and invalid source ports, the session becomes inactive + 5. Remove miror session + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet0" + src_oid = self.getPortOid(dvs, src_port) + + # create mirror session + self.create_mirror_erspan_session(session, "1.1.1.1", "2.2.2.2", "0x6558", "8", "100", "0", None, src_port, "BOTH") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # bring up Ethernet16 + self.set_interface_status(dvs, "Ethernet16", "up") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # add IP address to Ethernet16 + self.add_ip_address("Ethernet16", "10.0.0.0/31") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # add neighbor to Ethernet16 + self.add_neighbor("Ethernet16", "10.0.0.1", "02:04:06:08:10:12") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # add route to mirror destination via 10.0.0.1 + self.add_route(dvs, "2.2.2.2", "10.0.0.1") + assert self.get_mirror_session_state(session)["status"] == "active" + assert self.get_mirror_session_state(session)["monitor_port"] == "Ethernet16" + assert self.get_mirror_session_state(session)["dst_mac"] == "02:04:06:08:10:12" + assert self.get_mirror_session_state(session)["route_prefix"] == "2.2.2.2/32" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 11 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE": + assert fv[1] == "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION": + assert fv[1] == "4" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TOS": + assert fv[1] == "32" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TTL": + assert fv[1] == "100" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS": + assert fv[1] == "1.1.1.1" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS": + assert fv[1] == "2.2.2.2" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS": + assert fv[1] == dvs.runcmd("bash -c \"ip link show eth0 | grep ether | awk '{print $2}'\"")[1].strip().upper() + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "02:04:06:08:10:12" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE": + assert fv[1] == "25944" # 0x6558 + else: + assert False + + # Check src_port state. + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # remove route + self.remove_route(dvs, "2.2.2.2") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove neighbor + self.remove_neighbor("Ethernet16", "10.0.0.1") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove IP address + self.remove_ip_address("Ethernet16", "10.0.0.0/31") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # bring down Ethernet16 + self.set_interface_status(dvs, "Ethernet16", "down") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove mirror session + self.remove_mirror_session(session) + def create_vlan(self, dvs, vlan): + #dvs.runcmd("ip link del Bridge") + #dvs.runcmd("ip link add Bridge up type bridge") + tbl = swsscommon.Table(self.cdb, "VLAN") + fvs = swsscommon.FieldValuePairs([("vlanid", vlan)]) + tbl.set("Vlan" + vlan, fvs) + time.sleep(1) + + def remove_vlan(self, vlan): + tbl = swsscommon.Table(self.cdb, "VLAN") + tbl._del("Vlan" + vlan) + time.sleep(1) + + def create_vlan_member(self, vlan, interface): + tbl = swsscommon.Table(self.cdb, "VLAN_MEMBER") + fvs = swsscommon.FieldValuePairs([("tagging_mode", "untagged")]) + tbl.set("Vlan" + vlan + "|" + interface, fvs) + time.sleep(1) + + def remove_vlan_member(self, vlan, interface): + tbl = swsscommon.Table(self.cdb, "VLAN_MEMBER") + tbl._del("Vlan" + vlan + "|" + interface) + time.sleep(1) + + def create_fdb(self, vlan, mac, interface): + tbl = swsscommon.ProducerStateTable(self.pdb, "FDB_TABLE") + fvs = swsscommon.FieldValuePairs([("port", interface), + ("type", "dynamic")]) + tbl.set("Vlan" + vlan + ":" + mac, fvs) + time.sleep(1) + + def remove_fdb(self, vlan, mac): + tbl = swsscommon.ProducerStateTable(self.pdb, "FDB_TABLE") + tbl._del("Vlan" + vlan + ":" + mac) + time.sleep(1) + + + # Ignore testcase in Debian Jessie + # TODO: Remove this skip if Jessie support is no longer needed + @pytest.mark.skipif(StrictVersion(platform.linux_distribution()[1]) <= StrictVersion('8.9'), reason="Debian 8.9 or before has no support") + def test_PortMirrorToVlanAddRemove(self, dvs, testlog): + """ + This test covers basic mirror session creation and removal operation + with destination port sits in a VLAN + Opeartion flow: + 1. Create mirror session + 2. Create VLAN; assign IP; create neighbor; create FDB + The session should be up only at this time. + 3. Remove FDB; remove neighbor; remove IP; remove VLAN + 4. Remove mirror session + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet0" + src_oid = self.getPortOid(dvs, src_port) + + # create mirror session + self.create_mirror_erspan_session(session, "5.5.5.5", "6.6.6.6", "0x6558", "8", "100", "0", None, src_port, "BOTH") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create vlan; create vlan member + self.create_vlan(dvs, "6") + self.create_vlan_member("6", "Ethernet4") + + # bring up vlan and member + self.set_interface_status(dvs, "Vlan6", "up") + self.set_interface_status(dvs, "Ethernet4", "up") + + # add ip address to vlan 6 + self.add_ip_address("Vlan6", "6.6.6.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create neighbor to vlan 6 + self.add_neighbor("Vlan6", "6.6.6.6", "66:66:66:66:66:66") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create fdb entry to ethernet4 + self.create_fdb("6", "66-66-66-66-66-66", "Ethernet4") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 16 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet4" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE": + assert fv[1] == "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION": + assert fv[1] == "4" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TOS": + assert fv[1] == "32" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TTL": + assert fv[1] == "100" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS": + assert fv[1] == "5.5.5.5" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS": + assert fv[1] == "6.6.6.6" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS": + assert fv[1] == dvs.runcmd("bash -c \"ip link show eth0 | grep ether | awk '{print $2}'\"")[1].strip().upper() + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "66:66:66:66:66:66" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE": + assert fv[1] == "25944" # 0x6558 + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": + assert fv[1] == "true" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_TPID": + assert fv[1] == "33024" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_ID": + assert fv[1] == "6" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_PRI": + assert fv[1] == "0" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_CFI": + assert fv[1] == "0" + else: + assert False + + # Check src_port state. + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # remove fdb entry + self.remove_fdb("6", "66-66-66-66-66-66") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove neighbor + self.remove_neighbor("Vlan6", "6.6.6.6") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove ip address + self.remove_ip_address("Vlan6", "6.6.6.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # bring down vlan and member + self.set_interface_status(dvs, "Ethernet4", "down") + self.set_interface_status(dvs, "Vlan6", "down") + + # remove vlan member; remove vlan + self.remove_vlan_member("6", "Ethernet4") + self.remove_vlan("6") + + # remove mirror session + self.remove_mirror_session(session) + + def create_port_channel(self, dvs, channel): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "9100")]) + tbl.set("PortChannel" + channel, fvs) + dvs.runcmd("ip link add PortChannel" + channel + " type bond") + tbl = swsscommon.Table(self.sdb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("state", "ok")]) + tbl.set("PortChannel" + channel, fvs) + time.sleep(1) + + def remove_port_channel(self, dvs, channel): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") + tbl._del("PortChannel" + channel) + dvs.runcmd("ip link del PortChannel" + channel) + tbl = swsscommon.Table(self.sdb, "LAG_TABLE") + tbl._del("PortChannel" + channel) + time.sleep(1) + + def create_port_channel_member(self, channel, interface): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + tbl.set("PortChannel" + channel + ":" + interface, fvs) + time.sleep(1) + + def remove_port_channel_member(self, channel, interface): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") + tbl._del("PortChannel" + channel + ":" + interface) + time.sleep(1) + + + def test_PortMirrorToLagAddRemove(self, dvs, testlog): + """ + This test covers basic mirror session creation and removal operations + with destination port sits in a LAG + Operation flow: + 1. Create mirror sesion + 2. Create LAG; assign IP; create directly connected neighbor + The session shoudl be up only at this time. + 3. Remove neighbor; remove IP; remove LAG + 4. Remove mirror session + + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet0" + src_oid = self.getPortOid(dvs, src_port) + + # create mirror session + self.create_mirror_erspan_session(session, "10.10.10.10", "11.11.11.11", "0x6558", "8", "100", "0", None, src_port, "TX") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create port channel; create port channel member + self.create_port_channel(dvs, "008") + self.create_port_channel_member("008", "Ethernet88") + + # bring up port channel and port channel member + self.set_interface_status(dvs, "PortChannel008", "up") + self.set_interface_status(dvs, "Ethernet88", "up") + + # add ip address to port channel 008 + self.add_ip_address("PortChannel008", "11.11.11.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create neighbor to port channel 008 + self.add_neighbor("PortChannel008", "11.11.11.11", "88:88:88:88:88:88") + assert self.get_mirror_session_state(session)["status"] == "active" + + # Check src_port state. + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + (status, fvs) = tbl.get(tbl.getKeys()[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet88" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "88:88:88:88:88:88" + + session_status= "1:"+format(mirror_entries[0]) + print src_oid + print session_status + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # remove neighbor + self.remove_neighbor("PortChannel008", "11.11.11.11") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove ip address + self.remove_ip_address("PortChannel008", "11.11.11.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # bring down port channel and port channel member + self.set_interface_status(dvs, "PortChannel008", "down") + self.set_interface_status(dvs, "Ethernet88", "down") + + # remove port channel member; remove port channel + self.remove_port_channel_member("008", "Ethernet88") + self.remove_port_channel(dvs, "008") + + # remove mirror session + self.remove_mirror_session(session) + + + # Ignore testcase in Debian Jessie + # TODO: Remove this skip if Jessie support is no longer needed + @pytest.mark.skipif(StrictVersion(platform.linux_distribution()[1]) <= StrictVersion('8.9'), reason="Debian 8.9 or before has no support") + def test_PortMirrorDestMoveVlan(self, dvs, testlog): + """ + This test tests mirror session destination move from non-VLAN to VLAN + and back to non-VLAN port + 1. Create mirror session + 2. Enable non-VLAN monitor port + 3. Create VLAN; move to VLAN without FDB entry + 4. Create FDB entry + 5. Remove FDB entry + 6. Remove VLAN; move to non-VLAN + 7. Disable non-VLAN monitor port + 8. Remove mirror session + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet0" + src_oid = self.getPortOid(dvs, src_port) + + # create mirror session + self.create_mirror_erspan_session(session, "7.7.7.7", "8.8.8.8", "0x6558", "8", "100", "0", None, src_port, "BOTH") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # bring up port; add ip; add neighbor; add route + self.set_interface_status(dvs, "Ethernet32", "up") + self.add_ip_address("Ethernet32", "80.0.0.0/31") + self.add_neighbor("Ethernet32", "80.0.0.1", "02:04:06:08:10:12") + self.add_route(dvs, "8.8.0.0/16", "80.0.0.1") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + assert len(tbl.getKeys()) == 1 + (status, fvs) = tbl.get(tbl.getKeys()[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": + assert fv[1] == "false" + + # mirror session move round 1 + # create vlan; create vlan member; bring up vlan and member + self.create_vlan(dvs, "9") + self.create_vlan_member("9", "Ethernet48") + self.set_interface_status(dvs, "Vlan9", "up") + self.set_interface_status(dvs, "Ethernet48", "up") + assert self.get_mirror_session_state(session)["status"] == "active" + + # add ip address to vlan 9 + self.add_ip_address("Vlan9", "8.8.8.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create neighbor to vlan 9 + self.add_neighbor("Vlan9", "8.8.8.8", "88:88:88:88:88:88") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create fdb entry to ethernet48 + self.create_fdb("9", "88-88-88-88-88-88", "Ethernet48") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet48" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": + assert fv[1] == "true" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_TPID": + assert fv[1] == "33024" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_ID": + assert fv[1] == "9" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_PRI": + assert fv[1] == "0" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_CFI": + assert fv[1] == "0" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # mirror session move round 2 + # remove fdb entry + self.remove_fdb("9", "88-88-88-88-88-88") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove neighbor + self.remove_neighbor("Vlan9", "8.8.8.8") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove ip address + self.remove_ip_address("Vlan9", "8.8.8.0/24") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + assert len(tbl.getKeys()) == 1 + (status, fvs) = tbl.get(tbl.getKeys()[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": + assert fv[1] == "false" + + # bring down vlan and member; remove vlan member; remove vlan + self.set_interface_status(dvs, "Ethernet48", "down") + self.set_interface_status(dvs, "Vlan9", "down") + self.remove_vlan_member("9", "Ethernet48") + self.remove_vlan("9") + + # remove route; remove neighbor; remove ip; bring down port + self.remove_route(dvs, "8.8.8.0/24") + self.remove_neighbor("Ethernet32", "80.0.0.1") + self.remove_ip_address("Ethernet32", "80.0.0.0/31") + self.set_interface_status(dvs, "Ethernet32", "down") + + # remove mirror session + self.remove_mirror_session(session) + + + def test_PortMirrorDestMoveLag(self, dvs, testlog): + """ + This test tests mirror session destination move from non-LAG to LAG + and back to non-LAG port + 1. Create mirror session with source ports. + 2. Enable non-LAG monitor port + 3. Create LAG; move to LAG with one member + 4. Remove LAG member + 5. Create LAG member + 6. Remove LAG; move to non-LAG + 7. Disable non-LAG monitor port + 8. Remove mirror session + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet0" + src_oid = self.getPortOid(dvs, src_port) + + # create mirror session + self.create_mirror_erspan_session(session, "12.12.12.12", "13.13.13.13", "0x6558", "8", "100", "0", None, src_port, "RX") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # bring up port; add ip; add neighbor; add route + self.set_interface_status(dvs, "Ethernet64", "up") + self.add_ip_address("Ethernet64", "100.0.0.0/31") + self.add_neighbor("Ethernet64", "100.0.0.1", "02:04:06:08:10:12") + self.add_route(dvs, "13.13.0.0/16", "100.0.0.1") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet64" + if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "02:04:06:08:10:12" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # mirror session move round 1 + # create port channel; create port channel member; bring up + self.create_port_channel(dvs, "080") + self.create_port_channel_member("080", "Ethernet32") + self.set_interface_status(dvs, "PortChannel080", "up") + self.set_interface_status(dvs, "Ethernet32", "up") + + # add ip address to port channel 080; create neighbor to port channel 080 + self.add_ip_address("PortChannel080", "200.0.0.0/31") + self.add_neighbor("PortChannel080", "200.0.0.1", "12:10:08:06:04:02") + assert self.get_mirror_session_state(session)["status"] == "active" + + # add route + self.add_route(dvs, "13.13.13.0/24", "200.0.0.1") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" + if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "12:10:08:06:04:02" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # mirror session move round 2 + # remove port channel member + self.remove_port_channel_member("080", "Ethernet32") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # mirror session move round 3 + # create port channel member + self.create_port_channel_member("080", "Ethernet32") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" + if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "12:10:08:06:04:02" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # mirror session move round 4 + # remove route + self.remove_route(dvs, "13.13.13.0/24") + assert self.get_mirror_session_state(session)["status"] == "active" + + port_oid = "" + # check monitor port + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet64" + if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "02:04:06:08:10:12" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # remove neighbor; remove ip address to port channel 080 + self.remove_neighbor("PortChannel080", "200.0.0.1") + self.remove_ip_address("PortChannel080", "200.0.0.0/31") + + # bring down; remove port channel member; remove port channel + self.set_interface_status(dvs, "Ethernet32", "down") + self.set_interface_status(dvs, "PortChannel080", "down") + self.remove_port_channel_member("080", "Ethernet32") + self.remove_port_channel(dvs, "080") + assert self.get_mirror_session_state(session)["status"] == "active" + + # remove route; remove neighbor; remove ip; bring down port + self.remove_route(dvs, "13.13.0.0/16") + self.remove_neighbor("Ethernet64", "100.0.0.1") + self.remove_ip_address("Ethernet64", "100.0.0.0/31") + self.set_interface_status(dvs, "Ethernet64", "down") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # remove mirror session + self.remove_mirror_session(session) + + def test_LAGMirrorToERSPANLagAddRemove(self, dvs, testlog): + """ + This test covers basic LAG mirror session creation and removal operations + with destination port sits in a LAG + Operation flow: + 1. Create source LAG + 2. configure mirror sesion with LAG as source port. + 3. Create destination LAG; assign IP; create directly connected neighbor + The session shoudl be up only at this time. + 4. Remove neighbor; remove IP; remove LAG + 5. Remove mirror session + + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + po_src_port = "PortChannel001" + src_port1 = "Ethernet0" + src_port2 = "Ethernet4" + src_oid1 = self.getPortOid(dvs, src_port1) + src_oid2 = self.getPortOid(dvs, src_port2) + + # create port channel; create port channel member + self.create_port_channel(dvs, "001") + self.create_port_channel_member("001", src_port1) + self.create_port_channel_member("001", src_port2) + + # bring up port channel and port channel member + self.set_interface_status(dvs, po_src_port, "up") + self.set_interface_status(dvs, src_port1, "up") + self.set_interface_status(dvs, src_port2, "up") + + # create mirror session + self.create_mirror_erspan_session(session, "10.10.10.10", "11.11.11.11", "0x6558", "8", "100", "0", None, po_src_port, "BOTH") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create port channel; create port channel member + self.create_port_channel(dvs, "008") + self.create_port_channel_member("008", "Ethernet88") + + # bring up port channel and port channel member + self.set_interface_status(dvs, "PortChannel008", "up") + self.set_interface_status(dvs, "Ethernet88", "up") + + # add ip address to port channel 008 + self.add_ip_address("PortChannel008", "11.11.11.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # create neighbor to port channel 008 + self.add_neighbor("PortChannel008", "11.11.11.11", "88:88:88:88:88:88") + assert self.get_mirror_session_state(session)["status"] == "active" + + # Check src_port state. + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + (status, fvs) = tbl.get(tbl.getKeys()[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet88" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": + assert fv[1] == "88:88:88:88:88:88" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + # remove neighbor + self.remove_neighbor("PortChannel008", "11.11.11.11") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + # remove ip address + self.remove_ip_address("PortChannel008", "11.11.11.0/24") + assert self.get_mirror_session_state(session)["status"] == "inactive" + + #verify mirror config is removed from LAG source ports. + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # bring down port channel and port channel member + self.set_interface_status(dvs, "PortChannel008", "down") + self.set_interface_status(dvs, "Ethernet88", "down") + + # remove port channel member; remove port channel + self.remove_port_channel_member("008", "Ethernet88") + self.remove_port_channel(dvs, "008") + self.remove_port_channel_member("001", src_port1) + self.remove_port_channel_member("001", src_port2) + self.remove_port_channel(dvs, "001") + + # remove mirror session + self.remove_mirror_session(session) \ No newline at end of file diff --git a/tests/test_mirror_port_span.py b/tests/test_mirror_port_span.py new file mode 100644 index 00000000000..77fbce58645 --- /dev/null +++ b/tests/test_mirror_port_span.py @@ -0,0 +1,762 @@ +# This test suite covers the functionality of mirror feature in SwSS +import platform +import pytest +import time + +from swsscommon import swsscommon +from distutils.version import StrictVersion + + +class TestMirror(object): + def setup_db(self, dvs): + self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + self.sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) + + def set_interface_status(self, dvs, interface, admin_status): + if interface.startswith("PortChannel"): + tbl_name = "PORTCHANNEL" + elif interface.startswith("Vlan"): + tbl_name = "VLAN" + else: + tbl_name = "PORT" + tbl = swsscommon.Table(self.cdb, tbl_name) + fvs = swsscommon.FieldValuePairs([("admin_status", "up")]) + tbl.set(interface, fvs) + time.sleep(1) + + # when using FRR, route cannot be inserted if the neighbor is not + # connected. thus it is mandatory to force the interface up manually + if interface.startswith("PortChannel"): + dvs.runcmd("bash -c 'echo " + ("1" if admin_status == "up" else "0") +\ + " > /sys/class/net/" + interface + "/carrier'") + + def getPortOid(self, dvs, port_name): + + cnt_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) + port_map_tbl = swsscommon.Table(cnt_db, 'COUNTERS_PORT_NAME_MAP') + + for k in port_map_tbl.get('')[1]: + if k[0] == port_name: + return k[1] + + + def getPortAttr(self, dvs, port_oid, port_attr): + + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + port_tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_PORT:{0}'.format(port_oid)) + + for k in port_tbl.get('')[1]: + if k[0] == port_attr: + return k[1] + + def create_mirror_span_session(self, name, dst_port, src_port=None, direction=None, queue=None, policer=None): + tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") + if src_port is None and direction is None: + if queue is None and policer is None: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port)]) + elif queue is None: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port), + ("policer", policer)]) + elif policer is None: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port), + ("queue", queue)]) + else: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port), + ("queue", queue), + ("policer", policer)]) + else: + if queue is None and policer is None: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port), + ("src_port", src_port), + ("direction", direction)]) + elif queue is None: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port), + ("src_port", src_port), + ("direction", direction), + ("policer", policer)]) + elif policer is None: + fvs = swsscommon.FieldValuePairs([("type", "SPAN"), + ("dst_port", dst_port), + ("src_port", src_port), + ("direction", direction), + ("queue", queue)]) + tbl.set(name, fvs) + time.sleep(2) + + def remove_mirror_session(self, name): + tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") + tbl._del(name) + time.sleep(1) + + def get_mirror_session_status(self, name): + return self.get_mirror_session_state(name)["status"] + + def get_mirror_session_state(self, name): + tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") + (status, fvs) = tbl.get(name) + assert status == True + assert len(fvs) > 0 + return { fv[0]: fv[1] for fv in fvs } + + def check_mirror_session_state(self, name, status): + tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") + (session_status, fvs) = tbl.get(name) + assert session_status == status + + @pytest.mark.skipif(StrictVersion(platform.linux_distribution()[1]) <= StrictVersion('8.9'), reason="Debian 8.9 or before has no support") + def test_PortMirrorAddRemove(self, dvs, testlog): + """ + This test covers the basic SPAN mirror session creation and removal operations + Operation flow: + 1. Create mirror session with only dst_port , verify session becomes active. + 2. Create mirror session with invalid dst_port, verify session doesnt get created. + 3. Create mirror session with invalid source port, verify session doesnt get created. + 4. Create mirror session with source port, verify session becomes active + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet12" + dst_port = "Ethernet16" + invld_port = "Invalid" + src_oid = self.getPortOid(dvs, src_port) + + # Sub Test 1 + # create mirror session + self.create_mirror_span_session(session, "Ethernet16") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + # verify asicdb + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 2 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + + # remove mirror session + self.remove_mirror_session(session) + + # Sub Test 2 + # create mirror session with invalid dst_port + self.create_mirror_span_session(session, invld_port) + self.check_mirror_session_state(session, False) + + # Sub Test 3 + # create mirror session with invalid src_port + self.create_mirror_span_session(session, dst_port, invld_port, "RX") + self.check_mirror_session_state(session, False) + + # Sub Test 4 + # create mirror session with dst_port, src_port, direction + self.create_mirror_span_session(session, dst_port, src_port, "RX") + assert self.get_mirror_session_state(session)["status"] == "active" + + #verify asicdb + mirror_entries = tbl.getKeys() + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 2 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # remove mirror session + self.remove_mirror_session(session) + + def test_PortMirrorMultiSpanAddRemove(self, dvs, testlog): + """ + This test covers the Multiple SPAN mirror session creation and removal operations + Operation flow: + 1. Create mirror session with multiple source ports, verify that session is active + 2. Create mirror session with multiple source with valid,invalid ports, session becomes inactive. + 3. Create multiple mirror sessions with multiple source ports. + 4. Create mirror session with invalid source port, the session becomes inactive, + 5. Create mirror session with multiple source ports, the session becomes active + 6. Create mirror session with valid and invalid source ports, the session becomes inactive + 5. Remove mirror session + """ + self.setup_db(dvs) + + session1 = "TEST_SESSION1" + session2 = "TEST_SESSION2" + src_port1 = "Ethernet0" + src_port2 = "Ethernet4" + src_port3 = "Ethernet8" + src_port4 = "Ethernet12" + dst_port1 = "Ethernet16" + dst_port2 = "Ethernet20" + invld_port = "Ethernet" + src_oid1 = self.getPortOid(dvs, src_port1) + src_oid2 = self.getPortOid(dvs, src_port2) + src_oid3 = self.getPortOid(dvs, src_port3) + src_oid4 = self.getPortOid(dvs, src_port4) + queue = 1 + + # Sub test 1 + # Create mirror session with multiple source ports, verify that session is active + self.create_mirror_span_session(session1, dst_port1, src_port1+","+src_port2+","+src_port3, "BOTH") + assert self.get_mirror_session_state(session1)["status"] == "active" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + # verify asicdb + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 2 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == dst_port1 + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # remove mirror session + self.remove_mirror_session(session1) + + #Subtest 2 + # create mirror session with valid and invalid ports. + self.create_mirror_span_session(session1, dst_port1, src_port1+','+invld_port+','+src_port2, "BOTH") + self.check_mirror_session_state(session1, False) + + # Subtest 3 + # create mirror session with multiple source ports. + self.create_mirror_span_session(session1, invld_port, src_port1+','+src_port2+','+src_port3, "BOTH") + self.check_mirror_session_state(session1, False) + + # create mirror session + self.create_mirror_span_session(session1, dst_port1, src_port1+","+src_port2, "BOTH") + assert self.get_mirror_session_state(session1)["status"] == "active" + self.create_mirror_span_session(session2, dst_port2, src_port3+","+src_port4, "BOTH") + assert self.get_mirror_session_state(session2)["status"] == "active" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 2 + + # verify asicdb + (status1, fvs1) = tbl.get(mirror_entries[0]) + (status2, fvs2) = tbl.get(mirror_entries[1]) + assert status1 == True and status2 == True + assert len(fvs1) == 2 and len(fvs2) == 2 + for fv in fvs1: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + if dvs.asicdb.portoidmap[fv[1]] == dst_port1: + session_oid1 = mirror_entries[0] + if dvs.asicdb.portoidmap[fv[1]] == dst_port2: + session_oid2 = mirror_entries[0] + + for fv in fvs2: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + if dvs.asicdb.portoidmap[fv[1]] == dst_port1: + session_oid1 = mirror_entries[1] + if dvs.asicdb.portoidmap[fv[1]] == dst_port2: + session_oid2 = mirror_entries[1] + assert session_oid1 is not None or session_oid2 is not None + + (status1, fvs1) = tbl.get(session_oid1) + for fv in fvs1: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == dst_port1 + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": + assert fv[1] == policer_oid1 + + (status1, fvs2) = tbl.get(session_oid2) + for fv in fvs2: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == dst_port2 + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": + assert fv[1] == policer_oid2 + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 2 + + session_status1= "1:"+format(session_oid1) + session_status2="1:"+format(session_oid2) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status1 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status1 + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status1 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status1 + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status2 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status2 + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status2 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status2 + + # remove mirror session + self.remove_mirror_session(session1) + self.remove_mirror_session(session2) + + def create_policer(self, name): + tbl = swsscommon.Table(self.cdb, "POLICER") + fvs = swsscommon.FieldValuePairs([("meter_type", "packets"), + ("mode", "sr_tcm"), + ("cir", "600"), + ("cbs", "600"), + ("red_packet_action", "drop")]) + tbl.set(name, fvs) + time.sleep(1) + + def remove_policer(self, name): + tbl = swsscommon.Table(self.cdb, "POLICER") + tbl._del(name) + time.sleep(1) + + def test_PortMirrorPolicerAddRemove(self, dvs, testlog): + """ + This test covers the basic SPAN mirror session creation and removal operations + Operation flow: + 1. Create mirror session with only dst_port and policer , verify session becomes active + 2. Verify policer config is proper. + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + src_port = "Ethernet12" + dst_port = "Ethernet16" + invld_port = "Invalid" + policer= "POLICER" + src_oid = self.getPortOid(dvs, src_port) + + # create policer + self.create_policer(policer) + + # Sub Test 1 + # create mirror session + self.create_mirror_span_session(session, "Ethernet16", None, None, None, policer) + assert self.get_mirror_session_state(session)["status"] == "active" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_POLICER") + policer_entries = tbl.getKeys() + assert len(policer_entries) == 1 + policer_oid = policer_entries[0] + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + # verify asicdb + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 3 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": + assert fv[1] == policer_oid + + # remove mirror session + self.remove_mirror_session(session) + self.remove_policer(policer) + + def test_PortMirrorPolicerMultiAddRemove(self, dvs, testlog): + """ + This test covers the SPAN mirror session with multiple source ports and multiple policers. + Operation flow: + 1. Create mirror session with multiple source ports and policers. + 2. Verify mirror and policer config is proper. + """ + self.setup_db(dvs) + + session1 = "TEST_SESSION1" + session2 = "TEST_SESSION2" + src_port1 = "Ethernet0" + src_port2 = "Ethernet4" + src_port3 = "Ethernet8" + src_port4 = "Ethernet12" + dst_port1 = "Ethernet16" + dst_port2 = "Ethernet20" + policer1= "POLICER1" + policer2= "POLICER2" + src_oid1 = self.getPortOid(dvs, src_port1) + src_oid2 = self.getPortOid(dvs, src_port2) + src_oid3 = self.getPortOid(dvs, src_port3) + src_oid4 = self.getPortOid(dvs, src_port4) + + # create policer + self.create_policer(policer1) + # create policer + self.create_policer(policer2) + + # create mirror session + source=src_port1+","+src_port2 + self.create_mirror_span_session(session1, dst_port1, source, "BOTH", None, policer1) + assert self.get_mirror_session_state(session1)["status"] == "active" + # create mirror session + source=src_port3+","+src_port4 + self.create_mirror_span_session(session2, dst_port2, source, "BOTH", None, policer2) + assert self.get_mirror_session_state(session2)["status"] == "active" + + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_POLICER") + policer_entries = tbl.getKeys() + assert len(policer_entries) == 2 + policer_oid1 = policer_entries[1] + policer_oid2 = policer_entries[0] + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 2 + + # verify asicdb + (status1, fvs1) = tbl.get(mirror_entries[0]) + (status2, fvs2) = tbl.get(mirror_entries[1]) + assert status1 == True and status2 == True + assert len(fvs1) == 3 and len(fvs2) == 3 + for fv in fvs1: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + if dvs.asicdb.portoidmap[fv[1]] == dst_port1: + session_oid1 = mirror_entries[0] + if dvs.asicdb.portoidmap[fv[1]] == dst_port2: + session_oid2 = mirror_entries[0] + + for fv in fvs2: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + if dvs.asicdb.portoidmap[fv[1]] == dst_port1: + session_oid1 = mirror_entries[1] + if dvs.asicdb.portoidmap[fv[1]] == dst_port2: + session_oid2 = mirror_entries[1] + assert session_oid1 is not None or session_oid2 is not None + + (status1, fvs1) = tbl.get(session_oid1) + for fv in fvs1: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == dst_port1 + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": + assert fv[1] == policer_oid1 or fv[1] == policer_oid2 + + (status1, fvs2) = tbl.get(session_oid2) + for fv in fvs2: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == dst_port2 + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": + assert fv[1] == policer_oid2 or fv[1] == policer_oid1 + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 2 + + session_status1= "1:"+format(session_oid1) + session_status2="1:"+format(session_oid2) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status1 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status1 + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status1 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status1 + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status2 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status2 + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status2 + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status2 + + # remove mirror session + self.remove_mirror_session(session1) + self.remove_mirror_session(session2) + + def create_acl_table(self, table, interfaces): + tbl = swsscommon.Table(self.cdb, "ACL_TABLE") + fvs = swsscommon.FieldValuePairs([("policy_desc", "mirror_test"), + ("type", "mirror"), + ("ports", ",".join(interfaces))]) + tbl.set(table, fvs) + time.sleep(1) + + def remove_acl_table(self, table): + tbl = swsscommon.Table(self.cdb, "ACL_TABLE") + tbl._del(table) + time.sleep(1) + + def create_mirror_acl_dscp_rule(self, table, rule, dscp, session): + tbl = swsscommon.Table(self.cdb, "ACL_RULE") + fvs = swsscommon.FieldValuePairs([("priority", "1000"), + ("mirror_action", session), + ("DSCP", dscp)]) + tbl.set(table + "|" + rule, fvs) + time.sleep(1) + + def remove_mirror_acl_dscp_rule(self, table, rule): + tbl = swsscommon.Table(self.cdb, "ACL_RULE") + tbl._del(table + "|" + rule) + time.sleep(1) + + def test_PortMirrorPolicerWithAcl(self, dvs, testlog): + """ + This test covers the port mirroring with policer and ACL configurations. + Operation flow: + 1. Create port mirror session with policer. + 2. Create ACL and configure mirror + 2. Verify mirror and ACL config is proper. + """ + self.setup_db(dvs) + + session = "MIRROR_SESSION" + policer= "POLICER" + acl_table = "MIRROR_TABLE" + acl_rule = "MIRROR_RULE" + dst_port = "Ethernet16" + + # create policer + self.create_policer(policer) + + # create mirror session + self.create_mirror_span_session(session, dst_port, None, None, None, policer=policer) + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + mirror_oid = mirror_entries[0] + + # create acl table + self.create_acl_table(acl_table, ["Ethernet0", "Ethernet4"]) + + # create acl rule with dscp value and mask + self.create_mirror_acl_dscp_rule(acl_table, acl_rule, "8/56", session) + + # assert acl rule is created + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY") + rule_entries = [k for k in tbl.getKeys() if k not in dvs.asicdb.default_acl_entries] + assert len(rule_entries) == 1 + + (status, fvs) = tbl.get(rule_entries[0]) + assert status == True + for fv in fvs: + if fv[0] == "SAI_ACL_ENTRY_ATTR_FIELD_DSCP": + assert fv[1] == "8&mask:0x38" + if fv[0] == "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS": + assert fv[1] == "1:" + mirror_oid + + # remove acl rule + self.remove_mirror_acl_dscp_rule(acl_table, acl_rule) + # remove acl table + self.remove_acl_table(acl_table) + self.remove_mirror_session(session) + + # remove policer + self.remove_policer(policer) + + + def create_port_channel(self, dvs, channel): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "9100")]) + tbl.set("PortChannel" + channel, fvs) + dvs.runcmd("ip link add PortChannel" + channel + " type bond") + tbl = swsscommon.Table(self.sdb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("state", "ok")]) + tbl.set("PortChannel" + channel, fvs) + time.sleep(1) + + def remove_port_channel(self, dvs, channel): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") + tbl._del("PortChannel" + channel) + dvs.runcmd("ip link del PortChannel" + channel) + tbl = swsscommon.Table(self.sdb, "LAG_TABLE") + tbl._del("PortChannel" + channel) + time.sleep(1) + + def create_port_channel_member(self, channel, interface): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + tbl.set("PortChannel" + channel + ":" + interface, fvs) + time.sleep(1) + + def remove_port_channel_member(self, channel, interface): + tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") + tbl._del("PortChannel" + channel + ":" + interface) + time.sleep(1) + + def test_LAGMirorrSpanAddRemove(self, dvs, testlog): + """ + This test covers the LAG mirror session creation and removal operations + Operation flow: + 1. Create port channel with 2 members. + 2. Create mirror session with LAG as source port. + 3. Verify that source ports have proper mirror config. + 4. Remove port from port-channel and verify mirror config is removed from the port. + 5. Remove second port and verify mirror config is removed. + """ + self.setup_db(dvs) + + session = "TEST_SESSION" + dst_port = "Ethernet16" + po_src_port = "PortChannel008" + src_port1 = "Ethernet0" + src_port2 = "Ethernet4" + src_oid1 = self.getPortOid(dvs, src_port1) + src_oid2 = self.getPortOid(dvs, src_port2) + + # create port channel; create port channel member + self.create_port_channel(dvs, "008") + self.create_port_channel_member("008", src_port1) + self.create_port_channel_member("008", src_port2) + + # bring up port channel and port channel member + self.set_interface_status(dvs, po_src_port, "up") + self.set_interface_status(dvs, src_port1, "up") + self.set_interface_status(dvs, src_port2, "up") + + # Sub Test 1 + self.create_mirror_span_session(session, dst_port, po_src_port, "BOTH") + assert self.get_mirror_session_state(session)["status"] == "active" + + # check asic database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") + mirror_entries = tbl.getKeys() + assert len(mirror_entries) == 1 + + # verify asicdb + (status, fvs) = tbl.get(mirror_entries[0]) + assert status == True + assert len(fvs) == 2 + for fv in fvs: + if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": + assert dvs.asicdb.portoidmap[fv[1]] == dst_port + elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": + assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" + + session_status= "1:"+format(mirror_entries[0]) + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # Verify port has mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + # Sub Test 2 + # remove port channel member; remove port channel + self.remove_port_channel_member("008", src_port1) + + session_status= "1:"+format(mirror_entries[0]) + + # Verify first port doesnt have any mirror config + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + # Verify second port has mirror config + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == session_status + # Verify port has egress mirror session enabled with session oid. + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == session_status + + self.remove_port_channel_member("008", src_port2) + + # Verify second port doesnt have any mirror config + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') + assert status == None or status == "0:null" + + self.remove_port_channel(dvs, "008") + self.remove_mirror_session(session) From b92c3d4f2548b788a7c75e0db912bc8082956da3 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Mon, 29 Jun 2020 09:55:10 -0700 Subject: [PATCH 3/8] Addressed review comments. --- orchagent/mirrororch.cpp | 129 +++- orchagent/mirrororch.h | 13 +- tests/conftest.py | 33 + tests/dvslib/dvs_acl.py | 10 + tests/dvslib/dvs_mirror.py | 107 ++++ tests/dvslib/dvs_policer.py | 18 + tests/test_mirror_port_erspan.py | 1012 +++++++++--------------------- tests/test_mirror_port_span.py | 1001 +++++++++++------------------ 8 files changed, 939 insertions(+), 1384 deletions(-) create mode 100644 tests/dvslib/dvs_mirror.py create mode 100644 tests/dvslib/dvs_policer.py diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index 4d01c88c300..03fb853c1c5 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -265,6 +265,76 @@ bool MirrorOrch::decreaseRefCount(const string& name) return true; } +bool MirrorOrch::validateDstPort(const string& dstPort) +{ + Port port; + if (!m_portsOrch->getPort(dstPort, port) && port.m_type != Port::PHY) + { + SWSS_LOG_ERROR("Failed to locate port %s", dstPort.c_str()); + return false; + } + return true; +} + +bool MirrorOrch::checkPortExistsInSrcPortList(const string& port, const string& srcPort) +{ + auto ports = tokenize(srcPort, ','); + if (ports.size() != 0) + { + for (auto alias : ports) + { + if(port == alias) + { + return true; + } + } + } + + return false; +} + +bool MirrorOrch::validateSrcPort(const string& srcPort) +{ + auto ports = tokenize(srcPort, ','); + + if (ports.size() != 0) + { + for (auto alias : ports) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_ERROR("Failed to locate Port/LAG %s", alias.c_str()); + return false; + } + + if(!(port.m_type == Port::PHY || port.m_type == Port::LAG)) + { + SWSS_LOG_ERROR("Not supported port %s", alias.c_str()); + return false; + } + + // Check if the ports in LAG are part of source port list + if (port.m_type == Port::LAG) + { + vector portv; + m_portsOrch->getLagMember(port, portv); + for (const auto p : portv) + { + if (checkPortExistsInSrcPortList(p.m_alias, srcPort)) + { + SWSS_LOG_ERROR("Port %s in LAG %s is also part of src_port config %s", + p.m_alias.c_str(), port.m_alias.c_str(), srcPort.c_str()); + return false; + } + } + } + } + } + + return true; +} + void MirrorOrch::createEntry(const string& key, const vector& data) { SWSS_LOG_ENTER(); @@ -331,36 +401,26 @@ void MirrorOrch::createEntry(const string& key, const vector& d } else if (fvField(i) == MIRROR_SESSION_SRC_PORT) { - auto ports = tokenize(fvValue(i), ','); - if (ports.size() != 0) + if (!validateSrcPort(fvValue(i))) { - for (auto alias : ports) - { - Port port; - if (!gPortsOrch->getPort(alias, port)) - { - SWSS_LOG_ERROR("Failed to locate port/LAG %s", alias.c_str()); - return; - } - } + SWSS_LOG_ERROR("Failed to get valid source port list %s", fvValue(i).c_str()); + return; } entry.src_port = fvValue(i); } else if (fvField(i) == MIRROR_SESSION_DST_PORT) { - Port dst_port; - if (!m_portsOrch->getPort(fvValue(i), dst_port)) + if (!validateDstPort(fvValue(i))) { - SWSS_LOG_ERROR("Failed to locate port %s", fvValue(i).c_str()); + SWSS_LOG_ERROR("Failed to get valid destination port %s", fvValue(i).c_str()); return; } entry.dst_port = fvValue(i); - } else if (fvField(i) == MIRROR_SESSION_DIRECTION) { - if (!(fvValue(i) == mirror_rx_direction || fvValue(i) == mirror_tx_direction - || fvValue(i) == mirror_both_direction)) + if (!(fvValue(i) == MIRROR_RX_DIRECTION || fvValue(i) == MIRROR_TX_DIRECTION + || fvValue(i) == MIRROR_BOTH_DIRECTION)) { SWSS_LOG_ERROR("Failed to get valid direction %s", fvValue(i).c_str()); return; @@ -395,7 +455,7 @@ void MirrorOrch::createEntry(const string& key, const vector& d setSessionState(key, entry); - if (entry.type == mirror_session_span && !entry.dst_port.empty()) + if (entry.type == MIRROR_SESSION_SPAN && !entry.dst_port.empty()) { auto &session1 = m_syncdMirrors.find(key)->second; activateSession(key, session1); @@ -430,7 +490,7 @@ task_process_status MirrorOrch::deleteEntry(const string& name) if (session.status) { - if (session.type != mirror_session_span) + if (session.type != MIRROR_SESSION_SPAN) { m_routeOrch->detach(this, session.dstIp); } @@ -700,8 +760,9 @@ bool MirrorOrch::setUnsetPortMirror(Port port, status = sai_port_api->set_port_attribute(p.m_port_id, &port_attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to configure mirror session port %s: %s, status %d, sessionId %x\n", - port.m_alias.c_str(), p.m_alias.c_str(), status, sessionId); + SWSS_LOG_ERROR("Failed to configure %s session on port %s: %s, status %d, sessionId %x\n", + ingress ? "RX" : "TX", port.m_alias.c_str(), + p.m_alias.c_str(), status, sessionId); return false; } } @@ -711,8 +772,8 @@ bool MirrorOrch::setUnsetPortMirror(Port port, status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to configure mirror session to port %s, status %d, sessionId %x\n", - port.m_alias.c_str(), status, sessionId); + SWSS_LOG_ERROR("Failed to configure %s session on port %s, status %d, sessionId %x\n", + ingress ? "RX" : "TX", port.m_alias.c_str(), status, sessionId); return false; } } @@ -732,15 +793,23 @@ bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& ses SWSS_LOG_ERROR("Failed to locate port/LAG %s", alias.c_str()); return false; } - if (session.direction == mirror_rx_direction || session.direction == mirror_both_direction) + if (session.direction == MIRROR_RX_DIRECTION || session.direction == MIRROR_BOTH_DIRECTION) { if (!setUnsetPortMirror(port, true, set, session.sessionId)) + { + SWSS_LOG_ERROR("Failed to configure mirror session %s port %s\n", + name.c_str(), port.m_alias.c_str()); return false; + } } - if (session.direction == mirror_tx_direction || session.direction == mirror_both_direction) + if (session.direction == MIRROR_TX_DIRECTION || session.direction == MIRROR_BOTH_DIRECTION) { if (!setUnsetPortMirror(port, false, set, session.sessionId)) + { + SWSS_LOG_ERROR("Failed to configure mirror session %s port %s \n", + name.c_str(), port.m_alias.c_str()); return false; + } } } } @@ -767,7 +836,7 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) attrs.push_back(attr); } - if (session.type == mirror_session_span) + if (session.type == MIRROR_SESSION_SPAN) { Port dst_port; if (!m_portsOrch->getPort(session.dst_port, dst_port)) @@ -1225,16 +1294,18 @@ void MirrorOrch::updateLagMember(const LagMemberUpdate& update) // Check the following conditions: // 1) Session is active // 2) LAG is part of mirror session source ports. + // 3) Member port is not part of session source ports. // if the above condition matches then set/unset mirror configuration to new member port. if (session.status && !session.src_port.empty() && - session.src_port.find(update.lag.m_alias.c_str()) != std::string::npos) + session.src_port.find(update.lag.m_alias.c_str()) != std::string::npos && + !checkPortExistsInSrcPortList(update.member.m_alias, session.src_port)) { - if (session.direction == mirror_rx_direction || session.direction == mirror_both_direction) + if (session.direction == MIRROR_RX_DIRECTION || session.direction == MIRROR_BOTH_DIRECTION) { setUnsetPortMirror(update.member, true, update.add, session.sessionId); } - if (session.direction == mirror_tx_direction || session.direction == mirror_both_direction) + if (session.direction == MIRROR_TX_DIRECTION || session.direction == MIRROR_BOTH_DIRECTION) { setUnsetPortMirror(update.member, false, update.add, session.sessionId); } diff --git a/orchagent/mirrororch.h b/orchagent/mirrororch.h index a4e9c73fe7d..73eaafde35f 100644 --- a/orchagent/mirrororch.h +++ b/orchagent/mirrororch.h @@ -18,11 +18,11 @@ #include #include -const string mirror_rx_direction = "RX"; -const string mirror_tx_direction = "TX"; -const string mirror_both_direction = "BOTH"; -const string mirror_session_span = "SPAN"; -const string mirror_session_erspan = "ERSPAN"; +#define MIRROR_RX_DIRECTION "RX" +#define MIRROR_TX_DIRECTION "TX" +#define MIRROR_BOTH_DIRECTION "BOTH" +#define MIRROR_SESSION_SPAN "SPAN" +#define MIRROR_SESSION_ERSPAN "ERSPAN" /* * Contains session data specified by user in config file @@ -128,6 +128,9 @@ class MirrorOrch : public Orch, public Observer, public Subject void updateLagMember(const LagMemberUpdate&); void updateVlanMember(const VlanMemberUpdate&); + bool checkPortExistsInSrcPortList(const string& port, const string& srcPort); + bool validateSrcPort(const string& srcPort); + bool validateDstPort(const string& dstPort); bool setUnsetPortMirror(Port port, bool ingress, bool set, sai_object_id_t sessionId); bool configurePortMirrorSession(const string&, MirrorEntry&, bool enable); diff --git a/tests/conftest.py b/tests/conftest.py index fac32b32176..a62dcc2a96e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,8 @@ from dvslib import dvs_acl from dvslib import dvs_vlan from dvslib import dvs_lag +from dvslib import dvs_mirror +from dvslib import dvs_policer def ensure_system(cmd): (rc, output) = commands.getstatusoutput(cmd) @@ -816,6 +818,26 @@ def remove_neighbor(self, interface, ip): tbl._del(interface + ":" + ip) time.sleep(1) + def add_route(self, prefix, nexthop): + self.runcmd("ip route add " + prefix + " via " + nexthop) + time.sleep(1) + + def remove_route(self, prefix): + self.runcmd("ip route del " + prefix) + time.sleep(1) + + def create_fdb(self, vlan, mac, interface): + tbl = swsscommon.ProducerStateTable(self.pdb, "FDB_TABLE") + fvs = swsscommon.FieldValuePairs([("port", interface), + ("type", "dynamic")]) + tbl.set("Vlan" + vlan + ":" + mac, fvs) + time.sleep(1) + + def remove_fdb(self, vlan, mac): + tbl = swsscommon.ProducerStateTable(self.pdb, "FDB_TABLE") + tbl._del("Vlan" + vlan + ":" + mac) + time.sleep(1) + def setup_db(self): self.pdb = swsscommon.DBConnector(0, self.redis_sock, 0) self.adb = swsscommon.DBConnector(1, self.redis_sock, 0) @@ -1023,6 +1045,17 @@ def dvs_vlan_manager(request, dvs): dvs.get_state_db(), dvs.get_counters_db(), dvs.get_app_db()) +@pytest.yield_fixture(scope="class") +def dvs_mirror_manager(request, dvs): + request.cls.dvs_mirror = dvs_mirror.DVSMirror(dvs.get_asic_db(), + dvs.get_config_db(), + dvs.get_state_db(), + dvs.get_counters_db(), + dvs.get_app_db()) +@pytest.yield_fixture(scope="class") +def dvs_policer_manager(request, dvs): + request.cls.dvs_policer = dvs_policer.DVSPolicer(dvs.get_asic_db(), + dvs.get_config_db()) ##################### DPB fixtures ########################################### def create_dpb_config_file(dvs): cmd = "sonic-cfggen -j /etc/sonic/init_cfg.json -j /tmp/ports.json --print-data > /tmp/dpb_config_db.json" diff --git a/tests/dvslib/dvs_acl.py b/tests/dvslib/dvs_acl.py index e859b23aaee..d21add4149c 100644 --- a/tests/dvslib/dvs_acl.py +++ b/tests/dvslib/dvs_acl.py @@ -136,6 +136,16 @@ def create_acl_rule(self, table_name, rule_name, qualifiers, action="FORWARD", p self.config_db.create_entry("ACL_RULE", "{}|{}".format(table_name, rule_name), fvs) + def create_mirror_acl_rule(self, table_name, rule_name, qualifiers, priority="2020"): + fvs = { + "priority": priority + } + + for k, v in qualifiers.items(): + fvs[k] = v + + self.config_db.create_entry("ACL_RULE", "{}|{}".format(table_name, rule_name), fvs) + def remove_acl_rule(self, table_name, rule_name): self.config_db.delete_entry("ACL_RULE", "{}|{}".format(table_name, rule_name)) diff --git a/tests/dvslib/dvs_mirror.py b/tests/dvslib/dvs_mirror.py new file mode 100644 index 00000000000..c90e5da2011 --- /dev/null +++ b/tests/dvslib/dvs_mirror.py @@ -0,0 +1,107 @@ +from dvs_database import DVSDatabase + +class DVSMirror(object): + def __init__(self, adb, cdb, sdb, cntrdb, appdb): + self.asic_db = adb + self.config_db = cdb + self.state_db = sdb + self.counters_db = cntrdb + self.app_db = appdb + + def src_ports_to_list(): + src_port_list = [] + for port in src_ports.split(","): + src_port_list.append(port) + src_port=",".join(src_port_list) + + def create_span_session(self, name, dst_port, src_ports=None, direction="BOTH", queue=None, policer=None): + mirror_entry = {"type": "SPAN"} + if dst_port: + mirror_entry["dst_port"] = dst_port + + if src_ports: + mirror_entry["src_port"] = src_ports + # set direction without source port to uncover any swss issues. + mirror_entry["direction"] = direction + + if queue: + mirror_entry["queue"] = queue + if policer: + mirror_entry["policer"] = policer + self.config_db.create_entry("MIRROR_SESSION", name, mirror_entry) + + def create_erspan_session(self, name, src, dst, gre, dscp, ttl, queue, policer=None, src_ports=None, direction="BOTH"): + mirror_entry = {"type": "ERSPAN"} + mirror_entry["src_ip"] = src + mirror_entry["dst_ip"] = dst + mirror_entry["gre_type"] = gre + mirror_entry["dscp"] = dscp + mirror_entry["ttl"] = ttl + mirror_entry["queue"] = queue + if policer: + mirror_entry["policer"] = policer + if src_ports: + mirror_entry["src_port"] = src_ports + mirror_entry["direction"] = direction + + self.config_db.create_entry("MIRROR_SESSION", name, mirror_entry) + + def remove_mirror_session(self, name): + self.config_db.delete_entry("MIRROR_SESSION", name) + + def verify_no_mirror(self): + self.config_db.wait_for_n_keys("MIRROR_SESSION", 0) + self.state_db.wait_for_n_keys("MIRROR_SESSION_TABLE", 0) + + def verify_session_status(self, name, status="active", expected=1): + self.state_db.wait_for_n_keys("MIRROR_SESSION_TABLE", expected) + if expected: + self.state_db.wait_for_field_match("MIRROR_SESSION_TABLE", name, {"status": status}) + + def verify_port_mirror_config(self, dvs, ports, direction, session_oid="null"): + fvs = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + fvs = dict(fvs) + for p in ports: + port_oid = fvs.get(p) + member = dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid) + if direction in {"RX", "BOTH"}: + assert member["SAI_PORT_ATTR_INGRESS_MIRROR_SESSION"] == "1:"+session_oid + else: + assert "SAI_PORT_ATTR_INGRESS_MIRROR_SESSION" not in member.keys() or member["SAI_PORT_ATTR_INGRESS_MIRROR_SESSION"] == "0:null" + if direction in {"TX", "BOTH"}: + assert member["SAI_PORT_ATTR_EGRESS_MIRROR_SESSION"] == "1:"+session_oid + else: + assert "SAI_PORT_ATTR_EGRESS_MIRROR_SESSION" not in member.keys() or member["SAI_PORT_ATTR_EGRESS_MIRROR_SESSION"] == "0:null" + + def verify_session_db(self, dvs, name, asic_table=None, asic=None, state=None, asic_size=None): + if asic: + fv_pairs = dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", asic_table) + assert all(fv_pairs.get(k) == v for k, v in asic.items()) + if asic_size: + assert asic_size == len(fv_pairs) + if state: + fv_pairs = dvs.state_db.get_entry("MIRROR_SESSION_TABLE", name) + assert all(fv_pairs.get(k) == v for k, v in state.items()) + + def verify_session_policer(self, dvs, policer_oid, cir): + if cir: + entry = dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_POLICER", policer_oid) + assert entry["SAI_POLICER_ATTR_CIR"] == cir + + def verify_session(self, dvs, name, asic_db=None, state_db=None, dst_oid=None, src_ports=None, direction="BOTH", policer=None, expected = 1, asic_size=None): + member_ids = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", expected) + session_oid=member_ids[0] + # with multiple sessions, match on dst_oid to get session_oid + if dst_oid: + for member in member_ids: + entry=dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", member) + if entry["SAI_MIRROR_SESSION_ATTR_MONITOR_PORT"] == dst_oid: + session_oid = member + + self.verify_session_db(dvs, name, session_oid, asic=asic_db, state=state_db, asic_size=asic_size) + if policer: + cir = dvs.config_db.get_entry("POLICER", policer)["cir"] + entry=dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", session_oid) + self.verify_session_policer(dvs, entry["SAI_MIRROR_SESSION_ATTR_POLICER"], cir) + if src_ports: + self.verify_port_mirror_config(dvs, src_ports, direction, session_oid=session_oid) diff --git a/tests/dvslib/dvs_policer.py b/tests/dvslib/dvs_policer.py new file mode 100644 index 00000000000..217e0fe8ea4 --- /dev/null +++ b/tests/dvslib/dvs_policer.py @@ -0,0 +1,18 @@ +class DVSPolicer(object): + def __init__(self, adb, cdb): + self.asic_db = adb + self.config_db = cdb + + def create_policer(self, name, type="packets", cir="600", cbs="600", mode="sr_tcm", red_action="drop" ): + policer_entry = {"meter_type": type, "mode": mode, + "cir": cir, "cbs": cbs, "red_packet_action": red_action} + self.config_db.create_entry("POLICER", name, policer_entry) + + def remove_policer(self, name): + self.config_db.delete_entry("POLICER", name) + + def verify_policer(self, name, expected=1): + self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_POLICER", expected) + + def verify_no_policer(self): + self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", 0) diff --git a/tests/test_mirror_port_erspan.py b/tests/test_mirror_port_erspan.py index 3a59f594e0f..3f1ac8dc469 100644 --- a/tests/test_mirror_port_erspan.py +++ b/tests/test_mirror_port_erspan.py @@ -6,449 +6,179 @@ from swsscommon import swsscommon from distutils.version import StrictVersion +@pytest.mark.usefixtures("testlog") +@pytest.mark.usefixtures('dvs_vlan_manager') +@pytest.mark.usefixtures('dvs_lag_manager') +@pytest.mark.usefixtures('dvs_mirror_manager') class TestMirror(object): - def setup_db(self, dvs): - self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) - self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) - self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) - self.sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) - - def set_interface_status(self, dvs, interface, admin_status): - if interface.startswith("PortChannel"): - tbl_name = "PORTCHANNEL" - elif interface.startswith("Vlan"): - tbl_name = "VLAN" - else: - tbl_name = "PORT" - tbl = swsscommon.Table(self.cdb, tbl_name) - fvs = swsscommon.FieldValuePairs([("admin_status", "up")]) - tbl.set(interface, fvs) - time.sleep(1) - - # when using FRR, route cannot be inserted if the neighbor is not - # connected. thus it is mandatory to force the interface up manually - if interface.startswith("PortChannel"): - dvs.runcmd("bash -c 'echo " + ("1" if admin_status == "up" else "0") +\ - " > /sys/class/net/" + interface + "/carrier'") - - def add_ip_address(self, interface, ip): - if interface.startswith("PortChannel"): - tbl_name = "PORTCHANNEL_INTERFACE" - elif interface.startswith("Vlan"): - tbl_name = "VLAN_INTERFACE" - else: - tbl_name = "INTERFACE" - tbl = swsscommon.Table(self.cdb, tbl_name) - fvs = swsscommon.FieldValuePairs([("NULL", "NULL")]) - tbl.set(interface + "|" + ip, fvs) - tbl.set(interface, fvs) - time.sleep(1) - - def remove_ip_address(self, interface, ip): - if interface.startswith("PortChannel"): - tbl_name = "PORTCHANNEL_INTERFACE" - elif interface.startswith("Vlan"): - tbl_name = "VLAN_INTERFACE" - else: - tbl_name = "INTERFACE" - tbl = swsscommon.Table(self.cdb, tbl_name) - tbl._del(interface + "|" + ip) - tbl._del(interface) - time.sleep(1) - - def add_neighbor(self, interface, ip, mac): - tbl = swsscommon.ProducerStateTable(self.pdb, "NEIGH_TABLE") - fvs = swsscommon.FieldValuePairs([("neigh", mac), - ("family", "IPv4")]) - tbl.set(interface + ":" + ip, fvs) - time.sleep(1) - - def remove_neighbor(self, interface, ip): - tbl = swsscommon.ProducerStateTable(self.pdb, "NEIGH_TABLE") - tbl._del(interface + ":" + ip) - time.sleep(1) - - def add_route(self, dvs, prefix, nexthop): - dvs.runcmd("ip route add " + prefix + " via " + nexthop) - time.sleep(1) - - def remove_route(self, dvs, prefix): - dvs.runcmd("ip route del " + prefix) - time.sleep(1) - - def create_policer(self, name): - tbl = swsscommon.Table(self.cdb, "POLICER") - fvs = swsscommon.FieldValuePairs([("meter_type", "packets"), - ("mode", "sr_tcm"), - ("cir", "600"), - ("cbs", "600"), - ("red_packet_action", "drop")]) - tbl.set(name, fvs) - time.sleep(1) - - def remove_policer(self, name): - tbl = swsscommon.Table(self.cdb, "POLICER") - tbl._del(name) - time.sleep(1) - - def getPortOid(self, dvs, port_name): - - cnt_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) - port_map_tbl = swsscommon.Table(cnt_db, 'COUNTERS_PORT_NAME_MAP') - - for k in port_map_tbl.get('')[1]: - if k[0] == port_name: - return k[1] - - - def getPortAttr(self, dvs, port_oid, port_attr): - - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - port_tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_PORT:{0}'.format(port_oid)) - - for k in port_tbl.get('')[1]: - if k[0] == port_attr: - return k[1] - - def create_mirror_erspan_session(self, name, src, dst, gre, dscp, ttl, queue, policer=None, src_port=None, direction=None): - tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") - if src_port is None and policer is None and direction is None: - fvs = swsscommon.FieldValuePairs([("src_ip", src), - ("dst_ip", dst), - ("gre_type", gre), - ("dscp", dscp), - ("ttl", ttl), - ("queue", queue)]) - elif policer is None: - fvs = swsscommon.FieldValuePairs([("src_ip", src), - ("dst_ip", dst), - ("gre_type", gre), - ("dscp", dscp), - ("ttl", ttl), - ("queue", queue), - ("src_port", src_port), - ("direction", direction)]) - else: - fvs = swsscommon.FieldValuePairs([("src_ip", src), - ("dst_ip", dst), - ("gre_type", gre), - ("dscp", dscp), - ("ttl", ttl), - ("queue", queue), - ("src_port", src_port), - ("direction", direction), - ("policer", policer)]) - tbl.set(name, fvs) - time.sleep(3) - - def remove_mirror_session(self, name): - tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") - tbl._del(name) - time.sleep(2) - - def get_mirror_session_status(self, name): - return self.get_mirror_session_state(name)["status"] - - def get_mirror_session_state(self, name): - tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") - (status, fvs) = tbl.get(name) - assert status == True - assert len(fvs) > 0 - return { fv[0]: fv[1] for fv in fvs } - - def check_mirror_session_state(self, name, status): - tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") - (session_status, fvs) = tbl.get(name) - assert session_status == status - def test_PortMirrorERSpanAddRemove(self, dvs, testlog): """ - This test covers the basic mirror session creation and removal operations + This test covers the basic ERSPANmirror session creation and removal operations Operation flow: - 1. Create mirror session with only dst_port - The session becomes active. - 2. Create mirror session with invalid dst_port, session becomes inactive. - 2. Create mirror session with invalid source port, the session becomes inactive, - 3. Create mirror session with multiple source ports, the session becomes active - 4. Create mirror session with valid and invalid source ports, the session becomes inactive - 5. Remove miror session + 1. Create mirror session with source ports. + The session remains inactive because no nexthop/neighbor exists + 2. Bring up port; assign IP; create neighbor; create route + The session remains inactive until the route is created + 3. Verify that port mirror config is proper. + 4. Remove route; remove neighbor; remove IP; bring down port + The session becomes inactive again till the end """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet0" - src_oid = self.getPortOid(dvs, src_port) + src_ports = "Ethernet12" + src_asic_ports = ["Ethernet12"] # create mirror session - self.create_mirror_erspan_session(session, "1.1.1.1", "2.2.2.2", "0x6558", "8", "100", "0", None, src_port, "BOTH") - assert self.get_mirror_session_state(session)["status"] == "inactive" + self.dvs_mirror.create_erspan_session(session, "1.1.1.1", "2.2.2.2", "0x6558", "8", "100", "0", None, src_ports) + self.dvs_mirror.verify_session_status(session, status="inactive") # bring up Ethernet16 - self.set_interface_status(dvs, "Ethernet16", "up") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.set_interface_status("Ethernet16", "up") + self.dvs_mirror.verify_session_status(session, status="inactive") # add IP address to Ethernet16 - self.add_ip_address("Ethernet16", "10.0.0.0/31") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_ip_address("Ethernet16", "10.0.0.0/31") + self.dvs_mirror.verify_session_status(session, status="inactive") # add neighbor to Ethernet16 - self.add_neighbor("Ethernet16", "10.0.0.1", "02:04:06:08:10:12") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_neighbor("Ethernet16", "10.0.0.1", "02:04:06:08:10:12") + self.dvs_mirror.verify_session_status(session, status="inactive") # add route to mirror destination via 10.0.0.1 - self.add_route(dvs, "2.2.2.2", "10.0.0.1") - assert self.get_mirror_session_state(session)["status"] == "active" - assert self.get_mirror_session_state(session)["monitor_port"] == "Ethernet16" - assert self.get_mirror_session_state(session)["dst_mac"] == "02:04:06:08:10:12" - assert self.get_mirror_session_state(session)["route_prefix"] == "2.2.2.2/32" - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 11 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE": - assert fv[1] == "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION": - assert fv[1] == "4" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TOS": - assert fv[1] == "32" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TTL": - assert fv[1] == "100" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS": - assert fv[1] == "1.1.1.1" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS": - assert fv[1] == "2.2.2.2" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS": - assert fv[1] == dvs.runcmd("bash -c \"ip link show eth0 | grep ether | awk '{print $2}'\"")[1].strip().upper() - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "02:04:06:08:10:12" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE": - assert fv[1] == "25944" # 0x6558 - else: - assert False - - # Check src_port state. - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + dvs.add_route("2.2.2.2", "10.0.0.1") + src_mac = dvs.runcmd("bash -c \"ip link show eth0 | grep ether | awk '{print $2}'\"")[1].strip().upper() + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet16"), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE", + "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE": "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL", + "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION": "4", + "SAI_MIRROR_SESSION_ATTR_TOS": "32", + "SAI_MIRROR_SESSION_ATTR_TTL": "100", + "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS": "1.1.1.1", + "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS": "2.2.2.2", + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "02:04:06:08:10:12", + "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS": src_mac, + "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE": "25944"} + expected_state_db = {"status": "active", + "monitor_port": "Ethernet16", + "dst_mac": "02:04:06:08:10:12", + "route_prefix": "2.2.2.2/32"} + self.dvs_mirror.verify_session_status(session) + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, state_db=expected_state_db, src_ports=src_asic_ports, asic_size=11) # remove route - self.remove_route(dvs, "2.2.2.2") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_route("2.2.2.2") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove neighbor - self.remove_neighbor("Ethernet16", "10.0.0.1") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_neighbor("Ethernet16", "10.0.0.1") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove IP address - self.remove_ip_address("Ethernet16", "10.0.0.0/31") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_ip_address("Ethernet16", "10.0.0.0/31") + self.dvs_mirror.verify_session_status(session, status="inactive") # bring down Ethernet16 - self.set_interface_status(dvs, "Ethernet16", "down") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.set_interface_status("Ethernet16", "down") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove mirror session - self.remove_mirror_session(session) - def create_vlan(self, dvs, vlan): - #dvs.runcmd("ip link del Bridge") - #dvs.runcmd("ip link add Bridge up type bridge") - tbl = swsscommon.Table(self.cdb, "VLAN") - fvs = swsscommon.FieldValuePairs([("vlanid", vlan)]) - tbl.set("Vlan" + vlan, fvs) - time.sleep(1) - - def remove_vlan(self, vlan): - tbl = swsscommon.Table(self.cdb, "VLAN") - tbl._del("Vlan" + vlan) - time.sleep(1) - - def create_vlan_member(self, vlan, interface): - tbl = swsscommon.Table(self.cdb, "VLAN_MEMBER") - fvs = swsscommon.FieldValuePairs([("tagging_mode", "untagged")]) - tbl.set("Vlan" + vlan + "|" + interface, fvs) - time.sleep(1) - - def remove_vlan_member(self, vlan, interface): - tbl = swsscommon.Table(self.cdb, "VLAN_MEMBER") - tbl._del("Vlan" + vlan + "|" + interface) - time.sleep(1) - - def create_fdb(self, vlan, mac, interface): - tbl = swsscommon.ProducerStateTable(self.pdb, "FDB_TABLE") - fvs = swsscommon.FieldValuePairs([("port", interface), - ("type", "dynamic")]) - tbl.set("Vlan" + vlan + ":" + mac, fvs) - time.sleep(1) - - def remove_fdb(self, vlan, mac): - tbl = swsscommon.ProducerStateTable(self.pdb, "FDB_TABLE") - tbl._del("Vlan" + vlan + ":" + mac) - time.sleep(1) - - - # Ignore testcase in Debian Jessie - # TODO: Remove this skip if Jessie support is no longer needed - @pytest.mark.skipif(StrictVersion(platform.linux_distribution()[1]) <= StrictVersion('8.9'), reason="Debian 8.9 or before has no support") + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + def test_PortMirrorToVlanAddRemove(self, dvs, testlog): """ This test covers basic mirror session creation and removal operation with destination port sits in a VLAN Opeartion flow: - 1. Create mirror session + 1. Create mirror session with source ports. 2. Create VLAN; assign IP; create neighbor; create FDB The session should be up only at this time. + verify source port mirror config. 3. Remove FDB; remove neighbor; remove IP; remove VLAN 4. Remove mirror session """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet0" - src_oid = self.getPortOid(dvs, src_port) + src_ports = "Ethernet12,Ethernet16" + src_asic_ports = ["Ethernet12", "Ethernet16"] + vlan_id = "10" + vlan = "Vlan10" # create mirror session - self.create_mirror_erspan_session(session, "5.5.5.5", "6.6.6.6", "0x6558", "8", "100", "0", None, src_port, "BOTH") - assert self.get_mirror_session_state(session)["status"] == "inactive" + self.dvs_mirror.create_erspan_session(session, "5.5.5.5", "6.6.6.6", "0x6558", "8", "100", "0", None, src_ports, direction="TX") + self.dvs_mirror.verify_session_status(session, status="inactive") # create vlan; create vlan member - self.create_vlan(dvs, "6") - self.create_vlan_member("6", "Ethernet4") + self.dvs_vlan.create_vlan(vlan_id) + self.dvs_vlan.create_vlan_member(vlan_id, "Ethernet4") # bring up vlan and member - self.set_interface_status(dvs, "Vlan6", "up") - self.set_interface_status(dvs, "Ethernet4", "up") + dvs.set_interface_status(vlan, "up") + dvs.set_interface_status("Ethernet4", "up") # add ip address to vlan 6 - self.add_ip_address("Vlan6", "6.6.6.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_ip_address(vlan, "6.6.6.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # create neighbor to vlan 6 - self.add_neighbor("Vlan6", "6.6.6.6", "66:66:66:66:66:66") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_neighbor(vlan, "6.6.6.6", "66:66:66:66:66:66") + self.dvs_mirror.verify_session_status(session, status="inactive") # create fdb entry to ethernet4 - self.create_fdb("6", "66-66-66-66-66-66", "Ethernet4") - assert self.get_mirror_session_state(session)["status"] == "active" - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 16 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet4" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE": - assert fv[1] == "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION": - assert fv[1] == "4" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TOS": - assert fv[1] == "32" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TTL": - assert fv[1] == "100" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS": - assert fv[1] == "5.5.5.5" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS": - assert fv[1] == "6.6.6.6" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS": - assert fv[1] == dvs.runcmd("bash -c \"ip link show eth0 | grep ether | awk '{print $2}'\"")[1].strip().upper() - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "66:66:66:66:66:66" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE": - assert fv[1] == "25944" # 0x6558 - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": - assert fv[1] == "true" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_TPID": - assert fv[1] == "33024" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_ID": - assert fv[1] == "6" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_PRI": - assert fv[1] == "0" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_CFI": - assert fv[1] == "0" - else: - assert False - - # Check src_port state. - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + dvs.create_fdb(vlan_id, "66-66-66-66-66-66", "Ethernet4") + self.dvs_mirror.verify_session_status(session) + + src_mac = dvs.runcmd("bash -c \"ip link show eth0 | grep ether | awk '{print $2}'\"")[1].strip().upper() + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet4"), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE", + "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE": "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL", + "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION": "4", + "SAI_MIRROR_SESSION_ATTR_TOS": "32", + "SAI_MIRROR_SESSION_ATTR_TTL": "100", + "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS": "5.5.5.5", + "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS": "6.6.6.6", + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "66:66:66:66:66:66", + "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS": src_mac, + "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE": "25944", + "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": "true", + "SAI_MIRROR_SESSION_ATTR_VLAN_TPID": "33024", + "SAI_MIRROR_SESSION_ATTR_VLAN_ID": vlan_id, + "SAI_MIRROR_SESSION_ATTR_VLAN_PRI": "0", + "SAI_MIRROR_SESSION_ATTR_VLAN_CFI": "0"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, asic_size=16, direction="TX") + + dvs.set_interface_status("Ethernet4", "down") # remove fdb entry - self.remove_fdb("6", "66-66-66-66-66-66") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_fdb(vlan_id, "66-66-66-66-66-66") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove neighbor - self.remove_neighbor("Vlan6", "6.6.6.6") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_neighbor(vlan, "6.6.6.6") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove ip address - self.remove_ip_address("Vlan6", "6.6.6.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_ip_address(vlan, "6.6.6.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # bring down vlan and member - self.set_interface_status(dvs, "Ethernet4", "down") - self.set_interface_status(dvs, "Vlan6", "down") - - # remove vlan member; remove vlan - self.remove_vlan_member("6", "Ethernet4") - self.remove_vlan("6") + dvs.set_interface_status("Ethernet4", "down") + dvs.set_interface_status(vlan, "down") # remove mirror session - self.remove_mirror_session(session) - - def create_port_channel(self, dvs, channel): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") - fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "9100")]) - tbl.set("PortChannel" + channel, fvs) - dvs.runcmd("ip link add PortChannel" + channel + " type bond") - tbl = swsscommon.Table(self.sdb, "LAG_TABLE") - fvs = swsscommon.FieldValuePairs([("state", "ok")]) - tbl.set("PortChannel" + channel, fvs) - time.sleep(1) - - def remove_port_channel(self, dvs, channel): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") - tbl._del("PortChannel" + channel) - dvs.runcmd("ip link del PortChannel" + channel) - tbl = swsscommon.Table(self.sdb, "LAG_TABLE") - tbl._del("PortChannel" + channel) - time.sleep(1) - - def create_port_channel_member(self, channel, interface): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") - fvs = swsscommon.FieldValuePairs([("status", "enabled")]) - tbl.set("PortChannel" + channel + ":" + interface, fvs) - time.sleep(1) - - def remove_port_channel_member(self, channel, interface): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") - tbl._del("PortChannel" + channel + ":" + interface) - time.sleep(1) + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + + # remove vlan member; remove vlan + self.dvs_vlan.remove_vlan_member(vlan_id, "Ethernet4") + self.dvs_vlan.remove_vlan(vlan_id) def test_PortMirrorToLagAddRemove(self, dvs, testlog): @@ -456,84 +186,77 @@ def test_PortMirrorToLagAddRemove(self, dvs, testlog): This test covers basic mirror session creation and removal operations with destination port sits in a LAG Operation flow: - 1. Create mirror sesion + 1. Create mirror sesion with source ports, direction 2. Create LAG; assign IP; create directly connected neighbor The session shoudl be up only at this time. 3. Remove neighbor; remove IP; remove LAG 4. Remove mirror session """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet0" - src_oid = self.getPortOid(dvs, src_port) + src_ports = "Ethernet0,Ethernet4" + src_asic_ports = ["Ethernet0", "Ethernet4"] # create mirror session - self.create_mirror_erspan_session(session, "10.10.10.10", "11.11.11.11", "0x6558", "8", "100", "0", None, src_port, "TX") - assert self.get_mirror_session_state(session)["status"] == "inactive" + self.dvs_mirror.create_erspan_session(session, "10.10.10.10", "11.11.11.11", "0x6558", + "8", "100", "0", None, src_ports, "TX") + self.dvs_mirror.verify_session_status(session, status="inactive") # create port channel; create port channel member - self.create_port_channel(dvs, "008") - self.create_port_channel_member("008", "Ethernet88") + self.dvs_lag.create_port_channel("008") + lag_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.create_port_channel_member("008", "Ethernet88") + + # Verify the LAG has been initialized properly + lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 1) + fvs = self.dvs_vlan.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", lag_member_entries[0]) + assert len(fvs) == 4 + assert fvs.get("SAI_LAG_MEMBER_ATTR_LAG_ID") == lag_entries[0] + assert self.dvs_vlan.asic_db.port_to_id_map[fvs.get("SAI_LAG_MEMBER_ATTR_PORT_ID")] == "Ethernet88" # bring up port channel and port channel member - self.set_interface_status(dvs, "PortChannel008", "up") - self.set_interface_status(dvs, "Ethernet88", "up") + dvs.set_interface_status("PortChannel008", "up") + dvs.set_interface_status("Ethernet88", "up") # add ip address to port channel 008 - self.add_ip_address("PortChannel008", "11.11.11.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_ip_address("PortChannel008", "11.11.11.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # create neighbor to port channel 008 - self.add_neighbor("PortChannel008", "11.11.11.11", "88:88:88:88:88:88") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.add_neighbor("PortChannel008", "11.11.11.11", "88:88:88:88:88:88") + self.dvs_mirror.verify_session_status(session) # Check src_port state. - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - (status, fvs) = tbl.get(tbl.getKeys()[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet88" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "88:88:88:88:88:88" - - session_status= "1:"+format(mirror_entries[0]) - print src_oid - print session_status - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet88"), + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "88:88:88:88:88:88"} + + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, direction="TX") # remove neighbor - self.remove_neighbor("PortChannel008", "11.11.11.11") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_neighbor("PortChannel008", "11.11.11.11") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove ip address - self.remove_ip_address("PortChannel008", "11.11.11.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_ip_address("PortChannel008", "11.11.11.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # bring down port channel and port channel member - self.set_interface_status(dvs, "PortChannel008", "down") - self.set_interface_status(dvs, "Ethernet88", "down") + dvs.set_interface_status("PortChannel008", "down") + dvs.set_interface_status("Ethernet88", "down") # remove port channel member; remove port channel - self.remove_port_channel_member("008", "Ethernet88") - self.remove_port_channel(dvs, "008") - # remove mirror session - self.remove_mirror_session(session) + self.dvs_lag.remove_port_channel_member("008", "Ethernet88") + self.dvs_lag.remove_port_channel("008") + # remove mirror session + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() - # Ignore testcase in Debian Jessie - # TODO: Remove this skip if Jessie support is no longer needed - @pytest.mark.skipif(StrictVersion(platform.linux_distribution()[1]) <= StrictVersion('8.9'), reason="Debian 8.9 or before has no support") def test_PortMirrorDestMoveVlan(self, dvs, testlog): """ This test tests mirror session destination move from non-VLAN to VLAN @@ -547,120 +270,92 @@ def test_PortMirrorDestMoveVlan(self, dvs, testlog): 7. Disable non-VLAN monitor port 8. Remove mirror session """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet0" - src_oid = self.getPortOid(dvs, src_port) + src_ports = "Ethernet0" + src_asic_ports = ["Ethernet0"] # create mirror session - self.create_mirror_erspan_session(session, "7.7.7.7", "8.8.8.8", "0x6558", "8", "100", "0", None, src_port, "BOTH") - assert self.get_mirror_session_state(session)["status"] == "inactive" + self.dvs_mirror.create_erspan_session(session, "7.7.7.7", "8.8.8.8", "0x6558", "8", "100", "0", None, src_ports) + self.dvs_mirror.verify_session_status(session, status="inactive") # bring up port; add ip; add neighbor; add route - self.set_interface_status(dvs, "Ethernet32", "up") - self.add_ip_address("Ethernet32", "80.0.0.0/31") - self.add_neighbor("Ethernet32", "80.0.0.1", "02:04:06:08:10:12") - self.add_route(dvs, "8.8.0.0/16", "80.0.0.1") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.set_interface_status("Ethernet32", "up") + dvs.add_ip_address("Ethernet32", "80.0.0.0/31") + dvs.add_neighbor("Ethernet32", "80.0.0.1", "02:04:06:08:10:12") + dvs.add_route("8.8.0.0/16", "80.0.0.1") + + self.dvs_mirror.verify_session_status(session) # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - assert len(tbl.getKeys()) == 1 - (status, fvs) = tbl.get(tbl.getKeys()[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": - assert fv[1] == "false" + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet32")} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db) # mirror session move round 1 # create vlan; create vlan member; bring up vlan and member - self.create_vlan(dvs, "9") - self.create_vlan_member("9", "Ethernet48") - self.set_interface_status(dvs, "Vlan9", "up") - self.set_interface_status(dvs, "Ethernet48", "up") - assert self.get_mirror_session_state(session)["status"] == "active" + self.dvs_vlan.create_vlan("9") + self.dvs_vlan.create_vlan_member("9", "Ethernet48") + dvs.set_interface_status("Vlan9", "up") + dvs.set_interface_status("Ethernet48", "up") + + self.dvs_mirror.verify_session_status(session) # add ip address to vlan 9 - self.add_ip_address("Vlan9", "8.8.8.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_ip_address("Vlan9", "8.8.8.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # create neighbor to vlan 9 - self.add_neighbor("Vlan9", "8.8.8.8", "88:88:88:88:88:88") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_neighbor("Vlan9", "8.8.8.8", "88:88:88:88:88:88") + self.dvs_mirror.verify_session_status(session, status="inactive") # create fdb entry to ethernet48 - self.create_fdb("9", "88-88-88-88-88-88", "Ethernet48") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.create_fdb("9", "88-88-88-88-88-88", "Ethernet48") + self.dvs_mirror.verify_session_status(session) # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet48" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": - assert fv[1] == "true" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_TPID": - assert fv[1] == "33024" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_ID": - assert fv[1] == "9" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_PRI": - assert fv[1] == "0" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_CFI": - assert fv[1] == "0" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet48"), + "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": "true", + "SAI_MIRROR_SESSION_ATTR_VLAN_TPID": "33024", + "SAI_MIRROR_SESSION_ATTR_VLAN_ID": "9", + "SAI_MIRROR_SESSION_ATTR_VLAN_PRI": "0", + "SAI_MIRROR_SESSION_ATTR_VLAN_CFI": "0"} + + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports) # mirror session move round 2 # remove fdb entry - self.remove_fdb("9", "88-88-88-88-88-88") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_fdb("9", "88-88-88-88-88-88") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove neighbor - self.remove_neighbor("Vlan9", "8.8.8.8") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_neighbor("Vlan9", "8.8.8.8") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove ip address - self.remove_ip_address("Vlan9", "8.8.8.0/24") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.remove_ip_address("Vlan9", "8.8.8.0/24") + self.dvs_mirror.verify_session_status(session) - # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - assert len(tbl.getKeys()) == 1 - (status, fvs) = tbl.get(tbl.getKeys()[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_VLAN_HEADER_VALID": - assert fv[1] == "false" + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet32")} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db) # bring down vlan and member; remove vlan member; remove vlan - self.set_interface_status(dvs, "Ethernet48", "down") - self.set_interface_status(dvs, "Vlan9", "down") - self.remove_vlan_member("9", "Ethernet48") - self.remove_vlan("9") + dvs.set_interface_status("Ethernet48", "down") + dvs.set_interface_status("Vlan9", "down") + dvs.remove_vlan_member("9", "Ethernet48") + dvs.remove_vlan("9") # remove route; remove neighbor; remove ip; bring down port - self.remove_route(dvs, "8.8.8.0/24") - self.remove_neighbor("Ethernet32", "80.0.0.1") - self.remove_ip_address("Ethernet32", "80.0.0.0/31") - self.set_interface_status(dvs, "Ethernet32", "down") + dvs.remove_route("8.8.8.0/24") + dvs.remove_neighbor("Ethernet32", "80.0.0.1") + dvs.remove_ip_address("Ethernet32", "80.0.0.0/31") + dvs.set_interface_status("Ethernet32", "down") # remove mirror session - self.remove_mirror_session(session) + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() def test_PortMirrorDestMoveLag(self, dvs, testlog): @@ -676,163 +371,98 @@ def test_PortMirrorDestMoveLag(self, dvs, testlog): 7. Disable non-LAG monitor port 8. Remove mirror session """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet0" - src_oid = self.getPortOid(dvs, src_port) - + src_ports = "Ethernet0,Ethernet4" + src_asic_ports = ["Ethernet0", "Ethernet4"] # create mirror session - self.create_mirror_erspan_session(session, "12.12.12.12", "13.13.13.13", "0x6558", "8", "100", "0", None, src_port, "RX") - assert self.get_mirror_session_state(session)["status"] == "inactive" + self.dvs_mirror.create_erspan_session(session, "12.12.12.12", "13.13.13.13", "0x6558", "8", "100", "0", None, src_ports, direction="RX") + self.dvs_mirror.verify_session_status(session, status="inactive") # bring up port; add ip; add neighbor; add route - self.set_interface_status(dvs, "Ethernet64", "up") - self.add_ip_address("Ethernet64", "100.0.0.0/31") - self.add_neighbor("Ethernet64", "100.0.0.1", "02:04:06:08:10:12") - self.add_route(dvs, "13.13.0.0/16", "100.0.0.1") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.set_interface_status("Ethernet64", "up") + dvs.add_ip_address("Ethernet64", "100.0.0.0/31") + dvs.add_neighbor("Ethernet64", "100.0.0.1", "02:04:06:08:10:12") + dvs.add_route("13.13.0.0/16", "100.0.0.1") + self.dvs_mirror.verify_session_status(session) # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet64" - if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "02:04:06:08:10:12" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet64"), + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "02:04:06:08:10:12"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, direction="RX") # mirror session move round 1 # create port channel; create port channel member; bring up - self.create_port_channel(dvs, "080") - self.create_port_channel_member("080", "Ethernet32") - self.set_interface_status(dvs, "PortChannel080", "up") - self.set_interface_status(dvs, "Ethernet32", "up") + self.dvs_lag.create_port_channel("080") + lag_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.create_port_channel_member("080", "Ethernet32") + dvs.set_interface_status("PortChannel080", "up") + dvs.set_interface_status("Ethernet32", "up") # add ip address to port channel 080; create neighbor to port channel 080 - self.add_ip_address("PortChannel080", "200.0.0.0/31") - self.add_neighbor("PortChannel080", "200.0.0.1", "12:10:08:06:04:02") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.add_ip_address("PortChannel080", "200.0.0.0/31") + dvs.add_neighbor("PortChannel080", "200.0.0.1", "12:10:08:06:04:02") + self.dvs_mirror.verify_session_status(session) # add route - self.add_route(dvs, "13.13.13.0/24", "200.0.0.1") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.add_route("13.13.13.0/24", "200.0.0.1") + self.dvs_mirror.verify_session_status(session) - # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" - if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "12:10:08:06:04:02" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet32"), + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "12:10:08:06:04:02"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, direction="RX") # mirror session move round 2 # remove port channel member - self.remove_port_channel_member("080", "Ethernet32") - assert self.get_mirror_session_state(session)["status"] == "inactive" + self.dvs_lag.remove_port_channel_member("080", "Ethernet32") + self.dvs_mirror.verify_session_status(session, status="inactive") # mirror session move round 3 # create port channel member - self.create_port_channel_member("080", "Ethernet32") - assert self.get_mirror_session_state(session)["status"] == "active" + self.dvs_lag.create_port_channel_member("080", "Ethernet32") + self.dvs_mirror.verify_session_status(session) # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet32" - if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "12:10:08:06:04:02" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet32"), + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "12:10:08:06:04:02"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, direction="RX") # mirror session move round 4 # remove route - self.remove_route(dvs, "13.13.13.0/24") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.remove_route("13.13.13.0/24") + self.dvs_mirror.verify_session_status(session) - port_oid = "" # check monitor port - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet64" - if fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "02:04:06:08:10:12" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet64"), + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "02:04:06:08:10:12"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, direction="RX") # remove neighbor; remove ip address to port channel 080 - self.remove_neighbor("PortChannel080", "200.0.0.1") - self.remove_ip_address("PortChannel080", "200.0.0.0/31") + dvs.remove_neighbor("PortChannel080", "200.0.0.1") + dvs.remove_ip_address("PortChannel080", "200.0.0.0/31") # bring down; remove port channel member; remove port channel - self.set_interface_status(dvs, "Ethernet32", "down") - self.set_interface_status(dvs, "PortChannel080", "down") - self.remove_port_channel_member("080", "Ethernet32") - self.remove_port_channel(dvs, "080") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.set_interface_status("Ethernet32", "down") + dvs.set_interface_status("PortChannel080", "down") + self.dvs_lag.remove_port_channel_member("080", "Ethernet32") + self.dvs_lag.remove_port_channel("080") + self.dvs_mirror.verify_session_status(session) + # remove route; remove neighbor; remove ip; bring down port - self.remove_route(dvs, "13.13.0.0/16") - self.remove_neighbor("Ethernet64", "100.0.0.1") - self.remove_ip_address("Ethernet64", "100.0.0.0/31") - self.set_interface_status(dvs, "Ethernet64", "down") - assert self.get_mirror_session_state(session)["status"] == "inactive" - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + dvs.remove_route("13.13.0.0/16") + dvs.remove_neighbor("Ethernet64", "100.0.0.1") + dvs.remove_ip_address("Ethernet64", "100.0.0.0/31") + dvs.set_interface_status("Ethernet64", "down") + self.dvs_mirror.verify_session_status(session, status="inactive") + # remove mirror session - self.remove_mirror_session(session) + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() def test_LAGMirrorToERSPANLagAddRemove(self, dvs, testlog): """ @@ -847,105 +477,73 @@ def test_LAGMirrorToERSPANLagAddRemove(self, dvs, testlog): 5. Remove mirror session """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - po_src_port = "PortChannel001" - src_port1 = "Ethernet0" - src_port2 = "Ethernet4" - src_oid1 = self.getPortOid(dvs, src_port1) - src_oid2 = self.getPortOid(dvs, src_port2) + src_port1="Ethernet0" + po_src_port="PortChannel001" + src_port2="Ethernet4" + src_ports = "PortChannel001,Ethernet8" + src_asic_ports = ["Ethernet0", "Ethernet4", "Ethernet8"] # create port channel; create port channel member - self.create_port_channel(dvs, "001") - self.create_port_channel_member("001", src_port1) - self.create_port_channel_member("001", src_port2) + self.dvs_lag.create_port_channel("001") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.create_port_channel_member("001", src_port1) + self.dvs_lag.create_port_channel_member("001", src_port2) # bring up port channel and port channel member - self.set_interface_status(dvs, po_src_port, "up") - self.set_interface_status(dvs, src_port1, "up") - self.set_interface_status(dvs, src_port2, "up") + dvs.set_interface_status(po_src_port, "up") + dvs.set_interface_status(src_port1, "up") + dvs.set_interface_status(src_port2, "up") # create mirror session - self.create_mirror_erspan_session(session, "10.10.10.10", "11.11.11.11", "0x6558", "8", "100", "0", None, po_src_port, "BOTH") - assert self.get_mirror_session_state(session)["status"] == "inactive" - + self.dvs_mirror.create_erspan_session(session, "10.10.10.10", "11.11.11.11", "0x6558", "8", "100", "0", None, src_ports) + self.dvs_mirror.verify_session_status(session, status="inactive") + # create port channel; create port channel member - self.create_port_channel(dvs, "008") - self.create_port_channel_member("008", "Ethernet88") + self.dvs_lag.create_port_channel("008") + lag_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 2) + self.dvs_lag.create_port_channel_member("008", "Ethernet88") # bring up port channel and port channel member - self.set_interface_status(dvs, "PortChannel008", "up") - self.set_interface_status(dvs, "Ethernet88", "up") + dvs.set_interface_status("PortChannel008", "up") + dvs.set_interface_status("Ethernet88", "up") # add ip address to port channel 008 - self.add_ip_address("PortChannel008", "11.11.11.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.add_ip_address("PortChannel008", "11.11.11.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # create neighbor to port channel 008 - self.add_neighbor("PortChannel008", "11.11.11.11", "88:88:88:88:88:88") - assert self.get_mirror_session_state(session)["status"] == "active" + dvs.add_neighbor("PortChannel008", "11.11.11.11", "88:88:88:88:88:88") + self.dvs_mirror.verify_session_status(session) # Check src_port state. - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - (status, fvs) = tbl.get(tbl.getKeys()[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet88" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": - assert fv[1] == "88:88:88:88:88:88" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet88"), + "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS": "88:88:88:88:88:88"} + + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports) + # remove neighbor - self.remove_neighbor("PortChannel008", "11.11.11.11") - assert self.get_mirror_session_state(session)["status"] == "inactive" + dvs.remove_neighbor("PortChannel008", "11.11.11.11") + self.dvs_mirror.verify_session_status(session, status="inactive") # remove ip address - self.remove_ip_address("PortChannel008", "11.11.11.0/24") - assert self.get_mirror_session_state(session)["status"] == "inactive" - - #verify mirror config is removed from LAG source ports. - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - + dvs.remove_ip_address("PortChannel008", "11.11.11.0/24") + self.dvs_mirror.verify_session_status(session, status="inactive") # bring down port channel and port channel member - self.set_interface_status(dvs, "PortChannel008", "down") - self.set_interface_status(dvs, "Ethernet88", "down") + dvs.set_interface_status("PortChannel008", "down") + dvs.set_interface_status("Ethernet88", "down") # remove port channel member; remove port channel - self.remove_port_channel_member("008", "Ethernet88") - self.remove_port_channel(dvs, "008") - self.remove_port_channel_member("001", src_port1) - self.remove_port_channel_member("001", src_port2) - self.remove_port_channel(dvs, "001") + self.dvs_lag.remove_port_channel_member("008", "Ethernet88") + self.dvs_lag.remove_port_channel("008") + self.dvs_lag.remove_port_channel_member("001", src_port1) + self.dvs_lag.remove_port_channel_member("001", src_port2) + self.dvs_lag.remove_port_channel("001") # remove mirror session - self.remove_mirror_session(session) \ No newline at end of file + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() diff --git a/tests/test_mirror_port_span.py b/tests/test_mirror_port_span.py index 77fbce58645..e2dc18a4380 100644 --- a/tests/test_mirror_port_span.py +++ b/tests/test_mirror_port_span.py @@ -6,112 +6,14 @@ from swsscommon import swsscommon from distutils.version import StrictVersion +@pytest.mark.usefixtures("testlog") +@pytest.mark.usefixtures('dvs_vlan_manager') +@pytest.mark.usefixtures('dvs_lag_manager') +@pytest.mark.usefixtures('dvs_mirror_manager') +@pytest.mark.usefixtures('dvs_acl_manager') +@pytest.mark.usefixtures('dvs_policer_manager') class TestMirror(object): - def setup_db(self, dvs): - self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) - self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) - self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) - self.sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) - - def set_interface_status(self, dvs, interface, admin_status): - if interface.startswith("PortChannel"): - tbl_name = "PORTCHANNEL" - elif interface.startswith("Vlan"): - tbl_name = "VLAN" - else: - tbl_name = "PORT" - tbl = swsscommon.Table(self.cdb, tbl_name) - fvs = swsscommon.FieldValuePairs([("admin_status", "up")]) - tbl.set(interface, fvs) - time.sleep(1) - - # when using FRR, route cannot be inserted if the neighbor is not - # connected. thus it is mandatory to force the interface up manually - if interface.startswith("PortChannel"): - dvs.runcmd("bash -c 'echo " + ("1" if admin_status == "up" else "0") +\ - " > /sys/class/net/" + interface + "/carrier'") - - def getPortOid(self, dvs, port_name): - - cnt_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) - port_map_tbl = swsscommon.Table(cnt_db, 'COUNTERS_PORT_NAME_MAP') - - for k in port_map_tbl.get('')[1]: - if k[0] == port_name: - return k[1] - - - def getPortAttr(self, dvs, port_oid, port_attr): - - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - port_tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_PORT:{0}'.format(port_oid)) - - for k in port_tbl.get('')[1]: - if k[0] == port_attr: - return k[1] - - def create_mirror_span_session(self, name, dst_port, src_port=None, direction=None, queue=None, policer=None): - tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") - if src_port is None and direction is None: - if queue is None and policer is None: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port)]) - elif queue is None: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port), - ("policer", policer)]) - elif policer is None: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port), - ("queue", queue)]) - else: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port), - ("queue", queue), - ("policer", policer)]) - else: - if queue is None and policer is None: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port), - ("src_port", src_port), - ("direction", direction)]) - elif queue is None: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port), - ("src_port", src_port), - ("direction", direction), - ("policer", policer)]) - elif policer is None: - fvs = swsscommon.FieldValuePairs([("type", "SPAN"), - ("dst_port", dst_port), - ("src_port", src_port), - ("direction", direction), - ("queue", queue)]) - tbl.set(name, fvs) - time.sleep(2) - - def remove_mirror_session(self, name): - tbl = swsscommon.Table(self.cdb, "MIRROR_SESSION") - tbl._del(name) - time.sleep(1) - - def get_mirror_session_status(self, name): - return self.get_mirror_session_state(name)["status"] - - def get_mirror_session_state(self, name): - tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") - (status, fvs) = tbl.get(name) - assert status == True - assert len(fvs) > 0 - return { fv[0]: fv[1] for fv in fvs } - - def check_mirror_session_state(self, name, status): - tbl = swsscommon.Table(self.sdb, "MIRROR_SESSION_TABLE") - (session_status, fvs) = tbl.get(name) - assert session_status == status - - @pytest.mark.skipif(StrictVersion(platform.linux_distribution()[1]) <= StrictVersion('8.9'), reason="Debian 8.9 or before has no support") def test_PortMirrorAddRemove(self, dvs, testlog): """ This test covers the basic SPAN mirror session creation and removal operations @@ -120,466 +22,264 @@ def test_PortMirrorAddRemove(self, dvs, testlog): 2. Create mirror session with invalid dst_port, verify session doesnt get created. 3. Create mirror session with invalid source port, verify session doesnt get created. 4. Create mirror session with source port, verify session becomes active + 5. Create mirror session with Vlan as dst_port, verify session doesnt get created. + 6. Create mirror session with Vlan as source port, verify session doesnt get created. """ - self.setup_db(dvs) + + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet12" dst_port = "Ethernet16" - invld_port = "Invalid" - src_oid = self.getPortOid(dvs, src_port) - + # Sub Test 1 - # create mirror session - self.create_mirror_span_session(session, "Ethernet16") - assert self.get_mirror_session_state(session)["status"] == "active" - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - - # verify asicdb - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 2 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - - # remove mirror session - self.remove_mirror_session(session) + self.dvs_mirror.create_span_session(session, dst_port) + self.dvs_mirror.verify_session_status(session) + a = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet16"), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session(dvs, session, asic_db=a) + self.dvs_mirror.remove_mirror_session(session) # Sub Test 2 - # create mirror session with invalid dst_port - self.create_mirror_span_session(session, invld_port) - self.check_mirror_session_state(session, False) + self.dvs_mirror.create_span_session(session, "Invalid") + self.dvs_mirror.verify_session_status(session, expected=0) # Sub Test 3 - # create mirror session with invalid src_port - self.create_mirror_span_session(session, dst_port, invld_port, "RX") - self.check_mirror_session_state(session, False) + self.dvs_mirror.create_span_session(session, dst_port, "Invalid", "RX") + self.dvs_mirror.verify_session_status(session, expected=0) # Sub Test 4 # create mirror session with dst_port, src_port, direction - self.create_mirror_span_session(session, dst_port, src_port, "RX") - assert self.get_mirror_session_state(session)["status"] == "active" - - #verify asicdb - mirror_entries = tbl.getKeys() - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 2 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - - # remove mirror session - self.remove_mirror_session(session) + src_ports = "Ethernet12" + src_asic_ports = ["Ethernet12"] + self.dvs_mirror.create_span_session(session, dst_port, src_ports, "RX") + self.dvs_mirror.verify_session_status(session) + self.dvs_mirror.verify_session(dvs, session, asic_db=a, src_ports=src_asic_ports, direction = "RX") + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + + ## Sub Test 5 + self.dvs_vlan.create_vlan("10") + self.dvs_mirror.create_span_session(session, dst_port="Vlan10") + self.dvs_mirror.verify_session_status(session, expected=0) + + ## Sub Test 6 + self.dvs_mirror.create_span_session(session, dst_port, src_ports="Vlan10") + self.dvs_mirror.verify_session_status(session, expected=0) + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + self.dvs_vlan.remove_vlan("10") + def test_PortMirrorMultiSpanAddRemove(self, dvs, testlog): """ This test covers the Multiple SPAN mirror session creation and removal operations Operation flow: 1. Create mirror session with multiple source ports, verify that session is active - 2. Create mirror session with multiple source with valid,invalid ports, session becomes inactive. - 3. Create multiple mirror sessions with multiple source ports. - 4. Create mirror session with invalid source port, the session becomes inactive, - 5. Create mirror session with multiple source ports, the session becomes active - 6. Create mirror session with valid and invalid source ports, the session becomes inactive - 5. Remove mirror session + 2. Create mirror session with multiple source with valid,invalid ports, session doesnt get created. + 3. Create mirror session with multiple source with invalid destination, session doesnt get created. + 4. Create two mirror sessions with multiple source ports. + 5. Verify session config in both sessions. """ - self.setup_db(dvs) + + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session1 = "TEST_SESSION1" session2 = "TEST_SESSION2" - src_port1 = "Ethernet0" - src_port2 = "Ethernet4" - src_port3 = "Ethernet8" - src_port4 = "Ethernet12" dst_port1 = "Ethernet16" + dst_oid1 = pmap.get(dst_port1) dst_port2 = "Ethernet20" - invld_port = "Ethernet" - src_oid1 = self.getPortOid(dvs, src_port1) - src_oid2 = self.getPortOid(dvs, src_port2) - src_oid3 = self.getPortOid(dvs, src_port3) - src_oid4 = self.getPortOid(dvs, src_port4) - queue = 1 + dst_oid2 = pmap.get(dst_port2) # Sub test 1 - # Create mirror session with multiple source ports, verify that session is active - self.create_mirror_span_session(session1, dst_port1, src_port1+","+src_port2+","+src_port3, "BOTH") - assert self.get_mirror_session_state(session1)["status"] == "active" - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 + src_ports = "Ethernet0,Ethernet4,Ethernet8" + src_asic_ports = ["Ethernet0","Ethernet4","Ethernet8"] + self.dvs_mirror.create_span_session(session1, dst_port1, src_ports) + a = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": dst_oid1, + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session_status(session1) + self.dvs_mirror.verify_session(dvs, session1, asic_db=a, src_ports=src_asic_ports) + self.dvs_mirror.remove_mirror_session(session1) + self.dvs_mirror.verify_no_mirror() - # verify asicdb - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 2 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == dst_port1 - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status - - # remove mirror session - self.remove_mirror_session(session1) - #Subtest 2 + # create mirror session with valid and invalid ports. - self.create_mirror_span_session(session1, dst_port1, src_port1+','+invld_port+','+src_port2, "BOTH") - self.check_mirror_session_state(session1, False) + src_ports = "Ethernet0,Invalid,Ethernet8" + self.dvs_mirror.create_span_session(session1, dst_port1, src_ports) + self.dvs_mirror.verify_session_status(session1, expected=0) # Subtest 3 - # create mirror session with multiple source ports. - self.create_mirror_span_session(session1, invld_port, src_port1+','+src_port2+','+src_port3, "BOTH") - self.check_mirror_session_state(session1, False) + src_ports = "Ethernet0,Ethernet4,Ethernet8" + self.dvs_mirror.create_span_session(session1, "Invalid", src_ports) + self.dvs_mirror.verify_session_status(session1, expected=0) # create mirror session - self.create_mirror_span_session(session1, dst_port1, src_port1+","+src_port2, "BOTH") - assert self.get_mirror_session_state(session1)["status"] == "active" - self.create_mirror_span_session(session2, dst_port2, src_port3+","+src_port4, "BOTH") - assert self.get_mirror_session_state(session2)["status"] == "active" - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 2 - - # verify asicdb - (status1, fvs1) = tbl.get(mirror_entries[0]) - (status2, fvs2) = tbl.get(mirror_entries[1]) - assert status1 == True and status2 == True - assert len(fvs1) == 2 and len(fvs2) == 2 - for fv in fvs1: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - if dvs.asicdb.portoidmap[fv[1]] == dst_port1: - session_oid1 = mirror_entries[0] - if dvs.asicdb.portoidmap[fv[1]] == dst_port2: - session_oid2 = mirror_entries[0] - - for fv in fvs2: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - if dvs.asicdb.portoidmap[fv[1]] == dst_port1: - session_oid1 = mirror_entries[1] - if dvs.asicdb.portoidmap[fv[1]] == dst_port2: - session_oid2 = mirror_entries[1] - assert session_oid1 is not None or session_oid2 is not None - - (status1, fvs1) = tbl.get(session_oid1) - for fv in fvs1: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == dst_port1 - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": - assert fv[1] == policer_oid1 - - (status1, fvs2) = tbl.get(session_oid2) - for fv in fvs2: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == dst_port2 - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": - assert fv[1] == policer_oid2 - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 2 - - session_status1= "1:"+format(session_oid1) - session_status2="1:"+format(session_oid2) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status1 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status1 - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status1 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status1 - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status2 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status2 - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status2 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status2 - - # remove mirror session - self.remove_mirror_session(session1) - self.remove_mirror_session(session2) - - def create_policer(self, name): - tbl = swsscommon.Table(self.cdb, "POLICER") - fvs = swsscommon.FieldValuePairs([("meter_type", "packets"), - ("mode", "sr_tcm"), - ("cir", "600"), - ("cbs", "600"), - ("red_packet_action", "drop")]) - tbl.set(name, fvs) - time.sleep(1) - - def remove_policer(self, name): - tbl = swsscommon.Table(self.cdb, "POLICER") - tbl._del(name) - time.sleep(1) + src_ports1 = "Ethernet0,Ethernet4" + src_asic_ports1 = ["Ethernet0","Ethernet4"] + self.dvs_mirror.create_span_session(session1, dst_port1, src_ports1) + src_ports2 = "Ethernet8,Ethernet12" + src_asic_ports2 = ["Ethernet8","Ethernet12"] + self.dvs_mirror.create_span_session(session2, dst_port2, src_ports2) + + a1 = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": dst_oid1, + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + a2 = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": dst_oid2, + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session_status(session1, expected = 2) + self.dvs_mirror.verify_session_status(session2, expected = 2) + self.dvs_mirror.verify_session(dvs, session1, dst_oid=dst_oid1, asic_db=a1, src_ports=src_asic_ports1, expected = 2) + self.dvs_mirror.verify_session(dvs, session2, dst_oid=dst_oid2, asic_db=a2, src_ports=src_asic_ports2, expected = 2) + self.dvs_mirror.remove_mirror_session(session1) + self.dvs_mirror.remove_mirror_session(session2) + self.dvs_mirror.verify_no_mirror() def test_PortMirrorPolicerAddRemove(self, dvs, testlog): """ This test covers the basic SPAN mirror session creation and removal operations Operation flow: 1. Create mirror session with only dst_port and policer , verify session becomes active - 2. Verify policer config is proper. + 2. Create session with invalid policer, verify session doesnt get created. + 2. Create mirror with policer and multiple source ports, verify session config on all ports. """ - self.setup_db(dvs) - + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" - src_port = "Ethernet12" dst_port = "Ethernet16" - invld_port = "Invalid" - policer= "POLICER" - src_oid = self.getPortOid(dvs, src_port) - - # create policer - self.create_policer(policer) - - # Sub Test 1 - # create mirror session - self.create_mirror_span_session(session, "Ethernet16", None, None, None, policer) - assert self.get_mirror_session_state(session)["status"] == "active" - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_POLICER") - policer_entries = tbl.getKeys() - assert len(policer_entries) == 1 - policer_oid = policer_entries[0] - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - - # verify asicdb - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 3 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet16" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": - assert fv[1] == policer_oid - - # remove mirror session - self.remove_mirror_session(session) - self.remove_policer(policer) - - def test_PortMirrorPolicerMultiAddRemove(self, dvs, testlog): + policer="POLICER" + + #Sub Test 1 + self.dvs_policer.create_policer(policer) + self.dvs_policer.verify_policer(policer) + self.dvs_mirror.create_span_session(session, dst_port, policer="POLICER") + self.dvs_mirror.verify_session_status(session) + a = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get("Ethernet16"), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session(dvs, session, asic_db=a, policer="POLICER") + self.dvs_mirror.remove_mirror_session(session) + self.dvs_policer.remove_policer("POLICER") + self.dvs_policer.verify_no_policer() + self.dvs_mirror.verify_no_mirror() + + # Sub test 2 + src_ports = "Ethernet0,Ethernet4,Ethernet8" + src_asic_ports = ["Ethernet0","Ethernet4","Ethernet8"] + self.dvs_mirror.create_span_session(session, dst_port, src_ports, policer="POLICER") + self.dvs_mirror.verify_session_status(session, expected=0) + + # Sub test 3 + self.dvs_policer.create_policer(policer) + self.dvs_policer.verify_policer(policer) + self.dvs_mirror.create_span_session(session, dst_port, src_ports, policer="POLICER") + self.dvs_mirror.verify_session_status(session) + self.dvs_mirror.verify_session(dvs, session, asic_db=a, src_ports=src_asic_ports, policer="POLICER") + self.dvs_mirror.remove_mirror_session(session) + self.dvs_policer.remove_policer("POLICER") + self.dvs_policer.verify_no_policer() + self.dvs_mirror.verify_no_mirror() + + + def test_PortMultiMirrorPolicerAddRemove(self, dvs, testlog): """ - This test covers the SPAN mirror session with multiple source ports and multiple policers. + This test covers the basic SPAN mirror session creation and removal operations Operation flow: - 1. Create mirror session with multiple source ports and policers. - 2. Verify mirror and policer config is proper. + 1. Create mirror session with multiple source with multiple policer. + 2. Verify port/policer/session config on all. """ - self.setup_db(dvs) + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session1 = "TEST_SESSION1" session2 = "TEST_SESSION2" - src_port1 = "Ethernet0" - src_port2 = "Ethernet4" - src_port3 = "Ethernet8" - src_port4 = "Ethernet12" dst_port1 = "Ethernet16" + dst_oid1 = pmap.get(dst_port1) dst_port2 = "Ethernet20" - policer1= "POLICER1" - policer2= "POLICER2" - src_oid1 = self.getPortOid(dvs, src_port1) - src_oid2 = self.getPortOid(dvs, src_port2) - src_oid3 = self.getPortOid(dvs, src_port3) - src_oid4 = self.getPortOid(dvs, src_port4) + dst_oid2 = pmap.get(dst_port2) + policer1 = "POLICER1" + policer2 = "POLICER2" + + #Sub Test 1 + self.dvs_policer.create_policer(policer1, cir="600") + self.dvs_policer.verify_policer(policer1) + self.dvs_policer.create_policer(policer2, cir="800") + self.dvs_policer.verify_policer(policer2, expected = 2) + + src_ports1 = "Ethernet0,Ethernet4" + src_asic_ports1 = ["Ethernet0","Ethernet4"] + self.dvs_mirror.create_span_session(session1, dst_port1, src_ports1, policer=policer1) + src_ports2 = "Ethernet8,Ethernet12" + src_asic_ports2 = ["Ethernet8","Ethernet12"] + self.dvs_mirror.create_span_session(session2, dst_port2, src_ports2, policer=policer2) + + a1 = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": dst_oid1, + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + a2 = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": dst_oid2, + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session_status(session1, expected = 2) + self.dvs_mirror.verify_session_status(session2, expected = 2) + self.dvs_mirror.verify_session(dvs, session1, dst_oid=dst_oid1, asic_db=a1, src_ports=src_asic_ports1, expected = 2, policer=policer1) + self.dvs_mirror.verify_session(dvs, session2, dst_oid=dst_oid2, asic_db=a2, src_ports=src_asic_ports2, expected = 2, policer=policer2) + self.dvs_mirror.remove_mirror_session(session1) + self.dvs_mirror.remove_mirror_session(session2) + self.dvs_policer.remove_policer(policer1) + self.dvs_policer.remove_policer(policer2) + self.dvs_policer.verify_no_policer() + self.dvs_mirror.verify_no_mirror() - # create policer - self.create_policer(policer1) - # create policer - self.create_policer(policer2) - - # create mirror session - source=src_port1+","+src_port2 - self.create_mirror_span_session(session1, dst_port1, source, "BOTH", None, policer1) - assert self.get_mirror_session_state(session1)["status"] == "active" - # create mirror session - source=src_port3+","+src_port4 - self.create_mirror_span_session(session2, dst_port2, source, "BOTH", None, policer2) - assert self.get_mirror_session_state(session2)["status"] == "active" + def test_LAGMirorrSpanAddRemove(self, dvs, testlog): + """ + This test covers the LAG mirror session creation and removal operations + Operation flow: + 1. Create port channel with 2 members. + 2. Create mirror session with LAG as source port. + 3. Verify that source ports have proper mirror config. + 4. Remove port from port-channel and verify mirror config is removed from the port. + 5. Remove second port and verify mirror config is removed. + """ + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) + session = "TEST_SESSION" + dst_port = "Ethernet16" + src_port1="Ethernet8" + src_port2="Ethernet4" + po_src_port="PortChannel008" + src_ports = "PortChannel008,Ethernet12" + src_asic_ports = ["Ethernet8", "Ethernet4", "Ethernet12"] - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_POLICER") - policer_entries = tbl.getKeys() - assert len(policer_entries) == 2 - policer_oid1 = policer_entries[1] - policer_oid2 = policer_entries[0] - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 2 + # create port channel; create port channel member + self.dvs_lag.create_port_channel("008") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.create_port_channel_member("008", src_port1) + self.dvs_lag.create_port_channel_member("008", src_port2) + + # bring up port channel and port channel member + dvs.set_interface_status(po_src_port, "up") + dvs.set_interface_status(src_port1, "up") + dvs.set_interface_status(src_port2, "up") + + # Sub Test 1 + self.dvs_mirror.create_span_session(session, dst_port, src_ports) + self.dvs_mirror.verify_session_status(session) # verify asicdb - (status1, fvs1) = tbl.get(mirror_entries[0]) - (status2, fvs2) = tbl.get(mirror_entries[1]) - assert status1 == True and status2 == True - assert len(fvs1) == 3 and len(fvs2) == 3 - for fv in fvs1: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - if dvs.asicdb.portoidmap[fv[1]] == dst_port1: - session_oid1 = mirror_entries[0] - if dvs.asicdb.portoidmap[fv[1]] == dst_port2: - session_oid2 = mirror_entries[0] - - for fv in fvs2: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - if dvs.asicdb.portoidmap[fv[1]] == dst_port1: - session_oid1 = mirror_entries[1] - if dvs.asicdb.portoidmap[fv[1]] == dst_port2: - session_oid2 = mirror_entries[1] - assert session_oid1 is not None or session_oid2 is not None - - (status1, fvs1) = tbl.get(session_oid1) - for fv in fvs1: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == dst_port1 - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": - assert fv[1] == policer_oid1 or fv[1] == policer_oid2 - - (status1, fvs2) = tbl.get(session_oid2) - for fv in fvs2: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == dst_port2 - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_POLICER": - assert fv[1] == policer_oid2 or fv[1] == policer_oid1 - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 2 - - session_status1= "1:"+format(session_oid1) - session_status2="1:"+format(session_oid2) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status1 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status1 - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status1 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status1 - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status2 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid3, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status2 - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status2 - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid4, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status2 - - # remove mirror session - self.remove_mirror_session(session1) - self.remove_mirror_session(session2) - - def create_acl_table(self, table, interfaces): - tbl = swsscommon.Table(self.cdb, "ACL_TABLE") - fvs = swsscommon.FieldValuePairs([("policy_desc", "mirror_test"), - ("type", "mirror"), - ("ports", ",".join(interfaces))]) - tbl.set(table, fvs) - time.sleep(1) - - def remove_acl_table(self, table): - tbl = swsscommon.Table(self.cdb, "ACL_TABLE") - tbl._del(table) - time.sleep(1) - - def create_mirror_acl_dscp_rule(self, table, rule, dscp, session): - tbl = swsscommon.Table(self.cdb, "ACL_RULE") - fvs = swsscommon.FieldValuePairs([("priority", "1000"), - ("mirror_action", session), - ("DSCP", dscp)]) - tbl.set(table + "|" + rule, fvs) - time.sleep(1) - - def remove_mirror_acl_dscp_rule(self, table, rule): - tbl = swsscommon.Table(self.cdb, "ACL_RULE") - tbl._del(table + "|" + rule) - time.sleep(1) + # Check src_port state. + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get(dst_port), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, asic_size=2) + + # Sub Test 2 + # remove port channel member; remove port channel + self.dvs_lag.remove_port_channel_member("008", src_port1) + src_asic_ports = ["Ethernet4", "Ethernet12"] + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, asic_size=2) + self.dvs_lag.remove_port_channel_member("008", src_port2) + + self.dvs_lag.remove_port_channel("008") + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() def test_PortMirrorPolicerWithAcl(self, dvs, testlog): """ @@ -589,7 +289,9 @@ def test_PortMirrorPolicerWithAcl(self, dvs, testlog): 2. Create ACL and configure mirror 2. Verify mirror and ACL config is proper. """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "MIRROR_SESSION" policer= "POLICER" @@ -598,165 +300,178 @@ def test_PortMirrorPolicerWithAcl(self, dvs, testlog): dst_port = "Ethernet16" # create policer - self.create_policer(policer) + self.dvs_policer.create_policer(policer) + self.dvs_policer.verify_policer(policer) # create mirror session - self.create_mirror_span_session(session, dst_port, None, None, None, policer=policer) - - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 - mirror_oid = mirror_entries[0] + self.dvs_mirror.create_span_session(session, dst_port, policer=policer) + self.dvs_mirror.verify_session_status(session) + member_ids = dvs.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", 1) + # create acl table - self.create_acl_table(acl_table, ["Ethernet0", "Ethernet4"]) - - # create acl rule with dscp value and mask - self.create_mirror_acl_dscp_rule(acl_table, acl_rule, "8/56", session) - - # assert acl rule is created - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY") - rule_entries = [k for k in tbl.getKeys() if k not in dvs.asicdb.default_acl_entries] - assert len(rule_entries) == 1 - - (status, fvs) = tbl.get(rule_entries[0]) - assert status == True - for fv in fvs: - if fv[0] == "SAI_ACL_ENTRY_ATTR_FIELD_DSCP": - assert fv[1] == "8&mask:0x38" - if fv[0] == "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS": - assert fv[1] == "1:" + mirror_oid - - # remove acl rule - self.remove_mirror_acl_dscp_rule(acl_table, acl_rule) - # remove acl table - self.remove_acl_table(acl_table) - self.remove_mirror_session(session) - - # remove policer - self.remove_policer(policer) + bind_ports = ["Ethernet0", "Ethernet4"] + self.dvs_acl.create_acl_table("test", "mirror", bind_ports) + self.dvs_acl.verify_acl_group_num(len(bind_ports)) + + config_qualifiers = {"mirror_action": session, + "DSCP": "8/56"} + mirror_oid="1:" + member_ids[0] + expected_sai_qualifiers = {"SAI_ACL_ENTRY_ATTR_FIELD_DSCP": "8&mask:0x38", + "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS": mirror_oid} + self.dvs_acl.create_mirror_acl_rule("test", "mirror_rule", config_qualifiers) + self.dvs_acl.remove_acl_rule("test", "mirror_rule") + self.dvs_acl.verify_no_acl_rules() + + self.dvs_acl.remove_acl_table("test") + self.dvs_acl.verify_acl_table_count(0) + self.dvs_mirror.remove_mirror_session(session) - def create_port_channel(self, dvs, channel): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") - fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "9100")]) - tbl.set("PortChannel" + channel, fvs) - dvs.runcmd("ip link add PortChannel" + channel + " type bond") - tbl = swsscommon.Table(self.sdb, "LAG_TABLE") - fvs = swsscommon.FieldValuePairs([("state", "ok")]) - tbl.set("PortChannel" + channel, fvs) - time.sleep(1) - - def remove_port_channel(self, dvs, channel): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE") - tbl._del("PortChannel" + channel) - dvs.runcmd("ip link del PortChannel" + channel) - tbl = swsscommon.Table(self.sdb, "LAG_TABLE") - tbl._del("PortChannel" + channel) - time.sleep(1) - - def create_port_channel_member(self, channel, interface): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") - fvs = swsscommon.FieldValuePairs([("status", "enabled")]) - tbl.set("PortChannel" + channel + ":" + interface, fvs) - time.sleep(1) - - def remove_port_channel_member(self, channel, interface): - tbl = swsscommon.ProducerStateTable(self.pdb, "LAG_MEMBER_TABLE") - tbl._del("PortChannel" + channel + ":" + interface) - time.sleep(1) - - def test_LAGMirorrSpanAddRemove(self, dvs, testlog): + self.dvs_policer.remove_policer(policer) + self.dvs_policer.verify_no_policer() + self.dvs_mirror.verify_no_mirror() + + def test_PortMirrorLAGPortSpanAddRemove(self, dvs, testlog): """ This test covers the LAG mirror session creation and removal operations Operation flow: 1. Create port channel with 2 members. - 2. Create mirror session with LAG as source port. - 3. Verify that source ports have proper mirror config. - 4. Remove port from port-channel and verify mirror config is removed from the port. - 5. Remove second port and verify mirror config is removed. + 2. Create mirror session with LAG and LAG port. session creation has to fail. + 3. Create mirror session with LAG and other LAG port. session creation has to fail + 4. Create mirror session with LAG and new port, session will become active. + 5. Verify all LAG and new port has session config. + 6. Remove one LAG member and verify that failing session works fine. """ - self.setup_db(dvs) + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) session = "TEST_SESSION" dst_port = "Ethernet16" - po_src_port = "PortChannel008" - src_port1 = "Ethernet0" - src_port2 = "Ethernet4" - src_oid1 = self.getPortOid(dvs, src_port1) - src_oid2 = self.getPortOid(dvs, src_port2) + + session = "TEST_SESSION" + src_port1="Ethernet8" + src_port2="Ethernet4" + po_src_port="PortChannel008" # create port channel; create port channel member - self.create_port_channel(dvs, "008") - self.create_port_channel_member("008", src_port1) - self.create_port_channel_member("008", src_port2) + self.dvs_lag.create_port_channel("008") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.create_port_channel_member("008", src_port1) + self.dvs_lag.create_port_channel_member("008", src_port2) + lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 2) # bring up port channel and port channel member - self.set_interface_status(dvs, po_src_port, "up") - self.set_interface_status(dvs, src_port1, "up") - self.set_interface_status(dvs, src_port2, "up") + dvs.set_interface_status(po_src_port, "up") + dvs.set_interface_status(src_port1, "up") + dvs.set_interface_status(src_port2, "up") # Sub Test 1 - self.create_mirror_span_session(session, dst_port, po_src_port, "BOTH") - assert self.get_mirror_session_state(session)["status"] == "active" + src_ports = "PortChannel008,Ethernet8" + self.dvs_mirror.create_span_session(session, dst_port, src_ports) + self.dvs_mirror.verify_session_status(session, expected=0) + self.dvs_mirror.verify_session_status(session, status="inactive", expected = 0) - # check asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - mirror_entries = tbl.getKeys() - assert len(mirror_entries) == 1 + # Sub Test 2 + src_ports = "PortChannel008,Ethernet4" + self.dvs_mirror.create_span_session(session, dst_port, src_ports) + self.dvs_mirror.verify_session_status(session, expected=0) + self.dvs_mirror.verify_session_status(session, status="inactive", expected=0) - # verify asicdb - (status, fvs) = tbl.get(mirror_entries[0]) - assert status == True - assert len(fvs) == 2 - for fv in fvs: - if fv[0] == "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": - assert dvs.asicdb.portoidmap[fv[1]] == dst_port - elif fv[0] == "SAI_MIRROR_SESSION_ATTR_TYPE": - assert fv[1] == "SAI_MIRROR_SESSION_TYPE_LOCAL" - - session_status= "1:"+format(mirror_entries[0]) - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status - - # Verify port has mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - session_status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + # Sub Test 3 + src_ports = "PortChannel008,Ethernet40" + src_asic_ports = ["Ethernet8", "Ethernet40", "Ethernet4"] + self.dvs_mirror.create_span_session(session, dst_port, src_ports) + self.dvs_mirror.verify_session_status(session, status="active") - # Sub Test 2 - # remove port channel member; remove port channel - self.remove_port_channel_member("008", src_port1) + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get(dst_port), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, asic_size=2) + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + + # Sub Test 4 + self.dvs_lag.remove_port_channel_member("008", "Ethernet4") + lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 1) + src_ports = "PortChannel008,Ethernet40" + src_asic_ports = ["Ethernet8", "Ethernet40"] + self.dvs_mirror.create_span_session(session, dst_port, src_ports) + self.dvs_mirror.verify_session_status(session) + self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) + + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + self.dvs_lag.remove_port_channel_member("008", "Ethernet8") + lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 0) + self.dvs_lag.remove_port_channel("008") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 0) + + + def test_PortLAGMirrorUpdateLAG(self, dvs, testlog): + """ + This test covers the LAG mirror session creation and removal operations + Operation flow: + 1. Create port channel with 2 members. + 2. Create mirror session with LAG and other port P1 + 3. Verify mirror session is active and ports have proper config + 4. Add port P1 to LAG and verify mirror config on all ports. + 5. Remove port P1 from LAG and verify mirror config on P1 is intact. + 6. Remove port from LAG and verify mirror config on other ports in intact. + """ + dvs.setup_db() + pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") + pmap = dict(pmap) - session_status= "1:"+format(mirror_entries[0]) + session = "TEST_SESSION" + dst_port = "Ethernet16" + src_port1="Ethernet8" + src_port2="Ethernet4" + po_src_port="PortChannel008" - # Verify first port doesnt have any mirror config - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - status = self.getPortAttr(dvs, src_oid1, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + # create port channel; create port channel member + self.dvs_lag.create_port_channel("008") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.create_port_channel_member("008", src_port1) + self.dvs_lag.create_port_channel_member("008", src_port2) + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 2) - # Verify second port has mirror config - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == session_status - # Verify port has egress mirror session enabled with session oid. - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == session_status + # bring up port channel and port channel member + dvs.set_interface_status(po_src_port, "up") + dvs.set_interface_status(src_port1, "up") + dvs.set_interface_status(src_port2, "up") + + # Sub Test 1 + src_ports = "PortChannel008,Ethernet40" + src_asic_ports = ["Ethernet8", "Ethernet40", "Ethernet4"] + self.dvs_mirror.create_span_session(session, dst_port, src_ports) + self.dvs_mirror.verify_session_status(session, status="active") + + expected_asic_db = {"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT": pmap.get(dst_port), + "SAI_MIRROR_SESSION_ATTR_TYPE": "SAI_MIRROR_SESSION_TYPE_LOCAL"} + self.dvs_mirror.verify_session(dvs, session, asic_db=expected_asic_db, src_ports=src_asic_ports, asic_size=2) - self.remove_port_channel_member("008", src_port2) - # Verify second port doesnt have any mirror config - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_INGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" - status = self.getPortAttr(dvs, src_oid2, 'SAI_PORT_ATTR_EGRESS_MIRROR_SESSION') - assert status == None or status == "0:null" + # Add source port Ethernet40 to LAG + self.dvs_lag.create_port_channel_member("008", "Ethernet40") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 3) + self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) - self.remove_port_channel(dvs, "008") - self.remove_mirror_session(session) + # Remove source port Ethernet40 from LAG + self.dvs_lag.remove_port_channel_member("008", "Ethernet40") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 2) + self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) + + # Remove one port from LAG + self.dvs_lag.remove_port_channel_member("008", "Ethernet4") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 1) + src_asic_ports = ["Ethernet8"] + self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) + + #cleanup + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() + self.dvs_lag.remove_port_channel_member("008", "Ethernet8") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 0) + self.dvs_lag.remove_port_channel("008") + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 0) From 31368164c6d9539155aed3519fba91bb30285295 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Mon, 29 Jun 2020 11:18:22 -0700 Subject: [PATCH 4/8] Fixed lgtm issues --- tests/dvslib/dvs_mirror.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/dvslib/dvs_mirror.py b/tests/dvslib/dvs_mirror.py index c90e5da2011..e4e51f1bb22 100644 --- a/tests/dvslib/dvs_mirror.py +++ b/tests/dvslib/dvs_mirror.py @@ -1,5 +1,3 @@ -from dvs_database import DVSDatabase - class DVSMirror(object): def __init__(self, adb, cdb, sdb, cntrdb, appdb): self.asic_db = adb @@ -8,12 +6,6 @@ def __init__(self, adb, cdb, sdb, cntrdb, appdb): self.counters_db = cntrdb self.app_db = appdb - def src_ports_to_list(): - src_port_list = [] - for port in src_ports.split(","): - src_port_list.append(port) - src_port=",".join(src_port_list) - def create_span_session(self, name, dst_port, src_ports=None, direction="BOTH", queue=None, policer=None): mirror_entry = {"type": "SPAN"} if dst_port: From daaade439ee34e8fd6a51d4c16907042a2923c7e Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Mon, 29 Jun 2020 11:58:36 -0700 Subject: [PATCH 5/8] Misc fixes --- tests/dvslib/dvs_mirror.py | 1 + tests/dvslib/dvs_policer.py | 1 + tests/test_mirror_port_erspan.py | 1 + tests/test_mirror_port_span.py | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/dvslib/dvs_mirror.py b/tests/dvslib/dvs_mirror.py index e4e51f1bb22..14c0f784582 100644 --- a/tests/dvslib/dvs_mirror.py +++ b/tests/dvslib/dvs_mirror.py @@ -97,3 +97,4 @@ def verify_session(self, dvs, name, asic_db=None, state_db=None, dst_oid=None, s self.verify_session_policer(dvs, entry["SAI_MIRROR_SESSION_ATTR_POLICER"], cir) if src_ports: self.verify_port_mirror_config(dvs, src_ports, direction, session_oid=session_oid) + diff --git a/tests/dvslib/dvs_policer.py b/tests/dvslib/dvs_policer.py index 217e0fe8ea4..5aa839a86a9 100644 --- a/tests/dvslib/dvs_policer.py +++ b/tests/dvslib/dvs_policer.py @@ -16,3 +16,4 @@ def verify_policer(self, name, expected=1): def verify_no_policer(self): self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", 0) + diff --git a/tests/test_mirror_port_erspan.py b/tests/test_mirror_port_erspan.py index 3f1ac8dc469..e1b82569fd1 100644 --- a/tests/test_mirror_port_erspan.py +++ b/tests/test_mirror_port_erspan.py @@ -547,3 +547,4 @@ def test_LAGMirrorToERSPANLagAddRemove(self, dvs, testlog): # remove mirror session self.dvs_mirror.remove_mirror_session(session) self.dvs_mirror.verify_no_mirror() + diff --git a/tests/test_mirror_port_span.py b/tests/test_mirror_port_span.py index e2dc18a4380..f4595f46041 100644 --- a/tests/test_mirror_port_span.py +++ b/tests/test_mirror_port_span.py @@ -475,3 +475,4 @@ def test_PortLAGMirrorUpdateLAG(self, dvs, testlog): self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 0) self.dvs_lag.remove_port_channel("008") self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 0) + From 6ca20160a957bd21b72584ed16deb08277a52cf4 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Tue, 30 Jun 2020 10:08:12 -0700 Subject: [PATCH 6/8] Addressed review comments. Fixed lgtm issues --- orchagent/mirrororch.cpp | 48 +++++++++++++++++++------------- orchagent/mirrororch.h | 4 +-- tests/conftest.py | 3 +- tests/dvslib/dvs_acl.py | 1 + tests/dvslib/dvs_lag.py | 10 ++++++- tests/dvslib/dvs_mirror.py | 16 +++++------ tests/test_mirror_port_erspan.py | 24 +++++++--------- tests/test_mirror_port_span.py | 40 +++++++++++--------------- 8 files changed, 77 insertions(+), 69 deletions(-) diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index 03fb853c1c5..e82eade32d2 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -268,17 +268,22 @@ bool MirrorOrch::decreaseRefCount(const string& name) bool MirrorOrch::validateDstPort(const string& dstPort) { Port port; - if (!m_portsOrch->getPort(dstPort, port) && port.m_type != Port::PHY) + if (!m_portsOrch->getPort(dstPort, port)) { SWSS_LOG_ERROR("Failed to locate port %s", dstPort.c_str()); return false; } + if (port.m_type != Port::PHY) + { + SWSS_LOG_ERROR("Not supported port %s", dstPort.c_str()); + return false; + } return true; } -bool MirrorOrch::checkPortExistsInSrcPortList(const string& port, const string& srcPort) +bool MirrorOrch::checkPortExistsInSrcPortList(const string& port, const string& srcPortList) { - auto ports = tokenize(srcPort, ','); + auto ports = tokenize(srcPortList, ','); if (ports.size() != 0) { for (auto alias : ports) @@ -293,9 +298,9 @@ bool MirrorOrch::checkPortExistsInSrcPortList(const string& port, const string& return false; } -bool MirrorOrch::validateSrcPort(const string& srcPort) +bool MirrorOrch::validateSrcPortList(const string& srcPortList) { - auto ports = tokenize(srcPort, ','); + auto ports = tokenize(srcPortList, ','); if (ports.size() != 0) { @@ -321,10 +326,10 @@ bool MirrorOrch::validateSrcPort(const string& srcPort) m_portsOrch->getLagMember(port, portv); for (const auto p : portv) { - if (checkPortExistsInSrcPortList(p.m_alias, srcPort)) + if (checkPortExistsInSrcPortList(p.m_alias, srcPortList)) { SWSS_LOG_ERROR("Port %s in LAG %s is also part of src_port config %s", - p.m_alias.c_str(), port.m_alias.c_str(), srcPort.c_str()); + p.m_alias.c_str(), port.m_alias.c_str(), srcPortList.c_str()); return false; } } @@ -358,7 +363,7 @@ void MirrorOrch::createEntry(const string& key, const vector& d entry.srcIp = fvValue(i); if (!entry.srcIp.isV4()) { - SWSS_LOG_ERROR("Unsupported version of sessions %s source IP address\n", key.c_str()); + SWSS_LOG_ERROR("Unsupported version of sessions %s source IP address", key.c_str()); return; } } @@ -367,7 +372,7 @@ void MirrorOrch::createEntry(const string& key, const vector& d entry.dstIp = fvValue(i); if (!entry.dstIp.isV4()) { - SWSS_LOG_ERROR("Unsupported version of sessions %s destination IP address\n", key.c_str()); + SWSS_LOG_ERROR("Unsupported version of sessions %s destination IP address", key.c_str()); return; } } @@ -401,7 +406,7 @@ void MirrorOrch::createEntry(const string& key, const vector& d } else if (fvField(i) == MIRROR_SESSION_SRC_PORT) { - if (!validateSrcPort(fvValue(i))) + if (!validateSrcPortList(fvValue(i))) { SWSS_LOG_ERROR("Failed to get valid source port list %s", fvValue(i).c_str()); return; @@ -433,7 +438,7 @@ void MirrorOrch::createEntry(const string& key, const vector& d } else { - SWSS_LOG_ERROR("Failed to parse session %s configuration. Unknown attribute %s.\n", key.c_str(), fvField(i).c_str()); + SWSS_LOG_ERROR("Failed to parse session %s configuration. Unknown attribute %s", key.c_str(), fvField(i).c_str()); return; } } @@ -757,10 +762,15 @@ bool MirrorOrch::setUnsetPortMirror(Port port, m_portsOrch->getLagMember(port, portv); for (const auto p : portv) { + if (p.m_type != Port::PHY) + { + SWSS_LOG_ERROR("Failed to locate port %s", p.m_alias.c_str()); + return false; + } status = sai_port_api->set_port_attribute(p.m_port_id, &port_attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to configure %s session on port %s: %s, status %d, sessionId %x\n", + SWSS_LOG_ERROR("Failed to configure %s session on port %s: %s, status %d, sessionId %x", ingress ? "RX" : "TX", port.m_alias.c_str(), p.m_alias.c_str(), status, sessionId); return false; @@ -772,7 +782,7 @@ bool MirrorOrch::setUnsetPortMirror(Port port, status = sai_port_api->set_port_attribute(port.m_port_id, &port_attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to configure %s session on port %s, status %d, sessionId %x\n", + SWSS_LOG_ERROR("Failed to configure %s session on port %s, status %d, sessionId %x", ingress ? "RX" : "TX", port.m_alias.c_str(), status, sessionId); return false; } @@ -797,7 +807,7 @@ bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& ses { if (!setUnsetPortMirror(port, true, set, session.sessionId)) { - SWSS_LOG_ERROR("Failed to configure mirror session %s port %s\n", + SWSS_LOG_ERROR("Failed to configure mirror session %s port %s", name.c_str(), port.m_alias.c_str()); return false; } @@ -806,7 +816,7 @@ bool MirrorOrch::configurePortMirrorSession(const string& name, MirrorEntry& ses { if (!setUnsetPortMirror(port, false, set, session.sessionId)) { - SWSS_LOG_ERROR("Failed to configure mirror session %s port %s \n", + SWSS_LOG_ERROR("Failed to configure mirror session %s port %s", name.c_str(), port.m_alias.c_str()); return false; } @@ -944,7 +954,7 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) create_mirror_session(&session.sessionId, gSwitchId, (uint32_t)attrs.size(), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to activate mirroring session %s\n", name.c_str()); + SWSS_LOG_ERROR("Failed to activate mirroring session %s", name.c_str()); session.status = false; return false; @@ -957,7 +967,7 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session) status = configurePortMirrorSession(name, session, true); if (status == false) { - SWSS_LOG_ERROR("Failed to activate port mirror session %s\n", name.c_str()); + SWSS_LOG_ERROR("Failed to activate port mirror session %s", name.c_str()); session.status = false; return false; } @@ -988,7 +998,7 @@ bool MirrorOrch::deactivateSession(const string& name, MirrorEntry& session) status = configurePortMirrorSession(name, session, false); if (status == false) { - SWSS_LOG_ERROR("Failed to deactivate port mirror session %s\n", name.c_str()); + SWSS_LOG_ERROR("Failed to deactivate port mirror session %s", name.c_str()); return false; } } @@ -997,7 +1007,7 @@ bool MirrorOrch::deactivateSession(const string& name, MirrorEntry& session) if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to deactivate mirroring session %s\n", name.c_str()); + SWSS_LOG_ERROR("Failed to deactivate mirroring session %s", name.c_str()); return false; } diff --git a/orchagent/mirrororch.h b/orchagent/mirrororch.h index 73eaafde35f..5edbf0ee456 100644 --- a/orchagent/mirrororch.h +++ b/orchagent/mirrororch.h @@ -128,8 +128,8 @@ class MirrorOrch : public Orch, public Observer, public Subject void updateLagMember(const LagMemberUpdate&); void updateVlanMember(const VlanMemberUpdate&); - bool checkPortExistsInSrcPortList(const string& port, const string& srcPort); - bool validateSrcPort(const string& srcPort); + bool checkPortExistsInSrcPortList(const string& port, const string& srcPortList); + bool validateSrcPortList(const string& srcPort); bool validateDstPort(const string& dstPort); bool setUnsetPortMirror(Port port, bool ingress, bool set, sai_object_id_t sessionId); diff --git a/tests/conftest.py b/tests/conftest.py index a62dcc2a96e..c8d676f8b79 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1036,7 +1036,8 @@ def dvs_acl_manager(request, dvs): @pytest.yield_fixture(scope="class") def dvs_lag_manager(request, dvs): - request.cls.dvs_lag = dvs_lag.DVSLag(dvs.get_config_db()) + request.cls.dvs_lag = dvs_lag.DVSLag(dvs.get_asic_db(), + dvs.get_config_db()) @pytest.yield_fixture(scope="class") def dvs_vlan_manager(request, dvs): diff --git a/tests/dvslib/dvs_acl.py b/tests/dvslib/dvs_acl.py index d21add4149c..3f557620098 100644 --- a/tests/dvslib/dvs_acl.py +++ b/tests/dvslib/dvs_acl.py @@ -239,3 +239,4 @@ def _match_acl_range(sai_acl_range): return True return _match_acl_range + diff --git a/tests/dvslib/dvs_lag.py b/tests/dvslib/dvs_lag.py index 6eafb084f82..06dd0c42178 100644 --- a/tests/dvslib/dvs_lag.py +++ b/tests/dvslib/dvs_lag.py @@ -1,5 +1,6 @@ class DVSLag(object): - def __init__(self, cdb): + def __init__(self, adb, cdb): + self.asic_db = adb self.config_db = cdb def create_port_channel(self, lag_id, admin_status="up", mtu="1500"): @@ -19,3 +20,10 @@ def create_port_channel_member(self, lag_id, interface): def remove_port_channel_member(self, lag_id, interface): member = "PortChannel{}|{}".format(lag_id, interface) self.config_db.delete_entry("PORTCHANNEL_MEMBER", member) + + def get_and_verify_port_channel_members(self, expected_num): + return self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", expected_num) + + def get_and_verify_port_channel(self, expected_num): + return self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", expected_num) + diff --git a/tests/dvslib/dvs_mirror.py b/tests/dvslib/dvs_mirror.py index 14c0f784582..6529b1a7265 100644 --- a/tests/dvslib/dvs_mirror.py +++ b/tests/dvslib/dvs_mirror.py @@ -23,7 +23,7 @@ def create_span_session(self, name, dst_port, src_ports=None, direction="BOTH", self.config_db.create_entry("MIRROR_SESSION", name, mirror_entry) def create_erspan_session(self, name, src, dst, gre, dscp, ttl, queue, policer=None, src_ports=None, direction="BOTH"): - mirror_entry = {"type": "ERSPAN"} + mirror_entry = {} mirror_entry["src_ip"] = src mirror_entry["dst_ip"] = dst mirror_entry["gre_type"] = gre @@ -55,7 +55,7 @@ def verify_port_mirror_config(self, dvs, ports, direction, session_oid="null"): fvs = dict(fvs) for p in ports: port_oid = fvs.get(p) - member = dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid) + member = dvs.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid) if direction in {"RX", "BOTH"}: assert member["SAI_PORT_ATTR_INGRESS_MIRROR_SESSION"] == "1:"+session_oid else: @@ -67,17 +67,17 @@ def verify_port_mirror_config(self, dvs, ports, direction, session_oid="null"): def verify_session_db(self, dvs, name, asic_table=None, asic=None, state=None, asic_size=None): if asic: - fv_pairs = dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", asic_table) + fv_pairs = dvs.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", asic_table) assert all(fv_pairs.get(k) == v for k, v in asic.items()) if asic_size: assert asic_size == len(fv_pairs) if state: - fv_pairs = dvs.state_db.get_entry("MIRROR_SESSION_TABLE", name) + fv_pairs = dvs.state_db.wait_for_entry("MIRROR_SESSION_TABLE", name) assert all(fv_pairs.get(k) == v for k, v in state.items()) def verify_session_policer(self, dvs, policer_oid, cir): if cir: - entry = dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_POLICER", policer_oid) + entry = dvs.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_POLICER", policer_oid) assert entry["SAI_POLICER_ATTR_CIR"] == cir def verify_session(self, dvs, name, asic_db=None, state_db=None, dst_oid=None, src_ports=None, direction="BOTH", policer=None, expected = 1, asic_size=None): @@ -86,14 +86,14 @@ def verify_session(self, dvs, name, asic_db=None, state_db=None, dst_oid=None, s # with multiple sessions, match on dst_oid to get session_oid if dst_oid: for member in member_ids: - entry=dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", member) + entry=dvs.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", member) if entry["SAI_MIRROR_SESSION_ATTR_MONITOR_PORT"] == dst_oid: session_oid = member self.verify_session_db(dvs, name, session_oid, asic=asic_db, state=state_db, asic_size=asic_size) if policer: - cir = dvs.config_db.get_entry("POLICER", policer)["cir"] - entry=dvs.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", session_oid) + cir = dvs.config_db.wait_for_entry("POLICER", policer)["cir"] + entry=dvs.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION", session_oid) self.verify_session_policer(dvs, entry["SAI_MIRROR_SESSION_ATTR_POLICER"], cir) if src_ports: self.verify_port_mirror_config(dvs, src_ports, direction, session_oid=session_oid) diff --git a/tests/test_mirror_port_erspan.py b/tests/test_mirror_port_erspan.py index e1b82569fd1..47d9d5d1ca6 100644 --- a/tests/test_mirror_port_erspan.py +++ b/tests/test_mirror_port_erspan.py @@ -1,10 +1,5 @@ # This test suite covers the functionality of mirror feature in SwSS -import platform import pytest -import time - -from swsscommon import swsscommon -from distutils.version import StrictVersion @pytest.mark.usefixtures("testlog") @pytest.mark.usefixtures('dvs_vlan_manager') @@ -172,14 +167,14 @@ def test_PortMirrorToVlanAddRemove(self, dvs, testlog): dvs.set_interface_status("Ethernet4", "down") dvs.set_interface_status(vlan, "down") - # remove mirror session - self.dvs_mirror.remove_mirror_session(session) - self.dvs_mirror.verify_no_mirror() - # remove vlan member; remove vlan self.dvs_vlan.remove_vlan_member(vlan_id, "Ethernet4") + self.dvs_vlan.get_and_verify_vlan_member_ids(0) self.dvs_vlan.remove_vlan(vlan_id) + # remove mirror session + self.dvs_mirror.remove_mirror_session(session) + self.dvs_mirror.verify_no_mirror() def test_PortMirrorToLagAddRemove(self, dvs, testlog): """ @@ -212,7 +207,7 @@ def test_PortMirrorToLagAddRemove(self, dvs, testlog): self.dvs_lag.create_port_channel_member("008", "Ethernet88") # Verify the LAG has been initialized properly - lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 1) + lag_member_entries = self.dvs_lag.get_and_verify_port_channel_members(1) fvs = self.dvs_vlan.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", lag_member_entries[0]) assert len(fvs) == 4 assert fvs.get("SAI_LAG_MEMBER_ATTR_LAG_ID") == lag_entries[0] @@ -344,8 +339,9 @@ def test_PortMirrorDestMoveVlan(self, dvs, testlog): # bring down vlan and member; remove vlan member; remove vlan dvs.set_interface_status("Ethernet48", "down") dvs.set_interface_status("Vlan9", "down") - dvs.remove_vlan_member("9", "Ethernet48") - dvs.remove_vlan("9") + self.dvs_vlan.remove_vlan_member("9", "Ethernet48") + self.dvs_vlan.get_and_verify_vlan_member_ids(0) + self.dvs_vlan.remove_vlan("9") # remove route; remove neighbor; remove ip; bring down port dvs.remove_route("8.8.8.0/24") @@ -397,7 +393,7 @@ def test_PortMirrorDestMoveLag(self, dvs, testlog): # mirror session move round 1 # create port channel; create port channel member; bring up self.dvs_lag.create_port_channel("080") - lag_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) self.dvs_lag.create_port_channel_member("080", "Ethernet32") dvs.set_interface_status("PortChannel080", "up") dvs.set_interface_status("Ethernet32", "up") @@ -505,7 +501,7 @@ def test_LAGMirrorToERSPANLagAddRemove(self, dvs, testlog): # create port channel; create port channel member self.dvs_lag.create_port_channel("008") - lag_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 2) + self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 2) self.dvs_lag.create_port_channel_member("008", "Ethernet88") # bring up port channel and port channel member diff --git a/tests/test_mirror_port_span.py b/tests/test_mirror_port_span.py index f4595f46041..66619725c47 100644 --- a/tests/test_mirror_port_span.py +++ b/tests/test_mirror_port_span.py @@ -1,10 +1,5 @@ # This test suite covers the functionality of mirror feature in SwSS -import platform import pytest -import time - -from swsscommon import swsscommon -from distutils.version import StrictVersion @pytest.mark.usefixtures("testlog") @pytest.mark.usefixtures('dvs_vlan_manager') @@ -69,6 +64,7 @@ def test_PortMirrorAddRemove(self, dvs, testlog): self.dvs_mirror.remove_mirror_session(session) self.dvs_mirror.verify_no_mirror() self.dvs_vlan.remove_vlan("10") + self.dvs_vlan.get_and_verify_vlan_ids(0) def test_PortMirrorMultiSpanAddRemove(self, dvs, testlog): @@ -290,13 +286,8 @@ def test_PortMirrorPolicerWithAcl(self, dvs, testlog): 2. Verify mirror and ACL config is proper. """ dvs.setup_db() - pmap = dvs.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "") - pmap = dict(pmap) - session = "MIRROR_SESSION" policer= "POLICER" - acl_table = "MIRROR_TABLE" - acl_rule = "MIRROR_RULE" dst_port = "Ethernet16" # create policer @@ -317,9 +308,10 @@ def test_PortMirrorPolicerWithAcl(self, dvs, testlog): config_qualifiers = {"mirror_action": session, "DSCP": "8/56"} mirror_oid="1:" + member_ids[0] - expected_sai_qualifiers = {"SAI_ACL_ENTRY_ATTR_FIELD_DSCP": "8&mask:0x38", - "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS": mirror_oid} + expected_sai_qualifiers = {"SAI_ACL_ENTRY_ATTR_FIELD_DSCP": self.dvs_acl.get_simple_qualifier_comparator("8&mask:0x38"), + "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS": self.dvs_acl.get_simple_qualifier_comparator(mirror_oid)} self.dvs_acl.create_mirror_acl_rule("test", "mirror_rule", config_qualifiers) + self.dvs_acl.verify_acl_rule(expected_sai_qualifiers) self.dvs_acl.remove_acl_rule("test", "mirror_rule") self.dvs_acl.verify_no_acl_rules() @@ -349,18 +341,16 @@ def test_PortMirrorLAGPortSpanAddRemove(self, dvs, testlog): session = "TEST_SESSION" dst_port = "Ethernet16" - - session = "TEST_SESSION" src_port1="Ethernet8" src_port2="Ethernet4" po_src_port="PortChannel008" # create port channel; create port channel member self.dvs_lag.create_port_channel("008") - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.get_and_verify_port_channel(1) self.dvs_lag.create_port_channel_member("008", src_port1) self.dvs_lag.create_port_channel_member("008", src_port2) - lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 2) + self.dvs_lag.get_and_verify_port_channel_members(2) # bring up port channel and port channel member dvs.set_interface_status(po_src_port, "up") @@ -393,7 +383,7 @@ def test_PortMirrorLAGPortSpanAddRemove(self, dvs, testlog): # Sub Test 4 self.dvs_lag.remove_port_channel_member("008", "Ethernet4") - lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 1) + self.dvs_lag.get_and_verify_port_channel_members(1) src_ports = "PortChannel008,Ethernet40" src_asic_ports = ["Ethernet8", "Ethernet40"] self.dvs_mirror.create_span_session(session, dst_port, src_ports) @@ -403,8 +393,9 @@ def test_PortMirrorLAGPortSpanAddRemove(self, dvs, testlog): self.dvs_mirror.remove_mirror_session(session) self.dvs_mirror.verify_no_mirror() self.dvs_lag.remove_port_channel_member("008", "Ethernet8") - lag_member_entries = self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 0) + self.dvs_lag.get_and_verify_port_channel_members(0) self.dvs_lag.remove_port_channel("008") + self.dvs_lag.get_and_verify_port_channel(0) self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 0) @@ -431,10 +422,10 @@ def test_PortLAGMirrorUpdateLAG(self, dvs, testlog): # create port channel; create port channel member self.dvs_lag.create_port_channel("008") - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 1) + self.dvs_lag.get_and_verify_port_channel(1) self.dvs_lag.create_port_channel_member("008", src_port1) self.dvs_lag.create_port_channel_member("008", src_port2) - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 2) + self.dvs_lag.get_and_verify_port_channel_members(2) # bring up port channel and port channel member dvs.set_interface_status(po_src_port, "up") @@ -454,17 +445,17 @@ def test_PortLAGMirrorUpdateLAG(self, dvs, testlog): # Add source port Ethernet40 to LAG self.dvs_lag.create_port_channel_member("008", "Ethernet40") - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 3) + self.dvs_lag.get_and_verify_port_channel_members(3) self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) # Remove source port Ethernet40 from LAG self.dvs_lag.remove_port_channel_member("008", "Ethernet40") - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 2) + self.dvs_lag.get_and_verify_port_channel_members(2) self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) # Remove one port from LAG self.dvs_lag.remove_port_channel_member("008", "Ethernet4") - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 1) + self.dvs_lag.get_and_verify_port_channel_members(1) src_asic_ports = ["Ethernet8"] self.dvs_mirror.verify_session(dvs, session, src_ports=src_asic_ports) @@ -472,7 +463,8 @@ def test_PortLAGMirrorUpdateLAG(self, dvs, testlog): self.dvs_mirror.remove_mirror_session(session) self.dvs_mirror.verify_no_mirror() self.dvs_lag.remove_port_channel_member("008", "Ethernet8") - self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", 0) + self.dvs_lag.get_and_verify_port_channel_members(0) self.dvs_lag.remove_port_channel("008") + self.dvs_lag.get_and_verify_port_channel(0) self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 0) From 08f57e6d54eeb02b907b4585c86707724b3aba09 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Tue, 30 Jun 2020 10:15:18 -0700 Subject: [PATCH 7/8] Misc fixes --- orchagent/mirrororch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index e82eade32d2..4eac56ee7a5 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -270,7 +270,7 @@ bool MirrorOrch::validateDstPort(const string& dstPort) Port port; if (!m_portsOrch->getPort(dstPort, port)) { - SWSS_LOG_ERROR("Failed to locate port %s", dstPort.c_str()); + SWSS_LOG_ERROR("Not supported port %s type %d", dstPort.c_str(), port.m_type); return false; } if (port.m_type != Port::PHY) From f9c03c96878d04df0ceb219e93d484fb8b060e10 Mon Sep 17 00:00:00 2001 From: Rupesh Kumar Date: Tue, 30 Jun 2020 10:22:04 -0700 Subject: [PATCH 8/8] Fixed typo --- tests/test_mirror_port_span.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_mirror_port_span.py b/tests/test_mirror_port_span.py index 66619725c47..e5f8c683ec0 100644 --- a/tests/test_mirror_port_span.py +++ b/tests/test_mirror_port_span.py @@ -223,7 +223,7 @@ def test_PortMultiMirrorPolicerAddRemove(self, dvs, testlog): self.dvs_policer.verify_no_policer() self.dvs_mirror.verify_no_mirror() - def test_LAGMirorrSpanAddRemove(self, dvs, testlog): + def test_LAGMirrorSpanAddRemove(self, dvs, testlog): """ This test covers the LAG mirror session creation and removal operations Operation flow: