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