bmv2
Designing your own switch target with bmv2
Loading...
Searching...
No Matches
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
35namespace bm {
36
37class P4Objects;
38class ExternType;
39
40class 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
128class 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_