Skip to content

Commit

Permalink
udf/acl/mirror integration test for NAK mirror case
Browse files Browse the repository at this point in the history
Summary:
New test to verify prod case with match on UDF and action mirror.
VerifyUdfNakMirrorAction

Reviewed By: srikrishnagopu, msomasundaran

Differential Revision: D62192723

fbshipit-source-id: ac3a16688838bfe7da6dea73181da5e0890ea85a
  • Loading branch information
Ravi Vantipalli authored and facebook-github-bot committed Sep 20, 2024
1 parent f3d8197 commit e4334ba
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 6 deletions.
176 changes: 176 additions & 0 deletions fboss/agent/test/agent_hw_tests/AgentFlowletSwitchingTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "fboss/agent/test/utils/AclTestUtils.h"
#include "fboss/agent/test/utils/ConfigUtils.h"
#include "fboss/agent/test/utils/LoadBalancerTestUtils.h"
#include "fboss/agent/test/utils/MirrorTestUtils.h"
#include "fboss/agent/test/utils/ScaleTestUtils.h"
#include "fboss/lib/CommonUtils.h"

Expand All @@ -35,6 +36,11 @@ enum AclType {
};
}

const std::string kSflowMirrorName = "sflow_mirror";
const std::string sflowDestinationVIP = "2001::101";
const std::string aclMirror = "acl_mirror";
const std::string aclDestinationVIP = "2002::101";

namespace facebook::fboss {

class AgentAclCounterTestBase : public AgentHwTest {
Expand Down Expand Up @@ -118,6 +124,39 @@ class AgentAclCounterTestBase : public AgentHwTest {
});
}

RoutePrefixV6 getMirrorDestRoutePrefix(const folly::IPAddress dip) const {
return RoutePrefixV6{
folly::IPAddressV6{dip.str()}, static_cast<uint8_t>(dip.bitCount())};
}

void addSamplingConfig(cfg::SwitchConfig& config) {
auto trafficPort = getAgentEnsemble()->masterLogicalPortIds(
{cfg::PortType::INTERFACE_PORT})[utility::kTrafficPortIndex];
std::vector<PortID> samplePorts = {trafficPort};
utility::configureSflowSampling(config, kSflowMirrorName, samplePorts, 1);
}

void resolveMirror(const std::string& mirrorName, uint8_t dstPort) {
auto destinationPort = getAgentEnsemble()->masterLogicalPortIds(
{cfg::PortType::INTERFACE_PORT})[dstPort];
resolveNeigborAndProgramRoutes(*helper_, 1);
applyNewState([&](const std::shared_ptr<SwitchState>& in) {
boost::container::flat_set<PortDescriptor> nhopPorts{
PortDescriptor(destinationPort)};
return helper_->resolveNextHops(in, nhopPorts);
});
getSw()->getUpdateEvb()->runInFbossEventBaseThreadAndWait([] {});
auto mirror = getSw()->getState()->getMirrors()->getNodeIf(mirrorName);
auto dip = mirror->getDestinationIp();
if (dip.has_value()) {
auto prefix = getMirrorDestRoutePrefix(dip.value());
boost::container::flat_set<PortDescriptor> nhopPorts{
PortDescriptor(destinationPort)};
auto wrapper = getSw()->getRouteUpdater();
helper_->programRoutes(&wrapper, nhopPorts, {prefix});
}
}

void generateApplyConfig(AclType aclType) {
auto newCfg{initialConfig(*getAgentEnsemble())};
addAclAndStat(&newCfg, aclType);
Expand Down Expand Up @@ -346,6 +385,12 @@ class AgentAclCounterTestBase : public AgentHwTest {
if (roceMask.has_value()) {
acl->roceMask() = {static_cast<signed char>(roceMask.value())};
}
if (aclName == getAclName(AclType::UDF_NAK)) {
cfg::Ttl ttl;
ttl.value() = 255;
ttl.mask() = 0xFF;
acl->ttl() = ttl;
}
utility::addAclStat(
config, aclName, counterName, std::move(setCounterTypes));
}
Expand Down Expand Up @@ -537,6 +582,80 @@ class AgentFlowletAclPriorityTest : public AgentFlowletSwitchingTest {
}
};

