libbgp  0.6
A C++ BGP Library.
bgp-rib4.cc
Go to the documentation of this file.
1 
11 #include "bgp-rib4.h"
12 #include <arpa/inet.h>
13 #define MAKE_ENTRY4(r, e) std::make_pair(BgpRib4EntryKey(r), e)
14 
15 namespace libbgp {
16 
17 BgpRib4Entry::BgpRib4Entry() {
18  src_router_id = 0;
19 }
20 
28 BgpRib4Entry::BgpRib4Entry(Prefix4 r, uint32_t src, const std::vector<std::shared_ptr<BgpPathAttrib>> as) : route(r) {
30  attribs = as;
31 }
32 
39 uint32_t BgpRib4Entry::getNexthop() const {
40  for (const std::shared_ptr<BgpPathAttrib> &attr : attribs) {
41  if (attr->type_code == NEXT_HOP) {
42  const BgpPathAttribNexthop &nh = dynamic_cast<const BgpPathAttribNexthop &>(*attr);
43  return nh.next_hop;
44  }
45  }
46 
47  throw "no_nexthop";
48 }
49 
56  this->logger = logger;
57  update_id = 0;
58 }
59 
60 rib4_t::iterator BgpRib4::find_best (const Prefix4 &prefix) {
61  std::pair<rib4_t::iterator, rib4_t::iterator> its =
62  rib.equal_range(BgpRib4EntryKey(prefix));
63 
64  rib4_t::iterator best = rib.end();
65  if (its.first == rib.end()) return rib.end();
66 
67  for (rib4_t::iterator it = its.first; it != its.second; it++) {
68  if (it->second.route == prefix) {
69  if (best == rib.end()) best = it;
70  else {
71  const BgpRib4Entry *best_ptr = selectEntry(&(best->second), &(it->second));
72  best = best_ptr == &(best->second) ? best : it;
73  }
74  }
75  }
76 
77  return best;
78 }
79 
80 rib4_t::iterator BgpRib4::find_entry (const Prefix4 &prefix, uint32_t src) {
81  std::pair<rib4_t::iterator, rib4_t::iterator> its =
82  rib.equal_range(BgpRib4EntryKey(prefix));
83 
84  if (its.first == rib.end()) return rib.end();
85 
86  for (rib4_t::iterator it = its.first; it != its.second; it++) {
87  if (it->second.route == prefix && it->second.src_router_id == src) {
88  return it;
89  }
90  }
91 
92  return rib.end();
93 }
94 
113 std::pair<const BgpRib4Entry*, bool> BgpRib4::insertPriv(uint32_t src_router_id, const Prefix4 &route, const std::vector<std::shared_ptr<BgpPathAttrib>> &attrib, int32_t weight, uint32_t ibgp_asn) {
114  std::lock_guard<std::recursive_mutex> lock(mutex);
115 
116  /* construct the new entry object */
117  BgpRib4Entry new_entry(route, src_router_id, attrib);
118  new_entry.update_id = update_id;
119  new_entry.weight = weight;
120  new_entry.src = ibgp_asn > 0 ? SRC_IBGP : SRC_EBGP;
121  new_entry.ibgp_peer_asn = ibgp_asn;
122 
123  // for logging
124  const char *op = "new_entry";
125  const char *act = "new_best";
126 
127  std::pair<rib4_t::iterator, rib4_t::iterator> entries =
128  rib.equal_range(BgpRib4EntryKey(route));
129 
130  bool newly_inserted_is_best = false;
131  bool best_changed = false;
132  bool old_exist = entries.first != rib.end();
133  BgpRib4Entry *new_best = NULL;
134 
135  // older route exist
136  if (old_exist) {
137  // find old best & route to replace
138  rib4_t::const_iterator to_replace = rib.end();
139  BgpRib4Entry *old_best = NULL;
140  for (rib4_t::iterator it = entries.first; it != entries.second; it++) {
141  if (it->second.route != route) continue;
142  if (it->second.src_router_id == src_router_id) {
143  to_replace = it;
144  continue;
145  }
146  old_best = selectEntry(old_best, &(it->second));
147  //if (it->second.status == RS_ACTIVE) old_best = &(it->second);
148  }
149 
150  const BgpRib4Entry *candidate = selectEntry(&new_entry, old_best);
151  if (candidate == old_best) {
152  new_entry.status = RS_STANDBY;
153  act = "not_new_best";
154  } else {
155  if (old_best != NULL) old_best->status = RS_STANDBY;
156  best_changed = true;
157  }
158 
159  if (to_replace != rib.end()) {
160  const BgpRib4Entry *candidate = selectEntry(&(to_replace->second), old_best);
161  if (candidate == &(to_replace->second)) {
162  // the replaced route was the best route, now it is removed
163  act = "new_best";
164  best_changed = true;
165  }
166  // we need to replace a route
167  op = "update";
168  rib.erase(to_replace);
169  }
170 
171  rib4_t::iterator inserted = rib.insert(MAKE_ENTRY4(route, new_entry));
172 
173  if (best_changed) {
174  newly_inserted_is_best = candidate == &new_entry;
175  new_best = newly_inserted_is_best ? &(inserted->second) : old_best;
176  }
177 
178  } else { // no older route, new one is best
179  best_changed = newly_inserted_is_best = true;
180  rib4_t::iterator inserted = rib.insert(MAKE_ENTRY4(route, new_entry));
181  new_best = &(inserted->second);
182  }
183 
184  if (new_best != NULL) new_best->status = RS_ACTIVE;
185 
186  LIBBGP_LOG(logger, DEBUG) {
187  uint32_t prefix = route.getPrefix();
188  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET_ADDRSTRLEN];
189  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
190  inet_ntop(AF_INET, &prefix, prefix_str, INET_ADDRSTRLEN);
191  logger->log(DEBUG, "BgpRib4::insertPriv: (%s/%s) group %d, scope %s, route %s/%d\n", op, act, new_entry.update_id, src_router_id_str, prefix_str, route.getLength());
192  }
193 
194  return std::make_pair(new_best, newly_inserted_is_best);
195 }
196 
218 const BgpRib4Entry* BgpRib4::insert(BgpLogHandler *logger, const Prefix4 &route, uint32_t nexthop, int32_t weight) {
219  std::vector<std::shared_ptr<BgpPathAttrib>> attribs;
220  BgpPathAttribOrigin *origin = new BgpPathAttribOrigin(logger);
221  BgpPathAttribNexthop *nexhop_attr = new BgpPathAttribNexthop(logger);
222  BgpPathAttribAsPath *as_path = new BgpPathAttribAsPath(logger, true);
223  nexhop_attr->next_hop = nexthop;
224  origin->origin = IGP;
225 
226  attribs.push_back(std::shared_ptr<BgpPathAttrib>(origin));
227  attribs.push_back(std::shared_ptr<BgpPathAttrib>(nexhop_attr));
228  attribs.push_back(std::shared_ptr<BgpPathAttrib>(as_path));
229 
230  uint64_t use_update_id = update_id;
231 
232  for (const auto &entry : rib) {
233  if (entry.second.src_router_id == 0 && entry.second.route == route) {
234  this->logger->log(ERROR, "BgpRib4::insert: route exists.\n");
235  return NULL;
236  }
237 
238  // see if we can group this entry to other local entries
239  if (entry.second.src_router_id == 0) {
240  for (const std::shared_ptr<BgpPathAttrib> &attr : entry.second.attribs) {
241  if (attr->type_code == NEXT_HOP) {
242  const BgpPathAttribNexthop &nh = dynamic_cast<const BgpPathAttribNexthop &>(*attr);
243  if (nh.next_hop == nexthop) use_update_id = entry.second.update_id;
244  }
245  }
246  }
247  }
248 
249  BgpRib4Entry new_entry(route, 0, attribs);
250  std::lock_guard<std::recursive_mutex> lock(mutex);
251  new_entry.update_id = use_update_id;
252  new_entry.weight = weight;
253  if (use_update_id == update_id) update_id++;
254  rib4_t::const_iterator it = rib.insert(MAKE_ENTRY4(route, new_entry));
255 
256  return &(it->second);
257 }
258 
272 const std::vector<BgpRib4Entry> BgpRib4::insert(BgpLogHandler *logger, const std::vector<Prefix4> &routes, uint32_t nexthop, int32_t weight) {
273  std::vector<BgpRib4Entry> inserted;
274  std::vector<std::shared_ptr<BgpPathAttrib>> attribs;
275  BgpPathAttribOrigin *origin = new BgpPathAttribOrigin(logger);
276  BgpPathAttribNexthop *nexhop_attr = new BgpPathAttribNexthop(logger);
277  BgpPathAttribAsPath *as_path = new BgpPathAttribAsPath(logger, true);
278  nexhop_attr->next_hop = nexthop;
279  origin->origin = IGP;
280 
281  attribs.push_back(std::shared_ptr<BgpPathAttrib>(origin));
282  attribs.push_back(std::shared_ptr<BgpPathAttrib>(nexhop_attr));
283  attribs.push_back(std::shared_ptr<BgpPathAttrib>(as_path));
284 
285  for (const Prefix4 &route : routes) {
286  rib4_t::const_iterator it = find_entry(route, 0);
287 
288  if (it != rib.end()) continue;
289 
290  BgpRib4Entry new_entry (route, 0, attribs);
291  new_entry.update_id = update_id;
292  new_entry.weight = weight;
293  rib4_t::const_iterator isrt_it = rib.insert(MAKE_ENTRY4(route, new_entry));
294  inserted.push_back(isrt_it->second);
295  }
296 
297  update_id++;
298  return inserted;
299 }
300 
311 std::pair<const BgpRib4Entry*, bool> BgpRib4::insert(uint32_t src_router_id, const Prefix4 &route, const std::vector<std::shared_ptr<BgpPathAttrib>> &attrib, int32_t weight, uint32_t ibgp_asn) {
312  update_id++;
313  return insertPriv(src_router_id, route, attrib, weight, ibgp_asn);
314 }
315 
327 std::pair<std::vector<BgpRib4Entry>, std::vector<Prefix4>> BgpRib4::insert(uint32_t src_router_id, const std::vector<Prefix4> &routes, const std::vector<std::shared_ptr<BgpPathAttrib>> &attrib, int32_t weight, uint32_t ibgp_asn) {
328  update_id++;
329  std::vector<BgpRib4Entry> updated;
330  std::vector<Prefix4> unchanged;
331  for (const Prefix4 &route : routes) {
332  std::pair<const BgpRib4Entry*, bool> rslt = insertPriv(src_router_id, route, attrib, weight, ibgp_asn);
333  if (rslt.first != NULL) {
334  if (!rslt.second) updated.push_back(*(rslt.first));
335  else unchanged.push_back(route);
336  }
337  }
338  return std::make_pair(updated, unchanged);
339 }
340 
353 std::pair<bool, const BgpRib4Entry*> BgpRib4::withdraw(uint32_t src_router_id, const Prefix4 &route) {
354  std::lock_guard<std::recursive_mutex> lock(mutex);
355  std::pair<rib4_t::iterator, rib4_t::iterator> old_entries =
356  rib.equal_range(BgpRib4EntryKey(route));
357 
358  if (old_entries.first == rib.end())
359  return std::make_pair<bool, const BgpRib4Entry*>(false, NULL); // not in RIB.
360 
361  const char *op = "dropped/no_change";
362  BgpRib4Entry *replacement = NULL;
363  // uint64_t old_best_uid = 0;
364  rib4_t::const_iterator to_remove = rib.end();
365 
366  for (rib4_t::iterator it = old_entries.first; it != old_entries.second; it++) {
367  if (it->second.route == route) {
368  if (it->second.src_router_id == src_router_id) {
369  to_remove = it;
370  continue;
371  }
372  replacement = selectEntry(replacement, &(it->second));
373  }
374  }
375 
376  bool reachabled = true;
377 
378  if (to_remove == rib.end())
379  return std::make_pair<bool, const BgpRib4Entry*>(false, NULL);
380 
381  if (replacement != NULL) {
382  // const BgpRib4Entry *candidate = selectEntry(replacement, &(to_remove->second));
383  if (to_remove->second.status == RS_ACTIVE) {
384  op = "dropped/best_changed";
385  } else replacement = NULL;
386  } else {
387  reachabled = false;
388  op = "dropped/unreachabled";
389  }
390 
391  rib.erase(to_remove);
392  if (replacement != NULL) replacement->status = RS_ACTIVE;
393 
394  LIBBGP_LOG(logger, DEBUG) {
395  uint32_t prefix = route.getPrefix();
396  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET_ADDRSTRLEN];
397  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
398  inet_ntop(AF_INET, &prefix, prefix_str, INET_ADDRSTRLEN);
399  logger->log(DEBUG, "BgpRib4::withdraw: (%s) scope %s, route %s/%d\n", op, src_router_id_str, prefix_str, route.getLength());
400  }
401 
402  return std::pair<bool, const BgpRib4Entry*>(reachabled, replacement);
403 }
404 
414 std::pair<std::vector<Prefix4>, std::vector<BgpRib4Entry>> BgpRib4::discard(uint32_t src_router_id) {
415  std::lock_guard<std::recursive_mutex> lock(mutex);
416  std::vector<Prefix4> reevaluate_routes;
417  std::vector<Prefix4> dropped_routes;
418 
419  for (rib4_t::const_iterator it = rib.begin(); it != rib.end();) {
420  const char *op = "dropped/silent";
421  if (it->second.src_router_id != src_router_id) {
422  it++;
423  continue;
424  }
425  if (it->second.status == RS_ACTIVE) {
426  reevaluate_routes.push_back(it->second.route);
427  op = "dropped/pending-reevaluate";
428  }
429  LIBBGP_LOG(logger, DEBUG) {
430  uint32_t prefix = it->second.route.getPrefix();
431  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET_ADDRSTRLEN];
432  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
433  inet_ntop(AF_INET, &prefix, prefix_str, INET_ADDRSTRLEN);
434  logger->log(DEBUG, "BgpRib4::discard: (%s) scope %s, route %s/%d\n", op, src_router_id_str, prefix_str, it->second.route.getLength());
435  }
436  it = rib.erase(it);
437  }
438 
439  std::vector<BgpRib4Entry> replacements;
440 
441  for (std::vector<Prefix4>::const_iterator it = reevaluate_routes.begin(); it != reevaluate_routes.end(); it++) {
442  const char *op = "replacement found";
443  const Prefix4 &prefix = *it;
444  rib4_t::iterator replacement = find_best(prefix);
445  if (replacement == rib.end()) { // no replacement.
446  dropped_routes.push_back(prefix);
447  op = "no available replacement";
448  } else {
449  replacement->second.status = RS_ACTIVE;
450  replacements.push_back(replacement->second);
451  }
452 
453  LIBBGP_LOG(logger, DEBUG) {
454  uint32_t pfx = prefix.getPrefix();
455  char prefix_str[INET_ADDRSTRLEN];
456  inet_ntop(AF_INET, &pfx, prefix_str, INET_ADDRSTRLEN);
457  logger->log(DEBUG, "BgpRib4::discard: %s for route %s/%d\n", op, prefix_str, prefix.getLength());
458  }
459  }
460 
461  return std::make_pair(dropped_routes, replacements);
462 }
463 
472 const BgpRib4Entry* BgpRib4::lookup(uint32_t dest) const {
473  /*const BgpRib4Entry *selected_entry = NULL;
474 
475  for (const auto &entry : rib) {
476  const Prefix4 &route = entry.second.route;
477  if (route.includes(dest))
478  selected_entry = selectEntry(&entry.second, selected_entry);
479  }*/
480 
481  for (const auto &entry : rib) {
482  if (entry.second.status != RS_ACTIVE) continue;
483  if (entry.second.route.includes(dest)) return &entry.second;
484  }
485 
486  return NULL;
487 }
488 
501 const BgpRib4Entry* BgpRib4::lookup(uint32_t src_router_id, uint32_t dest) const {
502  /*const BgpRib4Entry *selected_entry = NULL;
503 
504  for (const auto &entry : rib) {
505  if (entry.second.src_router_id != src_router_id) continue;
506  const Prefix4 &route = entry.second.route;
507  if (route.includes(dest))
508  selected_entry = selectEntry(&entry.second, selected_entry);
509  }
510 
511  return selected_entry;*/
512 
513  for (const auto &entry : rib) {
514  if (entry.second.status != RS_ACTIVE) continue;
515  if (entry.second.src_router_id != src_router_id) continue;
516  if (entry.second.route.includes(dest)) return &entry.second;
517  }
518 
519  return NULL;
520 }
521 
527 const rib4_t& BgpRib4::get() const {
528  return rib;
529 }
530 
531 }
uint32_t getPrefix() const
Get prefix.
Definition: prefix4.cc:288
std::vector< std::shared_ptr< BgpPathAttrib > > attribs
Path attributes for this entry.
Definition: bgp-rib.h:74
Prefix4 route
The prefix of this entry.
Definition: bgp-rib4.h:75
Key for the Rib4 entry map.
Definition: bgp-rib4.h:29
std::pair< bool, const BgpRib4Entry * > withdraw(uint32_t src_router_id, const Prefix4 &route)
Withdraw a route from RIB.
Definition: bgp-rib4.cc:353
void log(LogLevel level, const char *format_str,...)
Log a message. Consider using LIBBGP_LOG if logging the message needs a lot of computing power...
The BgpRib4Entry class.
Definition: bgp-rib4.h:66
uint8_t getLength() const
Get netmask.
Definition: prefix4.cc:297
BgpRouteSource src
Source of this entry.
Definition: bgp-rib.h:83
uint32_t ibgp_peer_asn
ASN of the IBGP peer. (Valid iff src == SRC_IBGP)
Definition: bgp-rib.h:100
IPv4 Route/Prefix related utilities.
Definition: prefix4.h:25
int32_t weight
Weight of this entry.
Definition: bgp-rib.h:68
BgpRib4(BgpLogHandler *logger)
Construct a new BgpRib4 object with logging.
Definition: bgp-rib4.cc:55
uint32_t src_router_id
The originating BGP speaker&#39;s ID of this entry. (network bytes order)
Definition: bgp-rib.h:49
Definition: bgp-afi.h:14
The IPv4 BGP Routing Information Base.
The BgpLogHandler class.
const BgpRib4Entry * insert(BgpLogHandler *logger, const Prefix4 &route, uint32_t nexthop, int32_t weight=0)
Insert a local route into RIB.
Definition: bgp-rib4.cc:218
BgpRouteStatus status
Status of this entry.
Definition: bgp-rib.h:91
uint64_t update_id
The update ID.
Definition: bgp-rib.h:59
uint32_t getNexthop() const
Get nexthop for this entry.
Definition: bgp-rib4.cc:39
uint32_t next_hop
The nexthop in network byte order.
std::pair< std::vector< Prefix4 >, std::vector< BgpRib4Entry > > discard(uint32_t src_router_id)
Drop all routes from RIB that originated from a BGP speaker.
Definition: bgp-rib4.cc:414
const rib4_t & get() const
Get the RIB.
Definition: bgp-rib4.cc:527
const BgpRib4Entry * lookup(uint32_t dest) const
Lookup a destination in RIB.
Definition: bgp-rib4.cc:472