OpenSDN source code
bgp_attr_base.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  * Copyright Contributors to the OpenSDN project
4  */
5 
6 #ifndef SRC_BGP_BGP_ATTR_BASE_H_
7 #define SRC_BGP_BGP_ATTR_BASE_H_
8 
9 #include <boost/functional/hash.hpp>
10 #include <boost/scoped_array.hpp>
11 
12 #include <set>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 #include <mutex>
17 
18 #include "base/parse_object.h"
19 #include "base/task.h"
20 
21 class BgpAttr;
22 
23 class BgpAttribute : public ParseObject {
24 public:
25  enum Flag {
26  Optional = 1 << 7,
27  Transitive = 1 << 6,
28  Partial = 1 << 5,
29  ExtendedLength = 1 << 4
30  };
31  enum Code {
32  Reserved = 0,
33  Origin = 1,
34  AsPath = 2,
35  NextHop = 3,
37  LocalPref = 5,
46  As4Path = 17,
48  PmsiTunnel = 22,
52  OriginVnPath = 243,
53  };
54  enum Subcode {
55  OList = 1,
57  SourceRd = 3,
58  Esi = 4,
59  Params = 5,
60  LeafOList = 6,
61  SubProtocol = 7
62  };
63 
64  BgpAttribute() : code(0), subcode(0), flags(0) { }
65  BgpAttribute(uint8_t code, uint8_t flags)
66  : code(code), subcode(0), flags(flags) { }
67  BgpAttribute(uint8_t code, uint8_t subcode, uint8_t flags)
68  : code(code), subcode(subcode), flags(flags) { }
69  static const uint8_t FLAG_MASK = Optional|Transitive;
70  uint8_t code;
71  uint8_t subcode;
72  uint8_t flags;
73  /*
74  * Variable length attributes should return the size of the attribute
75  * for encoding purposes in order to set the ExtendedLength flag.
76  */
77  virtual size_t EncodeLength() const;
78  /*
79  * Helper method to compute flags used when encoding attributes.
80  */
81  uint8_t GetEncodeFlags() const;
82 
83  virtual std::string ToString() const;
84  virtual int CompareTo(const BgpAttribute &rhs) const;
85  virtual void ToCanonical(BgpAttr *attr) { }
86 };
87 
88 //
89 // Canonical structure used to exchange a single NLRI prefix between the
90 // common parser and the address family specific BGP code.
91 //
92 // ReadLabel and WriteLabel need a label offset because the label is at
93 // different locations in different NLRI.
94 //
95 // The prefix length is in bits.
96 // The type is relevant only for NLRI that have multiple route types e.g.
97 // erm-vpn and e-vpn.
98 //
99 struct BgpProtoPrefix : public ParseObject {
100  static const size_t kLabelSize;
101 
102  BgpProtoPrefix();
103 
104  uint32_t ReadLabel(size_t label_offset, bool is_vni = false) const;
105  void WriteLabel(size_t label_offset, uint32_t label, bool is_vni = false);
106 
107  std::vector<uint8_t> prefix;
109  uint8_t type;
110 };
111 
112 //
113 // Base class to manage BGP Path Attributes database. This class provides
114 // thread safe access to the data base.
115 //
116 // Lock contention can be tuned by varying the hash table size passed to the
117 // constructor.
118 //
119 // Attribute contents must be hashable via hash_value() and hashed using
120 // boost::hash_combine() to partition the attribute database.
121 //
122 template <class Type, class TypePtr, class TypeSpec, typename TypeCompare,
123  class TypeDB>
125 public:
126  explicit BgpPathAttributeDB(int hash_size = GetHashSize())
127  : hash_size_(hash_size),
128  set_(new Set[hash_size]),
129  mutex_(new std::mutex[hash_size]) {
130  }
131 
132  size_t Size() {
133  size_t size = 0;
134 
135  for (size_t i = 0; i < hash_size_; i++) {
136  std::scoped_lock lock(mutex_[i]);
137  size += set_[i].size();
138  }
139  return size;
140  }
141 
142  void Delete(Type *attr) {
143  size_t hash = HashCompute(attr);
144 
145  std::scoped_lock lock(mutex_[hash]);
146  assert(set_[hash].erase(attr));
147  }
148 
149  // Locate passed in attribute in the data base based on the attr ptr.
150  TypePtr Locate(Type *attr) {
151  return LocateInternal(attr);
152  }
153 
154  // Locate passed in attribute in the data base, based on the attr spec.
155  TypePtr Locate(const TypeSpec &spec) {
156  Type *attr = new Type(static_cast<TypeDB *>(this), spec);
157  return LocateInternal(attr);
158  }
159 
160 private:
161  const size_t HashCompute(Type *attr) const {
162  if (hash_size_ <= 1) return 0;
163 
164  size_t hash = 0;
165  boost::hash_combine(hash, *attr);
166  return hash % hash_size_;
167  }
168 
169  static size_t GetHashSize() {
170  char *str = getenv("BGP_PATH_ATTRIBUTE_DB_HASH_SIZE");
171 
172  // Use just one bucket for now.
173  if (!str) return 1;
174  return strtoul(str, NULL, 0);
175  }
176 
177  // This template safely retrieves an attribute entry from its data base.
178  // If the entry is not found, it is inserted into the database.
179  //
180  // If the entry is already present, then passed in entry is freed and
181  // existing entry is returned.
182  TypePtr LocateInternal(Type *attr) {
183  // Hash attribute contents to to avoid potential mutex contention.
184  size_t hash = HashCompute(attr);
185  while (true) {
186  // Grab mutex to keep db access thread safe.
187  std::scoped_lock lock(mutex_[hash]);
188  std::pair<typename Set::iterator, bool> ret;
189 
190  // Try to insert the passed entry into the database.
191  ret = set_[hash].insert(attr);
192 
193  // Take a reference to prevent this entry from getting deleted.
194  // Counter is automatically incremented, hence we get thread safety
195  // here.
196  int prev = intrusive_ptr_add_ref(*ret.first);
197 
198  // Check if passed in entry did get into the data base.
199  if (ret.second) {
200  // Take intrusive pointer, thereby incrementing the refcount.
201  TypePtr ptr = TypePtr(*ret.first);
202 
203  // Release redundant refcount taken above to protect this entry
204  // from getting deleted, as we have now bumped up refcount above
205  intrusive_ptr_del_ref(*ret.first);
206  return ptr;
207  }
208 
209  // Make sure that this entry, though in the database is not
210  // undergoing deletion. This can happen because attribute intrusive
211  // pointer is released without taking the mutex.
212  //
213  // If the previous refcount is 0, it implies that this entry is
214  // about to get deleted (after we release the mutex). In such
215  // cases, we retry inserting the passed attribute pointer into the
216  // data base.
217  if (prev > 0) {
218  // Free passed in attribute, as it is already in the database.
219  delete attr;
220 
221  // Take intrusive pointer, thereby incrementing the refcount.
222  TypePtr ptr = TypePtr(*ret.first);
223 
224  // Release redundant refcount taken above to protect this entry
225  // from getting deleted, as we have now bumped up refcount above
226  intrusive_ptr_del_ref(*ret.first);
227  return ptr;
228  }
229 
230  // Decrement the counter bumped up above as we can't use this entry
231  // which is about to be deleted. Instead, retry inserting the passed
232  // entry again, into the database.
233  intrusive_ptr_del_ref(*ret.first);
234  }
235 
236  assert(false);
237  return NULL;
238  }
239 
240  typedef std::set<Type *, TypeCompare> Set;
241  size_t hash_size_;
242  boost::scoped_array<Set> set_;
243  boost::scoped_array<std::mutex> mutex_;
244 };
245 
246 #endif // SRC_BGP_BGP_ATTR_BASE_H_
int intrusive_ptr_del_ref(const AsPath *cpath)
Definition: bgp_aspath.h:152
int intrusive_ptr_add_ref(const AsPath *cpath)
Definition: bgp_aspath.h:148
virtual void ToCanonical(BgpAttr *attr)
Definition: bgp_attr_base.h:85
uint8_t subcode
Definition: bgp_attr_base.h:71
uint8_t flags
Definition: bgp_attr_base.h:72
BgpAttribute(uint8_t code, uint8_t subcode, uint8_t flags)
Definition: bgp_attr_base.h:67
virtual int CompareTo(const BgpAttribute &rhs) const
uint8_t GetEncodeFlags() const
static const uint8_t FLAG_MASK
Definition: bgp_attr_base.h:69
uint8_t code
Definition: bgp_attr_base.h:70
BgpAttribute(uint8_t code, uint8_t flags)
Definition: bgp_attr_base.h:65
virtual size_t EncodeLength() const
virtual std::string ToString() const
void Delete(Type *attr)
boost::scoped_array< std::mutex > mutex_
std::set< Type *, TypeCompare > Set
TypePtr Locate(Type *attr)
boost::scoped_array< Set > set_
static size_t GetHashSize()
TypePtr LocateInternal(Type *attr)
TypePtr Locate(const TypeSpec &spec)
BgpPathAttributeDB(int hash_size=GetHashSize())
const size_t HashCompute(Type *attr) const
void WriteLabel(size_t label_offset, uint32_t label, bool is_vni=false)
uint32_t ReadLabel(size_t label_offset, bool is_vni=false) const
static const size_t kLabelSize
std::vector< uint8_t > prefix