bmv2
Designing your own switch target with bmv2
P4Objects.h
1 /* Copyright 2013-present Barefoot Networks, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /*
17  * Antonin Bas (antonin@barefootnetworks.com)
18  *
19  */
20 
21 #ifndef BM_BM_SIM_P4OBJECTS_H_
22 #define BM_BM_SIM_P4OBJECTS_H_
23 
24 #include <iosfwd>
25 #include <vector>
26 #include <unordered_map>
27 #include <string>
28 #include <memory>
29 #include <set>
30 #include <tuple>
31 #include <utility> // for pair<>
32 
33 #include "tables.h"
34 #include "headers.h"
35 #include "phv_forward.h"
36 #include "parser.h"
37 #include "deparser.h"
38 #include "pipeline.h"
39 #include "conditionals.h"
40 #include "checksums.h"
41 #include "control_flow.h"
42 #include "learning.h"
43 #include "meters.h"
44 #include "counters.h"
45 #include "stateful.h"
46 #include "ageing.h"
47 #include "field_lists.h"
48 #include "extern.h"
49 #include "enums.h"
50 #include "control_action.h"
51 #include "device_id.h"
52 
53 // forward declaration of Json::Value
54 namespace Json {
55 
56 class Value;
57 
58 } // namespace Json
59 
60 namespace bm {
61 
62 using ConfigOptionMap = std::unordered_map<std::string, std::string>;
63 
64 class P4Objects {
65  public:
66  using header_field_pair = std::pair<std::string, std::string>;
67 
68  enum class ResourceType {
69  MATCH_TABLE,
70  ACTION_PROFILE,
71  COUNTER,
72  METER,
73  REGISTER,
74  LEARNING_LIST
75  };
76 
77  class ForceArith {
78  friend class P4Objects;
79 
80  public:
81  void add_field(const std::string &header_name,
82  const std::string &field_name) {
83  fields.insert(std::make_pair(header_name, field_name));
84  }
85 
86  void add_header(const std::string &header_name) {
87  headers.insert(header_name);
88  }
89 
90  private:
91  std::set<header_field_pair> fields;
92  std::set<std::string> headers;
93  };
94 
95  public:
96  // NOLINTNEXTLINE(runtime/references)
97  explicit P4Objects(std::ostream &outstream, bool verbose_output = false);
98  P4Objects();
99 
100  int init_objects(std::istream *is,
101  LookupStructureFactory *lookup_factory,
102  device_id_t device_id = 0, cxt_id_t cxt_id = 0,
103  std::shared_ptr<TransportIface> transport = nullptr,
104  const std::set<header_field_pair> &required_fields =
105  std::set<header_field_pair>(),
106  const ForceArith &arith_objects = ForceArith());
107 
108  P4Objects(const P4Objects &other) = delete;
109  P4Objects &operator=(const P4Objects &) = delete;
110 
111  public:
112  PHVFactory &get_phv_factory() { return phv_factory; }
113 
114  LearnEngineIface *get_learn_engine() { return learn_engine.get(); }
115 
116  std::shared_ptr<TransportIface> get_notifications_transport() {
117  return notifications_transport;
118  }
119 
120  AgeingMonitorIface *get_ageing_monitor() { return ageing_monitor.get(); }
121 
122  void reset_state();
123 
124  void serialize(std::ostream *out) const;
125  void deserialize(std::istream *in);
126 
127  enum class IdLookupErrorCode {
128  SUCCESS,
129  INVALID_RESOURCE_TYPE,
130  INVALID_RESOURCE_NAME
131  };
132 
133  IdLookupErrorCode id_from_name(ResourceType type, const std::string &name,
134  p4object_id_t *id);
135 
136  ActionFn *get_action_by_id(p4object_id_t id) const {
137  return actions_map.at(id).get();
138  }
139 
140  // TODO(antonin): temporary function to ensure backwards compat of JSON
141  ActionFn *get_one_action_with_name(const std::string &name) const {
142  for (auto it = actions_map.begin(); it != actions_map.end(); it++) {
143  if (it->second->get_name() == name) return it->second.get();
144  }
145  return nullptr;
146  }
147 
148  ActionFn *get_action(const std::string &table_name,
149  const std::string &action_name) const {
150  return t_actions_map.at(std::make_pair(table_name, action_name));
151  }
152 
153  ActionFn *get_action_for_action_profile(
154  const std::string &act_prof_name, const std::string &action_name) const;
155 
156  ActionFn *get_action_rt(const std::string &table_name,
157  const std::string &action_name) const;
158 
159  ActionFn *get_action_for_action_profile_rt(
160  const std::string &act_prof_name, const std::string &action_name) const;
161 
162  // For most functions I have a get_* version that will throw an exception if
163  // an element does not exist (exception not caught) and a get_*_rt version
164  // that returns a nullptr if it does not exist. I should probably get rid of
165  // the first version...
166  Parser *get_parser(const std::string &name) const {
167  return parsers.at(name).get();
168  }
169 
170  Parser *get_parser_rt(const std::string &name) const;
171 
172  ParseVSet *get_parse_vset(const std::string &name) const {
173  return parse_vsets.at(name).get();
174  }
175 
176  ParseVSet *get_parse_vset_rt(const std::string &name) const;
177 
178  Deparser *get_deparser(const std::string &name) const {
179  return deparsers.at(name).get();
180  }
181 
182  Deparser *get_deparser_rt(const std::string &name) const;
183 
184  MatchTableAbstract *get_abstract_match_table(const std::string &name) const {
185  return match_action_tables_map.at(name)->get_match_table();
186  }
187 
188  MatchTableAbstract *get_abstract_match_table_rt(
189  const std::string &name) const;
190 
191  MatchActionTable *get_match_action_table(const std::string &name) const {
192  return match_action_tables_map.at(name).get();
193  }
194 
195  Conditional *get_conditional(const std::string &name) const {
196  return conditionals_map.at(name).get();
197  }
198 
199  ControlFlowNode *get_control_node(const std::string &name) const {
200  return control_nodes_map.at(name);
201  }
202 
203  Pipeline *get_pipeline(const std::string &name) const {
204  return pipelines_map.at(name).get();
205  }
206 
207  Pipeline *get_pipeline_rt(const std::string &name) const;
208 
209  MeterArray *get_meter_array(const std::string &name) const {
210  return meter_arrays.at(name).get();
211  }
212 
213  MeterArray *get_meter_array_rt(const std::string &name) const;
214 
215  CounterArray *get_counter_array(const std::string &name) const {
216  return counter_arrays.at(name).get();
217  }
218 
219  CounterArray *get_counter_array_rt(const std::string &name) const;
220 
221  RegisterArray *get_register_array(const std::string &name) const {
222  return register_arrays.at(name).get();
223  }
224 
225  RegisterArray *get_register_array_rt(const std::string &name) const;
226 
227  NamedCalculation *get_named_calculation(const std::string &name) const {
228  return calculations.at(name).get();
229  }
230 
231  FieldList *get_field_list(const p4object_id_t field_list_id) const {
232  return field_lists.at(field_list_id).get();
233  }
234 
235  ExternType *get_extern_instance(const std::string &name) const {
236  return extern_instances.at(name).get();
237  }
238 
239  ExternType *get_extern_instance_rt(const std::string &name) const;
240 
241  ActionProfile *get_action_profile(const std::string &name) const {
242  return action_profiles_map.at(name).get();
243  }
244 
245  ActionProfile *get_action_profile_rt(const std::string &name) const;
246 
247  bool field_exists(const std::string &header_name,
248  const std::string &field_name) const;
249 
250  bool header_exists(const std::string &header_name) const;
251 
252  // public to be accessed by test class
253  ActionPrimitive_ *get_primitive(const std::string &name);
254 
255  ConfigOptionMap get_config_options() const;
256 
257  ErrorCodeMap get_error_codes() const;
258 
259  EnumMap::type_t get_enum_value(const std::string &name) const;
260  const std::string &get_enum_name(const std::string &enum_name,
261  EnumMap::type_t entry_value) const;
262 
263  // returns maximum bmv2 json version supported by this parser as
264  // "<major>.<minor>"
265  static std::string get_json_version_string();
266 
267  private:
268  // The get_*_cfg are used during json parsing: they will throw a
269  // json_exception if the name cannot be resolved, which will lead to an error
270  // message being displayed to the user.
271  void add_header_type(const std::string &name,
272  std::unique_ptr<HeaderType> header_type);
273 
274  HeaderType *get_header_type_cfg(const std::string &name);
275 
276  void add_header_id(const std::string &name, header_id_t header_id);
277 
278  void add_header_stack_id(const std::string &name,
279  header_stack_id_t header_stack_id);
280 
281  void add_header_union_id(const std::string &name,
282  header_union_id_t header_union_id);
283 
284  void add_header_union_stack_id(const std::string &name,
285  header_union_stack_id_t header_union_stack_id);
286 
287  header_id_t get_header_id_cfg(const std::string &name) const;
288 
289  header_stack_id_t get_header_stack_id_cfg(const std::string &name) const;
290 
291  header_union_id_t get_header_union_id_cfg(const std::string &name) const;
292 
293  header_union_stack_id_t get_header_union_stack_id_cfg(
294  const std::string &name) const;
295 
296  void add_action(p4object_id_t id, std::unique_ptr<ActionFn> action);
297 
298  void add_action_to_table(const std::string &table_name,
299  const std::string &action_name, ActionFn *action);
300 
301  void add_action_to_act_prof(const std::string &act_prof_name,
302  const std::string &action_name,
303  ActionFn *action);
304 
305  void add_parser(const std::string &name, std::unique_ptr<Parser> parser);
306 
307  void add_parse_vset(const std::string &name,
308  std::unique_ptr<ParseVSet> parse_vset);
309 
310  ParseVSet *get_parse_vset_cfg(const std::string &name) const;
311 
312  void add_deparser(const std::string &name,
313  std::unique_ptr<Deparser> deparser);
314 
315  void add_match_action_table(const std::string &name,
316  std::unique_ptr<MatchActionTable> table);
317 
318  void add_action_profile(const std::string &name,
319  std::unique_ptr<ActionProfile> action_profile);
320 
321  ActionProfile *get_action_profile_cfg(const std::string &name) const;
322 
323  void add_conditional(const std::string &name,
324  std::unique_ptr<Conditional> conditional);
325 
326  void add_control_action(const std::string &name,
327  std::unique_ptr<ControlAction> control_action);
328 
329  void add_control_node(const std::string &name, ControlFlowNode *node);
330 
331  ControlFlowNode *get_control_node_cfg(const std::string &name) const;
332 
333  void add_pipeline(const std::string &name,
334  std::unique_ptr<Pipeline> pipeline);
335 
336  void add_meter_array(const std::string &name,
337  std::unique_ptr<MeterArray> meter_array);
338 
339  MeterArray *get_meter_array_cfg(const std::string &name) const;
340 
341  void add_counter_array(const std::string &name,
342  std::unique_ptr<CounterArray> counter_array);
343 
344  CounterArray *get_counter_array_cfg(const std::string &name) const;
345 
346  void add_register_array(const std::string &name,
347  std::unique_ptr<RegisterArray> register_array);
348 
349  RegisterArray *get_register_array_cfg(const std::string &name) const;
350 
351  void add_named_calculation(const std::string &name,
352  std::unique_ptr<NamedCalculation> calculation);
353 
354  NamedCalculation *get_named_calculation_cfg(const std::string &name) const;
355 
356  void add_field_list(const p4object_id_t field_list_id,
357  std::unique_ptr<FieldList> field_list);
358 
359  void add_extern_instance(const std::string &name,
360  std::unique_ptr<ExternType> extern_instance);
361 
362  ExternType *get_extern_instance_cfg(const std::string &name) const;
363 
364  struct InitState;
365  void init_enums(const Json::Value &root);
366  void init_header_types(const Json::Value &root);
367  void init_headers(const Json::Value &root);
368  void init_header_stacks(const Json::Value &root);
369  void init_header_unions(const Json::Value &root, InitState *);
370  void init_header_union_stacks(const Json::Value &root, InitState *);
371  void init_extern_instances(const Json::Value &root);
372  void init_parse_vsets(const Json::Value &root);
373  void init_errors(const Json::Value &root);
374  void init_parsers(const Json::Value &root, InitState *);
375  void init_deparsers(const Json::Value &root);
376  void init_calculations(const Json::Value &root);
377  void init_counter_arrays(const Json::Value &root);
378  void init_meter_arrays(const Json::Value &root, InitState *);
379  void init_register_arrays(const Json::Value &root);
380  void init_actions(const Json::Value &root);
381  void check_next_nodes(const Json::Value &cfg_next_nodes,
382  const Json::Value &cfg_actions,
383  const std::string &table_name,
384  bool *next_is_hit_miss);
385  void init_pipelines(const Json::Value &root, LookupStructureFactory *,
386  InitState *);
387  void init_checksums(const Json::Value &root);
388  void init_learn_lists(const Json::Value &root);
389  void init_field_lists(const Json::Value &root);
390 
391  void build_expression(const Json::Value &json_expression, Expression *expr);
392  void build_expression(const Json::Value &json_expression, Expression *expr,
393  ExprType *expr_type);
394 
395  void add_primitive_to_action(const Json::Value &primitive,
396  ActionFn *action_fn);
397  void process_single_param(ActionFn* action_fn,
398  const Json::Value &cfg_parameter,
399  const std::string &primitive_name);
400 
401  void parse_config_options(const Json::Value &root);
402 
403  private:
404  PHVFactory phv_factory{}; // this is probably temporary
405 
406  std::unordered_map<std::string, header_id_t> header_ids_map{};
407  std::unordered_map<std::string, header_stack_id_t> header_stack_ids_map{};
408  std::unordered_map<std::string, header_union_id_t> header_union_ids_map{};
409  std::unordered_map<std::string, header_union_stack_id_t>
410  header_union_stack_ids_map{};
411  std::unordered_map<std::string, HeaderType *> header_to_type_map{};
412  std::unordered_map<std::string, HeaderType *> header_stack_to_type_map{};
413 
414  std::unordered_map<std::string, std::unique_ptr<HeaderType> >
415  header_types_map{};
416 
417  // tables
418  std::unordered_map<std::string, std::unique_ptr<MatchActionTable> >
419  match_action_tables_map{};
420 
421  std::unordered_map<std::string, std::unique_ptr<ActionProfile> >
422  action_profiles_map{};
423 
424  std::unordered_map<std::string, std::unique_ptr<Conditional> >
425  conditionals_map{};
426 
427  std::unordered_map<std::string, std::unique_ptr<ControlAction> >
428  control_actions_map{};
429 
430  std::unordered_map<std::string, ControlFlowNode *> control_nodes_map{};
431 
432  // pipelines
433  std::unordered_map<std::string, std::unique_ptr<Pipeline> > pipelines_map{};
434 
435  // actions
436  // TODO(antonin): make this a vector?
437  std::unordered_map<p4object_id_t, std::unique_ptr<ActionFn> > actions_map{};
438  using table_action_pair = std::pair<std::string, std::string>;
439  struct TableActionPairKeyHash {
440  std::size_t operator()(const table_action_pair& p) const {
441  std::size_t seed = 0;
442  boost::hash_combine(seed, p.first);
443  boost::hash_combine(seed, p.second);
444 
445  return seed;
446  }
447  };
448  std::unordered_map<table_action_pair, ActionFn *, TableActionPairKeyHash>
449  t_actions_map{};
450  using aprof_action_pair = table_action_pair;
451  using AprofActionPairKeyHash = TableActionPairKeyHash;
452  std::unordered_map<aprof_action_pair, ActionFn *, AprofActionPairKeyHash>
453  aprof_actions_map{};
454 
455  // parsers
456  std::unordered_map<std::string, std::unique_ptr<Parser> > parsers{};
457  // this is to give the objects a place where to live
458  std::vector<std::unique_ptr<ParseState> > parse_states{};
459  // this is to give ActionFn objects a place to live
460  std::vector<std::unique_ptr<ActionFn> > parse_methods{};
461  std::vector<std::unique_ptr<ActionFn> > deparse_methods{};
462 
463  // parse vsets
464  std::unordered_map<std::string, std::unique_ptr<ParseVSet> > parse_vsets{};
465 
466  ErrorCodeMap error_codes;
467 
468  EnumMap enums{};
469 
470  // checksums
471  std::vector<std::unique_ptr<Checksum> > checksums{};
472 
473  std::unordered_map<std::string, std::unique_ptr<Deparser> > deparsers{};
474 
475  std::unique_ptr<LearnEngineIface> learn_engine{};
476  // for now, used exclusively as a way to map list names to ids
477  class LearnList : public NamedP4Object {
478  public:
479  LearnList(const std::string &name, p4object_id_t id)
480  : NamedP4Object(name, id) { }
481  };
482  std::unordered_map<std::string, std::unique_ptr<LearnList> > learn_lists{};
483 
484  std::shared_ptr<TransportIface> notifications_transport{};
485 
486  std::unique_ptr<AgeingMonitorIface> ageing_monitor{};
487 
488  // meter arrays
489  std::unordered_map<std::string, std::unique_ptr<MeterArray> > meter_arrays{};
490 
491  // counter arrays
492  std::unordered_map<std::string, std::unique_ptr<CounterArray> >
493  counter_arrays{};
494 
495  // register arrays
496  std::unordered_map<std::string, std::unique_ptr<RegisterArray> >
497  register_arrays{};
498 
499  // calculations
500  std::unordered_map<std::string, std::unique_ptr<NamedCalculation> >
501  calculations{};
502 
503  // field lists
504  std::unordered_map<p4object_id_t, std::unique_ptr<FieldList> > field_lists{};
505 
506  // extern instances
507  std::unordered_map<std::string, std::unique_ptr<ExternType> >
508  extern_instances{};
509 
510  std::unordered_map<std::string, header_field_pair> field_aliases{};
511 
512  // used for initialization only
513  std::unordered_map<p4object_id_t, p4object_id_t> header_id_to_stack_id{};
514  struct HeaderUnionPos {
515  header_union_id_t union_id;
516  size_t offset; // the offset of the header in the union
517  };
518  std::unordered_map<p4object_id_t, HeaderUnionPos> header_id_to_union_pos{};
519  std::unordered_map<p4object_id_t, header_union_stack_id_t>
520  union_id_to_union_stack_id{};
521 
522  ConfigOptionMap config_options{};
523 
524  // maps primitive names to primitive instances
525  std::unordered_map<std::string, std::unique_ptr<ActionPrimitive_>>
526  primitives{};
527 
528  std::ostream &outstream;
529  bool verbose_output;
530 
531  private:
532  int get_field_offset(header_id_t header_id,
533  const std::string &field_name) const;
534  size_t get_field_bytes(header_id_t header_id, int field_offset) const;
535  size_t get_field_bits(header_id_t header_id, int field_offset) const;
536  size_t get_header_bits(header_id_t header_id) const;
537  std::tuple<header_id_t, int> field_info(const std::string &header_name,
538  const std::string &field_name) const;
539  bool check_required_fields(
540  const std::set<header_field_pair> &required_fields);
541 
542  std::unique_ptr<CalculationsMap::MyC> check_hash(
543  const std::string &name) const;
544 
545  void enable_arith(header_id_t header_id, int field_offset);
546  void enable_arith(header_id_t header_id);
547 
548  std::unique_ptr<Calculation> process_cfg_selector(
549  const Json::Value &cfg_selector) const;
550 };
551 
552 } // namespace bm
553 
554 #endif // BM_BM_SIM_P4OBJECTS_H_
field_lists.h
pipeline.h
extern.h
headers.h
learning.h
counters.h
stateful.h
deparser.h
meters.h
parser.h