libbgp  0.6
A C++ BGP Library.
bgp-rib6.cc
Go to the documentation of this file.
1 
11 #include <string.h>
12 #include <arpa/inet.h>
13 #include "bgp-rib6.h"
14 #define MAKE_ENTRY6(r, e) std::make_pair(BgpRib6EntryKey(r), e)
15 
16 namespace libbgp {
17 
27 BgpRib6Entry::BgpRib6Entry (Prefix6 r, uint32_t src, const uint8_t nexthop_global[16],
28  const uint8_t nexthop_linklocal[16], const std::vector<std::shared_ptr<BgpPathAttrib>> attribs)
29  : route(r) {
30 
31  memcpy(this->nexthop_global, nexthop_global, 16);
32  if (nexthop_linklocal != NULL) memcpy(this->nexthop_linklocal, nexthop_linklocal, 16);
33  else memset(this->nexthop_linklocal, 0, 16);
35  this->attribs = attribs;
36 }
37 
44  this->logger = logger;
45  update_id = 0;
46 }
47 
48 rib6_t::iterator BgpRib6::find_entry(const Prefix6 &prefix, uint32_t src) {
49  std::pair<rib6_t::iterator, rib6_t::iterator> its =
50  rib.equal_range(BgpRib6EntryKey(prefix));
51 
52  if (its.first == rib.end()) return rib.end();
53 
54  for (rib6_t::iterator it = its.first; it != its.second; it++) {
55  if (it->second.route == prefix && it->second.src_router_id == src) {
56  return it;
57  }
58  }
59 
60  return rib.end();
61 }
62 
63 rib6_t::iterator BgpRib6::find_best (const Prefix6 &prefix) {
64  std::pair<rib6_t::iterator, rib6_t::iterator> its =
65  rib.equal_range(BgpRib6EntryKey(prefix));
66 
67  rib6_t::iterator best = rib.end();
68  if (its.first == rib.end()) return rib.end();
69 
70  for (rib6_t::iterator it = its.first; it != its.second; it++) {
71  if (it->second.route == prefix) {
72  if (best == rib.end()) best = it;
73  else {
74  const BgpRib6Entry *best_ptr = selectEntry(&(best->second), &(it->second));
75  best = best_ptr == &(best->second) ? best : it;
76  }
77  }
78  }
79 
80  return best;
81 }
82 
83 std::pair<const BgpRib6Entry*, bool> BgpRib6::insertPriv(uint32_t src_router_id,
84  const Prefix6 &route,
85  const uint8_t nexthop_global[16], const uint8_t nexthop_linklocal[16],
86  const std::vector<std::shared_ptr<BgpPathAttrib>> &attribs,
87  int32_t weight, uint32_t ibgp_asn) {
88  std::lock_guard<std::recursive_mutex> lock(mutex);
89  BgpRib6Entry new_entry(route, src_router_id, nexthop_global, nexthop_linklocal, attribs);
90  new_entry.update_id = update_id;
91  new_entry.weight = weight;
92  new_entry.src = ibgp_asn > 0 ? SRC_IBGP : SRC_EBGP;
93  new_entry.ibgp_peer_asn = ibgp_asn;
94 
95  const char *op = "new_entry";
96  const char *act = "new_best";
97 
98  std::pair<rib6_t::iterator, rib6_t::iterator> entries = rib.equal_range(BgpRib6EntryKey(route));
99 
100  bool newly_inserted_is_best = false;
101  bool best_changed = false;
102  bool old_exist = entries.first != rib.end();
103  BgpRib6Entry *new_best = NULL;
104 
105  // older route exist
106  if (old_exist) {
107  // find old best & route to replace
108  rib6_t::const_iterator to_replace = rib.end();
109  BgpRib6Entry *old_best = NULL;
110  for (rib6_t::iterator it = entries.first; it != entries.second; it++) {
111  if (it->second.route != route) continue;
112  if (it->second.src_router_id == src_router_id) {
113  to_replace = it;
114  continue;
115  }
116  old_best = selectEntry(old_best, &(it->second));
117  //if (it->second.status == RS_ACTIVE) old_best = &(it->second);
118  }
119 
120  const BgpRib6Entry *candidate = selectEntry(&new_entry, old_best);
121  if (candidate == old_best) {
122  new_entry.status = RS_STANDBY;
123  act = "not_new_best";
124  } else {
125  if (old_best != NULL) old_best->status = RS_STANDBY;
126  best_changed = true;
127  }
128 
129  if (to_replace != rib.end()) {
130  const BgpRib6Entry *candidate = selectEntry(&(to_replace->second), old_best);
131  if (candidate == &(to_replace->second)) {
132  // the replaced route was the best route, now it is removed
133  act = "new_best";
134  best_changed = true;
135  }
136  // we need to replace a route
137  op = "update";
138  rib.erase(to_replace);
139  }
140 
141  rib6_t::iterator inserted = rib.insert(MAKE_ENTRY6(route, new_entry));
142 
143  if (best_changed) {
144  newly_inserted_is_best = candidate == &new_entry;
145  new_best = newly_inserted_is_best ? &(inserted->second) : old_best;
146  }
147 
148  } else { // no older route, new one is best
149  best_changed = newly_inserted_is_best = true;
150  rib6_t::iterator inserted = rib.insert(MAKE_ENTRY6(route, new_entry));
151  new_best = &(inserted->second);
152  }
153 
154  if (new_best != NULL) new_best->status = RS_ACTIVE;
155 
156  LIBBGP_LOG(logger, INFO) {
157  uint8_t prefix_arr[16];
158  route.getPrefix(prefix_arr);
159  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET6_ADDRSTRLEN];
160  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
161  inet_ntop(AF_INET6, prefix_arr, prefix_str, INET6_ADDRSTRLEN);
162  logger->log(INFO, "BgpRib6::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());
163  }
164 
165  return std::make_pair(new_best, newly_inserted_is_best);
166 }
167 
191 const BgpRib6Entry* BgpRib6::insert(BgpLogHandler *logger, const Prefix6 &route,
192  const uint8_t nexthop_global[16], const uint8_t nexthop_linklocal[16], int32_t weight) {
193  std::vector<std::shared_ptr<BgpPathAttrib>> attribs;
194  BgpPathAttribOrigin *origin = new BgpPathAttribOrigin(logger);
195  BgpPathAttribAsPath *as_path = new BgpPathAttribAsPath(logger, true);
196  origin->origin = IGP;
197 
198  attribs.push_back(std::shared_ptr<BgpPathAttrib>(origin));
199  attribs.push_back(std::shared_ptr<BgpPathAttrib>(as_path));
200 
201  BgpRib6Entry new_entry(route, 0, nexthop_global, nexthop_linklocal, attribs);
202  new_entry.weight = weight;
203  uint64_t use_update_id = update_id;
204 
205  for (const auto &entry : rib) {
206  if (entry.second.src_router_id == 0 && entry.second.route == route) {
207  this->logger->log(ERROR, "BgpRib6::insert: route exists.\n");
208  return NULL;
209  }
210 
211  // see if we can group this entry to other local entries
212  if (entry.second.src_router_id == 0) {
213  if (memcmp(new_entry.nexthop_global, entry.second.nexthop_global, 16) == 0 &&
214  memcmp(new_entry.nexthop_linklocal, entry.second.nexthop_linklocal, 16) == 0) {
215  use_update_id = entry.second.update_id;
216  }
217  }
218  }
219 
220  std::lock_guard<std::recursive_mutex> lock(mutex);
221  new_entry.update_id = use_update_id;
222  if (use_update_id == update_id) update_id++;
223  rib6_t::const_iterator it = rib.insert(MAKE_ENTRY6(route, new_entry));
224 
225  return &(it->second);
226 }
227 
242 const std::vector<BgpRib6Entry> BgpRib6::insert(BgpLogHandler *logger,
243  const std::vector<Prefix6> &routes, const uint8_t nexthop_global[16],
244  const uint8_t nexthop_linklocal[16], int32_t weight) {
245  std::vector<BgpRib6Entry> inserted;
246  std::vector<std::shared_ptr<BgpPathAttrib>> attribs;
247  BgpPathAttribOrigin *origin = new BgpPathAttribOrigin(logger);
248  BgpPathAttribAsPath *as_path = new BgpPathAttribAsPath(logger, true);
249  origin->origin = IGP;
250 
251  attribs.push_back(std::shared_ptr<BgpPathAttrib>(origin));
252  attribs.push_back(std::shared_ptr<BgpPathAttrib>(as_path));
253 
254  for (const Prefix6 &route : routes) {
255  rib6_t::const_iterator it = find_entry(route, 0);
256 
257  if (it != rib.end()) continue;
258 
259  BgpRib6Entry new_entry (route, 0, nexthop_global, nexthop_linklocal, attribs);
260  new_entry.update_id = update_id;
261  new_entry.weight = weight;
262  rib6_t::const_iterator isrt_it = rib.insert(MAKE_ENTRY6(route, new_entry));
263  inserted.push_back(isrt_it->second);
264  }
265 
266  update_id++;
267  return inserted;
268 }
269 
290 std::pair<const BgpRib6Entry*, bool> BgpRib6::insert(uint32_t src_router_id,
291  const Prefix6 &route,
292  const uint8_t nexthop_global[16], const uint8_t nexthop_linklocal[16],
293  const std::vector<std::shared_ptr<BgpPathAttrib>> &attribs, int32_t weight,
294  uint32_t ibgp_asn) {
295 
296  update_id++;
297  return insertPriv(src_router_id, route, nexthop_global, nexthop_linklocal, attribs, weight, ibgp_asn);
298 }
299 
312 std::pair<std::vector<BgpRib6Entry>, std::vector<Prefix6>> BgpRib6::insert(
313  uint32_t src_router_id, const std::vector<Prefix6> &routes,
314  const uint8_t nexthop_global[16], const uint8_t nexthop_linklocal[16],
315  const std::vector<std::shared_ptr<BgpPathAttrib>> &attribs, int32_t weight, uint32_t ibgp_asn) {
316  update_id++;
317  std::vector<BgpRib6Entry> updated;
318  std::vector<Prefix6> unchanged;
319  for (const Prefix6 &route : routes) {
320  std::pair<const BgpRib6Entry*, bool> rslt = insertPriv(src_router_id, route, nexthop_global, nexthop_linklocal, attribs, weight, ibgp_asn);
321  if (rslt.first != NULL) {
322  if (!rslt.second) updated.push_back(*(rslt.first));
323  else unchanged.push_back(route);
324  }
325  }
326  return std::make_pair(updated, unchanged);
327 }
328 
341 std::pair<bool, const BgpRib6Entry*> BgpRib6::withdraw(uint32_t src_router_id, const Prefix6 &route) {
342  std::lock_guard<std::recursive_mutex> lock(mutex);
343 
344  std::pair<rib6_t::iterator, rib6_t::iterator> old_entries =
345  rib.equal_range(BgpRib6EntryKey(route));
346 
347  if (old_entries.first == rib.end())
348  return std::make_pair<bool, const BgpRib6Entry*>(false, NULL); // not in RIB.
349 
350  const char *op = "dropped/no_change";
351 
352  BgpRib6Entry *replacement = NULL;
353  // uint64_t old_best_uid = 0;
354  rib6_t::const_iterator to_remove = rib.end();
355 
356  for (rib6_t::iterator it = old_entries.first; it != old_entries.second; it++) {
357  if (it->second.route == route) {
358  if (it->second.src_router_id == src_router_id) {
359  to_remove = it;
360  continue;
361  }
362  replacement = selectEntry(replacement, &(it->second));
363  }
364  }
365 
366  bool reachabled = true;
367 
368  if (to_remove == rib.end())
369  return std::make_pair<bool, const BgpRib6Entry*>(false, NULL);
370 
371  if (replacement != NULL) {
372  if (to_remove->second.status == RS_ACTIVE) {
373  op = "dropped/best_changed";
374  } else replacement = NULL;
375  } else {
376  reachabled = false;
377  op = "dropped/unreachabled";
378  }
379 
380  rib.erase(to_remove);
381  if (replacement != NULL) replacement->status = RS_ACTIVE;
382 
383  LIBBGP_LOG(logger, INFO) {
384  uint8_t prefix_arr[16];
385  route.getPrefix(prefix_arr);
386  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET6_ADDRSTRLEN];
387  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
388  inet_ntop(AF_INET6, prefix_arr, prefix_str, INET6_ADDRSTRLEN);
389  logger->log(INFO, "BgpRib6::withdraw: (%s) scope %s, route %s/%d\n", op, src_router_id_str, prefix_str, route.getLength());
390  }
391 
392  return std::pair<bool, const BgpRib6Entry*>(reachabled, replacement);
393 }
394 
403 std::pair<std::vector<Prefix6>, std::vector<BgpRib6Entry>> BgpRib6::discard(uint32_t src_router_id) {
404  std::lock_guard<std::recursive_mutex> lock(mutex);
405  /*std::vector<Prefix6> dropped_routes;
406 
407  for (rib6_t::const_iterator it = rib.begin(); it != rib.end();) {
408  if (it->second.src_router_id == src_router_id) {
409  dropped_routes.push_back(it->second.route);
410  LIBBGP_LOG(logger, INFO) {
411  uint8_t prefix_arr[16];
412  it->second.route.getPrefix(prefix_arr);
413  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET6_ADDRSTRLEN];
414  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
415  inet_ntop(AF_INET6, prefix_arr, prefix_str, INET6_ADDRSTRLEN);
416  logger->log(INFO, "BgpRib6::discard: (dropped) scope %s, route %s/%d\n", src_router_id_str, prefix_str, it->second.route.getLength());
417  }
418  it = rib.erase(it);
419  } else it++;
420  }*/
421 
422  std::vector<Prefix6> reevaluate_routes;
423  std::vector<Prefix6> dropped_routes;
424 
425  for (rib6_t::const_iterator it = rib.begin(); it != rib.end();) {
426  const char *op = "dropped/silent";
427  if (it->second.src_router_id != src_router_id) {
428  it++;
429  continue;
430  }
431  if (it->second.status == RS_ACTIVE) {
432  reevaluate_routes.push_back(it->second.route);
433  op = "dropped/pending-reevaluate";
434  }
435  LIBBGP_LOG(logger, INFO) {
436  uint8_t prefix_arr[16];
437  it->second.route.getPrefix(prefix_arr);
438  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET6_ADDRSTRLEN];
439  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
440  inet_ntop(AF_INET6, prefix_arr, prefix_str, INET6_ADDRSTRLEN);
441  logger->log(INFO, "BgpRib6::discard: (%s) scope %s, route %s/%d\n", op, src_router_id_str, prefix_str, it->second.route.getLength());
442  }
443  it = rib.erase(it);
444  }
445 
446  std::vector<BgpRib6Entry> replacements;
447 
448  for (std::vector<Prefix6>::const_iterator it = reevaluate_routes.begin(); it != reevaluate_routes.end(); it++) {
449  const char *op = "replacement found";
450  const Prefix6 &prefix = *it;
451  rib6_t::iterator replacement = find_best(prefix);
452  if (replacement == rib.end()) { // no replacement.
453  dropped_routes.push_back(prefix);
454  op = "no available replacement";
455  } else {
456  replacement->second.status = RS_ACTIVE;
457  replacements.push_back(replacement->second);
458  }
459 
460  LIBBGP_LOG(logger, INFO) {
461  uint8_t prefix_arr[16];
462  prefix.getPrefix(prefix_arr);
463  char src_router_id_str[INET_ADDRSTRLEN], prefix_str[INET6_ADDRSTRLEN];
464  inet_ntop(AF_INET, &src_router_id, src_router_id_str, INET_ADDRSTRLEN);
465  inet_ntop(AF_INET6, prefix_arr, prefix_str, INET6_ADDRSTRLEN);
466  logger->log(INFO, "BgpRib6::discard: (%s) scope %s, route %s/%d\n", op, src_router_id_str, prefix_str, prefix.getLength());
467  }
468  }
469 
470  return std::make_pair(dropped_routes, replacements);
471 
472  // return dropped_routes;
473 }
474 
483 const BgpRib6Entry* BgpRib6::lookup(const uint8_t dest[16]) const {
484  /*const BgpRib6Entry *selected_entry = NULL;
485 
486  for (const auto &entry : rib) {
487  const Prefix6 &route = entry.second.route;
488  if (route.includes(dest))
489  selected_entry = selectEntry(&entry.second, selected_entry);
490  }*/
491 
492  for (const auto &entry : rib) {
493  if (entry.second.status != RS_ACTIVE) continue;
494  if (entry.second.route.includes(dest)) return &entry.second;
495  }
496 
497  return NULL;
498 }
499 
512 const BgpRib6Entry* BgpRib6::lookup(uint32_t src_router_id, const uint8_t dest[16]) const {
513  /*const BgpRib6Entry *selected_entry = NULL;
514 
515  for (const auto &entry : rib) {
516  if (entry.second.src_router_id != src_router_id) continue;
517  const Prefix6 &route = entry.second.route;
518  if (route.includes(dest))
519  selected_entry = selectEntry(&entry.second, selected_entry);
520  }
521 
522  return selected_entry;*/
523 
524  for (const auto &entry : rib) {
525  if (entry.second.status != RS_ACTIVE) continue;
526  if (entry.second.src_router_id != src_router_id) continue;
527  if (entry.second.route.includes(dest)) return &entry.second;
528  }
529 
530  return NULL;
531 }
532 
538 const rib6_t& BgpRib6::get() const {
539  return rib;
540 }
541 
542 }
IPv6 Route/Prefix related utilities.
Definition: prefix6.h:27
std::vector< std::shared_ptr< BgpPathAttrib > > attribs
Path attributes for this entry.
Definition: bgp-rib.h:74
Key for the Rib6 entry map.
Definition: bgp-rib6.h:30
BgpRib6Entry(Prefix6 r, uint32_t src, const uint8_t nexthop_global[16], const uint8_t nexthop_linklocal[16], const std::vector< std::shared_ptr< BgpPathAttrib >> attribs)
Construct a new BgpRib6Entry.
Definition: bgp-rib6.cc:27
uint8_t getLength() const
Get netmask.
Definition: prefix6.cc:459
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...
uint8_t nexthop_global[16]
Global IPv6 address of the next hop in network btyes order.
Definition: bgp-rib6.h:82
BgpRouteSource src
Source of this entry.
Definition: bgp-rib.h:83
The BgpRib6Entry class.
Definition: bgp-rib6.h:66
uint32_t ibgp_peer_asn
ASN of the IBGP peer. (Valid iff src == SRC_IBGP)
Definition: bgp-rib.h:100
int32_t weight
Weight of this entry.
Definition: bgp-rib.h:68
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 BgpLogHandler class.
std::pair< bool, const BgpRib6Entry * > withdraw(uint32_t src_router_id, const Prefix6 &route)
Withdraw a route from RIB.
Definition: bgp-rib6.cc:341
std::pair< std::vector< Prefix6 >, std::vector< BgpRib6Entry > > discard(uint32_t src_router_id)
Drop all routes from RIB that originated from a BGP speaker.
Definition: bgp-rib6.cc:403
void getPrefix(uint8_t prefix[16]) const
Get prefix.
Definition: prefix6.cc:450
const BgpRib6Entry * insert(BgpLogHandler *logger, const Prefix6 &route, const uint8_t nexthop_global[16], const uint8_t nexthop_linklocal[16], int32_t weight=0)
Insert a local route into RIB.
Definition: bgp-rib6.cc:191
Prefix6 route
The prefix of this entry.
Definition: bgp-rib6.h:76
BgpRouteStatus status
Status of this entry.
Definition: bgp-rib.h:91
uint64_t update_id
The update ID.
Definition: bgp-rib.h:59
const BgpRib6Entry * lookup(const uint8_t dest[16]) const
Lookup a destination in RIB.
Definition: bgp-rib6.cc:483
uint8_t nexthop_linklocal[16]
Link local IPv6 address of the next hop in network btyes order. (all 0 if not avaliable) ...
Definition: bgp-rib6.h:89
const rib6_t & get() const
Get the RIB.
Definition: bgp-rib6.cc:538
The BGP Routing Information Base for IPv6.
BgpRib6(BgpLogHandler *logger)
Construct a new BgpRib6 object with logging.
Definition: bgp-rib6.cc:43