16 #include <arpa/inet.h> 20 const char* bgp_fsm_state_str[] = {
28 BgpFsm::BgpFsm(
const BgpConfig &config) : in_sink(config.use_4b_asn) {
29 this->config = config;
31 out_buffer = (uint8_t *) malloc(BGP_FSM_BUFFER_SIZE);
35 config.rev_bus->subscribe(
this);
36 }
else rev_bus_exist =
false;
39 clock =
new RealtimeClock();
46 if (!config.log_handler) {
47 logger =
new BgpLogHandler();
50 logger = config.log_handler;
54 in_sink.setLogger(logger);
57 rib4 =
new BgpRib4(logger);
65 rib6 =
new BgpRib6(logger);
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;
91 return config.router_id;
107 return rib4_local ? *rib4 : *(config.rib4);
111 return rib4_local ? *rib6 : *(config.rib6);
119 if (state == BROKEN) {
120 logger->log(ERROR,
"BgpFsm::start: FSM is broken, consider reset.\n");
125 logger->log(ERROR,
"BgpFsm::start: not in IDLE state.\n");
129 logger->log(DEBUG,
"BgpFsm::start: sending OPEN message to peer.\n");
131 uint16_t my_asn_2b = config.asn >= 0xffff ? 23456 : config.asn;
133 BgpOpenMessage msg(logger, config.use_4b_asn, my_asn_2b, config.hold_timer, config.router_id);
134 if (config.use_4b_asn) {
138 if (config.mp_bgp_ipv4) {
145 if (config.mp_bgp_ipv6) {
153 if(!writeMessage(msg))
return -1;
158 if (state == BROKEN) {
159 logger->log(ERROR,
"BgpFsm::stop: FSM is broken, consider reset.\n");
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");
169 logger->log(INFO,
"BgpFsm::stop: de-peering...\n");
175 if(!writeMessage(notify))
return -1;
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");
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");
193 if (!config.no_autotick) {
194 int tick_ret = tick();
195 if (tick_ret <= 0)
return tick_ret;
198 last_recv = clock->getTime();
200 int final_ret_val = -1;
203 while (in_sink.getBytesInSink() > 0) {
205 ssize_t poured = in_sink.pour(&packet);
208 logger->log(ERROR,
"BgpFsm::run: sink seems to be broken, please reset.\n");
213 if (poured == 0)
return 3;
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);
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");
236 BgpNotificationMessage notify (logger, msg->getErrorCode(), msg->getErrorSubCode(), msg->getError(), msg->getErrorLength());
238 if(!writeMessage(notify))
return -1;
243 if (msg->type == NOTIFICATION) {
254 logger->log(ERROR,
"BgpFsm::run: got NOTIFICATION: %s (%d): %s (%d).\n", err_msg, notify->
errcode, err_sub_msg, notify->
subcode);
262 int vald_ret = validateState(msg->type);
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;
274 logger->log(ERROR,
"BgpFsm::run: FSM in invalid state: %d.\n", state);
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;
287 return final_ret_val;
291 if (state != ESTABLISHED)
return 1;
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);
299 if(!writeMessage(notify))
return -1;
304 if (hold_timer > 0 && now - last_sent > hold_timer / 3) {
306 if(!writeMessage(keep))
return -1;
315 if(!writeMessage(notify))
return -1;
326 if (open_msg->version != 4) {
329 if(!writeMessage(notify))
return -1;
333 peer_asn = open_msg->
getAsn();
335 if (config.peer_asn != 0 && peer_asn != config.peer_asn) {
338 if(!writeMessage(notify))
return -1;
342 ibgp = config.asn == peer_asn;
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);
352 if(!writeMessage(notify))
return -1;
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);
361 if(!writeMessage(notify))
return -1;
365 if (!config.no_collision_detection && rev_bus_exist) {
367 col.peer_bgp_id = open_msg->bgp_id;
374 if(config.rev_bus->publish(
this, col) > 0) {
375 int res_result = resloveCollision(open_msg->bgp_id,
true);
377 if(res_result == -1)
return -1;
378 if(res_result == 0)
return 0;
381 if(res_result == 1) {
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" 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;
399 const std::vector<std::shared_ptr<BgpCapability>> &capabilities = open_msg->
getCapabilities();
401 for (
const std::shared_ptr<BgpCapability> &cap : capabilities) {
402 if (cap->code == MP_BGP) {
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;
410 send_ipv4_routes =
true && !(config.mp_bgp_ipv6 && !config.mp_bgp_ipv4);
411 send_ipv6_routes =
false;
417 int BgpFsm::resloveCollision(uint32_t peer_bgp_id,
bool is_new) {
419 if (ntohl(config.router_id) > ntohl(peer_bgp_id)) {
424 if(!writeMessage(notify))
return -1;
426 logger->log(INFO,
"(new_session) we have higher router id, dispose this new session.\n");
435 logger->log(INFO,
"(new_session) peer has higher router id, ask the other fsm to dispose session.\n");
439 if (ntohl(config.router_id) > ntohl(peer_bgp_id)) {
442 logger->log(INFO,
"(old_session) we have higher router id, keep this old session.\n");
449 logger->log(INFO,
"(old_session) peer has higher router id, dispose this session.\n");
451 if(!writeMessage(notify))
return -1;
460 logger->log(ERROR,
"BgpFsm::resloveCollison: ??? :( \n");
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));
475 if (state != OPEN_CONFIRM || peer_bgp_id != ev.peer_bgp_id)
return false;
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)));
480 return resloveCollision(ev.peer_bgp_id,
false) == 1;
484 if (state != ESTABLISHED)
return false;
485 if (!send_ipv6_routes)
return false;
492 logger->log(DEBUG,
"BgpFsm::handleRoute6AddEvent: got route-add event with %zu routes.\n", nroutes);
496 std::vector<Prefix6> routes;
499 alterNexthop6(nh_local, nh_global);
503 routes.push_back(route);
505 LIBBGP_LOG(logger, DEBUG) {
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());
515 if (routes.size() > 0) {
518 prepareUpdateMessage(update);
519 update.setNlri6(routes, nh_global, nh_local);
521 if(!writeMessage(update))
return false;
525 logger->log(DEBUG,
"BgpFsm::handleRoute6AddEvent: ignoring new_routes in add event since remote is IBGP.\n");
528 logger->log(DEBUG,
"BgpFsm::handleRoute6AddEvent: new_routes or shared_attribs is NULL.\n");
532 logger->log(DEBUG,
"BgpFsm::handleRoute6AddEvent: replaced_entries is NULL.\n");
538 if (entry.src_router_id == peer_bgp_id)
continue;
540 if (ibgp && entry.ibgp_peer_asn == peer_asn) {
541 LIBBGP_LOG(logger, DEBUG) {
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());
552 if (config.out_filters6.apply(entry.route, entry.attribs) !=
ACCEPT) {
553 LIBBGP_LOG(logger, DEBUG) {
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());
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;
580 if (state != ESTABLISHED)
return false;
581 if (!send_ipv6_routes)
return false;
582 if (ev.
routes == NULL)
return false;
584 logger->log(DEBUG,
"BgpFsm::handleRoute6WithdrawEvent: got route-withdraw event with %zu routes.\n", ev.
routes->size());
588 withdraw.setWithdrawn6(*(ev.
routes));
590 if(!writeMessage(withdraw))
return false;
595 if (state != ESTABLISHED)
return false;
596 if (!send_ipv4_routes)
return false;
603 logger->log(DEBUG,
"BgpFsm::handleRoute4AddEvent: got route-add event with %zu routes.\n", nroutes);
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());
623 if (update.nlri.size() > 0) {
624 alterNexthop4(update);
625 prepareUpdateMessage(update);
627 if(!writeMessage(update))
return false;
630 logger->log(DEBUG,
"BgpFsm::handleRoute4AddEvent: ignoring new_routes in add event since remote is IBGP.\n");
633 logger->log(DEBUG,
"BgpFsm::handleRoute4AddEvent: new_routes or shared_attribs is NULL.\n");
637 logger->log(DEBUG,
"BgpFsm::handleRoute4AddEvent: replaced_entries is NULL.\n");
643 if (entry.src_router_id == peer_bgp_id)
continue;
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());
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());
670 alterNexthop4(update);
671 prepareUpdateMessage(update);
672 if(!writeMessage(update))
return false;
679 if (state != ESTABLISHED)
return false;
680 if (!send_ipv4_routes)
return false;
681 if (ev.
routes == NULL)
return false;
683 logger->log(DEBUG,
"BgpFsm::handleRoute4AddEvent: got route-withdraw event with %zu routes.\n", ev.
routes->size());
688 if(!writeMessage(withdraw))
return false;
694 if (ibgp && !config.ibgp_alter_nexthop)
return;
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);
704 logger->log(INFO,
"BgpFsm::alterNexthop4: no nethop attribute set, using %s as nexthop.\n", ip_str);
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);
719 nh.
next_hop = config.default_nexthop4;
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);
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);
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);
738 nh_global = config.default_nexthop6_global;
739 nh_local = config.default_nexthop6_linklocal;
746 if (config.use_4b_asn && use_4b_asn) {
754 if (!ibgp) update.
prepend(config.asn);
757 int BgpFsm::validateState(uint8_t type) {
761 logger->log(ERROR,
"BgpFsm::validateState: got non-OPEN message in IDLE state.\n");
767 logger->log(ERROR,
"BgpFsm::validateState: got non-OPEN message in OPEN_SENT state.\n");
770 if(!writeMessage(notify))
return -1;
776 if (type != KEEPALIVE) {
777 logger->log(ERROR,
"BgpFsm::validateState: got non-KEEPALIVE message in OPEN_CONFIRM state.\n");
780 if(!writeMessage(notify))
return -1;
786 if (type != UPDATE && type != KEEPALIVE) {
787 logger->log(ERROR,
"BgpFsm::validateState: got invalid message (type %d) in ESTABLISHED state.\n", type);
790 if(!writeMessage(notify))
return -1;
796 logger->log(ERROR,
"BgpFsm::validateState: got message in bad state. consider reset.\n");
801 int BgpFsm::fsmEvalIdle(
const BgpMessage *msg) {
804 int retval = openRecv(open_msg);
805 if (retval != 1)
return retval;
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);
811 open_reply.
setAsn(config.asn);
814 if (config.mp_bgp_ipv4) {
818 open_reply.
addCapability(std::shared_ptr<BgpCapability>(cap));
821 if (config.mp_bgp_ipv6) {
825 open_reply.
addCapability(std::shared_ptr<BgpCapability>(cap));
828 setState(OPEN_CONFIRM);
829 if(!writeMessage(open_reply))
return -1;
834 int BgpFsm::fsmEvalOpenSent(
const BgpMessage *msg) {
837 int retval = openRecv(open_msg);
838 if (retval != 1)
return retval;
841 setState(OPEN_CONFIRM);
842 if(!writeMessage(keep))
return -1;
847 int BgpFsm::fsmEvalOpenConfirm(__attribute__((unused))
const BgpMessage *msg) {
849 setState(ESTABLISHED);
850 if(!writeMessage(keep))
return -1;
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();
858 while (iter != end) {
859 uint64_t cur_group_id = iter->second.update_id;
862 alterNexthop4(update);
863 prepareUpdateMessage(update);
866 size_t msg_len = 19 + 4;
868 for (
const std::shared_ptr<BgpPathAttrib> &attrib : update.path_attribute) {
869 msg_len += attrib->length();
872 for (; iter != end && cur_group_id == iter->second.update_id && msg_len < 4096; iter++) {
875 if (e.
status == RS_STANDBY)
continue;
878 LIBBGP_LOG(logger, DEBUG) {
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());
888 if (iter->second.src_router_id == peer_bgp_id) {
889 LIBBGP_LOG(logger, WARN) {
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());
898 if (config.out_filters4.apply(r, update.path_attribute) ==
ACCEPT) {
900 if (msg_len > 4096) {
907 LIBBGP_LOG(logger, DEBUG) {
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());
917 if (update.nlri.size() > 0) {
918 if(!writeMessage(update))
return -1;
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();
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;
935 prepareUpdateMessage(update);
936 std::vector<Prefix6> filtered_nlri;
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();
945 for (; iter != end && cur_group_id == iter->second.update_id && msg_len < 4096; iter++) {
948 if (e.
status != RS_ACTIVE)
continue;
950 LIBBGP_LOG(logger, DEBUG) {
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());
960 if (iter->second.src_router_id == peer_bgp_id) {
961 LIBBGP_LOG(logger, WARN) {
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());
972 if (config.out_filters6.apply(r, update.path_attribute) ==
ACCEPT) {
974 if (msg_len > 4096) {
979 filtered_nlri.push_back(r);
981 LIBBGP_LOG(logger, DEBUG) {
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());
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;
1004 int BgpFsm::fsmEvalEstablished(
const BgpMessage *msg) {
1005 if (msg->type == KEEPALIVE)
return 1;
1009 bool ignore_routes =
false;
1012 if (update->
hasAttrib(AS_PATH) && update->nlri.size() > 0) {
1016 int8_t local_count = 0;
1018 for (uint32_t asn : seg.
value) {
1019 if (asn == config.asn) local_count++;
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;
1028 }
else ignore_routes =
true;
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));
1043 if (update->nlri.size() > 0) {
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);
1052 ignore_routes =
true;
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());
1065 ignore_routes =
true;
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);
1076 LIBBGP_LOG(logger, DEBUG) {
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());
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);
1089 changed_entries.push_back(entry);
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());
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;
1099 aev.
new_routes = rslt.second.size() > 0 ? &(rslt.second) : NULL;
1101 config.rev_bus->publish(
this, aev);
1104 if (rev_bus_exist && unreach.size() > 0) {
1105 logger->log(DEBUG,
"BgpFsm::fsmEvalEstablished: publishing dropped v4 routes on event bus...\n");
1108 config.rev_bus->publish(
this, wev);
1113 if (send_ipv6_routes) {
1114 std::vector<Prefix6> unreach;
1115 std::vector<BgpRib6Entry> changed_entries;
1116 if (update->
hasAttrib(MP_UNREACH_NLRI)) {
1119 if (mp_unreach.
afi == IPV6 && mp_unreach.
safi == UNICAST) {
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));
1133 if (!ignore_routes && update->
hasAttrib(MP_REACH_NLRI)) {
1136 if (mp_reach.
afi == IPV6 && mp_reach.
safi == UNICAST) {
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);
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);
1151 if (filtered_routes.size() <= 0)
return 1;
1156 std::vector<std::shared_ptr<BgpPathAttrib>> attrs;
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);
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());
1167 changed_entries.push_back(e);
1170 if (rev_bus_exist && (changed_entries.size() > 0 || rslt.second.size() > 0)) {
1174 aev.
new_routes = rslt.second.size() > 0 ? &(rslt.second) : NULL;
1175 aev.
replaced_entries = changed_entries.size() > 0 ? &changed_entries : NULL;
1178 config.rev_bus->publish(
this, aev);
1181 if (rev_bus_exist && unreach.size() > 0) {
1182 logger->log(DEBUG,
"BgpFsm::fsmEvalEstablished: publishing dropped v6 routes on event bus...\n");
1185 config.rev_bus->publish(
this, wev);
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) {
1199 wev.
routes = &(rslt4.first);
1200 config.rev_bus->publish(
this, wev);
1202 if (rev_bus_exist && rslt4.second.size() > 0) {
1205 config.rev_bus->publish(
this, aev);
1207 std::pair<std::vector<Prefix6>, std::vector<BgpRib6Entry>> rslt6 = rib6->discard(peer_bgp_id);
1208 if (rev_bus_exist && rslt6.first.size() > 0) {
1210 wev.
routes = &(rslt6.first);
1211 config.rev_bus->publish(
this, wev);
1213 if (rev_bus_exist && rslt6.second.size() > 0) {
1216 config.rev_bus->publish(
this, aev);
1221 void BgpFsm::setState(
BgpState new_state) {
1222 if (state == new_state)
return;
1224 if (config.out_handler) config.out_handler->notifyStateChange(state, new_state);
1226 logger->log(INFO,
"BgpFsm::setState: changing state: %s -> %s\n", bgp_fsm_state_str[state], bgp_fsm_state_str[new_state]);
1228 if (state == ESTABLISHED) {
1229 logger->log(INFO,
"BgpFsm::setState: dropping all routes received from peer...\n");
1238 bool BgpFsm::validAddr4(uint32_t addr)
const {
1239 if (addr == config.default_nexthop4 || addr == config.router_id) {
1243 uint32_t addr_host = ntohl(addr);
1244 uint32_t first = addr_host >> 24;
1246 if (first == 0 || first == 127 || (first >= 224 && first <= 239) || first > 240) {
1253 bool BgpFsm::validAddr6(
const uint8_t addr[16])
const {
1254 static Prefix6 bad_range(
"0000::", 8);
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);
1266 std::lock_guard<std::recursive_mutex> lock(out_buffer_mutex);
1268 ssize_t pkt_len = pkt.
write(out_buffer, BGP_FSM_BUFFER_SIZE);
1269 last_sent = clock->getTime();
1272 logger->log(ERROR,
"BgpFsm::writeMessage: failed to write message, abort.\n");
1277 if (config.out_handler && !config.out_handler->handleOut(out_buffer, pkt_len)) {
1278 logger->log(ERROR,
"BgpFsm::writeMessage: out_handler failed, abort.\n");
std::vector< std::shared_ptr< BgpPathAttrib > > * shared_attribs
Path attribues of the route.
int run(const uint8_t *buffer, const size_t buffer_size)
Run the FSM on buffer.
uint8_t errcode
Notification message error code.
IPv6 Route/Prefix related utilities.
uint32_t getPrefix() const
Get prefix.
const std::vector< BgpRib4Entry > * replaced_entries
Pointer to the route replacement entries vector.
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.
BgpRib4 & getRib4() const
Get the IPv4 Routing Information Base.
const char * bgp_error_code_str[7]
Error strings for BGP error codes.
const std::vector< Prefix4 > * new_routes
Newly added routes.
The BgpOpenMessage class.
const std::vector< std::shared_ptr< BgpPathAttrib > > * shared_attribs
Shared attributes for the new routes.
std::vector< uint32_t > value
The segment value.
RouteEventType type
Type of this event.
MP-BGP ReachNlri IPv6 NLRI class.
The BGP Finite State Machine.
int stop()
Stop the FSM. (Any -> Idle)
Prefix4 route
The prefix of this entry.
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.
The BgpCapabilityMpBgp class.
uint32_t getPeerAsn() const
Get peer ASN.
void resetHard()
Perform a hard reset.
uint8_t getLength() const
Get netmask.
The BgpNotificationMessage object.
Probe for collision detection.
uint16_t afi
Address Family Identifier.
const BgpMessage * getMessage() const
Get pointer to the contained message.
BgpState
BGP Finite State Machine status.
uint32_t getPeerBgpId() const
Get peer BGP ID.
std::vector< BgpAsPathSegment > as_paths
The AS Path segments.
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.
bool includes(const uint8_t address[16]) const
Test if an address is inside this prefix.
BgpRouteSource src
Source of this entry.
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.
const char * bgp_fsm_error_str[4]
Error strings for BGP FSM error subcodes.
uint8_t nexthop_global[16]
Global IPv6 nexthop.
uint32_t ibgp_peer_asn
ASN of the IBGP peer. (Valid iff src == SRC_IBGP)
The BgpMessage base class.
const char * bgp_cease_error_str[9]
Error strings for BGP cease error subcodes.
IPv4 Route/Prefix related utilities.
bool v6addr_is_zero(const uint8_t prefix[16])
Test if a IPv6 addresss is all zero.
Buffer operation helpers.
The BgpRib6 (IPv6 BGP Routing Information Base) class.
uint8_t safi
Subsequent Address Family Identifier.
The BgpKeepaliveMessage class.
const char * bgp_open_error_subcode_str[8]
Error strings for BGP open message error subcodes.
A Clock implementation to use system time as time.
MP-BGP Reach/Unreach NLRI base class.
uint16_t afi
Address Family Identifier.
int start()
send OPEN message to peer. (IDLE -> OpenSent)
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.
BgpState getState() const
Get current FSM state.
An AS_PATH or AS4_PATH segment.
const char * bgp_update_error_str[12]
Error strings for BGP update message error subcodes.
void getPrefix(uint8_t prefix[16]) const
Get prefix.
bool addNlri4(uint32_t prefix, uint8_t length)
Add NLRI route.
uint16_t getHoldTimer() const
Get the negotiated hold timer.
uint8_t nexthop_linklocal[16]
Link-local IPv6 nexthop.
Prefix6 route
The prefix of this entry.
bool hasAttrib(uint8_t type) const
Test if update message has an attribute.
std::vector< Prefix6 > * new_routes
Routes to add.
BgpRouteStatus status
Status of this entry.
uint32_t getAsn() const
Get ASN.
std::vector< Prefix4 > * routes
Routes to withdraw.
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.
uint8_t safi
Subsequent Address Family Identifier.
BgpRib6 & getRib6() const
Get the IPv6 Routing Information Base.
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.
uint32_t ibgp_peer_asn
ASN of the IBGP peer if the originating session is a IBGP session.
ssize_t write(uint8_t *to, size_t buf_sz) const
Serialize a BGP message.
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.
int tick()
Tick the clock (Check for time-based events)
The BgpUpdateMessage class.
const std::vector< BgpRib6Entry > * replaced_entries
Pointer to the route replacement entries vector.
MP-BGP UnreachNlri IPv6 class.