-
Notifications
You must be signed in to change notification settings - Fork 444
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a P4Info API to the control-plane folder and P4Tools. (#4381)
* Add a P4Runtime API to P4Tools. * Tests and refactoring. * Switch back to pointer based unpacking for now. * Apply fix-its. * Review comments.
- Loading branch information
Showing
11 changed files
with
881 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include "backends/p4tools/common/control_plane/p4info_map.h" | ||
|
||
namespace P4::ControlPlaneAPI { | ||
|
||
P4InfoMaps::P4InfoMaps(const p4::config::v1::P4Info &p4Info) { buildP4InfoMaps(p4Info); } | ||
|
||
uint64_t szudzikPairing(p4rt_id_t x, p4rt_id_t y) { | ||
// See https://en.wikipedia.org/wiki/Pairing_function#Other_pairing_functions | ||
// This static assert ensures that p4rt_id_t used here is a uint32_t. | ||
// In case things change down the road. | ||
static_assert(std::is_convertible_v<p4rt_id_t, uint32_t> && | ||
std::is_same_v<p4rt_id_t, uint32_t>); | ||
return x >= y ? static_cast<uint64_t>(x) * x + x + y : x + static_cast<uint64_t>(y) * y; | ||
} | ||
|
||
void P4InfoMaps::buildP4InfoMaps(const p4::config::v1::P4Info &p4Info) { | ||
for (const auto &table : p4Info.tables()) { | ||
nameToIdMap[table.preamble().name()] = table.preamble().id(); | ||
idToNameMap[table.preamble().id()] = table.preamble().name(); | ||
for (const auto &matchField : table.match_fields()) { | ||
auto combinedName = table.preamble().name() + "_" + matchField.name(); | ||
nameToIdMap[combinedName] = matchField.id(); | ||
idToNameMap[szudzikPairing(table.preamble().id(), matchField.id())] = matchField.name(); | ||
} | ||
} | ||
for (const auto &action : p4Info.actions()) { | ||
nameToIdMap[action.preamble().name()] = action.preamble().id(); | ||
idToNameMap[action.preamble().id()] = action.preamble().name(); | ||
for (const auto ¶m : action.params()) { | ||
auto combinedName = action.preamble().name() + "_" + param.name(); | ||
nameToIdMap[combinedName] = param.id(); | ||
idToNameMap[szudzikPairing(action.preamble().id(), param.id())] = param.name(); | ||
} | ||
} | ||
for (const auto &actionProfile : p4Info.action_profiles()) { | ||
nameToIdMap[actionProfile.preamble().name()] = actionProfile.preamble().id(); | ||
idToNameMap[actionProfile.preamble().id()] = actionProfile.preamble().name(); | ||
} | ||
for (const auto &counter : p4Info.counters()) { | ||
nameToIdMap[counter.preamble().name()] = counter.preamble().id(); | ||
idToNameMap[counter.preamble().id()] = counter.preamble().name(); | ||
} | ||
for (const auto &counter : p4Info.direct_counters()) { | ||
nameToIdMap[counter.preamble().name()] = counter.preamble().id(); | ||
idToNameMap[counter.preamble().id()] = counter.preamble().name(); | ||
} | ||
for (const auto &meter : p4Info.meters()) { | ||
nameToIdMap[meter.preamble().name()] = meter.preamble().id(); | ||
idToNameMap[meter.preamble().id()] = meter.preamble().name(); | ||
} | ||
for (const auto &directMeter : p4Info.direct_meters()) { | ||
nameToIdMap[directMeter.preamble().name()] = directMeter.preamble().id(); | ||
idToNameMap[directMeter.preamble().id()] = directMeter.preamble().name(); | ||
} | ||
for (const auto &controllerMetadata : p4Info.controller_packet_metadata()) { | ||
nameToIdMap[controllerMetadata.preamble().name()] = controllerMetadata.preamble().id(); | ||
idToNameMap[controllerMetadata.preamble().id()] = controllerMetadata.preamble().name(); | ||
} | ||
for (const auto &valueSet : p4Info.value_sets()) { | ||
nameToIdMap[valueSet.preamble().name()] = valueSet.preamble().id(); | ||
idToNameMap[valueSet.preamble().id()] = valueSet.preamble().name(); | ||
} | ||
for (const auto &p4Register : p4Info.registers()) { | ||
nameToIdMap[p4Register.preamble().name()] = p4Register.preamble().id(); | ||
idToNameMap[p4Register.preamble().id()] = p4Register.preamble().name(); | ||
} | ||
for (const auto &digest : p4Info.digests()) { | ||
nameToIdMap[digest.preamble().name()] = digest.preamble().id(); | ||
idToNameMap[digest.preamble().id()] = digest.preamble().name(); | ||
} | ||
for (const auto &p4Extern : p4Info.externs()) { | ||
nameToIdMap[p4Extern.extern_type_name()] = p4Extern.extern_type_id(); | ||
idToNameMap[p4Extern.extern_type_id()] = p4Extern.extern_type_name(); | ||
} | ||
} | ||
|
||
std::optional<uint64_t> P4InfoMaps::lookUpP4RuntimeId(cstring controlPlaneName) const { | ||
auto it = nameToIdMap.find(controlPlaneName); | ||
if (it == nameToIdMap.end()) { | ||
return std::nullopt; | ||
} | ||
return it->second; | ||
} | ||
|
||
std::optional<cstring> P4InfoMaps::lookUpControlPlaneName(uint64_t id) const { | ||
auto it = idToNameMap.find(id); | ||
if (it == idToNameMap.end()) { | ||
return std::nullopt; | ||
} | ||
return it->second; | ||
} | ||
|
||
} // namespace P4::ControlPlaneAPI |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#ifndef BACKENDS_P4TOOLS_COMMON_CONTROL_PLANE_P4INFO_MAP_H_ | ||
#define BACKENDS_P4TOOLS_COMMON_CONTROL_PLANE_P4INFO_MAP_H_ | ||
#include <cstdint> | ||
#include <map> | ||
#include <optional> | ||
|
||
#include "control-plane/p4RuntimeArchHandler.h" | ||
#include "control-plane/p4RuntimeSerializer.h" | ||
#include "lib/cstring.h" | ||
|
||
#pragma GCC diagnostic push | ||
#pragma GCC diagnostic ignored "-Wunused-parameter" | ||
#pragma GCC diagnostic ignored "-Wpedantic" | ||
#include "p4/config/v1/p4info.pb.h" | ||
#pragma GCC diagnostic pop | ||
|
||
/// TODO: Consider migrating this API to the top-level control-plane folder. | ||
/// The reason we have not already done this is because that folder already provides similar utility | ||
/// functions. However, these functions are tied to the P4RuntimeTableIface, which is fairly | ||
/// inflexible. We just need an API that can perform lookup operations on a P4Info or P4RuntimeAPI | ||
/// object. | ||
namespace P4::ControlPlaneAPI { | ||
|
||
/// Computes a unique pairing of two input numbers. We use this to generate unique P4Runtime IDs | ||
/// for combinations of tables and key elements, or actions and parameters. | ||
/// https://en.wikipedia.org/wiki/Pairing_function#Other_pairing_functions | ||
/// The maximum szudzikPairing value is 2^64 - 1, which is why we use uint64_t for the p4rt_id_t, | ||
/// which is uint32_t bit. | ||
uint64_t szudzikPairing(p4rt_id_t x, p4rt_id_t y); | ||
|
||
/// This object maps P4 control plane names to their P4Runtime IDs and vice versa. | ||
/// It uses the P4Info object to populate the maps. | ||
/// Since ids for action parameters and table keys are not unique, we use a pairing function to | ||
/// compute a unique identifier. This pairing function uses the id of the parent object (e.g., a | ||
/// table or action) and combines it with the id of the parameter or key element to create a unique | ||
/// identifier. | ||
class P4InfoMaps { | ||
/// Type definitions for convenience. | ||
using P4RuntimeIdToControlPlaneNameMap = std::map<uint64_t, cstring>; | ||
using ControlPlaneNameToP4RuntimeIdMap = std::map<cstring, uint64_t>; | ||
|
||
protected: | ||
/// Maps P4Runtime IDs to control plane names. | ||
P4RuntimeIdToControlPlaneNameMap idToNameMap; | ||
|
||
/// Maps control plane names to P4Runtime IDs. | ||
ControlPlaneNameToP4RuntimeIdMap nameToIdMap; | ||
|
||
/// Iterate over the P4Info object and build a mapping from P4 control plane names to their ids. | ||
virtual void buildP4InfoMaps(const p4::config::v1::P4Info &p4Info); | ||
|
||
public: | ||
explicit P4InfoMaps(const p4::config::v1::P4Info &p4Info); | ||
|
||
/// Looks up the P4Runtime id for the given control plane name in the pre-computed P4Runtime-ID | ||
/// map. @returns std::nullopt if the name is not in the map. | ||
[[nodiscard]] std::optional<uint64_t> lookUpP4RuntimeId(cstring controlPlaneName) const; | ||
|
||
/// Looks up the control plane name for the given P4Runtime id in the pre-computed P4Runtime-ID | ||
/// map. @returns std::nullopt if the id is not in the map. | ||
[[nodiscard]] std::optional<cstring> lookUpControlPlaneName(uint64_t id) const; | ||
}; | ||
|
||
} // namespace P4::ControlPlaneAPI | ||
|
||
#endif /* BACKENDS_P4TOOLS_COMMON_CONTROL_PLANE_P4INFO_MAP_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#include "backends/p4tools/modules/testgen/test/lib/p4info_api.h" | ||
|
||
#include "backends/p4tools/common/control_plane/p4info_map.h" | ||
|
||
namespace Test { | ||
|
||
namespace { | ||
|
||
using P4::ControlPlaneAPI::p4rt_id_t; | ||
using P4::ControlPlaneAPI::szudzikPairing; | ||
|
||
TEST_F(P4RuntimeApiTest, SzudzikPairingisCorrect) { | ||
EXPECT_EQ(szudzikPairing(0, 0), 0); | ||
EXPECT_EQ(szudzikPairing(0, 1), 1); | ||
EXPECT_EQ(szudzikPairing(1, 0), 2); | ||
EXPECT_EQ(szudzikPairing(3, 5), 28); | ||
EXPECT_EQ(szudzikPairing(5, 3), 33); | ||
EXPECT_EQ(szudzikPairing(UINT32_MAX, UINT32_MAX), UINT64_MAX); | ||
EXPECT_EQ(szudzikPairing(0, UINT32_MAX), 18446744065119617025U); | ||
EXPECT_EQ(szudzikPairing(UINT32_MAX, 0), 18446744069414584320U); | ||
} | ||
|
||
} // namespace | ||
|
||
} // namespace Test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#ifndef BACKENDS_P4TOOLS_MODULES_TESTGEN_TEST_LIB_P4INFO_API_H_ | ||
#define BACKENDS_P4TOOLS_MODULES_TESTGEN_TEST_LIB_P4INFO_API_H_ | ||
|
||
#include "backends/p4tools/modules/testgen/test/gtest_utils.h" | ||
|
||
namespace Test { | ||
|
||
/// Helper methods to build configurations for P4RuntimeApi Tests. | ||
class P4RuntimeApiTest : public P4ToolsTest {}; | ||
|
||
} // namespace Test | ||
|
||
#endif /* BACKENDS_P4TOOLS_MODULES_TESTGEN_TEST_LIB_P4INFO_API_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.