bmv2
Designing your own switch target with bmv2
extern.h
Go to the documentation of this file.
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 
22 
23 #ifndef BM_BM_SIM_EXTERN_H_
24 #define BM_BM_SIM_EXTERN_H_
25 
26 #include <unordered_map>
27 #include <string>
28 #include <memory>
29 #include <type_traits>
30 #include <mutex>
31 
32 #include "actions.h"
33 #include "named_p4object.h"
34 
35 namespace bm {
36 
37 class P4Objects;
38 class ExternType;
39 
40 class ExternFactoryMap {
41  public:
42  using ExternFactoryFn = std::function<std::unique_ptr<ExternType>()>;
43 
44  static ExternFactoryMap *get_instance();
45 
46  int register_extern_type(const char *extern_type_name, ExternFactoryFn fn);
47 
48  std::unique_ptr<ExternType> get_extern_instance(
49  const std::string &extern_type_name) const;
50 
51  private:
52  std::unordered_map<std::string, ExternFactoryFn> factory_map{};
53 };
54 
55 #define _BM_EXTERN_TO_STRING(name) #name
56 
57 #define BM_EXTERN_ADD_EXTERN_PREFIX(name) __extern_##name
58 
59 #define BM_REGISTER_EXTERN_W_NAME(extern_name, extern__) \
60  static_assert(std::is_default_constructible<extern__>::value, \
61  "User-defined extern type " #extern__ \
62  " needs to be default-constructible"); \
63  int _extern_##extern_name##_create_ = \
64  ::bm::ExternFactoryMap::get_instance()->register_extern_type( \
65  #extern_name, \
66  [](){ return std::unique_ptr<::bm::ExternType>(new extern__()); });
67 
68 #define BM_REGISTER_EXTERN(extern_name) \
69  BM_REGISTER_EXTERN_W_NAME(extern_name, extern_name)
70 
71 #define BM_REGISTER_EXTERN_W_NAME_METHOD(extern_name, extern__, \
72  extern_method_name, ...) \
73  template <typename... Args> \
74  struct _##extern_name##_##extern_method_name##_0 \
75  : public ::bm::ActionPrimitive<::bm::ExternType *, Args...> { \
76  void operator ()(::bm::ExternType *instance, Args... args) override { \
77  auto lock = instance->_unique_lock(); \
78  instance->_set_packet_ptr(&this->get_packet()); \
79  dynamic_cast<extern__ *>(instance)->extern_method_name(args...); \
80  } \
81  }; \
82  struct _##extern_name##_##extern_method_name \
83  : public _##extern_name##_##extern_method_name##_0<__VA_ARGS__> {}; \
84  REGISTER_PRIMITIVE_W_NAME( \
85  _BM_EXTERN_TO_STRING(_##extern_name##_##extern_method_name), \
86  _##extern_name##_##extern_method_name)
87 
88 #define BM_REGISTER_EXTERN_METHOD(extern_name, extern_method_name, ...) \
89  template <typename... Args> \
90  struct _##extern_name##_##extern_method_name##_0 \
91  : public ::bm::ActionPrimitive<::bm::ExternType *, Args...> { \
92  void operator ()(::bm::ExternType *instance, Args... args) override { \
93  auto lock = instance->_unique_lock(); \
94  instance->_set_packet_ptr(&this->get_packet()); \
95  dynamic_cast<extern_name *>(instance)->extern_method_name(args...); \
96  } \
97  }; \
98  struct _##extern_name##_##extern_method_name \
99  : public _##extern_name##_##extern_method_name##_0<__VA_ARGS__> {}; \
100  REGISTER_PRIMITIVE(_##extern_name##_##extern_method_name)
101 
102 #define BM_REGISTER_EXTERN_FUNCTION_W_NAME(extern_function_name, \
103  __extern_func, ...) \
104  template <typename... Args> \
105  struct __extern_##__extern_func##_0 \
106  : public ::bm::ActionPrimitive<Args...> { \
107  void operator ()(Args... args) override { \
108  __extern_func(args...); \
109  } \
110  }; \
111  struct __extern_##__extern_func \
112  : public __extern_##__extern_func##_0<__VA_ARGS__> {}; \
113  REGISTER_PRIMITIVE_W_NAME(_BM_EXTERN_TO_STRING(extern_function_name), \
114  __extern_##__extern_func)
115 
116 #define BM_REGISTER_EXTERN_FUNCTION(extern_function_name, ...) \
117  BM_REGISTER_EXTERN_FUNCTION_W_NAME(extern_function_name, \
118  extern_function_name, __VA_ARGS__)
119 
120 #define BM_EXTERN_ATTRIBUTES void _register_attributes() override
121 
122 #define BM_EXTERN_ATTRIBUTE_ADD(attr_name) \
123  _add_attribute(#attr_name, static_cast<void *>(&attr_name));
124 
125 
126 // TODO(Antonin): have it inherit from NamedP4Object? It is a bit tricky because
127 // extern types need to be default constructible
128 class ExternType {
129  public:
130  virtual ~ExternType() { }
131 
132  // needs to be called before init() when setting up the extern instance, in
133  // case init's implementation relies on p4objects (e.g. to resolve names to
134  // objects, such as register arrays)
135  void _set_p4objects(P4Objects *p4objects);
136 
137  template <typename T>
138  void _set_attribute(const std::string &attr_name, const T &v) {
139  T *attr = static_cast<T *>(attributes.at(attr_name));
140  *attr = v;
141  }
142 
143  bool _has_attribute(const std::string &attr_name) const {
144  return attributes.find(attr_name) != attributes.end();
145  }
146 
147  void _set_packet_ptr(Packet *pkt_ptr) { pkt = pkt_ptr; }
148 
149  // called in P4Objects after constructing the instance
150  void _set_name_and_id(const std::string &name, p4object_id_t id);
151 
152  const std::string &get_name() const { return name; }
153  p4object_id_t get_id() const { return id; }
154 
155  using UniqueLock = std::unique_lock<std::mutex>;
156  UniqueLock _unique_lock() { return UniqueLock(mutex); }
157 
158  virtual void _register_attributes() = 0;
159 
160  virtual void init() { }
161 
162  protected:
163  void _add_attribute(const std::string &name, void *ptr) {
164  attributes[name] = ptr;
165  }
166 
167  Packet &get_packet() const { return *pkt; }
168 
169  P4Objects &get_p4objects() const { return *p4objects; }
170 
171  private:
172  // will use static_cast to cast from T * to void * and vice-versa
173  std::unordered_map<std::string, void *> attributes;
174  mutable std::mutex mutex{};
175  Packet *pkt{nullptr};
176  // set by _set_name_and_id
177  std::string name{};
178  p4object_id_t id{};
179  // while we improve the extern support in bmv2, it is useful to expose this to
180  // extern implementations, to give them maximum flexibility
181  // non-owning pointer, as ExternType instances themselves are owned by the
182  // P4Object instance
183  P4Objects *p4objects{nullptr};
184 };
185 
186 } // namespace bm
187 
188 #endif // BM_BM_SIM_EXTERN_H_
named_p4object.h
actions.h