bmv2
Designing your own switch target with bmv2
action_profile.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_ACTION_PROFILE_H_
22 #define BM_BM_SIM_ACTION_PROFILE_H_
23 
24 #include <iosfwd>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 // shared_mutex will only be available in C++-14, so for now I'm using boost
31 #include <boost/thread/shared_mutex.hpp>
32 
33 #include "action_entry.h"
34 #include "calculations.h"
35 #include "handle_mgr.h"
36 #include "match_error_codes.h"
37 #include "ras.h"
38 
39 namespace bm {
40 
41 class ActionProfile : public NamedP4Object {
42  friend class MatchTableIndirect;
43  friend class MatchTableIndirectWS;
44 
45  public:
46  using mbr_hdl_t = uint32_t;
47  using grp_hdl_t = uint32_t;
48 
49  using hash_t = unsigned int;
50 
51  class IndirectIndex {
52  public:
53  IndirectIndex() { }
54 
55  bool is_mbr() const { return ((index >> 24) == _mbr); }
56  bool is_grp() const { return ((index >> 24) == _grp); }
57  unsigned int get() const { return (index & _index_mask); }
58  unsigned int get_mbr() const { assert(is_mbr()); return get(); }
59  unsigned int get_grp() const { assert(is_grp()); return get(); }
60 
61  void dump(std::ostream *stream) const {
62  if (is_grp())
63  (*stream) << "group(" << get() << ")";
64  else
65  (*stream) << "member(" << get() << ")";
66  }
67 
68  friend std::ostream& operator<<(std::ostream &out, const IndirectIndex &i) {
69  i.dump(&out);
70  return out;
71  }
72 
73  void serialize(std::ostream *out) const;
74  void deserialize(std::istream *in, const P4Objects &objs);
75 
76  static IndirectIndex make_mbr_index(unsigned int index) {
77  assert(index <= _index_mask);
78  return IndirectIndex((_mbr << 24) | index);
79  }
80 
81  static IndirectIndex make_grp_index(unsigned int index) {
82  assert(index <= _index_mask);
83  return IndirectIndex((_grp << 24) | index);
84  }
85 
86  private:
87  explicit IndirectIndex(unsigned int index) : index(index) { }
88 
89  static const unsigned char _mbr = 0x00;
90  static const unsigned char _grp = 0x01;
91  static const unsigned int _index_mask = 0x00FFFFFF;
92 
93  unsigned int index{0};
94  };
95 
96  struct Member {
97  mbr_hdl_t mbr;
98  const ActionFn *action_fn;
99  ActionData action_data;
100  };
101 
102  struct Group {
103  grp_hdl_t grp;
104  std::vector<mbr_hdl_t> mbr_handles;
105  };
106 
107  class GroupSelectionIface {
108  public:
109  virtual ~GroupSelectionIface() { }
110 
111  virtual void add_member_to_group(grp_hdl_t grp, mbr_hdl_t mbr) = 0;
112  virtual void remove_member_from_group(grp_hdl_t grp, mbr_hdl_t mbr) = 0;
113  virtual mbr_hdl_t get_from_hash(grp_hdl_t grp, hash_t h) const = 0;
114  virtual void reset() = 0;
115  };
116 
117  ActionProfile(const std::string &name, p4object_id_t id, bool with_selection);
118 
119  bool has_selection() const;
120 
121  void set_hash(std::unique_ptr<Calculation> h) {
122  hash = std::move(h);
123  }
124 
125  // give the target some control over the member selection process
126  void set_group_selector(std::shared_ptr<GroupSelectionIface> selector);
127 
128  // runtime interface
129 
130  MatchErrorCode add_member(const ActionFn *action_fn,
131  ActionData action_data, // move it
132  mbr_hdl_t *mbr);
133 
134  MatchErrorCode delete_member(mbr_hdl_t mbr);
135 
136  MatchErrorCode modify_member(mbr_hdl_t mbr,
137  const ActionFn *action_fn,
138  ActionData action_data);
139 
140  MatchErrorCode create_group(grp_hdl_t *grp);
141 
142  MatchErrorCode delete_group(grp_hdl_t grp);
143 
144  MatchErrorCode add_member_to_group(mbr_hdl_t mbr, grp_hdl_t grp);
145 
146  MatchErrorCode remove_member_from_group(mbr_hdl_t mbr, grp_hdl_t grp);
147 
148  // end of runtime interface
149 
150  MatchErrorCode get_member(mbr_hdl_t mbr, Member *member) const;
151 
152  std::vector<Member> get_members() const;
153 
154  MatchErrorCode get_group(grp_hdl_t grp, Group *group) const;
155 
156  std::vector<Group> get_groups() const;
157 
158  size_t get_num_members() const;
159  size_t get_num_groups() const;
160 
161  MatchErrorCode get_num_members_in_group(grp_hdl_t grp, size_t *nb) const;
162 
163  void reset_state();
164 
165  void serialize(std::ostream *out) const;
166  void deserialize(std::istream *in, const P4Objects &objs);
167 
168  private:
169  using ReadLock = boost::shared_lock<boost::shared_mutex>;
170  using WriteLock = boost::unique_lock<boost::shared_mutex>;
171 
172  class IndirectIndexRefCount {
173  public:
174  using count_t = unsigned int;
175 
176  public:
177  void set(const IndirectIndex &index, count_t value) {
178  unsigned int i = index.get();
179  auto &v = (index.is_mbr()) ? mbr_count : grp_count;
180  assert(i <= v.size());
181  if (i == v.size())
182  v.push_back(value);
183  else
184  v[i] = value;
185  }
186 
187  count_t get(const IndirectIndex &index) const {
188  unsigned int i = index.get();
189  return (index.is_mbr()) ? mbr_count[i] : grp_count[i];
190  }
191 
192  void increase(const IndirectIndex &index) {
193  unsigned int i = index.get();
194  if (index.is_mbr())
195  mbr_count[i]++;
196  else
197  grp_count[i]++;
198  }
199 
200  void decrease(const IndirectIndex &index) {
201  unsigned int i = index.get();
202  if (index.is_mbr())
203  mbr_count[i]--;
204  else
205  grp_count[i]--;
206  }
207 
208  void serialize(std::ostream *out) const;
209  void deserialize(std::istream *in);
210 
211  private:
212  std::vector<count_t> mbr_count{};
213  std::vector<count_t> grp_count{};
214  };
215 
216  class GroupInfo {
217  public:
218  using iterator = RandAccessUIntSet::iterator;
219  using const_iterator = RandAccessUIntSet::const_iterator;
220 
221  MatchErrorCode add_member(mbr_hdl_t mbr);
222  MatchErrorCode delete_member(mbr_hdl_t mbr);
223  bool contains_member(mbr_hdl_t mbr) const;
224  size_t size() const;
225  mbr_hdl_t get_nth(size_t n) const;
226 
227  // iterators
228  iterator begin() { return mbrs.begin(); }
229  const_iterator begin() const { return mbrs.begin(); }
230  iterator end() { return mbrs.end(); }
231  const_iterator end() const { return mbrs.end(); }
232 
233  void serialize(std::ostream *out) const;
234  void deserialize(std::istream *in);
235 
236  private:
237  RandAccessUIntSet mbrs{};
238  };
239 
240  class GroupMgr : public GroupSelectionIface {
241  public:
242  void add_member_to_group(grp_hdl_t grp, mbr_hdl_t mbr) override;
243  void remove_member_from_group(grp_hdl_t grp, mbr_hdl_t mbr) override;
244 
245  mbr_hdl_t get_from_hash(grp_hdl_t grp, hash_t h) const override;
246 
247  void reset() override;
248 
249  void insert_group(grp_hdl_t grp);
250 
251  size_t group_size(grp_hdl_t grp) const;
252 
253  GroupInfo &at(grp_hdl_t grp);
254  const GroupInfo &at(grp_hdl_t grp) const;
255 
256  void clear();
257 
258  private:
259  std::vector<GroupInfo> groups{};
260  };
261 
262  private:
263  mbr_hdl_t choose_from_group(grp_hdl_t grp, const Packet &pkt) const;
264 
265  MatchErrorCode get_member_(mbr_hdl_t handle, Member *member) const;
266 
267  MatchErrorCode get_group_(grp_hdl_t grp, Group *group) const;
268 
269  void entries_insert(mbr_hdl_t mbr, ActionEntry &&entry);
270 
271  // lock can be acquired by MatchTableIndirect
272  ReadLock lock_read() const { return ReadLock(t_mutex); }
273  WriteLock lock_write() const { return WriteLock(t_mutex); }
274 
275  // this method is called by MatchTableIndirect and assumes that the provided
276  // index is correct
277  void dump_entry(std::ostream *out, const IndirectIndex &index) const;
278 
279  // called by MatchTableIndirect for reference counting (a member cannot be
280  // deleted if match entries are pointing to it)
281  void ref_count_increase(const IndirectIndex &index);
282  void ref_count_decrease(const IndirectIndex &index);
283 
284  bool is_valid_mbr(mbr_hdl_t mbr) const {
285  return mbr_handles.valid_handle(mbr);
286  }
287 
288  bool is_valid_grp(grp_hdl_t grp) const {
289  return grp_handles.valid_handle(grp);
290  }
291 
292  bool group_is_empty(grp_hdl_t grp) const;
293 
294  const ActionEntry &lookup(const Packet &pkt,
295  const IndirectIndex &index) const;
296 
297  private:
298  mutable boost::shared_mutex t_mutex{};
299  bool with_selection;
300  std::vector<ActionEntry> action_entries{};
301  IndirectIndexRefCount index_ref_count{};
302  HandleMgr mbr_handles{};
303  HandleMgr grp_handles{};
304  size_t num_members{0};
305  size_t num_groups{0};
306  GroupMgr grp_mgr{};
307  std::shared_ptr<GroupSelectionIface> grp_selector_{nullptr};
308  GroupSelectionIface *grp_selector{&grp_mgr};
309  std::unique_ptr<Calculation> hash{nullptr};
310 };
311 
312 } // namespace bm
313 
314 #endif // BM_BM_SIM_ACTION_PROFILE_H_
calculations.h