8
8
9
9
extern sai_object_id_t gSwitchId ;
10
10
11
+ extern IntfsOrch *gIntfsOrch ;
11
12
extern NeighOrch *gNeighOrch ;
12
13
extern RouteOrch *gRouteOrch ;
13
14
extern NhgOrch *gNhgOrch ;
@@ -58,6 +59,8 @@ void NhgOrch::doTask(Consumer& consumer)
58
59
string aliases;
59
60
string weights;
60
61
string mpls_nhs;
62
+ string nhgs;
63
+ bool is_recursive = false ;
61
64
62
65
/* Get group's next hop IPs and aliases */
63
66
for (auto i : kfvFieldsValues (t))
@@ -73,24 +76,96 @@ void NhgOrch::doTask(Consumer& consumer)
73
76
74
77
if (fvField (i) == " mpls_nh" )
75
78
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
+ }
76
86
}
77
87
78
- /* Split ips and alaises strings into vectors of tokens. */
88
+ /* Split ips and aliases strings into vectors of tokens. */
79
89
vector<string> ipv = tokenize (ips, ' ,' );
80
90
vector<string> alsv = tokenize (aliases, ' ,' );
81
91
vector<string> mpls_nhv = tokenize (mpls_nhs, ' ,' );
92
+ vector<string> nhgv = tokenize (nhgs, ' ,' );
82
93
83
94
/* Create the next hop group key. */
84
95
string nhg_str;
85
96
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)
87
101
{
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 ())
90
143
{
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];
92
168
}
93
- nhg_str += ipv[i] + NH_DELIMITER + alsv[i];
94
169
}
95
170
96
171
NextHopGroupKey nhg_key = NextHopGroupKey (nhg_str, weights);
@@ -133,10 +208,21 @@ void NhgOrch::doTask(Consumer& consumer)
133
208
else
134
209
{
135
210
auto nhg = std::make_unique<NextHopGroup>(nhg_key, false );
136
- success = nhg->sync ();
137
211
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 ();
138
219
if (success)
139
220
{
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
+ }
140
226
m_syncdNextHopGroups.emplace (index , NhgEntry<NextHopGroup>(std::move (nhg)));
141
227
}
142
228
}
@@ -216,6 +302,12 @@ void NhgOrch::doTask(Consumer& consumer)
216
302
else
217
303
{
218
304
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
+ }
219
311
}
220
312
}
221
313
}
@@ -367,7 +459,19 @@ sai_object_id_t NextHopGroupMember::getNhId() const
367
459
368
460
sai_object_id_t nh_id = SAI_NULL_OBJECT_ID;
369
461
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))
371
475
{
372
476
nh_id = gNeighOrch ->getNextHopId (m_key);
373
477
}
@@ -484,7 +588,7 @@ NextHopGroupMember::~NextHopGroupMember()
484
588
* Params: IN key - The next hop group's key.
485
589
* Returns: Nothing.
486
590
*/
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 )
488
592
{
489
593
SWSS_LOG_ENTER ();
490
594
@@ -506,6 +610,7 @@ NextHopGroup& NextHopGroup::operator=(NextHopGroup&& nhg)
506
610
SWSS_LOG_ENTER ();
507
611
508
612
m_is_temp = nhg.m_is_temp ;
613
+ m_is_recursive = nhg.m_is_recursive ;
509
614
510
615
NhgCommon::operator =(std::move (nhg));
511
616
@@ -532,11 +637,8 @@ bool NextHopGroup::sync()
532
637
return true ;
533
638
}
534
639
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 ())
540
642
{
541
643
const NextHopGroupMember& nhgm = m_members.begin ()->second ;
542
644
sai_object_id_t nhid = nhgm.getNhId ();
@@ -549,6 +651,12 @@ bool NextHopGroup::sync()
549
651
else
550
652
{
551
653
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);
552
660
}
553
661
}
554
662
else
@@ -663,9 +771,16 @@ bool NextHopGroup::remove()
663
771
{
664
772
SWSS_LOG_ENTER ();
665
773
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 () )
668
776
{
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
+
669
784
m_id = SAI_NULL_OBJECT_ID;
670
785
return true ;
671
786
}
@@ -687,6 +802,9 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys)
687
802
{
688
803
SWSS_LOG_ENTER ();
689
804
805
+ /* This method should not be called for non-recursive nexthop groups */
806
+ assert (isRecursive ());
807
+
690
808
ObjectBulker<sai_next_hop_group_api_t > nextHopGroupMemberBulker (sai_next_hop_group_api, gSwitchId , gMaxBulkSize );
691
809
692
810
/*
@@ -776,6 +894,22 @@ bool NextHopGroup::update(const NextHopGroupKey& nhg_key)
776
894
{
777
895
SWSS_LOG_ENTER ();
778
896
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
+
779
913
/* Update the key. */
780
914
m_key = nhg_key;
781
915
@@ -891,7 +1025,12 @@ bool NextHopGroup::validateNextHop(const NextHopKey& nh_key)
891
1025
{
892
1026
SWSS_LOG_ENTER ();
893
1027
894
- return syncMembers ({nh_key});
1028
+ if (isRecursive ())
1029
+ {
1030
+ return syncMembers ({nh_key});
1031
+ }
1032
+
1033
+ return true ;
895
1034
}
896
1035
897
1036
/*
@@ -905,5 +1044,10 @@ bool NextHopGroup::invalidateNextHop(const NextHopKey& nh_key)
905
1044
{
906
1045
SWSS_LOG_ENTER ();
907
1046
908
- return removeMembers ({nh_key});
1047
+ if (isRecursive ())
1048
+ {
1049
+ return removeMembers ({nh_key});
1050
+ }
1051
+
1052
+ return true ;
909
1053
}
0 commit comments