class AgentFlowletMirrorTest : public AgentFlowletSwitchingTest {
public:
// TH* supports upto 4 different source types to mirror to same egress port.
// Here IFP mirror action and ingress port sflow actions can generate 2 copies
// going to same VIP or different VIP (different egress port in the test)
enum MirrorScope {
MIRROR_ONLY,
MIRROR_SFLOW_SAME_VIP,
MIRROR_SFLOW_DIFFERENT_VIP,
};
std::vector<production_features::ProductionFeature>
getProductionFeaturesVerified() const override {
return {
production_features::ProductionFeature::DLB,
production_features::ProductionFeature::SFLOWv6_SAMPLING,
production_features::ProductionFeature::INGRESS_MIRRORING,
production_features::ProductionFeature::SINGLE_ACL_TABLE};
}

protected:
cfg::SwitchConfig initialConfig(
const AgentEnsemble& ensemble) const override {
auto cfg = utility::onePortPerInterfaceConfig(
ensemble.getSw(),
ensemble.masterLogicalPortIds(),
true /*interfaceHasSubnet*/);
utility::addFlowletConfigs(cfg, ensemble.masterLogicalPortIds());
addAclAndStat(&cfg, AclType::UDF_NAK);
// overwrite existing traffic policy which only has a counter action
// It is added in addAclAndStat above
cfg.dataPlaneTrafficPolicy() = cfg::TrafficPolicyConfig();
std::string counterName = getCounterName(AclType::UDF_NAK);
utility::addAclMatchActions(
&cfg, getAclName(AclType::UDF_NAK), std::move(counterName), aclMirror);

// mirror session for acl
utility::configureSflowMirror(
cfg, aclMirror, false /* truncate */, aclDestinationVIP, 6344);

return cfg;
}

void verifyMirror(MirrorScope scope) {
// In addition to counting ACL hit with verifyAcl, verify packet mirrored
auto mirrorPort = helper_->ecmpPortDescriptorAt(1).phyPortID();
auto sflowPort = helper_->ecmpPortDescriptorAt(2).phyPortID();
auto pktsMirrorBefore =
*getNextUpdatedPortStats(mirrorPort).outUnicastPkts__ref();
auto pktsSflowBefore =
*getNextUpdatedPortStats(sflowPort).outUnicastPkts__ref();

verifyAcl(AclType::UDF_NAK);

WITH_RETRIES({
auto pktsMirrorAfter =
*getNextUpdatedPortStats(mirrorPort).outUnicastPkts__ref();
auto pktsSflowAfter =
*getNextUpdatedPortStats(sflowPort).outUnicastPkts__ref();
XLOG(DBG2) << "PacketMirrorCounter: " << pktsMirrorBefore << " -> "
<< pktsMirrorAfter
<< " PacketSflowCounter: " << pktsSflowBefore << " -> "
<< pktsSflowAfter;
if (scope == MirrorScope::MIRROR_ONLY) {
EXPECT_EVENTUALLY_GT(pktsMirrorAfter, pktsMirrorBefore);
} else if (scope == MirrorScope::MIRROR_SFLOW_SAME_VIP) {
EXPECT_EVENTUALLY_GE(pktsMirrorAfter, pktsMirrorBefore + 2);
} else if (scope == MirrorScope::MIRROR_SFLOW_DIFFERENT_VIP) {
EXPECT_EVENTUALLY_GT(pktsMirrorAfter, pktsMirrorBefore);
EXPECT_EVENTUALLY_GT(pktsSflowAfter, pktsSflowBefore);
}
});
}
};

