Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DASH] Add support for ENI counters #3266

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
126 changes: 125 additions & 1 deletion orchagent/dash/dashorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "crmorch.h"
#include "saihelper.h"
#include "directory.h"
#include "flex_counter_manager.h"

#include "taskworker.h"
#include "pbutils.h"
Expand All @@ -35,10 +36,38 @@ extern sai_dash_eni_api_t* sai_dash_eni_api;
extern sai_object_id_t gSwitchId;
extern size_t gMaxBulkSize;
extern CrmOrch *gCrmOrch;
extern bool gTraditionalFlexCounter;

DashOrch::DashOrch(DBConnector *db, vector<string> &tableName, ZmqServer *zmqServer) : ZmqOrch(db, tableName, zmqServer)
#define FLEX_COUNTER_UPD_INTERVAL 1

DashOrch::DashOrch(DBConnector *db, vector<string> &tableName, ZmqServer *zmqServer) :
ZmqOrch(db, tableName, zmqServer),
m_eni_stat_manager(ENI_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, ENI_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false)
{
SWSS_LOG_ENTER();

m_asic_db = std::shared_ptr<DBConnector>(new DBConnector("ASIC_DB", 0));
m_counter_db = std::shared_ptr<DBConnector>(new DBConnector("COUNTERS_DB", 0));
m_eni_name_table = std::unique_ptr<Table>(new Table(m_counter_db.get(), COUNTERS_ENI_NAME_MAP));

if (gTraditionalFlexCounter)
{
m_vid_to_rid_table = std::make_unique<Table>(m_asic_db.get(), "VIDTORID");
}

auto intervT = timespec { .tv_sec = FLEX_COUNTER_UPD_INTERVAL , .tv_nsec = 0 };
m_fc_update_timer = new SelectableTimer(intervT);
auto executorT = new ExecutableTimer(m_fc_update_timer, this, "FLEX_COUNTER_UPD_TIMER");
Orch::addExecutor(executorT);

/* Fetch the available counter Ids */
m_counter_stats.clear();
auto stat_enum_list = queryAvailableCounterStats((sai_object_type_t)SAI_OBJECT_TYPE_ENI);
for (auto &stat_enum: stat_enum_list)
{
auto counter_id = static_cast<sai_eni_stat_t>(stat_enum);
m_counter_stats.insert(sai_serialize_eni_stat(counter_id));
}
}

bool DashOrch::getRouteTypeActions(dash::route_type::RoutingType routing_type, dash::route_type::RouteType& route_type)
Expand Down Expand Up @@ -448,6 +477,8 @@ bool DashOrch::addEniObject(const string& eni, EniEntry& entry)
}
}

addEniToFC(eni_id, eni);

gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_DASH_ENI);

SWSS_LOG_NOTICE("Created ENI object for %s", eni.c_str());
Expand Down Expand Up @@ -530,6 +561,9 @@ bool DashOrch::removeEniObject(const string& eni)
SWSS_LOG_ENTER();

EniEntry entry = eni_entries_[eni];

removeEniFromFC(entry.eni_id, eni);

sai_status_t status = sai_dash_eni_api->remove_eni(entry.eni_id);
if (status != SAI_STATUS_SUCCESS)
{
Expand Down Expand Up @@ -912,3 +946,93 @@ void DashOrch::doTask(ConsumerBase& consumer)
SWSS_LOG_ERROR("Unknown table: %s", tn.c_str());
}
}

void DashOrch::removeEniFromFC(sai_object_id_t oid, const string &name)
{
SWSS_LOG_ENTER();

if (oid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_WARN("Cannot remove counter on NULL OID for eni %s", name.c_str());
return;
}

if (m_eni_stat_work_queue.find(oid) != m_eni_stat_work_queue.end())
{
m_eni_stat_work_queue.erase(oid);
return;
}

m_eni_name_table->hdel("", name);
m_eni_stat_manager.clearCounterIdList(oid);
SWSS_LOG_DEBUG("Unregistered eni %s to Flex counter", name.c_str());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to set m_eni_fc_status to false here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not required, this is set in handleFCStatusUpdate if the request comes from DB/user

}

void DashOrch::clearEniFCStats()
{
for (auto it = eni_entries_.begin(); it != eni_entries_.end(); it++)
{
removeEniFromFC(it->second.eni_id, it->first);
}
}

void DashOrch::handleFCStatusUpdate(bool enabled)
{
if (!enabled && m_eni_fc_status)
{
m_fc_update_timer->stop();
clearEniFCStats();
}
else if (enabled && !m_eni_fc_status)
{
m_fc_update_timer->start();
}
m_eni_fc_status = enabled;
}

void DashOrch::addEniToFC(sai_object_id_t oid, const string &name)
{
auto was_empty = m_eni_stat_work_queue.empty();
m_eni_stat_work_queue[oid] = name;
if (was_empty)
{
m_fc_update_timer->start();
}
}

