diff options
-rw-r--r-- | bgpd/bgp_fsm.c | 46 | ||||
-rw-r--r-- | bgpd/bgp_fsm.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_main.c | 9 | ||||
-rw-r--r-- | bgpd/bgp_nexthop.c | 1057 | ||||
-rw-r--r-- | bgpd/bgp_nexthop.h | 28 | ||||
-rw-r--r-- | bgpd/bgp_nht.c | 94 | ||||
-rw-r--r-- | bgpd/bgp_nht.h | 16 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 15 | ||||
-rw-r--r-- | bgpd/bgp_packet.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 163 | ||||
-rw-r--r-- | bgpd/bgpd.c | 53 | ||||
-rw-r--r-- | zebra/zebra_rnh.c | 14 | ||||
-rw-r--r-- | zebra/zebra_rnh.h | 1 | ||||
-rw-r--r-- | zebra/zserv.c | 11 |
14 files changed, 340 insertions, 1169 deletions
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 2059a98d1..13325190a 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1185,6 +1185,7 @@ int bgp_start (struct peer *peer) { int status; + int connected = 0; bgp_peer_conf_if_to_su_update(peer); @@ -1225,6 +1226,12 @@ bgp_start (struct peer *peer) return 0; } + /* Register to be notified on peer up */ + if ((peer->ttl == 1) || (peer->gtsm_hops == 1)) + connected = 1; + + bgp_find_or_add_nexthop(family2afi(peer->su.sa.sa_family), NULL, peer, + connected); status = bgp_connect (peer); switch (status) @@ -1492,6 +1499,45 @@ bgp_ignore (struct peer *peer) return 0; } +void +bgp_fsm_nht_update(struct peer *peer, int valid) +{ + int ret = 0; + + if (!peer) + return; + + switch (peer->status) + { + case Idle: + if (valid) + BGP_EVENT_ADD(peer, BGP_Start); + break; + case Connect: + ret = bgp_connect_check(peer, 0); + if (!ret && valid) + { + BGP_TIMER_OFF(peer->t_connect); + BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); + } + break; + case Active: + if (valid) + { + BGP_TIMER_OFF(peer->t_connect); + BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); + } + case OpenSent: + case OpenConfirm: + case Established: + case Clearing: + case Deleted: + default: + break; + } +} + + /* Finite State Machine structure */ static const struct { int (*func) (struct peer *); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index a1a3ce4d5..bd6c416d3 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -74,6 +74,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_MSEC_JITTER 10 /* Prototypes. */ +extern void bgp_fsm_nht_update(struct peer *, int valid); extern int bgp_event (struct thread *); extern int bgp_event_update (struct peer *, int event); extern int bgp_stop (struct peer *peer); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index ae73afc0a..b9d114f4d 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -227,7 +227,6 @@ bgp_exit (int status) int *socket; struct interface *ifp; extern struct zclient *zclient; - extern struct zclient *zlookup; /* it only makes sense for this to be called on a clean exit */ assert (status == 0); @@ -266,9 +265,6 @@ bgp_exit (int status) /* cleanup route maps */ bgp_route_map_terminate(); - /* reverse bgp_scan_init */ - bgp_scan_finish (); - /* reverse access_list_init */ access_list_add_hook (NULL); access_list_delete_hook (NULL); @@ -291,13 +287,14 @@ bgp_exit (int status) vty_terminate (); if (zclient) zclient_free (zclient); - if (zlookup) - zclient_free (zlookup); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); if (bgp_ifindices_buf) stream_free (bgp_ifindices_buf); + /* reverse bgp_scan_init */ + bgp_scan_finish (); + /* reverse bgp_master_init */ if (master) thread_master_free (master); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 258120123..df3c90343 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -43,35 +43,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ -extern struct zclient *zclient; -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 */ - -/* Only one BGP scan thread are activated at the same time. */ -static struct thread *bgp_scan_thread = NULL; - -/* BGP import thread */ -static struct thread *bgp_import_thread = NULL; - -/* BGP scan interval. */ -static int bgp_scan_interval; - -/* BGP import interval. */ -static int bgp_import_interval; /* 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]; /* Route table for connected route. */ static struct bgp_table *bgp_connected_table[AFI_MAX]; -/* BGP nexthop lookup query client. */ -struct zclient *zlookup = NULL; char * bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) @@ -80,21 +60,6 @@ bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) return buf; } -/* Add nexthop to the end of the list. */ -static void -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 bnc_nexthop_free (struct bgp_nexthop_cache *bnc) { @@ -125,40 +90,12 @@ bnc_free (struct bgp_nexthop_cache *bnc) XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } -static int -bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, - 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)) - 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) { struct bgp_node *rn; - /* If zebra is not enabled return */ - if (zlookup->sock < 0) - return 1; - /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { @@ -192,178 +129,6 @@ bgp_nexthop_onlink (afi_t afi, struct attr *attr) return 0; } -#ifdef HAVE_IPV6 -/* Check specified next-hop is reachable or not. */ -static int -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; - } - - /* 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)) - 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; - - /* IBGP or ebgp-multihop */ - rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); - - 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 - { - 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]; - else - old = cache1_table[AFI_IP6]; - - oldrn = bgp_node_lookup (old, &p); - if (oldrn) - { - struct bgp_nexthop_cache *oldbnc = oldrn->info; - - bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); - - if (bnc->metric != oldbnc->metric) - bnc->metricchanged = 1; - - bgp_unlock_node (oldrn); - } - } - } - 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; - - 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; - } - -#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); - - if (rn->info) - { - bnc = rn->info; - bgp_unlock_node (rn); - } - else - { - if (NULL == (bnc = zlookup_query (addr))) - bnc = bnc_new (); - else - { - 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]; - else - old = cache1_table[AFI_IP]; - - oldrn = bgp_node_lookup (old, &p); - if (oldrn) - { - struct bgp_nexthop_cache *oldbnc = oldrn->info; - - bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); - - if (bnc->metric != oldbnc->metric) - bnc->metricchanged = 1; - - bgp_unlock_node (oldrn); - } - } - } - 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; - - return bnc->valid; -} - /* Reset and free all BGP nexthop cache. */ static void bgp_nexthop_cache_reset (struct bgp_table *table) @@ -380,148 +145,6 @@ bgp_nexthop_cache_reset (struct bgp_table *table) } } -static void -bgp_scan (afi_t afi, safi_t safi) -{ - 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 - 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]; - else - bgp_nexthop_cache_table[afi] = cache1_table[afi]; -#endif - - /* Get default bgp. */ - bgp = bgp_get_default (); - if (bgp == NULL) - return; - - /* Maximum prefix check */ - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - { - 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); - } - - for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn; - 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 - 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); - else - valid = bgp_nexthop_lookup (afi, bi->peer, bi, - &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); - } - else - { - bgp_info_set_flag (rn, bi, BGP_INFO_VALID); - bgp_aggregate_increment (bgp, &rn->p, bi, - afi, SAFI_UNICAST); - } - } -#endif - - if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], - BGP_CONFIG_DAMPENING) - && bi->extra && bi->extra->damp_info ) - if (bgp_damp_scan (bi, afi, SAFI_UNICAST)) - bgp_aggregate_increment (bgp, &rn->p, bi, - afi, SAFI_UNICAST); - } - } - bgp_process (bgp, rn, afi, SAFI_UNICAST); - } - -#if BGP_SCAN_NEXTHOP - /* Flash old cache. */ - if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) - bgp_nexthop_cache_reset (cache2_table[afi]); - 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); - } -} - -/* BGP scan thread. This thread check nexthop reachability. */ -static int -bgp_scan_timer (struct thread *t) -{ - bgp_scan_thread = - thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); - - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("Performing BGP general scanning"); - - bgp_scan (AFI_IP, SAFI_UNICAST); - -#ifdef HAVE_IPV6 - bgp_scan (AFI_IP6, SAFI_UNICAST); -#endif /* HAVE_IPV6 */ - - return 0; -} - /* BGP own address structure */ struct bgp_addr { @@ -764,617 +387,40 @@ bgp_nexthop_self (struct attr *attr) return 0; } -static struct bgp_nexthop_cache * -zlookup_read (void) -{ - struct stream *s; - uint16_t length; - u_char marker; - u_char version; - uint16_t command; - int nbytes; - struct in_addr raddr; - uint32_t metric; - 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); - - 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)); - 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; - case ZEBRA_NEXTHOP_IFINDEX: - case ZEBRA_NEXTHOP_IFNAME: - nexthop->ifindex = stream_getl (s); - break; - default: - /* do nothing */ - break; - } - 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); - 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)); - 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) -{ - struct stream *s; - uint16_t length; - u_char version, marker; - uint16_t command; - int nbytes; - struct in6_addr raddr; - uint32_t metric; - 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); - - 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)); - 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; - } - 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); - stream_put (s, addr, 16); - stream_putw_at (s, 0, stream_get_endp (s)); - - ret = writen (zlookup->sock, s->data, stream_get_endp (s)); - 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) -{ - struct stream *s; - int ret; - u_int16_t length, command; - u_char version, marker; - 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); - - stream_putc (s, p->prefixlen); - stream_put_in_addr (s, &p->u.prefix4); - - stream_putw_at (s, 0, stream_get_endp (s)); - - /* Write the packet. */ - ret = writen (zlookup->sock, s->data, stream_get_endp (s)); - - 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); - - 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) - { - case ZEBRA_NEXTHOP_IPV4: - 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; - } - *igpnexthop = nexthop; - - return 1; - } - else - return 0; -} - -/* Scan all configured BGP route then check the route exists in IGP or - not. */ -static int -bgp_import (struct thread *t) -{ - struct bgp *bgp; - struct bgp_node *rn; - struct bgp_static *bgp_static; - struct listnode *node, *nnode; - 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."); - - for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) - { - 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) - { - if (bgp_static->backdoor) - continue; - - 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); - else - { - 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); - } - } - } - return 0; -} - -/* Connect to zebra for nexthop lookup. */ -static int -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) - return -1; - - return 0; -} -/* Check specified multiaccess next-hop. */ int -bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) +bgp_multiaccess_check_v4 (struct in_addr nexthop, struct peer *peer) { struct bgp_node *rn1; struct bgp_node *rn2; - struct prefix p1; - struct prefix p2; - struct in_addr addr; + struct prefix p; 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; + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = nexthop; - rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); - if (! rn1) + rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p); + if (!rn1) return 0; - bgp_unlock_node (rn1); - - rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); - if (! rn2) - return 0; - bgp_unlock_node (rn2); - - /* This is safe, even with above unlocks, since we are just - comparing pointers to the objects, not the objects themselves. */ - if (rn1 == rn2) - return 1; - - return 0; -} - -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); - } - - 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; + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = peer->su.sin.sin_addr; - if (bgp_scan_thread) + rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p); + if (!rn2) { - thread_cancel (bgp_scan_thread); - bgp_scan_thread = - thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); + bgp_unlock_node(rn1); + return 0; } - 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) -{ - struct bgp_node *rn; - char buf[INET6_ADDRSTRLEN]; - struct nexthop *nexthop; - - 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 - 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 (bnc->valid) - { - 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 (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " gate %s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN)); - vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); - break; - default: - vty_out (vty, " invalid nexthop type %u%s", nexthop->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_IPV6 - { - for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); - rn; - rn = bgp_route_next (rn)) - if ((bnc = rn->info) != NULL) - { - if (bnc->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 (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV6: - vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); - break; - default: - vty_out (vty, " invalid nexthop type %u%s", nexthop->type, VTY_NEWLINE); - } - } - else - vty_out (vty, " %s invalid%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), - VTY_NEWLINE); - } - } -#endif /* HAVE_IPV6 */ -#else - vty_out (vty, "BGP next-hop tracking is on%s", VTY_NEWLINE); -#endif - 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)) - if (rn->info != NULL) - vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, - VTY_NEWLINE); + ret = (rn1 == rn2) ? 1 : 0; -#ifdef HAVE_IPV6 - { - for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); - rn; - rn = bgp_route_next (rn)) - if (rn->info != NULL) - vty_out (vty, " %s/%d%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), - rn->p.prefixlen, - VTY_NEWLINE); - } -#endif /* HAVE_IPV6 */ + bgp_unlock_node(rn1); + bgp_unlock_node(rn2); - return CMD_SUCCESS; + return (ret); } static int @@ -1489,29 +535,6 @@ show_ip_bgp_nexthop_table (struct vty *vty, int detail) 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", @@ -1534,55 +557,29 @@ DEFUN (show_ip_bgp_nexthop_detail, return show_ip_bgp_nexthop_table (vty, 1); } -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) { - 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; - 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]; bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); #ifdef HAVE_IPV6 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]; bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); #endif /* HAVE_IPV6 */ - /* Make BGP scan thread. */ - bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, - NULL, bgp_scan_interval); - /* Make BGP import there. */ - bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0); - - 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); +} + +void +bgp_scan_vty_init() +{ + install_element (ENABLE_NODE, &show_ip_bgp_nexthop_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); - 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); } void @@ -1594,9 +591,6 @@ bgp_scan_finish (void) 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; @@ -1607,9 +601,6 @@ bgp_scan_finish (void) 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 */ diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index abcf24263..4d582465f 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -25,21 +25,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "queue.h" #include "prefix.h" -#define BGP_SCAN_INTERVAL_DEFAULT 60 -#define BGP_IMPORT_INTERVAL_DEFAULT 15 - /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { - /* This nexthop exists in IGP. */ - u_char valid; - - /* Nexthop is changed. */ - u_char changed; - - /* Nexthop is changed. */ - u_char metricchanged; - /* IGP route's metric. */ u_int32_t metric; @@ -49,26 +37,28 @@ struct bgp_nexthop_cache time_t last_update; u_int16_t flags; -#define BGP_NEXTHOP_VALID (1 << 0) -#define BGP_NEXTHOP_REGISTERED (1 << 1) +#define BGP_NEXTHOP_VALID (1 << 0) +#define BGP_NEXTHOP_REGISTERED (1 << 1) +#define BGP_NEXTHOP_CONNECTED (1 << 2) +#define BGP_NEXTHOP_PEER_NOTIFIED (1 << 3) u_int16_t change_flags; -#define BGP_NEXTHOP_CHANGED (1 << 0) -#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) +#define BGP_NEXTHOP_CHANGED (1 << 0) +#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) +#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) struct bgp_node *node; + void *nht_info; /* In BGP, peer session */ LIST_HEAD(path_list, bgp_info) paths; unsigned int path_count; }; -extern void bgp_scan_init (void); -extern void bgp_scan_finish (void); extern int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, int *, int *); extern void bgp_connected_add (struct connected *c); extern void bgp_connected_delete (struct connected *c); -extern int bgp_multiaccess_check_v4 (struct in_addr, char *); +extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *); extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (struct attr *); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8f5f1af96..df479bf25 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -50,19 +50,15 @@ static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, int keep); int -bgp_find_nexthop (struct bgp_info *path, int *changed, int *metricchanged) +bgp_find_nexthop (struct bgp_info *path, int connected) { struct bgp_nexthop_cache *bnc = path->nexthop; if (!bnc) return 0; - if (changed) - *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); - - if (metricchanged) - *metricchanged = CHECK_FLAG(bnc->change_flags, - BGP_NEXTHOP_METRIC_CHANGED); + if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) + return 0; return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } @@ -77,7 +73,7 @@ bgp_unlink_nexthop (struct bgp_info *path) path_nh_map(path, NULL, 0); - if (LIST_EMPTY(&(bnc->paths))) + if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { if (BGP_DEBUG(nht, NHT)) { @@ -93,15 +89,34 @@ bgp_unlink_nexthop (struct bgp_info *path) } int -bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed, - int *metricchanged) +bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, + int connected) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; struct prefix p; - if (make_prefix(afi, ri, &p) < 0) - return 1; + if (ri) + { + if (make_prefix(afi, ri, &p) < 0) + return 1; + } + else if (peer) + { + if (afi == AFI_IP) + { + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = peer->su.sin.sin_addr; + } + else if (afi == AFI_IP6) + { + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = peer->su.sin6.sin6_addr; + } + } + rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); if (!rn->info) @@ -110,23 +125,27 @@ bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed, rn->info = bnc; bnc->node = rn; bgp_lock_node(rn); - register_nexthop(bnc); + if (connected) + SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); } + bnc = rn->info; bgp_unlock_node (rn); - path_nh_map(ri, bnc, 1); - if (changed) - *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); + if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) + register_nexthop(bnc); - if (metricchanged) - *metricchanged = CHECK_FLAG(bnc->change_flags, - BGP_NEXTHOP_METRIC_CHANGED); + if (ri) + { + path_nh_map(ri, bnc, 1); - if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) - (bgp_info_extra_get(ri))->igpmetric = bnc->metric; - else if (ri->extra) - ri->extra->igpmetric = 0; + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) + (bgp_info_extra_get(ri))->igpmetric = bnc->metric; + else if (ri->extra) + ri->extra->igpmetric = 0; + } + else if (peer) + bnc->nht_info = (void *)peer; return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } @@ -265,6 +284,7 @@ bgp_parse_nexthop_update (void) else { bnc->flags &= ~BGP_NEXTHOP_VALID; + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); bnc_nexthop_free(bnc); bnc->nexthop = NULL; } @@ -322,12 +342,21 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) /* Check socket. */ if (!zclient || zclient->sock < 0) - return; + { + zlog_debug("%s: Can't send NH register, Zebra client not established", + __FUNCTION__); + return; + } p = &(bnc->node->p); s = zclient->obuf; stream_reset (s); zclient_create_header (s, command); + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + stream_putc(s, 1); + else + stream_putc(s, 0); + stream_putw(s, PREFIX_FAMILY(p)); stream_putc(s, p->prefixlen); switch (PREFIX_FAMILY(p)) @@ -349,6 +378,11 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) /* TBD: handle the failure */ if (ret < 0) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); + + if (command == ZEBRA_NEXTHOP_REGISTER) + SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + else if (command == ZEBRA_NEXTHOP_UNREGISTER) + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); return; } @@ -367,7 +401,6 @@ register_nexthop (struct bgp_nexthop_cache *bnc) if (bnc->flags & BGP_NEXTHOP_REGISTERED) return; sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER); - SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); } /** @@ -385,7 +418,6 @@ unregister_nexthop (struct bgp_nexthop_cache *bnc) return; sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER); - UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); } /** @@ -402,6 +434,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) struct bgp_info *path; struct bgp *bgp = bgp_get_default(); int afi; + struct peer *peer = (struct peer *)bnc->nht_info; LIST_FOREACH(path, &(bnc->paths), nh_thread) { @@ -444,6 +477,15 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) bgp_process(bgp, rn, afi, SAFI_UNICAST); } + + if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) + { + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host); + bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); + SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); + } + RESET_FLAG(bnc->change_flags); } diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 0e43f0a44..0897d43a0 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -31,12 +31,9 @@ extern void bgp_parse_nexthop_update(); * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object * ARGUMENTS: * p - path for which the nexthop object is being looked up - * c - output variable that stores whether the nexthop object has changed - * since last time. - * m - output variable that stores whether the nexthop metric has changed - * since last time. + * connected - True if NH MUST be a connected route */ -extern int bgp_find_nexthop(struct bgp_info *p, int *c, int *m); +extern int bgp_find_nexthop(struct bgp_info *p, int connected); /** * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc @@ -45,12 +42,11 @@ extern int bgp_find_nexthop(struct bgp_info *p, int *c, int *m); * ARGUMENTS: * a - afi: AFI_IP or AF_IP6 * p - path for which the nexthop object is being looked up - * c - output variable that stores whether the nexthop object has changed - * since last time. - * m - output variable that stores whether the nexthop metric has changed - * since last time. + * peer - The BGP peer associated with this NHT + * connected - True if NH MUST be a connected route */ -extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, int *c, int *m); +extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, + struct peer *peer, int connected); /** * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure. diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index cd96cbcf1..ec7b0d60b 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -100,8 +100,8 @@ bgp_packet_delete (struct peer *peer) } /* Check file descriptor whether connect is established. */ -static void -bgp_connect_check (struct peer *peer) +int +bgp_connect_check (struct peer *peer, int change_state) { int status; socklen_t slen; @@ -120,20 +120,23 @@ bgp_connect_check (struct peer *peer) { zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); - return; + return -1; } /* When status is 0 then TCP connection is established. */ if (status == 0) { BGP_EVENT_ADD (peer, TCP_connection_open); + return 1; } else { if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect failed (%s)", peer->host, safe_strerror (errno)); - BGP_EVENT_ADD (peer, TCP_connection_open_failed); + if (change_state) + BGP_EVENT_ADD (peer, TCP_connection_open_failed); + return 0; } } @@ -698,7 +701,7 @@ bgp_write (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer); + bgp_connect_check (peer, 1); return 0; } @@ -2541,7 +2544,7 @@ bgp_read (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer); + bgp_connect_check (peer, 1); goto done; } else diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 79390ec8a..fe3917f92 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -40,6 +40,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Packet send and receive function prototypes. */ extern int bgp_read (struct thread *); extern int bgp_write (struct thread *); +extern int bgp_connect_check (struct peer *, int change_state); extern void bgp_keepalive_send (struct peer *); extern void bgp_open_send (struct peer *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d45ffd0e1..4638d7512 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -55,7 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" -#include "bgpd/bgp_nht.c" +#include "bgpd/bgp_nht.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -1064,7 +1064,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ || (peer->sort == BGP_PEER_EBGP - && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) + && (bgp_multiaccess_check_v4 (attr->nexthop, peer) == 0))) { /* Set IPv4 nexthop. */ if (p->family == AF_INET) @@ -2229,6 +2229,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; + int connected = 0; bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); @@ -2306,17 +2307,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) { - /* If the peer is EBGP and nexthop is not on connected route, - discard it. */ - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 - && ! bgp_nexthop_onlink (afi, &new_attr) - && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) - { - reason = "non-connected next-hop;"; - bgp_attr_flush (&new_attr); - goto filtered; - } - /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ if (new_attr.nexthop.s_addr == 0 @@ -2443,20 +2433,29 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && safi == SAFI_UNICAST - && (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED - || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) - || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { - if (bgp_find_or_add_nexthop (afi, ri, NULL, NULL)) + if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && + ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + connected = 1; + else + connected = 0; + + if (bgp_find_or_add_nexthop (afi, ri, NULL, connected)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else - bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + } } else - bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); @@ -2484,17 +2483,26 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, memcpy ((bgp_info_extra_get (new))->tag, tag, 3); /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && safi == SAFI_UNICAST - && (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED - || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) - || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) - { - if (bgp_find_or_add_nexthop (afi, new, NULL, NULL)) + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) + { + if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && + ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + connected = 1; + else + connected = 0; + + if (bgp_find_or_add_nexthop (afi, new, NULL, connected)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else - bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + } } else bgp_info_set_flag (rn, new, BGP_INFO_VALID); @@ -3558,6 +3566,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, ri->attr = attr_new; ri->uptime = bgp_clock (); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, ri, NULL, 0)) + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, + buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + } + } /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); @@ -3570,7 +3595,25 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, /* Make new BGP info. */ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); - SET_FLAG (new->flags, BGP_INFO_VALID); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, new, NULL, 0)) + bgp_info_set_flag (rn, new, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, + buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + } + } + else + bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Register new BGP information. */ bgp_info_add (rn, new); @@ -3588,7 +3631,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, static void bgp_static_update_main (struct bgp *bgp, struct prefix *p, - struct bgp_static *bgp_static, afi_t afi, safi_t safi) + struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; @@ -3672,6 +3715,23 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, ri->attr = attr_new; ri->uptime = bgp_clock (); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, ri, NULL, 0)) + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, + buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + } + } /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); @@ -3685,7 +3745,25 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, /* Make new BGP info. */ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); - SET_FLAG (new->flags, BGP_INFO_VALID); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, new, NULL, 0)) + bgp_info_set_flag (rn, new, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, + INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + } + } + else + bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); @@ -3770,6 +3848,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, safi); + bgp_unlink_nexthop(ri); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } @@ -3906,17 +3985,12 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, rn->info = bgp_static; } - /* If BGP scan is not enabled, we should install this route here. */ - if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) - { - bgp_static->valid = 1; - - if (need_update) - bgp_static_withdraw (bgp, &p, afi, safi); + bgp_static->valid = 1; + if (need_update) + bgp_static_withdraw (bgp, &p, afi, safi); - if (! bgp_static->backdoor) - bgp_static_update (bgp, &p, bgp_static, afi, safi); - } + if (! bgp_static->backdoor) + bgp_static_update (bgp, &p, bgp_static, afi, safi); return CMD_SUCCESS; } @@ -3964,6 +4038,7 @@ bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str, bgp_static_withdraw (bgp, &p, afi, safi); /* Clear configuration. */ + bgp_unlink_nexthop(bgp_static); bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4332722ef..550ef526f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -58,6 +58,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_nht.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ @@ -4733,24 +4734,33 @@ peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, else UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - return 0; - - group = peer->group; - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (! peer->af_group[afi][safi]) - continue; + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + if (! peer->af_group[afi][safi]) + continue; - SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); - peer->pmax[afi][safi] = max; - peer->pmax_threshold[afi][safi] = threshold; - peer->pmax_restart[afi][safi] = restart; - if (warning) - SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); - else - UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + peer->pmax[afi][safi] = max; + peer->pmax_threshold[afi][safi] = threshold; + peer->pmax_restart[afi][safi] = restart; + if (warning) + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + + if ((peer->status == Established) && (peer->afc[afi][safi])) + bgp_maximum_prefix_overflow (peer, afi, safi, 1); + } + } + else + { + if ((peer->status == Established) && (peer->afc[afi][safi])) + bgp_maximum_prefix_overflow (peer, afi, safi, 1); } + return 0; } @@ -5767,9 +5777,6 @@ bgp_config_write (struct vty *vty) if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); - /* BGP scan interval. */ - bgp_config_write_scan_time (vty); - /* BGP flag dampening. */ if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], BGP_CONFIG_DAMPENING)) @@ -5849,12 +5856,16 @@ bgp_master_init (void) void bgp_init (void) { - /* BGP VTY commands installation. */ - bgp_vty_init (); + + /* allocates some vital data structures used by peer commands in vty_init */ + bgp_scan_init (); /* Init zebra. */ bgp_zebra_init (); + /* BGP VTY commands installation. */ + bgp_vty_init (); + /* BGP inits. */ bgp_attr_init (); bgp_debug_init (); @@ -5862,7 +5873,7 @@ bgp_init (void) bgp_route_init (); bgp_route_map_init (); bgp_address_init (); - bgp_scan_init (); + bgp_scan_vty_init(); bgp_mplsvpn_init (); /* Access list initialize. */ diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 05e10ce73..85ab0910a 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -233,7 +233,15 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + break; + } + else + break; + } } } @@ -649,7 +657,9 @@ print_rnh (struct route_node *rn, struct vty *vty) print_nh(nexthop, vty); } else - vty_out(vty, " unresolved%s", VTY_NEWLINE); + vty_out(vty, " unresolved%s%s", + CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "", + VTY_NEWLINE); vty_out(vty, " Client list:"); for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 0843c0eb5..92e4c7a88 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -30,6 +30,7 @@ struct rnh { u_char flags; +#define ZEBRA_NHT_CONNECTED 0x1 struct rib *state; struct list *client_list; struct route_node *node; diff --git a/zebra/zserv.c b/zebra/zserv.c index 69efcc004..4fc9a80d9 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -755,6 +755,7 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length) struct stream *s; struct prefix p; u_short l = 0; + u_char connected; if (IS_ZEBRA_DEBUG_NHT) zlog_debug("nexthop_register msg from client %s: length=%d\n", @@ -764,12 +765,16 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length) while (l < length) { + connected = stream_getc(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); - l += 3; + l += 4; stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); l += PSIZE(p.prefixlen); rnh = zebra_add_rnh(&p, 0); + if (connected) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + zebra_add_rnh_client(rnh, client); } zebra_evaluate_rnh_table(0, AF_INET, 0); @@ -785,6 +790,7 @@ zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) struct stream *s; struct prefix p; u_short l = 0; + u_char connected; if (IS_ZEBRA_DEBUG_NHT) zlog_debug("nexthop_unregister msg from client %s: length=%d\n", @@ -794,9 +800,10 @@ zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) while (l < length) { + connected = stream_getc(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); - l += 3; + l += 4; stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); l += PSIZE(p.prefixlen); rnh = zebra_lookup_rnh(&p, 0); |