P4C
The P4 Compiler
Loading...
Searching...
No Matches
dpdk/control-plane/bfruntime_arch_handler.h
1/*
2 * Copyright 2021 Intel Corporation
3 * SPDX-FileCopyrightText: 2021 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7#ifndef BACKENDS_DPDK_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_
8#define BACKENDS_DPDK_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_
9
10#include <iostream>
11#include <optional>
12#include <set>
13#include <unordered_map>
14#include <vector>
15
16#pragma GCC diagnostic push
17#pragma GCC diagnostic ignored "-Wunused-parameter"
18#pragma GCC diagnostic ignored "-Wpedantic"
19#include "backends/dpdk/p4/config/p4info.pb.h"
20#pragma GCC diagnostic pop
21
22#include "control-plane/bfruntime.h"
23#include "control-plane/p4RuntimeArchHandler.h"
24#include "control-plane/p4RuntimeArchStandard.h"
25#include "control-plane/p4RuntimeSerializer.h"
26#include "control-plane/typeSpecConverter.h"
27#include "frontends/common/resolveReferences/referenceMap.h"
28#include "frontends/p4/externInstance.h"
29#include "frontends/p4/methodInstance.h"
30#include "frontends/p4/typeMap.h"
31#include "midend/eliminateTypedefs.h"
32
33using ::P4::ReferenceMap;
34using ::P4::TypeMap;
37
38namespace p4configv1 = ::p4::config::v1;
39
40namespace P4 {
41
44namespace ControlPlaneAPI {
45
47namespace Standard {
48
49cstring prefix(cstring p, cstring str) { return p.isNullOrEmpty() ? str : p + "." + str; }
50
52class SymbolTypeDPDK final : public SymbolType {
53 public:
54 SymbolTypeDPDK() = delete;
55
56 static P4RuntimeSymbolType P4RT_ACTION_SELECTOR() {
57 return P4RuntimeSymbolType::make(dpdk::P4Ids::ACTION_SELECTOR);
58 }
59};
60
64 const cstring name; // The fully qualified external name of this action selector.
65 const int64_t size; // TODO(hanw): size does not make sense with new ActionSelector P4 extern
66 const int64_t maxGroupSize;
67 const int64_t numGroups;
68 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this action
69 // profile declaration.
70
71 static constexpr int64_t defaultMaxGroupSize = 120;
72
73 p4rt_id_t getId(const P4RuntimeSymbolTableIface &symbols) const {
74 return symbols.getId(SymbolTypeDPDK::P4RT_ACTION_SELECTOR(), name + "_sel");
75 }
76};
77
78template <Arch arch>
79class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon<arch> {
80 protected:
81 std::unordered_map<const IR::Block *, cstring> blockNamePrefixMap;
82
83 public:
84 template <typename Func>
85 void forAllPipeBlocks(const IR::ToplevelBlock *evaluatedProgram, Func function) {
86 auto main = evaluatedProgram->getMain();
87 if (!main)
88 ::P4::error(ErrorType::ERR_NOT_FOUND, "Program does not contain a `main` module");
89 auto cparams = main->getConstructorParameters();
90 int index = -1;
91 for (auto param : main->constantValue) {
92 index++;
93 if (!param.second) continue;
94 auto pipe = param.second;
95 if (!pipe->is<IR::PackageBlock>()) continue;
96 auto idxParam = cparams->getParameter(index);
97 auto pipeName = idxParam->name;
98 function(pipeName, pipe->to<IR::PackageBlock>());
99 }
100 }
101
102 using ArchCounterExtern = CounterExtern<arch>;
104 using ArchMeterExtern = MeterExtern<arch>;
106
107 using Counter = p4configv1::Counter;
108 using Meter = p4configv1::Meter;
109 using CounterSpec = p4configv1::CounterSpec;
110 using MeterSpec = p4configv1::MeterSpec;
111
112 BFRuntimeArchHandler(ReferenceMap *refMap, TypeMap *typeMap,
113 const IR::ToplevelBlock *evaluatedProgram)
114 : P4RuntimeArchHandlerCommon<arch>(refMap, typeMap, evaluatedProgram) {
115 // Create a map of all blocks to their pipe names. This map will
116 // be used during collect and post processing to prefix
117 // table/extern instances wherever applicable with a fully qualified
118 // name. This distinction is necessary when the driver looks up
119 // context.json across multiple pipes for the table name
120 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
121 Helpers::forAllEvaluatedBlocks(pkg, [&](const IR::Block *block) {
122 auto decl = pkg->node->to<IR::Declaration_Instance>();
123 cstring blockNamePrefix = pipeName;
124 if (decl) blockNamePrefix = decl->controlPlaneName();
125 blockNamePrefixMap[block] = blockNamePrefix;
126 });
127 });
128 }
129
130 cstring getBlockNamePrefix(const IR::Block *blk) {
131 if (blockNamePrefixMap.count(blk) > 0) return blockNamePrefixMap[blk];
132 return "pipe"_cs;
133 }
134
135 static p4configv1::Extern *getP4InfoExtern(P4RuntimeSymbolType typeId, cstring typeName,
136 p4configv1::P4Info *p4info) {
137 for (auto &externType : *p4info->mutable_externs()) {
138 if (externType.extern_type_id() == static_cast<p4rt_id_t>(typeId)) return &externType;
139 }
140 auto *externType = p4info->add_externs();
141 externType->set_extern_type_id(static_cast<p4rt_id_t>(typeId));
142 externType->set_extern_type_name(typeName);
143 return externType;
144 }
145
146 static void addP4InfoExternInstance(const P4RuntimeSymbolTableIface &symbols,
147 P4RuntimeSymbolType typeId, cstring typeName, cstring name,
148 const IR::IAnnotated *annotations,
149 const ::google::protobuf::Message &message,
150 p4configv1::P4Info *p4info,
151 cstring pipeName = cstring::empty) {
152 auto *externType = getP4InfoExtern(typeId, typeName, p4info);
153 auto *externInstance = externType->add_instances();
154 auto *pre = externInstance->mutable_preamble();
155 pre->set_id(symbols.getId(typeId, name));
156 pre->set_name(prefix(pipeName, name));
157 pre->set_alias(symbols.getAlias(name));
158 Helpers::addAnnotations(pre, annotations);
159 Helpers::addDocumentation(pre, annotations);
160 externInstance->mutable_info()->PackFrom(message);
161 }
162
163 std::optional<ActionSelector> getActionSelector(const IR::ExternBlock *instance) {
164 auto actionSelDecl = instance->node->to<IR::IDeclaration>();
165 // to be deleted, used to support deprecated ActionSelector constructor.
166 auto size = instance->getParameterValue("size"_cs);
167 BUG_CHECK(size->is<IR::Constant>(), "Non-constant size");
168 return ActionSelector{actionSelDecl->controlPlaneName(), size->to<IR::Constant>()->asInt(),
169 ActionSelector::defaultMaxGroupSize,
170 size->to<IR::Constant>()->asInt(),
171 actionSelDecl->to<IR::IAnnotated>()};
172 }
173
174 void addActionSelector(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
175 const ActionSelector &actionSelector,
176 cstring pipeName = cstring::empty) {
177 ::dpdk::ActionSelector selector;
178 selector.set_max_group_size(actionSelector.maxGroupSize);
179 selector.set_num_groups(actionSelector.numGroups);
180 p4configv1::ActionProfile profile;
181 profile.set_size(actionSelector.size);
182 auto tablesIt = this->actionProfilesRefs.find(actionSelector.name);
183 if (tablesIt != this->actionProfilesRefs.end()) {
184 for (const auto &table : tablesIt->second) {
185 profile.add_table_ids(symbols.getId(P4RuntimeSymbolType::P4RT_TABLE(), table));
186 selector.add_table_ids(symbols.getId(P4RuntimeSymbolType::P4RT_TABLE(), table));
187 }
188 }
189 // We use the ActionSelector name for the action profile, and add a "_sel" suffix for
190 // the action selector.
191 cstring profileName = actionSelector.name;
192 selector.set_action_profile_id(
193 symbols.getId(SymbolType::P4RT_ACTION_PROFILE(), profileName));
194 cstring selectorName = profileName + "_sel";
195 addP4InfoExternInstance(symbols, SymbolTypeDPDK::P4RT_ACTION_SELECTOR(),
196 "ActionSelector"_cs, selectorName, actionSelector.annotations,
197 selector, p4Info, pipeName);
198 }
199
201 const IR::ExternBlock *externBlock) override {
203
204 auto decl = externBlock->node->to<IR::IDeclaration>();
205 if (decl == nullptr) return;
206 if (externBlock->type->name == "Digest") {
207 symbols->add(SymbolType::P4RT_DIGEST(), decl);
208 } else if (externBlock->type->name == ActionSelectorTraits<arch>::typeName()) {
209 auto selName = decl->controlPlaneName() + "_sel";
210 auto profName = decl->controlPlaneName();
211 symbols->add(SymbolTypeDPDK::P4RT_ACTION_SELECTOR(), selName);
212 symbols->add(SymbolType::P4RT_ACTION_PROFILE(), profName);
213 }
214 }
215
216 void addTableProperties(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
217 p4configv1::Table *table, const IR::TableBlock *tableBlock) override {
218 P4RuntimeArchHandlerCommon<arch>::addTableProperties(symbols, p4info, table, tableBlock);
219
220 auto tableDeclaration = tableBlock->container;
221 bool supportsTimeout = getSupportsTimeout(tableDeclaration);
222 if (supportsTimeout) {
223 table->set_idle_timeout_behavior(p4configv1::Table::NOTIFY_CONTROL);
224 } else {
225 table->set_idle_timeout_behavior(p4configv1::Table::NO_TIMEOUT);
226 }
227
228 // add pipe name prefix to the table names
229 auto pipeName = getBlockNamePrefix(tableBlock);
230 auto *pre = table->mutable_preamble();
231 if (pre->name() == tableDeclaration->controlPlaneName())
232 pre->set_name(prefix(pipeName, pre->name()));
233 }
234
235 void addExternInstance(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
236 const IR::ExternBlock *externBlock) override {
237 P4RuntimeArchHandlerCommon<arch>::addExternInstance(symbols, p4info, externBlock);
238
239 auto decl = externBlock->node->to<IR::Declaration_Instance>();
240 if (decl == nullptr) return;
241
242 // DPDK control plane software requires pipe name to be prefixed to the
243 // table and extern names
244 cstring pipeName = getBlockNamePrefix(externBlock);
245
246 auto p4RtTypeInfo = p4info->mutable_type_info();
247 if (externBlock->type->name == "Digest") {
248 auto digest = getDigest(decl, p4RtTypeInfo);
249 if (digest) this->addDigest(symbols, p4info, *digest);
250 } else if (externBlock->type->name == "ActionSelector") {
251 auto actionSelector = getActionSelector(externBlock);
252 if (actionSelector) addActionSelector(symbols, p4info, *actionSelector, pipeName);
253 for (auto &extType : *p4info->mutable_action_profiles()) {
254 auto *pre = extType.mutable_preamble();
255 if (pre->name() == decl->controlPlaneName()) {
256 pre->set_name(prefix(pipeName, pre->name()));
257 break;
258 }
259 }
260 } else if (externBlock->type->name == "ActionProfile") {
261 for (auto &extType : *p4info->mutable_action_profiles()) {
262 auto *pre = extType.mutable_preamble();
263 if (pre->name() == decl->controlPlaneName()) {
264 pre->set_name(prefix(pipeName, pre->name()));
265 break;
266 }
267 }
268 } else if (externBlock->type->name == "Meter") {
269 for (auto &extType : *p4info->mutable_meters()) {
270 auto *pre = extType.mutable_preamble();
271 if (pre->name() == decl->controlPlaneName()) {
272 pre->set_name(prefix(pipeName, pre->name()));
273 break;
274 }
275 }
276 } else if (externBlock->type->name == "Counter") {
277 for (auto &extType : *p4info->mutable_counters()) {
278 auto *pre = extType.mutable_preamble();
279 if (pre->name() == decl->controlPlaneName()) {
280 pre->set_name(prefix(pipeName, pre->name()));
281 break;
282 }
283 }
284 } else if (externBlock->type->name == "Register") {
285 for (auto &extType : *p4info->mutable_registers()) {
286 auto *pre = extType.mutable_preamble();
287 if (pre->name() == decl->controlPlaneName()) {
288 pre->set_name(prefix(pipeName, pre->name()));
289 break;
290 }
291 }
292 }
293 }
294
296 std::optional<Digest> getDigest(const IR::Declaration_Instance *decl,
297 p4configv1::P4TypeInfo *p4RtTypeInfo) {
298 BUG_CHECK(decl->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
299 decl->type);
300 auto type = decl->type->to<IR::Type_Specialized>();
301 BUG_CHECK(type->arguments->size() == 1, "%1%: expected one type argument", decl);
302 auto typeArg = type->arguments->at(0);
303 auto typeSpec =
304 TypeSpecConverter::convert(this->refMap, this->typeMap, typeArg, p4RtTypeInfo);
305 BUG_CHECK(typeSpec != nullptr,
306 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
307
308 return Digest{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>()};
309 }
310
313 static bool getSupportsTimeout(const IR::P4Table *table) {
314 auto timeout = table->properties->getProperty("psa_idle_timeout");
315
316 if (timeout == nullptr) return false;
317
318 if (auto exprValue = timeout->value->to<IR::ExpressionValue>()) {
319 if (auto expr = exprValue->expression) {
320 if (auto member = expr->to<IR::Member>()) {
321 if (member->member == "NOTIFY_CONTROL") {
322 return true;
323 } else if (member->member == "NO_TIMEOUT") {
324 return false;
325 }
326 } else if (expr->is<IR::PathExpression>()) {
327 ::P4::error(ErrorType::ERR_UNEXPECTED,
328 "Unresolved value %1% for psa_idle_timeout "
329 "property on table %2%. Must be a constant and one of "
330 "{ NOTIFY_CONTROL, NO_TIMEOUT }",
331 timeout, table);
332 return false;
333 }
334 }
335 }
336
337 ::P4::error(ErrorType::ERR_UNEXPECTED,
338 "Unexpected value %1% for psa_idle_timeout "
339 "property on table %2%. Supported values are "
340 "{ NOTIFY_CONTROL, NO_TIMEOUT }",
341 timeout, table);
342 return false;
343 }
344};
345
346class BFRuntimeArchHandlerPSA final : public BFRuntimeArchHandler<Arch::PSA> {
347 public:
348 BFRuntimeArchHandlerPSA(ReferenceMap *refMap, TypeMap *typeMap,
349 const IR::ToplevelBlock *evaluatedProgram)
350 : BFRuntimeArchHandler(refMap, typeMap, evaluatedProgram) {}
351};
352
353class BFRuntimeArchHandlerPNA final : public BFRuntimeArchHandler<Arch::PNA> {
354 public:
355 BFRuntimeArchHandlerPNA(ReferenceMap *refMap, TypeMap *typeMap,
356 const IR::ToplevelBlock *evaluatedProgram)
357 : BFRuntimeArchHandler(refMap, typeMap, evaluatedProgram) {}
358};
359
363 ReferenceMap *refMap, TypeMap *typeMap,
364 const IR::ToplevelBlock *evaluatedProgram) const override {
366 evaluatedProgram);
367 }
368};
369
373 ReferenceMap *refMap, TypeMap *typeMap,
374 const IR::ToplevelBlock *evaluatedProgram) const override {
376 evaluatedProgram);
377 }
378};
379
380} // namespace Standard
381
382} // namespace ControlPlaneAPI
383 /* end group control_plane */
385} // namespace P4
386
387#endif /* BACKENDS_DPDK_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_ */
Definition p4RuntimeArchHandler.h:130
Definition p4RuntimeArchHandler.h:100
virtual p4rt_id_t getId(P4RuntimeSymbolType type, const IR::IDeclaration *declaration) const =0
virtual cstring getAlias(cstring name) const =0
virtual void add(P4RuntimeSymbolType type, const IR::IDeclaration *declaration)=0
Add a @type symbol, extracting the name and id from @declaration.
Definition p4RuntimeArchHandler.h:54
std::optional< Digest > getDigest(const IR::Declaration_Instance *decl, p4configv1::P4TypeInfo *p4RtTypeInfo)
Definition dpdk/control-plane/bfruntime_arch_handler.h:296
static bool getSupportsTimeout(const IR::P4Table *table)
Definition dpdk/control-plane/bfruntime_arch_handler.h:313
void collectExternInstance(P4RuntimeSymbolTableIface *symbols, const IR::ExternBlock *externBlock) override
Collects architecture-specific @externBlock instance in @symbols table.
Definition dpdk/control-plane/bfruntime_arch_handler.h:200
Definition dpdk/control-plane/bfruntime_arch_handler.h:353
Definition dpdk/control-plane/bfruntime_arch_handler.h:346
void collectExternInstance(P4RuntimeSymbolTableIface *symbols, const IR::ExternBlock *externBlock) override
Collects architecture-specific @externBlock instance in @symbols table.
Definition p4RuntimeArchStandard.h:584
static const ::p4::config::v1::P4DataTypeSpec * convert(const P4::ReferenceMap *refMap, P4::TypeMap *typeMap, const IR::Type *type, ::p4::config::v1::P4TypeInfo *typeInfo)
Definition typeSpecConverter.cpp:377
The Declaration interface, representing objects with names.
Definition declaration.h:17
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
Definition typeMap.h:32
Definition cstring.h:85
Definition p4RuntimeArchHandler.h:100
void forAllEvaluatedBlocks(const IR::Block *block, Func function)
Definition p4RuntimeArchHandler.h:225
std::optional< ExternInstance > getExternInstanceFromProperty(const IR::P4Table *table, const cstring &propertyName, ReferenceMap *refMap, TypeMap *typeMap, bool *isConstructedInPlace)
Definition p4RuntimeArchHandler.cpp:30
bool isExternPropertyConstructedInPlace(const IR::P4Table *table, const cstring &propertyName)
Definition p4RuntimeArchHandler.cpp:66
void addDocumentation(Message *message, const IR::IAnnotated *annotated)
' and '@description' annotations if present.
Definition p4RuntimeArchHandler.h:299
A traits class describing the properties of "counterlike" things.
Definition p4RuntimeArchHandler.h:360
Declarations specific to standard architectures (v1model & PSA).
Definition dpdk/control-plane/bfruntime_arch_handler.h:47
Definition p4RuntimeArchStandard.h:339
Definition p4RuntimeArchStandard.h:41
Definition p4RuntimeArchStandard.h:414
Definition p4RuntimeArchStandard.h:43
TODO(antonin): High level goals of the generator go here!!
Definition dpdk/control-plane/bfruntime_arch_handler.h:44
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition p4RuntimeArchHandler.h:195
Definition dpdk/control-plane/bfruntime_arch_handler.h:63
The architecture handler builder implementation for PNA.
Definition dpdk/control-plane/bfruntime_arch_handler.h:371
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition dpdk/control-plane/bfruntime_arch_handler.h:372
The architecture handler builder implementation for PSA.
Definition dpdk/control-plane/bfruntime_arch_handler.h:361
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition dpdk/control-plane/bfruntime_arch_handler.h:362
T * to() noexcept
Definition rtti.h:226
bool is() const noexcept
Definition rtti.h:216
Definition register_reference.h:28