// empty to UDF A
TEST_F(AgentFlowletSwitchingTest, VerifyFlowletToUdfFlowlet) {
flowletSwitchingAclHitHelper(AclType::FLOWLET, AclType::UDF_FLOWLET);
Expand Down Expand Up @@ -617,6 +736,63 @@ TEST_F(AgentFlowletSwitchingTest, VerifyUdfAckWithNakToUdfNak) {
flowletSwitchingAclHitHelper(AclType::UDF_ACK_WITH_NAK, AclType::UDF_NAK);
}

TEST_F(AgentFlowletMirrorTest, VerifyUdfNakMirrorAction) {
auto setup = [this]() {
this->setup();
auto newCfg{initialConfig(*getAgentEnsemble())};
applyNewConfig(newCfg);
resolveMirror(aclMirror, utility::kMirrorToPortIndex);
};

auto verify = [this]() { verifyMirror(MirrorScope::MIRROR_ONLY); };

verifyAcrossWarmBoots(setup, verify);
}

TEST_F(AgentFlowletMirrorTest, VerifyUdfNakMirrorSflowSameVip) {
auto setup = [this]() {
this->setup();
auto newCfg{initialConfig(*getAgentEnsemble())};

// mirror session for ingress port sflow
// use same VIP as ACL mirror, only dst port varies
utility::configureSflowMirror(
newCfg, kSflowMirrorName, false /* truncate */, aclDestinationVIP);
// configure sampling on traffic port
addSamplingConfig(newCfg);

applyNewConfig(newCfg);
resolveMirror(aclMirror, utility::kMirrorToPortIndex);
};

auto verify = [this]() { verifyMirror(MirrorScope::MIRROR_SFLOW_SAME_VIP); };

verifyAcrossWarmBoots(setup, verify);
}

TEST_F(AgentFlowletMirrorTest, VerifyUdfNakMirrorSflowDifferentVip) {
auto setup = [this]() {
this->setup();
auto newCfg{initialConfig(*getAgentEnsemble())};

// mirror session for ingress port sflow
utility::configureSflowMirror(
newCfg, kSflowMirrorName, false /* truncate */, sflowDestinationVIP);
// configure sampling on traffic port
addSamplingConfig(newCfg);

applyNewConfig(newCfg);
resolveMirror(aclMirror, utility::kMirrorToPortIndex);
resolveMirror(kSflowMirrorName, utility::kSflowToPortIndex);
};

auto verify = [this]() {
verifyMirror(MirrorScope::MIRROR_SFLOW_DIFFERENT_VIP);
};

verifyAcrossWarmBoots(setup, verify);
}

// Skip this and next test due to lack of TCAM in ACL table on TH3
TEST_F(AgentFlowletAclPriorityTest, VerifyUdfAclPriority) {
auto setup = [this]() {
Expand Down
9 changes: 7 additions & 2 deletions fboss/agent/test/agent_hw_tests/AgentSflowMirrorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ class AgentSflowMirrorTest : public AgentHwTest {
}

void configureMirror(cfg::SwitchConfig& cfg, bool v4) const {
utility::configureSflowMirror(cfg, kSflowMirror, false, v4);
utility::configureSflowMirror(
cfg, kSflowMirror, false, utility::getSflowMirrorDestination(v4).str());
}

virtual void configureMirror(cfg::SwitchConfig& cfg) const {
Expand Down Expand Up @@ -478,7 +479,11 @@ class AgentSflowMirrorTruncateTest : public AgentSflowMirrorTest<AddrT> {
}

void configureMirror(cfg::SwitchConfig& cfg, bool v4) const {
utility::configureSflowMirror(cfg, kSflowMirror, true /* truncate */, v4);
utility::configureSflowMirror(
cfg,
kSflowMirror,
true /* truncate */,
utility::getSflowMirrorDestination(v4).str());
}

virtual void configureMirror(cfg::SwitchConfig& cfg) const override {
Expand Down
28 changes: 28 additions & 0 deletions fboss/agent/test/utils/AclTestUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,34 @@ void renameAclStat(
addAclStat(cfg, matcher, newCounterName);
}

// Just mirror and counter for now. More can go here if needed
void addAclMatchActions(
cfg::SwitchConfig* cfg,
const std::string& matcher,
const std::optional<std::string>& counterName,
const std::optional<std::string>& mirrorName,
bool ingress) {
cfg::MatchAction matchAction = cfg::MatchAction();
if (mirrorName.has_value()) {
if (ingress) {
matchAction.ingressMirror() = mirrorName.value();
} else {
matchAction.egressMirror() = mirrorName.value();
}
}
if (counterName.has_value()) {
matchAction.counter() = counterName.value();
}
auto matchToAction = cfg::MatchToAction();
*matchToAction.matcher() = matcher;
*matchToAction.action() = matchAction;

if (!cfg->dataPlaneTrafficPolicy()) {
cfg->dataPlaneTrafficPolicy() = cfg::TrafficPolicyConfig();
}
cfg->dataPlaneTrafficPolicy()->matchToAction()->push_back(matchToAction);
}

std::vector<cfg::CounterType> getAclCounterTypes(
const std::vector<const HwAsic*>& asics) {
auto asic = checkSameAndGetAsic(asics);
Expand Down
7 changes: 7 additions & 0 deletions fboss/agent/test/utils/AclTestUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ void delAclStat(
const std::string& matcher,
const std::string& counterName);

void addAclMatchActions(
cfg::SwitchConfig* cfg,
const std::string& matcher,
const std::optional<std::string>& counterName,
const std::optional<std::string>& mirrorName,
bool ingress = true);

void renameAclStat(
cfg::SwitchConfig* cfg,
const std::string& matcher,
Expand Down
7 changes: 4 additions & 3 deletions fboss/agent/test/utils/MirrorTestUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ void configureSflowMirror(
cfg::SwitchConfig& config,
const std::string& mirrorName,
bool truncate,
bool isV4) {
const std::string& destinationIp,
uint32_t udpDstPort) {
cfg::SflowTunnel sflowTunnel;
sflowTunnel.ip() = getSflowMirrorDestination(isV4).str();
sflowTunnel.ip() = destinationIp;
sflowTunnel.udpSrcPort() = 6545;
sflowTunnel.udpDstPort() = 6343;
sflowTunnel.udpDstPort() = udpDstPort;

cfg::MirrorTunnel tunnel;
tunnel.sflowTunnel() = sflowTunnel;
Expand Down
4 changes: 3 additions & 1 deletion fboss/agent/test/utils/MirrorTestUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ inline const std::string kEgressErspan("egress_erspan");
// Port 0 is used for traffic and port 1 is used for mirroring.
inline const uint8_t kTrafficPortIndex = 0;
inline const uint8_t kMirrorToPortIndex = 1;
inline const uint8_t kSflowToPortIndex = 2;

constexpr auto kDscpDefault = facebook::fboss::cfg::switch_config_constants::
DEFAULT_MIRROR_DSCP_; // default dscp value
Expand All @@ -55,7 +56,8 @@ void configureSflowMirror(
cfg::SwitchConfig& config,
const std::string& mirrorName,
bool truncate,
bool isV4 = true);
const std::string& destinationIp,
uint32_t udpSrcPort = 6343);

void configureSflowSampling(
cfg::SwitchConfig& config,
Expand Down

0 comments on commit e4334ba

Please sign in to comment.