summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/Makefile.am5
-rw-r--r--bgpd/bgp_debug.c57
-rw-r--r--bgpd/bgp_debug.h3
-rw-r--r--bgpd/bgp_nexthop.c221
-rw-r--r--bgpd/bgp_nexthop.h20
-rw-r--r--bgpd/bgp_nht.c473
-rw-r--r--bgpd/bgp_nht.h62
-rw-r--r--bgpd/bgp_route.c103
-rw-r--r--bgpd/bgp_route.h14
-rw-r--r--bgpd/bgp_zebra.c11
10 files changed, 852 insertions, 117 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 92fa10cd..e5bb6151 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -15,14 +15,15 @@ libbgp_a_SOURCES = \
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
- bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c
+ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
+ bgp_nht.c
noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
- bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h
+ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 1d097697..91e6ad17 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -45,6 +45,7 @@ unsigned long conf_bgp_debug_keepalive;
unsigned long conf_bgp_debug_update;
unsigned long conf_bgp_debug_normal;
unsigned long conf_bgp_debug_zebra;
+unsigned long conf_bgp_debug_nht;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_fsm;
@@ -55,6 +56,7 @@ unsigned long term_bgp_debug_keepalive;
unsigned long term_bgp_debug_update;
unsigned long term_bgp_debug_normal;
unsigned long term_bgp_debug_zebra;
+unsigned long term_bgp_debug_nht;
/* messages for BGP-4 status */
const struct message bgp_status_msg[] =
@@ -471,6 +473,48 @@ ALIAS (no_debug_bgp_events,
BGP_STR
"BGP events\n")
+DEFUN (debug_bgp_nht,
+ debug_bgp_nht_cmd,
+ "debug bgp nht",
+ DEBUG_STR
+ BGP_STR
+ "BGP nexthop tracking events\n")
+{
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON (nht, NHT);
+ else
+ {
+ TERM_DEBUG_ON (nht, NHT);
+ vty_out (vty, "BGP nexthop tracking debugging is on%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_nht,
+ no_debug_bgp_nht_cmd,
+ "no debug bgp nht",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP nexthop tracking events\n")
+{
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF (nht, NHT);
+ else
+ {
+ TERM_DEBUG_OFF (nht, NHT);
+ vty_out (vty, "BGP nexthop tracking debugging is off%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_nht,
+ undebug_bgp_nht_cmd,
+ "undebug bgp nht",
+ UNDEBUG_STR
+ BGP_STR
+ "BGP next-hop tracking updates\n")
+
DEFUN (debug_bgp_filter,
debug_bgp_filter_cmd,
"debug bgp filters",
@@ -787,6 +831,8 @@ DEFUN (show_debugging_bgp,
vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE);
if (BGP_DEBUG (as4, AS4_SEGMENT))
vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE);
+ if (BGP_DEBUG (nht, NHT))
+ vty_out (vty, " BGP next-hop tracking debugging is on%s", VTY_NEWLINE);
vty_out (vty, "%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -860,6 +906,12 @@ bgp_config_write_debug (struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG (nht, NHT))
+ {
+ vty_out (vty, "debug bgp nht%s", VTY_NEWLINE);
+ write++;
+ }
+
return write;
}
@@ -886,6 +938,8 @@ bgp_debug_init (void)
install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
install_element (ENABLE_NODE, &debug_bgp_events_cmd);
install_element (CONFIG_NODE, &debug_bgp_events_cmd);
+ install_element (ENABLE_NODE, &debug_bgp_nht_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_nht_cmd);
install_element (ENABLE_NODE, &debug_bgp_filter_cmd);
install_element (CONFIG_NODE, &debug_bgp_filter_cmd);
install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd);
@@ -912,6 +966,9 @@ bgp_debug_init (void)
install_element (ENABLE_NODE, &no_debug_bgp_events_cmd);
install_element (ENABLE_NODE, &undebug_bgp_events_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_events_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_nht_cmd);
+ install_element (ENABLE_NODE, &undebug_bgp_nht_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_nht_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd);
install_element (ENABLE_NODE, &undebug_bgp_filter_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd);
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index ce8547b0..0090f814 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -67,6 +67,7 @@ extern unsigned long conf_bgp_debug_keepalive;
extern unsigned long conf_bgp_debug_update;
extern unsigned long conf_bgp_debug_normal;
extern unsigned long conf_bgp_debug_zebra;
+extern unsigned long conf_bgp_debug_nht;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_fsm;
@@ -77,6 +78,7 @@ extern unsigned long term_bgp_debug_keepalive;
extern unsigned long term_bgp_debug_update;
extern unsigned long term_bgp_debug_normal;
extern unsigned long term_bgp_debug_zebra;
+extern unsigned long term_bgp_debug_nht;
#define BGP_DEBUG_AS4 0x01
#define BGP_DEBUG_AS4_SEGMENT 0x02
@@ -90,6 +92,7 @@ extern unsigned long term_bgp_debug_zebra;
#define BGP_DEBUG_UPDATE_OUT 0x02
#define BGP_DEBUG_NORMAL 0x01
#define BGP_DEBUG_ZEBRA 0x01
+#define BGP_DEBUG_NHT 0x01
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 6218e670..39d2c641 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -30,17 +30,21 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "hash.h"
#include "jhash.h"
+#include "nexthop.h"
#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"
#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;
+
struct bgp_nexthop_cache *zlookup_query (struct in_addr);
#ifdef HAVE_IPV6
struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
@@ -59,7 +63,7 @@ static int bgp_scan_interval;
static int bgp_import_interval;
/* Route table for next-hop lookup cache. */
-static struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
+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];
@@ -69,6 +73,13 @@ 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)
+{
+ prefix2str(&(bnc->node->p), buf, size);
+ return buf;
+}
+
/* Add nexthop to the end of the list. */
static void
bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop)
@@ -84,7 +95,7 @@ bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop)
nexthop->prev = last;
}
-static void
+void
bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
{
struct nexthop *nexthop;
@@ -97,13 +108,17 @@ bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
}
}
-static struct bgp_nexthop_cache *
-bnc_new (void)
+struct bgp_nexthop_cache *
+bnc_new ()
{
- return XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache));
+ struct bgp_nexthop_cache *bnc;
+
+ bnc = XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache));
+ LIST_INIT(&(bnc->paths));
+ return bnc;
}
-static void
+void
bnc_free (struct bgp_nexthop_cache *bnc)
{
bnc_nexthop_free (bnc);
@@ -111,48 +126,6 @@ bnc_free (struct bgp_nexthop_cache *bnc)
}
static int
-bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2)
-{
- if (next1->type != next2->type)
- return 0;
-
- switch (next1->type)
- {
- case ZEBRA_NEXTHOP_IPV4:
- if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
- return 0;
- break;
- case ZEBRA_NEXTHOP_IPV4_IFINDEX:
- if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)
- || next1->ifindex != next2->ifindex)
- return 0;
- break;
- case ZEBRA_NEXTHOP_IFINDEX:
- case ZEBRA_NEXTHOP_IFNAME:
- if (next1->ifindex != next2->ifindex)
- return 0;
- break;
-#ifdef HAVE_IPV6
- case ZEBRA_NEXTHOP_IPV6:
- if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
- return 0;
- break;
- case ZEBRA_NEXTHOP_IPV6_IFINDEX:
- case ZEBRA_NEXTHOP_IPV6_IFNAME:
- if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
- return 0;
- if (next1->ifindex != next2->ifindex)
- return 0;
- break;
-#endif /* HAVE_IPV6 */
- default:
- /* do nothing */
- break;
- }
- return 1;
-}
-
-static int
bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
struct bgp_nexthop_cache *bnc2)
{
@@ -167,7 +140,7 @@ bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
for (i = 0; i < bnc1->nexthop_num; i++)
{
- if (! bgp_nexthop_same (next1, next2))
+ if (! nexthop_same_no_recurse (next1, next2))
return 1;
next1 = next1->next;
@@ -416,6 +389,7 @@ bgp_scan (afi_t afi, safi_t safi)
struct bgp_info *next;
struct peer *peer;
struct listnode *node, *nnode;
+#if BGP_SCAN_NEXTHOP
int valid;
int current;
int changed;
@@ -426,6 +400,7 @@ bgp_scan (afi_t afi, safi_t safi)
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 ();
@@ -455,6 +430,7 @@ bgp_scan (afi_t afi, safi_t safi)
if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL)
{
+#if BGP_SCAN_NEXTHOP
changed = 0;
metricchanged = 0;
@@ -487,6 +463,7 @@ bgp_scan (afi_t afi, safi_t safi)
afi, SAFI_UNICAST);
}
}
+#endif
if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_DAMPENING)
@@ -499,11 +476,13 @@ bgp_scan (afi_t afi, safi_t safi)
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))
{
@@ -1301,9 +1280,7 @@ static int
show_ip_bgp_scan_tables (struct vty *vty, const char detail)
{
struct bgp_node *rn;
- struct bgp_nexthop_cache *bnc;
char buf[INET6_ADDRSTRLEN];
- u_char i;
if (bgp_scan_thread)
vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
@@ -1311,6 +1288,7 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail)
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)
@@ -1375,7 +1353,9 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail)
}
}
#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;
@@ -1400,6 +1380,117 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail)
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",
@@ -1423,6 +1514,28 @@ DEFUN (show_ip_bgp_scan_detail,
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);
+}
+
int
bgp_config_write_scan_time (struct vty *vty)
{
@@ -1465,8 +1578,12 @@ bgp_scan_init (void)
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);
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);
}
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 6e5350ea..abcf2426 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -22,6 +22,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define _QUAGGA_BGP_NEXTHOP_H
#include "if.h"
+#include "queue.h"
+#include "prefix.h"
#define BGP_SCAN_INTERVAL_DEFAULT 60
#define BGP_IMPORT_INTERVAL_DEFAULT 15
@@ -44,6 +46,20 @@ struct bgp_nexthop_cache
/* Nexthop number and nexthop linked list.*/
u_char nexthop_num;
struct nexthop *nexthop;
+ time_t last_update;
+ u_int16_t flags;
+
+#define BGP_NEXTHOP_VALID (1 << 0)
+#define BGP_NEXTHOP_REGISTERED (1 << 1)
+
+ u_int16_t change_flags;
+
+#define BGP_NEXTHOP_CHANGED (1 << 0)
+#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
+
+ struct bgp_node *node;
+ LIST_HEAD(path_list, bgp_info) paths;
+ unsigned int path_count;
};
extern void bgp_scan_init (void);
@@ -57,5 +73,9 @@ 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 *);
extern void bgp_address_init (void);
+extern struct bgp_nexthop_cache *bnc_new();
+extern void bnc_free(struct bgp_nexthop_cache *bnc);
+extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
+extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
#endif /* _QUAGGA_BGP_NEXTHOP_H */
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
new file mode 100644
index 00000000..8f5f1af9
--- /dev/null
+++ b/bgpd/bgp_nht.c
@@ -0,0 +1,473 @@
+/* BGP Nexthop tracking
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * 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 "nexthop.h"
+
+#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_debug.h"
+#include "bgpd/bgp_nht.h"
+
+extern struct zclient *zclient;
+extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
+
+static void register_nexthop(struct bgp_nexthop_cache *bnc);
+static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
+static void evaluate_paths(struct bgp_nexthop_cache *bnc);
+static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
+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)
+{
+ 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);
+
+ return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
+}
+
+void
+bgp_unlink_nexthop (struct bgp_info *path)
+{
+ struct bgp_nexthop_cache *bnc = path->nexthop;
+
+ if (!bnc)
+ return;
+
+ path_nh_map(path, NULL, 0);
+
+ if (LIST_EMPTY(&(bnc->paths)))
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
+ bnc_str(bnc, buf, INET6_ADDRSTRLEN));
+ }
+ unregister_nexthop(bnc);
+ bnc->node->info = NULL;
+ bgp_unlock_node(bnc->node);
+ bnc_free(bnc);
+ }
+}
+
+int
+bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed,
+ int *metricchanged)
+{
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
+ struct prefix p;
+
+ if (make_prefix(afi, ri, &p) < 0)
+ return 1;
+ rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
+
+ if (!rn->info)
+ {
+ bnc = bnc_new();
+ rn->info = bnc;
+ bnc->node = rn;
+ bgp_lock_node(rn);
+ register_nexthop(bnc);
+ }
+ 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 (metricchanged)
+ *metricchanged = CHECK_FLAG(bnc->change_flags,
+ BGP_NEXTHOP_METRIC_CHANGED);
+
+ 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;
+
+ return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
+}
+
+void
+bgp_parse_nexthop_update (void)
+{
+ struct stream *s;
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
+ struct nexthop *nexthop;
+ struct nexthop *oldnh;
+ struct nexthop *nhlist_head = NULL;
+ struct nexthop *nhlist_tail = NULL;
+ uint32_t metric;
+ u_char nexthop_num;
+ struct prefix p;
+ int i;
+
+ s = zclient->ibuf;
+
+ memset(&p, 0, sizeof(struct prefix));
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ switch (p.family)
+ {
+ case AF_INET:
+ p.u.prefix4.s_addr = stream_get_ipv4 (s);
+ break;
+ case AF_INET6:
+ stream_get(&p.u.prefix6, s, 16);
+ break;
+ default:
+ break;
+ }
+
+ rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
+ if (!rn || !rn->info)
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ prefix2str(&p, buf, INET6_ADDRSTRLEN);
+ zlog_debug("parse nexthop update(%s): rn not found", buf);
+ }
+ return;
+ }
+
+ bnc = rn->info;
+ bnc->last_update = bgp_clock();
+ bnc->change_flags = 0;
+ metric = stream_getl (s);
+ nexthop_num = stream_getc (s);
+
+ /* debug print the input */
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ prefix2str(&p, buf, INET6_ADDRSTRLEN);
+ zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
+ metric, nexthop_num);
+ }
+
+ if (metric != bnc->metric)
+ bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
+
+ if(nexthop_num != bnc->nexthop_num)
+ bnc->change_flags |= BGP_NEXTHOP_CHANGED;
+
+ if (nexthop_num)
+ {
+ bnc->flags |= BGP_NEXTHOP_VALID;
+ bnc->metric = metric;
+ bnc->nexthop_num = nexthop_num;
+
+ for (i = 0; i < nexthop_num; i++)
+ {
+ nexthop = nexthop_new();
+ 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_IFINDEX:
+ case ZEBRA_NEXTHOP_IFNAME:
+ nexthop->ifindex = stream_getl (s);
+ break;
+ case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+ case ZEBRA_NEXTHOP_IPV4_IFNAME:
+ nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+ nexthop->ifindex = stream_getl (s);
+ break;
+#ifdef HAVE_IPV6
+ 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;
+#endif
+ default:
+ /* do nothing */
+ break;
+ }
+
+ if (nhlist_tail)
+ {
+ nhlist_tail->next = nexthop;
+ nhlist_tail = nexthop;
+ }
+ else
+ {
+ nhlist_tail = nexthop;
+ nhlist_head = nexthop;
+ }
+
+ /* No need to evaluate the nexthop if we have already determined
+ * that there has been a change.
+ */
+ if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
+ continue;
+
+ for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
+ if (nexthop_same_no_recurse(oldnh, nexthop))
+ break;
+
+ if (!oldnh)
+ bnc->change_flags |= BGP_NEXTHOP_CHANGED;
+ }
+ bnc_nexthop_free(bnc);
+ bnc->nexthop = nhlist_head;
+ }
+ else
+ {
+ bnc->flags &= ~BGP_NEXTHOP_VALID;
+ bnc_nexthop_free(bnc);
+ bnc->nexthop = NULL;
+ }
+
+ evaluate_paths(bnc);
+}
+
+/**
+ * make_prefix - make a prefix structure from the path (essentially
+ * path's node.
+ */
+static int
+make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
+{
+ memset (p, 0, sizeof (struct prefix));
+ switch (afi)
+ {
+ case AFI_IP:
+ p->family = AF_INET;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ p->u.prefix4 = ri->attr->nexthop;
+ break;
+#ifdef HAVE_IPV6
+ case AFI_IP6:
+ if (ri->attr->extra->mp_nexthop_len != 16
+ || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
+ return -1;
+
+ p->family = AF_INET6;
+ p->prefixlen = IPV6_MAX_BITLEN;
+ p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
+ break;
+#endif
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * sendmsg_nexthop -- Format and send a nexthop register/Unregister
+ * command to Zebra.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
+ * RETURNS:
+ * void.
+ */
+static void
+sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
+{
+ struct stream *s;
+ struct prefix *p;
+ int ret;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ p = &(bnc->node->p);
+ s = zclient->obuf;
+ stream_reset (s);
+ zclient_create_header (s, command);
+ stream_putw(s, PREFIX_FAMILY(p));
+ stream_putc(s, p->prefixlen);
+ switch (PREFIX_FAMILY(p))
+ {
+ case AF_INET:
+ stream_put_in_addr (s, &p->u.prefix4);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ stream_put(s, &(p->u.prefix6), 16);
+ break;
+#endif
+ default:
+ break;
+ }
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ ret = zclient_send_message(zclient);
+ /* TBD: handle the failure */
+ if (ret < 0)
+ zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
+ return;
+}
+
+/**
+ * register_nexthop - register a nexthop with Zebra for notification
+ * when the route to the nexthop changes.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * RETURNS:
+ * void.
+ */
+static void
+register_nexthop (struct bgp_nexthop_cache *bnc)
+{
+ /* Check if we have already registered */
+ if (bnc->flags & BGP_NEXTHOP_REGISTERED)
+ return;
+ sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+}
+
+/**
+ * unregister_nexthop -- Unregister the nexthop from Zebra.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * RETURNS:
+ * void.
+ */
+static void
+unregister_nexthop (struct bgp_nexthop_cache *bnc)
+{
+ /* Check if we have already registered */
+ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
+ return;
+
+ sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+}
+
+/**
+ * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * RETURNS:
+ * void.
+ */
+static void
+evaluate_paths (struct bgp_nexthop_cache *bnc)
+{
+ struct bgp_node *rn;
+ struct bgp_info *path;
+ struct bgp *bgp = bgp_get_default();
+ int afi;
+
+ LIST_FOREACH(path, &(bnc->paths), nh_thread)
+ {
+ if (!(path->type == ZEBRA_ROUTE_BGP &&
+ path->sub_type == BGP_ROUTE_NORMAL))
+ continue;
+
+ rn = path->net;
+ afi = family2afi(rn->p.family);
+
+ /* Path becomes valid/invalid depending on whether the nexthop
+ * reachable/unreachable.
+ */
+ if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
+ (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
+ {
+ if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
+ {
+ bgp_aggregate_decrement (bgp, &rn->p, path,
+ afi, SAFI_UNICAST);
+ bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
+ }
+ else
+ {
+ bgp_info_set_flag (rn, path, BGP_INFO_VALID);
+ bgp_aggregate_increment (bgp, &rn->p, path,
+ afi, SAFI_UNICAST);
+ }
+ }
+
+ /* Copy the metric to the path. Will be used for bestpath computation */
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
+ (bgp_info_extra_get(path))->igpmetric = bnc->metric;
+ else if (path->extra)
+ path->extra->igpmetric = 0;
+
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
+ SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
+
+ bgp_process(bgp, rn, afi, SAFI_UNICAST);
+ }
+ RESET_FLAG(bnc->change_flags);
+}
+
+/**
+ * path_nh_map - make or break path-to-nexthop association.
+ * ARGUMENTS:
+ * path - pointer to the path structure
+ * bnc - pointer to the nexthop structure
+ * make - if set, make the association. if unset, just break the existing
+ * association.
+ */
+static void
+path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
+{
+ if (path->nexthop)
+ {
+ LIST_REMOVE(path, nh_thread);
+ path->nexthop->path_count--;
+ path->nexthop = NULL;
+ }
+ if (make)
+ {
+ LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
+ path->nexthop = bnc;
+ path->nexthop->path_count++;
+ }
+}
diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h
new file mode 100644
index 00000000..0e43f0a4
--- /dev/null
+++ b/bgpd/bgp_nht.h
@@ -0,0 +1,62 @@
+/* BGP Nexthop tracking
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _BGP_NHT_H
+#define _BGP_NHT_H
+
+/**
+ * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra.
+ */
+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.
+ */
+extern int bgp_find_nexthop(struct bgp_info *p, int *c, int *m);
+
+/**
+ * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc
+ * object. If not found, create a new object and register with ZEBRA for
+ * nexthop notification.
+ * 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.
+ */
+extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, int *c, int *m);
+
+/**
+ * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure.
+ * ARGUMENTS:
+ * p - path structure.
+ */
+extern void bgp_unlink_nexthop(struct bgp_info *p);
+
+#endif /* _BGP_NHT_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 34ba1abe..2453803f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -55,6 +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"
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
@@ -126,20 +127,14 @@ bgp_info_extra_get (struct bgp_info *ri)
return ri->extra;
}
-/* Allocate new bgp info structure. */
-static struct bgp_info *
-bgp_info_new (void)
-{
- return XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info));
-}
-
/* Free bgp route information. */
static void
bgp_info_free (struct bgp_info *binfo)
{
if (binfo->attr)
bgp_attr_unintern (&binfo->attr);
-
+
+ bgp_unlink_nexthop(binfo);
bgp_info_extra_free (&binfo->extra);
bgp_info_mpath_free (&binfo->mpath);
@@ -1841,6 +1836,23 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
bgp_rib_remove (rn, ri, peer, afi, safi);
}
+static struct bgp_info *
+info_make (int type, int sub_type, struct peer *peer, struct attr *attr,
+ struct bgp_node *rn)
+{
+ struct bgp_info *new;
+
+ /* Make new BGP info. */
+ new = XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info));
+ new->type = type;
+ new->sub_type = sub_type;
+ new->peer = peer;
+ new->attr = attr;
+ new->uptime = bgp_clock ();
+ new->net = rn;
+ return new;
+}
+
static void
bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
struct attr *attr, struct peer *peer, struct prefix *p, int type,
@@ -1988,13 +2000,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
p->prefixlen, rsclient->host);
}
- /* Make new BGP info. */
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = sub_type;
- new->peer = peer;
- new->attr = attr_new;
- new->uptime = bgp_clock ();
+ new = info_make(type, sub_type, peer, attr_new, rn);
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
@@ -2300,7 +2306,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|| (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
{
- if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL))
+ if (bgp_find_or_add_nexthop (afi, ri, NULL, NULL))
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
else
bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
@@ -2327,12 +2333,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = sub_type;
- new->peer = peer;
- new->attr = attr_new;
- new->uptime = bgp_clock ();
+ new = info_make(type, sub_type, peer, attr_new, rn);
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
@@ -2346,7 +2347,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|| (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
{
- if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL))
+ if (bgp_find_or_add_nexthop (afi, new, NULL, NULL))
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
else
bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
@@ -3433,15 +3434,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
return;
}
}
-
+
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
+ attr_new, rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = attr_new;
- new->uptime = bgp_clock ();
/* Register new BGP information. */
bgp_info_add (rn, new);
@@ -3554,13 +3551,9 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
}
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new,
+ rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = attr_new;
- new->uptime = bgp_clock ();
/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -3605,13 +3598,10 @@ bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi,
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
- new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP);
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
+ bgp_attr_default_intern(BGP_ORIGIN_IGP), rn);
+
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->uptime = bgp_clock ();
new->extra = bgp_info_extra_new();
memcpy (new->extra->tag, tag, 3);
@@ -4670,13 +4660,10 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
if (aggregate->count > 0)
{
rn = bgp_node_get (table, p);
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_AGGREGATE;
- new->peer = bgp->peer_self;
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self,
+ bgp_attr_aggregate_intern(bgp, origin, aspath, community,
+ aggregate->as_set), rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
- new->uptime = bgp_clock ();
bgp_info_add (rn, new);
bgp_unlock_node (rn);
@@ -4854,14 +4841,10 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
if (aggregate->count)
{
rn = bgp_node_get (table, p);
-
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_AGGREGATE;
- new->peer = bgp->peer_self;
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self,
+ bgp_attr_aggregate_intern(bgp, origin, aspath, community,
+ aggregate->as_set), rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
- new->uptime = bgp_clock ();
bgp_info_add (rn, new);
bgp_unlock_node (rn);
@@ -5501,16 +5484,12 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
- }
+ }
}
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = BGP_ROUTE_REDISTRIBUTE;
- new->peer = bgp->peer_self;
+ new = info_make(type, BGP_ROUTE_REDISTRIBUTE, bgp->peer_self,
+ new_attr, bn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = new_attr;
- new->uptime = bgp_clock ();
bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST);
bgp_info_add (bn, new);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 3d2eea51..266d4cbb 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -21,8 +21,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ROUTE_H
#define _QUAGGA_BGP_ROUTE_H
+#include "queue.h"
#include "bgp_table.h"
+struct bgp_nexthop_cache;
+
/* Ancillary information to struct bgp_info,
* used for uncommonly used data (aggregation, MPLS, etc.)
* and lazily allocated to save memory.
@@ -47,7 +50,16 @@ struct bgp_info
/* For linked list. */
struct bgp_info *next;
struct bgp_info *prev;
-
+
+ /* For nexthop linked list */
+ LIST_ENTRY(bgp_info) nh_thread;
+
+ /* Back pointer to the prefix node */
+ struct bgp_node *net;
+
+ /* Back pointer to the nexthop structure */
+ struct bgp_nexthop_cache *nexthop;
+
/* Peer structure. */
struct peer *peer;
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index f18d916f..146a7153 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_nexthop.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@@ -74,6 +75,15 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length)
return 0;
}
+/* Nexthop update message from zebra. */
+static int
+bgp_read_nexthop_update (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ bgp_parse_nexthop_update();
+ return 0;
+}
+
/* Inteface addition message from zebra. */
static int
bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
@@ -1095,6 +1105,7 @@ bgp_zebra_init (void)
zclient->ipv6_route_add = zebra_read_ipv6;
zclient->ipv6_route_delete = zebra_read_ipv6;
#endif /* HAVE_IPV6 */
+ zclient->nexthop_update = bgp_read_nexthop_update;
/* Interface related init. */
if_init ();