frr/bgpd/bgp_nexthop.c

1612 lines
38 KiB
C
Raw Normal View History

2002-12-13 21:15:29 +01:00
/* BGP nexthop scan
Copyright (C) 2000 Kunihiro Ishiguro
This file is part of GNU Zebra.
GNU Zebra is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU Zebra is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Zebra; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include <zebra.h>
#include "command.h"
#include "thread.h"
#include "prefix.h"
#include "zclient.h"
#include "stream.h"
#include "network.h"
#include "log.h"
#include "memory.h"
#include "hash.h"
#include "jhash.h"
#include "nexthop.h"
2002-12-13 21:15:29 +01:00
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
2002-12-13 21:15:29 +01:00
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_damp.h"
#include "zebra/rib.h"
#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */
extern struct zclient *zclient;
2002-12-13 21:15:29 +01:00
struct bgp_nexthop_cache *zlookup_query (struct in_addr);
#ifdef HAVE_IPV6
struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
#endif /* HAVE_IPV6 */
2002-12-13 21:15:29 +01:00
/* Only one BGP scan thread are activated at the same time. */
static struct thread *bgp_scan_thread = NULL;
2002-12-13 21:15:29 +01:00
/* BGP import thread */
static struct thread *bgp_import_thread = NULL;
2002-12-13 21:15:29 +01:00
/* BGP scan interval. */
static int bgp_scan_interval;
2002-12-13 21:15:29 +01:00
/* BGP import interval. */
static int bgp_import_interval;
2002-12-13 21:15:29 +01:00
/* Route table for next-hop lookup cache. */
struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
static struct bgp_table *cache1_table[AFI_MAX];
static struct bgp_table *cache2_table[AFI_MAX];
2002-12-13 21:15:29 +01:00
/* Route table for connected route. */
static struct bgp_table *bgp_connected_table[AFI_MAX];
2002-12-13 21:15:29 +01:00
/* BGP nexthop lookup query client. */
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
struct zclient *zlookup = NULL;
char *
bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size)
{
prefix2str(&(bnc->node->p), buf, size);
return buf;
}
2002-12-13 21:15:29 +01:00
/* Add nexthop to the end of the list. */
static void
2002-12-13 21:15:29 +01:00
bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop)
{
struct nexthop *last;
for (last = bnc->nexthop; last && last->next; last = last->next)
;
if (last)
last->next = nexthop;
else
bnc->nexthop = nexthop;
nexthop->prev = last;
}
void
2002-12-13 21:15:29 +01:00
bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
{
struct nexthop *nexthop;
struct nexthop *next = NULL;
for (nexthop = bnc->nexthop; nexthop; nexthop = next)
{
next = nexthop->next;
XFREE (MTYPE_NEXTHOP, nexthop);
}
}
struct bgp_nexthop_cache *
bnc_new ()
2002-12-13 21:15:29 +01:00
{
struct bgp_nexthop_cache *bnc;
bnc = XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache));
LIST_INIT(&(bnc->paths));
return bnc;
2002-12-13 21:15:29 +01:00
}
void
2002-12-13 21:15:29 +01:00
bnc_free (struct bgp_nexthop_cache *bnc)
{
bnc_nexthop_free (bnc);
XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc);
}
static int
bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
2002-12-13 21:15:29 +01:00
struct bgp_nexthop_cache *bnc2)
{
int i;
struct nexthop *next1, *next2;
if (bnc1->nexthop_num != bnc2->nexthop_num)
return 1;
next1 = bnc1->nexthop;
next2 = bnc2->nexthop;
for (i = 0; i < bnc1->nexthop_num; i++)
{
if (! nexthop_same_no_recurse (next1, next2))
2002-12-13 21:15:29 +01:00
return 1;
next1 = next1->next;
next2 = next2->next;
}
return 0;
}
/* If nexthop exists on connected network return 1. */
int
bgp_nexthop_onlink (afi_t afi, struct attr *attr)
2002-12-13 21:15:29 +01:00
{
struct bgp_node *rn;
/* If zebra is not enabled return */
if (zlookup->sock < 0)
return 1;
2002-12-13 21:15:29 +01:00
/* Lookup the address is onlink or not. */
if (afi == AFI_IP)
{
rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop);
2002-12-13 21:15:29 +01:00
if (rn)
{
bgp_unlock_node (rn);
return 1;
}
}
#ifdef HAVE_IPV6
else if (afi == AFI_IP6)
{
if (attr->extra->mp_nexthop_len == 32)
2002-12-13 21:15:29 +01:00
return 1;
else if (attr->extra->mp_nexthop_len == 16)
2002-12-13 21:15:29 +01:00
{
if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
2002-12-13 21:15:29 +01:00
return 1;
rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6],
&attr->extra->mp_nexthop_global);
2002-12-13 21:15:29 +01:00
if (rn)
{
bgp_unlock_node (rn);
return 1;
}
}
}
#endif /* HAVE_IPV6 */
return 0;
}
#ifdef HAVE_IPV6
/* Check specified next-hop is reachable or not. */
static int
2002-12-13 21:15:29 +01:00
bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
int *metricchanged)
{
struct bgp_node *rn;
struct prefix p;
struct bgp_nexthop_cache *bnc;
struct attr *attr;
/* If lookup is not enabled, return valid. */
if (zlookup->sock < 0)
{
if (ri->extra)
ri->extra->igpmetric = 0;
return 1;
}
2002-12-13 21:15:29 +01:00
/* Only check IPv6 global address only nexthop. */
attr = ri->attr;
if (attr->extra->mp_nexthop_len != 16
|| IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
2002-12-13 21:15:29 +01:00
return 1;
memset (&p, 0, sizeof (struct prefix));
p.family = AF_INET6;
p.prefixlen = IPV6_MAX_BITLEN;
p.u.prefix6 = attr->extra->mp_nexthop_global;
2002-12-13 21:15:29 +01:00
/* IBGP or ebgp-multihop */
rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p);
2002-12-13 21:15:29 +01:00
if (rn->info)
{
bnc = rn->info;
bgp_unlock_node (rn);
}
else
{
if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global)))
bnc = bnc_new ();
else
2002-12-13 21:15:29 +01:00
{
if (changed)
{
struct bgp_table *old;
struct bgp_node *oldrn;
if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6])
old = cache2_table[AFI_IP6];
2002-12-13 21:15:29 +01:00
else
old = cache1_table[AFI_IP6];
2002-12-13 21:15:29 +01:00
oldrn = bgp_node_lookup (old, &p);
if (oldrn)
{
struct bgp_nexthop_cache *oldbnc = oldrn->info;
2002-12-13 21:15:29 +01:00
bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
2002-12-13 21:15:29 +01:00
if (bnc->metric != oldbnc->metric)
bnc->metricchanged = 1;
bgp_unlock_node (oldrn);
2002-12-13 21:15:29 +01:00
}
}
}
rn->info = bnc;
}
if (changed)
*changed = bnc->changed;
if (metricchanged)
*metricchanged = bnc->metricchanged;
if (bnc->valid && bnc->metric)
(bgp_info_extra_get (ri))->igpmetric = bnc->metric;
else if (ri->extra)
ri->extra->igpmetric = 0;
2002-12-13 21:15:29 +01:00
return bnc->valid;
}
#endif /* HAVE_IPV6 */
/* Check specified next-hop is reachable or not. */
int
bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
int *changed, int *metricchanged)
{
struct bgp_node *rn;
struct prefix p;
struct bgp_nexthop_cache *bnc;
struct in_addr addr;
/* If lookup is not enabled, return valid. */
if (zlookup->sock < 0)
{
if (ri->extra)
ri->extra->igpmetric = 0;
return 1;
}
2002-12-13 21:15:29 +01:00
#ifdef HAVE_IPV6
if (afi == AFI_IP6)
return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged);
#endif /* HAVE_IPV6 */
addr = ri->attr->nexthop;
memset (&p, 0, sizeof (struct prefix));
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
p.u.prefix4 = addr;
/* IBGP or ebgp-multihop */
rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p);
2002-12-13 21:15:29 +01:00
if (rn->info)
{
bnc = rn->info;
bgp_unlock_node (rn);
}
else
{
if (NULL == (bnc = zlookup_query (addr)))
bnc = bnc_new ();
else
2002-12-13 21:15:29 +01:00
{
if (changed)
{
struct bgp_table *old;
struct bgp_node *oldrn;
if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP])
old = cache2_table[AFI_IP];
2002-12-13 21:15:29 +01:00
else
old = cache1_table[AFI_IP];
2002-12-13 21:15:29 +01:00
oldrn = bgp_node_lookup (old, &p);
if (oldrn)
{
struct bgp_nexthop_cache *oldbnc = oldrn->info;
2002-12-13 21:15:29 +01:00
bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
2002-12-13 21:15:29 +01:00
if (bnc->metric != oldbnc->metric)
bnc->metricchanged = 1;
bgp_unlock_node (oldrn);
2002-12-13 21:15:29 +01:00
}
}
}
rn->info = bnc;
}
if (changed)
*changed = bnc->changed;
if (metricchanged)
*metricchanged = bnc->metricchanged;
if (bnc->valid && bnc->metric)
(bgp_info_extra_get(ri))->igpmetric = bnc->metric;
else if (ri->extra)
ri->extra->igpmetric = 0;
2002-12-13 21:15:29 +01:00
return bnc->valid;
}
/* Reset and free all BGP nexthop cache. */
static void
2002-12-13 21:15:29 +01:00
bgp_nexthop_cache_reset (struct bgp_table *table)
{
struct bgp_node *rn;
struct bgp_nexthop_cache *bnc;
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
if ((bnc = rn->info) != NULL)
{
bnc_free (bnc);
rn->info = NULL;
bgp_unlock_node (rn);
}
}
static void
bgp_scan (afi_t afi, safi_t safi)
2002-12-13 21:15:29 +01:00
{
struct bgp_node *rn;
struct bgp *bgp;
struct bgp_info *bi;
struct bgp_info *next;
struct peer *peer;
struct listnode *node, *nnode;
#if BGP_SCAN_NEXTHOP
2002-12-13 21:15:29 +01:00
int valid;
int current;
int changed;
int metricchanged;
/* Change cache. */
if (bgp_nexthop_cache_table[afi] == cache1_table[afi])
bgp_nexthop_cache_table[afi] = cache2_table[afi];
2002-12-13 21:15:29 +01:00
else
bgp_nexthop_cache_table[afi] = cache1_table[afi];
#endif
2002-12-13 21:15:29 +01:00
/* Get default bgp. */
bgp = bgp_get_default ();
if (bgp == NULL)
return;
/* Maximum prefix check */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
2002-12-13 21:15:29 +01:00
{
if (peer->status != Established)
continue;
if (peer->afc[afi][SAFI_UNICAST])
bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1);
if (peer->afc[afi][SAFI_MULTICAST])
bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1);
if (peer->afc[afi][SAFI_MPLS_VPN])
bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1);
2002-12-13 21:15:29 +01:00
}
for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn;
2002-12-13 21:15:29 +01:00
rn = bgp_route_next (rn))
{
for (bi = rn->info; bi; bi = next)
{
next = bi->next;
if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL)
{
#if BGP_SCAN_NEXTHOP
2002-12-13 21:15:29 +01:00
changed = 0;
metricchanged = 0;
if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1
&& !CHECK_FLAG(bi->peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
valid = bgp_nexthop_onlink (afi, bi->attr);
2002-12-13 21:15:29 +01:00
else
valid = bgp_nexthop_lookup (afi, bi->peer, bi,
2002-12-13 21:15:29 +01:00
&changed, &metricchanged);
current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0;
if (changed)
SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
else
UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
if (valid != current)
{
if (CHECK_FLAG (bi->flags, BGP_INFO_VALID))
{
bgp_aggregate_decrement (bgp, &rn->p, bi,
afi, SAFI_UNICAST);
bgp_info_unset_flag (rn, bi, BGP_INFO_VALID);
2002-12-13 21:15:29 +01:00
}
else
{
bgp_info_set_flag (rn, bi, BGP_INFO_VALID);
2002-12-13 21:15:29 +01:00
bgp_aggregate_increment (bgp, &rn->p, bi,
afi, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
}
}
#endif
2002-12-13 21:15:29 +01:00
if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST],
2002-12-13 21:15:29 +01:00
BGP_CONFIG_DAMPENING)
&& bi->extra && bi->extra->damp_info )
if (bgp_damp_scan (bi, afi, SAFI_UNICAST))
2002-12-13 21:15:29 +01:00
bgp_aggregate_increment (bgp, &rn->p, bi,
afi, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
}
}
bgp_process (bgp, rn, afi, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
}
#if BGP_SCAN_NEXTHOP
2002-12-13 21:15:29 +01:00
/* Flash old cache. */
if (bgp_nexthop_cache_table[afi] == cache1_table[afi])
bgp_nexthop_cache_reset (cache2_table[afi]);
2002-12-13 21:15:29 +01:00
else
bgp_nexthop_cache_reset (cache1_table[afi]);
#endif
if (BGP_DEBUG (events, EVENTS))
{
if (afi == AFI_IP)
zlog_debug ("scanning IPv4 Unicast routing tables");
else if (afi == AFI_IP6)
zlog_debug ("scanning IPv6 Unicast routing tables");
}
/* Reevaluate default-originate route-maps and announce/withdraw
* default route if neccesary. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
if (peer->status == Established
&& CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
&& peer->default_rmap[afi][safi].name)
bgp_default_originate (peer, afi, safi, 0);
}
2002-12-13 21:15:29 +01:00
}
/* BGP scan thread. This thread check nexthop reachability. */
static int
bgp_scan_timer (struct thread *t)
2002-12-13 21:15:29 +01:00
{
bgp_scan_thread =
thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval);
2002-12-13 21:15:29 +01:00
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("Performing BGP general scanning");
2002-12-13 21:15:29 +01:00
bgp_scan (AFI_IP, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
#ifdef HAVE_IPV6
bgp_scan (AFI_IP6, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
#endif /* HAVE_IPV6 */
return 0;
}
/* BGP own address structure */
struct bgp_addr
{
struct in_addr addr;
int refcnt;
};
static struct hash *bgp_address_hash;
static void *
bgp_address_hash_alloc (void *p)
{
struct in_addr *val = p;
struct bgp_addr *addr;
addr = XMALLOC (MTYPE_BGP_ADDR, sizeof (struct bgp_addr));
addr->refcnt = 0;
addr->addr.s_addr = val->s_addr;
return addr;
}
static unsigned int
bgp_address_hash_key_make (void *p)
{
const struct bgp_addr *addr = p;
return jhash_1word(addr->addr.s_addr, 0);
}
static int
bgp_address_hash_cmp (const void *p1, const void *p2)
{
const struct bgp_addr *addr1 = p1;
const struct bgp_addr *addr2 = p2;
return addr1->addr.s_addr == addr2->addr.s_addr;
}
void
bgp_address_init (void)
{
bgp_address_hash = hash_create (bgp_address_hash_key_make,
bgp_address_hash_cmp);
}
static void
bgp_address_add (struct prefix *p)
{
struct bgp_addr tmp;
struct bgp_addr *addr;
tmp.addr = p->u.prefix4;
addr = hash_get (bgp_address_hash, &tmp, bgp_address_hash_alloc);
addr->refcnt++;
}
static void
bgp_address_del (struct prefix *p)
{
struct bgp_addr tmp;
struct bgp_addr *addr;
tmp.addr = p->u.prefix4;
addr = hash_lookup (bgp_address_hash, &tmp);
/* may have been deleted earlier by bgp_interface_down() */
if (addr == NULL)
return;
addr->refcnt--;
if (addr->refcnt == 0)
{
hash_release (bgp_address_hash, addr);
XFREE (MTYPE_BGP_ADDR, addr);
}
}
struct bgp_connected_ref
2002-12-13 21:15:29 +01:00
{
unsigned int refcnt;
};
void
bgp_connected_add (struct connected *ifc)
{
struct prefix p;
struct prefix *addr;
struct interface *ifp;
struct bgp_node *rn;
struct bgp_connected_ref *bc;
2002-12-13 21:15:29 +01:00
ifp = ifc->ifp;
if (! ifp)
return;
if (if_is_loopback (ifp))
return;
addr = ifc->address;
if (addr->family == AF_INET)
{
[PtP over ethernet] New peer flag allows much more addressing flexibility 2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating whether a peer address has been configured. Comment now shows the new interpretation of the destination addr: if ZEBRA_IFA_PEER is set, then it must contain the destination address, otherwise it may contain the broadcast address or be NULL. (CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete macros that were specific to IPv4 and not fully general. (CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag. (CONNECTED_PREFIX) New macro giving the prefix to insert into the RIB: if CONNECTED_PEER, then use the destination (peer) address, else use the address field. (CONNECTED_ID) New macro to come up with an identifying address for the struct connected. * if.c: (if_lookup_address, connected_lookup_address) Streamline logic with new CONNECTED_PREFIX macro. * prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros for better performance than the general prefix_copy function. * zclient.c: (zebra_interface_address_read) For non-null destination addresses, set prefixlen to equal the address prefixlen. This is needed to get the new CONNECTED_PREFIX macro to work properly. * connected.c: (connected_up_ipv4, connected_down_ipv4, connected_up_ipv6, connected_down_ipv6) Simplify logic using the new CONNECTED_PREFIX macro. (connected_add_ipv4) Set prefixlen in destination addresses (required by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead of testing for IFF_POINTOPOINT. Delete invalid warning message. Warn about cases where the ZEBRA_IFA_PEER is set but no destination address has been supplied (and turn off the flag). (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning. Set prefixlen in destination address so CONNECTED_PREFIX will work. * connected.h: (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. * interface.c: (connected_dump_vty) Use CONNECTED_PEER macro to decide whether the destination address is a peer or broadcast address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT). * if_ioctl.c: (if_getaddrs) Instead of setting a peer address only when the IFF_POINTOPOINT is set, we now accept a peer address whenever it is available and not the same as the local address. Otherwise (no peer address assigned), we check for a broadcast address (regardless of the IFF_BROADCAST flag). And must now pass a flags value of ZEBRA_IFA_PEER to connected_add_ipv4 when a peer address is assigned. The same new logic is used with the IPv6 code as well (and we pass the new flags argument to connected_add_ipv6). (if_get_addr) Do not bother to check IFF_POINTOPOINT: just issue the SIOCGIFDSTADDR ioctl and see if we get back a peer address not matching the local address (and set the ZEBRA_IFA_PEER in that case). If there's no peer address, try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set. * if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl without bothering to check the IFF_POINTOPOINT flag. And if no peer address was found, just try the SIOCGLIFBRDADDR ioctl without checking the IFF_BROADCAST flag. Call connected_add_ipv4 and connected_add_ipv6 with appropriate flags. * if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to connected_add_ipv6. * kernel_socket.c: (ifam_read) Must pass new flags argument to connected_add_ipv6. * rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2 to determine local and possible peer address (so there's no longer a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately. Pass new flags argument to connected_add_ipv6. (netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast to determine whether the connected destination address is a broadcast address. * bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete) Simplify logic by using new CONNECTED_PREFIX macro. * ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix, ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX macro. * ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX macro, both options collapse into the same code. * ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new CONNECTED_ID macro. (ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX macro. * ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro instead of testing the IFF_POINTOPOINT flag. * ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro instead of testing with if_is_pointopoint. And add commented-out code to implement alternative (in my opinion) more elegant behavior that has no special-case treatment for PtP addresses. (ospf_network_run) Use new CONNECTED_ID macro to simplify logic. * rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID macro to simplify logic. (rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does not give a useful result if prefixlen is 32 (we require a peer address in such cases). * ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
2002-12-13 21:15:29 +01:00
apply_mask_ipv4 ((struct prefix_ipv4 *) &p);
if (prefix_ipv4_any ((struct prefix_ipv4 *) &p))
return;
bgp_address_add (addr);
rn = bgp_node_get (bgp_connected_table[AFI_IP], (struct prefix *) &p);
2002-12-13 21:15:29 +01:00
if (rn->info)
{
bc = rn->info;
bc->refcnt++;
}
else
{
bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref));
2002-12-13 21:15:29 +01:00
bc->refcnt = 1;
rn->info = bc;
}
}
#ifdef HAVE_IPV6
[PtP over ethernet] New peer flag allows much more addressing flexibility 2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating whether a peer address has been configured. Comment now shows the new interpretation of the destination addr: if ZEBRA_IFA_PEER is set, then it must contain the destination address, otherwise it may contain the broadcast address or be NULL. (CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete macros that were specific to IPv4 and not fully general. (CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag. (CONNECTED_PREFIX) New macro giving the prefix to insert into the RIB: if CONNECTED_PEER, then use the destination (peer) address, else use the address field. (CONNECTED_ID) New macro to come up with an identifying address for the struct connected. * if.c: (if_lookup_address, connected_lookup_address) Streamline logic with new CONNECTED_PREFIX macro. * prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros for better performance than the general prefix_copy function. * zclient.c: (zebra_interface_address_read) For non-null destination addresses, set prefixlen to equal the address prefixlen. This is needed to get the new CONNECTED_PREFIX macro to work properly. * connected.c: (connected_up_ipv4, connected_down_ipv4, connected_up_ipv6, connected_down_ipv6) Simplify logic using the new CONNECTED_PREFIX macro. (connected_add_ipv4) Set prefixlen in destination addresses (required by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead of testing for IFF_POINTOPOINT. Delete invalid warning message. Warn about cases where the ZEBRA_IFA_PEER is set but no destination address has been supplied (and turn off the flag). (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning. Set prefixlen in destination address so CONNECTED_PREFIX will work. * connected.h: (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. * interface.c: (connected_dump_vty) Use CONNECTED_PEER macro to decide whether the destination address is a peer or broadcast address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT). * if_ioctl.c: (if_getaddrs) Instead of setting a peer address only when the IFF_POINTOPOINT is set, we now accept a peer address whenever it is available and not the same as the local address. Otherwise (no peer address assigned), we check for a broadcast address (regardless of the IFF_BROADCAST flag). And must now pass a flags value of ZEBRA_IFA_PEER to connected_add_ipv4 when a peer address is assigned. The same new logic is used with the IPv6 code as well (and we pass the new flags argument to connected_add_ipv6). (if_get_addr) Do not bother to check IFF_POINTOPOINT: just issue the SIOCGIFDSTADDR ioctl and see if we get back a peer address not matching the local address (and set the ZEBRA_IFA_PEER in that case). If there's no peer address, try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set. * if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl without bothering to check the IFF_POINTOPOINT flag. And if no peer address was found, just try the SIOCGLIFBRDADDR ioctl without checking the IFF_BROADCAST flag. Call connected_add_ipv4 and connected_add_ipv6 with appropriate flags. * if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to connected_add_ipv6. * kernel_socket.c: (ifam_read) Must pass new flags argument to connected_add_ipv6. * rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2 to determine local and possible peer address (so there's no longer a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately. Pass new flags argument to connected_add_ipv6. (netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast to determine whether the connected destination address is a broadcast address. * bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete) Simplify logic by using new CONNECTED_PREFIX macro. * ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix, ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX macro. * ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX macro, both options collapse into the same code. * ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new CONNECTED_ID macro. (ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX macro. * ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro instead of testing the IFF_POINTOPOINT flag. * ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro instead of testing with if_is_pointopoint. And add commented-out code to implement alternative (in my opinion) more elegant behavior that has no special-case treatment for PtP addresses. (ospf_network_run) Use new CONNECTED_ID macro to simplify logic. * rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID macro to simplify logic. (rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does not give a useful result if prefixlen is 32 (we require a peer address in such cases). * ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
else if (addr->family == AF_INET6)
2002-12-13 21:15:29 +01:00
{
[PtP over ethernet] New peer flag allows much more addressing flexibility 2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating whether a peer address has been configured. Comment now shows the new interpretation of the destination addr: if ZEBRA_IFA_PEER is set, then it must contain the destination address, otherwise it may contain the broadcast address or be NULL. (CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete macros that were specific to IPv4 and not fully general. (CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag. (CONNECTED_PREFIX) New macro giving the prefix to insert into the RIB: if CONNECTED_PEER, then use the destination (peer) address, else use the address field. (CONNECTED_ID) New macro to come up with an identifying address for the struct connected. * if.c: (if_lookup_address, connected_lookup_address) Streamline logic with new CONNECTED_PREFIX macro. * prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros for better performance than the general prefix_copy function. * zclient.c: (zebra_interface_address_read) For non-null destination addresses, set prefixlen to equal the address prefixlen. This is needed to get the new CONNECTED_PREFIX macro to work properly. * connected.c: (connected_up_ipv4, connected_down_ipv4, connected_up_ipv6, connected_down_ipv6) Simplify logic using the new CONNECTED_PREFIX macro. (connected_add_ipv4) Set prefixlen in destination addresses (required by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead of testing for IFF_POINTOPOINT. Delete invalid warning message. Warn about cases where the ZEBRA_IFA_PEER is set but no destination address has been supplied (and turn off the flag). (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning. Set prefixlen in destination address so CONNECTED_PREFIX will work. * connected.h: (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. * interface.c: (connected_dump_vty) Use CONNECTED_PEER macro to decide whether the destination address is a peer or broadcast address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT). * if_ioctl.c: (if_getaddrs) Instead of setting a peer address only when the IFF_POINTOPOINT is set, we now accept a peer address whenever it is available and not the same as the local address. Otherwise (no peer address assigned), we check for a broadcast address (regardless of the IFF_BROADCAST flag). And must now pass a flags value of ZEBRA_IFA_PEER to connected_add_ipv4 when a peer address is assigned. The same new logic is used with the IPv6 code as well (and we pass the new flags argument to connected_add_ipv6). (if_get_addr) Do not bother to check IFF_POINTOPOINT: just issue the SIOCGIFDSTADDR ioctl and see if we get back a peer address not matching the local address (and set the ZEBRA_IFA_PEER in that case). If there's no peer address, try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set. * if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl without bothering to check the IFF_POINTOPOINT flag. And if no peer address was found, just try the SIOCGLIFBRDADDR ioctl without checking the IFF_BROADCAST flag. Call connected_add_ipv4 and connected_add_ipv6 with appropriate flags. * if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to connected_add_ipv6. * kernel_socket.c: (ifam_read) Must pass new flags argument to connected_add_ipv6. * rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2 to determine local and possible peer address (so there's no longer a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately. Pass new flags argument to connected_add_ipv6. (netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast to determine whether the connected destination address is a broadcast address. * bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete) Simplify logic by using new CONNECTED_PREFIX macro. * ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix, ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX macro. * ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX macro, both options collapse into the same code. * ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new CONNECTED_ID macro. (ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX macro. * ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro instead of testing the IFF_POINTOPOINT flag. * ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro instead of testing with if_is_pointopoint. And add commented-out code to implement alternative (in my opinion) more elegant behavior that has no special-case treatment for PtP addresses. (ospf_network_run) Use new CONNECTED_ID macro to simplify logic. * rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID macro to simplify logic. (rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does not give a useful result if prefixlen is 32 (we require a peer address in such cases). * ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
2002-12-13 21:15:29 +01:00
apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6))
return;
if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
return;
rn = bgp_node_get (bgp_connected_table[AFI_IP6], (struct prefix *) &p);
2002-12-13 21:15:29 +01:00
if (rn->info)
{
bc = rn->info;
bc->refcnt++;
}
else
{
bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref));
2002-12-13 21:15:29 +01:00
bc->refcnt = 1;
rn->info = bc;
}
}
#endif /* HAVE_IPV6 */
}
void
bgp_connected_delete (struct connected *ifc)
{
struct prefix p;
struct prefix *addr;
struct interface *ifp;
struct bgp_node *rn;
struct bgp_connected_ref *bc;
2002-12-13 21:15:29 +01:00
ifp = ifc->ifp;
if (if_is_loopback (ifp))
return;
addr = ifc->address;
if (addr->family == AF_INET)
{
[PtP over ethernet] New peer flag allows much more addressing flexibility 2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating whether a peer address has been configured. Comment now shows the new interpretation of the destination addr: if ZEBRA_IFA_PEER is set, then it must contain the destination address, otherwise it may contain the broadcast address or be NULL. (CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete macros that were specific to IPv4 and not fully general. (CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag. (CONNECTED_PREFIX) New macro giving the prefix to insert into the RIB: if CONNECTED_PEER, then use the destination (peer) address, else use the address field. (CONNECTED_ID) New macro to come up with an identifying address for the struct connected. * if.c: (if_lookup_address, connected_lookup_address) Streamline logic with new CONNECTED_PREFIX macro. * prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros for better performance than the general prefix_copy function. * zclient.c: (zebra_interface_address_read) For non-null destination addresses, set prefixlen to equal the address prefixlen. This is needed to get the new CONNECTED_PREFIX macro to work properly. * connected.c: (connected_up_ipv4, connected_down_ipv4, connected_up_ipv6, connected_down_ipv6) Simplify logic using the new CONNECTED_PREFIX macro. (connected_add_ipv4) Set prefixlen in destination addresses (required by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead of testing for IFF_POINTOPOINT. Delete invalid warning message. Warn about cases where the ZEBRA_IFA_PEER is set but no destination address has been supplied (and turn off the flag). (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning. Set prefixlen in destination address so CONNECTED_PREFIX will work. * connected.h: (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. * interface.c: (connected_dump_vty) Use CONNECTED_PEER macro to decide whether the destination address is a peer or broadcast address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT). * if_ioctl.c: (if_getaddrs) Instead of setting a peer address only when the IFF_POINTOPOINT is set, we now accept a peer address whenever it is available and not the same as the local address. Otherwise (no peer address assigned), we check for a broadcast address (regardless of the IFF_BROADCAST flag). And must now pass a flags value of ZEBRA_IFA_PEER to connected_add_ipv4 when a peer address is assigned. The same new logic is used with the IPv6 code as well (and we pass the new flags argument to connected_add_ipv6). (if_get_addr) Do not bother to check IFF_POINTOPOINT: just issue the SIOCGIFDSTADDR ioctl and see if we get back a peer address not matching the local address (and set the ZEBRA_IFA_PEER in that case). If there's no peer address, try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set. * if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl without bothering to check the IFF_POINTOPOINT flag. And if no peer address was found, just try the SIOCGLIFBRDADDR ioctl without checking the IFF_BROADCAST flag. Call connected_add_ipv4 and connected_add_ipv6 with appropriate flags. * if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to connected_add_ipv6. * kernel_socket.c: (ifam_read) Must pass new flags argument to connected_add_ipv6. * rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2 to determine local and possible peer address (so there's no longer a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately. Pass new flags argument to connected_add_ipv6. (netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast to determine whether the connected destination address is a broadcast address. * bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete) Simplify logic by using new CONNECTED_PREFIX macro. * ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix, ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX macro. * ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX macro, both options collapse into the same code. * ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new CONNECTED_ID macro. (ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX macro. * ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro instead of testing the IFF_POINTOPOINT flag. * ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro instead of testing with if_is_pointopoint. And add commented-out code to implement alternative (in my opinion) more elegant behavior that has no special-case treatment for PtP addresses. (ospf_network_run) Use new CONNECTED_ID macro to simplify logic. * rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID macro to simplify logic. (rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does not give a useful result if prefixlen is 32 (we require a peer address in such cases). * ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
2002-12-13 21:15:29 +01:00
apply_mask_ipv4 ((struct prefix_ipv4 *) &p);
if (prefix_ipv4_any ((struct prefix_ipv4 *) &p))
return;
bgp_address_del (addr);
rn = bgp_node_lookup (bgp_connected_table[AFI_IP], &p);
2002-12-13 21:15:29 +01:00
if (! rn)
return;
bc = rn->info;
bc->refcnt--;
if (bc->refcnt == 0)
{
XFREE (MTYPE_BGP_CONN, bc);
2002-12-13 21:15:29 +01:00
rn->info = NULL;
}
bgp_unlock_node (rn);
bgp_unlock_node (rn);
}
#ifdef HAVE_IPV6
else if (addr->family == AF_INET6)
{
[PtP over ethernet] New peer flag allows much more addressing flexibility 2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating whether a peer address has been configured. Comment now shows the new interpretation of the destination addr: if ZEBRA_IFA_PEER is set, then it must contain the destination address, otherwise it may contain the broadcast address or be NULL. (CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete macros that were specific to IPv4 and not fully general. (CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag. (CONNECTED_PREFIX) New macro giving the prefix to insert into the RIB: if CONNECTED_PEER, then use the destination (peer) address, else use the address field. (CONNECTED_ID) New macro to come up with an identifying address for the struct connected. * if.c: (if_lookup_address, connected_lookup_address) Streamline logic with new CONNECTED_PREFIX macro. * prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros for better performance than the general prefix_copy function. * zclient.c: (zebra_interface_address_read) For non-null destination addresses, set prefixlen to equal the address prefixlen. This is needed to get the new CONNECTED_PREFIX macro to work properly. * connected.c: (connected_up_ipv4, connected_down_ipv4, connected_up_ipv6, connected_down_ipv6) Simplify logic using the new CONNECTED_PREFIX macro. (connected_add_ipv4) Set prefixlen in destination addresses (required by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead of testing for IFF_POINTOPOINT. Delete invalid warning message. Warn about cases where the ZEBRA_IFA_PEER is set but no destination address has been supplied (and turn off the flag). (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning. Set prefixlen in destination address so CONNECTED_PREFIX will work. * connected.h: (connected_add_ipv6) Add new flags argument so callers may set the ZEBRA_IFA_PEER flag. * interface.c: (connected_dump_vty) Use CONNECTED_PEER macro to decide whether the destination address is a peer or broadcast address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT). * if_ioctl.c: (if_getaddrs) Instead of setting a peer address only when the IFF_POINTOPOINT is set, we now accept a peer address whenever it is available and not the same as the local address. Otherwise (no peer address assigned), we check for a broadcast address (regardless of the IFF_BROADCAST flag). And must now pass a flags value of ZEBRA_IFA_PEER to connected_add_ipv4 when a peer address is assigned. The same new logic is used with the IPv6 code as well (and we pass the new flags argument to connected_add_ipv6). (if_get_addr) Do not bother to check IFF_POINTOPOINT: just issue the SIOCGIFDSTADDR ioctl and see if we get back a peer address not matching the local address (and set the ZEBRA_IFA_PEER in that case). If there's no peer address, try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set. * if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl without bothering to check the IFF_POINTOPOINT flag. And if no peer address was found, just try the SIOCGLIFBRDADDR ioctl without checking the IFF_BROADCAST flag. Call connected_add_ipv4 and connected_add_ipv6 with appropriate flags. * if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to connected_add_ipv6. * kernel_socket.c: (ifam_read) Must pass new flags argument to connected_add_ipv6. * rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2 to determine local and possible peer address (so there's no longer a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately. Pass new flags argument to connected_add_ipv6. (netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast to determine whether the connected destination address is a broadcast address. * bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete) Simplify logic by using new CONNECTED_PREFIX macro. * ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix, ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX macro. * ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX macro, both options collapse into the same code. * ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new CONNECTED_ID macro. (ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX macro. * ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro instead of testing the IFF_POINTOPOINT flag. * ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro instead of testing with if_is_pointopoint. And add commented-out code to implement alternative (in my opinion) more elegant behavior that has no special-case treatment for PtP addresses. (ospf_network_run) Use new CONNECTED_ID macro to simplify logic. * rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID macro to simplify logic. (rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does not give a useful result if prefixlen is 32 (we require a peer address in such cases). * ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
2002-12-13 21:15:29 +01:00
apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6))
return;
if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
return;
rn = bgp_node_lookup (bgp_connected_table[AFI_IP6], (struct prefix *) &p);
2002-12-13 21:15:29 +01:00
if (! rn)
return;
bc = rn->info;
bc->refcnt--;
if (bc->refcnt == 0)
{
XFREE (MTYPE_BGP_CONN, bc);
2002-12-13 21:15:29 +01:00
rn->info = NULL;
}
bgp_unlock_node (rn);
bgp_unlock_node (rn);
}
#endif /* HAVE_IPV6 */
}
int
bgp_nexthop_self (struct attr *attr)
2002-12-13 21:15:29 +01:00
{
struct bgp_addr tmp, *addr;
2002-12-13 21:15:29 +01:00
tmp.addr = attr->nexthop;
addr = hash_lookup (bgp_address_hash, &tmp);
if (addr)
return 1;
2002-12-13 21:15:29 +01:00
return 0;
}
static struct bgp_nexthop_cache *
zlookup_read (void)
2002-12-13 21:15:29 +01:00
{
struct stream *s;
uint16_t length;
u_char marker;
u_char version;
uint16_t command;
2002-12-13 21:15:29 +01:00
int nbytes;
struct in_addr raddr;
uint32_t metric;
2002-12-13 21:15:29 +01:00
int i;
u_char nexthop_num;
struct nexthop *nexthop;
struct bgp_nexthop_cache *bnc;
s = zlookup->ibuf;
stream_reset (s);
nbytes = stream_read (s, zlookup->sock, 2);
length = stream_getw (s);
nbytes = stream_read (s, zlookup->sock, length - 2);
marker = stream_getc (s);
version = stream_getc (s);
if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER)
{
zlog_err("%s: socket %d version mismatch, marker %d, version %d",
__func__, zlookup->sock, marker, version);
return NULL;
}
command = stream_getw (s);
2002-12-13 21:15:29 +01:00
raddr.s_addr = stream_get_ipv4 (s);
metric = stream_getl (s);
nexthop_num = stream_getc (s);
if (nexthop_num)
{
bnc = bnc_new ();
bnc->valid = 1;
bnc->metric = metric;
bnc->nexthop_num = nexthop_num;
for (i = 0; i < nexthop_num; i++)
{
nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
2002-12-13 21:15:29 +01:00
nexthop->type = stream_getc (s);
switch (nexthop->type)
{
case ZEBRA_NEXTHOP_IPV4:
nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
break;
case ZEBRA_NEXTHOP_IPV4_IFINDEX:
nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
nexthop->ifindex = stream_getl (s);
break;
2002-12-13 21:15:29 +01:00
case ZEBRA_NEXTHOP_IFINDEX:
case ZEBRA_NEXTHOP_IFNAME:
nexthop->ifindex = stream_getl (s);
break;
default:
/* do nothing */
break;
2002-12-13 21:15:29 +01:00
}
bnc_nexthop_add (bnc, nexthop);
}
}
else
return NULL;
return bnc;
}
struct bgp_nexthop_cache *
zlookup_query (struct in_addr addr)
{
int ret;
struct stream *s;
/* Check socket. */
if (zlookup->sock < 0)
return NULL;
s = zlookup->obuf;
stream_reset (s);
zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
2002-12-13 21:15:29 +01:00
stream_put_in_addr (s, &addr);
stream_putw_at (s, 0, stream_get_endp (s));
ret = writen (zlookup->sock, s->data, stream_get_endp (s));
2002-12-13 21:15:29 +01:00
if (ret < 0)
{
zlog_err ("can't write to zlookup->sock");
close (zlookup->sock);
zlookup->sock = -1;
return NULL;
}
if (ret == 0)
{
zlog_err ("zlookup->sock connection closed");
close (zlookup->sock);
zlookup->sock = -1;
return NULL;
}
return zlookup_read ();
}
#ifdef HAVE_IPV6
static struct bgp_nexthop_cache *
zlookup_read_ipv6 (void)
2002-12-13 21:15:29 +01:00
{
struct stream *s;
uint16_t length;
u_char version, marker;
uint16_t command;
2002-12-13 21:15:29 +01:00
int nbytes;
struct in6_addr raddr;
uint32_t metric;
2002-12-13 21:15:29 +01:00
int i;
u_char nexthop_num;
struct nexthop *nexthop;
struct bgp_nexthop_cache *bnc;
s = zlookup->ibuf;
stream_reset (s);
nbytes = stream_read (s, zlookup->sock, 2);
length = stream_getw (s);
nbytes = stream_read (s, zlookup->sock, length - 2);
marker = stream_getc (s);
version = stream_getc (s);
if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER)
{
zlog_err("%s: socket %d version mismatch, marker %d, version %d",
__func__, zlookup->sock, marker, version);
return NULL;
}
command = stream_getw (s);
2002-12-13 21:15:29 +01:00
stream_get (&raddr, s, 16);
metric = stream_getl (s);
nexthop_num = stream_getc (s);
if (nexthop_num)
{
bnc = bnc_new ();
bnc->valid = 1;
bnc->metric = metric;
bnc->nexthop_num = nexthop_num;
for (i = 0; i < nexthop_num; i++)
{
nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
2002-12-13 21:15:29 +01:00
nexthop->type = stream_getc (s);
switch (nexthop->type)
{
case ZEBRA_NEXTHOP_IPV6:
stream_get (&nexthop->gate.ipv6, s, 16);
break;
case ZEBRA_NEXTHOP_IPV6_IFINDEX:
case ZEBRA_NEXTHOP_IPV6_IFNAME:
stream_get (&nexthop->gate.ipv6, s, 16);
nexthop->ifindex = stream_getl (s);
break;
case ZEBRA_NEXTHOP_IFINDEX:
case ZEBRA_NEXTHOP_IFNAME:
nexthop->ifindex = stream_getl (s);
break;
default:
/* do nothing */
break;
2002-12-13 21:15:29 +01:00
}
bnc_nexthop_add (bnc, nexthop);
}
}
else
return NULL;
return bnc;
}
struct bgp_nexthop_cache *
zlookup_query_ipv6 (struct in6_addr *addr)
{
int ret;
struct stream *s;
/* Check socket. */
if (zlookup->sock < 0)
return NULL;
s = zlookup->obuf;
stream_reset (s);
zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
2002-12-13 21:15:29 +01:00
stream_put (s, addr, 16);
stream_putw_at (s, 0, stream_get_endp (s));
ret = writen (zlookup->sock, s->data, stream_get_endp (s));
2002-12-13 21:15:29 +01:00
if (ret < 0)
{
zlog_err ("can't write to zlookup->sock");
close (zlookup->sock);
zlookup->sock = -1;
return NULL;
}
if (ret == 0)
{
zlog_err ("zlookup->sock connection closed");
close (zlookup->sock);
zlookup->sock = -1;
return NULL;
}
return zlookup_read_ipv6 ();
}
#endif /* HAVE_IPV6 */
static int
bgp_import_check (struct prefix *p, u_int32_t *igpmetric,
struct in_addr *igpnexthop)
2002-12-13 21:15:29 +01:00
{
struct stream *s;
int ret;
u_int16_t length, command;
u_char version, marker;
2002-12-13 21:15:29 +01:00
int nbytes;
struct in_addr addr;
struct in_addr nexthop;
u_int32_t metric = 0;
u_char nexthop_num;
u_char nexthop_type;
/* If lookup connection is not available return valid. */
if (zlookup->sock < 0)
{
if (igpmetric)
*igpmetric = 0;
return 1;
}
/* Send query to the lookup connection */
s = zlookup->obuf;
stream_reset (s);
zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP);
2002-12-13 21:15:29 +01:00
stream_putc (s, p->prefixlen);
stream_put_in_addr (s, &p->u.prefix4);
stream_putw_at (s, 0, stream_get_endp (s));
2002-12-13 21:15:29 +01:00
/* Write the packet. */
ret = writen (zlookup->sock, s->data, stream_get_endp (s));
2002-12-13 21:15:29 +01:00
if (ret < 0)
{
zlog_err ("can't write to zlookup->sock");
close (zlookup->sock);
zlookup->sock = -1;
return 1;
}
if (ret == 0)
{
zlog_err ("zlookup->sock connection closed");
close (zlookup->sock);
zlookup->sock = -1;
return 1;
}
/* Get result. */
stream_reset (s);
/* Fetch length. */
nbytes = stream_read (s, zlookup->sock, 2);
length = stream_getw (s);
/* Fetch whole data. */
nbytes = stream_read (s, zlookup->sock, length - 2);
marker = stream_getc (s);
version = stream_getc (s);
if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER)
{
zlog_err("%s: socket %d version mismatch, marker %d, version %d",
__func__, zlookup->sock, marker, version);
return 0;
}
command = stream_getw (s);
2002-12-13 21:15:29 +01:00
addr.s_addr = stream_get_ipv4 (s);
metric = stream_getl (s);
nexthop_num = stream_getc (s);
/* Set IGP metric value. */
if (igpmetric)
*igpmetric = metric;
/* If there is nexthop then this is active route. */
if (nexthop_num)
{
nexthop.s_addr = 0;
nexthop_type = stream_getc (s);
switch (nexthop_type)
2002-12-13 21:15:29 +01:00
{
case ZEBRA_NEXTHOP_IPV4:
2002-12-13 21:15:29 +01:00
nexthop.s_addr = stream_get_ipv4 (s);
break;
case ZEBRA_NEXTHOP_IPV4_IFINDEX:
nexthop.s_addr = stream_get_ipv4 (s);
/* ifindex */ (void)stream_getl (s);
break;
default:
/* do nothing */
break;
2002-12-13 21:15:29 +01:00
}
*igpnexthop = nexthop;
2002-12-13 21:15:29 +01:00
return 1;
}
else
return 0;
}
/* Scan all configured BGP route then check the route exists in IGP or
not. */
static int
2002-12-13 21:15:29 +01:00
bgp_import (struct thread *t)
{
struct bgp *bgp;
struct bgp_node *rn;
struct bgp_static *bgp_static;
struct listnode *node, *nnode;
2002-12-13 21:15:29 +01:00
int valid;
u_int32_t metric;
struct in_addr nexthop;
afi_t afi;
safi_t safi;
bgp_import_thread =
thread_add_timer (master, bgp_import, NULL, bgp_import_interval);
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("Import timer expired.");
2002-12-13 21:15:29 +01:00
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
2003-04-28 19:11:02 +02:00
{
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++)
for (rn = bgp_table_top (bgp->route[afi][safi]); rn;
rn = bgp_route_next (rn))
if ((bgp_static = rn->info) != NULL)
2002-12-13 21:15:29 +01:00
{
2003-04-28 19:11:02 +02:00
if (bgp_static->backdoor)
continue;
2002-12-13 21:15:29 +01:00
2003-04-28 19:11:02 +02:00
valid = bgp_static->valid;
metric = bgp_static->igpmetric;
nexthop = bgp_static->igpnexthop;
if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)
&& afi == AFI_IP && safi == SAFI_UNICAST)
bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric,
&bgp_static->igpnexthop);
2002-12-13 21:15:29 +01:00
else
2003-04-28 19:11:02 +02:00
{
bgp_static->valid = 1;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
}
if (bgp_static->valid != valid)
{
if (bgp_static->valid)
bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
else
bgp_static_withdraw (bgp, &rn->p, afi, safi);
}
else if (bgp_static->valid)
{
if (bgp_static->igpmetric != metric
|| bgp_static->igpnexthop.s_addr != nexthop.s_addr
|| bgp_static->rmap.name)
bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
}
2002-12-13 21:15:29 +01:00
}
2003-04-28 19:11:02 +02:00
}
2002-12-13 21:15:29 +01:00
return 0;
}
/* Connect to zebra for nexthop lookup. */
static int
2002-12-13 21:15:29 +01:00
zlookup_connect (struct thread *t)
{
struct zclient *zlookup;
zlookup = THREAD_ARG (t);
zlookup->t_connect = NULL;
if (zlookup->sock != -1)
return 0;
if (zclient_socket_connect (zlookup) < 0)
2002-12-13 21:15:29 +01:00
return -1;
return 0;
}
/* Check specified multiaccess next-hop. */
int
bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer)
{
struct bgp_node *rn1;
struct bgp_node *rn2;
struct prefix p1;
struct prefix p2;
struct in_addr addr;
int ret;
ret = inet_aton (peer, &addr);
if (! ret)
return 0;
memset (&p1, 0, sizeof (struct prefix));
p1.family = AF_INET;
p1.prefixlen = IPV4_MAX_BITLEN;
p1.u.prefix4 = nexthop;
memset (&p2, 0, sizeof (struct prefix));
p2.family = AF_INET;
p2.prefixlen = IPV4_MAX_BITLEN;
p2.u.prefix4 = addr;
/* If bgp scan is not enabled, return invalid. */
if (zlookup->sock < 0)
return 0;
rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1);
2002-12-13 21:15:29 +01:00
if (! rn1)
return 0;
bgp_unlock_node (rn1);
2002-12-13 21:15:29 +01:00
rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2);
2002-12-13 21:15:29 +01:00
if (! rn2)
return 0;
bgp_unlock_node (rn2);
2002-12-13 21:15:29 +01:00
/* This is safe, even with above unlocks, since we are just
comparing pointers to the objects, not the objects themselves. */
2002-12-13 21:15:29 +01:00
if (rn1 == rn2)
return 1;
return 0;
}
2002-12-13 21:15:29 +01:00
DEFUN (bgp_scan_time,
bgp_scan_time_cmd,
"bgp scan-time <5-60>",
"BGP specific commands\n"
"Configure background scanner interval\n"
"Scanner interval (seconds)\n")
{
bgp_scan_interval = atoi (argv[0]);
if (bgp_scan_thread)
{
thread_cancel (bgp_scan_thread);
bgp_scan_thread =
thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval);
2002-12-13 21:15:29 +01:00
}
return CMD_SUCCESS;
}
DEFUN (no_bgp_scan_time,
no_bgp_scan_time_cmd,
"no bgp scan-time",
NO_STR
"BGP specific commands\n"
"Configure background scanner interval\n")
{
bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
if (bgp_scan_thread)
{
thread_cancel (bgp_scan_thread);
bgp_scan_thread =
thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval);
2002-12-13 21:15:29 +01:00
}
return CMD_SUCCESS;
}
ALIAS (no_bgp_scan_time,
no_bgp_scan_time_val_cmd,
"no bgp scan-time <5-60>",
NO_STR
"BGP specific commands\n"
"Configure background scanner interval\n"
"Scanner interval (seconds)\n")
static int
show_ip_bgp_scan_tables (struct vty *vty, const char detail)
2002-12-13 21:15:29 +01:00
{
struct bgp_node *rn;
char buf[INET6_ADDRSTRLEN];
2002-12-13 21:15:29 +01:00
if (bgp_scan_thread)
vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
else
vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE);
vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE);
#if BGP_SCAN_NEXTHOP
2002-12-13 21:15:29 +01:00
vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE);
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn))
2002-12-13 21:15:29 +01:00
if ((bnc = rn->info) != NULL)
{
if (bnc->valid)
{
2002-12-13 21:15:29 +01:00
vty_out (vty, " %s valid [IGP metric %d]%s",
inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE);
if (detail)
for (i = 0; i < bnc->nexthop_num; i++)
switch (bnc->nexthop[i].type)
{
case NEXTHOP_TYPE_IPV4:
vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out (vty, " gate %s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN));
vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
break;
default:
vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
}
}
2002-12-13 21:15:29 +01:00
else
vty_out (vty, " %s invalid%s",
inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
2002-12-13 21:15:29 +01:00
}
#ifdef HAVE_IPV6
{
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
2002-12-13 21:15:29 +01:00
if ((bnc = rn->info) != NULL)
{
if (bnc->valid)
{
2002-12-13 21:15:29 +01:00
vty_out (vty, " %s valid [IGP metric %d]%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
2002-12-13 21:15:29 +01:00
bnc->metric, VTY_NEWLINE);
if (detail)
for (i = 0; i < bnc->nexthop_num; i++)
switch (bnc->nexthop[i].type)
{
case NEXTHOP_TYPE_IPV6:
vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
break;
default:
vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
}
}
2002-12-13 21:15:29 +01:00
else
vty_out (vty, " %s invalid%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
2002-12-13 21:15:29 +01:00
VTY_NEWLINE);
}
}
#endif /* HAVE_IPV6 */
#else
vty_out (vty, "BGP next-hop tracking is on%s", VTY_NEWLINE);
#endif
2002-12-13 21:15:29 +01:00
vty_out (vty, "BGP connected route:%s", VTY_NEWLINE);
for (rn = bgp_table_top (bgp_connected_table[AFI_IP]);
rn;
rn = bgp_route_next (rn))
2002-12-13 21:15:29 +01:00
if (rn->info != NULL)
vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
VTY_NEWLINE);
#ifdef HAVE_IPV6
{
for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
2002-12-13 21:15:29 +01:00
if (rn->info != NULL)
vty_out (vty, " %s/%d%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
2002-12-13 21:15:29 +01:00
rn->p.prefixlen,
VTY_NEWLINE);
}
#endif /* HAVE_IPV6 */
return CMD_SUCCESS;
}
static int
show_ip_bgp_nexthop_table (struct vty *vty, int detail)
{
struct bgp_node *rn;
struct bgp_nexthop_cache *bnc;
char buf[INET6_ADDRSTRLEN];
time_t tbuf;
u_char i;
vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE);
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn))
if ((bnc = rn->info) != NULL)
{
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))
{
vty_out (vty, " %s valid [IGP metric %d], #paths %d%s",
inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN),
bnc->metric, bnc->path_count, VTY_NEWLINE);
if (detail)
for (i = 0; i < bnc->nexthop_num; i++)
switch (bnc->nexthop[i].type)
{
case NEXTHOP_TYPE_IPV4:
vty_out (vty, " gate %s%s",
inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf,
INET6_ADDRSTRLEN), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " if %s%s",
ifindex2ifname(bnc->nexthop[i].ifindex), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out (vty, " gate %s, if %s%s",
inet_ntop(AF_INET, &bnc->nexthop[i].gate.ipv4, buf,
INET6_ADDRSTRLEN),
ifindex2ifname(bnc->nexthop[i].ifindex), VTY_NEWLINE);
break;
default:
vty_out (vty, " invalid nexthop type %u%s",
bnc->nexthop[i].type, VTY_NEWLINE);
}
}
else
vty_out (vty, " %s invalid%s",
inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
#ifdef HAVE_CLOCK_MONOTONIC
tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
vty_out (vty, " Last update: %s", ctime(&tbuf));
#else
vty_out (vty, " Last update: %s", ctime(&bnc->uptime));
#endif /* HAVE_CLOCK_MONOTONIC */
vty_out(vty, "%s", VTY_NEWLINE);
}
#ifdef HAVE_IPV6
{
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
if ((bnc = rn->info) != NULL)
{
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))
{
vty_out (vty, " %s valid [IGP metric %d]%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf,
INET6_ADDRSTRLEN),
bnc->metric, VTY_NEWLINE);
if (detail)
for (i = 0; i < bnc->nexthop_num; i++)
switch (bnc->nexthop[i].type)
{
case NEXTHOP_TYPE_IPV6:
vty_out (vty, " gate %s%s",
inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6,
buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
vty_out(vty, " gate %s, if %s%s",
inet_ntop(AF_INET6, &bnc->nexthop[i].gate.ipv6, buf,
INET6_ADDRSTRLEN),
ifindex2ifname(bnc->nexthop[i].ifindex),
VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex,
VTY_NEWLINE);
break;
default:
vty_out (vty, " invalid nexthop type %u%s",
bnc->nexthop[i].type, VTY_NEWLINE);
}
}
else
vty_out (vty, " %s invalid%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
VTY_NEWLINE);
#ifdef HAVE_CLOCK_MONOTONIC
tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
vty_out (vty, " Last update: %s", ctime(&tbuf));
#else
vty_out (vty, " Last update: %s", ctime(&bnc->uptime));
#endif /* HAVE_CLOCK_MONOTONIC */
vty_out(vty, "%s", VTY_NEWLINE);
}
}
#endif /* HAVE_IPV6 */
return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_scan,
show_ip_bgp_scan_cmd,
"show ip bgp scan",
SHOW_STR
IP_STR
BGP_STR
"BGP scan status\n")
{
return show_ip_bgp_scan_tables (vty, 0);
}
DEFUN (show_ip_bgp_scan_detail,
show_ip_bgp_scan_detail_cmd,
"show ip bgp scan detail",
SHOW_STR
IP_STR
BGP_STR
"BGP scan status\n"
"More detailed output\n")
{
return show_ip_bgp_scan_tables (vty, 1);
}
DEFUN (show_ip_bgp_nexthop,
show_ip_bgp_nexthop_cmd,
"show ip bgp nexthop",
SHOW_STR
IP_STR
BGP_STR
"BGP nexthop table\n")
{
return show_ip_bgp_nexthop_table (vty, 0);
}
DEFUN (show_ip_bgp_nexthop_detail,
show_ip_bgp_nexthop_detail_cmd,
"show ip bgp nexthop detail",
SHOW_STR
IP_STR
BGP_STR
"BGP nexthop table\n")
{
return show_ip_bgp_nexthop_table (vty, 1);
}
2002-12-13 21:15:29 +01:00
int
bgp_config_write_scan_time (struct vty *vty)
{
if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT)
vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE);
return CMD_SUCCESS;
}
void
bgp_scan_init (void)
2002-12-13 21:15:29 +01:00
{
zlookup = zclient_new ();
zlookup->sock = -1;
zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0);
bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT;
[bgpd] Record afi/safi in bgp_table. Serialise peer clear with FSM. 2006-02-21 Paul Jakma <paul.jakma@sun.com> * bgpd.h: move the clear_node_queue to be peer specific. Add a new peer status flag, PEER_STATUS_CLEARING. * bgp_table.h: (struct bgp_table) Add fields to record afi, safi of the table. (bgp_table_init) Take afi and safi to create table for. * bgp_table.c: (bgp_table_init) record the afi and safi. * bgp_nexthop.c: Update all calls to bgp_table_init. * bgp_vty.c: ditto. * bgpd.c: ditto. * bgp_fsm.c: (bgp_timer_set) dont bring up a session which is clearing. * bgp_route.c: (general) Update all bgp_table_init calls. (bgp_process_{rsclient,main}) clear_node is serialised via PEER_STATUS_CLEARING and fsm now. (struct bgp_clear_node_queue) can be removed. struct bgp_node can be the queue item data directly, as struct peer can be kept in the new wq global user data and afi/safi can be retrieved via bgp_node -> bgp_table. (bgp_clear_route_node) fix to get peer via wq->spec.data, afi/safi via bgp_node->bgp_table. (bgp_clear_node_queue_del) no more item data to delete, only unlock the bgp_node. (bgp_clear_node_complete) only need to unset CLEARING flag and unlock struct peer. (bgp_clear_node_queue_init) queue attaches to struct peer now. record peer name as queue name. (bgp_clear_route_table) If queue transitions to active, serialise clearing by setting PEER_STATUS_CLEARING rather than plugging process queue, and lock peer while queue active. Update to pass only bgp_node as per-queue-item specific data.
2006-02-21 02:09:01 +01:00
cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
cache2_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP];
2002-12-13 21:15:29 +01:00
[bgpd] Record afi/safi in bgp_table. Serialise peer clear with FSM. 2006-02-21 Paul Jakma <paul.jakma@sun.com> * bgpd.h: move the clear_node_queue to be peer specific. Add a new peer status flag, PEER_STATUS_CLEARING. * bgp_table.h: (struct bgp_table) Add fields to record afi, safi of the table. (bgp_table_init) Take afi and safi to create table for. * bgp_table.c: (bgp_table_init) record the afi and safi. * bgp_nexthop.c: Update all calls to bgp_table_init. * bgp_vty.c: ditto. * bgpd.c: ditto. * bgp_fsm.c: (bgp_timer_set) dont bring up a session which is clearing. * bgp_route.c: (general) Update all bgp_table_init calls. (bgp_process_{rsclient,main}) clear_node is serialised via PEER_STATUS_CLEARING and fsm now. (struct bgp_clear_node_queue) can be removed. struct bgp_node can be the queue item data directly, as struct peer can be kept in the new wq global user data and afi/safi can be retrieved via bgp_node -> bgp_table. (bgp_clear_route_node) fix to get peer via wq->spec.data, afi/safi via bgp_node->bgp_table. (bgp_clear_node_queue_del) no more item data to delete, only unlock the bgp_node. (bgp_clear_node_complete) only need to unset CLEARING flag and unlock struct peer. (bgp_clear_node_queue_init) queue attaches to struct peer now. record peer name as queue name. (bgp_clear_route_table) If queue transitions to active, serialise clearing by setting PEER_STATUS_CLEARING rather than plugging process queue, and lock peer while queue active. Update to pass only bgp_node as per-queue-item specific data.
2006-02-21 02:09:01 +01:00
bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
#ifdef HAVE_IPV6
[bgpd] Record afi/safi in bgp_table. Serialise peer clear with FSM. 2006-02-21 Paul Jakma <paul.jakma@sun.com> * bgpd.h: move the clear_node_queue to be peer specific. Add a new peer status flag, PEER_STATUS_CLEARING. * bgp_table.h: (struct bgp_table) Add fields to record afi, safi of the table. (bgp_table_init) Take afi and safi to create table for. * bgp_table.c: (bgp_table_init) record the afi and safi. * bgp_nexthop.c: Update all calls to bgp_table_init. * bgp_vty.c: ditto. * bgpd.c: ditto. * bgp_fsm.c: (bgp_timer_set) dont bring up a session which is clearing. * bgp_route.c: (general) Update all bgp_table_init calls. (bgp_process_{rsclient,main}) clear_node is serialised via PEER_STATUS_CLEARING and fsm now. (struct bgp_clear_node_queue) can be removed. struct bgp_node can be the queue item data directly, as struct peer can be kept in the new wq global user data and afi/safi can be retrieved via bgp_node -> bgp_table. (bgp_clear_route_node) fix to get peer via wq->spec.data, afi/safi via bgp_node->bgp_table. (bgp_clear_node_queue_del) no more item data to delete, only unlock the bgp_node. (bgp_clear_node_complete) only need to unset CLEARING flag and unlock struct peer. (bgp_clear_node_queue_init) queue attaches to struct peer now. record peer name as queue name. (bgp_clear_route_table) If queue transitions to active, serialise clearing by setting PEER_STATUS_CLEARING rather than plugging process queue, and lock peer while queue active. Update to pass only bgp_node as per-queue-item specific data.
2006-02-21 02:09:01 +01:00
cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
cache2_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6];
[bgpd] Record afi/safi in bgp_table. Serialise peer clear with FSM. 2006-02-21 Paul Jakma <paul.jakma@sun.com> * bgpd.h: move the clear_node_queue to be peer specific. Add a new peer status flag, PEER_STATUS_CLEARING. * bgp_table.h: (struct bgp_table) Add fields to record afi, safi of the table. (bgp_table_init) Take afi and safi to create table for. * bgp_table.c: (bgp_table_init) record the afi and safi. * bgp_nexthop.c: Update all calls to bgp_table_init. * bgp_vty.c: ditto. * bgpd.c: ditto. * bgp_fsm.c: (bgp_timer_set) dont bring up a session which is clearing. * bgp_route.c: (general) Update all bgp_table_init calls. (bgp_process_{rsclient,main}) clear_node is serialised via PEER_STATUS_CLEARING and fsm now. (struct bgp_clear_node_queue) can be removed. struct bgp_node can be the queue item data directly, as struct peer can be kept in the new wq global user data and afi/safi can be retrieved via bgp_node -> bgp_table. (bgp_clear_route_node) fix to get peer via wq->spec.data, afi/safi via bgp_node->bgp_table. (bgp_clear_node_queue_del) no more item data to delete, only unlock the bgp_node. (bgp_clear_node_complete) only need to unset CLEARING flag and unlock struct peer. (bgp_clear_node_queue_init) queue attaches to struct peer now. record peer name as queue name. (bgp_clear_route_table) If queue transitions to active, serialise clearing by setting PEER_STATUS_CLEARING rather than plugging process queue, and lock peer while queue active. Update to pass only bgp_node as per-queue-item specific data.
2006-02-21 02:09:01 +01:00
bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
2002-12-13 21:15:29 +01:00
#endif /* HAVE_IPV6 */
/* Make BGP scan thread. */
bgp_scan_thread = thread_add_timer (master, bgp_scan_timer,
NULL, bgp_scan_interval);
2003-04-28 19:11:02 +02:00
/* Make BGP import there. */
bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0);
2002-12-13 21:15:29 +01:00
install_element (BGP_NODE, &bgp_scan_time_cmd);
install_element (BGP_NODE, &no_bgp_scan_time_cmd);
install_element (BGP_NODE, &no_bgp_scan_time_val_cmd);
install_element (VIEW_NODE, &show_ip_bgp_scan_cmd);
install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd);
install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd);
install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd);
2002-12-13 21:15:29 +01:00
install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_nexthop_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_nexthop_detail_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd);
2002-12-13 21:15:29 +01:00
}
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
void
bgp_scan_finish (void)
{
/* Only the current one needs to be reset. */
bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]);
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
bgp_table_unlock (cache1_table[AFI_IP]);
cache1_table[AFI_IP] = NULL;
bgp_table_unlock (cache2_table[AFI_IP]);
cache2_table[AFI_IP] = NULL;
bgp_table_unlock (bgp_connected_table[AFI_IP]);
bgp_connected_table[AFI_IP] = NULL;
#ifdef HAVE_IPV6
/* Only the current one needs to be reset. */
bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]);
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
bgp_table_unlock (cache1_table[AFI_IP6]);
cache1_table[AFI_IP6] = NULL;
bgp_table_unlock (cache2_table[AFI_IP6]);
cache2_table[AFI_IP6] = NULL;
bgp_table_unlock (bgp_connected_table[AFI_IP6]);
bgp_connected_table[AFI_IP6] = NULL;
#endif /* HAVE_IPV6 */
}