-
Notifications
You must be signed in to change notification settings - Fork 17
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
VRF implementation for dataplane #242
base: main
Are you sure you want to change the base?
Conversation
6b2cf70
to
591f52f
Compare
common/define.h
Outdated
@@ -103,6 +103,7 @@ extern LogPriority logPriority; | |||
#define YANET_RIB_PRIORITY_DEFAULT ((uint32_t)10000) | |||
#define YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK ((uint32_t)11000) | |||
#define YANET_RIB_PRIORITY_ROUTE_REPEAT ((uint32_t)12000) | |||
#define YANET_RIB_VRF_DEFAULT "default" |
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.
constexpr auto YANET_RIB_VRF_DEFAULT = "default";
common/define.h
Outdated
#define YANET_RIB_PRIORITY_ROUTE_REPEAT ((uint32_t)12000) | ||
#define YANET_RIB_VRF_DEFAULT "default" |
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.
I think we should replace that in 97th line in librib/libyabird.cpp
too:
std::get<1>(request) = {peer_address,
{"default", ///< @todo: vrf
YANET_RIB_PRIORITY_DEFAULT}};
controlplane/route.h
Outdated
bool is_ignored_table(const std::string& table_name) const | ||
{ |
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.
const method returning value should be marked [[nodiscard]]
79639b4
to
c0399dd
Compare
common/controlplaneconfig.h
Outdated
config_t() : | ||
vrf(YANET_RIB_VRF_DEFAULT), | ||
tunnel_enabled(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.
I think this is redundant, since that class' fields are already defined with default values:
std::string vrf{"default"};
bool tunnel_enabled{};
We need to change that "default"
to YANET_RIB_VRF_DEFAULT
though, and that's it
@@ -118,6 +118,8 @@ extern LogPriority logPriority; | |||
#define YANET_RIB_PRIORITY_DEFAULT ((uint32_t)10000) | |||
#define YANET_RIB_PRIORITY_ROUTE_TUNNEL_FALLBACK ((uint32_t)11000) | |||
#define YANET_RIB_PRIORITY_ROUTE_REPEAT ((uint32_t)12000) | |||
#define YANET_RIB_VRF_DEFAULT "default" | |||
#define YANET_RIB_VRF_MAX_NUMBER 64 |
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.
#define YANET_RIB_VRF_MAX_NUMBER 64 | |
inline constexpr auto YANET_RIB_VRF_MAX_NUMBER = 64; |
or replace auto
with int
, whichever you prefer
controlplane/controlplane.cpp
Outdated
tVrfId VrfIdStorage::GetOrCreateOrException(const std::string& vrfName, const std::string& message) | ||
{ | ||
std::optional<tVrfId> vrfId = GetOrCreate(vrfName); | ||
if (!vrfId.has_value()) | ||
{ | ||
throw error_result_t(eResult::invalidVrfId, message + vrfName); | ||
} | ||
return *vrfId; | ||
} |
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 pass only string literals as message
to this function. Since we're taking const ref to a string, we will first require to construct that string from a string literal, and then we will construct another string by concatenating both when throwing an exception.
The better approach is to take message
as a string_view
, which is specifically designed as non-owning reference to a string.
Next, when calling this function, we expect user to add additional symbols ((": "
) to message
to make the error message pretty:
logicalPort.vrfId = controlplane_ptr->getVrfIdsStorage().GetOrCreateOrException(logicalPort.vrf, "Can't get id logicalPort.vrf: ");
The cleaner approach is to use std::ostringstream
to construct the error message (which is far more efficient that concatenation with operator+
).
So I suggest:
tVrfId VrfIdStorage::GetOrCreateOrException(const std::string& vrfName, const std::string& message) | |
{ | |
std::optional<tVrfId> vrfId = GetOrCreate(vrfName); | |
if (!vrfId.has_value()) | |
{ | |
throw error_result_t(eResult::invalidVrfId, message + vrfName); | |
} | |
return *vrfId; | |
} | |
tVrfId VrfIdStorage::GetOrCreateOrException(const std::string& vrfName, std::string_view message) | |
{ | |
std::optional<tVrfId> vrfId = GetOrCreate(vrfName); | |
if (!vrfId.has_value()) | |
{ | |
std::ostringstream oss; | |
oss << message <<": " << vrfName; | |
throw error_result_t(eResult::invalidVrfId, oss.str()); | |
} | |
return *vrfId; | |
} |
if (vrf_ids.size() + 1 >= YANET_RIB_VRF_MAX_NUMBER) | ||
{ | ||
vrf_ids[vrfName] = std::nullopt; |
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.
Do we need to store std::nullopt
in a map if we exceed the number of different id's?
I think we can just don't put it there.
This way we can use plain tVrfId
instead of std::optional<tVrfId>
in the map. If the ID can’t be assigned, we simply don’t put an entry in the map at all
controlplane/controlplane.cpp
Outdated
std::optional<tVrfId> VrfIdStorage::Get(const std::string& vrfName) | ||
{ | ||
if (vrfName.empty() || vrfName == YANET_RIB_VRF_DEFAULT) | ||
{ | ||
return 0; | ||
} | ||
|
||
std::shared_lock lock(mutex); | ||
|
||
auto iter = vrf_ids.find(vrfName); | ||
if (iter != vrf_ids.end()) | ||
{ | ||
return iter->second; | ||
} | ||
|
||
return std::nullopt; | ||
} |
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.
IMHO Get
method should be marked const
. It makes sense that in order to get something, we don't actually change the state of the class.
Now, we do capture a mutex here, so we need to mark it mutable
(mutable mutexes is a good idea):
private:
mutable std::shared_mutex mutex;
dataplane/updater.h
Outdated
updaters_[vrf] = std::make_unique<UpdaterType>(name.c_str(), memory_manager_, socket_id_); | ||
if (updaters_[vrf] == nullptr) | ||
{ | ||
return eResult::errorAllocatingMemory; | ||
} |
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.
This won't work. std::make_unique
never returns nullptr
- either it succeeds, or it throws std::bad_alloc
.
If we want to return an appropriate eResult
, we need to use one of the new
operator overloads that takes std::nothrow
object:
auto new_updater = std::unique_ptr<UpdaterType>(
new(std::nothrow) UpdaterType(uniqueName.c_str(), memory_manager_, socket_id_)
);
Or you can define helper function in the util
namespace:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_nothrow(Args&&... args) {
return std::unique_ptr<T>(new(std::nothrow) T(std::forward<Args>(args)...));
}
for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) | ||
{ | ||
if (updaters_[index]) | ||
{ | ||
updaters_[index]->limits(limits); | ||
} | ||
} |
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.
for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) | |
{ | |
if (updaters_[index]) | |
{ | |
updaters_[index]->limits(limits); | |
} | |
} | |
for (const auto& updater : updaters_) | |
{ | |
if (updater) | |
{ | |
updater->limits(limits); | |
} | |
} |
for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) | ||
{ | ||
if (updaters_[index]) | ||
{ | ||
updaters_[index]->report(report); | ||
} | ||
} |
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.
for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) | |
{ | |
if (updaters_[index]) | |
{ | |
updaters_[index]->report(report); | |
} | |
} | |
for (const auto& updater : updaters_) | |
{ | |
if (updater) | |
{ | |
updater->report(report); | |
} | |
} |
for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) | ||
{ | ||
if (updaters_[index]) | ||
{ | ||
updaters_[index]->clear(); | ||
updaters_[index] = nullptr; | ||
} | ||
} |
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.
for (size_t index = 0; index < YANET_RIB_VRF_MAX_NUMBER; index++) | |
{ | |
if (updaters_[index]) | |
{ | |
updaters_[index]->clear(); | |
updaters_[index] = nullptr; | |
} | |
} | |
for (const auto& updater : updaters_) | |
{ | |
if (updater) | |
{ | |
updater->clear(); | |
updater.reset(); | |
} | |
} |
} | ||
|
||
private: | ||
std::array<InnerLpmType*, YANET_RIB_VRF_MAX_NUMBER> lpms_; |
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.
std::array<InnerLpmType*, YANET_RIB_VRF_MAX_NUMBER>
is a common type, as I can see. I suggest to add an alias for it.
We will be able to utilize it GetLpms
method of updater_vrf_lpm
class too
void Lookup(const Address* ipAddresses, const tVrfId* vrfIds, uint32_t* valueIds, const unsigned int& count) const | ||
{ | ||
for (unsigned int index = 0; index < count; index++) | ||
{ | ||
valueIds[index] = lpmValueIdInvalid; | ||
tVrfId vrf = vrfIds[index]; | ||
if ((vrf < YANET_RIB_VRF_MAX_NUMBER) && (lpms_[vrf] != nullptr)) | ||
{ | ||
lpms_[vrf]->lookup(ipAddresses + index, valueIds + index, 1); | ||
} | ||
} | ||
} |
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.
The correct approach would be to use iterators to std::array
instead of pointer arithmetics, but we're so elbow deep in c-style arrays and pointer arithmetics in worker.h
and in underlying lpm
that such change would seem unnecessary.
Let's hope that in YANET2 we will be able to make things right (:
(that's not an issue, ignore it)
@@ -51,6 +51,11 @@ class tStack | |||
mbufsCount = 0; | |||
} | |||
|
|||
inline void copy_from(tStack& other) |
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.
inline void copy_from(tStack& other) | |
void copy_from(tStack& other) |
inline
is redundant.
A function defined entirely inside a class/struct/union definition, whether it's a member function or a non-member friend function, is implicitly an inline function
- Fixed filling in lpm stats. - Checking that the route table is ignored has been moved.
- VRF storage has been added in some structures, and vrf is also passed in calls to some functions. - In controlplane.conf one can set the vrf in logicalPort. In the metadata of the network packet the vrfId is filled in according to the value from logicalPort. - A VrfIdStorage object has been added to the cControlPlane class, which issues an id named vrf.
In controlplane.conf, one can set the vrf for lan and wan in the nat64statefull and nat46clat sections, these values will be set in the packet metadata.
I see that you've pushed Fix based on review comments commit. |
I see that you've fixed the most important one among my review requests -- about |
Previously, it was possible to add routing rules for different VRFs, but it was not possible to set VRFs for packets and only 'default' was used for them.
In the current change, the ability to set VRF for the entire logical port has been added. Later it will be possible to set VRF by acl rules.
To solve the LPM problem, an algorithm like to 'a path-compressed trie' is used.