1010#include " crmorch.h"
1111#include " subscriberstatetable.h"
1212#include " redisutility.h"
13+ #include " flex_counter_manager.h"
14+ #include " flow_counter_handler.h"
1315
1416using namespace std ;
1517using namespace swss ;
@@ -21,6 +23,9 @@ using namespace swss;
2123#define LOCATOR_DEFAULT_FUNC_LEN " 16"
2224#define LOCATOR_DEFAULT_ARG_LEN " 0"
2325
26+ #define SRV6_FLEX_COUNTER_UPDATE_TIMER 1
27+ #define SRV6_STAT_COUNTER_POLLING_INTERVAL_MS 10000
28+
2429extern sai_object_id_t gSwitchId ;
2530extern sai_object_id_t gVirtualRouterId ;
2631extern sai_object_id_t gUnderlayIfId ;
@@ -31,6 +36,7 @@ extern sai_router_interface_api_t* sai_router_intfs_api;
3136
3237extern RouteOrch *gRouteOrch ;
3338extern CrmOrch *gCrmOrch ;
39+ extern bool gTraditionalFlexCounter ;
3440
3541const map<string, sai_my_sid_entry_endpoint_behavior_t > end_behavior_map =
3642{
@@ -89,6 +95,222 @@ static bool mySidDscpModeToSai(const string& mode, sai_tunnel_dscp_mode_t& sai_m
8995 return false ;
9096}
9197
98+ Srv6Orch::Srv6Orch (DBConnector *cfgDb, DBConnector *applDb, const vector<TableConnector>& tables, SwitchOrch *switchOrch, VRFOrch *vrfOrch, NeighOrch *neighOrch):
99+ Orch(tables),
100+ m_vrfOrch(vrfOrch),
101+ m_switchOrch(switchOrch),
102+ m_neighOrch(neighOrch),
103+ m_sidTable(applDb, APP_SRV6_SID_LIST_TABLE_NAME),
104+ m_mysidTable(applDb, APP_SRV6_MY_SID_TABLE_NAME),
105+ m_piccontextTable(applDb, APP_PIC_CONTEXT_TABLE_NAME),
106+ m_mysidCfgTable(cfgDb, CFG_SRV6_MY_SID_TABLE_NAME),
107+ m_locatorCfgTable(cfgDb, CFG_SRV6_MY_LOCATOR_TABLE_NAME),
108+ m_counter_manager(SRV6_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, SRV6_STAT_COUNTER_POLLING_INTERVAL_MS, false )
109+ {
110+ m_neighOrch->attach (this );
111+
112+ initializeCounters ();
113+ }
114+
115+ Srv6Orch::~Srv6Orch ()
116+ {
117+ m_neighOrch->detach (this );
118+ }
119+
120+ void Srv6Orch::initializeCounters ()
121+ {
122+ m_mysid_counters_supported = queryMySidCountersCapability ();
123+ if (!m_mysid_counters_supported)
124+ {
125+ SWSS_LOG_INFO (" SRv6 counters are not supported on this platform" );
126+ return ;
127+ }
128+
129+ m_asic_db = make_shared<DBConnector>(" ASIC_DB" , 0 );
130+ m_counter_db = make_shared<DBConnector>(" COUNTERS_DB" , 0 );
131+ m_mysid_counters_table = make_unique<Table>(m_counter_db.get (), COUNTERS_SRV6_NAME_MAP);
132+
133+ if (gTraditionalFlexCounter )
134+ {
135+ m_vid_to_rid_table = make_unique<Table>(m_asic_db.get (), " VIDTORID" );
136+ }
137+
138+ m_counter_update_timer = new SelectableTimer (timespec { .tv_sec = SRV6_FLEX_COUNTER_UPDATE_TIMER , .tv_nsec = 0 });
139+ auto et = new ExecutableTimer (m_counter_update_timer, this , " SRV6_FLEX_COUNTER_UPDATE_TIMER" );
140+ Orch::addExecutor (et);
141+ }
142+
143+ bool Srv6Orch::queryMySidCountersCapability () const
144+ {
145+ sai_attr_capability_t capability;
146+ sai_status_t status = sai_query_attribute_capability (gSwitchId , SAI_OBJECT_TYPE_MY_SID_ENTRY, SAI_MY_SID_ENTRY_ATTR_COUNTER_ID, &capability);
147+ if (status != SAI_STATUS_SUCCESS)
148+ {
149+ SWSS_LOG_WARN (" Could not query SRv6 MySID entry attribute SAI_MY_SID_ENTRY_ATTR_COUNTER_ID %d" , status);
150+ return false ;
151+ }
152+
153+ return capability.set_implemented && capability.create_implemented ;
154+ }
155+
156+
157+ bool Srv6Orch::getMySidCountersEnabled () const
158+ {
159+ return m_mysid_counters_enabled;
160+ }
161+
162+ bool Srv6Orch::getMySidCountersSupported () const
163+ {
164+ return m_mysid_counters_supported;
165+ }
166+
167+ IpAddress Srv6Orch::getMySidAddress (const sai_my_sid_entry_t & sai_entry) const
168+ {
169+ ip_addr_t ip_addr = {};
170+ ip_addr.family = AF_INET6;
171+ memcpy (&ip_addr.ip_addr .ipv6_addr , sai_entry.sid , sizeof (ip_addr.ip_addr .ipv6_addr ));
172+
173+ return IpAddress (ip_addr);
174+ }
175+
176+ string Srv6Orch::getMySidCounterKey (const sai_my_sid_entry_t & sai_entry) const
177+ {
178+ auto mysid_addr = getMySidAddress (sai_entry).to_string ();
179+ auto locator_cfg = getMySidEntryLocatorCfg (sai_entry);
180+ return getMySidPrefix (mysid_addr, locator_cfg);
181+ }
182+
183+ bool Srv6Orch::addMySidCounter (const sai_my_sid_entry_t & sai_entry, sai_object_id_t & counter_oid)
184+ {
185+ SWSS_LOG_ENTER ();
186+
187+ if (!FlowCounterHandler::createGenericCounter (counter_oid))
188+ {
189+ SWSS_LOG_ERROR (" Failed to create SAI counter for SRv6 MySID entry" );
190+ return false ;
191+ }
192+
193+ auto key = getMySidCounterKey (sai_entry);
194+ vector<FieldValueTuple> fvs = {
195+ {key, sai_serialize_object_id (counter_oid)}
196+ };
197+
198+ m_mysid_counters_table->set (" " , fvs);
199+
200+ auto was_empty = m_pending_counters.empty ();
201+ m_pending_counters[counter_oid] = key;
202+
203+ if (was_empty)
204+ {
205+ m_counter_update_timer->start ();
206+ }
207+
208+ return true ;
209+ }
210+
211+ void Srv6Orch::removeMySidCounter (const sai_my_sid_entry_t & sai_entry, sai_object_id_t & counter_oid)
212+ {
213+ SWSS_LOG_ENTER ();
214+
215+ if (counter_oid == SAI_NULL_OBJECT_ID)
216+ {
217+ return ;
218+ }
219+
220+ auto key = getMySidCounterKey (sai_entry);
221+
222+ m_mysid_counters_table->hdel (" " , key);
223+
224+ auto was_pending = m_pending_counters.erase (counter_oid) == 1 ;
225+ if (!was_pending)
226+ {
227+ SWSS_LOG_INFO (" Unregistering SRv6 counter for %s, oid %s" , key.c_str (), sai_serialize_object_id (counter_oid).c_str ());
228+ m_counter_manager.clearCounterIdList (counter_oid);
229+ }
230+
231+ FlowCounterHandler::removeGenericCounter (counter_oid);
232+ counter_oid = SAI_NULL_OBJECT_ID;
233+ }
234+
235+ void Srv6Orch::setMySidEntryCounter (const sai_my_sid_entry_t & sai_entry, sai_object_id_t counter_oid)
236+ {
237+ SWSS_LOG_ENTER ();
238+
239+ sai_attribute_t attr;
240+ attr.id = SAI_MY_SID_ENTRY_ATTR_COUNTER_ID;
241+ attr.value .oid = counter_oid;
242+
243+ auto status = sai_srv6_api->set_my_sid_entry_attribute (&sai_entry, &attr);
244+ if (status != SAI_STATUS_SUCCESS)
245+ {
246+ SWSS_LOG_ERROR (" Failed to set my_sid entry counter oid to %s, rc: %s" , sai_serialize_object_id (counter_oid).c_str (), sai_serialize_status (status).c_str ());
247+ }
248+ }
249+
250+ void Srv6Orch::setCountersState (bool enable)
251+ {
252+ SWSS_LOG_ENTER ();
253+
254+ if (!getMySidCountersSupported ())
255+ {
256+ SWSS_LOG_WARN (" Ignoring SRv6 counters state change as they are not supported on this platform" );
257+ return ;
258+ }
259+
260+ if (enable == m_mysid_counters_enabled)
261+ {
262+ return ;
263+ }
264+
265+ SWSS_LOG_NOTICE (" Setting SRv6 MySID counters state to %s" , enable ? " enabled" : " disabled" );
266+
267+ for (auto & mysid : srv6_my_sid_table_)
268+ {
269+ const auto & sai_entry = mysid.second .entry ;
270+ auto &counter_oid = mysid.second .counter ;
271+
272+ if (enable)
273+ {
274+ addMySidCounter (sai_entry, counter_oid);
275+ setMySidEntryCounter (sai_entry, counter_oid);
276+ } else {
277+ setMySidEntryCounter (sai_entry, SAI_NULL_OBJECT_ID);
278+ removeMySidCounter (sai_entry, counter_oid);
279+ }
280+ }
281+
282+ m_mysid_counters_enabled = enable;
283+ }
284+
285+ void Srv6Orch::doTask (SelectableTimer &timer)
286+ {
287+ SWSS_LOG_ENTER ();
288+
289+ string value;
290+ for (auto it = m_pending_counters.begin (); it != m_pending_counters.end ();)
291+ {
292+ const auto oid = sai_serialize_object_id (it->first );
293+ if (!gTraditionalFlexCounter || m_vid_to_rid_table->hget (" " , oid, value))
294+ {
295+ SWSS_LOG_INFO (" Registering SRv6 counter for %s, oid %s" , it->second .c_str (), oid.c_str ());
296+
297+ unordered_set<string> counter_stats;
298+ FlowCounterHandler::getGenericCounterStatIdList (counter_stats);
299+ m_counter_manager.setCounterIdList (it->first , CounterType::SRV6, counter_stats);
300+ it = m_pending_counters.erase (it);
301+ }
302+ else
303+ {
304+ ++it;
305+ }
306+ }
307+
308+ if (m_pending_counters.empty ())
309+ {
310+ m_counter_update_timer->stop ();
311+ }
312+ }
313+
92314MySidLocatorCfg Srv6Orch::getMySidEntryLocatorCfg (const sai_my_sid_entry_t & sai_entry) const
93315{
94316 return {
@@ -99,6 +321,12 @@ MySidLocatorCfg Srv6Orch::getMySidEntryLocatorCfg(const sai_my_sid_entry_t& sai_
99321 };
100322}
101323
324+
325+ string Srv6Orch::getMySidPrefix (const string& my_sid_addr, const MySidLocatorCfg& locator_cfg) const
326+ {
327+ return my_sid_addr + " /" + to_string (locator_cfg.block_len + locator_cfg.node_len + locator_cfg.func_len );
328+ }
329+
102330bool Srv6Orch::getLocatorCfgFromDb (const string& locator, MySidLocatorCfg& cfg)
103331{
104332 vector<FieldValueTuple> fvs;
@@ -201,7 +429,7 @@ void Srv6Orch::mySidCfgCacheRefresh()
201429
202430bool Srv6Orch::getMySidEntryDscpMode (const string& my_sid_addr, const MySidLocatorCfg& locator_cfg, sai_tunnel_dscp_mode_t & dscp_mode)
203431{
204- auto my_sid_prefix = my_sid_addr + " / " + to_string ( locator_cfg. block_len + locator_cfg. node_len + locator_cfg. func_len );
432+ auto my_sid_prefix = getMySidPrefix ( my_sid_addr, locator_cfg);
205433
206434 auto cfg_cache = my_sid_dscp_cfg_cache_.equal_range (my_sid_prefix);
207435 if (cfg_cache.first == my_sid_dscp_cfg_cache_.end ())
@@ -1356,13 +1584,28 @@ bool Srv6Orch::createUpdateMysidEntry(string my_sid_string, const string dt_vrf,
13561584 sai_status_t status = SAI_STATUS_SUCCESS;
13571585 if (!entry_exists)
13581586 {
1587+ sai_object_id_t counter_oid = SAI_NULL_OBJECT_ID;
1588+ if (getMySidCountersSupported () && getMySidCountersEnabled ())
1589+ {
1590+ auto ok = addMySidCounter (my_sid_entry, counter_oid);
1591+ if (!ok)
1592+ {
1593+ return false ;
1594+ }
1595+
1596+ attr.id = SAI_MY_SID_ENTRY_ATTR_COUNTER_ID;
1597+ attr.value .oid = counter_oid;
1598+ attributes.push_back (attr);
1599+ }
1600+
13591601 status = sai_srv6_api->create_my_sid_entry (&my_sid_entry, (uint32_t ) attributes.size (), attributes.data ());
13601602 if (status != SAI_STATUS_SUCCESS)
13611603 {
13621604 SWSS_LOG_ERROR (" Failed to create my_sid entry %s, rv %d" , key_string.c_str (), status);
13631605 return false ;
13641606 }
13651607 gCrmOrch ->incCrmResUsedCounter (CrmResourceType::CRM_SRV6_MY_SID_ENTRY);
1608+ srv6_my_sid_table_[key_string].counter = counter_oid;
13661609 }
13671610 else
13681611 {
@@ -1415,6 +1658,7 @@ bool Srv6Orch::deleteMysidEntry(const string my_sid_string)
14151658 return false ;
14161659 }
14171660 sai_my_sid_entry_t my_sid_entry = srv6_my_sid_table_[my_sid_string].entry ;
1661+ sai_object_id_t & counter = srv6_my_sid_table_[my_sid_string].counter ;
14181662
14191663 SWSS_LOG_NOTICE (" MySid Delete: sid %s" , my_sid_string.c_str ());
14201664 status = sai_srv6_api->remove_my_sid_entry (&my_sid_entry);
@@ -1425,6 +1669,7 @@ bool Srv6Orch::deleteMysidEntry(const string my_sid_string)
14251669 }
14261670 gCrmOrch ->decCrmResUsedCounter (CrmResourceType::CRM_SRV6_MY_SID_ENTRY);
14271671
1672+ removeMySidCounter (my_sid_entry, counter);
14281673
14291674 auto endBehavior = srv6_my_sid_table_[my_sid_string].endBehavior ;
14301675 /* Decrease VRF refcount */
0 commit comments