libbgp  0.6
A C++ BGP Library.
bgp-fsm.cc
Go to the documentation of this file.
1 
11 #include "bgp-fsm.h"
12 #include "realtime-clock.h"
13 #include "value-op.h"
14 #include <stdlib.h>
15 #include <string.h>
16 #include <arpa/inet.h>
17 
18 namespace libbgp {
19 
20 const char* bgp_fsm_state_str[] = {
21  "Idle",
22  "Open Sent",
23  "Open Confirm",
24  "Established",
25  "Broken"
26 };
27 
28 BgpFsm::BgpFsm(const BgpConfig &config) : in_sink(config.use_4b_asn) {
29  this->config = config;
30  state = IDLE;
31  out_buffer = (uint8_t *) malloc(BGP_FSM_BUFFER_SIZE);
32 
33  if (config.rev_bus) {
34  rev_bus_exist = true;
35  config.rev_bus->subscribe(this);
36  } else rev_bus_exist = false;
37 
38  if (!config.clock) {
39  clock = new RealtimeClock();
40  clock_local = true;
41  } else {
42  clock = config.clock;
43  clock_local = false;
44  }
45 
46  if (!config.log_handler) {
47  logger = new BgpLogHandler();
48  log_local = true;
49  } else {
50  logger = config.log_handler;
51  log_local = false;
52  }
53 
54  in_sink.setLogger(logger);
55 
56  if (!config.rib4) {
57  rib4 = new BgpRib4(logger);
58  rib4_local = true;
59  } else {
60  rib4 = config.rib4;
61  rib4_local = false;
62  }
63 
64  if (!config.rib6) {
65  rib6 = new BgpRib6(logger);
66  rib6_local = true;
67  } else {
68  rib6 = config.rib6;
69  rib6_local = false;
70  }
71 
72  hold_timer = 0;
73  peer_bgp_id = 0;
74  peer_asn = 0;
75 }
76 
77 BgpFsm::~BgpFsm() {
78  free(out_buffer);
79  if (rib4_local) delete rib4;
80  if (rib6_local) delete rib6;
81  if (clock_local) delete clock;
82  if (rev_bus_exist) config.rev_bus->unsubscribe(this);
83  if (log_local) delete logger;
84 }
85 
86 uint32_t BgpFsm::getAsn() const {
87  return config.asn;
88 }
89 
90 uint32_t BgpFsm::getBgpId() const {
91  return config.router_id;
92 }
93 
94 uint32_t BgpFsm::getPeerAsn() const {
95  return peer_asn;
96 }
97 
98 uint32_t BgpFsm::getPeerBgpId() const {
99  return peer_bgp_id;
100 }
101 
102 uint16_t BgpFsm::getHoldTimer() const {
103  return hold_timer;
104 }
105 
107  return rib4_local ? *rib4 : *(config.rib4);
108 }
109 
111  return rib4_local ? *rib6 : *(config.rib6);
112 }
113 
115  return state;
116 }
117 
119  if (state == BROKEN) {
120  logger->log(ERROR, "BgpFsm::start: FSM is broken, consider reset.\n");
121  return 0;
122  }
123 
124  if (state != IDLE) {
125  logger->log(ERROR, "BgpFsm::start: not in IDLE state.\n");
126  return 0;
127  }
128 
129  logger->log(DEBUG, "BgpFsm::start: sending OPEN message to peer.\n");
130 
131  uint16_t my_asn_2b = config.asn >= 0xffff ? 23456 : config.asn;
132 
133  BgpOpenMessage msg(logger, config.use_4b_asn, my_asn_2b, config.hold_timer, config.router_id);
134  if (config.use_4b_asn) {
135  msg.setAsn(config.asn);
136  }
137 
138  if (config.mp_bgp_ipv4) {
139  BgpCapabilityMpBgp *cap = new BgpCapabilityMpBgp(logger);
140  cap->afi = IPV4;
141  cap->safi = UNICAST;
142  msg.addCapability(std::shared_ptr<BgpCapability>(cap));
143  }
144 
145  if (config.mp_bgp_ipv6) {
146  BgpCapabilityMpBgp *cap = new BgpCapabilityMpBgp(logger);
147  cap->afi = IPV6;
148  cap->safi = UNICAST;
149  msg.addCapability(std::shared_ptr<BgpCapability>(cap));
150  }
151 
152  setState(OPEN_SENT);
153  if(!writeMessage(msg)) return -1;
154  return 1;
155 }
156 
158  if (state == BROKEN) {
159  logger->log(ERROR, "BgpFsm::stop: FSM is broken, consider reset.\n");
160  return 0;
161  }
162 
163  if (state == IDLE) return 1;
164  if (state != ESTABLISHED) {
165  logger->log(ERROR, "BgpFsm::stop: FSM in not ESTABLISED nor IDLE, can't stop. To force stop, do a reset.\n");
166  return 0;
167  }
168 
169  logger->log(INFO, "BgpFsm::stop: de-peering...\n");
170 
171 
172  BgpNotificationMessage notify (logger, E_CEASE, E_SHUTDOWN, NULL, 0);
173 
174  setState(IDLE);
175  if(!writeMessage(notify)) return -1;
176  return 1;
177 }
178 
179 int BgpFsm::run(const uint8_t *buffer, const size_t buffer_size) {
180  if (state == BROKEN) {
181  logger->log(ERROR, "BgpFsm::run: FSM is broken, consider reset.\n");
182  return -1;
183  }
184 
185  ssize_t fill_ret = in_sink.fill(buffer, buffer_size);
186  if (fill_ret != (ssize_t) buffer_size) {
187  logger->log(ERROR, "BgpFsm::run: failed to fill() sink.\n");
188  setState(BROKEN);
189  return -1;
190  }
191 
192  // tick the clock
193  if (!config.no_autotick) {
194  int tick_ret = tick();
195  if (tick_ret <= 0) return tick_ret;
196  }
197 
198  last_recv = clock->getTime();
199 
200  int final_ret_val = -1;
201 
202  // keep running untill sink empty
203  while (in_sink.getBytesInSink() > 0) {
204  BgpPacket *packet = NULL;
205  ssize_t poured = in_sink.pour(&packet);
206 
207  if (poured <= -2) {
208  logger->log(ERROR, "BgpFsm::run: sink seems to be broken, please reset.\n");
209  setState(BROKEN);
210  return -1;
211  }
212 
213  if (poured == 0) return 3;
214 
215  LIBBGP_LOG(logger, DEBUG) {
216  logger->log(DEBUG, "BgpFsm::run: got message (Current state: %s):\n", bgp_fsm_state_str[state]);
217  logger->log(DEBUG, *packet);
218  }
219 
220  const BgpMessage *msg = packet->getMessage();
221  // parse failed / packet invalid (errors like Unsupported Optional
222  // Parameter falls in this catagory, since those errors are checked by
223  // parsers, other errors like FSM error, Bad Peer AS, etc is handled in
224  // fsmEval*)
225  if (poured == -1) {
226  if (msg->type == NOTIFICATION) {
227  logger->log(ERROR, "BgpFsm::run: got invalid NOTIFICATION message.\n");
228  if (state == ESTABLISHED) {
229  logger->log(ERROR, "BgpFsm::run: discarding all routes.\n");
230  }
231 
232  delete packet;
233  setState(IDLE);
234  return 0;
235  }
236  BgpNotificationMessage notify (logger, msg->getErrorCode(), msg->getErrorSubCode(), msg->getError(), msg->getErrorLength());
237  setState(IDLE);
238  if(!writeMessage(notify)) return -1;
239  delete packet;
240  return 0;
241  }
242 
243  if (msg->type == NOTIFICATION) {
244  const BgpNotificationMessage *notify = dynamic_cast<const BgpNotificationMessage *>(msg);
245  const char *err_msg = bgp_error_code_str[notify->errcode];
246  const char *err_sub_msg = bgp_error_code_str[0];
247  switch (notify->errcode) {
248  case E_HEADER: err_sub_msg = bgp_header_error_subcode_str[notify->subcode]; break;
249  case E_OPEN: err_sub_msg = bgp_open_error_subcode_str[notify->subcode]; break;
250  case E_UPDATE: err_sub_msg = bgp_update_error_str[notify->subcode]; break;
251  case E_FSM: err_sub_msg = bgp_fsm_error_str[notify->subcode]; break;
252  case E_CEASE: err_sub_msg = bgp_cease_error_str[notify->subcode]; break;
253  }
254  logger->log(ERROR, "BgpFsm::run: got NOTIFICATION: %s (%d): %s (%d).\n", err_msg, notify->errcode, err_sub_msg, notify->subcode);
255  delete packet;
256  setState(IDLE);
257  return 0;
258  }
259 
260  int retval = -1;
261 
262  int vald_ret = validateState(msg->type);
263  if (vald_ret <= 0) {
264  delete packet;
265  return vald_ret;
266  }
267 
268  switch (state) {
269  case IDLE: retval = fsmEvalIdle(msg); break;
270  case OPEN_SENT: retval = fsmEvalOpenSent(msg); break;
271  case OPEN_CONFIRM: retval = fsmEvalOpenConfirm(msg); break;
272  case ESTABLISHED: retval = fsmEvalEstablished(msg); break;
273  default: {
274  logger->log(ERROR, "BgpFsm::run: FSM in invalid state: %d.\n", state);
275  delete packet;
276  return -1;
277  }
278  }
279 
280  delete packet;
281  if (retval < 0) return retval;
282  if (retval == 0) final_ret_val = 0;
283  if (retval == 1 && final_ret_val != 0 && final_ret_val != 2) final_ret_val = 1;
284  if (retval == 2) final_ret_val = 2;
285  }
286 
287  return final_ret_val;
288 }
289 
291  if (state != ESTABLISHED) return 1;
292 
293  // peer hold-timer exipred?
294  uint64_t now = clock->getTime();
295  if (hold_timer > 0 && now - last_recv > hold_timer) {
296  logger->log(ERROR, "BgpFsm::tick: peer hold timer expired (last_recv: %d, now: %d, diff: %d, hold: %d).\n", last_recv, now, now - last_recv, hold_timer);
297  BgpNotificationMessage notify (logger, E_HOLD, 0, NULL, 0);
298  setState(IDLE);
299  if(!writeMessage(notify)) return -1;
300  return 0;
301  }
302 
303  // send keepalive?
304  if (hold_timer > 0 && now - last_sent > hold_timer / 3) {
306  if(!writeMessage(keep)) return -1;
307  return 2;
308  }
309 
310  return 1;
311 }
312 
314  BgpNotificationMessage notify (logger, E_CEASE, E_RESET, NULL, 0);
315  if(!writeMessage(notify)) return -1;
316  resetHard();
317  return 0;
318 }
319 
321  in_sink.drain();
322  setState(IDLE);
323 }
324 
325 int BgpFsm::openRecv(const BgpOpenMessage *open_msg) {
326  if (open_msg->version != 4) {
327  BgpNotificationMessage notify (logger, E_OPEN, E_VERSION, NULL, 0);
328  setState(IDLE);
329  if(!writeMessage(notify)) return -1;
330  return 0;
331  }
332 
333  peer_asn = open_msg->getAsn();
334 
335  if (config.peer_asn != 0 && peer_asn != config.peer_asn) {
336  BgpNotificationMessage notify (logger, E_OPEN, E_PEER_AS, NULL, 0);
337  setState(IDLE);
338  if(!writeMessage(notify)) return -1;
339  return 0;
340  }
341 
342  ibgp = config.asn == peer_asn;
343 
344  if (!validAddr4(open_msg->bgp_id)) {
345  LIBBGP_LOG(logger, ERROR) {
346  char ip_str[INET_ADDRSTRLEN];
347  inet_ntop(AF_INET, &(open_msg->bgp_id), ip_str, INET_ADDRSTRLEN);
348  logger->log(ERROR, "BgpFsm::openRecv: peer BGP ID (%s) invalid.\n", ip_str);
349  }
350  BgpNotificationMessage notify (logger, E_OPEN, E_BGP_ID, NULL, 0);
351  setState(IDLE);
352  if(!writeMessage(notify)) return -1;
353  return 0;
354  }
355 
356  // if hold timer != 0 but < 3, reject witl E_HOLD_TIME (as per rfc4271)
357  if (open_msg->hold_time < 3 && open_msg->hold_time != 0) {
358  logger->log(ERROR, "BgpFsm::openRecv: invalid hold timer %d.\n", open_msg->hold_time);
359  BgpNotificationMessage notify (logger, E_OPEN, E_HOLD_TIME, NULL, 0);
360  setState(IDLE);
361  if(!writeMessage(notify)) return -1;
362  return 0;
363  }
364 
365  if (!config.no_collision_detection && rev_bus_exist) {
367  col.peer_bgp_id = open_msg->bgp_id;
368 
369  // publish returned 0: no one complained about collision (either
370  // there's no collision, or some fsm has killed themselves)
371  //
372  // publish returned > 0: someone complained about collision, it think
373  // this session should be dropped
374  if(config.rev_bus->publish(this, col) > 0) {
375  int res_result = resloveCollision(open_msg->bgp_id, true);
376 
377  if(res_result == -1) return -1;
378  if(res_result == 0) return 0;
379 
380  // should not be happening
381  if(res_result == 1) {
382  logger->log(ERROR,
383  "BgpFsm::openRecv: collision found, and some other FSM feels like they should live"
384  "while we feel like we should live too. is there duplicated FSMs?\n"
385  );
386  setState(BROKEN);
387  return -1;
388  }
389  }
390  }
391 
392  hold_timer = config.hold_timer > open_msg->hold_time ? open_msg->hold_time : config.hold_timer;
393  peer_bgp_id = open_msg->bgp_id;
394  use_4b_asn = open_msg->hasCapability(ASN_4B) && config.use_4b_asn;
395  send_ipv4_routes = true;
396  if (open_msg->hasCapability(MP_BGP) && (config.mp_bgp_ipv6 || config.mp_bgp_ipv4)) {
397  send_ipv4_routes = send_ipv6_routes = false;
398 
399  const std::vector<std::shared_ptr<BgpCapability>> &capabilities = open_msg->getCapabilities();
400 
401  for (const std::shared_ptr<BgpCapability> &cap : capabilities) {
402  if (cap->code == MP_BGP) {
403  const BgpCapabilityMpBgp &mp_cap = dynamic_cast<const BgpCapabilityMpBgp &> (*cap);
404  if (mp_cap.safi != UNICAST) continue;
405  if (mp_cap.afi == IPV6) send_ipv6_routes = true && config.mp_bgp_ipv6;
406  if (mp_cap.afi == IPV4) send_ipv4_routes = true && config.mp_bgp_ipv4;
407  }
408  }
409  } else {
410  send_ipv4_routes = true && !(config.mp_bgp_ipv6 && !config.mp_bgp_ipv4);
411  send_ipv6_routes = false;
412  }
413 
414  return 1;
415 }
416 
417 int BgpFsm::resloveCollision(uint32_t peer_bgp_id, bool is_new) {
418  if(is_new) {
419  if (ntohl(config.router_id) > ntohl(peer_bgp_id)) {
420  // this is a new connection, and "we" have higer ID, there's
421  // already a connection so THIS fsm should be dispose. since
422  // THIS fsm is created by peer connecting to us.
423  BgpNotificationMessage notify (logger, E_CEASE, E_COLLISION, NULL, 0);
424  if(!writeMessage(notify)) return -1;
425 
426  logger->log(INFO, "(new_session) we have higher router id, dispose this new session.\n");
427 
428  setState(IDLE);
429  return 0;
430  } else {
431  // this is a new connection, and peer has higher ID. the exisiting
432  // connection should be dispose, since THIS fsm is created by peer
433  // connecting to us, this one will be kept, we do nothing.
434 
435  logger->log(INFO, "(new_session) peer has higher router id, ask the other fsm to dispose session.\n");
436  return 1;
437  }
438  } else {
439  if (ntohl(config.router_id) > ntohl(peer_bgp_id)) {
440  // this is a old connection, and "we" have higer ID, the new one
441  // shoud close, we do nothing.
442  logger->log(INFO, "(old_session) we have higher router id, keep this old session.\n");
443 
444  return 1;
445  } else {
446  // this is a old connection, and "peer" have higer ID, this one
447  // shoud close.
448 
449  logger->log(INFO, "(old_session) peer has higher router id, dispose this session.\n");
450  BgpNotificationMessage notify (logger, E_CEASE, E_COLLISION, NULL, 0);
451  if(!writeMessage(notify)) return -1;
452 
453  setState(IDLE);
454  return 0;
455  }
456  }
457 
458  // UNREACHED
459  setState(BROKEN);
460  logger->log(ERROR, "BgpFsm::resloveCollison: ??? :( \n");
461  return -1;
462 }
463 
464 bool BgpFsm::handleRouteEvent(const RouteEvent &ev) {
465  if (ev.type == ADD4) return handleRoute4AddEvent(dynamic_cast <const Route4AddEvent&>(ev));
466  if (ev.type == WITHDRAW4) return handleRoute4WithdrawEvent(dynamic_cast <const Route4WithdrawEvent&>(ev));
467  if (ev.type == ADD6) return handleRoute6AddEvent(dynamic_cast <const Route6AddEvent&>(ev));
468  if (ev.type == WITHDRAW6) return handleRoute6WithdrawEvent(dynamic_cast <const Route6WithdrawEvent&>(ev));
469  if (ev.type == COLLISION) return handleRouteCollisionEvent(dynamic_cast <const RouteCollisionEvent&>(ev));
470 
471  return false;
472 }
473 
474 bool BgpFsm::handleRouteCollisionEvent(const RouteCollisionEvent &ev) {
475  if (state != OPEN_CONFIRM || peer_bgp_id != ev.peer_bgp_id) return false;
476 
477  LIBBGP_LOG(logger, INFO) {
478  logger->log(INFO, "BgpFsm::handleRouteCollisionEvent: detecting collision with %s.\n", inet_ntoa(*(const struct in_addr*) &(ev.peer_bgp_id)));
479  }
480  return resloveCollision(ev.peer_bgp_id, false) == 1;
481 }
482 
483 bool BgpFsm::handleRoute6AddEvent(const Route6AddEvent &ev) {
484  if (state != ESTABLISHED) return false;
485  if (!send_ipv6_routes) return false;
486  if ((ev.shared_attribs == NULL || ev.new_routes == NULL) && ev.replaced_entries == NULL) return false;
487 
488  size_t nroutes = 0;
489  if (ev.replaced_entries != NULL) nroutes += ev.replaced_entries->size();
490  if (ev.new_routes != NULL) nroutes += ev.new_routes->size();
491 
492  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: got route-add event with %zu routes.\n", nroutes);
493 
494  if (ev.new_routes != NULL && ev.shared_attribs != NULL) {
495  if (!ibgp || ev.ibgp_peer_asn != peer_asn) {
496  std::vector<Prefix6> routes;
497  const uint8_t *nh_global = ev.nexthop_global;
498  const uint8_t *nh_local = ev.nexthop_linklocal;
499  alterNexthop6(nh_local, nh_global);
500 
501  for (const Prefix6 &route : *(ev.new_routes)) {
502  if (config.out_filters6.apply(route, *(ev.shared_attribs))) {
503  routes.push_back(route);
504  } else {
505  LIBBGP_LOG(logger, DEBUG) {
506  uint8_t prefix[16];
507  route.getPrefix(prefix);
508  char prefix_str[INET6_ADDRSTRLEN];
509  inet_ntop(AF_INET6, &prefix, prefix_str, INET6_ADDRSTRLEN);
510  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: route %s/%d filtered by out_filter.\n", prefix_str, route.getLength());
511  }
512  }
513  }
514 
515  if (routes.size() > 0) {
516  BgpUpdateMessage update (logger, use_4b_asn);
517  update.setAttribs(*(ev.shared_attribs));
518  prepareUpdateMessage(update);
519  update.setNlri6(routes, nh_global, nh_local);
520 
521  if(!writeMessage(update)) return false;
522  }
523 
524  } else {
525  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: ignoring new_routes in add event since remote is IBGP.\n");
526  }
527  } else {
528  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: new_routes or shared_attribs is NULL.\n");
529  }
530 
531  if (ev.replaced_entries == NULL) {
532  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: replaced_entries is NULL.\n");
533  return true;
534  }
535 
536  // consider merging of replaced_entries?
537  for (const BgpRib6Entry &entry : *(ev.replaced_entries)) {
538  if (entry.src_router_id == peer_bgp_id) continue;
539 
540  if (ibgp && entry.ibgp_peer_asn == peer_asn) {
541  LIBBGP_LOG(logger, DEBUG) {
542  uint8_t prefix[16];
543  entry.route.getPrefix(prefix);
544  char prefix_str[INET6_ADDRSTRLEN];
545  inet_ntop(AF_INET6, &prefix, prefix_str, INET6_ADDRSTRLEN);
546  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: route %s/%d in replaced_entries ignored as it is IBGP.\n", prefix_str, entry.route.getLength());
547  }
548 
549  continue;
550  }
551 
552  if (config.out_filters6.apply(entry.route, entry.attribs) != ACCEPT) {
553  LIBBGP_LOG(logger, DEBUG) {
554  uint8_t prefix[16];
555  entry.route.getPrefix(prefix);
556  char prefix_str[INET6_ADDRSTRLEN];
557  inet_ntop(AF_INET6, &prefix, prefix_str, INET6_ADDRSTRLEN);
558  logger->log(DEBUG, "BgpFsm::handleRoute6AddEvent: route %s/%d in replaced_entries filtered.\n", prefix_str, entry.route.getLength());
559  }
560 
561  continue;
562  }
563 
564  BgpUpdateMessage update (logger, use_4b_asn);
565  update.setAttribs(entry.attribs);
566  const uint8_t *nh_global = entry.nexthop_global;
567  const uint8_t *nh_local = entry.nexthop_linklocal;
568  alterNexthop6(nh_local, nh_global);
569  std::vector<Prefix6> routes;
570  routes.push_back(entry.route);
571  update.setNlri6(routes, nh_global, nh_local);
572  prepareUpdateMessage(update);
573  if(!writeMessage(update)) return false;
574  }
575 
576  return true;
577 }
578 
579 bool BgpFsm::handleRoute6WithdrawEvent(const Route6WithdrawEvent &ev) {
580  if (state != ESTABLISHED) return false;
581  if (!send_ipv6_routes) return false;
582  if (ev.routes == NULL) return false;
583 
584  logger->log(DEBUG, "BgpFsm::handleRoute6WithdrawEvent: got route-withdraw event with %zu routes.\n", ev.routes->size());
585 
586 
587  BgpUpdateMessage withdraw (logger, use_4b_asn);
588  withdraw.setWithdrawn6(*(ev.routes));
589 
590  if(!writeMessage(withdraw)) return false;
591  return true;
592 }
593 
594 bool BgpFsm::handleRoute4AddEvent(const Route4AddEvent &ev) {
595  if (state != ESTABLISHED) return false;
596  if (!send_ipv4_routes) return false;
597  if ((ev.shared_attribs == NULL || ev.new_routes == NULL) && ev.replaced_entries == NULL) return false;
598 
599  size_t nroutes = 0;
600  if (ev.replaced_entries != NULL) nroutes += ev.replaced_entries->size();
601  if (ev.new_routes != NULL) nroutes += ev.new_routes->size();
602 
603  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: got route-add event with %zu routes.\n", nroutes);
604 
605  if (ev.new_routes != NULL && ev.shared_attribs != NULL) {
606  if (!ibgp || ev.ibgp_peer_asn != peer_asn) {
607  BgpUpdateMessage update (logger, use_4b_asn);
608  update.setAttribs(*(ev.shared_attribs));
609 
610  for (const Prefix4 &route : *(ev.new_routes)) {
611  if (config.out_filters4.apply(route, *(ev.shared_attribs)) == ACCEPT) {
612  update.addNlri4(route);
613  } else {
614  LIBBGP_LOG(logger, DEBUG) {
615  uint32_t prefix = route.getPrefix();
616  char ip_str[INET_ADDRSTRLEN];
617  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
618  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: route %s/%d filtered by out_filter.\n", ip_str, route.getLength());
619  }
620  }
621  }
622 
623  if (update.nlri.size() > 0) {
624  alterNexthop4(update);
625  prepareUpdateMessage(update);
626 
627  if(!writeMessage(update)) return false;
628  }
629  } else {
630  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: ignoring new_routes in add event since remote is IBGP.\n");
631  }
632  } else {
633  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: new_routes or shared_attribs is NULL.\n");
634  }
635 
636  if (ev.replaced_entries == NULL) {
637  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: replaced_entries is NULL.\n");
638  return true;
639  }
640 
641  // consider merging of replaced_entries?
642  for (const BgpRib4Entry &entry : *(ev.replaced_entries)) {
643  if (entry.src_router_id == peer_bgp_id) continue;
644 
645  if (ibgp && entry.ibgp_peer_asn == peer_asn) {
646  LIBBGP_LOG(logger, DEBUG) {
647  uint32_t prefix = entry.route.getPrefix();
648  char ip_str[INET_ADDRSTRLEN];
649  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
650  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: route %s/%d ignored since remote is IBGP.\n", ip_str, entry.route.getLength());
651  }
652 
653  continue;
654  }
655 
656  if (config.out_filters4.apply(entry.route, entry.attribs) != ACCEPT) {
657  LIBBGP_LOG(logger, DEBUG) {
658  uint32_t prefix = entry.route.getPrefix();
659  char ip_str[INET_ADDRSTRLEN];
660  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
661  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: route %s/%d filtered by out_filter.\n", ip_str, entry.route.getLength());
662  }
663 
664  continue;
665  }
666 
667  BgpUpdateMessage update (logger, use_4b_asn);
668  update.setAttribs(entry.attribs);
669  update.addNlri4(entry.route);
670  alterNexthop4(update);
671  prepareUpdateMessage(update);
672  if(!writeMessage(update)) return false;
673  }
674 
675  return true;
676 }
677 
678 bool BgpFsm::handleRoute4WithdrawEvent(const Route4WithdrawEvent &ev) {
679  if (state != ESTABLISHED) return false;
680  if (!send_ipv4_routes) return false;
681  if (ev.routes == NULL) return false;
682 
683  logger->log(DEBUG, "BgpFsm::handleRoute4AddEvent: got route-withdraw event with %zu routes.\n", ev.routes->size());
684 
685  BgpUpdateMessage withdraw (logger, use_4b_asn);
686  withdraw.setWithdrawn4(*(ev.routes));
687 
688  if(!writeMessage(withdraw)) return false;
689  return true;
690 }
691 
692 void BgpFsm::alterNexthop4 (BgpUpdateMessage &update) {
693  // ibgp
694  if (ibgp && !config.ibgp_alter_nexthop) return;
695 
696  // configured to fource default nexthop, or does not have a nexthop attribute
697  if (config.forced_default_nexthop4 || !update.hasAttrib(NEXT_HOP)) {
698  LIBBGP_LOG(logger, INFO) {
699  char ip_str[INET_ADDRSTRLEN];
700  inet_ntop(AF_INET, &(config.default_nexthop4), ip_str, INET_ADDRSTRLEN);
701  if (config.forced_default_nexthop4) {
702  logger->log(INFO, "BgpFsm::alterNexthop4: forced_default_nexthop4 set, using %s as nexthop.\n", ip_str);
703  } else {
704  logger->log(INFO, "BgpFsm::alterNexthop4: no nethop attribute set, using %s as nexthop.\n", ip_str);
705  }
706  }
707  update.setNextHop(config.default_nexthop4);
708  } else {
709  // nexthop not forced, check w/ peering LAN
710  BgpPathAttribNexthop &nh = dynamic_cast<BgpPathAttribNexthop &> (update.getAttrib(NEXT_HOP));
711  if (!config.peering_lan4.includes(nh.next_hop)) {
712  LIBBGP_LOG(logger, INFO) {
713  char def_nexthop[INET_ADDRSTRLEN];
714  char cur_nexthop[INET_ADDRSTRLEN];
715  inet_ntop(AF_INET, &(config.default_nexthop4), def_nexthop, INET_ADDRSTRLEN);
716  inet_ntop(AF_INET, &(nh.next_hop), cur_nexthop, INET_ADDRSTRLEN);
717  logger->log(INFO, "BgpFsm::alterNexthop4: nexthop %s not in peering lan, using %s.\n", cur_nexthop, def_nexthop);
718  }
719  nh.next_hop = config.default_nexthop4;
720  }
721  }
722 }
723 
724 void BgpFsm::alterNexthop6 (const uint8_t* &nh_global, const uint8_t* &nh_local) {
725  if (config.forced_default_nexthop6 && !config.peering_lan6.includes(nh_global) && !ibgp && !config.ibgp_alter_nexthop) {
726  LIBBGP_LOG(logger, INFO) {
727  char nh_old_str[INET6_ADDRSTRLEN];
728  char nh_def_str[INET6_ADDRSTRLEN];
729  inet_ntop(AF_INET6, &nh_global, nh_old_str, INET6_ADDRSTRLEN);
730  inet_ntop(AF_INET6, &nh_def_str, nh_def_str, INET6_ADDRSTRLEN);
731 
732  if (config.forced_default_nexthop6) {
733  logger->log(INFO, "BgpFsm::alterNexthop6: forced_default_nexthop6 set, default (%s) will be used.\n", nh_def_str);
734  }
735  else logger->log(INFO, "BgpFsm::alterNexthop6: nexthop %s is not in peering lan, default (%s) will be used.\n", nh_old_str, nh_def_str);
736  }
737 
738  nh_global = config.default_nexthop6_global;
739  nh_local = config.default_nexthop6_linklocal;
740  }
741 }
742 
743 void BgpFsm::prepareUpdateMessage(BgpUpdateMessage &update) {
744  update.dropNonTransitive();
745 
746  if (config.use_4b_asn && use_4b_asn) {
747  update.restoreAsPath();
748  update.restoreAggregator();
749  } else {
750  update.downgradeAsPath();
751  update.downgradeAggregator();
752  }
753 
754  if (!ibgp) update.prepend(config.asn);
755 }
756 
757 int BgpFsm::validateState(uint8_t type) {
758  switch(state) {
759  case IDLE:
760  if (type != OPEN) {
761  logger->log(ERROR, "BgpFsm::validateState: got non-OPEN message in IDLE state.\n");
762  return 0;
763  }
764  return 1;
765  case OPEN_SENT:
766  if (type != OPEN) {
767  logger->log(ERROR, "BgpFsm::validateState: got non-OPEN message in OPEN_SENT state.\n");
768  BgpNotificationMessage notify (logger, E_FSM, E_OPEN_SENT, NULL, 0);
769  setState(IDLE);
770  if(!writeMessage(notify)) return -1;
771 
772  return 0;
773  }
774  return 1;
775  case OPEN_CONFIRM:
776  if (type != KEEPALIVE) {
777  logger->log(ERROR, "BgpFsm::validateState: got non-KEEPALIVE message in OPEN_CONFIRM state.\n");
778  BgpNotificationMessage notify (logger, E_FSM, E_OPEN_CONFIRM, NULL, 0);
779  setState(IDLE);
780  if(!writeMessage(notify)) return -1;
781 
782  return 0;
783  }
784  return 1;
785  case ESTABLISHED:
786  if (type != UPDATE && type != KEEPALIVE) {
787  logger->log(ERROR, "BgpFsm::validateState: got invalid message (type %d) in ESTABLISHED state.\n", type);
788  BgpNotificationMessage notify (logger, E_FSM, E_ESTABLISHED, NULL, 0);
789  setState(IDLE);
790  if(!writeMessage(notify)) return -1;
791 
792  return 0;
793  }
794  return 1;
795  default:
796  logger->log(ERROR, "BgpFsm::validateState: got message in bad state. consider reset.\n");
797  return -1;
798  }
799 }
800 
801 int BgpFsm::fsmEvalIdle(const BgpMessage *msg) {
802  const BgpOpenMessage *open_msg = dynamic_cast<const BgpOpenMessage *>(msg);
803 
804  int retval = openRecv(open_msg);
805  if (retval != 1) return retval;
806 
807  uint16_t my_asn_2b = config.asn >= 0xffff ? 23456 : config.asn;
808  BgpOpenMessage open_reply (logger, use_4b_asn, my_asn_2b, hold_timer, config.router_id);
809 
810  if (use_4b_asn) {
811  open_reply.setAsn(config.asn);
812  }
813 
814  if (config.mp_bgp_ipv4) {
815  BgpCapabilityMpBgp *cap = new BgpCapabilityMpBgp(logger);
816  cap->afi = IPV4;
817  cap->safi = UNICAST;
818  open_reply.addCapability(std::shared_ptr<BgpCapability>(cap));
819  }
820 
821  if (config.mp_bgp_ipv6) {
822  BgpCapabilityMpBgp *cap = new BgpCapabilityMpBgp(logger);
823  cap->afi = IPV6;
824  cap->safi = UNICAST;
825  open_reply.addCapability(std::shared_ptr<BgpCapability>(cap));
826  }
827 
828  setState(OPEN_CONFIRM);
829  if(!writeMessage(open_reply)) return -1;
830 
831  return 1;
832 }
833 
834 int BgpFsm::fsmEvalOpenSent(const BgpMessage *msg) {
835  const BgpOpenMessage *open_msg = dynamic_cast<const BgpOpenMessage *>(msg);
836 
837  int retval = openRecv(open_msg);
838  if (retval != 1) return retval;
839 
841  setState(OPEN_CONFIRM);
842  if(!writeMessage(keep)) return -1;
843 
844  return 1;
845 }
846 
847 int BgpFsm::fsmEvalOpenConfirm(__attribute__((unused)) const BgpMessage *msg) {
849  setState(ESTABLISHED);
850  if(!writeMessage(keep)) return -1;
851 
852  if (send_ipv4_routes) {
853  rib4_t::const_iterator iter = rib4->get().begin();
854  rib4_t::const_iterator last_iter = iter;
855  const rib4_t::const_iterator end = rib4->get().end();
856 
857  // group routes and and updates
858  while (iter != end) {
859  uint64_t cur_group_id = iter->second.update_id;
860  BgpUpdateMessage update (logger, use_4b_asn);
861  update.setAttribs(iter->second.attribs);
862  alterNexthop4(update);
863  prepareUpdateMessage(update);
864 
865  // length of the update message, 19: headers, 4: length fields
866  size_t msg_len = 19 + 4;
867 
868  for (const std::shared_ptr<BgpPathAttrib> &attrib : update.path_attribute) {
869  msg_len += attrib->length();
870  }
871 
872  for (; iter != end && cur_group_id == iter->second.update_id && msg_len < 4096; iter++) {
873  const BgpRib4Entry &e = iter->second;
874  const Prefix4 &r = e.route;
875  if (e.status == RS_STANDBY) continue;
876 
877  if (ibgp && e.src == SRC_IBGP && e.ibgp_peer_asn == peer_asn) {
878  LIBBGP_LOG(logger, DEBUG) {
879  uint32_t prefix = r.getPrefix();
880  char ip_str[INET_ADDRSTRLEN];
881  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
882  logger->log(DEBUG, "BgpFsm::fsmEvalOpenConfirm: ignored IBGP route %s/%d.\n", ip_str, r.getLength());
883  }
884  last_iter = iter;
885  continue;
886  }
887 
888  if (iter->second.src_router_id == peer_bgp_id) {
889  LIBBGP_LOG(logger, WARN) {
890  uint32_t prefix = r.getPrefix();
891  char ip_str[INET_ADDRSTRLEN];
892  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
893  logger->log(WARN, "BgpFsm::fsmEvalOpenConfirm: route %s/%d has src_bgp_id same as peer, ignore.\n", ip_str, r.getLength());
894  }
895  last_iter = iter;
896  continue;
897  }
898  if (config.out_filters4.apply(r, update.path_attribute) == ACCEPT) {
899  msg_len += 1 + (r.getLength() + 7) / 8;
900  if (msg_len > 4096) {
901  // size too big, roll back and break.
902  iter = last_iter;
903  break;
904  }
905  update.addNlri4(r);
906  } else {
907  LIBBGP_LOG(logger, DEBUG) {
908  uint32_t prefix = r.getPrefix();
909  char ip_str[INET_ADDRSTRLEN];
910  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
911  logger->log(DEBUG, "BgpFsm::fsmEvalOpenConfirm: route %s/%d filtered by out_filter.\n", ip_str, r.getLength());
912  }
913  }
914  last_iter = iter;
915  }
916 
917  if (update.nlri.size() > 0) {
918  if(!writeMessage(update)) return -1;
919  }
920  }
921  }
922 
923  if (send_ipv6_routes) {
924  rib6_t::const_iterator iter = rib6->get().begin();
925  rib6_t::const_iterator last_iter = iter;
926  const rib6_t::const_iterator end = rib6->get().end();
927 
928  while (iter != end) {
929  uint64_t cur_group_id = iter->second.update_id;
930  const uint8_t *nh_global = iter->second.nexthop_global;
931  const uint8_t *nh_linklocal = iter->second.nexthop_linklocal;
932  BgpUpdateMessage update (logger, use_4b_asn);
933  update.setAttribs(iter->second.attribs);
934 
935  prepareUpdateMessage(update);
936  std::vector<Prefix6> filtered_nlri;
937 
938  // 8: mp-reach-nlri headers (attrib hdr: 3, afi/safi/nh_len/res: 5)
939  // 32: max nexthop len
940  size_t msg_len = 19 + 4 + 8 + 32;
941  for (const std::shared_ptr<BgpPathAttrib> &attrib : update.path_attribute) {
942  msg_len += attrib->length();
943  }
944 
945  for (; iter != end && cur_group_id == iter->second.update_id && msg_len < 4096; iter++) {
946  const BgpRib6Entry &e = iter->second;
947  const Prefix6 &r = e.route;
948  if (e.status != RS_ACTIVE) continue;
949  if (ibgp && e.src == SRC_IBGP && e.ibgp_peer_asn == peer_asn) {
950  LIBBGP_LOG(logger, DEBUG) {
951  uint8_t prefix[16];
952  r.getPrefix(prefix);
953  char ip_str[INET6_ADDRSTRLEN];
954  inet_ntop(AF_INET6, &prefix, ip_str, INET6_ADDRSTRLEN);
955  logger->log(DEBUG, "BgpFsm::fsmEvalOpenConfirm: ignored IBGP route %s/%d.\n", ip_str, r.getLength());
956  }
957  last_iter = iter;
958  continue;
959  }
960  if (iter->second.src_router_id == peer_bgp_id) {
961  LIBBGP_LOG(logger, WARN) {
962  uint8_t prefix[16];
963  r.getPrefix(prefix);
964  char ip_str[INET6_ADDRSTRLEN];
965  inet_ntop(AF_INET6, &prefix, ip_str, INET6_ADDRSTRLEN);
966  logger->log(WARN, "BgpFsm::fsmEvalOpenConfirm: route %s/%d has src_bgp_id same as peer, ignore.\n", ip_str, r.getLength());
967  }
968  last_iter = iter;
969  continue;
970  }
971 
972  if (config.out_filters6.apply(r, update.path_attribute) == ACCEPT) {
973  msg_len += 1 + (r.getLength() + 7) / 8;
974  if (msg_len > 4096) {
975  // size too big, roll back and break.
976  iter = last_iter;
977  break;
978  }
979  filtered_nlri.push_back(r);
980  } else {
981  LIBBGP_LOG(logger, DEBUG) {
982  uint8_t prefix[16];
983  r.getPrefix(prefix);
984  char ip_str[INET6_ADDRSTRLEN];
985  inet_ntop(AF_INET6, &prefix, ip_str, INET6_ADDRSTRLEN);
986  logger->log(DEBUG, "BgpFsm::fsmEvalOpenConfirm: route %s/%d filtered by out_filter.\n", ip_str, r.getLength());
987  }
988  }
989  last_iter = iter;
990  }
991 
992  if (filtered_nlri.size() > 0) {
993  alterNexthop6(nh_global, nh_linklocal);
994  update.setNlri6(filtered_nlri, nh_global, nh_linklocal);
995  if(!writeMessage(update)) return -1;
996  }
997 
998  }
999  }
1000 
1001  return 1;
1002 }
1003 
1004 int BgpFsm::fsmEvalEstablished(const BgpMessage *msg) {
1005  if (msg->type == KEEPALIVE) return 1;
1006 
1007  const BgpUpdateMessage *update = dynamic_cast<const BgpUpdateMessage *>(msg);
1008 
1009  bool ignore_routes = false;
1010 
1011  // checks
1012  if (update->hasAttrib(AS_PATH) && update->nlri.size() > 0) {
1013  const BgpPathAttribAsPath &as_path = dynamic_cast<const BgpPathAttribAsPath&>(update->getAttrib(AS_PATH));
1014 
1015  for (const BgpAsPathSegment &seg : as_path.as_paths) {
1016  int8_t local_count = 0;
1017 
1018  for (uint32_t asn : seg.value) {
1019  if (asn == config.asn) local_count++;
1020  }
1021 
1022  if (local_count > config.allow_local_as) {
1023  logger->log(WARN, "BgpFsm::fsmEvalEstablished: ignoring routes with %d local asn in as_path (max %d are allowed).\n", local_count, config.allow_local_as);
1024  ignore_routes = true;
1025  break;
1026  }
1027  }
1028  } else ignore_routes = true; // since no AS_PATH and nlri non empty. (should be handleded by update-msg already tho)
1029 
1030  if (send_ipv4_routes) {
1031  std::vector<Prefix4> unreach;
1032  std::vector<BgpRib4Entry> changed_entries;
1033  for (const Prefix4 &r : update->withdrawn_routes) {
1034  std::pair<bool, const BgpRib4Entry*> w_ret = rib4->withdraw(peer_bgp_id, r);
1035  if (!rev_bus_exist) continue;
1036  if (!w_ret.first) unreach.push_back(r);
1037  else if (w_ret.second != NULL) {
1038  changed_entries.push_back(*(w_ret.second));
1039  }
1040  }
1041 
1042  // more checks
1043  if (update->nlri.size() > 0) {
1044  const BgpPathAttribNexthop &nh = dynamic_cast<const BgpPathAttribNexthop &>(update->getAttrib(NEXT_HOP));
1045 
1046  if (!ignore_routes && !validAddr4(nh.next_hop)) {
1047  LIBBGP_LOG(logger, WARN) {
1048  char ip_str[INET_ADDRSTRLEN];
1049  inet_ntop(AF_INET, &(nh.next_hop), ip_str, INET_ADDRSTRLEN);
1050  logger->log(WARN, "BgpFsm::fsmEvalEstablished: ignored %zu routes with invalid nexthop %s\n", update->nlri.size(), ip_str);
1051  }
1052  ignore_routes = true;
1053  }
1054 
1055  if (!ignore_routes && !config.no_nexthop_check4 && !config.peering_lan4.includes(nh.next_hop) && !ibgp) {
1056  LIBBGP_LOG(logger, WARN) {
1057  char ip_str_nh[INET_ADDRSTRLEN];
1058  char ip_str_lan[INET_ADDRSTRLEN];
1059  inet_ntop(AF_INET, &(nh.next_hop), ip_str_nh, INET_ADDRSTRLEN);
1060  uint32_t peering_lan_pfx = config.peering_lan4.getPrefix();
1061  inet_ntop(AF_INET, &peering_lan_pfx, ip_str_lan, INET_ADDRSTRLEN);
1062  logger->log(WARN, "BgpFsm::fsmEvalEstablished: ignored %zu routes with nexthop outside peering LAN. (%s not in %s/%d)\n",
1063  update->nlri.size(), ip_str_nh, ip_str_lan, config.peering_lan4.getLength());
1064  }
1065  ignore_routes = true;
1066  };
1067  }
1068 
1069  // filter & insert to rib
1070  if (!ignore_routes) {
1071  std::vector<Prefix4> routes = std::vector<Prefix4> ();
1072  for (const Prefix4 &route : update->nlri) {
1073  if(config.in_filters4.apply(route, update->path_attribute) == ACCEPT) {
1074  routes.push_back(route);
1075  } else {
1076  LIBBGP_LOG(logger, DEBUG) {
1077  uint32_t prefix = route.getPrefix();
1078  char ip_str[INET_ADDRSTRLEN];
1079  inet_ntop(AF_INET, &prefix, ip_str, INET_ADDRSTRLEN);
1080  logger->log(DEBUG, "BgpFsm::fsmEvalEstablished: route %s/%d filtered by in_filters4.\n", ip_str, route.getLength());
1081  }
1082  }
1083  }
1084 
1085  std::pair<std::vector<BgpRib4Entry>, std::vector<Prefix4>> rslt;
1086  if (routes.size() > 0) {
1087  rslt = rib4->insert(peer_bgp_id, routes, update->path_attribute, config.weight, ibgp ? peer_asn : 0);
1088  for (const BgpRib4Entry &entry : rslt.first) {
1089  changed_entries.push_back(entry);
1090  }
1091  logger->log(DEBUG, "BgpFsm::fsmEvalEstablished: rib4.insert(): %zu altered and %zu added in %zu routes.\n", rslt.first.size(), rslt.second.size(), routes.size());
1092  }
1093 
1094  if (rev_bus_exist && (changed_entries.size() > 0 || rslt.second.size() > 0)) {
1095  logger->log(DEBUG, "BgpFsm::fsmEvalEstablished: publishing new v4 routes on event bus...\n");
1097  aev.replaced_entries = changed_entries.size() > 0 ? &changed_entries : NULL;
1098  aev.shared_attribs = &(update->path_attribute);
1099  aev.new_routes = rslt.second.size() > 0 ? &(rslt.second) : NULL;
1100  if (ibgp) aev.ibgp_peer_asn = peer_asn;
1101  config.rev_bus->publish(this, aev);
1102  }
1103 
1104  if (rev_bus_exist && unreach.size() > 0) {
1105  logger->log(DEBUG, "BgpFsm::fsmEvalEstablished: publishing dropped v4 routes on event bus...\n");
1107  wev.routes = &unreach;
1108  config.rev_bus->publish(this, wev);
1109  }
1110  }
1111  }
1112 
1113  if (send_ipv6_routes) {
1114  std::vector<Prefix6> unreach;
1115  std::vector<BgpRib6Entry> changed_entries;
1116  if (update->hasAttrib(MP_UNREACH_NLRI)) {
1117  const BgpPathAttrib &attr = update->getAttrib(MP_UNREACH_NLRI);
1118  const BgpPathAttribMpNlriBase &mp_unreach = dynamic_cast<const BgpPathAttribMpNlriBase &>(attr);
1119  if (mp_unreach.afi == IPV6 && mp_unreach.safi == UNICAST) {
1120  const BgpPathAttribMpUnreachNlriIpv6 &u = dynamic_cast<const BgpPathAttribMpUnreachNlriIpv6 &>(mp_unreach);
1121 
1122  for (const Prefix6 &r : u.withdrawn_routes) {
1123  std::pair<bool, const BgpRib6Entry*> w_ret = rib6->withdraw(peer_bgp_id, r);
1124  if (!rev_bus_exist) continue;
1125  if (!w_ret.first) unreach.push_back(r);
1126  else if (w_ret.second != NULL) {
1127  changed_entries.push_back(*(w_ret.second));
1128  }
1129  }
1130  }
1131  }
1132 
1133  if (!ignore_routes && update->hasAttrib(MP_REACH_NLRI)) {
1134  const BgpPathAttrib &attr = update->getAttrib(MP_REACH_NLRI);
1135  const BgpPathAttribMpNlriBase &mp_reach = dynamic_cast<const BgpPathAttribMpNlriBase &>(attr);
1136  if (mp_reach.afi == IPV6 && mp_reach.safi == UNICAST) {
1137  const BgpPathAttribMpReachNlriIpv6 &reach = dynamic_cast<const BgpPathAttribMpReachNlriIpv6 &>(mp_reach);
1138 
1139  if (!validAddr6(reach.nexthop_global) || (!v6addr_is_zero(reach.nexthop_linklocal) && !validAddr6(reach.nexthop_linklocal))) {
1140  logger->log(WARN, "BgpFsm::fsmEvalEstablished: ignored %zu routes with invalid nexthop:\n", reach.nlri.size());
1141  logger->log(WARN, reach);
1142  return 1;
1143  }
1144 
1145  // filter toures
1146  std::vector<Prefix6> filtered_routes;
1147  for (const Prefix6 &route : reach.nlri) {
1148  if (config.in_filters6.apply(route, update->path_attribute) == ACCEPT) filtered_routes.push_back(route);
1149  }
1150 
1151  if (filtered_routes.size() <= 0) return 1;
1152 
1153  // TODO verify with no_nexthop_check6
1154 
1155  // remove MP_* & nexthop attribute
1156  std::vector<std::shared_ptr<BgpPathAttrib>> attrs;
1157 
1158  for (const std::shared_ptr<BgpPathAttrib> &attr : update->path_attribute) {
1159  if (attr->type_code == MP_REACH_NLRI || attr->type_code == MP_UNREACH_NLRI || attr->type_code == NEXT_HOP) continue;
1160  attrs.push_back(attr);
1161  }
1162 
1163  std::pair<std::vector<BgpRib6Entry>, std::vector<Prefix6>> rslt = rib6->insert(peer_bgp_id, filtered_routes, reach.nexthop_global, reach.nexthop_linklocal, attrs, config.weight, ibgp ? peer_asn : 0);
1164  logger->log(DEBUG, "BgpFsm::fsmEvalEstablished: rib6.insert(): %zu altered and %zu added in %zu routes.\n", rslt.first.size(), rslt.second.size(), filtered_routes.size());
1165 
1166  for (const BgpRib6Entry &e : rslt.first) {
1167  changed_entries.push_back(e);
1168  }
1169 
1170  if (rev_bus_exist && (changed_entries.size() > 0 || rslt.second.size() > 0)) {
1172  memcpy(aev.nexthop_global, reach.nexthop_global, 16);
1173  memcpy(aev.nexthop_linklocal, reach.nexthop_linklocal, 16);
1174  aev.new_routes = rslt.second.size() > 0 ? &(rslt.second) : NULL;
1175  aev.replaced_entries = changed_entries.size() > 0 ? &changed_entries : NULL;
1176  aev.shared_attribs = &attrs;
1177  if (ibgp) aev.ibgp_peer_asn = peer_asn;
1178  config.rev_bus->publish(this, aev);
1179  }
1180 
1181  if (rev_bus_exist && unreach.size() > 0) {
1182  logger->log(DEBUG, "BgpFsm::fsmEvalEstablished: publishing dropped v6 routes on event bus...\n");
1184  wev.routes = &unreach;
1185  config.rev_bus->publish(this, wev);
1186  }
1187  }
1188  }
1189  }
1190 
1191  return 1;
1192 }
1193 
1194 void BgpFsm::dropAllRoutes() {
1195  if (peer_bgp_id != 0) {
1196  std::pair<std::vector<Prefix4>, std::vector<BgpRib4Entry>> rslt4 = rib4->discard(peer_bgp_id);
1197  if (rev_bus_exist && rslt4.first.size() > 0) {
1198  Route4WithdrawEvent wev;
1199  wev.routes = &(rslt4.first);
1200  config.rev_bus->publish(this, wev);
1201  }
1202  if (rev_bus_exist && rslt4.second.size() > 0) {
1203  Route4AddEvent aev;
1204  aev.replaced_entries = &(rslt4.second);
1205  config.rev_bus->publish(this, aev);
1206  }
1207  std::pair<std::vector<Prefix6>, std::vector<BgpRib6Entry>> rslt6 = rib6->discard(peer_bgp_id);
1208  if (rev_bus_exist && rslt6.first.size() > 0) {
1209  Route6WithdrawEvent wev;
1210  wev.routes = &(rslt6.first);
1211  config.rev_bus->publish(this, wev);
1212  }
1213  if (rev_bus_exist && rslt6.second.size() > 0) {
1214  Route6AddEvent aev;
1215  aev.replaced_entries = &(rslt6.second);
1216  config.rev_bus->publish(this, aev);
1217  }
1218  }
1219 }
1220 
1221 void BgpFsm::setState(BgpState new_state) {
1222  if (state == new_state) return;
1223 
1224  if (config.out_handler) config.out_handler->notifyStateChange(state, new_state);
1225 
1226  logger->log(INFO, "BgpFsm::setState: changing state: %s -> %s\n", bgp_fsm_state_str[state], bgp_fsm_state_str[new_state]);
1227 
1228  if (state == ESTABLISHED) {
1229  logger->log(INFO, "BgpFsm::setState: dropping all routes received from peer...\n");
1230 
1231  // moved from ESTABLISHED to something else. Drop all routes.
1232  dropAllRoutes();
1233  }
1234 
1235  state = new_state;
1236 }
1237 
1238 bool BgpFsm::validAddr4(uint32_t addr) const {
1239  if (addr == config.default_nexthop4 || addr == config.router_id) {
1240  return false;
1241  }
1242 
1243  uint32_t addr_host = ntohl(addr);
1244  uint32_t first = addr_host >> 24;
1245 
1246  if (first == 0 || first == 127 || (first >= 224 && first <= 239) || first > 240) {
1247  return false;
1248  }
1249 
1250  return true;
1251 }
1252 
1253 bool BgpFsm::validAddr6(const uint8_t addr[16]) const {
1254  static Prefix6 bad_range("0000::", 8);
1255 
1256  return !bad_range.includes(addr);
1257 }
1258 
1259 bool BgpFsm::writeMessage(const BgpMessage &msg) {
1260  BgpPacket pkt(logger, use_4b_asn, &msg);
1261  LIBBGP_LOG(logger, DEBUG) {
1262  logger->log(DEBUG, "BgpFsm::writeMessage: write (Current state: %s):\n", bgp_fsm_state_str[state]);
1263  logger->log(DEBUG, pkt);
1264  }
1265 
1266  std::lock_guard<std::recursive_mutex> lock(out_buffer_mutex);
1267 
1268  ssize_t pkt_len = pkt.write(out_buffer, BGP_FSM_BUFFER_SIZE);
1269  last_sent = clock->getTime();
1270 
1271  if (pkt_len < 0) {
1272  logger->log(ERROR, "BgpFsm::writeMessage: failed to write message, abort.\n");
1273  setState(BROKEN);
1274  return false;
1275  }
1276 
1277  if (config.out_handler && !config.out_handler->handleOut(out_buffer, pkt_len)) {
1278  logger->log(ERROR, "BgpFsm::writeMessage: out_handler failed, abort.\n");
1279  setState(BROKEN);
1280  return false;
1281  }
1282 
1283  return true;
1284 }
1285 
1286 }
std::vector< std::shared_ptr< BgpPathAttrib > > * shared_attribs
Path attribues of the route.
Definition: route-event.h:127
int run(const uint8_t *buffer, const size_t buffer_size)
Run the FSM on buffer.
Definition: bgp-fsm.cc:179
uint8_t errcode
Notification message error code.
IPv6 Route/Prefix related utilities.
Definition: prefix6.h:27
uint32_t getPrefix() const
Get prefix.
Definition: prefix4.cc:288
const std::vector< BgpRib4Entry > * replaced_entries
Pointer to the route replacement entries vector.
Definition: route-event.h:80
bool setAsn(uint32_t my_asn)
Set ASN.
bool setNextHop(uint32_t nexthop)
Set/Create nexthop attribtue.
bool restoreAsPath()
Restore the AS_PATH attribute to four octets ASN flavor.
The BgpRib4 (IPv4 BGP Routing Information Base) class.
Definition: bgp-rib4.h:87
BgpRib4 & getRib4() const
Get the IPv4 Routing Information Base.
Definition: bgp-fsm.cc:106
const char * bgp_error_code_str[7]
Error strings for BGP error codes.
Definition: bgp-errcode.cc:19
const std::vector< Prefix4 > * new_routes
Newly added routes.
Definition: route-event.h:74
The BgpOpenMessage class.
const std::vector< std::shared_ptr< BgpPathAttrib > > * shared_attribs
Shared attributes for the new routes.
Definition: route-event.h:68
std::vector< uint32_t > value
The segment value.
The BgpPathAttrib class.
RouteEventType type
Type of this event.
Definition: route-event.h:46
MP-BGP ReachNlri IPv6 NLRI class.
The BGP Finite State Machine.
int stop()
Stop the FSM. (Any -> Idle)
Definition: bgp-fsm.cc:157
Prefix4 route
The prefix of this entry.
Definition: bgp-rib4.h:75
bool setWithdrawn4(const std::vector< Prefix4 > &routes)
Set withdrawn routes.
BgpPathAttrib & getAttrib(uint8_t type)
Get mutable reference to attribute by typecode.
uint32_t getBgpId() const
Get local BGP ID.
Definition: bgp-fsm.cc:90
The BgpCapabilityMpBgp class.
uint32_t getPeerAsn() const
Get peer ASN.
Definition: bgp-fsm.cc:94
void resetHard()
Perform a hard reset.
Definition: bgp-fsm.cc:320
uint8_t getLength() const
Get netmask.
Definition: prefix6.cc:459
The BgpNotificationMessage object.
Probe for collision detection.
Definition: route-event.h:184
uint16_t afi
Address Family Identifier.
const BgpMessage * getMessage() const
Get pointer to the contained message.
Definition: bgp-packet.cc:172
BgpState
BGP Finite State Machine status.
Definition: bgp-fsm.h:32
uint32_t getPeerBgpId() const
Get peer BGP ID.
Definition: bgp-fsm.cc:98
std::vector< BgpAsPathSegment > as_paths
The AS Path segments.
The BgpRib4Entry class.
Definition: bgp-rib4.h:66
const std::vector< std::shared_ptr< BgpCapability > > & getCapabilities() const
Get capabilities list.
uint8_t subcode
Notification message error subcode.
bool downgradeAggregator()
Downgrade aggregator to two octets.
uint8_t getLength() const
Get netmask.
Definition: prefix4.cc:297
An Route6WithdrawEvent.
Definition: route-event.h:166
bool includes(const uint8_t address[16]) const
Test if an address is inside this prefix.
Definition: prefix6.cc:315
BgpRouteSource src
Source of this entry.
Definition: bgp-rib.h:83
bool restoreAggregator()
Restore aggregator attribute from as4_aggregator.
bool prepend(uint32_t asn)
Prepend ASN to AS_PATH and AS4_PATH (if in 2b-mode ans AS4_PATH exists)
std::vector< Prefix6 > * routes
Routes to withdraw.
Definition: route-event.h:174
The BgpRib6Entry class.
Definition: bgp-rib6.h:66
const char * bgp_fsm_error_str[4]
Error strings for BGP FSM error subcodes.
Definition: bgp-errcode.cc:78
uint8_t nexthop_global[16]
Global IPv6 nexthop.
Definition: route-event.h:145
uint32_t ibgp_peer_asn
ASN of the IBGP peer. (Valid iff src == SRC_IBGP)
Definition: bgp-rib.h:100
The BgpMessage base class.
Definition: bgp-message.h:35
An Route4WithdrawEvent.
Definition: route-event.h:95
const char * bgp_cease_error_str[9]
Error strings for BGP cease error subcodes.
Definition: bgp-errcode.cc:89
IPv4 Route/Prefix related utilities.
Definition: prefix4.h:25
bool v6addr_is_zero(const uint8_t prefix[16])
Test if a IPv6 addresss is all zero.
Definition: prefix6.cc:195
Buffer operation helpers.
The BgpRib6 (IPv6 BGP Routing Information Base) class.
Definition: bgp-rib6.h:98
uint8_t safi
Subsequent Address Family Identifier.
An Route4AddEvent.
Definition: route-event.h:54
The BgpKeepaliveMessage class.
An Route6AddEvent.
Definition: route-event.h:113
const char * bgp_open_error_subcode_str[8]
Error strings for BGP open message error subcodes.
Definition: bgp-errcode.cc:44
A Clock implementation to use system time as time.
Definition: bgp-afi.h:14
MP-BGP Reach/Unreach NLRI base class.
uint16_t afi
Address Family Identifier.
int start()
send OPEN message to peer. (IDLE -> OpenSent)
Definition: bgp-fsm.cc:118
bool hasCapability(uint8_t code) const
Check if open message has a capability.
bool dropNonTransitive()
Drop all non-transitive attributes from the update message.
uint32_t getAsn() const
Get local ASN.
Definition: bgp-fsm.cc:86
BgpState getState() const
Get current FSM state.
Definition: bgp-fsm.cc:114
An AS_PATH or AS4_PATH segment.
const char * bgp_update_error_str[12]
Error strings for BGP update message error subcodes.
Definition: bgp-errcode.cc:59
void getPrefix(uint8_t prefix[16]) const
Get prefix.
Definition: prefix6.cc:450
bool addNlri4(uint32_t prefix, uint8_t length)
Add NLRI route.
uint16_t getHoldTimer() const
Get the negotiated hold timer.
Definition: bgp-fsm.cc:102
uint8_t nexthop_linklocal[16]
Link-local IPv6 nexthop.
Definition: route-event.h:151
Prefix6 route
The prefix of this entry.
Definition: bgp-rib6.h:76
bool hasAttrib(uint8_t type) const
Test if update message has an attribute.
The BgpPacket class.
Definition: bgp-packet.h:26
std::vector< Prefix6 > * new_routes
Routes to add.
Definition: route-event.h:133
BgpRouteStatus status
Status of this entry.
Definition: bgp-rib.h:91
uint32_t getAsn() const
Get ASN.
std::vector< Prefix4 > * routes
Routes to withdraw.
Definition: route-event.h:106
uint32_t next_hop
The nexthop in network byte order.
const char * bgp_header_error_subcode_str[4]
Error strings for BGP header error subcodes.
Definition: bgp-errcode.cc:33
uint8_t safi
Subsequent Address Family Identifier.
BgpRib6 & getRib6() const
Get the IPv6 Routing Information Base.
Definition: bgp-fsm.cc:110
bool setAttribs(const std::vector< std::shared_ptr< BgpPathAttrib >> &attrs)
Replace the attributes list with another attribute list.
uint32_t ibgp_peer_asn
ASN of the IBGP peer if the originating session is a IBGP session.
Definition: route-event.h:159
uint32_t ibgp_peer_asn
ASN of the IBGP peer if the originating session is a IBGP session.
Definition: route-event.h:88
ssize_t write(uint8_t *to, size_t buf_sz) const
Serialize a BGP message.
Definition: bgp-packet.cc:128
bool addCapability(std::shared_ptr< BgpCapability > capability)
Add a capability.
bool downgradeAsPath()
Downgrade the AS_PATH to two octets flavor.
int resetSoft()
Perform a soft reset.
Definition: bgp-fsm.cc:313
int tick()
Tick the clock (Check for time-based events)
Definition: bgp-fsm.cc:290
The BgpUpdateMessage class.
const std::vector< BgpRib6Entry > * replaced_entries
Pointer to the route replacement entries vector.
Definition: route-event.h:139
MP-BGP UnreachNlri IPv6 class.
The RouteEvent base.
Definition: route-event.h:39