P4C
The P4 Compiler
Loading...
Searching...
No Matches
control-plane/bfruntime.h
1/*
2 * Copyright 2021 Intel Corporation
3 * SPDX-FileCopyrightText: 2021 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7#ifndef CONTROL_PLANE_BFRUNTIME_H_
8#define CONTROL_PLANE_BFRUNTIME_H_
9
10#include <algorithm>
11#include <iosfwd>
12#include <iterator>
13#include <optional>
14#include <ostream>
15#include <string>
16
17#include "control-plane/p4RuntimeSerializer.h"
18#include "lib/error.h"
19#include "lib/error_catalog.h"
20#include "lib/json.h"
21#pragma GCC diagnostic push
22#pragma GCC diagnostic ignored "-Wunused-parameter"
23#pragma GCC diagnostic ignored "-Wpedantic"
24#include "p4/config/v1/p4info.pb.h"
25#pragma GCC diagnostic pop
26
27namespace p4configv1 = ::p4::config::v1;
28
29namespace P4 {
30struct P4RuntimeAPI;
31} // namespace P4
32
33namespace P4 {
34
35namespace BFRT {
36
37using P4Id = uint32_t;
38
39// Helpers
40template <typename T, typename R>
41static inline constexpr P4Id makeBFRuntimeId(T base, R prefix) {
42 return static_cast<P4Id>((base & 0xffffff) | (prefix << 24));
43}
44
45static inline constexpr P4Id getIdPrefix(P4Id id) { return ((id >> 24) & 0xff); }
46
47static inline Util::JsonObject *findJsonTable(Util::JsonArray *tablesJson, cstring tblName) {
48 for (auto *t : *tablesJson) {
49 auto *tblObj = t->to<Util::JsonObject>();
50 auto tName = tblObj->getAs<Util::JsonValue>("name")->getString();
51 if (tName == tblName) {
52 return tblObj;
53 }
54 }
55 return nullptr;
56}
57
58static inline Util::JsonObject *transformAnnotation(const cstring &annotation) {
59 auto *annotationJson = new Util::JsonObject();
60 // TODO(antonin): annotation string will need to be parsed so we can have it
61 // in key/value format here.
62 annotationJson->emplace("name", annotation.escapeJson());
63 return annotationJson;
64}
65
66template <typename It>
67static inline Util::JsonArray *transformAnnotations(const It &first, const It &last) {
68 auto *annotations = new Util::JsonArray();
69 for (auto it = first; it != last; it++) annotations->append(transformAnnotation(*it));
70 return annotations;
71}
72
73static inline Util::JsonArray *transformAnnotations(const p4configv1::Preamble &pre) {
74 return transformAnnotations(pre.annotations().begin(), pre.annotations().end());
75}
76
78template <typename T>
79static inline bool isOfType(P4Id id, T prefix) {
80 return getIdPrefix(id) == static_cast<P4Id>(prefix);
81}
82
83namespace Standard {
84
85template <typename It>
86static inline auto findP4InfoObject(const It &first, const It &last, P4Id objectId) -> const
87 typename std::iterator_traits<It>::value_type * {
88 using T = typename std::iterator_traits<It>::value_type;
89 auto desiredObject = std::find_if(
90 first, last, [&](const T &object) { return object.preamble().id() == objectId; });
91 if (desiredObject == last) return nullptr;
92 return &*desiredObject;
93}
94
95static inline const p4configv1::Table *findTable(const p4configv1::P4Info &p4info, P4Id tableId) {
96 const auto &tables = p4info.tables();
97 return findP4InfoObject(tables.begin(), tables.end(), tableId);
98}
99
100static inline const p4configv1::Action *findAction(const p4configv1::P4Info &p4info,
101 P4Id actionId) {
102 const auto &actions = p4info.actions();
103 return Standard::findP4InfoObject(actions.begin(), actions.end(), actionId);
104}
105
106static inline const p4configv1::ActionProfile *findActionProf(const p4configv1::P4Info &p4info,
107 P4Id actionProfId) {
108 const auto &actionProfs = p4info.action_profiles();
109 return findP4InfoObject(actionProfs.begin(), actionProfs.end(), actionProfId);
110}
111
112static inline const p4configv1::DirectCounter *findDirectCounter(const p4configv1::P4Info &p4info,
113 P4Id counterId) {
114 const auto &counters = p4info.direct_counters();
115 return findP4InfoObject(counters.begin(), counters.end(), counterId);
116}
117
118static inline const p4configv1::DirectMeter *findDirectMeter(const p4configv1::P4Info &p4info,
119 P4Id meterId) {
120 const auto &meters = p4info.direct_meters();
121 return findP4InfoObject(meters.begin(), meters.end(), meterId);
122}
123
124} // namespace Standard
125
126static inline Util::JsonObject *makeType(cstring type) {
127 auto *typeObj = new Util::JsonObject();
128 typeObj->emplace("type", type);
129 return typeObj;
130}
131
132template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
133static inline Util::JsonObject *makeType(cstring type, T defaultValue) {
134 auto *typeObj = new Util::JsonObject();
135 typeObj->emplace("type", type);
136 typeObj->emplace("default_value", defaultValue);
137 return typeObj;
138}
139
140static inline Util::JsonObject *makeTypeBool(std::optional<bool> defaultValue = std::nullopt) {
141 auto *typeObj = new Util::JsonObject();
142 typeObj->emplace("type", "bool");
143 if (defaultValue != std::nullopt) typeObj->emplace("default_value", *defaultValue);
144 return typeObj;
145}
146
147static inline Util::JsonObject *makeTypeBytes(int width,
148 std::optional<int64_t> defaultValue = std::nullopt) {
149 auto *typeObj = new Util::JsonObject();
150 typeObj->emplace("type", "bytes");
151 typeObj->emplace("width", width);
152 if (defaultValue != std::nullopt) typeObj->emplace("default_value", *defaultValue);
153 return typeObj;
154}
155
156static inline Util::JsonObject *makeTypeEnum(const std::vector<cstring> &choices,
157 std::optional<cstring> defaultValue = std::nullopt) {
158 auto *typeObj = new Util::JsonObject();
159 typeObj->emplace("type", "string");
160 auto *choicesArray = new Util::JsonArray();
161 for (auto choice : choices) choicesArray->append(choice);
162 typeObj->emplace("choices", choicesArray);
163 if (defaultValue != std::nullopt) typeObj->emplace("default_value", *defaultValue);
164 return typeObj;
165}
166
167static inline void addSingleton(Util::JsonArray *dataJson, Util::JsonObject *dataField,
168 bool mandatory, bool readOnly) {
169 auto *singletonJson = new Util::JsonObject();
170 singletonJson->emplace("mandatory", mandatory);
171 singletonJson->emplace("read_only", readOnly);
172 singletonJson->emplace("singleton", dataField);
173 dataJson->append(singletonJson);
174}
175
176static inline void addOneOf(Util::JsonArray *dataJson, Util::JsonArray *choicesJson, bool mandatory,
177 bool readOnly) {
178 auto *oneOfJson = new Util::JsonObject();
179 oneOfJson->emplace("mandatory", mandatory);
180 oneOfJson->emplace("read_only", readOnly);
181 oneOfJson->emplace("oneof", choicesJson);
182 dataJson->append(oneOfJson);
183}
184
185// FIXME: Switch to std::string_view
186static inline std::optional<cstring> transformMatchType(
187 p4configv1::MatchField_MatchType matchType) {
188 switch (matchType) {
189 case p4configv1::MatchField_MatchType_UNSPECIFIED:
190 return std::nullopt;
191 case p4configv1::MatchField_MatchType_EXACT:
192 return "Exact"_cs;
193 case p4configv1::MatchField_MatchType_LPM:
194 return "LPM"_cs;
195 case p4configv1::MatchField_MatchType_TERNARY:
196 return "Ternary"_cs;
197 case p4configv1::MatchField_MatchType_RANGE:
198 return "Range"_cs;
199 case p4configv1::MatchField_MatchType_OPTIONAL:
200 return "Optional"_cs;
201 default:
202 return std::nullopt;
203 }
204}
205
206// FIXME: Switch to std::string_view
207static inline std::optional<cstring> transformOtherMatchType(std::string matchType) {
208 if (matchType == "atcam_partition_index") return "ATCAM"_cs;
209 if (matchType == "dleft_hash") return "DLEFT_HASH"_cs;
210
211 return std::nullopt;
212}
213
214template <typename It>
215static std::vector<P4Id> collectTableIds(const p4configv1::P4Info &p4info, const It &first,
216 const It &last) {
217 std::vector<P4Id> tableIds;
218 for (auto it = first; it != last; it++) {
219 auto *table = Standard::findTable(p4info, *it);
220 if (table == nullptr) {
221 ::P4::error(ErrorType::ERR_INVALID, "Invalid table id '%1%'", *it);
222 continue;
223 }
224 tableIds.push_back(*it);
225 }
226 return tableIds;
227}
228
232class TypeSpecParser {
233 public:
234 struct Field {
235 cstring name;
236 P4Id id;
237 Util::JsonObject *type;
238 };
239
240 using Fields = std::vector<Field>;
241 using iterator = Fields::iterator;
242 using const_iterator = Fields::const_iterator;
243
244 static TypeSpecParser make(const p4configv1::P4Info &p4info,
245 const p4configv1::P4DataTypeSpec &typeSpec, cstring instanceType,
246 cstring instanceName,
247 const std::vector<cstring> *fieldNames = nullptr,
248 cstring prefix = cstring::empty, cstring suffix = cstring::empty,
249 P4Id idOffset = 1);
250
251 iterator begin() { return fields.begin(); }
252 const_iterator cbegin() { return fields.cbegin(); }
253 iterator end() { return fields.end(); }
254 const_iterator cend() { return fields.cend(); }
255 size_t size() { return fields.size(); }
256
257 private:
258 explicit TypeSpecParser(Fields &&fields) : fields(std::move(fields)) {}
259
260 Fields fields;
261};
262
263class BFRuntimeGenerator {
264 public:
265 virtual ~BFRuntimeGenerator() = default;
266 explicit BFRuntimeGenerator(const p4configv1::P4Info &p4info) : p4info(p4info) {}
267
269 virtual const Util::JsonObject *genSchema() const;
270
273 void serializeBFRuntimeSchema(std::ostream *destination);
274
275 protected:
276 // To avoid potential clashes with P4 names, we prefix the names of "fixed"
277 // data field with a '$'. For example, for TD_DATA_ACTION_MEMBER_ID, we
278 // use the name $ACTION_MEMBER_ID.
279 enum TDDataFieldIds : P4Id {
280 // ids for fixed data fields must not collide with the auto-generated
281 // ids for P4 fields (e.g. match key fields).
282 TD_DATA_START = (1 << 16),
283
284 TD_DATA_MATCH_PRIORITY,
285
286 TD_DATA_ACTION,
287 TD_DATA_ACTION_MEMBER_ID,
288 TD_DATA_SELECTOR_GROUP_ID,
289 TD_DATA_ACTION_MEMBER_STATUS,
290 TD_DATA_MAX_GROUP_SIZE,
291
292 TD_DATA_ENTRY_TTL,
293 TD_DATA_ENTRY_HIT_STATE,
294
295 TD_DATA_METER_SPEC_CIR_KBPS,
296 TD_DATA_METER_SPEC_PIR_KBPS,
297 TD_DATA_METER_SPEC_CBS_KBITS,
298 TD_DATA_METER_SPEC_PBS_KBITS,
299
300 TD_DATA_METER_SPEC_CIR_PPS,
301 TD_DATA_METER_SPEC_PIR_PPS,
302 TD_DATA_METER_SPEC_CBS_PKTS,
303 TD_DATA_METER_SPEC_PBS_PKTS,
304
305 TD_DATA_COUNTER_SPEC_BYTES,
306 TD_DATA_COUNTER_SPEC_PKTS,
307
308 TD_DATA_METER_INDEX,
309 TD_DATA_COUNTER_INDEX,
310 TD_DATA_REGISTER_INDEX,
311
312 TD_DATA_END,
313 };
314
316 struct Counter {
317 enum Unit { UNSPECIFIED = 0, BYTES = 1, PACKETS = 2, BOTH = 3 };
318 std::string name;
319 P4Id id;
320 int64_t size;
321 Unit unit;
322 Util::JsonArray *annotations;
323
324 static std::optional<Counter> from(const p4configv1::Counter &counterInstance);
325 static std::optional<Counter> fromDirect(const p4configv1::DirectCounter &counterInstance);
326 };
327
329 struct Meter {
330 enum Unit { UNSPECIFIED = 0, BYTES = 1, PACKETS = 2 };
331 enum Type { COLOR_UNAWARE = 0, COLOR_AWARE = 1 };
332 std::string name;
333 P4Id id;
334 int64_t size;
335 Unit unit;
336 Util::JsonArray *annotations;
337
338 static std::optional<Meter> from(const p4configv1::Meter &meterInstance);
339 static std::optional<Meter> fromDirect(const p4configv1::DirectMeter &meterInstance);
340 };
341
344 struct ActionProf {
345 std::string name;
346 P4Id id;
347 int64_t size;
348 std::vector<P4Id> tableIds;
349 Util::JsonArray *annotations;
350 static P4Id makeActProfId(P4Id implementationId);
351 static std::optional<ActionProf> from(const p4configv1::P4Info &p4info,
352 const p4configv1::ActionProfile &actionProfile);
353 };
354
356 struct Digest {
357 std::string name;
358 P4Id id;
359 p4configv1::P4DataTypeSpec typeSpec;
360 Util::JsonArray *annotations;
361
362 static std::optional<Digest> from(const p4configv1::Digest &digest);
363 };
364
366 struct Register {
367 std::string name;
368 std::string dataFieldName;
369 P4Id id;
370 int64_t size;
371 p4configv1::P4DataTypeSpec typeSpec;
372 Util::JsonArray *annotations;
373
374 static std::optional<Register> from(const p4configv1::Register &regInstance);
375 };
376
377 void addMatchTables(Util::JsonArray *tablesJson) const;
378 virtual bool addMatchTypePriority(std::optional<cstring> &matchType) const;
379 virtual void addConstTableAttr(Util::JsonArray *attrJson) const;
380 virtual void addActionProfs(Util::JsonArray *tablesJson) const;
381 virtual bool addActionProfIds(const p4configv1::Table &table,
382 Util::JsonObject *tableJson) const;
383 void addCounters(Util::JsonArray *tablesJson) const;
384 void addMeters(Util::JsonArray *tablesJson) const;
385 void addRegisters(Util::JsonArray *tablesJson) const;
386
387 void addCounterCommon(Util::JsonArray *tablesJson, const Counter &counter) const;
388 void addMeterCommon(Util::JsonArray *tablesJson, const Meter &meter) const;
389 void addRegisterCommon(Util::JsonArray *tablesJson, const Register &reg) const;
390 void addActionProfCommon(Util::JsonArray *tablesJson, const ActionProf &actionProf) const;
391 void addLearnFilters(Util::JsonArray *learnFiltersJson) const;
392 void addLearnFilterCommon(Util::JsonArray *learnFiltersJson, const Digest &digest) const;
393 virtual void addDirectResources(const p4configv1::Table &table, Util::JsonArray *dataJson,
394 Util::JsonArray *operationsJson,
395 Util::JsonArray *attributesJson,
396 P4Id maxActionParamId = 0) const;
397
398 virtual std::optional<bool> actProfHasSelector(P4Id actProfId) const;
404 Util::JsonArray *makeActionSpecs(const p4configv1::Table &table,
405 P4Id *maxActionParamId = nullptr) const;
406 virtual std::optional<Counter> getDirectCounter(P4Id counterId) const;
407 virtual std::optional<Meter> getDirectMeter(P4Id meterId) const;
408
418 const p4configv1::P4DataTypeSpec &typeSpec,
419 cstring instanceType, cstring instanceName,
420 const std::vector<cstring> *fieldNames = nullptr,
421 cstring prefix = cstring::empty,
422 cstring suffix = cstring::empty, P4Id idOffset = 1) const;
423
424 static void addMeterDataFields(Util::JsonArray *dataJson, const Meter &meter);
425 static Util::JsonObject *makeCommonDataField(P4Id id, cstring name, Util::JsonObject *type,
426 bool repeated,
427 Util::JsonArray *annotations = nullptr);
428
429 static Util::JsonObject *makeContainerDataField(P4Id id, cstring name, Util::JsonArray *items,
430 bool repeated,
431 Util::JsonArray *annotations = nullptr);
432
433 static void addActionDataField(Util::JsonArray *dataJson, P4Id id, const std::string &name,
434 bool mandatory, bool read_only, Util::JsonObject *type,
435 Util::JsonArray *annotations = nullptr);
436
437 static void addKeyField(Util::JsonArray *dataJson, P4Id id, cstring name, bool mandatory,
438 cstring matchType, Util::JsonObject *type,
439 Util::JsonArray *annotations = nullptr);
440
441 static void addCounterDataFields(Util::JsonArray *dataJson, const Counter &counter);
442
443 static Util::JsonObject *initTableJson(const std::string &name, P4Id id, cstring tableType,
444 int64_t size, Util::JsonArray *annotations = nullptr);
445
446 static void addToDependsOn(Util::JsonObject *tableJson, P4Id id);
447
451 void addRegisterDataFields(Util::JsonArray *dataJson, const Register &register_,
452 P4Id idOffset = 1) const;
453
454 const p4configv1::P4Info &p4info;
455};
456
457} // namespace BFRT
458
459} // namespace P4
460
461#endif /* CONTROL_PLANE_BFRUNTIME_H_ */
void addRegisterDataFields(Util::JsonArray *dataJson, const Register &register_, P4Id idOffset=1) const
Definition control-plane/bfruntime.cpp:402
void serializeBFRuntimeSchema(std::ostream *destination)
Definition control-plane/bfruntime.cpp:864
virtual const Util::JsonObject * genSchema() const
Generates the schema as a Json object for the provided P4Info instance.
Definition control-plane/bfruntime.cpp:843
void transformTypeSpecToDataFields(Util::JsonArray *fieldsJson, const p4configv1::P4DataTypeSpec &typeSpec, cstring instanceType, cstring instanceName, const std::vector< cstring > *fieldNames=nullptr, cstring prefix=cstring::empty, cstring suffix=cstring::empty, P4Id idOffset=1) const
Definition control-plane/bfruntime.cpp:388
Util::JsonArray * makeActionSpecs(const p4configv1::Table &table, P4Id *maxActionParamId=nullptr) const
Definition control-plane/bfruntime.cpp:532
Definition control-plane/bfruntime.h:234
Definition lib/json.h:128
Definition lib/json.h:177
Definition cstring.h:85
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 control-plane/bfruntime.h:344
Common counter representation between PSA and other architectures.
Definition control-plane/bfruntime.h:316
Common digest representation between PSA and other architectures.
Definition control-plane/bfruntime.h:356
Common meter representation between PSA and other architectures.
Definition control-plane/bfruntime.h:329
Common register representation between PSA and other architectures.
Definition control-plane/bfruntime.h:366
Definition p4RuntimeSerializer.h:48
Definition register_reference.h:28