Skip to content

Commit 4b8cad4

Browse files
authored
[SRv6] Add support for SRv6 VPN (sonic-net#3293)
* [SRv6] Add support for SRv6 VPN (sonic-net#3293) What I did Implementation according to [HLD] SRv6 VPN HLD Why I did it This PR is to support SRv6 VPN functions How I verified it sonic-mgmt phoenix wing ptf test plan orchagent UT (tests/test_srv6.py) in this PR
1 parent df08d2d commit 4b8cad4

File tree

9 files changed

+1719
-157
lines changed

9 files changed

+1719
-157
lines changed

orchagent/nexthopgroupkey.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class NextHopGroupKey
1313
{
1414
m_overlay_nexthops = false;
1515
m_srv6_nexthops = false;
16+
m_srv6_vpn = false;
1617
auto nhv = tokenize(nexthops, NHG_DELIMITER);
1718
for (const auto &nh : nhv)
1819
{
@@ -27,6 +28,7 @@ class NextHopGroupKey
2728
{
2829
m_overlay_nexthops = true;
2930
m_srv6_nexthops = false;
31+
m_srv6_vpn = false;
3032
auto nhv = tokenize(nexthops, NHG_DELIMITER);
3133
for (const auto &nh_str : nhv)
3234
{
@@ -38,11 +40,16 @@ class NextHopGroupKey
3840
{
3941
m_overlay_nexthops = false;
4042
m_srv6_nexthops = true;
43+
m_srv6_vpn = false;
4144
auto nhv = tokenize(nexthops, NHG_DELIMITER);
4245
for (const auto &nh_str : nhv)
4346
{
4447
auto nh = NextHopKey(nh_str, overlay_nh, srv6_nh);
4548
m_nexthops.insert(nh);
49+
if (nh.isSrv6Vpn())
50+
{
51+
m_srv6_vpn = true;
52+
}
4653
}
4754
}
4855
}
@@ -51,6 +58,7 @@ class NextHopGroupKey
5158
{
5259
m_overlay_nexthops = false;
5360
m_srv6_nexthops = false;
61+
m_srv6_vpn = false;
5462
std::vector<std::string> nhv = tokenize(nexthops, NHG_DELIMITER);
5563
std::vector<std::string> wtv = tokenize(weights, NHG_DELIMITER);
5664
bool set_weight = wtv.size() == nhv.size();
@@ -221,15 +229,21 @@ class NextHopGroupKey
221229
return m_srv6_nexthops;
222230
}
223231

232+
inline bool is_srv6_vpn() const
233+
{
234+
return m_srv6_vpn;
235+
}
236+
224237
void clear()
225238
{
226239
m_nexthops.clear();
227240
}
228241

229242
private:
230243
std::set<NextHopKey> m_nexthops;
231-
bool m_overlay_nexthops;
232-
bool m_srv6_nexthops;
244+
bool m_overlay_nexthops = false;
245+
bool m_srv6_nexthops = false;
246+
bool m_srv6_vpn = false;
233247
};
234248

235249
#endif /* SWSS_NEXTHOPGROUPKEY_H */

orchagent/nexthopkey.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct NextHopKey
2222
uint32_t weight; // NH weight for NHGs
2323
string srv6_segment; // SRV6 segment string
2424
string srv6_source; // SRV6 source address
25+
string srv6_vpn_sid; // SRV6 vpn sid
2526

2627
NextHopKey() : weight(0) {}
2728
NextHopKey(const std::string &str, const std::string &alias) :
@@ -76,14 +77,15 @@ struct NextHopKey
7677
vni = 0;
7778
weight = 0;
7879
auto keys = tokenize(str, NH_DELIMITER);
79-
if (keys.size() != 3)
80+
if (keys.size() != 4)
8081
{
8182
std::string err = "Error converting " + str + " to Nexthop";
8283
throw std::invalid_argument(err);
8384
}
8485
ip_address = keys[0];
8586
srv6_segment = keys[1];
8687
srv6_source = keys[2];
88+
srv6_vpn_sid = keys[3];
8789
}
8890
else
8991
{
@@ -115,7 +117,8 @@ struct NextHopKey
115117
{
116118
if (srv6_nh)
117119
{
118-
return ip_address.to_string() + NH_DELIMITER + srv6_segment + NH_DELIMITER + srv6_source;
120+
return ip_address.to_string() + NH_DELIMITER + srv6_segment + NH_DELIMITER + srv6_source + NH_DELIMITER
121+
+ srv6_vpn_sid + NH_DELIMITER;
119122
}
120123
std::string str = formatMplsNextHop();
121124
str += (ip_address.to_string() + NH_DELIMITER + alias + NH_DELIMITER +
@@ -125,16 +128,17 @@ struct NextHopKey
125128

126129
bool operator<(const NextHopKey &o) const
127130
{
128-
return tie(ip_address, alias, label_stack, vni, mac_address, srv6_segment, srv6_source) <
129-
tie(o.ip_address, o.alias, o.label_stack, o.vni, o.mac_address, o.srv6_segment, o.srv6_source);
131+
return tie(ip_address, alias, label_stack, vni, mac_address, srv6_segment, srv6_source, srv6_vpn_sid) <
132+
tie(o.ip_address, o.alias, o.label_stack, o.vni, o.mac_address, o.srv6_segment, o.srv6_source, o.srv6_vpn_sid);
130133
}
131134

132135
bool operator==(const NextHopKey &o) const
133136
{
134137
return (ip_address == o.ip_address) && (alias == o.alias) &&
135138
(label_stack == o.label_stack) &&
136139
(vni == o.vni) && (mac_address == o.mac_address) &&
137-
(srv6_segment == o.srv6_segment) && (srv6_source == o.srv6_source);
140+
(srv6_segment == o.srv6_segment) && (srv6_source == o.srv6_source) &&
141+
(srv6_vpn_sid == o.srv6_vpn_sid);
138142
}
139143

140144
bool operator!=(const NextHopKey &o) const
@@ -154,7 +158,12 @@ struct NextHopKey
154158

155159
bool isSrv6NextHop() const
156160
{
157-
return (srv6_segment != "");
161+
return ((srv6_segment != "") || (srv6_vpn_sid != "") || (srv6_source != ""));
162+
}
163+
164+
bool isSrv6Vpn() const
165+
{
166+
return (srv6_vpn_sid != "");
158167
}
159168

160169
std::string parseMplsNextHop(const std::string& str)

orchagent/nhgorch.cpp

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "neighorch.h"
33
#include "crmorch.h"
44
#include "routeorch.h"
5+
#include "srv6orch.h"
56
#include "bulker.h"
67
#include "logger.h"
78
#include "swssnet.h"
@@ -12,6 +13,7 @@ extern IntfsOrch *gIntfsOrch;
1213
extern NeighOrch *gNeighOrch;
1314
extern RouteOrch *gRouteOrch;
1415
extern NhgOrch *gNhgOrch;
16+
extern Srv6Orch *gSrv6Orch;
1517

1618
extern size_t gMaxBulkSize;
1719

@@ -61,6 +63,9 @@ void NhgOrch::doTask(Consumer& consumer)
6163
string mpls_nhs;
6264
string nhgs;
6365
bool is_recursive = false;
66+
string srv6_source;
67+
bool overlay_nh = false;
68+
bool srv6_nh = false;
6469

6570
/* Get group's next hop IPs and aliases */
6671
for (auto i : kfvFieldsValues(t))
@@ -77,6 +82,12 @@ void NhgOrch::doTask(Consumer& consumer)
7782
if (fvField(i) == "mpls_nh")
7883
mpls_nhs = fvValue(i);
7984

85+
if (fvField(i) == "seg_src")
86+
{
87+
srv6_source = fvValue(i);
88+
srv6_nh = true;
89+
}
90+
8091
if (fvField(i) == "nexthop_group")
8192
{
8293
nhgs = fvValue(i);
@@ -96,9 +107,11 @@ void NhgOrch::doTask(Consumer& consumer)
96107
vector<string> alsv = tokenize(aliases, ',');
97108
vector<string> mpls_nhv = tokenize(mpls_nhs, ',');
98109
vector<string> nhgv = tokenize(nhgs, NHG_DELIMITER);
110+
vector<string> srv6_srcv = tokenize(srv6_source, ',');
99111

100112
/* Create the next hop group key. */
101113
string nhg_str;
114+
NextHopGroupKey nhg_key;
102115

103116
/* Keeps track of any non-existing member of a recursive nexthop group */
104117
bool non_existent_member = false;
@@ -154,28 +167,77 @@ void NhgOrch::doTask(Consumer& consumer)
154167
/* Form nexthopgroup key with the nexthopgroup keys of available members */
155168
nhgv = tokenize(nhgs, NHG_DELIMITER);
156169

170+
bool nhg_mismatch = false;
157171
for (uint32_t i = 0; i < nhgv.size(); i++)
158172
{
159-
if (i) nhg_str += NHG_DELIMITER;
173+
auto k = m_syncdNextHopGroups.at(nhgv[i]).nhg->getKey();
174+
if (i)
175+
{
176+
if (k.is_srv6_nexthop() != srv6_nh || k.is_overlay_nexthop() != overlay_nh)
177+
{
178+
SWSS_LOG_ERROR("Inconsistent nexthop group type between %s and %s",
179+
m_syncdNextHopGroups.at(nhgv[0]).nhg->getKey().to_string().c_str(),
180+
k.to_string().c_str());
181+
nhg_mismatch = true;
182+
break;
183+
}
184+
nhg_str += NHG_DELIMITER;
185+
}
186+
else
187+
{
188+
srv6_nh = k.is_srv6_nexthop();
189+
overlay_nh = k.is_overlay_nexthop();
190+
}
160191

161192
nhg_str += m_syncdNextHopGroups.at(nhgv[i]).nhg->getKey().to_string();
162193
}
194+
195+
if (nhg_mismatch)
196+
{
197+
it = consumer.m_toSync.erase(it);
198+
continue;
199+
}
200+
201+
if (srv6_nh)
202+
nhg_key = NextHopGroupKey(nhg_str, overlay_nh, srv6_nh);
203+
else
204+
nhg_key = NextHopGroupKey(nhg_str, weights);
163205
}
164206
else
165207
{
166-
for (uint32_t i = 0; i < ipv.size(); i++)
208+
if (srv6_nh)
167209
{
168-
if (i) nhg_str += NHG_DELIMITER;
169-
if (!mpls_nhv.empty() && mpls_nhv[i] != "na")
210+
if (ipv.size() != srv6_srcv.size())
211+
{
212+
SWSS_LOG_ERROR("inconsistent number of endpoints and srv6_srcs.");
213+
it = consumer.m_toSync.erase(it);
214+
continue;
215+
}
216+
for (uint32_t i = 0; i < ipv.size(); i++)
170217
{
171-
nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER;
218+
if (i) nhg_str += NHG_DELIMITER;
219+
nhg_str += ipv[i] + NH_DELIMITER; // ip address
220+
nhg_str += NH_DELIMITER; // srv6 segment
221+
nhg_str += srv6_srcv[i] + NH_DELIMITER; // srv6 source
222+
nhg_str += NH_DELIMITER; // srv6 vpn sid
223+
}
224+
nhg_key = NextHopGroupKey(nhg_str, overlay_nh, srv6_nh);
225+
}
226+
else
227+
{
228+
for (uint32_t i = 0; i < ipv.size(); i++)
229+
{
230+
if (i) nhg_str += NHG_DELIMITER;
231+
if (!mpls_nhv.empty() && mpls_nhv[i] != "na")
232+
{
233+
nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER;
234+
}
235+
nhg_str += ipv[i] + NH_DELIMITER + alsv[i];
172236
}
173-
nhg_str += ipv[i] + NH_DELIMITER + alsv[i];
237+
nhg_key = NextHopGroupKey(nhg_str, weights);
174238
}
175239
}
176240

177-
NextHopGroupKey nhg_key = NextHopGroupKey(nhg_str, weights);
178-
179241
/* If the group does not exist, create one. */
180242
if (nhg_it == m_syncdNextHopGroups.end())
181243
{
@@ -192,6 +254,13 @@ void NhgOrch::doTask(Consumer& consumer)
192254
{
193255
SWSS_LOG_DEBUG("Next hop group count reached its limit.");
194256

257+
// don't create temp nhg for srv6
258+
if (nhg_key.is_srv6_nexthop())
259+
{
260+
++it;
261+
continue;
262+
}
263+
195264
try
196265
{
197266
auto nhg = std::make_unique<NextHopGroup>(createTempNhg(nhg_key));
@@ -476,6 +545,14 @@ sai_object_id_t NextHopGroupMember::getNhId() const
476545
else if (gNeighOrch->hasNextHop(m_key))
477546
{
478547
nh_id = gNeighOrch->getNextHopId(m_key);
548+
if (m_key.isSrv6NextHop())
549+
{
550+
SWSS_LOG_INFO("Single NH: create srv6 nexthop %s", m_key.to_string(false, true).c_str());
551+
if (!gSrv6Orch->createSrv6NexthopWithoutVpn(m_key, nh_id))
552+
{
553+
SWSS_LOG_ERROR("Failed to create SRv6 nexthop %s", m_key.to_string(false, true).c_str());
554+
}
555+
}
479556
}
480557
/*
481558
* If the next hop is labeled and the IP next hop exists, create the
@@ -494,7 +571,20 @@ sai_object_id_t NextHopGroupMember::getNhId() const
494571
}
495572
else
496573
{
497-
gNeighOrch->resolveNeighbor(m_key);
574+
if (m_key.isSrv6NextHop())
575+
{
576+
SWSS_LOG_INFO("Single NH: create srv6 nexthop %s", m_key.to_string(false, true).c_str());
577+
if (!gSrv6Orch->createSrv6NexthopWithoutVpn(m_key, nh_id))
578+
{
579+
SWSS_LOG_ERROR("Failed to create SRv6 nexthop %s", m_key.to_string(false, true).c_str());
580+
}
581+
}
582+
else
583+
{
584+
SWSS_LOG_INFO("Failed to get next hop %s, resolving neighbor",
585+
m_key.to_string().c_str());
586+
gNeighOrch->resolveNeighbor(m_key);
587+
}
498588
}
499589

500590
return nh_id;
@@ -570,14 +660,22 @@ NextHopGroupMember::~NextHopGroupMember()
570660
{
571661
SWSS_LOG_ENTER();
572662

663+
if (m_key.isSrv6NextHop() && gNeighOrch->hasNextHop(m_key) &&
664+
!gNeighOrch->getNextHopRefCount(m_key))
665+
{
666+
if (!gSrv6Orch->removeSrv6NexthopWithoutVpn(m_key))
667+
{
668+
SWSS_LOG_ERROR("SRv6 Nexthop %s delete failed", m_key.to_string(false, true).c_str());
669+
}
670+
}
573671
/*
574672
* If the labeled next hop is unreferenced, remove it from NeighOrch as
575673
* NhgOrch and RouteOrch are the ones controlling it's lifetime. They both
576674
* watch over these labeled next hops, so it doesn't matter who created
577675
* them as they're both doing the same checks before removing a labeled
578676
* next hop.
579677
*/
580-
if (isLabeled() &&
678+
else if (isLabeled() &&
581679
gNeighOrch->hasNextHop(m_key) &&
582680
(gNeighOrch->getNextHopRefCount(m_key) == 0))
583681
{
@@ -824,6 +922,7 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys)
824922
*/
825923
std::map<NextHopKey, sai_object_id_t> syncingMembers;
826924

925+
bool success = true;
827926
for (const auto& nh_key : nh_keys)
828927
{
829928
NextHopGroupMember& nhgm = m_members.at(nh_key);
@@ -841,7 +940,8 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys)
841940
{
842941
SWSS_LOG_WARN("Failed to get next hop %s in group %s",
843942
nhgm.to_string().c_str(), to_string().c_str());
844-
return false;
943+
success = false;
944+
continue;
845945
}
846946

847947
/* If the neighbor's interface is down, skip from being syncd. */
@@ -868,7 +968,6 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys)
868968
* Go through the synced members and increment the Crm ref count for the
869969
* successful ones.
870970
*/
871-
bool success = true;
872971
for (const auto& mbr : syncingMembers)
873972
{
874973
/* Check that the returned member ID is valid. */
@@ -941,7 +1040,7 @@ bool NextHopGroup::update(const NextHopGroupKey& nhg_key)
9411040
/* If the member is updated, update it's weight. */
9421041
else
9431042
{
944-
if (!mbr_it.second.updateWeight(new_nh_key_it->weight))
1043+
if (new_nh_key_it->weight && mbr_it.second.getWeight() != new_nh_key_it->weight && !mbr_it.second.updateWeight(new_nh_key_it->weight))
9451044
{
9461045
SWSS_LOG_WARN("Failed to update member %s weight", nh_key.to_string().c_str());
9471046
return false;

orchagent/orchdaemon.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ bool OrchDaemon::init()
222222

223223
vector<string> srv6_tables = {
224224
APP_SRV6_SID_LIST_TABLE_NAME,
225-
APP_SRV6_MY_SID_TABLE_NAME
225+
APP_SRV6_MY_SID_TABLE_NAME,
226+
APP_PIC_CONTEXT_TABLE_NAME
226227
};
227228
gSrv6Orch = new Srv6Orch(m_applDb, srv6_tables, gSwitchOrch, vrf_orch, gNeighOrch);
228229
gDirectory.set(gSrv6Orch);

0 commit comments

Comments
 (0)