71 #ifndef BM_BM_SIM_ACTIONS_H_
72 #define BM_BM_SIM_ACTIONS_H_
80 #include <unordered_map>
88 #include "expressions.h"
98 class NamedCalculation;
103 class ActionPrimitive_;
108 class ActionOpcodesMap {
110 using ActionPrimitiveFactoryFn =
111 std::function<std::unique_ptr<ActionPrimitive_>()>;
112 static ActionOpcodesMap *get_instance();
113 bool register_primitive(
const char *name, ActionPrimitiveFactoryFn primitive);
115 std::unique_ptr<ActionPrimitive_> get_primitive(
const std::string &name);
123 std::unordered_map<std::string, ActionPrimitiveFactoryFn> map_{};
128 #define REGISTER_PRIMITIVE(primitive_name) \
129 bool primitive_name##_create_ = \
130 bm::ActionOpcodesMap::get_instance()->register_primitive( \
132 [](){ return std::unique_ptr<::bm::ActionPrimitive_>( \
133 new primitive_name()); })
138 #define REGISTER_PRIMITIVE_W_NAME(primitive_name, primitive) \
139 bool primitive##_create_ = \
140 bm::ActionOpcodesMap::get_instance()->register_primitive( \
142 [](){ return std::unique_ptr<::bm::ActionPrimitive_>( \
146 const Data &get(
int offset)
const {
return action_data[offset]; }
148 void push_back_action_data(
const Data &data) {
149 action_data.push_back(data);
152 void push_back_action_data(
unsigned int data) {
153 action_data.emplace_back(data);
156 void push_back_action_data(
const char *bytes,
int nbytes) {
157 action_data.emplace_back(bytes, nbytes);
160 size_t size()
const {
return action_data.size(); }
162 std::vector<Data> action_data{};
165 struct ActionEngineState;
176 enum {CONST, FIELD, HEADER, ACTION_DATA, REGISTER_REF, REGISTER_GEN,
177 HEADER_STACK, LAST_HEADER_STACK_FIELD,
179 METER_ARRAY, COUNTER_ARRAY, REGISTER_ARRAY,
180 EXPRESSION, EXPRESSION_HEADER, EXPRESSION_HEADER_STACK,
181 EXPRESSION_HEADER_UNION, EXPRESSION_HEADER_UNION_STACK,
184 HEADER_UNION, HEADER_UNION_STACK, PARAMS_VECTOR, FIELD_LIST} tag;
187 unsigned int const_offset;
196 unsigned int action_data_offset;
203 RegisterArray *array;
208 RegisterArray *array;
209 ArithExpression *idx;
212 header_stack_id_t header_stack;
228 header_stack_id_t header_stack;
233 const NamedCalculation *calculation;
236 MeterArray *meter_array;
239 CounterArray *counter_array;
242 RegisterArray *register_array;
252 ExternType *extern_instance;
256 const std::string *str;
258 header_union_stack_id_t header_union_stack;
260 header_union_id_t header_union;
264 template <
typename T> T to(ActionEngineState *state)
const;
267 struct ActionEngineState {
270 const ActionData &action_data;
271 const std::vector<Data> &const_values;
272 const std::vector<ActionParam> ¶meters_vector;
273 const std::vector<ActionParam> &field_list;
275 ActionEngineState(Packet *pkt,
276 const ActionData &action_data,
277 const std::vector<Data> &const_values,
278 const std::vector<ActionParam> ¶meters_vector,
279 const std::vector<ActionParam> &field_list);
287 Data &ActionParam::to<Data &>(ActionEngineState *state)
const {
288 static thread_local Data data_temp;
291 case ActionParam::FIELD:
292 return state->phv.get_field(field.header, field.field_offset);
293 case ActionParam::REGISTER_REF:
294 return register_ref.array->at(register_ref.idx);
295 case ActionParam::REGISTER_GEN:
296 register_gen.idx->eval_arith(state->phv, &data_temp,
297 state->action_data.action_data);
298 return register_ref.array->at(data_temp.get<
size_t>());
299 case ActionParam::EXPRESSION:
300 return expression.ptr->eval_arith_lvalue(&state->phv,
301 state->action_data.action_data);
302 case ActionParam::LAST_HEADER_STACK_FIELD:
303 return state->phv.get_header_stack(stack_field.header_stack).get_last()
304 .get_field(stack_field.field_offset);
306 _BM_UNREACHABLE(
"Default switch case should not be reachable");
311 const Data &ActionParam::to<const Data &>(ActionEngineState *state)
const {
314 static thread_local
unsigned int data_temps_size = 4;
315 static thread_local std::vector<Data> data_temps(data_temps_size);
318 case ActionParam::CONST:
319 return state->const_values[const_offset];
320 case ActionParam::FIELD:
321 return state->phv.get_field(field.header, field.field_offset);
322 case ActionParam::ACTION_DATA:
323 return state->action_data.get(action_data_offset);
324 case ActionParam::REGISTER_REF:
325 return register_ref.array->at(register_ref.idx);
326 case ActionParam::REGISTER_GEN:
327 register_gen.idx->eval_arith(state->phv, &data_temps[0],
328 state->action_data.action_data);
329 return register_ref.array->at(data_temps[0].get<size_t>());
330 case ActionParam::EXPRESSION:
331 while (data_temps_size <= expression.offset) {
332 data_temps.emplace_back();
335 expression.ptr->eval_arith(state->phv, &data_temps[expression.offset],
336 state->action_data.action_data);
337 return data_temps[expression.offset];
338 case ActionParam::LAST_HEADER_STACK_FIELD:
339 return state->phv.get_header_stack(stack_field.header_stack).get_last()
340 .get_field(stack_field.field_offset);
342 _BM_UNREACHABLE(
"Default switch case should not be reachable");
350 Field &ActionParam::to<Field &>(ActionEngineState *state)
const {
351 assert(tag == ActionParam::FIELD);
352 return state->phv.get_field(field.header, field.field_offset);
356 const Field &ActionParam::to<const Field &>(ActionEngineState *state)
const {
357 return ActionParam::to<Field &>(state);
361 Header &ActionParam::to<Header &>(ActionEngineState *state)
const {
363 case ActionParam::HEADER:
364 return state->phv.get_header(header);
365 case ActionParam::EXPRESSION_HEADER:
366 return expression.ptr->eval_header(&state->phv,
367 state->action_data.action_data);
369 _BM_UNREACHABLE(
"Default switch case should not be reachable");
374 const Header &ActionParam::to<const Header &>(ActionEngineState *state)
const {
375 return ActionParam::to<Header &>(state);
379 HeaderStack &ActionParam::to<HeaderStack &>(ActionEngineState *state)
const {
381 case ActionParam::HEADER_STACK:
382 return state->phv.get_header_stack(header_stack);
383 case ActionParam::EXPRESSION_HEADER_STACK:
384 return expression.ptr->eval_header_stack(&state->phv,
385 state->action_data.action_data);
387 _BM_UNREACHABLE(
"Default switch case should not be reachable");
392 const HeaderStack &ActionParam::to<const HeaderStack &>(
393 ActionEngineState *state)
const {
394 return ActionParam::to<HeaderStack &>(state);
398 StackIface &ActionParam::to<StackIface &>(ActionEngineState *state)
const {
401 return state->phv.get_header_stack(header_stack);
402 case ActionParam::EXPRESSION_HEADER_STACK:
403 return expression.ptr->eval_header_stack(
404 &state->phv, state->action_data.action_data);
405 case HEADER_UNION_STACK:
406 return state->phv.get_header_union_stack(header_union_stack);
407 case ActionParam::EXPRESSION_HEADER_UNION_STACK:
408 return expression.ptr->eval_header_union_stack(
409 &state->phv, state->action_data.action_data);
411 _BM_UNREACHABLE(
"Default switch case should not be reachable");
416 const StackIface &ActionParam::to<const StackIface &>(
417 ActionEngineState *state)
const {
418 return ActionParam::to<StackIface &>(state);
422 HeaderUnion &ActionParam::to<HeaderUnion &>(ActionEngineState *state)
const {
424 case ActionParam::HEADER_UNION:
425 return state->phv.get_header_union(header_union);
426 case ActionParam::EXPRESSION_HEADER_UNION:
427 return expression.ptr->eval_header_union(&state->phv,
428 state->action_data.action_data);
430 _BM_UNREACHABLE(
"Default switch case should not be reachable");
435 const HeaderUnion &ActionParam::to<const HeaderUnion &>(
436 ActionEngineState *state)
const {
437 return ActionParam::to<HeaderUnion &>(state);
442 ActionEngineState *state)
const {
444 case ActionParam::HEADER_UNION_STACK:
445 return state->phv.get_header_union_stack(header_union_stack);
446 case ActionParam::EXPRESSION_HEADER_UNION_STACK:
447 return expression.ptr->eval_header_union_stack(
448 &state->phv, state->action_data.action_data);
450 _BM_UNREACHABLE(
"Default switch case should not be reachable");
456 ActionEngineState *state)
const {
457 return ActionParam::to<HeaderUnionStack &>(state);
461 const NamedCalculation &ActionParam::to<const NamedCalculation &>(
462 ActionEngineState *state)
const {
464 assert(tag == ActionParam::CALCULATION);
465 return *(calculation);
469 MeterArray &ActionParam::to<MeterArray &>(ActionEngineState *state)
const {
471 assert(tag == ActionParam::METER_ARRAY);
472 return *(meter_array);
476 const MeterArray &ActionParam::to<const MeterArray &>(
477 ActionEngineState *state)
const {
478 return ActionParam::to<MeterArray &>(state);
482 CounterArray &ActionParam::to<CounterArray &>(ActionEngineState *state)
const {
484 assert(tag == ActionParam::COUNTER_ARRAY);
485 return *(counter_array);
489 const CounterArray &ActionParam::to<const CounterArray &>(
490 ActionEngineState *state)
const {
491 return ActionParam::to<CounterArray &>(state);
495 RegisterArray &ActionParam::to<RegisterArray &>(
496 ActionEngineState *state)
const {
498 assert(tag == ActionParam::REGISTER_ARRAY);
499 return *(register_array);
503 const RegisterArray &ActionParam::to<const RegisterArray &>(
504 ActionEngineState *state)
const {
505 return ActionParam::to<RegisterArray &>(state);
509 ExternType *ActionParam::to<ExternType *>(ActionEngineState *state)
const {
511 assert(tag == ActionParam::EXTERN_INSTANCE);
512 return extern_instance;
516 const std::string &ActionParam::to<const std::string &>(
517 ActionEngineState *state)
const {
518 assert(tag == ActionParam::STRING);
526 const char *ActionParam::to<const char *>(ActionEngineState *state)
const {
527 assert(tag == ActionParam::STRING);
539 const std::vector<Data>
540 ActionParam::to<const std::vector<Data>>(ActionEngineState *state)
const {
541 _BM_ASSERT(tag == ActionParam::PARAMS_VECTOR &&
"not a params vector");
542 std::vector<Data> vec;
544 for (
auto i = params_vector.start ; i < params_vector.end ; i++) {
549 vec.push_back(state->parameters_vector[i].to<
const Data &>(state));
556 const std::vector<Field>
557 ActionParam::to<const std::vector<Field>>(ActionEngineState *state)
const {
558 _BM_ASSERT(tag == ActionParam::FIELD_LIST &&
"not a field list");
559 std::vector<Field> vec;
561 for (
auto i = field_list.start ; i < field_list.end ; i++) {
566 vec.push_back(state->field_list[i].to<
const Field &>(state));
576 template <std::size_t... Indices>
578 using next = indices<Indices...,
sizeof...(Indices)>;
581 template <std::
size_t N>
582 struct build_indices {
583 using type =
typename build_indices<N-1>::type::next;
587 struct build_indices<0> {
588 using type = indices<>;
591 template <std::
size_t N>
592 using BuildIndices =
typename build_indices<N>::type;
594 template <
typename... Args>
595 struct unpack_caller {
597 template <
typename T,
size_t... I>
598 void call(T *pObj, ActionEngineState *state,
599 const ActionParam *args,
600 const indices<I...>) {
603 (void) state; (void) args;
604 #define ELEM_TYPE typename std::tuple_element<I, std::tuple<Args...>>::type
605 (*pObj)(args[I].to<ELEM_TYPE>(state)...);
610 template <
typename T>
611 void operator () (T* pObj, ActionEngineState *state,
612 const ActionParam *args){
614 call(pObj, state, args, BuildIndices<
sizeof...(Args)>{});
618 class ActionPrimitive_ {
620 virtual ~ActionPrimitive_() { }
622 virtual void execute(
623 ActionEngineState *state,
624 const ActionParam *args) = 0;
626 virtual size_t get_num_params()
const = 0;
628 virtual size_t get_jump_offset(
size_t current_offset)
const {
629 return current_offset + 1;
632 void _set_p4objects(P4Objects *p4objects) {
633 this->p4objects = p4objects;
636 void set_source_info(SourceInfo *source_info) {
637 call_source_info = source_info;
646 static thread_local Packet *pkt;
647 static thread_local PHV *phv;
648 static thread_local SourceInfo *call_source_info;
650 P4Objects *get_p4objects() {
655 P4Objects *p4objects{
nullptr};
661 template <
typename... Args>
664 void execute(ActionEngineState *state,
const ActionParam *args)
override {
667 caller(
this, state, args);
671 size_t get_num_params()
const override {
return sizeof...(Args); }
673 virtual void operator ()(Args...) = 0;
679 return phv->get_field(name);
684 return phv->get_header(name);
700 unpack_caller<Args...> caller;
710 class ActionPrimitiveCall {
712 explicit ActionPrimitiveCall(
713 ActionPrimitive_ *primitive,
size_t param_offset,
714 std::unique_ptr<SourceInfo> source_info =
nullptr);
716 void execute(ActionEngineState *state,
const ActionParam *args)
const;
718 size_t get_num_params()
const;
720 size_t get_param_offset()
const {
return param_offset; }
722 size_t get_jump_offset(
size_t current_offset)
const {
723 return primitive->get_jump_offset(current_offset);
726 SourceInfo *get_source_info()
const {
return source_info.get(); }
729 ActionPrimitive_ *primitive;
731 std::unique_ptr<SourceInfo> source_info;
734 class ActionFn :
public NamedP4Object {
735 friend class ActionFnEntry;
738 ActionFn(
const std::string &name, p4object_id_t
id,
size_t num_params);
740 ActionFn(
const std::string &name, p4object_id_t
id,
size_t num_params,
741 std::unique_ptr<SourceInfo> source_info);
746 void parameter_push_back_field(header_id_t header,
int field_offset);
747 void parameter_push_back_header(header_id_t header);
748 void parameter_push_back_header_stack(header_stack_id_t header_stack);
749 void parameter_push_back_last_header_stack_field(
750 header_stack_id_t header_stack,
int field_offset);
751 void parameter_push_back_header_union(header_union_id_t header_union);
752 void parameter_push_back_header_union_stack(
753 header_union_stack_id_t header_union_stack);
754 void parameter_push_back_const(
const Data &data);
755 void parameter_push_back_action_data(
int action_data_offset);
756 void parameter_push_back_register_ref(RegisterArray *register_array,
758 void parameter_push_back_register_gen(RegisterArray *register_array,
759 std::unique_ptr<ArithExpression> idx);
760 void parameter_push_back_calculation(
const NamedCalculation *calculation);
761 void parameter_push_back_meter_array(MeterArray *meter_array);
762 void parameter_push_back_counter_array(CounterArray *counter_array);
763 void parameter_push_back_register_array(RegisterArray *register_array);
764 void parameter_push_back_expression(std::unique_ptr<Expression> expr);
765 void parameter_push_back_expression(std::unique_ptr<Expression> expr,
767 void parameter_push_back_extern_instance(ExternType *extern_instance);
768 void parameter_push_back_string(
const std::string &str);
776 void parameter_start_vector();
777 void parameter_end_vector();
778 void parameter_start_field_list();
779 void parameter_end_field_list();
781 void push_back_primitive(ActionPrimitive_ *primitive,
782 std::unique_ptr<SourceInfo> source_info =
nullptr);
784 void grab_register_accesses(RegisterSync *register_sync)
const;
786 size_t get_num_params()
const;
789 using ParameterList = std::vector<ActionParam>;
791 std::vector<ActionPrimitiveCall> primitives{};
792 ParameterList params{};
793 ParameterList sub_params{};
794 RegisterSync register_sync{};
795 std::vector<Data> const_values{};
797 std::vector<std::unique_ptr<Expression> > expressions{};
798 std::vector<std::string> strings{};
802 static size_t nb_data_tmps;
805 class ActionFnEntry {
809 ActionFnEntry(
const ActionFn *action_fn, ActionData action_data)
810 : action_fn(action_fn), action_data(std::move(action_data)) { }
812 explicit ActionFnEntry(
const ActionFn *action_fn)
813 : action_fn(action_fn) { }
816 void operator()(Packet *pkt)
const;
818 void execute(Packet *pkt)
const;
820 void push_back_action_data(
const Data &data);
822 void push_back_action_data(
unsigned int data);
824 void push_back_action_data(
const char *bytes,
int nbytes);
826 size_t action_data_size()
const {
return action_data.size(); }
828 const Data &get_action_data_at(
int offset)
const {
829 return action_data.get(offset);
832 const ActionData &get_action_data()
const {
836 void dump(std::ostream *stream)
const;
838 void serialize(std::ostream *out)
const;
839 void deserialize(std::istream *in,
const P4Objects &objs);
841 p4object_id_t get_action_id()
const {
842 if (!action_fn)
return std::numeric_limits<p4object_id_t>::max();
843 return action_fn->get_id();
846 const ActionFn *get_action_fn()
const {
850 ActionFnEntry(
const ActionFnEntry &other) =
default;
851 ActionFnEntry &operator=(
const ActionFnEntry &other) =
default;
854 ActionFnEntry(ActionFnEntry &&other) =
default;
856 ActionFnEntry &operator=(ActionFnEntry &&other) =
default;
859 const ActionFn *action_fn{
nullptr};
860 ActionData action_data{};
865 #endif // BM_BM_SIM_ACTIONS_H_