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