Skip to content

Commit 69c204f

Browse files
What I did:
Implemented recursive nexthop group enhancement in Orchagent (NhgOrch). They have been proposed in: sonic-net/SONiC#1636 Why I did it: These changes are required to handle a new field - "nexthop_group" in the App DB NEXT_HOP_GROUP_TABLE. Such nexthop groups are called recursive nexthop groups. This field contains the list of member (singleton) nexthop groups. Such recursive nexthop groups are represented by NEXT_HOP_GROUP objects.
1 parent 2e6c5b2 commit 69c204f

File tree

2 files changed

+170
-19
lines changed

2 files changed

+170
-19
lines changed

orchagent/nhgorch.cpp

+162-18
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
extern sai_object_id_t gSwitchId;
1010

11+
extern IntfsOrch *gIntfsOrch;
1112
extern NeighOrch *gNeighOrch;
1213
extern RouteOrch *gRouteOrch;
1314
extern NhgOrch *gNhgOrch;
@@ -58,6 +59,8 @@ void NhgOrch::doTask(Consumer& consumer)
5859
string aliases;
5960
string weights;
6061
string mpls_nhs;
62+
string nhgs;
63+
bool is_recursive = false;
6164

6265
/* Get group's next hop IPs and aliases */
6366
for (auto i : kfvFieldsValues(t))
@@ -73,24 +76,96 @@ void NhgOrch::doTask(Consumer& consumer)
7376

7477
if (fvField(i) == "mpls_nh")
7578
mpls_nhs = fvValue(i);
79+
80+
if (fvField(i) == "nexthop_group")
81+
{
82+
nhgs = fvValue(i);
83+
if (!nhgs.empty())
84+
is_recursive = true;
85+
}
7686
}
7787

78-
/* Split ips and alaises strings into vectors of tokens. */
88+
/* Split ips and aliases strings into vectors of tokens. */
7989
vector<string> ipv = tokenize(ips, ',');
8090
vector<string> alsv = tokenize(aliases, ',');
8191
vector<string> mpls_nhv = tokenize(mpls_nhs, ',');
92+
vector<string> nhgv = tokenize(nhgs, ',');
8293

8394
/* Create the next hop group key. */
8495
string nhg_str;
8596

86-
for (uint32_t i = 0; i < ipv.size(); i++)
97+
/* Keeps track of any non-existing member of a recursive nexthop group */
98+
bool non_existent_member = false;
99+
100+
if (is_recursive)
87101
{
88-
if (i) nhg_str += NHG_DELIMITER;
89-
if (!mpls_nhv.empty() && mpls_nhv[i] != "na")
102+
SWSS_LOG_INFO("Adding recursive nexthop group %s with %s", index.c_str(), nhgs.c_str());
103+
104+
/* Reset the "nexthop_group" field and update it with only the existing members */
105+
nhgs = "";
106+
107+
/* Check if any of the members are a recursive or temporary nexthop group */
108+
bool invalid_member = false;
109+
110+
for (auto& nhgm : nhgv)
111+
{
112+
const auto& nhgm_it = m_syncdNextHopGroups.find(nhgm);
113+
if (nhgm_it == m_syncdNextHopGroups.end())
114+
{
115+
SWSS_LOG_INFO("Member nexthop group %s in parent nhg %s not ready",
116+
nhgm.c_str(), index.c_str());
117+
118+
non_existent_member = true;
119+
continue;
120+
}
121+
if ((nhgm_it->second.nhg) &&
122+
(nhgm_it->second.nhg->isRecursive() || nhgm_it->second.nhg->isTemp()))
123+
{
124+
SWSS_LOG_ERROR("Invalid member nexthop group %s in parent nhg %s",
125+
nhgm.c_str(), index.c_str());
126+
127+
invalid_member = true;
128+
break;
129+
}
130+
/* Keep only the members which exist in the local cache */
131+
if (nhgs.empty())
132+
nhgs = nhgm;
133+
else
134+
nhgs += ',' + nhgm;
135+
}
136+
if (invalid_member)
137+
{
138+
it = consumer.m_toSync.erase(it);
139+
continue;
140+
}
141+
/* If no members are present */
142+
if (nhgs.empty())
90143
{
91-
nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER;
144+
it++;
145+
continue;
146+
}
147+
148+
/* Form nexthopgroup key with the nexthopgroup keys of available members */
149+
nhgv = tokenize(nhgs, ',');
150+
151+
for (uint32_t i = 0; i < nhgv.size(); i++)
152+
{
153+
if (i) nhg_str += NHG_DELIMITER;
154+
155+
nhg_str += m_syncdNextHopGroups.at(nhgv[i]).nhg->getKey().to_string();
156+
}
157+
}
158+
else
159+
{
160+
for (uint32_t i = 0; i < ipv.size(); i++)
161+
{
162+
if (i) nhg_str += NHG_DELIMITER;
163+
if (!mpls_nhv.empty() && mpls_nhv[i] != "na")
164+
{
165+
nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER;
166+
}
167+
nhg_str += ipv[i] + NH_DELIMITER + alsv[i];
92168
}
93-
nhg_str += ipv[i] + NH_DELIMITER + alsv[i];
94169
}
95170

