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