diff options
Diffstat (limited to 'bgpd')
-rw-r--r-- | bgpd/ChangeLog | 198 | ||||
-rw-r--r-- | bgpd/bgp_aspath.c | 20 | ||||
-rw-r--r-- | bgpd/bgp_aspath.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_damp.c | 19 | ||||
-rw-r--r-- | bgpd/bgp_debug.c | 61 | ||||
-rw-r--r-- | bgpd/bgp_debug.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 127 | ||||
-rw-r--r-- | bgpd/bgp_fsm.h | 43 | ||||
-rw-r--r-- | bgpd/bgp_main.c | 12 | ||||
-rw-r--r-- | bgpd/bgp_nexthop.c | 4 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 40 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 901 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 13 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 142 | ||||
-rw-r--r-- | bgpd/bgpd.c | 110 | ||||
-rw-r--r-- | bgpd/bgpd.h | 15 |
17 files changed, 1429 insertions, 282 deletions
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog index 13d6777a..236c0b77 100644 --- a/bgpd/ChangeLog +++ b/bgpd/ChangeLog @@ -1,3 +1,201 @@ +2006-12-07 Paul Jakma <paul.jakma@sun.com> + + * bgp_fsm.c: Bug #302 fix, diagnosis, suggestions and testing + by Juergen Kammer <j.kammer@eurodata.de>. Fix follows from + his suggested fix, just made in a slightly different way. + (bgp_event) Transitions into Clearing always must call + bgp_clear_route_all(). + (bgp_stop) No need to clear routes here, BGP FSM should do + it. + +2006-11-30 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + + * bgp_debug.h: Declare new bgp_debug_zebra conf and term flags, + and define BGP_DEBUG_ZEBRA. + * bgp_debug.c: Declare conf_bgp_debug_zebra and term_bgp_debug_zebra. + (debug_bgp_zebra, no_debug_bgp_zebra, undebug_bgp_zebra) New + functions to enable/disable bgp zebra debugging. + (no_debug_bgp_all) Turn off zebra debugging. + (show_debugging_bgp) Show whether zebra debugging is on. + (bgp_config_write_debug) Add 'debug bgp zebra' if configured. + (bgp_debug_init) Add new zebra debugging commands. + * bgp_zebra.c: (bgp_router_id_update, bgp_interface_add, + bgp_interface_delete, bgp_interface_up, bgp_interface_down, + bgp_interface_address_add, bgp_interface_address_delete, + zebra_read_ipv4, zebra_read_ipv6, bgp_zebra_announce, + bgp_zebra_withdraw, bgp_redistribute_set, bgp_redistribute_unset) + If zebra debugging is enabled, log an appropriate debug message. + +2006-11-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + + * bgp_route.c: (bgp_info_restore) New function that undoes + the effects of a previous call to bgp_info_delete. This is + used when a route is deleted and quickly re-added before the + deletion has been processed. + (bgp_static_update_rsclient, bgp_static_update_main, + bgp_redistribute_add) Check whether a pre-existing route + has the BGP_INFO_REMOVED set, and, if so, we need to call + bgp_info_restore to resurrect it. + +2006-10-27 Paul Jakma <paul.jakma@sun.com> + + * bgp_route.c: (bgp_table_stats) oops, u_intXX_t should be + uintXX_t + +2006-10-19 Paul Jakma <paul.jakma@sun.com> + + * bgpd.c: (peer_new) bgp element of peer absolutely must be + filled in, make peer_new() require it as argument and update + all callers. Fixes a crash reported by Jan 'yanek' Bortl and + Andrew Schorr where bgpd would crash in bgp_pcount_adjust + trying to dereference the bgp member of bgp->peer_self, + triggered through redistribution. + * bgp_route.c: (bgp_pcount_adjust) assert sanity of arguments. + +2006-10-15 Paul Jakma <paul.jakma@sun.com> + + * bgp_route.c: (bgp_table_stats_walker) NULL deref if table is + empty, bgp_table_top may return NULL, Coverity CID#73. + * bgp_packet.c: (bgp_update_packet) adv->rn can not be NULL, + check is bogus - changed to assert(), CID#64. + binfo is checked for NULL, but then dereferenced + unconditionally, fix, CID #63. + (bgp_withdraw_packet) Assert adv->rn is valid, as with + bgp_update_packet(). + +2006-10-14 Paul Jakma <paul.jakma@sun.com> + + * bgp_fsm.h: Remove BGP_EVENT_FLUSH_ADD, dangerous and not + needed. + * bgp_fsm.c: (bgp_stop) Move BGP_EVENT_FLUSH to the top of the + of the function, otherwise it could flush a ClearingCompleted + event, bug #302. + * bgp_packet.c: Replace all BGP_EVENT_FLUSH_ADD with + BGP_EVENT_ADD, fixing bug #302. + +2006-09-19 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + + * bgpd.c: (peer_uptime) Fix printf format/arg mismatch in + zlog_warn message (%ld/size_t -> %lu/u_long). + +2006-09-14 Paul Jakma <paul.jakma@sun.com> + + * bgp_route.c: (bgp_table_stats_walker) Address space announced + should only count top-level unaggregateable prefixes, to + avoid falling afoul of anti-dodgy-accounting regulations + in various jurisdictions.. ;) + (bgp_process_queue_init) process queue hold time too high, + adds extra memory load. Change to be much lower, until such + time as it's made configurable. + +2006-09-14 Paul Jakma <paul.jakma@sun.com> + + * (general) fix the peer refcount issue exposed by previous, by + just removing refcounting of peer threads, which is mostly + senseless as they're references leading from struct peer, + which peer_free cancels anyway. No need to muck around.. + * bgp_fsm.h: Just remove the refcounting from the various + TIMER/READ/WRITE/EVENT ON/OFF/ADD macros. + * bgp_fsm.c: (bgp_stop) use BGP_EVENT_FLUSH, no refcounts attached + to events anymore. + (bgp_event) remove peer_unlock, events not refcounted. + * bgpd.c: (peer_free) flush events before free. + +2006-09-14 Paul Jakma <paul.jakma@sun.com> + + * (general) Fix some niggly issues around 'shutdown' and clearing + by adding a Clearing FSM wait-state and a hidden 'Deleted' + FSM state, to allow deleted peers to 'cool off' and hit 0 + references. This introduces a slow memory leak of struct peer, + however that's more a testament to the fragility of the + reference counting than a bug in this patch, cleanup of + reference counting to fix this is to follow. + * bgpd.h: Add Clearing, Deleted states and Clearing_Completed + and event. + * bgp_debug.c: (bgp_status_msg[]) Add strings for Clearing and + Deleted. + * bgp_fsm.h: Don't allow timer/event threads to set anything + for Deleted peers. + * bgp_fsm.c: (bgp_timer_set) Add Clearing and Deleted. Deleted + needs to stop everything. + (bgp_stop) Remove explicit fsm_change_status call, the + general framework handles the transition. + (bgp_start) Log a warning if a start is attempted on a peer + that should stay down, trying to start a peer. + (struct .. FSM) Add Clearing_Completed + events, has little influence except when in state + Clearing to signal wait-state can end. + Add Clearing and Deleted states, former is a wait-state, + latter is a placeholder state to allow peers to disappear + quietly once refcounts settle. + (bgp_event) Try reduce verbosity of FSM state-change debug, + changes to same state are not interesting (Established->Established) + Allow NULL action functions in FSM. + * bgp_packet.c: (bgp_write) Use FSM events, rather than trying + to twiddle directly with FSM state behind the back of FSM. + (bgp_write_notify) ditto. + (bgp_read) Remove the vague ACCEPT_PEER peer_unlock, or else + this patch crashes, now it leaks instead. + * bgp_route.c: (bgp_clear_node_complete) Clearing_Completed + event, to end clearing. + (bgp_clear_route) See extensive comments. + * bgpd.c: (peer_free) should only be called while in Deleted, + peer refcounting controls when peer_free is called. + bgp_sync_delete should be here, not in peer_delete. + (peer_delete) Initiate delete. + Transition to Deleted state manually. + When removing peer from indices that provide visibility of it, + take great care to be idempotent wrt the reference counting + of struct peer through those indices. + Use bgp_timer_set, rather than replicating. + Call to bgp_sync_delete isn't appropriate here, sync can be + referenced while shutting down and finishing deletion. + (peer_group_bind) Take care to be idempotent wrt list references + indexing peers. + +2006-09-13 Paul Jakma <paul.jakma@sun.com> + + * bgp_aspath.c: (aspath_highest) new, return highest ASN in an + aspath. + * bgp_route.c: (bgp_peer_count_walker) new, do the walk done + in bgp_peer_counts as a thread. + (bgp_peer_counts) move walk to previous and call it via + thread_execute so this RIB walk shows up in thread stats. + (bgp_table_stats) New, gather some statistics for a given + RIB. + (bgp_table_stats_walker) New, RIB walker thread for former. + (bgp_table_stats_vty) Parsing front-end for 'show bgp ...', + useful model for future rationalisation of 'show ... bgp'. + (bgp_route_init) Add new RIB stats commands. + +2006-09-06 Paul Jakma <paul.jakma@sun.com> + + * (general) Squash any and all prefix-count issues by + abstracting route flag changes, and maintaining count as and + when flags are modified (rather than relying on explicit + modifications of count being sprinkled in just the right + places throughout the code). + * bgp_route.c: (bgp_pcount_{dec,inc}rement) removed. + (bgp_pcount_adjust) new, update prefix count as + needed for a given route. + (bgp_info_{uns,s}et_flag) set/unset a BGP_INFO route status + flag, calling previous function when appropriate. + (general) Update all set/unsets of flags to use previous. + Remove pcount_{dec,inc}rement calls. + No need to unset BGP_INFO_VALID in places where + bgp_info_delete is called, it does that anyway. + * bgp_{damp,nexthop}.c: Update to use bgp_info_{un,}set_flag. + * bgp_route.h: Export bgp_info_{un,}set_flag. + Add a 'meta' BGP_INFO flag, BGP_INFO_UNUSEABLE. + Move BGP_INFO_HOLDDOWN macro to here from bgpd.h + +2006-09-03 Paul Jakma <paul.jakma@sun.com> + + * bgp_route.c: Add 'show ... bgp ... <neighbour> prefix-count' + commands, to provide detailed counts of prefixes for a peer. + Informative, and should help pin down to pfxcnt drift + problems. + 2006-08-27 Paul Jakma <paul.jakma@sun.com> * bgp_advertise.c: (bgp_sync_delete) fix mtype in XFREE. diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 317e9f8d..327406fa 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -434,6 +434,26 @@ aspath_size (struct aspath *aspath) return size; } +/* Return highest public ASN in path */ +as_t +aspath_highest (struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + as_t highest = 0; + unsigned int i; + + while (seg) + { + for (i = 0; i < seg->length; i++) + if (seg->as[i] > highest + && (seg->as[i] < BGP_PRIVATE_AS_MIN + || seg->as[i] > BGP_PRIVATE_AS_MAX)) + highest = seg->as[i]; + seg = seg->next; + } + return highest; +} + /* Convert aspath structure to string expression. */ static char * aspath_make_str_count (struct aspath *as) diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index bf23e5d6..5400c57c 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -87,6 +87,7 @@ extern unsigned long aspath_count (void); extern unsigned int aspath_count_hops (struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); extern unsigned int aspath_size (struct aspath *); +extern as_t aspath_highest (struct aspath *); extern void aspath_put (struct stream *, struct aspath *); /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */ diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index a2163a4f..8ba39b65 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -148,12 +148,12 @@ bgp_reuse_timer (struct thread *t) if (bdi->penalty < damp->reuse_limit) { /* Reuse the route. */ - UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED); bdi->suppress_time = 0; if (bdi->lastrecord == BGP_RECORD_UPDATE) { - UNSET_FLAG (bdi->binfo->flags, BGP_INFO_HISTORY); + bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY); bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo, bdi->afi, bdi->safi); bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi); @@ -223,11 +223,13 @@ bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, bdi->flap++; } + assert ((rn == bdi->rn) && (binfo == bdi->binfo)); + bdi->lastrecord = BGP_RECORD_WITHDRAW; bdi->t_updated = t_now; /* Make this route as historical status. */ - SET_FLAG (binfo->flags, BGP_INFO_HISTORY); + bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY); /* Remove the route from a reuse list if it is on one. */ if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)) @@ -245,7 +247,7 @@ bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, insert into reuse_list. */ if (bdi->penalty >= damp->suppress_value) { - SET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED); bdi->suppress_time = t_now; BGP_DAMP_LIST_DEL (damp, bdi); bgp_reuse_list_add (bdi); @@ -267,7 +269,7 @@ bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn, return BGP_DAMP_USED; t_now = time (NULL); - UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY); bdi->lastrecord = BGP_RECORD_UPDATE; bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty); @@ -278,7 +280,7 @@ bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn, else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) && (bdi->penalty < damp->reuse_limit) ) { - UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED); bgp_reuse_list_delete (bdi); BGP_DAMP_LIST_ADD (damp, bdi); bdi->suppress_time = 0; @@ -311,7 +313,7 @@ bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi) if (t_diff >= damp->max_suppress_time) { - UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); + bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_DAMPED); bgp_reuse_list_delete (bdi); BGP_DAMP_LIST_ADD (damp, bdi); bdi->penalty = damp->reuse_limit; @@ -358,8 +360,7 @@ bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw) else BGP_DAMP_LIST_DEL (damp, bdi); - UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); - UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED); if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) bgp_info_delete (bdi->rn, binfo); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 1b398ee8..1986b35b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -43,6 +43,7 @@ unsigned long conf_bgp_debug_filter; unsigned long conf_bgp_debug_keepalive; unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_normal; +unsigned long conf_bgp_debug_zebra; unsigned long term_bgp_debug_fsm; unsigned long term_bgp_debug_events; @@ -51,6 +52,7 @@ unsigned long term_bgp_debug_filter; unsigned long term_bgp_debug_keepalive; unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_normal; +unsigned long term_bgp_debug_zebra; /* messages for BGP-4 status */ struct message bgp_status_msg[] = @@ -62,6 +64,8 @@ struct message bgp_status_msg[] = { OpenSent, "OpenSent" }, { OpenConfirm, "OpenConfirm" }, { Established, "Established" }, + { Clearing, "Clearing" }, + { Deleted, "Deleted" }, }; int bgp_status_msg_max = BGP_STATUS_MAX; @@ -588,6 +592,49 @@ ALIAS (no_debug_bgp_normal, UNDEBUG_STR BGP_STR) +DEFUN (debug_bgp_zebra, + debug_bgp_zebra_cmd, + "debug bgp zebra", + DEBUG_STR + BGP_STR + "BGP Zebra messages\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (zebra, ZEBRA); + else + { + TERM_DEBUG_ON (zebra, ZEBRA); + vty_out (vty, "BGP zebra debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_zebra, + no_debug_bgp_zebra_cmd, + "no debug bgp zebra", + NO_STR + DEBUG_STR + BGP_STR + "BGP Zebra messages\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (zebra, ZEBRA); + else + { + TERM_DEBUG_OFF (zebra, ZEBRA); + vty_out (vty, "BGP zebra debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_zebra, + undebug_bgp_zebra_cmd, + "undebug bgp zebra", + UNDEBUG_STR + DEBUG_STR + BGP_STR + "BGP Zebra messages\n") + DEFUN (no_debug_bgp_all, no_debug_bgp_all_cmd, "no debug all bgp", @@ -603,6 +650,7 @@ DEFUN (no_debug_bgp_all, TERM_DEBUG_OFF (update, UPDATE_OUT); TERM_DEBUG_OFF (fsm, FSM); TERM_DEBUG_OFF (filter, FILTER); + TERM_DEBUG_OFF (zebra, ZEBRA); vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -640,6 +688,8 @@ DEFUN (show_debugging_bgp, vty_out (vty, " BGP fsm debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (filter, FILTER)) vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (zebra, ZEBRA)) + vty_out (vty, " BGP zebra debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -695,6 +745,12 @@ bgp_config_write_debug (struct vty *vty) write++; } + if (CONF_BGP_DEBUG (zebra, ZEBRA)) + { + vty_out (vty, "debug bgp zebra%s", VTY_NEWLINE); + write++; + } + return write; } @@ -726,6 +782,8 @@ bgp_debug_init (void) install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd); install_element (ENABLE_NODE, &debug_bgp_normal_cmd); install_element (CONFIG_NODE, &debug_bgp_normal_cmd); + install_element (ENABLE_NODE, &debug_bgp_zebra_cmd); + install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd); install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd); @@ -745,6 +803,9 @@ bgp_debug_init (void) install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd); install_element (ENABLE_NODE, &undebug_bgp_normal_cmd); install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd); + install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); install_element (ENABLE_NODE, &undebug_bgp_all_cmd); } diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index bc8acf93..eab95d09 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -63,6 +63,7 @@ extern unsigned long conf_bgp_debug_filter; extern unsigned long conf_bgp_debug_keepalive; extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_normal; +extern unsigned long conf_bgp_debug_zebra; extern unsigned long term_bgp_debug_fsm; extern unsigned long term_bgp_debug_events; @@ -71,6 +72,7 @@ extern unsigned long term_bgp_debug_filter; extern unsigned long term_bgp_debug_keepalive; extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_normal; +extern unsigned long term_bgp_debug_zebra; #define BGP_DEBUG_FSM 0x01 #define BGP_DEBUG_EVENTS 0x01 @@ -80,6 +82,7 @@ extern unsigned long term_bgp_debug_normal; #define BGP_DEBUG_UPDATE_IN 0x01 #define BGP_DEBUG_UPDATE_OUT 0x02 #define BGP_DEBUG_NORMAL 0x01 +#define BGP_DEBUG_ZEBRA 0x01 #define BGP_DEBUG_PACKET_SEND 0x01 #define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 770a7911..d704c297 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -68,6 +68,11 @@ bgp_start_jitter (int time) return ((rand () % (time + 1)) - (time / 2)); } +/* Check if suppress start/restart of sessions to peer. */ +#define BGP_PEER_START_SUPPRESSED(P) \ + (CHECK_FLAG ((P)->flags, PEER_FLAG_SHUTDOWN) \ + || CHECK_FLAG ((P)->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + /* Hook function called after bgp event is occered. And vty's neighbor command invoke this function after making neighbor structure. */ @@ -82,10 +87,7 @@ bgp_timer_set (struct peer *peer) /* First entry point of peer's finite state machine. In Idle status start timer is on unless peer is shutdown or peer is inactive. All other timer must be turned off */ - if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) - || CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW) - || CHECK_FLAG (peer->sflags, PEER_STATUS_CLEARING) - || ! peer_active (peer)) + if (BGP_PEER_START_SUPPRESSED (peer) || ! peer_active (peer)) { BGP_TIMER_OFF (peer->t_start); } @@ -197,6 +199,17 @@ bgp_timer_set (struct peer *peer) } BGP_TIMER_OFF (peer->t_asorig); break; + case Deleted: + BGP_TIMER_OFF (peer->t_gr_restart); + BGP_TIMER_OFF (peer->t_gr_stale); + BGP_TIMER_OFF (peer->t_pmax_restart); + case Clearing: + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_OFF (peer->t_connect); + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + BGP_TIMER_OFF (peer->t_routeadv); } } @@ -413,14 +426,15 @@ bgp_stop (struct peer *peer) { afi_t afi; safi_t safi; - unsigned int i; char orf_name[BUFSIZ]; + /* Delete all existing events of the peer */ + BGP_EVENT_FLUSH (peer); + /* Increment Dropped count. */ if (peer->status == Established) { peer->dropped++; - bgp_fsm_change_status (peer, Idle); /* bgp log-neighbor-changes of neighbor Down */ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) @@ -469,9 +483,6 @@ bgp_stop (struct peer *peer) /* Reset uptime. */ bgp_uptime_reset (peer); - /* Need of clear of peer. */ - bgp_clear_route_all (peer); - /* Reset peer synctime */ peer->synctime = 0; } @@ -488,11 +499,6 @@ bgp_stop (struct peer *peer) BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); - /* Delete all existing events of the peer, - and corresponding peer ref-count */ - for (i = thread_cancel_event (master, peer); i > 0; i--) - peer_unlock (peer); /* thread event reference */ - /* Stream reset. */ peer->packet_size = 0; @@ -625,6 +631,14 @@ bgp_start (struct peer *peer) { int status; + if (BGP_PEER_START_SUPPRESSED (peer)) + { + if (BGP_DEBUG (fsm, FSM)) + plog_err (peer->log, "%s [FSM] Trying to start suppressed peer" + " - this is never supposed to happen!", peer->host); + return -1; + } + /* Scrub some information that might be left over from a previous, * session */ @@ -903,6 +917,7 @@ struct { {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Connect */ @@ -919,6 +934,7 @@ struct { {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Active, */ @@ -935,6 +951,7 @@ struct { {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* OpenSent, */ @@ -951,6 +968,7 @@ struct { {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* OpenConfirm, */ @@ -967,22 +985,58 @@ struct { {bgp_establish, Established}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Established, */ - {bgp_ignore, Established}, /* BGP_Start */ - {bgp_stop, Idle}, /* BGP_Stop */ - {bgp_stop, Idle}, /* TCP_connection_open */ - {bgp_stop, Idle}, /* TCP_connection_closed */ - {bgp_ignore, Idle}, /* TCP_connection_open_failed */ - {bgp_stop, Idle}, /* TCP_fatal_error */ - {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ - {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ + {bgp_ignore, Established}, /* BGP_Start */ + {bgp_stop, Clearing}, /* BGP_Stop */ + {bgp_stop, Clearing}, /* TCP_connection_open */ + {bgp_stop, Clearing}, /* TCP_connection_closed */ + {bgp_ignore, Clearing}, /* TCP_connection_open_failed */ + {bgp_stop, Clearing}, /* TCP_fatal_error */ + {bgp_ignore, Clearing}, /* ConnectRetry_timer_expired */ + {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */ {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */ - {bgp_stop, Idle}, /* Receive_OPEN_message */ - {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */ - {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ - {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_stop, Clearing}, /* Receive_OPEN_message */ + {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */ + {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ + {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle}, /* Clearing_Completed */ + }, + { + /* Clearing, */ + {bgp_ignore, Clearing}, /* BGP_Start */ + {bgp_ignore, Clearing}, /* BGP_Stop */ + {bgp_ignore, Clearing}, /* TCP_connection_open */ + {bgp_ignore, Clearing}, /* TCP_connection_closed */ + {bgp_ignore, Clearing}, /* TCP_connection_open_failed */ + {bgp_ignore, Clearing}, /* TCP_fatal_error */ + {bgp_ignore, Clearing}, /* ConnectRetry_timer_expired */ + {bgp_ignore, Clearing}, /* Hold_Timer_expired */ + {bgp_ignore, Clearing}, /* KeepAlive_timer_expired */ + {bgp_ignore, Clearing}, /* Receive_OPEN_message */ + {bgp_ignore, Clearing}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Clearing}, /* Receive_UPDATE_message */ + {bgp_ignore, Clearing}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Idle }, /* Clearing_Completed */ + }, + { + /* Deleted, */ + {bgp_ignore, Deleted}, /* BGP_Start */ + {bgp_ignore, Deleted}, /* BGP_Stop */ + {bgp_ignore, Deleted}, /* TCP_connection_open */ + {bgp_ignore, Deleted}, /* TCP_connection_closed */ + {bgp_ignore, Deleted}, /* TCP_connection_open_failed */ + {bgp_ignore, Deleted}, /* TCP_fatal_error */ + {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */ + {bgp_ignore, Deleted}, /* Hold_Timer_expired */ + {bgp_ignore, Deleted}, /* KeepAlive_timer_expired */ + {bgp_ignore, Deleted}, /* Receive_OPEN_message */ + {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ + {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ + {bgp_ignore, Deleted}, /* Clearing_Completed */ }, }; @@ -1001,14 +1055,15 @@ static const char *bgp_event_str[] = "Receive_OPEN_message", "Receive_KEEPALIVE_message", "Receive_UPDATE_message", - "Receive_NOTIFICATION_message" + "Receive_NOTIFICATION_message", + "Clearing_Completed", }; /* Execute event process. */ int bgp_event (struct thread *thread) { - int ret; + int ret = 0; int event; int next; struct peer *peer; @@ -1019,26 +1074,32 @@ bgp_event (struct thread *thread) /* Logging this event. */ next = FSM [peer->status -1][event - 1].next_state; - if (BGP_DEBUG (fsm, FSM)) + if (BGP_DEBUG (fsm, FSM) && peer->status != next) plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host, bgp_event_str[event], LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)); /* Call function. */ - ret = (*(FSM [peer->status - 1][event - 1].func))(peer); + if (FSM [peer->status -1][event - 1].func) + ret = (*(FSM [peer->status - 1][event - 1].func))(peer); /* When function do not want proceed next job return -1. */ if (ret >= 0) { /* If status is changed. */ if (next != peer->status) - bgp_fsm_change_status (peer, next); - + { + /* Transition into Clearing must /always/ clear all routes.. */ + if (next == Clearing) + bgp_clear_route_all (peer); + + bgp_fsm_change_status (peer, next); + } + /* Make sure timer is set. */ bgp_timer_set (peer); } - peer_unlock (peer); /* bgp-event peer reference */ return ret; } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index e90f3b43..a749f8ea 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -25,67 +25,48 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Macro for BGP read, write and timer thread. */ #define BGP_READ_ON(T,F,V) \ do { \ - if (!T) \ - { \ - peer_lock (peer); \ - THREAD_READ_ON(master,T,F,peer,V); \ - } \ + if (!(T) && (peer->status != Deleted)) \ + THREAD_READ_ON(master,T,F,peer,V); \ } while (0) #define BGP_READ_OFF(T) \ do { \ if (T) \ - { \ - peer_unlock (peer); \ - THREAD_READ_OFF(T); \ - } \ + THREAD_READ_OFF(T); \ } while (0) #define BGP_WRITE_ON(T,F,V) \ do { \ - if (!T) \ - { \ - peer_lock (peer); \ - THREAD_WRITE_ON(master,(T),(F),peer,(V)); \ - } \ + if (!(T) && (peer->status != Deleted)) \ + THREAD_WRITE_ON(master,(T),(F),peer,(V)); \ } while (0) #define BGP_WRITE_OFF(T) \ do { \ if (T) \ - { \ - peer_unlock (peer); \ - THREAD_WRITE_OFF(T); \ - } \ + THREAD_WRITE_OFF(T); \ } while (0) #define BGP_TIMER_ON(T,F,V) \ do { \ - if (!T) \ - { \ - peer_lock (peer); \ - THREAD_TIMER_ON(master,(T),(F),peer,(V)); \ - } \ + if (!(T) && (peer->status != Deleted)) \ + THREAD_TIMER_ON(master,(T),(F),peer,(V)); \ } while (0) #define BGP_TIMER_OFF(T) \ do { \ if (T) \ - { \ - peer_unlock (peer); \ - THREAD_TIMER_OFF(T); \ - } \ + THREAD_TIMER_OFF(T); \ } while (0) #define BGP_EVENT_ADD(P,E) \ do { \ - peer_lock (peer); /* bgp event reference */ \ - thread_add_event (master, bgp_event, (P), (E)); \ + if ((P)->status != Deleted) \ + thread_add_event (master, bgp_event, (P), (E)); \ } while (0) -#define BGP_EVENT_DELETE(P) \ +#define BGP_EVENT_FLUSH(P) \ do { \ - peer_unlock (peer); /* bgp event peer reference */ \ assert (peer); \ thread_cancel_event (master, (P)); \ } while (0) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 0baae3bf..ecfe62ef 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -50,6 +50,7 @@ struct option longopts[] = { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, + { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { 0 } }; @@ -141,6 +142,7 @@ redistribution between different routing protocols.\n\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ +-C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); @@ -196,6 +198,7 @@ main (int argc, char **argv) char *p; int opt; int daemon_mode = 0; + int dryrun = 0; char *progname; struct thread thread; @@ -214,7 +217,7 @@ main (int argc, char **argv) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:hp:A:P:rnu:g:v", longopts, 0); + opt = getopt_long (argc, argv, "df:i:hp:A:P:rnu:g:vC", longopts, 0); if (opt == EOF) break; @@ -265,6 +268,9 @@ main (int argc, char **argv) print_version (progname); exit (0); break; + case 'C': + dryrun = 1; + break; case 'h': usage (progname, 0); break; @@ -294,6 +300,10 @@ main (int argc, char **argv) /* Parse config file. */ vty_read_config (config_file, config_default); + /* Start execution only if not in dry-run mode */ + if(dryrun) + return(0); + /* Turn into daemon if daemon_mode is set. */ if (daemon_mode) daemon (0, 0); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index ea707ccb..bfc41a18 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -478,11 +478,11 @@ bgp_scan (afi_t afi, safi_t safi) { bgp_aggregate_decrement (bgp, &rn->p, bi, afi, SAFI_UNICAST); - UNSET_FLAG (bi->flags, BGP_INFO_VALID); + bgp_info_unset_flag (rn, bi, BGP_INFO_VALID); } else { - SET_FLAG (bi->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, bi, BGP_INFO_VALID); bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 8b024a1c..9859e50b 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -158,14 +158,14 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) while (adv) { - if (adv->rn) - rn = adv->rn; + assert (adv->rn); + rn = adv->rn; adj = adv->adj; if (adv->binfo) binfo = adv->binfo; /* When remaining space can't include NLRI and it's length. */ - if (rn && STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) + if (STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) break; /* If packet is empty, set attribute. */ @@ -173,11 +173,15 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) { struct prefix_rd *prd = NULL; u_char *tag = NULL; + struct peer *from = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; if (binfo) - tag = binfo->tag; + { + tag = binfo->tag; + from = binfo->peer; + } bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); @@ -186,7 +190,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, &rn->p, afi, safi, - binfo->peer, prd, tag); + from, prd, tag); stream_putw_at (s, pos, total_attr_len); } @@ -288,6 +292,7 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { + assert (adv->rn); adj = adv->adj; rn = adv->rn; @@ -637,9 +642,7 @@ bgp_write (struct thread *thread) if (write_errno == EWOULDBLOCK || write_errno == EAGAIN) break; - BGP_EVENT_ADD (peer, BGP_Stop); - peer->status = Idle; - bgp_timer_set (peer); + BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } if (num != writenum) @@ -673,10 +676,8 @@ bgp_write (struct thread *thread) if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); + /* Flush any existing events */ BGP_EVENT_ADD (peer, BGP_Stop); - /*bgp_stop (peer);*/ - peer->status = Idle; - bgp_timer_set (peer); return 0; case BGP_MSG_KEEPALIVE: peer->keepalive_out++; @@ -721,9 +722,7 @@ bgp_write_notify (struct peer *peer) ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); if (ret <= 0) { - BGP_EVENT_ADD (peer, BGP_Stop); - peer->status = Idle; - bgp_timer_set (peer); + BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } @@ -743,10 +742,7 @@ bgp_write_notify (struct peer *peer) if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); - /* We don't call event manager at here for avoiding other events. */ - bgp_stop (peer); - peer->status = Idle; - bgp_timer_set (peer); + BGP_EVENT_ADD (peer, BGP_Stop); return 0; } @@ -2375,14 +2371,6 @@ bgp_read (struct thread *thread) if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host); peer_delete (peer); - /* we've lost track of a reference to ACCEPT_PEER somehow. It doesnt - * _seem_ to be the 'update realpeer with accept peer' hack, yet it - * *must* be.. Very very odd, but I give up trying to - * root cause this - ACCEPT_PEER is a dirty hack, it should be fixed - * instead, which would make root-causing this a moot point.. - * A hack because of a hack, appropriate. - */ - peer_unlock (peer); /* god knows what reference... ACCEPT_PEER sucks */ } return 0; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 20276b49..8216fd4e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -187,12 +187,87 @@ bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri) void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri) { - /* leave info in place for now in place for now, - * bgp_process will reap it later. */ - SET_FLAG (ri->flags, BGP_INFO_REMOVED); + bgp_info_set_flag (rn, ri, BGP_INFO_REMOVED); + /* set of previous already took care of pcount */ UNSET_FLAG (ri->flags, BGP_INFO_VALID); } +/* undo the effects of a previous call to bgp_info_delete; typically + called when a route is deleted and then quickly re-added before the + deletion has been processed */ +static void +bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri) +{ + bgp_info_unset_flag (rn, ri, BGP_INFO_REMOVED); + /* unset of previous already took care of pcount */ + SET_FLAG (ri->flags, BGP_INFO_VALID); +} + +/* Adjust pcount as required */ +static void +bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) +{ + assert (rn && rn->table); + assert (ri && ri->peer && ri->peer->bgp); + + /* Ignore 'pcount' for RS-client tables */ + if (rn->table->type != BGP_TABLE_MAIN + || ri->peer == ri->peer->bgp->peer_self) + return; + + if (BGP_INFO_HOLDDOWN (ri) + && CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) + { + + UNSET_FLAG (ri->flags, BGP_INFO_COUNTED); + + /* slight hack, but more robust against errors. */ + if (ri->peer->pcount[rn->table->afi][rn->table->safi]) + ri->peer->pcount[rn->table->afi][rn->table->safi]--; + else + { + zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s", + __func__, ri->peer->host); + zlog_backtrace (LOG_WARNING); + zlog_warn ("%s: Please report to Quagga bugzilla", __func__); + } + } + else if (!BGP_INFO_HOLDDOWN (ri) + && !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) + { + SET_FLAG (ri->flags, BGP_INFO_COUNTED); + ri->peer->pcount[rn->table->afi][rn->table->safi]++; + } +} + + +/* Set/unset bgp_info flags, adjusting any other state as needed. + * This is here primarily to keep prefix-count in check. + */ +void +bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) +{ + SET_FLAG (ri->flags, flag); + + /* early bath if we know it's not a flag that changes useability state */ + if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) + return; + + bgp_pcount_adjust (rn, ri); +} + +void +bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) +{ + UNSET_FLAG (ri->flags, flag); + + /* early bath if we know it's not a flag that changes useability state */ + if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) + return; + + bgp_pcount_adjust (rn, ri); +} + /* Get MED value. If MED value is missing and "bgp bestpath missing-as-worst" is specified, treat it as the worst value. */ static u_int32_t @@ -1235,15 +1310,15 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair * { if (bgp_info_cmp (bgp, ri2, new_select)) { - UNSET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED); + bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; } - SET_FLAG (ri2->flags, BGP_INFO_DMED_CHECK); + bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK); } } - SET_FLAG (new_select->flags, BGP_INFO_DMED_CHECK); - SET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED); + bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK); + bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED); } /* Check old selected route and new selected route. */ @@ -1269,11 +1344,11 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair * if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))) { - UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK); + bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); continue; } - UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK); - UNSET_FLAG (ri->flags, BGP_INFO_DMED_SELECTED); + bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); + bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED); if (bgp_info_cmp (bgp, ri, new_select)) new_select = ri; @@ -1367,11 +1442,11 @@ bgp_process_rsclient (struct work_queue *wq, void *data) continue; if (old_select) - UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { - SET_FLAG (new_select->flags, BGP_INFO_SELECTED); - UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); } bgp_process_announce_selected (rsclient, new_select, rn, &attr, @@ -1381,11 +1456,11 @@ bgp_process_rsclient (struct work_queue *wq, void *data) else { if (old_select) - UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { - SET_FLAG (new_select->flags, BGP_INFO_SELECTED); - UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); } bgp_process_announce_selected (rsclient, new_select, rn, &attr, afi, safi); @@ -1433,11 +1508,11 @@ bgp_process_main (struct work_queue *wq, void *data) } if (old_select) - UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { - SET_FLAG (new_select->flags, BGP_INFO_SELECTED); - UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); } @@ -1504,7 +1579,7 @@ bgp_process_queue_init (void) bm->process_main_queue->spec.max_retries = bm->process_main_queue->spec.max_retries = 0; bm->process_rsclient_queue->spec.hold - = bm->process_main_queue->spec.hold = 500; + = bm->process_main_queue->spec.hold = 50; } void @@ -1636,43 +1711,6 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, return 0; } -static void -bgp_pcount_increment (struct bgp_node *rn, struct bgp_info *ri, - afi_t afi, safi_t safi) -{ - assert (ri && rn); - - if (!CHECK_FLAG (ri->flags, BGP_INFO_COUNTED) - && rn->table->type == BGP_TABLE_MAIN) - { - SET_FLAG (ri->flags, BGP_INFO_COUNTED); - ri->peer->pcount[afi][safi]++; - } -} - -static void -bgp_pcount_decrement (struct bgp_node *rn, struct bgp_info *ri, - afi_t afi, safi_t safi) -{ - /* Ignore 'pcount' for RS-client tables */ - if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED) - && rn->table->type == BGP_TABLE_MAIN) - { - UNSET_FLAG (ri->flags, BGP_INFO_COUNTED); - - /* slight hack, but more robust against errors. */ - if (ri->peer->pcount[afi][safi]) - ri->peer->pcount[afi][safi]--; - else - { - zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s", - __func__, ri->peer->host); - zlog_backtrace (LOG_WARNING); - zlog_warn ("%s: Please report to Quagga bugzilla", __func__); - } - } -} - /* Unconditionally remove the route from the RIB, without taking * damping into consideration (eg, because the session went down) */ @@ -1680,7 +1718,6 @@ static void bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, afi_t afi, safi_t safi) { - bgp_pcount_decrement (rn, ri, afi, safi); bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); if (!CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) @@ -1703,7 +1740,6 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0)) == BGP_DAMP_SUPPRESSED) { - bgp_pcount_decrement (rn, ri, afi, safi); bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); return; } @@ -1800,7 +1836,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, if (attrhash_cmp (ri->attr, attr_new)) { - UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, @@ -1823,7 +1859,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, p->prefixlen, rsclient->host); /* The attribute is changed. */ - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Update to new attribute. */ bgp_attr_unintern (ri->attr); @@ -1833,7 +1869,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, if (safi == SAFI_MPLS_VPN) memcpy (ri->tag, tag, 3); - SET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); /* Process change. */ bgp_process (bgp, rn, afi, safi); @@ -1863,7 +1899,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, if (safi == SAFI_MPLS_VPN) memcpy (new->tag, tag, 3); - SET_FLAG (new->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Register new BGP information. */ bgp_info_add (rn, new); @@ -2044,7 +2080,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Same attribute comes in. */ if (attrhash_cmp (ri->attr, attr_new)) { - UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer_sort (peer) == BGP_PEER_EBGP @@ -2056,8 +2092,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); - bgp_pcount_increment (rn, ri, afi, safi); - if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { bgp_aggregate_increment (bgp, p, ri, afi, safi); @@ -2076,8 +2110,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) { - UNSET_FLAG (ri->flags, BGP_INFO_STALE); - bgp_pcount_increment (rn, ri, afi, safi); + bgp_info_unset_flag (rn, ri, BGP_INFO_STALE); bgp_process (bgp, rn, afi, safi); } } @@ -2096,15 +2129,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) - UNSET_FLAG (ri->flags, BGP_INFO_STALE); + bgp_info_unset_flag (rn, ri, BGP_INFO_STALE); /* The attribute is changed. */ - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* implicit withdraw, decrement aggregate and pcount here. * only if update is accepted, they'll increment below. */ - bgp_pcount_decrement (rn, ri, afi, safi); bgp_aggregate_decrement (bgp, p, ri, afi, safi); /* Update bgp route dampening information. */ @@ -2146,15 +2178,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) - SET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else - UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } else - SET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); /* Process change. */ - bgp_pcount_increment (rn, ri, afi, safi); bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); @@ -2191,15 +2222,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) - SET_FLAG (new->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, new, BGP_INFO_VALID); else - UNSET_FLAG (new->flags, BGP_INFO_VALID); + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } else - SET_FLAG (new->flags, BGP_INFO_VALID); + bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Increment prefix */ - bgp_pcount_increment (rn, new, afi, safi); bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ @@ -2566,13 +2596,8 @@ bgp_clear_route_node (struct work_queue *wq, void *data) if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) && peer->nsf[afi][safi] && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE) - && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) - && ! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED) - && ! CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)) - { - bgp_pcount_decrement (rn, ri, afi, safi); - SET_FLAG (ri->flags, BGP_INFO_STALE); - } + && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + bgp_info_set_flag (rn, ri, BGP_INFO_STALE); else bgp_rib_remove (rn, ri, peer, afi, safi); break; @@ -2607,11 +2632,10 @@ bgp_clear_node_complete (struct work_queue *wq) { struct peer *peer = wq->spec.data; - UNSET_FLAG (peer->sflags, PEER_STATUS_CLEARING); peer_unlock (peer); /* bgp_clear_node_complete */ /* Tickle FSM to start moving again */ - BGP_EVENT_ADD (peer, BGP_Start); + BGP_EVENT_ADD (peer, Clearing_Completed); } static void @@ -2673,9 +2697,10 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) if (peer->clear_node_queue == NULL) bgp_clear_node_queue_init (peer); - /* bgp_fsm.c will not bring CLEARING sessions out of Idle this - * protects against peers which flap faster than we can we clear, - * which could lead to: + /* bgp_fsm.c keeps sessions in state Clearing, not transitioning to + * Idle until it receives a Clearing_Completed event. This protects + * against peers which flap faster than we can we clear, which could + * lead to: * * a) race with routes from the new session being installed before * clear_route_node visits the node (to delete the route of that @@ -2684,11 +2709,8 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) * on the process_main queue. Fast-flapping could cause that queue * to grow and grow. */ - if (!CHECK_FLAG (peer->sflags, PEER_STATUS_CLEARING)) - { - SET_FLAG (peer->sflags, PEER_STATUS_CLEARING); - peer_lock (peer); /* bgp_clear_node_complete */ - } + if (!peer->clear_node_queue->thread) + peer_lock (peer); /* bgp_clear_node_complete */ if (safi != SAFI_MPLS_VPN) bgp_clear_route_table (peer, afi, safi, NULL, NULL); @@ -2704,11 +2726,37 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) bgp_clear_route_table (peer, afi, safi, NULL, rsclient); } - /* If no routes were cleared, nothing was added to workqueue, run the - * completion function now. + /* If no routes were cleared, nothing was added to workqueue, the + * completion function won't be run by workqueue code - call it here. + * + * Additionally, there is a presumption in FSM that clearing is only + * needed if peer state is Established - peers in pre-Established states + * shouldn't have any route-update state associated with them (in or out). + * + * We still get here from FSM through bgp_stop->clear_route_all in + * pre-Established though, so this is a useful sanity check to ensure + * the assumption above holds. + * + * At some future point, this check could be move to the top of the + * function, and do a quick early-return when state is + * pre-Established, avoiding above list and table scans. Once we're + * sure it is safe.. */ if (!peer->clear_node_queue->thread) bgp_clear_node_complete (peer->clear_node_queue); + else + { + /* clearing queue scheduled. Normal if in Established state + * (and about to transition out of it), but otherwise... + */ + if (peer->status != Established) + { + plog_err (peer->log, "%s [Error] State %s is not Established," + " but routes were cleared - bug!", + peer->host, LOOKUP (bgp_status_msg, peer->status)); + assert (peer->status == Established); + } + } } void @@ -3002,9 +3050,8 @@ bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient, /* Withdraw static BGP route from routing table. */ if (ri) { - UNSET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_process (bgp, rn, afi, safi); bgp_info_delete (rn, ri); + bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ @@ -3106,7 +3153,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, if (ri) { - if (attrhash_cmp (ri->attr, attr_new)) + if (attrhash_cmp (ri->attr, attr_new) && + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (attr_new); @@ -3116,9 +3164,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, else { /* The attribute is changed. */ - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ + if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, ri); bgp_attr_unintern (ri->attr); ri->attr = attr_new; ri->uptime = time (NULL); @@ -3213,7 +3263,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (ri) { - if (attrhash_cmp (ri->attr, attr_new)) + if (attrhash_cmp (ri->attr, attr_new) && + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (attr_new); @@ -3223,10 +3274,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, else { /* The attribute is changed. */ - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ - bgp_aggregate_decrement (bgp, p, ri, afi, safi); + if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, ri); + else + bgp_aggregate_decrement (bgp, p, ri, afi, safi); bgp_attr_unintern (ri->attr); ri->attr = attr_new; ri->uptime = time (NULL); @@ -3333,9 +3387,8 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, safi); - UNSET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_process (bgp, rn, afi, safi); bgp_info_delete (rn, ri); + bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ @@ -3382,9 +3435,8 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, safi); - UNSET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_process (bgp, rn, afi, safi); bgp_info_delete (rn, ri); + bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ @@ -4165,7 +4217,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, if (aggregate->summary_only) { ri->suppress++; - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } @@ -4368,7 +4420,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, if (aggregate->summary_only) { ri->suppress++; - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } /* as-set aggregate route generate origin, as path, @@ -4468,7 +4520,7 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, if (ri->suppress == 0) { - SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } } @@ -4494,9 +4546,8 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, /* Withdraw static BGP route from routing table. */ if (ri) { - UNSET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_process (bgp, rn, afi, safi); bgp_info_delete (rn, ri); + bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ @@ -5010,7 +5061,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, if (bi) { - if (attrhash_cmp (bi->attr, new_attr)) + if (attrhash_cmp (bi->attr, new_attr) && + !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { bgp_attr_unintern (new_attr); aspath_unintern (attr.aspath); @@ -5020,10 +5072,13 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, else { /* The attribute is changed. */ - SET_FLAG (bi->flags, BGP_INFO_ATTR_CHANGED); + bgp_info_set_flag (bn, bi, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ - bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); + if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) + bgp_info_restore(bn, bi); + else + bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); bgp_attr_unintern (bi->attr); bi->attr = new_attr; bi->uptime = time (NULL); @@ -5081,9 +5136,8 @@ bgp_redistribute_delete (struct prefix *p, u_char type) if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST); - UNSET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_process (bgp, rn, afi, SAFI_UNICAST); bgp_info_delete (rn, ri); + bgp_process (bgp, rn, afi, SAFI_UNICAST); } bgp_unlock_node (rn); } @@ -5110,9 +5164,8 @@ bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type) if (ri) { bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST); - UNSET_FLAG (ri->flags, BGP_INFO_VALID); - bgp_process (bgp, rn, afi, SAFI_UNICAST); bgp_info_delete (rn, ri); + bgp_process (bgp, rn, afi, SAFI_UNICAST); } } } @@ -8495,6 +8548,598 @@ peer_lookup_in_view (struct vty *vty, const char *view_name, return peer; } + +enum bgp_stats +{ + BGP_STATS_MAXBITLEN = 0, + BGP_STATS_RIB, + BGP_STATS_PREFIXES, + BGP_STATS_TOTPLEN, + BGP_STATS_UNAGGREGATEABLE, + BGP_STATS_MAX_AGGREGATEABLE, + BGP_STATS_AGGREGATES, + BGP_STATS_SPACE, + BGP_STATS_ASPATH_COUNT, + BGP_STATS_ASPATH_MAXHOPS, + BGP_STATS_ASPATH_TOTHOPS, + BGP_STATS_ASPATH_MAXSIZE, + BGP_STATS_ASPATH_TOTSIZE, + BGP_STATS_ASN_HIGHEST, + BGP_STATS_MAX, +}; + +static const char *table_stats_strs[] = +{ + [BGP_STATS_PREFIXES] = "Total Prefixes", + [BGP_STATS_TOTPLEN] = "Average prefix length", + [BGP_STATS_RIB] = "Total Advertisements", + [BGP_STATS_UNAGGREGATEABLE] = "Unaggregateable prefixes", + [BGP_STATS_MAX_AGGREGATEABLE] = "Maximum aggregateable prefixes", + [BGP_STATS_AGGREGATES] = "BGP Aggregate advertisements", + [BGP_STATS_SPACE] = "Address space advertised", + [BGP_STATS_ASPATH_COUNT] = "Advertisements with paths", + [BGP_STATS_ASPATH_MAXHOPS] = "Longest AS-Path (hops)", + [BGP_STATS_ASPATH_MAXSIZE] = "Largest AS-Path (bytes)", + [BGP_STATS_ASPATH_TOTHOPS] = "Average AS-Path length (hops)", + [BGP_STATS_ASPATH_TOTSIZE] = "Average AS-Path size (bytes)", + [BGP_STATS_ASN_HIGHEST] = "Highest public ASN", + [BGP_STATS_MAX] = NULL, +}; + +struct bgp_table_stats +{ + struct bgp_table *table; + unsigned long long counts[BGP_STATS_MAX]; +}; + +#if 0 +#define TALLY_SIGFIG 100000 +static unsigned long +ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) +{ + unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); + unsigned long res = (newtot * TALLY_SIGFIG) / count; + unsigned long ret = newtot / count; + + if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) + return ret + 1; + else + return ret; +} +#endif + +static int +bgp_table_stats_walker (struct thread *t) +{ + struct bgp_node *rn; + struct bgp_node *top; + struct bgp_table_stats *ts = THREAD_ARG (t); + unsigned int space = 0; + + if (!(top = bgp_table_top (ts->table))) + return 0; + + switch (top->p.family) + { + case AF_INET: + space = IPV4_MAX_BITLEN; + break; + case AF_INET6: + space = IPV6_MAX_BITLEN; + break; + } + + ts->counts[BGP_STATS_MAXBITLEN] = space; + + for (rn = top; rn; rn = bgp_route_next (rn)) + { + struct bgp_info *ri; + struct bgp_node *prn = rn->parent; + unsigned int rinum = 0; + + if (rn == top) + continue; + + if (!rn->info) + continue; + + ts->counts[BGP_STATS_PREFIXES]++; + ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen; + +#if 0 + ts->counts[BGP_STATS_AVGPLEN] + = ravg_tally (ts->counts[BGP_STATS_PREFIXES], + ts->counts[BGP_STATS_AVGPLEN], + rn->p.prefixlen); +#endif + + /* check if the prefix is included by any other announcements */ + while (prn && !prn->info) + prn = prn->parent; + + if (prn == NULL || prn == top) + { + ts->counts[BGP_STATS_UNAGGREGATEABLE]++; + /* announced address space */ + if (space) + ts->counts[BGP_STATS_SPACE] += 1 << (space - rn->p.prefixlen); + } + else if (prn->info) + ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; + + for (ri = rn->info; ri; ri = ri->next) + { + rinum++; + ts->counts[BGP_STATS_RIB]++; + + if (ri->attr && + (CHECK_FLAG (ri->attr->flag, + ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)))) + ts->counts[BGP_STATS_AGGREGATES]++; + + /* as-path stats */ + if (ri->attr && ri->attr->aspath) + { + unsigned int hops = aspath_count_hops (ri->attr->aspath); + unsigned int size = aspath_size (ri->attr->aspath); + as_t highest = aspath_highest (ri->attr->aspath); + + ts->counts[BGP_STATS_ASPATH_COUNT]++; + + if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS]) + ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops; + + if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE]) + ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size; + + ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; + ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; +#if 0 + ts->counts[BGP_STATS_ASPATH_AVGHOPS] + = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], + ts->counts[BGP_STATS_ASPATH_AVGHOPS], + hops); + ts->counts[BGP_STATS_ASPATH_AVGSIZE] + = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], + ts->counts[BGP_STATS_ASPATH_AVGSIZE], + size); +#endif + if (highest > ts->counts[BGP_STATS_ASN_HIGHEST]) + ts->counts[BGP_STATS_ASN_HIGHEST] = highest; + } + } + } + return 0; +} + +static int +bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct bgp_table_stats ts; + unsigned int i; + + if (!bgp->rib[afi][safi]) + { + vty_out (vty, "%% No RIB exist for the AFI/SAFI%s", VTY_NEWLINE); + return CMD_WARNING; + } + + memset (&ts, 0, sizeof (ts)); + ts.table = bgp->rib[afi][safi]; + thread_execute (bm->master, bgp_table_stats_walker, &ts, 0); + + vty_out (vty, "BGP %s RIB statistics%s%s", + afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE); + + for (i = 0; i < BGP_STATS_MAX; i++) + { + if (!table_stats_strs[i]) + continue; + + switch (i) + { +#if 0 + case BGP_STATS_ASPATH_AVGHOPS: + case BGP_STATS_ASPATH_AVGSIZE: + case BGP_STATS_AVGPLEN: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12.2f", + (float)ts.counts[i] / (float)TALLY_SIGFIG); + break; +#endif + case BGP_STATS_ASPATH_TOTHOPS: + case BGP_STATS_ASPATH_TOTSIZE: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12.2f", + ts.counts[i] ? + (float)ts.counts[i] / + (float)ts.counts[BGP_STATS_ASPATH_COUNT] + : 0); + break; + case BGP_STATS_TOTPLEN: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12.2f", + ts.counts[i] ? + (float)ts.counts[i] / + (float)ts.counts[BGP_STATS_PREFIXES] + : 0); + break; + case BGP_STATS_SPACE: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12llu%s", ts.counts[i], VTY_NEWLINE); + if (ts.counts[BGP_STATS_MAXBITLEN] < 9) + break; + vty_out (vty, "%30s: ", "\% announced "); + vty_out (vty, "%12.2f%s", + 100 * (float)ts.counts[BGP_STATS_SPACE] / + (float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]), + VTY_NEWLINE); + vty_out (vty, "%30s: ", "/8 equivalent "); + vty_out (vty, "%12.2f%s", + (float)ts.counts[BGP_STATS_SPACE] / + (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)), + VTY_NEWLINE); + if (ts.counts[BGP_STATS_MAXBITLEN] < 25) + break; + vty_out (vty, "%30s: ", "/24 equivalent "); + vty_out (vty, "%12.2f", + (float)ts.counts[BGP_STATS_SPACE] / + (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24))); + break; + default: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12llu", ts.counts[i]); + } + + vty_out (vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +static int +bgp_table_stats_vty (struct vty *vty, const char *name, + const char *afi_str, const char *safi_str) +{ + struct bgp *bgp; + afi_t afi; + safi_t safi; + + if (name) + bgp = bgp_lookup_by_name (name); + else + bgp = bgp_get_default (); + + if (!bgp) + { + vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (strncmp (afi_str, "ipv", 3) == 0) + { + if (strncmp (afi_str, "ipv4", 4) == 0) + afi = AFI_IP; + else if (strncmp (afi_str, "ipv6", 4) == 0) + afi = AFI_IP6; + else + { + vty_out (vty, "%% Invalid address family %s%s", + afi_str, VTY_NEWLINE); + return CMD_WARNING; + } + if (strncmp (safi_str, "m", 1) == 0) + safi = SAFI_MULTICAST; + else if (strncmp (safi_str, "u", 1) == 0) + safi = SAFI_UNICAST; + else if (strncmp (safi_str, "vpnv4", 5) == 0) + safi = BGP_SAFI_VPNV4; + else if (strncmp (safi_str, "vpnv6", 6) == 0) + safi = BGP_SAFI_VPNV6; + else + { + vty_out (vty, "%% Invalid subsequent address family %s%s", + safi_str, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + vty_out (vty, "%% Invalid address family %s%s", + afi_str, VTY_NEWLINE); + return CMD_WARNING; + } + + if ((afi == AFI_IP && safi == BGP_SAFI_VPNV6) + || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4)) + { + vty_out (vty, "%% Invalid subsequent address family %s for %s%s", + afi_str, safi_str, VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_table_stats (vty, bgp, afi, safi); +} + +DEFUN (show_bgp_statistics, + show_bgp_statistics_cmd, + "show bgp (ipv4|ipv6) (unicast|multicast) statistics", + SHOW_STR + BGP_STR + "Address family\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") +{ + return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); +} + +ALIAS (show_bgp_statistics, + show_bgp_statistics_vpnv4_cmd, + "show bgp (ipv4) (vpnv4) statistics", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") + +DEFUN (show_bgp_statistics_view, + show_bgp_statistics_view_cmd, + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) statistics", + SHOW_STR + BGP_STR + "BGP view\n" + "Address family\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") +{ + return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); +} + +ALIAS (show_bgp_statistics_view, + show_bgp_statistics_view_vpnv4_cmd, + "show bgp view WORD (ipv4) (vpnv4) statistics", + SHOW_STR + BGP_STR + "BGP view\n" + "Address family\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") + +enum bgp_pcounts +{ + PCOUNT_ADJ_IN = 0, + PCOUNT_DAMPED, + PCOUNT_REMOVED, + PCOUNT_HISTORY, + PCOUNT_STALE, + PCOUNT_VALID, + PCOUNT_ALL, + PCOUNT_COUNTED, + PCOUNT_PFCNT, /* the figure we display to users */ + PCOUNT_MAX, +}; + +static const char *pcount_strs[] = +{ + [PCOUNT_ADJ_IN] = "Adj-in", + [PCOUNT_DAMPED] = "Damped", + [PCOUNT_REMOVED] = "Removed", + [PCOUNT_HISTORY] = "History", + [PCOUNT_STALE] = "Stale", + [PCOUNT_VALID] = "Valid", + [PCOUNT_ALL] = "All RIB", + [PCOUNT_COUNTED] = "PfxCt counted", + [PCOUNT_PFCNT] = "Useable", + [PCOUNT_MAX] = NULL, +}; + +struct peer_pcounts +{ + unsigned int count[PCOUNT_MAX]; + const struct peer *peer; + const struct bgp_table *table; +}; + +static int +bgp_peer_count_walker (struct thread *t) +{ + struct bgp_node *rn; + struct peer_pcounts *pc = THREAD_ARG (t); + const struct peer *peer = pc->peer; + + for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn)) + { + struct bgp_adj_in *ain; + struct bgp_info *ri; + + for (ain = rn->adj_in; ain; ain = ain->next) + if (ain->peer == peer) + pc->count[PCOUNT_ADJ_IN]++; + + for (ri = rn->info; ri; ri = ri->next) + { + char buf[SU_ADDRSTRLEN]; + + if (ri->peer != peer) + continue; + + pc->count[PCOUNT_ALL]++; + + if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)) + pc->count[PCOUNT_DAMPED]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + pc->count[PCOUNT_HISTORY]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)) + pc->count[PCOUNT_REMOVED]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) + pc->count[PCOUNT_STALE]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_VALID)) + pc->count[PCOUNT_VALID]++; + if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + pc->count[PCOUNT_PFCNT]++; + + if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) + { + pc->count[PCOUNT_COUNTED]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + plog_warn (peer->log, + "%s [pcount] %s/%d is counted but flags 0x%x", + peer->host, + inet_ntop(rn->p.family, &rn->p.u.prefix, + buf, SU_ADDRSTRLEN), + rn->p.prefixlen, + ri->flags); + } + else + { + if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + plog_warn (peer->log, + "%s [pcount] %s/%d not counted but flags 0x%x", + peer->host, + inet_ntop(rn->p.family, &rn->p.u.prefix, + buf, SU_ADDRSTRLEN), + rn->p.prefixlen, + ri->flags); + } + } + } + return 0; +} + +static int +bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_pcounts pcounts = { .peer = peer }; + unsigned int i; + + if (!peer || !peer->bgp || !peer->afc[afi][safi] + || !peer->bgp->rib[afi][safi]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + memset (&pcounts, 0, sizeof(pcounts)); + pcounts.peer = peer; + pcounts.table = peer->bgp->rib[afi][safi]; + + /* in-place call via thread subsystem so as to record execution time + * stats for the thread-walk (i.e. ensure this can't be blamed on + * on just vty_read()). + */ + thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0); + + vty_out (vty, "Prefix counts for %s, %s%s", + peer->host, afi_safi_print (afi, safi), VTY_NEWLINE); + vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE); + vty_out (vty, "%sCounts from RIB table walk:%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (i = 0; i < PCOUNT_MAX; i++) + vty_out (vty, "%20s: %-10d%s", + pcount_strs[i], pcounts.count[i], VTY_NEWLINE); + + if (pcounts.count[PCOUNT_PFCNT] != peer->pcount[afi][safi]) + { + vty_out (vty, "%s [pcount] PfxCt drift!%s", + peer->host, VTY_NEWLINE); + vty_out (vty, "Please report this bug, with the above command output%s", + VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_neighbor_prefix_counts, + show_ip_bgp_neighbor_prefix_counts_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv6_neighbor_prefix_counts, + show_bgp_ipv6_neighbor_prefix_counts_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts, + show_ip_bgp_ipv4_neighbor_prefix_counts_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; + + if (strncmp (argv[0], "m", 1) == 0) + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST); + + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts, + show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd, + "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN); +} + static void show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, @@ -10776,7 +11421,13 @@ bgp_route_init () install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); + /* prefix count */ + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); #ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd); + /* New config IPv6 BGP commands. */ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); @@ -10946,7 +11597,13 @@ bgp_route_init () install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); - + + /* Statistics */ + install_element (ENABLE_NODE, &show_bgp_statistics_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); + /* old command */ install_element (VIEW_NODE, &show_ipv6_bgp_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e5f3ae59..b0c2fccf 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -105,6 +105,17 @@ struct bgp_static u_char tag[3]; }; +/* Flags which indicate a route is unuseable in some form */ +#define BGP_INFO_UNUSEABLE \ + (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED) +/* Macro to check BGP information is alive or not. Sadly, + * not equivalent to just checking previous, because of the + * sense of the additional VALID flag. + */ +#define BGP_INFO_HOLDDOWN(BI) \ + (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID) \ + || CHECK_FLAG ((BI)->flags, BGP_INFO_UNUSEABLE)) + #define DISTRIBUTE_IN_NAME(F) ((F)->dlist[FILTER_IN].name) #define DISTRIBUTE_IN(F) ((F)->dlist[FILTER_IN].alist) #define DISTRIBUTE_OUT_NAME(F) ((F)->dlist[FILTER_OUT].name) @@ -151,6 +162,8 @@ extern struct bgp_info *bgp_info_lock (struct bgp_info *); extern struct bgp_info *bgp_info_unlock (struct bgp_info *); extern void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri); extern void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri); +extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); +extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t); extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 93096dc0..10c9778e 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6800,8 +6800,6 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) vty_out (vty, " Idle (Admin)"); else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) vty_out (vty, " Idle (PfxCt)"); - else if (CHECK_FLAG (peer->sflags, PEER_STATUS_CLEARING)) - vty_out (vty, " Idle (Clrng)"); else vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, peer->status)); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index a25297ab..1686b20e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_debug.h" /* All information about zebra. */ static struct zclient *zclient = NULL; @@ -50,6 +51,14 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length) struct bgp *bgp; zebra_router_id_update_read(zclient->ibuf,&router_id); + + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[128]; + prefix2str(&router_id, buf, sizeof(buf)); + zlog_debug("Zebra rcvd: router id update %s", buf); + } + router_id_zebra = router_id.u.prefix4; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) @@ -69,6 +78,9 @@ bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) ifp = zebra_interface_add_read (zclient->ibuf); + if (BGP_DEBUG(zebra, ZEBRA) && ifp) + zlog_debug("Zebra rcvd: interface add %s", ifp->name); + return 0; } @@ -83,6 +95,9 @@ bgp_interface_delete (int command, struct zclient *zclient, ifp = zebra_interface_state_read (s); ifp->ifindex = IFINDEX_INTERNAL; + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra rcvd: interface delete %s", ifp->name); + return 0; } @@ -100,6 +115,9 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) if (! ifp) return 0; + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra rcvd: interface %s up", ifp->name); + for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_add (c); @@ -119,6 +137,9 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) if (! ifp) return 0; + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra rcvd: interface %s down", ifp->name); + for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_delete (c); @@ -164,6 +185,14 @@ bgp_interface_address_add (int command, struct zclient *zclient, if (ifc == NULL) return 0; + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[128]; + prefix2str(ifc->address, buf, sizeof(buf)); + zlog_debug("Zebra rcvd: interface %s address add %s", + ifc->ifp->name, buf); + } + if (if_is_operative (ifc->ifp)) bgp_connected_add (ifc); @@ -181,6 +210,14 @@ bgp_interface_address_delete (int command, struct zclient *zclient, if (ifc == NULL) return 0; + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[128]; + prefix2str(ifc->address, buf, sizeof(buf)); + zlog_debug("Zebra rcvd: interface %s address delete %s", + ifc->ifp->name, buf); + } + if (if_is_operative (ifc->ifp)) bgp_connected_delete (ifc); @@ -233,9 +270,34 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) api.metric = 0; if (command == ZEBRA_IPV4_ROUTE_ADD) - bgp_redistribute_add ((struct prefix *)&p, &nexthop, api.metric, api.type); + { + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u", + zebra_route_string(api.type), + inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), + api.metric); + } + bgp_redistribute_add((struct prefix *)&p, &nexthop, api.metric, api.type); + } else - bgp_redistribute_delete ((struct prefix *)&p, api.type); + { + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d " + "nexthop %s metric %u", + zebra_route_string(api.type), + inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), + api.metric); + } + bgp_redistribute_delete((struct prefix *)&p, api.type); + } return 0; } @@ -291,9 +353,29 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) return 0; if (command == ZEBRA_IPV6_ROUTE_ADD) - bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); + { + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d metric %u", + zebra_route_string(api.type), + inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), + p.prefixlen, api.metric); + } + bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); + } else - bgp_redistribute_delete ((struct prefix *) &p, api.type); + { + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d metric %u", + zebra_route_string(api.type), + inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), + p.prefixlen, api.metric); + } + bgp_redistribute_delete ((struct prefix *) &p, api.type); + } return 0; } @@ -649,6 +731,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) } #endif + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u", + inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), + p->prefixlen, + inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])), + api.metric); + } + zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, (struct prefix_ipv4 *) p, &api); } @@ -705,6 +797,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u", + inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), + p->prefixlen, + inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), + api.metric); + } + zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, (struct prefix_ipv6 *) p, &api); } @@ -753,6 +855,16 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u", + inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), + p->prefixlen, + inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])), + api.metric); + } + zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); } @@ -798,6 +910,16 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if (BGP_DEBUG(zebra, ZEBRA)) + { + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %u", + inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), + p->prefixlen, + inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), + api.metric); + } + zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, (struct prefix_ipv6 *) p, &api); } @@ -820,6 +942,9 @@ bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) /* Return if zebra connection is not established. */ if (zclient->sock < 0) return CMD_WARNING; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type)); /* Send distribute add message to zebra. */ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); @@ -884,8 +1009,13 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) if (bgp->redist[AFI_IP][type] == 0 && bgp->redist[AFI_IP6][type] == 0 && zclient->sock >= 0) - /* Send distribute delete message to zebra. */ - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + { + /* Send distribute delete message to zebra. */ + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra send: redistribute delete %s", + zebra_route_string(type)); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + } /* Withdraw redistributed routes from current BGP's routing table. */ bgp_redistribute_withdraw (bgp, afi, type); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6256c54a..7163f3f9 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -691,6 +691,16 @@ peer_sort (struct peer *peer) static inline void peer_free (struct peer *peer) { + assert (peer->status == Deleted); + + /* this /ought/ to have been done already through bgp_stop earlier, + * but just to be sure.. + */ + bgp_timer_set (peer); + BGP_READ_OFF (peer->t_read); + BGP_WRITE_OFF (peer->t_write); + BGP_EVENT_FLUSH (peer); + if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); @@ -708,6 +718,7 @@ peer_free (struct peer *peer) if (peer->clear_node_queue) work_queue_free (peer->clear_node_queue); + bgp_sync_delete (peer); memset (peer, 0, sizeof (struct peer)); XFREE (MTYPE_BGP_PEER, peer); @@ -718,7 +729,8 @@ struct peer * peer_lock (struct peer *peer) { assert (peer && (peer->lock >= 0)); - + assert (peer->status != Deleted); + peer->lock++; return peer; @@ -757,26 +769,31 @@ peer_unlock (struct peer *peer) /* Allocate new peer object, implicitely locked. */ static struct peer * -peer_new () +peer_new (struct bgp *bgp) { afi_t afi; safi_t safi; struct peer *peer; struct servent *sp; - + + /* bgp argument is absolutely required */ + assert (bgp); + if (!bgp) + return NULL; + /* Allocate new peer. */ - peer = XMALLOC (MTYPE_BGP_PEER, sizeof (struct peer)); - memset (peer, 0, sizeof (struct peer)); + peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer)); /* Set default value. */ peer->fd = -1; - peer->lock = 1; peer->v_start = BGP_INIT_START_TIMER; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; peer->v_asorig = BGP_DEFAULT_ASORIGINATE; peer->status = Idle; peer->ostatus = Idle; peer->weight = 0; + peer->bgp = bgp; + peer = peer_lock (peer); /* initial reference */ #ifdef SUPPORT_REALMS peer->realm = 0; @@ -818,8 +835,7 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as, struct peer *peer; char buf[SU_ADDRSTRLEN]; - peer = peer_new (); - peer->bgp = bgp; + peer = peer_new (bgp); peer->su = *su; peer->local_as = local_as; peer->as = remote_as; @@ -865,8 +881,7 @@ peer_create_accept (struct bgp *bgp) { struct peer *peer; - peer = peer_new (); - peer->bgp = bgp; + peer = peer_new (bgp); peer = peer_lock (peer); /* bgp peer list reference */ listnode_add_sort (bgp->peer, peer); @@ -1147,7 +1162,17 @@ peer_nsf_stop (struct peer *peer) bgp_clear_route_all (peer); } -/* Delete peer from confguration. */ +/* Delete peer from confguration. + * + * The peer is moved to a dead-end "Deleted" neighbour-state, to allow + * it to "cool off" and refcounts to hit 0, at which state it is freed. + * + * This function /should/ take care to be idempotent, to guard against + * it being called multiple times through stray events that come in + * that happen to result in this function being called again. That + * said, getting here for a "Deleted" peer is a bug in the neighbour + * FSM. + */ int peer_delete (struct peer *peer) { @@ -1157,6 +1182,8 @@ peer_delete (struct peer *peer) struct bgp *bgp; struct bgp_filter *filter; + assert (peer->status != Deleted); + bgp = peer->bgp; if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) @@ -1166,8 +1193,13 @@ peer_delete (struct peer *peer) relationship. */ if (peer->group) { - peer = peer_unlock (peer); /* peer-group reference */ - listnode_delete (peer->group->peer, peer); + struct listnode *pn; + + if ((pn = listnode_lookup (peer->group->peer, peer))) + { + peer = peer_unlock (peer); /* group->peer list reference */ + list_delete_node (peer->group->peer, pn); + } peer->group = NULL; } @@ -1177,29 +1209,25 @@ peer_delete (struct peer *peer) */ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_stop (peer); - bgp_fsm_change_status (peer, Idle); /* stops all timers */ + bgp_fsm_change_status (peer, Deleted); + bgp_timer_set (peer); /* stops all timers for Deleted */ - /* Stop all timers - should already have been done in bgp_stop */ - BGP_TIMER_OFF (peer->t_start); - BGP_TIMER_OFF (peer->t_connect); - BGP_TIMER_OFF (peer->t_holdtime); - BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); - BGP_TIMER_OFF (peer->t_routeadv); - BGP_TIMER_OFF (peer->t_pmax_restart); - BGP_TIMER_OFF (peer->t_gr_restart); - BGP_TIMER_OFF (peer->t_gr_stale); - /* Delete from all peer list. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - peer_unlock (peer); /* bgp peer list reference */ - listnode_delete (bgp->peer, peer); + struct listnode *pn; - if (peer_rsclient_active (peer)) + if ((pn = listnode_lookup (bgp->peer, peer))) + { + peer_unlock (peer); /* bgp peer list reference */ + list_delete_node (bgp->peer, pn); + } + + if (peer_rsclient_active (peer) + && (pn = listnode_lookup (bgp->rsclient, peer))) { peer_unlock (peer); /* rsclient list reference */ - listnode_delete (bgp->rsclient, peer); + list_delete_node (bgp->rsclient, pn); } } @@ -1227,8 +1255,6 @@ peer_delete (struct peer *peer) sockunion_free (peer->su_remote); peer->su_local = peer->su_remote = NULL; - bgp_sync_delete (peer); - /* Free filter related memory. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) @@ -1330,11 +1356,10 @@ peer_group_get (struct bgp *bgp, const char *name) group->bgp = bgp; group->name = strdup (name); group->peer = list_new (); - group->conf = peer_new (); + group->conf = peer_new (bgp); if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; group->conf->host = strdup (name); - group->conf->bgp = bgp; group->conf->group = group; group->conf->as = 0; group->conf->ttl = 1; @@ -1707,7 +1732,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, peer->group = group; peer->af_group[afi][safi] = 1; - peer = peer_lock (peer); /* peer-group group->peer reference */ + peer = peer_lock (peer); /* group->peer list reference */ listnode_add (group->peer, peer); peer_group2peer_config_copy (group, peer, afi, safi); @@ -1748,9 +1773,11 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, { peer->group = group; - peer = peer_lock (peer); /* peer-group group->peer reference */ + peer = peer_lock (peer); /* group->peer list reference */ listnode_add (group->peer, peer); } + else + assert (group && peer->group == group); if (first_member) { @@ -1774,13 +1801,16 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { + struct listnode *pn; + /* If it's not configured as RSERVER_CLIENT in any other address family, without being member of a peer_group, remove it from list bgp->rsclient.*/ - if (! peer_rsclient_active (peer)) + if (! peer_rsclient_active (peer) + && (pn = listnode_lookup (bgp->rsclient, peer))) { peer_unlock (peer); /* peer rsclient reference */ - listnode_delete (bgp->rsclient, peer); + list_delete_node (bgp->rsclient, pn); } bgp_table_finish (peer->rib[afi][safi]); @@ -1836,6 +1866,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, if (! peer_group_active (peer)) { + assert (listnode_lookup (group->peer, peer)); peer_unlock (peer); /* peer group list reference */ listnode_delete (group->peer, peer); peer->group = NULL; @@ -1870,7 +1901,7 @@ bgp_create (as_t *as, const char *name) if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL) return NULL; - bgp->peer_self = peer_new (); + bgp->peer_self = peer_new (bgp); bgp->peer_self->host = strdup ("Static announcement"); bgp->peer = list_new (); @@ -4290,8 +4321,7 @@ peer_uptime (time_t uptime2, char *buf, size_t len) /* Check buffer length. */ if (len < BGP_UPTIME_LEN) { - /* XXX: warning: long int format, size_t arg (arg 2) */ - zlog_warn ("peer_uptime (): buffer shortage %ld", len); + zlog_warn ("peer_uptime (): buffer shortage %lu", (u_long)len); /* XXX: should return status instead of buf... */ snprintf (buf, len, "<error> "); return buf; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index dc451e78..e2802b9b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -386,7 +386,6 @@ struct peer #define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */ #define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */ #define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */ -#define PEER_STATUS_CLEARING (1 << 7) /* peers table being cleared */ /* Peer status af flags (reset in bgp_stop) */ u_int16_t af_sflags[AFI_MAX][SAFI_MAX]; @@ -667,7 +666,9 @@ struct bgp_nlri #define OpenSent 4 #define OpenConfirm 5 #define Established 6 -#define BGP_STATUS_MAX 7 +#define Clearing 7 +#define Deleted 8 +#define BGP_STATUS_MAX 9 /* BGP finite state machine events. */ #define BGP_Start 1 @@ -683,7 +684,8 @@ struct bgp_nlri #define Receive_KEEPALIVE_message 11 #define Receive_UPDATE_message 12 #define Receive_NOTIFICATION_message 13 -#define BGP_EVENTS_MAX 14 +#define Clearing_Completed 14 +#define BGP_EVENTS_MAX 15 /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 @@ -745,13 +747,6 @@ enum bgp_clear_type #define BGP_INPUT(P) ((P)->ibuf) #define BGP_INPUT_PNT(P) (STREAM_PNT(BGP_INPUT(P))) -/* Macro to check BGP information is alive or not. */ -#define BGP_INFO_HOLDDOWN(BI) \ - (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID) \ - || CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \ - || CHECK_FLAG ((BI)->flags, BGP_INFO_DAMPED) \ - || CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED)) - /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) |