P4C
The P4 Compiler
Loading...
Searching...
No Matches
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
41using ::P4::ReferenceMap;
42using ::P4::TypeMap;
43using ::P4::ControlPlaneAPI::Helpers::getExternInstanceFromProperty;
44using ::P4::ControlPlaneAPI::Helpers::isExternPropertyConstructedInPlace;
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)
96 ::P4::error(ErrorType::ERR_NOT_FOUND, "Program does not contain a `main` module");
97 auto cparams = main->getConstructorParameters();
98 int index = -1;
99 for (auto param : main->constantValue) {
100 index++;
101 if (!param.second) continue;
102 auto pipe = param.second;
103 if (!pipe->is<IR::PackageBlock>()) continue;
104 auto idxParam = cparams->getParameter(index);
105 auto pipeName = idxParam->name;
106 function(pipeName, pipe->to<IR::PackageBlock>());
107 }
108 }
109
114
115 using Counter = p4configv1::Counter;
116 using Meter = p4configv1::Meter;
117 using CounterSpec = p4configv1::CounterSpec;
118 using MeterSpec = p4configv1::MeterSpec;
119
120 BFRuntimeArchHandler(ReferenceMap *refMap, TypeMap *typeMap,
121 const IR::ToplevelBlock *evaluatedProgram)
122 : P4RuntimeArchHandlerCommon<arch>(refMap, typeMap, evaluatedProgram) {
123 // Create a map of all blocks to their pipe names. This map will
124 // be used during collect and post processing to prefix
125 // table/extern instances wherever applicable with a fully qualified
126 // name. This distinction is necessary when the driver looks up
127 // context.json across multiple pipes for the table name
128 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
129 Helpers::forAllEvaluatedBlocks(pkg, [&](const IR::Block *block) {
130 auto decl = pkg->node->to<IR::Declaration_Instance>();
131 cstring blockNamePrefix = pipeName;
132 if (decl) blockNamePrefix = decl->controlPlaneName();
133 blockNamePrefixMap[block] = blockNamePrefix;
134 });
135 });
136 }
137
138 cstring getBlockNamePrefix(const IR::Block *blk) {
139 if (blockNamePrefixMap.count(blk) > 0) return blockNamePrefixMap[blk];
140 return "pipe"_cs;
141 }
142
143 static p4configv1::Extern *getP4InfoExtern(P4RuntimeSymbolType typeId, cstring typeName,
144 p4configv1::P4Info *p4info) {
145 for (auto &externType : *p4info->mutable_externs()) {
146 if (externType.extern_type_id() == static_cast<p4rt_id_t>(typeId)) return &externType;
147 }
148 auto *externType = p4info->add_externs();
149 externType->set_extern_type_id(static_cast<p4rt_id_t>(typeId));
150 externType->set_extern_type_name(typeName);
151 return externType;
152 }
153
154 static void addP4InfoExternInstance(const P4RuntimeSymbolTableIface &symbols,
155 P4RuntimeSymbolType typeId, cstring typeName, cstring name,
156 const IR::IAnnotated *annotations,
157 const ::google::protobuf::Message &message,
158 p4configv1::P4Info *p4info,
159 cstring pipeName = cstring::empty) {
160 auto *externType = getP4InfoExtern(typeId, typeName, p4info);
161 auto *externInstance = externType->add_instances();
162 auto *pre = externInstance->mutable_preamble();
163 pre->set_id(symbols.getId(typeId, name));
164 pre->set_name(prefix(pipeName, name));
165 pre->set_alias(symbols.getAlias(name));
166 Helpers::addAnnotations(pre, annotations);
167 Helpers::addDocumentation(pre, annotations);
168 externInstance->mutable_info()->PackFrom(message);
169 }
170
171 std::optional<ActionSelector> getActionSelector(const IR::ExternBlock *instance) {
172 auto actionSelDecl = instance->node->to<IR::IDeclaration>();
173 // to be deleted, used to support deprecated ActionSelector constructor.
174 auto size = instance->getParameterValue("size"_cs);
175 BUG_CHECK(size->is<IR::Constant>(), "Non-constant size");
176 return ActionSelector{actionSelDecl->controlPlaneName(), size->to<IR::Constant>()->asInt(),
177 ActionSelector::defaultMaxGroupSize,
178 size->to<IR::Constant>()->asInt(),
179 actionSelDecl->to<IR::IAnnotated>()};
180 }
181
182 void addActionSelector(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
183 const ActionSelector &actionSelector,
184 cstring pipeName = cstring::empty) {
185 ::dpdk::ActionSelector selector;
186 selector.set_max_group_size(actionSelector.maxGroupSize);
187 selector.set_num_groups(actionSelector.numGroups);
188 p4configv1::ActionProfile profile;
189 profile.set_size(actionSelector.size);
190 auto tablesIt = this->actionProfilesRefs.find(actionSelector.name);
191 if (tablesIt != this->actionProfilesRefs.end()) {
192 for (const auto &table : tablesIt->second) {
193 profile.add_table_ids(symbols.getId(P4RuntimeSymbolType::P4RT_TABLE(), table));
194 selector.add_table_ids(symbols.getId(P4RuntimeSymbolType::P4RT_TABLE(), table));
195 }
196 }
197 // We use the ActionSelector name for the action profile, and add a "_sel" suffix for
198 // the action selector.
199 cstring profileName = actionSelector.name;
200 selector.set_action_profile_id(
201 symbols.getId(SymbolType::P4RT_ACTION_PROFILE(), profileName));
202 cstring selectorName = profileName + "_sel";
203 addP4InfoExternInstance(symbols, SymbolTypeDPDK::P4RT_ACTION_SELECTOR(),
204 "ActionSelector"_cs, selectorName, actionSelector.annotations,
205 selector, p4Info, pipeName);
206 }
207
209 const IR::ExternBlock *externBlock) override {
211
212 auto decl = externBlock->node->to<IR::IDeclaration>();
213 if (decl == nullptr) return;
214 if (externBlock->type->name == "Digest") {
215 symbols->add(SymbolType::P4RT_DIGEST(), decl);
216 } else if (externBlock->type->name == ActionSelectorTraits<arch>::typeName()) {
217 auto selName = decl->controlPlaneName() + "_sel";
218 auto profName = decl->controlPlaneName();
219 symbols->add(SymbolTypeDPDK::P4RT_ACTION_SELECTOR(), selName);
220 symbols->add(SymbolType::P4RT_ACTION_PROFILE(), profName);
221 }
222 }
223
224 void addTableProperties(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
225 p4configv1::Table *table, const IR::TableBlock *tableBlock) override {
226 P4RuntimeArchHandlerCommon<arch>::addTableProperties(symbols, p4info, table, tableBlock);
227
228 auto tableDeclaration = tableBlock->container;
229 bool supportsTimeout = getSupportsTimeout(tableDeclaration);
230 if (supportsTimeout) {
231 table->set_idle_timeout_behavior(p4configv1::Table::NOTIFY_CONTROL);
232 } else {
233 table->set_idle_timeout_behavior(p4configv1::Table::NO_TIMEOUT);
234 }
235
236 // add pipe name prefix to the table names
237 auto pipeName = getBlockNamePrefix(tableBlock);
238 auto *pre = table->mutable_preamble();
239 if (pre->name() == tableDeclaration->controlPlaneName())
240 pre->set_name(prefix(pipeName, pre->name()));
241 }
242
243 void addExternInstance(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
244 const IR::ExternBlock *externBlock) override {
245 P4RuntimeArchHandlerCommon<arch>::addExternInstance(symbols, p4info, externBlock);
246
247 auto decl = externBlock->node->to<IR::Declaration_Instance>();
248 if (decl == nullptr) return;
249
250 // DPDK control plane software requires pipe name to be prefixed to the
251 // table and extern names
252 cstring pipeName = getBlockNamePrefix(externBlock);
253
254 auto p4RtTypeInfo = p4info->mutable_type_info();
255 if (externBlock->type->name == "Digest") {
256 auto digest = getDigest(decl, p4RtTypeInfo);
257 if (digest) this->addDigest(symbols, p4info, *digest);
258 } else if (externBlock->type->name == "ActionSelector") {
259 auto actionSelector = getActionSelector(externBlock);
260 if (actionSelector) addActionSelector(symbols, p4info, *actionSelector, pipeName);
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 == "ActionProfile") {
269 for (auto &extType : *p4info->mutable_action_profiles()) {
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 == "Meter") {
277 for (auto &extType : *p4info->mutable_meters()) {
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 == "Counter") {
285 for (auto &extType : *p4info->mutable_counters()) {
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 } else if (externBlock->type->name == "Register") {
293 for (auto &extType : *p4info->mutable_registers()) {
294 auto *pre = extType.mutable_preamble();
295 if (pre->name() == decl->controlPlaneName()) {
296 pre->set_name(prefix(pipeName, pre->name()));
297 break;
298 }
299 }
300 }
301 }
302
304 std::optional<Digest> getDigest(const IR::Declaration_Instance *decl,
305 p4configv1::P4TypeInfo *p4RtTypeInfo) {
306 BUG_CHECK(decl->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
307 decl->type);
308 auto type = decl->type->to<IR::Type_Specialized>();
309 BUG_CHECK(type->arguments->size() == 1, "%1%: expected one type argument", decl);
310 auto typeArg = type->arguments->at(0);
311 auto typeSpec =
312 TypeSpecConverter::convert(this->refMap, this->typeMap, typeArg, p4RtTypeInfo);
313 BUG_CHECK(typeSpec != nullptr,
314 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
315
316 return Digest{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>()};
317 }
318
321 static bool getSupportsTimeout(const IR::P4Table *table) {
322 auto timeout = table->properties->getProperty("psa_idle_timeout");
323
324 if (timeout == nullptr) return false;
325
326 if (auto exprValue = timeout->value->to<IR::ExpressionValue>()) {
327 if (auto expr = exprValue->expression) {
328 if (auto member = expr->to<IR::Member>()) {
329 if (member->member == "NOTIFY_CONTROL") {
330 return true;
331 } else if (member->member == "NO_TIMEOUT") {
332 return false;
333 }
334 } else if (expr->is<IR::PathExpression>()) {
335 ::P4::error(ErrorType::ERR_UNEXPECTED,
336 "Unresolved value %1% for psa_idle_timeout "
337 "property on table %2%. Must be a constant and one of "
338 "{ NOTIFY_CONTROL, NO_TIMEOUT }",
339 timeout, table);
340 return false;
341 }
342 }
343 }
344
345 ::P4::error(ErrorType::ERR_UNEXPECTED,
346 "Unexpected value %1% for psa_idle_timeout "
347 "property on table %2%. Supported values are "
348 "{ NOTIFY_CONTROL, NO_TIMEOUT }",
349 timeout, table);
350 return false;
351 }
352};
353
354class BFRuntimeArchHandlerPSA final : public BFRuntimeArchHandler<Arch::PSA> {
355 public:
357 const IR::ToplevelBlock *evaluatedProgram)
358 : BFRuntimeArchHandler(refMap, typeMap, evaluatedProgram) {}
359};
360
361class BFRuntimeArchHandlerPNA final : public BFRuntimeArchHandler<Arch::PNA> {
362 public:
364 const IR::ToplevelBlock *evaluatedProgram)
365 : BFRuntimeArchHandler(refMap, typeMap, evaluatedProgram) {}
366};
367
371 ReferenceMap *refMap, TypeMap *typeMap,
372 const IR::ToplevelBlock *evaluatedProgram) const override {
374 evaluatedProgram);
375 }
376};
377
381 ReferenceMap *refMap, TypeMap *typeMap,
382 const IR::ToplevelBlock *evaluatedProgram) const override {
384 evaluatedProgram);
385 }
386};
387
388} // namespace Standard
389
390} // namespace ControlPlaneAPI
391
392 /* end group control_plane */
393} // namespace P4
394
395#endif /* DPDK_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_ */
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:304
static bool getSupportsTimeout(const IR::P4Table *table)
Definition bfruntime_arch_handler.h:321
void collectExternInstance(P4RuntimeSymbolTableIface *symbols, const IR::ExternBlock *externBlock) override
Collects architecture-specific @externBlock instance in @symbols table.
Definition bfruntime_arch_handler.h:208
Definition bfruntime_arch_handler.h:361
Definition bfruntime_arch_handler.h:354
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:387
The Declaration interface, representing objects with names.
Definition declaration.h:26
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition typeMap.h:41
Definition cstring.h:85
void forAllEvaluatedBlocks(const IR::Block *block, Func function)
Definition p4RuntimeArchHandler.h:234
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
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition error.h:51
Definition p4RuntimeArchHandler.h:204
Definition bfruntime_arch_handler.h:71
The architecture handler builder implementation for PNA.
Definition bfruntime_arch_handler.h:379
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition bfruntime_arch_handler.h:380
The architecture handler builder implementation for PSA.
Definition bfruntime_arch_handler.h:369
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition bfruntime_arch_handler.h:370
T * to() noexcept
Definition rtti.h:226
bool is() const noexcept
Definition rtti.h:216