-
Notifications
You must be signed in to change notification settings - Fork 547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SRv6] Add support for SRv6 VPN #3293
base: master
Are you sure you want to change the base?
Changes from 26 commits
991b2a7
787649f
d52ed4a
80b439d
5573368
6b87876
290102b
1d02012
8808707
81dd833
a9e9993
3a191c5
639e38b
f324cc2
f8286e8
83c46a0
d2c7ee1
945e619
706ea83
b009870
a98aad8
cfcb015
62a28c0
61cc376
ea46f5f
05728e7
ae0273b
9cc7d7b
beb9e71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
#include "neighorch.h" | ||
#include "crmorch.h" | ||
#include "routeorch.h" | ||
#include "srv6orch.h" | ||
#include "bulker.h" | ||
#include "logger.h" | ||
#include "swssnet.h" | ||
|
@@ -12,6 +13,7 @@ extern IntfsOrch *gIntfsOrch; | |
extern NeighOrch *gNeighOrch; | ||
extern RouteOrch *gRouteOrch; | ||
extern NhgOrch *gNhgOrch; | ||
extern Srv6Orch *gSrv6Orch; | ||
|
||
extern size_t gMaxBulkSize; | ||
|
||
|
@@ -61,6 +63,9 @@ void NhgOrch::doTask(Consumer& consumer) | |
string mpls_nhs; | ||
string nhgs; | ||
bool is_recursive = false; | ||
string srv6_source; | ||
bool overlay_nh = false; | ||
bool srv6_nh = false; | ||
|
||
/* Get group's next hop IPs and aliases */ | ||
for (auto i : kfvFieldsValues(t)) | ||
|
@@ -77,6 +82,12 @@ void NhgOrch::doTask(Consumer& consumer) | |
if (fvField(i) == "mpls_nh") | ||
mpls_nhs = fvValue(i); | ||
|
||
if (fvField(i) == "seg_src") | ||
{ | ||
srv6_source = fvValue(i); | ||
srv6_nh = true; | ||
} | ||
|
||
if (fvField(i) == "nexthop_group") | ||
{ | ||
nhgs = fvValue(i); | ||
|
@@ -96,9 +107,11 @@ void NhgOrch::doTask(Consumer& consumer) | |
vector<string> alsv = tokenize(aliases, ','); | ||
vector<string> mpls_nhv = tokenize(mpls_nhs, ','); | ||
vector<string> nhgv = tokenize(nhgs, NHG_DELIMITER); | ||
vector<string> srv6_srcv = tokenize(srv6_source, ','); | ||
|
||
/* Create the next hop group key. */ | ||
string nhg_str; | ||
NextHopGroupKey nhg_key; | ||
|
||
/* Keeps track of any non-existing member of a recursive nexthop group */ | ||
bool non_existent_member = false; | ||
|
@@ -154,28 +167,77 @@ void NhgOrch::doTask(Consumer& consumer) | |
/* Form nexthopgroup key with the nexthopgroup keys of available members */ | ||
nhgv = tokenize(nhgs, NHG_DELIMITER); | ||
|
||
bool nhg_mismatch = false; | ||
for (uint32_t i = 0; i < nhgv.size(); i++) | ||
{ | ||
if (i) nhg_str += NHG_DELIMITER; | ||
auto k = m_syncdNextHopGroups.at(nhgv[i]).nhg->getKey(); | ||
if (i) | ||
{ | ||
if (k.is_srv6_nexthop() != srv6_nh || k.is_overlay_nexthop() != overlay_nh) | ||
{ | ||
SWSS_LOG_ERROR("Inconsistent nexthop group type between %s and %s", | ||
m_syncdNextHopGroups.at(nhgv[0]).nhg->getKey().to_string().c_str(), | ||
k.to_string().c_str()); | ||
nhg_mismatch = true; | ||
break; | ||
} | ||
nhg_str += NHG_DELIMITER; | ||
} | ||
else | ||
{ | ||
srv6_nh = k.is_srv6_nexthop(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we include VPN SID for the mismatch? I believe there shouldn't be any mix of NHs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no "vpn_sid" field in "APP_NEXTHOP_GROUP_TABLE_NAME" for nhgorch. |
||
overlay_nh = k.is_overlay_nexthop(); | ||
} | ||
|
||
nhg_str += m_syncdNextHopGroups.at(nhgv[i]).nhg->getKey().to_string(); | ||
} | ||
|
||
if (nhg_mismatch) | ||
{ | ||
it = consumer.m_toSync.erase(it); | ||
continue; | ||
} | ||
|
||
if (srv6_nh) | ||
nhg_key = NextHopGroupKey(nhg_str, overlay_nh, srv6_nh); | ||
else | ||
nhg_key = NextHopGroupKey(nhg_str, weights); | ||
} | ||
else | ||
{ | ||
for (uint32_t i = 0; i < ipv.size(); i++) | ||
if (srv6_nh) | ||
{ | ||
if (i) nhg_str += NHG_DELIMITER; | ||
if (!mpls_nhv.empty() && mpls_nhv[i] != "na") | ||
if (ipv.size() != srv6_srcv.size()) | ||
{ | ||
SWSS_LOG_ERROR("inconsistent number of endpoints and srv6_srcs."); | ||
it = consumer.m_toSync.erase(it); | ||
continue; | ||
} | ||
for (uint32_t i = 0; i < ipv.size(); i++) | ||
{ | ||
nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER; | ||
if (i) nhg_str += NHG_DELIMITER; | ||
nhg_str += ipv[i] + NH_DELIMITER; // ip address | ||
nhg_str += NH_DELIMITER; // srv6 segment | ||
nhg_str += srv6_srcv[i] + NH_DELIMITER; // srv6 source | ||
nhg_str += NH_DELIMITER; // srv6 vpn sid | ||
} | ||
nhg_key = NextHopGroupKey(nhg_str, overlay_nh, srv6_nh); | ||
} | ||
else | ||
{ | ||
for (uint32_t i = 0; i < ipv.size(); i++) | ||
{ | ||
if (i) nhg_str += NHG_DELIMITER; | ||
if (!mpls_nhv.empty() && mpls_nhv[i] != "na") | ||
{ | ||
nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER; | ||
} | ||
nhg_str += ipv[i] + NH_DELIMITER + alsv[i]; | ||
} | ||
nhg_str += ipv[i] + NH_DELIMITER + alsv[i]; | ||
nhg_key = NextHopGroupKey(nhg_str, weights); | ||
} | ||
} | ||
|
||
NextHopGroupKey nhg_key = NextHopGroupKey(nhg_str, weights); | ||
|
||
/* If the group does not exist, create one. */ | ||
if (nhg_it == m_syncdNextHopGroups.end()) | ||
{ | ||
|
@@ -192,6 +254,13 @@ void NhgOrch::doTask(Consumer& consumer) | |
{ | ||
SWSS_LOG_DEBUG("Next hop group count reached its limit."); | ||
|
||
// don't create temp nhg for srv6 | ||
if (nhg_key.is_srv6_nexthop()) | ||
{ | ||
++it; | ||
continue; | ||
} | ||
|
||
try | ||
{ | ||
auto nhg = std::make_unique<NextHopGroup>(createTempNhg(nhg_key)); | ||
|
@@ -476,6 +545,14 @@ sai_object_id_t NextHopGroupMember::getNhId() const | |
else if (gNeighOrch->hasNextHop(m_key)) | ||
{ | ||
nh_id = gNeighOrch->getNextHopId(m_key); | ||
if (m_key.isSrv6NextHop()) | ||
{ | ||
SWSS_LOG_INFO("Single NH: create srv6 nexthop %s", m_key.to_string(false, true).c_str()); | ||
if (!gSrv6Orch->createSrv6NexthopWithoutVpn(m_key, nh_id)) | ||
{ | ||
SWSS_LOG_ERROR("Failed to create SRv6 nexthop %s", m_key.to_string(false, true).c_str()); | ||
} | ||
} | ||
} | ||
/* | ||
* 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 | |
} | ||
else | ||
{ | ||
gNeighOrch->resolveNeighbor(m_key); | ||
if (m_key.isSrv6NextHop()) | ||
{ | ||
SWSS_LOG_INFO("Single NH: create srv6 nexthop %s", m_key.to_string(false, true).c_str()); | ||
if (!gSrv6Orch->createSrv6NexthopWithoutVpn(m_key, nh_id)) | ||
{ | ||
SWSS_LOG_ERROR("Failed to create SRv6 nexthop %s", m_key.to_string(false, true).c_str()); | ||
} | ||
} | ||
else | ||
{ | ||
SWSS_LOG_INFO("Failed to get next hop %s, resolving neighbor", | ||
m_key.to_string().c_str()); | ||
gNeighOrch->resolveNeighbor(m_key); | ||
} | ||
} | ||
|
||
return nh_id; | ||
|
@@ -570,14 +660,22 @@ NextHopGroupMember::~NextHopGroupMember() | |
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
if (m_key.isSrv6NextHop() && gNeighOrch->hasNextHop(m_key) && | ||
!gNeighOrch->getNextHopRefCount(m_key)) | ||
{ | ||
if (!gSrv6Orch->removeSrv6NexthopWithoutVpn(m_key)) | ||
{ | ||
SWSS_LOG_ERROR("SRv6 Nexthop %s delete failed", m_key.to_string(false, true).c_str()); | ||
} | ||
} | ||
/* | ||
* If the labeled next hop is unreferenced, remove it from NeighOrch as | ||
* NhgOrch and RouteOrch are the ones controlling it's lifetime. They both | ||
* watch over these labeled next hops, so it doesn't matter who created | ||
* them as they're both doing the same checks before removing a labeled | ||
* next hop. | ||
*/ | ||
if (isLabeled() && | ||
else if (isLabeled() && | ||
gNeighOrch->hasNextHop(m_key) && | ||
(gNeighOrch->getNextHopRefCount(m_key) == 0)) | ||
{ | ||
|
@@ -824,6 +922,7 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys) | |
*/ | ||
std::map<NextHopKey, sai_object_id_t> syncingMembers; | ||
|
||
bool success = true; | ||
for (const auto& nh_key : nh_keys) | ||
{ | ||
NextHopGroupMember& nhgm = m_members.at(nh_key); | ||
|
@@ -841,7 +940,8 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys) | |
{ | ||
SWSS_LOG_WARN("Failed to get next hop %s in group %s", | ||
nhgm.to_string().c_str(), to_string().c_str()); | ||
return false; | ||
success = false; | ||
continue; | ||
} | ||
|
||
/* If the neighbor's interface is down, skip from being syncd. */ | ||
|
@@ -868,7 +968,6 @@ bool NextHopGroup::syncMembers(const std::set<NextHopKey>& nh_keys) | |
* Go through the synced members and increment the Crm ref count for the | ||
* successful ones. | ||
*/ | ||
bool success = true; | ||
for (const auto& mbr : syncingMembers) | ||
{ | ||
/* Check that the returned member ID is valid. */ | ||
|
@@ -941,7 +1040,7 @@ bool NextHopGroup::update(const NextHopGroupKey& nhg_key) | |
/* If the member is updated, update it's weight. */ | ||
else | ||
{ | ||
if (!mbr_it.second.updateWeight(new_nh_key_it->weight)) | ||
if (new_nh_key_it->weight && mbr_it.second.getWeight() != new_nh_key_it->weight && !mbr_it.second.updateWeight(new_nh_key_it->weight)) | ||
{ | ||
SWSS_LOG_WARN("Failed to update member %s weight", nh_key.to_string().c_str()); | ||
return false; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yuezhoujk @shuaishang Do we need NH_DELIMITER after VPN SID at the end?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd better have. Since
srv6_vpn_sid
could be empty and we limit the length of tokenized keys should be 4There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @goomadao. But the key would be ending with the delimiter, is that ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late reply. It's OK because
tokenize
is able to handle this situation.