96171
NextHopGroupKey nhg_key = NextHopGroupKey(nhg_str, weights);
@@ -133,10 +208,21 @@ void NhgOrch::doTask(Consumer& consumer)
133208
else
134209
{
135210
auto nhg = std::make_unique<NextHopGroup>(nhg_key, false);
136-
success = nhg->sync();
137211

212+
/*
213+
* Mark the nexthop group as recursive so as to create a
214+
* nexthop group object even if it has just one available path
215+
*/
216+
nhg->setRecursive(is_recursive);
217+
218+
success = nhg->sync();
138219
if (success)
139220
{
221+
/* Keep the msg in loop if any member path is not available yet */
222+
if (is_recursive && non_existent_member)
223+
{
224+
success = false;
225+
}
140226
m_syncdNextHopGroups.emplace(index, NhgEntry<NextHopGroup>(std::move(nhg)));
141227
}
142228
}
@@ -216,6 +302,12 @@ void NhgOrch::doTask(Consumer& consumer)
216302
else
217303
{
218304
success = nhg_ptr->update(nhg_key);
305+
306+
/* Keep the msg in loop if any member path is not available yet */
307+
if (is_recursive && non_existent_member)
308+
{
309+
success = false;
310+
}
219311
}
220312
}
221313
}
@@ -367,7 +459,19 @@ sai_object_id_t NextHopGroupMember::getNhId() const
367459

368460
sai_object_id_t nh_id = SAI_NULL_OBJECT_ID;
369461

370-
if (gNeighOrch->hasNextHop(m_key))
462+
if (m_key.isIntfNextHop())
463+
{
464+
nh_id = gIntfsOrch->getRouterIntfsId(m_key.alias);
465+
466+
if ((nh_id == SAI_NULL_OBJECT_ID) &&
467+
!m_key.alias.compare(0, strlen("Loopback"), "Loopback"))
468+
{
469+
Port cpu_port;
470+
gPortsOrch->getCpuPort(cpu_port);
471+
nh_id = cpu_port.m_port_id;
472+
}
473+
}
474+
else if (gNeighOrch->hasNextHop(m_key))
371475
{
372476
nh_id = gNeighOrch->getNextHopId(m_key);
373477
}
@@ -484,7 +588,7 @@ NextHopGroupMember::~NextHopGroupMember()
484588
* Params: IN key - The next hop group's key.
485589
* Returns: Nothing.
486590
*/
487-
NextHopGroup::NextHopGroup(const NextHopGroupKey& key, bool is_temp) : NhgCommon(key), m_is_temp(is_temp)
591+
NextHopGroup::NextHopGroup(const NextHopGroupKey& key, bool is_temp) : NhgCommon(key), m_is_temp(is_temp), m_is_recursive(false)
488592
{
489593
SWSS_LOG_ENTER();
490594

@@ -506,6 +610,7 @@ NextHopGroup& NextHopGroup::operator=(NextHopGroup&& nhg)
506610
SWSS_LOG_ENTER();
507611

508612
m_is_temp = nhg.m_is_temp;
613+
m_is_recursive = nhg.m_is_recursive;
509614

510615
NhgCommon::operator=(std::move(nhg));
511616

@@ -532,11 +637,8 @@ bool NextHopGroup::sync()
532637
return true;
533638
}
534639