void DashOrch::doTask(SelectableTimer &timer)
{
SWSS_LOG_ENTER();

if (!m_eni_fc_status)
{
m_fc_update_timer->stop();
return ;
}

for (auto it = m_eni_stat_work_queue.begin(); it != m_eni_stat_work_queue.end(); )
{
string value;
const auto id = sai_serialize_object_id(it->first);

if (!gTraditionalFlexCounter || m_vid_to_rid_table->hget("", id, value))
{
SWSS_LOG_INFO("Registering %s, id %s", it->second.c_str(), id.c_str());
std::vector<FieldValueTuple> eniNameFvs;
eniNameFvs.emplace_back(it->second, id);
m_eni_name_table->set("", eniNameFvs);

m_eni_stat_manager.setCounterIdList(it->first, CounterType::ENI, m_counter_stats);
it = m_eni_stat_work_queue.erase(it);
}
else
{
++it;
}
}

if (m_eni_stat_work_queue.empty())
{
m_fc_update_timer->stop();
}
}
21 changes: 21 additions & 0 deletions orchagent/dash/dashorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
#include "timer.h"
#include "zmqorch.h"
#include "zmqserver.h"
#include "flex_counter_manager.h"

#include "dash_api/appliance.pb.h"
#include "dash_api/route_type.pb.h"
#include "dash_api/eni.pb.h"
#include "dash_api/qos.pb.h"
#include "dash_api/eni_route.pb.h"

#define ENI_STAT_COUNTER_FLEX_COUNTER_GROUP "ENI_STAT_COUNTER"
#define ENI_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000

struct EniEntry
{
sai_object_id_t eni_id;
Expand All @@ -48,6 +52,7 @@ class DashOrch : public ZmqOrch
DashOrch(swss::DBConnector *db, std::vector<std::string> &tables, swss::ZmqServer *zmqServer);
const EniEntry *getEni(const std::string &eni) const;
bool getRouteTypeActions(dash::route_type::RoutingType routing_type, dash::route_type::RouteType& route_type);
void handleFCStatusUpdate(bool is_enabled);

private:
ApplianceTable appliance_entries_;
Expand Down Expand Up @@ -77,4 +82,20 @@ class DashOrch : public ZmqOrch
bool removeQosEntry(const std::string& qos_name);
bool setEniRoute(const std::string& eni, const dash::eni_route::EniRoute& entry);
bool removeEniRoute(const std::string& eni);

private:
std::map<sai_object_id_t, std::string> m_eni_stat_work_queue;
FlexCounterManager m_eni_stat_manager;
bool m_eni_fc_status = false;
std::unordered_set<std::string> m_counter_stats;
std::unique_ptr<swss::Table> m_eni_name_table;
std::unique_ptr<swss::Table> m_vid_to_rid_table;
std::shared_ptr<swss::DBConnector> m_counter_db;
std::shared_ptr<swss::DBConnector> m_asic_db;
swss::SelectableTimer* m_fc_update_timer = nullptr;

void doTask(swss::SelectableTimer&);
void addEniToFC(sai_object_id_t oid, const std::string& name);
void removeEniFromFC(sai_object_id_t oid, const std::string& name);
void clearEniFCStats();
};
1 change: 1 addition & 0 deletions orchagent/flex_counter/flex_counter_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const unordered_map<CounterType, string> FlexCounterManager::counter_id_field_lo
{ CounterType::TUNNEL, TUNNEL_COUNTER_ID_LIST },
{ CounterType::HOSTIF_TRAP, FLOW_COUNTER_ID_LIST },
{ CounterType::ROUTE, FLOW_COUNTER_ID_LIST },
{ CounterType::ENI, ENI_COUNTER_ID_LIST },
};

FlexManagerDirectory g_FlexManagerDirectory;
Expand Down
1 change: 1 addition & 0 deletions orchagent/flex_counter/flex_counter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum class CounterType
TUNNEL,
HOSTIF_TRAP,
ROUTE,
ENI
};

// FlexCounterManager allows users to manage a group of flex counters.
Expand Down
8 changes: 8 additions & 0 deletions orchagent/flexcounterorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <swss/tokenize.h>
#include "routeorch.h"
#include "macsecorch.h"
#include "dash/dashorch.h"
#include "flowcounterrouteorch.h"

extern sai_port_api_t *sai_port_api;
Expand All @@ -39,6 +40,7 @@ extern sai_object_id_t gSwitchId;
#define TUNNEL_KEY "TUNNEL"
#define FLOW_CNT_TRAP_KEY "FLOW_CNT_TRAP"
#define FLOW_CNT_ROUTE_KEY "FLOW_CNT_ROUTE"
#define ENI_KEY "ENI"

unordered_map<string, string> flexCounterGroupMap =
{
Expand All @@ -61,6 +63,7 @@ unordered_map<string, string> flexCounterGroupMap =
{"MACSEC_SA", COUNTERS_MACSEC_SA_GROUP},
{"MACSEC_SA_ATTR", COUNTERS_MACSEC_SA_ATTR_GROUP},
{"MACSEC_FLOW", COUNTERS_MACSEC_FLOW_GROUP},
{"ENI", ENI_STAT_COUNTER_FLEX_COUNTER_GROUP}
};


Expand All @@ -84,6 +87,7 @@ void FlexCounterOrch::doTask(Consumer &consumer)
SWSS_LOG_ENTER();

