88
99extern sai_object_id_t gSwitchId ;
1010
11+ extern IntfsOrch *gIntfsOrch ;
1112extern NeighOrch *gNeighOrch ;
1213extern RouteOrch *gRouteOrch ;
1314extern 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}
0 commit comments