535-
/*
536-
* If the group is temporary, the group ID will be the only member's NH
537-
* ID.
538-
*/
539-
if (m_is_temp)
640+
/* If the group is non-recursive, the group ID will be the only member's NH ID */
641+
if (!isRecursive())
540642
{
541643
const NextHopGroupMember& nhgm = m_members.begin()->second;
542644
sai_object_id_t nhid = nhgm.getNhId();
@@ -549,6 +651,12 @@ bool NextHopGroup::sync()
549651
else
550652
{
551653
m_id = nhid;
654+
655+
auto nh_key = nhgm.getKey();
656+
if (nh_key.isIntfNextHop())
657+
gIntfsOrch->increaseRouterIntfsRefCount(nh_key.alias);
658+
else
659+
gNeighOrch->increaseNextHopRefCount(nh_key);
552660
}
553661
}
554662
else
@@ -663,9 +771,16 @@ bool NextHopGroup::remove()
663771
{
664772
SWSS_LOG_ENTER();
665773

666-
// If the group is temporary, there is nothing to be done - just reset the ID.
667-
if (m_is_temp)
774+
// If the group is temporary or non-recursive, update the neigh or rif ref-count and reset the ID.
775+
if (m_is_temp || !isRecursive())
668776
{
777+
const NextHopGroupMember& nhgm = m_members.begin()->second;
778+
auto nh_key = nhgm.getKey();
779+
if (nh_key.isIntfNextHop())
780+
gIntfsOrch->decreaseRouterIntfsRefCount(nh_key.alias);
781+
else
782+
gNeighOrch->decreaseNextHopRefCount(nh_key);
783+
669784
m_id = SAI_NULL_OBJECT_ID;
670785
return true;
671786
}
@@ -687,6 +802,9 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys)
687802
{
688803
SWSS_LOG_ENTER();
689804

805+
/* This method should not be called for non-recursive nexthop groups */
806+
assert(isRecursive());
807+
690808
ObjectBulker<sai_next_hop_group_api_t> nextHopGroupMemberBulker(sai_next_hop_group_api, gSwitchId, gMaxBulkSize);
691809

692810
/*
@@ -776,6 +894,22 @@ bool NextHopGroup::update(const NextHopGroupKey& nhg_key)
776894
{
777895
SWSS_LOG_ENTER();
778896

897+
if (!(isRecursive() && isSynced()))
898+
{
899+
bool was_synced = isSynced();
900+
bool was_temp = isTemp();
901+
*this = NextHopGroup(nhg_key, false);
902+
903+
/*
904+
* For temporary nexthop group being updated, set the recursive flag
905+
* as it is expected to get promoted to multiple NHG
906+
*/
907+
setRecursive(was_temp);
908+
909+
/* Sync the group only if it was synced before. */
910+
return (was_synced ? sync() : true);
911+
}
912+
779913
/* Update the key. */
780914
m_key = nhg_key;
781915

@@ -891,7 +1025,12 @@ bool NextHopGroup::validateNextHop(const NextHopKey& nh_key)
8911025
{
8921026
SWSS_LOG_ENTER();
8931027

894-
return syncMembers({nh_key});
1028+
if (isRecursive())
1029+
{
1030+
return syncMembers({nh_key});
1031+
}
1032+
1033+
return true;
8951034
}
8961035

8971036
/*
@@ -905,5 +1044,10 @@ bool NextHopGroup::invalidateNextHop(const NextHopKey& nh_key)
9051044
{
9061045
SWSS_LOG_ENTER();
9071046

908-
return removeMembers({nh_key});
1047+
if (isRecursive())
1048+
{
1049+
return removeMembers({nh_key});
1050+
}
1051+
1052+
return true;
9091053
}

orchagent/nhgorch.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class NextHopGroup : public NhgCommon<NextHopGroupKey, NextHopKey, NextHopGroupM
5454
explicit NextHopGroup(const NextHopGroupKey& key, bool is_temp);
5555

5656
NextHopGroup(NextHopGroup&& nhg) :
57-
NhgCommon(move(nhg)), m_is_temp(nhg.m_is_temp)
57+
NhgCommon(move(nhg)), m_is_temp(nhg.m_is_temp), m_is_recursive(nhg.m_is_recursive)
5858
{ SWSS_LOG_ENTER(); }
5959

6060
NextHopGroup& operator=(NextHopGroup&& nhg);
@@ -83,6 +83,10 @@ class NextHopGroup : public NhgCommon<NextHopGroupKey, NextHopKey, NextHopGroupM
8383
/* Getters / Setters. */
8484
inline bool isTemp() const override { return m_is_temp; }
8585

86+
inline bool isRecursive() const { return m_is_recursive; }
87+
88+
inline void setRecursive(bool is_recursive) { m_is_recursive = is_recursive; }
89+
8690
NextHopGroupKey getNhgKey() const override { return m_key; }
8791

8892
/* Convert NHG's details to a string. */
@@ -95,6 +99,9 @@ class NextHopGroup : public NhgCommon<NextHopGroupKey, NextHopKey, NextHopGroupM
9599
/* Whether the group is temporary or not. */
96100
bool m_is_temp;
97101

102+
/* Whether the group is recursive i.e. having other nexthop group(s) as members */
103+
bool m_is_recursive;
104+
98105
/* Add group's members over the SAI API for the given keys. */
99106
bool syncMembers(const set<NextHopKey>& nh_keys) override;
100107

0 commit comments

Comments
 (0)