VxlanTunnelOrch* vxlan_tunnel_orch = gDirectory.get<VxlanTunnelOrch*>();
DashOrch* dash_orch = gDirectory.get<DashOrch*>();
if (gPortsOrch && !gPortsOrch->allPortsReady())
{
return;
Expand Down Expand Up @@ -200,6 +204,10 @@ void FlexCounterOrch::doTask(Consumer &consumer)
{
vxlan_tunnel_orch->generateTunnelCounterMap();
}
if (dash_orch && (key == ENI_KEY))
{
dash_orch->handleFCStatusUpdate((value == "enable"));
}
if (gCoppOrch && (key == FLOW_CNT_TRAP_KEY))
{
if (value == "enable")
Expand Down
30 changes: 30 additions & 0 deletions orchagent/saihelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,3 +1102,33 @@ void stopFlexCounterPolling(sai_object_id_t switch_oid,

sai_switch_api->set_switch_attribute(switch_oid, &attr);
}

/*
Use metadata info of the SAI object to infer all the available stats
Syncd already has logic to filter out the supported stats
*/
std::vector<sai_stat_id_t> queryAvailableCounterStats(const sai_object_type_t object_type)
{
std::vector<sai_stat_id_t> stat_list;
auto info = sai_metadata_get_object_type_info(object_type);
vivekrnv marked this conversation as resolved.
Show resolved Hide resolved

if (!info)
{
SWSS_LOG_ERROR("Metadata info query failed, invalid object: %d", object_type);
return stat_list;
}

SWSS_LOG_NOTICE("SAI object %s supports stat type %s",
sai_serialize_object_type(object_type).c_str(),
info->statenum->name);

auto statenumlist = info->statenum->values;
auto statnumcount = (uint32_t)info->statenum->valuescount;
stat_list.reserve(statnumcount);

for (uint32_t i = 0; i < statnumcount; i++)
{
stat_list.push_back(static_cast<sai_stat_id_t>(statenumlist[i]));
}
return stat_list;
}
2 changes: 2 additions & 0 deletions orchagent/saihelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ void startFlexCounterPolling(sai_object_id_t switch_oid,
const std::string &stats_mode="");
void stopFlexCounterPolling(sai_object_id_t switch_oid,
const std::string &key);

std::vector<sai_stat_id_t> queryAvailableCounterStats(const sai_object_type_t);
21 changes: 20 additions & 1 deletion tests/dash/test_dash_vnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from dash_api.vnet_mapping_pb2 import *
from dash_api.route_type_pb2 import *
from dash_api.types_pb2 import *
from dvslib.dvs_flex_counter import TestFlexCountersBase

from dash_db import *
from dash_configs import *
Expand All @@ -19,10 +20,17 @@

from dvslib.sai_utils import assert_sai_attribute_exists

eni_counter_group_meta = {
'key': 'ENI',
'group_name': 'ENI_STAT_COUNTER',
'name_map': 'COUNTERS_ENI_NAME_MAP',
'post_test': 'post_eni_counter_test'
}

DVS_ENV = ["HWSKU=DPU-2P"]
NUM_PORTS = 2

class TestDash(object):
class TestDash(TestFlexCountersBase):
def test_appliance(self, dash_db: DashDB):
self.appliance_id = "100"
self.sip = "10.0.0.1"
Expand Down Expand Up @@ -55,6 +63,14 @@ def test_vnet(self, dash_db: DashDB):
vnet_attr = dash_db.get_asic_db_entry(ASIC_VNET_TABLE, self.vnet_oid)
assert_sai_attribute_exists("SAI_VNET_ATTR_VNI", vnet_attr, self.vni)

def post_eni_counter_test(self, meta_data):
counters_keys = self.counters_db.db_connection.hgetall(meta_data['name_map'])
self.set_flex_counter_group_status(meta_data['key'], meta_data['name_map'], 'disable')

for counter_entry in counters_keys.items():
self.wait_for_id_list_remove(meta_data['group_name'], counter_entry[0], counter_entry[1])
self.wait_for_table_empty(meta_data['name_map'])

def test_eni(self, dash_db: DashDB):
self.vnet = "Vnet1"
self.mac_string = "F4939FEFC47E"
Expand All @@ -79,6 +95,9 @@ def test_eni(self, dash_db: DashDB):
assert_sai_attribute_exists("SAI_ENI_ATTR_VNET_ID", attrs, str(self.vnet_oid))
assert_sai_attribute_exists("SAI_ENI_ATTR_ADMIN_STATE", attrs, "true")

time.sleep(1)
self.verify_flex_counter_flow(dash_db.dvs, eni_counter_group_meta)

eni_addr_maps = dash_db.wait_for_asic_db_keys(ASIC_ENI_ETHER_ADDR_MAP_TABLE)
attrs = dash_db.get_asic_db_entry(ASIC_ENI_ETHER_ADDR_MAP_TABLE, eni_addr_maps[0])
assert_sai_attribute_exists("SAI_ENI_ETHER_ADDRESS_MAP_ENTRY_ATTR_ENI_ID", attrs, str(self.eni_oid))
Expand Down
Loading
Loading