mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-16 06:53:03 +00:00
nexthop-tracking.patch
quagga: nexthop-tracking.patch Add next hop tracking support to Quagga. Complete documentation in doc/next-hop-tracking.txt. Signed-off-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com> Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com> Signed-off-by: Dinesh Dutt <ddutt@cumulusnetworks.com>
This commit is contained in:
parent
f188f2c424
commit
fb018d251e
@ -15,14 +15,15 @@ libbgp_a_SOURCES = \
|
|||||||
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
|
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_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_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 = \
|
noinst_HEADERS = \
|
||||||
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
|
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 \
|
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 \
|
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_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_SOURCES = bgp_main.c
|
||||||
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
|
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
|
||||||
|
@ -45,6 +45,7 @@ unsigned long conf_bgp_debug_keepalive;
|
|||||||
unsigned long conf_bgp_debug_update;
|
unsigned long conf_bgp_debug_update;
|
||||||
unsigned long conf_bgp_debug_normal;
|
unsigned long conf_bgp_debug_normal;
|
||||||
unsigned long conf_bgp_debug_zebra;
|
unsigned long conf_bgp_debug_zebra;
|
||||||
|
unsigned long conf_bgp_debug_nht;
|
||||||
|
|
||||||
unsigned long term_bgp_debug_as4;
|
unsigned long term_bgp_debug_as4;
|
||||||
unsigned long term_bgp_debug_fsm;
|
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_update;
|
||||||
unsigned long term_bgp_debug_normal;
|
unsigned long term_bgp_debug_normal;
|
||||||
unsigned long term_bgp_debug_zebra;
|
unsigned long term_bgp_debug_zebra;
|
||||||
|
unsigned long term_bgp_debug_nht;
|
||||||
|
|
||||||
/* messages for BGP-4 status */
|
/* messages for BGP-4 status */
|
||||||
const struct message bgp_status_msg[] =
|
const struct message bgp_status_msg[] =
|
||||||
@ -471,6 +473,48 @@ ALIAS (no_debug_bgp_events,
|
|||||||
BGP_STR
|
BGP_STR
|
||||||
"BGP events\n")
|
"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,
|
DEFUN (debug_bgp_filter,
|
||||||
debug_bgp_filter_cmd,
|
debug_bgp_filter_cmd,
|
||||||
"debug bgp filters",
|
"debug bgp filters",
|
||||||
@ -787,6 +831,8 @@ DEFUN (show_debugging_bgp,
|
|||||||
vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE);
|
vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE);
|
||||||
if (BGP_DEBUG (as4, AS4_SEGMENT))
|
if (BGP_DEBUG (as4, AS4_SEGMENT))
|
||||||
vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE);
|
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);
|
vty_out (vty, "%s", VTY_NEWLINE);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -860,6 +906,12 @@ bgp_config_write_debug (struct vty *vty)
|
|||||||
write++;
|
write++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CONF_BGP_DEBUG (nht, NHT))
|
||||||
|
{
|
||||||
|
vty_out (vty, "debug bgp nht%s", VTY_NEWLINE);
|
||||||
|
write++;
|
||||||
|
}
|
||||||
|
|
||||||
return write;
|
return write;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -886,6 +938,8 @@ bgp_debug_init (void)
|
|||||||
install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
|
install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_bgp_events_cmd);
|
install_element (ENABLE_NODE, &debug_bgp_events_cmd);
|
||||||
install_element (CONFIG_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 (ENABLE_NODE, &debug_bgp_filter_cmd);
|
||||||
install_element (CONFIG_NODE, &debug_bgp_filter_cmd);
|
install_element (CONFIG_NODE, &debug_bgp_filter_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_bgp_keepalive_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, &no_debug_bgp_events_cmd);
|
||||||
install_element (ENABLE_NODE, &undebug_bgp_events_cmd);
|
install_element (ENABLE_NODE, &undebug_bgp_events_cmd);
|
||||||
install_element (CONFIG_NODE, &no_debug_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, &no_debug_bgp_filter_cmd);
|
||||||
install_element (ENABLE_NODE, &undebug_bgp_filter_cmd);
|
install_element (ENABLE_NODE, &undebug_bgp_filter_cmd);
|
||||||
install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd);
|
install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd);
|
||||||
|
@ -67,6 +67,7 @@ extern unsigned long conf_bgp_debug_keepalive;
|
|||||||
extern unsigned long conf_bgp_debug_update;
|
extern unsigned long conf_bgp_debug_update;
|
||||||
extern unsigned long conf_bgp_debug_normal;
|
extern unsigned long conf_bgp_debug_normal;
|
||||||
extern unsigned long conf_bgp_debug_zebra;
|
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_as4;
|
||||||
extern unsigned long term_bgp_debug_fsm;
|
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_update;
|
||||||
extern unsigned long term_bgp_debug_normal;
|
extern unsigned long term_bgp_debug_normal;
|
||||||
extern unsigned long term_bgp_debug_zebra;
|
extern unsigned long term_bgp_debug_zebra;
|
||||||
|
extern unsigned long term_bgp_debug_nht;
|
||||||
|
|
||||||
#define BGP_DEBUG_AS4 0x01
|
#define BGP_DEBUG_AS4 0x01
|
||||||
#define BGP_DEBUG_AS4_SEGMENT 0x02
|
#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_UPDATE_OUT 0x02
|
||||||
#define BGP_DEBUG_NORMAL 0x01
|
#define BGP_DEBUG_NORMAL 0x01
|
||||||
#define BGP_DEBUG_ZEBRA 0x01
|
#define BGP_DEBUG_ZEBRA 0x01
|
||||||
|
#define BGP_DEBUG_NHT 0x01
|
||||||
|
|
||||||
#define BGP_DEBUG_PACKET_SEND 0x01
|
#define BGP_DEBUG_PACKET_SEND 0x01
|
||||||
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
|
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
|
||||||
|
@ -30,17 +30,21 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "bgpd/bgpd.h"
|
#include "bgpd/bgpd.h"
|
||||||
#include "bgpd/bgp_table.h"
|
#include "bgpd/bgp_table.h"
|
||||||
#include "bgpd/bgp_route.h"
|
#include "bgpd/bgp_route.h"
|
||||||
#include "bgpd/bgp_attr.h"
|
#include "bgpd/bgp_attr.h"
|
||||||
#include "bgpd/bgp_nexthop.h"
|
#include "bgpd/bgp_nexthop.h"
|
||||||
|
#include "bgpd/bgp_nht.h"
|
||||||
#include "bgpd/bgp_debug.h"
|
#include "bgpd/bgp_debug.h"
|
||||||
#include "bgpd/bgp_damp.h"
|
#include "bgpd/bgp_damp.h"
|
||||||
#include "zebra/rib.h"
|
#include "zebra/rib.h"
|
||||||
#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */
|
#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */
|
||||||
|
|
||||||
|
extern struct zclient *zclient;
|
||||||
|
|
||||||
struct bgp_nexthop_cache *zlookup_query (struct in_addr);
|
struct bgp_nexthop_cache *zlookup_query (struct in_addr);
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
|
struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
|
||||||
@ -59,7 +63,7 @@ static int bgp_scan_interval;
|
|||||||
static int bgp_import_interval;
|
static int bgp_import_interval;
|
||||||
|
|
||||||
/* Route table for next-hop lookup cache. */
|
/* 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 *cache1_table[AFI_MAX];
|
||||||
static struct bgp_table *cache2_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. */
|
/* BGP nexthop lookup query client. */
|
||||||
struct zclient *zlookup = NULL;
|
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. */
|
/* Add nexthop to the end of the list. */
|
||||||
static void
|
static void
|
||||||
bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop)
|
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;
|
nexthop->prev = last;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
|
bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
|
||||||
{
|
{
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop;
|
||||||
@ -97,61 +108,23 @@ bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bgp_nexthop_cache *
|
struct bgp_nexthop_cache *
|
||||||
bnc_new (void)
|
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_free (struct bgp_nexthop_cache *bnc)
|
||||||
{
|
{
|
||||||
bnc_nexthop_free (bnc);
|
bnc_nexthop_free (bnc);
|
||||||
XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc);
|
XFREE (MTYPE_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
|
static int
|
||||||
bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
|
bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
|
||||||
struct bgp_nexthop_cache *bnc2)
|
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++)
|
for (i = 0; i < bnc1->nexthop_num; i++)
|
||||||
{
|
{
|
||||||
if (! bgp_nexthop_same (next1, next2))
|
if (! nexthop_same_no_recurse (next1, next2))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
next1 = next1->next;
|
next1 = next1->next;
|
||||||
@ -416,6 +389,7 @@ bgp_scan (afi_t afi, safi_t safi)
|
|||||||
struct bgp_info *next;
|
struct bgp_info *next;
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
struct listnode *node, *nnode;
|
struct listnode *node, *nnode;
|
||||||
|
#if BGP_SCAN_NEXTHOP
|
||||||
int valid;
|
int valid;
|
||||||
int current;
|
int current;
|
||||||
int changed;
|
int changed;
|
||||||
@ -426,6 +400,7 @@ bgp_scan (afi_t afi, safi_t safi)
|
|||||||
bgp_nexthop_cache_table[afi] = cache2_table[afi];
|
bgp_nexthop_cache_table[afi] = cache2_table[afi];
|
||||||
else
|
else
|
||||||
bgp_nexthop_cache_table[afi] = cache1_table[afi];
|
bgp_nexthop_cache_table[afi] = cache1_table[afi];
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get default bgp. */
|
/* Get default bgp. */
|
||||||
bgp = bgp_get_default ();
|
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 (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL)
|
||||||
{
|
{
|
||||||
|
#if BGP_SCAN_NEXTHOP
|
||||||
changed = 0;
|
changed = 0;
|
||||||
metricchanged = 0;
|
metricchanged = 0;
|
||||||
|
|
||||||
@ -487,6 +463,7 @@ bgp_scan (afi_t afi, safi_t safi)
|
|||||||
afi, SAFI_UNICAST);
|
afi, SAFI_UNICAST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST],
|
if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST],
|
||||||
BGP_CONFIG_DAMPENING)
|
BGP_CONFIG_DAMPENING)
|
||||||
@ -499,11 +476,13 @@ bgp_scan (afi_t afi, safi_t safi)
|
|||||||
bgp_process (bgp, rn, afi, SAFI_UNICAST);
|
bgp_process (bgp, rn, afi, SAFI_UNICAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BGP_SCAN_NEXTHOP
|
||||||
/* Flash old cache. */
|
/* Flash old cache. */
|
||||||
if (bgp_nexthop_cache_table[afi] == cache1_table[afi])
|
if (bgp_nexthop_cache_table[afi] == cache1_table[afi])
|
||||||
bgp_nexthop_cache_reset (cache2_table[afi]);
|
bgp_nexthop_cache_reset (cache2_table[afi]);
|
||||||
else
|
else
|
||||||
bgp_nexthop_cache_reset (cache1_table[afi]);
|
bgp_nexthop_cache_reset (cache1_table[afi]);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (BGP_DEBUG (events, EVENTS))
|
if (BGP_DEBUG (events, EVENTS))
|
||||||
{
|
{
|
||||||
@ -1294,9 +1273,7 @@ static int
|
|||||||
show_ip_bgp_scan_tables (struct vty *vty, const char detail)
|
show_ip_bgp_scan_tables (struct vty *vty, const char detail)
|
||||||
{
|
{
|
||||||
struct bgp_node *rn;
|
struct bgp_node *rn;
|
||||||
struct bgp_nexthop_cache *bnc;
|
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char buf[INET6_ADDRSTRLEN];
|
||||||
u_char i;
|
|
||||||
|
|
||||||
if (bgp_scan_thread)
|
if (bgp_scan_thread)
|
||||||
vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
|
vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
|
||||||
@ -1304,6 +1281,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 is not running%s", VTY_NEWLINE);
|
||||||
vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, 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);
|
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))
|
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn))
|
||||||
if ((bnc = rn->info) != NULL)
|
if ((bnc = rn->info) != NULL)
|
||||||
@ -1368,7 +1346,9 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_IPV6 */
|
#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);
|
vty_out (vty, "BGP connected route:%s", VTY_NEWLINE);
|
||||||
for (rn = bgp_table_top (bgp_connected_table[AFI_IP]);
|
for (rn = bgp_table_top (bgp_connected_table[AFI_IP]);
|
||||||
rn;
|
rn;
|
||||||
@ -1393,6 +1373,117 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail)
|
|||||||
return CMD_SUCCESS;
|
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,
|
DEFUN (show_ip_bgp_scan,
|
||||||
show_ip_bgp_scan_cmd,
|
show_ip_bgp_scan_cmd,
|
||||||
"show ip bgp scan",
|
"show ip bgp scan",
|
||||||
@ -1416,6 +1507,28 @@ DEFUN (show_ip_bgp_scan_detail,
|
|||||||
return show_ip_bgp_scan_tables (vty, 1);
|
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
|
int
|
||||||
bgp_config_write_scan_time (struct vty *vty)
|
bgp_config_write_scan_time (struct vty *vty)
|
||||||
{
|
{
|
||||||
@ -1458,8 +1571,12 @@ bgp_scan_init (void)
|
|||||||
install_element (BGP_NODE, &no_bgp_scan_time_val_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_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_scan_detail_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 (RESTRICTED_NODE, &show_ip_bgp_scan_cmd);
|
||||||
install_element (ENABLE_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);
|
install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|||||||
#define _QUAGGA_BGP_NEXTHOP_H
|
#define _QUAGGA_BGP_NEXTHOP_H
|
||||||
|
|
||||||
#include "if.h"
|
#include "if.h"
|
||||||
|
#include "queue.h"
|
||||||
|
#include "prefix.h"
|
||||||
|
|
||||||
#define BGP_SCAN_INTERVAL_DEFAULT 60
|
#define BGP_SCAN_INTERVAL_DEFAULT 60
|
||||||
#define BGP_IMPORT_INTERVAL_DEFAULT 15
|
#define BGP_IMPORT_INTERVAL_DEFAULT 15
|
||||||
@ -44,6 +46,20 @@ struct bgp_nexthop_cache
|
|||||||
/* Nexthop number and nexthop linked list.*/
|
/* Nexthop number and nexthop linked list.*/
|
||||||
u_char nexthop_num;
|
u_char nexthop_num;
|
||||||
struct nexthop *nexthop;
|
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);
|
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_onlink (afi_t, struct attr *);
|
||||||
extern int bgp_nexthop_self (struct attr *);
|
extern int bgp_nexthop_self (struct attr *);
|
||||||
extern void bgp_address_init (void);
|
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 */
|
#endif /* _QUAGGA_BGP_NEXTHOP_H */
|
||||||
|
473
bgpd/bgp_nht.c
Normal file
473
bgpd/bgp_nht.c
Normal file
@ -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++;
|
||||||
|
}
|
||||||
|
}
|
62
bgpd/bgp_nht.h
Normal file
62
bgpd/bgp_nht.h
Normal file
@ -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 */
|
103
bgpd/bgp_route.c
103
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_zebra.h"
|
||||||
#include "bgpd/bgp_vty.h"
|
#include "bgpd/bgp_vty.h"
|
||||||
#include "bgpd/bgp_mpath.h"
|
#include "bgpd/bgp_mpath.h"
|
||||||
|
#include "bgpd/bgp_nht.c"
|
||||||
|
|
||||||
/* Extern from bgp_dump.c */
|
/* Extern from bgp_dump.c */
|
||||||
extern const char *bgp_origin_str[];
|
extern const char *bgp_origin_str[];
|
||||||
@ -126,20 +127,14 @@ bgp_info_extra_get (struct bgp_info *ri)
|
|||||||
return ri->extra;
|
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. */
|
/* Free bgp route information. */
|
||||||
static void
|
static void
|
||||||
bgp_info_free (struct bgp_info *binfo)
|
bgp_info_free (struct bgp_info *binfo)
|
||||||
{
|
{
|
||||||
if (binfo->attr)
|
if (binfo->attr)
|
||||||
bgp_attr_unintern (&binfo->attr);
|
bgp_attr_unintern (&binfo->attr);
|
||||||
|
|
||||||
|
bgp_unlink_nexthop(binfo);
|
||||||
bgp_info_extra_free (&binfo->extra);
|
bgp_info_extra_free (&binfo->extra);
|
||||||
bgp_info_mpath_free (&binfo->mpath);
|
bgp_info_mpath_free (&binfo->mpath);
|
||||||
|
|
||||||
@ -1857,6 +1852,23 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
|
|||||||
bgp_rib_remove (rn, ri, peer, afi, safi);
|
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
|
static void
|
||||||
bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
|
bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
|
||||||
struct attr *attr, struct peer *peer, struct prefix *p, int type,
|
struct attr *attr, struct peer *peer, struct prefix *p, int type,
|
||||||
@ -2004,13 +2016,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
|
|||||||
p->prefixlen, rsclient->host);
|
p->prefixlen, rsclient->host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make new BGP info. */
|
new = info_make(type, sub_type, peer, attr_new, rn);
|
||||||
new = bgp_info_new ();
|
|
||||||
new->type = type;
|
|
||||||
new->sub_type = sub_type;
|
|
||||||
new->peer = peer;
|
|
||||||
new->attr = attr_new;
|
|
||||||
new->uptime = bgp_clock ();
|
|
||||||
|
|
||||||
/* Update MPLS tag. */
|
/* Update MPLS tag. */
|
||||||
if (safi == SAFI_MPLS_VPN)
|
if (safi == SAFI_MPLS_VPN)
|
||||||
@ -2316,7 +2322,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|
|||||||
|| (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
|| (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
||||||
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
|
|| 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);
|
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
|
||||||
else
|
else
|
||||||
bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
|
bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
|
||||||
@ -2343,12 +2349,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make new BGP info. */
|
/* Make new BGP info. */
|
||||||
new = bgp_info_new ();
|
new = info_make(type, sub_type, peer, attr_new, rn);
|
||||||
new->type = type;
|
|
||||||
new->sub_type = sub_type;
|
|
||||||
new->peer = peer;
|
|
||||||
new->attr = attr_new;
|
|
||||||
new->uptime = bgp_clock ();
|
|
||||||
|
|
||||||
/* Update MPLS tag. */
|
/* Update MPLS tag. */
|
||||||
if (safi == SAFI_MPLS_VPN)
|
if (safi == SAFI_MPLS_VPN)
|
||||||
@ -2362,7 +2363,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|
|||||||
|| (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
|| (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
||||||
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
|
|| 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);
|
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
|
||||||
else
|
else
|
||||||
bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
|
bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
|
||||||
@ -3450,15 +3451,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make new BGP info. */
|
/* Make new BGP info. */
|
||||||
new = bgp_info_new ();
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
|
||||||
new->type = ZEBRA_ROUTE_BGP;
|
attr_new, rn);
|
||||||
new->sub_type = BGP_ROUTE_STATIC;
|
|
||||||
new->peer = bgp->peer_self;
|
|
||||||
SET_FLAG (new->flags, BGP_INFO_VALID);
|
SET_FLAG (new->flags, BGP_INFO_VALID);
|
||||||
new->attr = attr_new;
|
|
||||||
new->uptime = bgp_clock ();
|
|
||||||
|
|
||||||
/* Register new BGP information. */
|
/* Register new BGP information. */
|
||||||
bgp_info_add (rn, new);
|
bgp_info_add (rn, new);
|
||||||
@ -3571,13 +3568,9 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make new BGP info. */
|
/* Make new BGP info. */
|
||||||
new = bgp_info_new ();
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new,
|
||||||
new->type = ZEBRA_ROUTE_BGP;
|
rn);
|
||||||
new->sub_type = BGP_ROUTE_STATIC;
|
|
||||||
new->peer = bgp->peer_self;
|
|
||||||
SET_FLAG (new->flags, BGP_INFO_VALID);
|
SET_FLAG (new->flags, BGP_INFO_VALID);
|
||||||
new->attr = attr_new;
|
|
||||||
new->uptime = bgp_clock ();
|
|
||||||
|
|
||||||
/* Aggregate address increment. */
|
/* Aggregate address increment. */
|
||||||
bgp_aggregate_increment (bgp, p, new, afi, safi);
|
bgp_aggregate_increment (bgp, p, new, afi, safi);
|
||||||
@ -3622,13 +3615,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);
|
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
|
||||||
|
|
||||||
/* Make new BGP info. */
|
/* Make new BGP info. */
|
||||||
new = bgp_info_new ();
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
|
||||||
new->type = ZEBRA_ROUTE_BGP;
|
bgp_attr_default_intern(BGP_ORIGIN_IGP), rn);
|
||||||
new->sub_type = BGP_ROUTE_STATIC;
|
|
||||||
new->peer = bgp->peer_self;
|
|
||||||
new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP);
|
|
||||||
SET_FLAG (new->flags, BGP_INFO_VALID);
|
SET_FLAG (new->flags, BGP_INFO_VALID);
|
||||||
new->uptime = bgp_clock ();
|
|
||||||
new->extra = bgp_info_extra_new();
|
new->extra = bgp_info_extra_new();
|
||||||
memcpy (new->extra->tag, tag, 3);
|
memcpy (new->extra->tag, tag, 3);
|
||||||
|
|
||||||
@ -4700,13 +4690,10 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
|
|||||||
if (aggregate->count > 0)
|
if (aggregate->count > 0)
|
||||||
{
|
{
|
||||||
rn = bgp_node_get (table, p);
|
rn = bgp_node_get (table, p);
|
||||||
new = bgp_info_new ();
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self,
|
||||||
new->type = ZEBRA_ROUTE_BGP;
|
bgp_attr_aggregate_intern(bgp, origin, aspath, community,
|
||||||
new->sub_type = BGP_ROUTE_AGGREGATE;
|
aggregate->as_set), rn);
|
||||||
new->peer = bgp->peer_self;
|
|
||||||
SET_FLAG (new->flags, BGP_INFO_VALID);
|
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_info_add (rn, new);
|
||||||
bgp_unlock_node (rn);
|
bgp_unlock_node (rn);
|
||||||
@ -4884,14 +4871,10 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
|
|||||||
if (aggregate->count)
|
if (aggregate->count)
|
||||||
{
|
{
|
||||||
rn = bgp_node_get (table, p);
|
rn = bgp_node_get (table, p);
|
||||||
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self,
|
||||||
new = bgp_info_new ();
|
bgp_attr_aggregate_intern(bgp, origin, aspath, community,
|
||||||
new->type = ZEBRA_ROUTE_BGP;
|
aggregate->as_set), rn);
|
||||||
new->sub_type = BGP_ROUTE_AGGREGATE;
|
|
||||||
new->peer = bgp->peer_self;
|
|
||||||
SET_FLAG (new->flags, BGP_INFO_VALID);
|
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_info_add (rn, new);
|
||||||
bgp_unlock_node (rn);
|
bgp_unlock_node (rn);
|
||||||
@ -5531,16 +5514,12 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
|
|||||||
aspath_unintern (&attr.aspath);
|
aspath_unintern (&attr.aspath);
|
||||||
bgp_attr_extra_free (&attr);
|
bgp_attr_extra_free (&attr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new = bgp_info_new ();
|
new = info_make(type, BGP_ROUTE_REDISTRIBUTE, bgp->peer_self,
|
||||||
new->type = type;
|
new_attr, bn);
|
||||||
new->sub_type = BGP_ROUTE_REDISTRIBUTE;
|
|
||||||
new->peer = bgp->peer_self;
|
|
||||||
SET_FLAG (new->flags, BGP_INFO_VALID);
|
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_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST);
|
||||||
bgp_info_add (bn, new);
|
bgp_info_add (bn, new);
|
||||||
|
@ -21,8 +21,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|||||||
#ifndef _QUAGGA_BGP_ROUTE_H
|
#ifndef _QUAGGA_BGP_ROUTE_H
|
||||||
#define _QUAGGA_BGP_ROUTE_H
|
#define _QUAGGA_BGP_ROUTE_H
|
||||||
|
|
||||||
|
#include "queue.h"
|
||||||
#include "bgp_table.h"
|
#include "bgp_table.h"
|
||||||
|
|
||||||
|
struct bgp_nexthop_cache;
|
||||||
|
|
||||||
/* Ancillary information to struct bgp_info,
|
/* Ancillary information to struct bgp_info,
|
||||||
* used for uncommonly used data (aggregation, MPLS, etc.)
|
* used for uncommonly used data (aggregation, MPLS, etc.)
|
||||||
* and lazily allocated to save memory.
|
* and lazily allocated to save memory.
|
||||||
@ -47,7 +50,16 @@ struct bgp_info
|
|||||||
/* For linked list. */
|
/* For linked list. */
|
||||||
struct bgp_info *next;
|
struct bgp_info *next;
|
||||||
struct bgp_info *prev;
|
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. */
|
/* Peer structure. */
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */
|
|||||||
#include "bgpd/bgp_fsm.h"
|
#include "bgpd/bgp_fsm.h"
|
||||||
#include "bgpd/bgp_debug.h"
|
#include "bgpd/bgp_debug.h"
|
||||||
#include "bgpd/bgp_mpath.h"
|
#include "bgpd/bgp_mpath.h"
|
||||||
|
#include "bgpd/bgp_nexthop.h"
|
||||||
|
|
||||||
/* All information about zebra. */
|
/* All information about zebra. */
|
||||||
struct zclient *zclient = NULL;
|
struct zclient *zclient = NULL;
|
||||||
@ -75,6 +76,15 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length)
|
|||||||
return 0;
|
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. */
|
/* Inteface addition message from zebra. */
|
||||||
static int
|
static int
|
||||||
bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
|
bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
|
||||||
@ -1187,6 +1197,7 @@ bgp_zebra_init (void)
|
|||||||
zclient->ipv6_route_add = zebra_read_ipv6;
|
zclient->ipv6_route_add = zebra_read_ipv6;
|
||||||
zclient->ipv6_route_delete = zebra_read_ipv6;
|
zclient->ipv6_route_delete = zebra_read_ipv6;
|
||||||
#endif /* HAVE_IPV6 */
|
#endif /* HAVE_IPV6 */
|
||||||
|
zclient->nexthop_update = bgp_read_nexthop_update;
|
||||||
|
|
||||||
/* Interface related init. */
|
/* Interface related init. */
|
||||||
if_init ();
|
if_init ();
|
||||||
|
326
doc/next-hop-tracking.txt
Normal file
326
doc/next-hop-tracking.txt
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
0. Introduction
|
||||||
|
|
||||||
|
This is the design specification for next hop tracking feature in
|
||||||
|
Quagga.
|
||||||
|
|
||||||
|
1. Background
|
||||||
|
|
||||||
|
Recursive routes are of the form:
|
||||||
|
|
||||||
|
p/m --> n
|
||||||
|
[Ex: 1.1.0.0/16 --> 2.2.2.2]
|
||||||
|
|
||||||
|
where 'n' itself is resolved through another route as follows:
|
||||||
|
|
||||||
|
p2/m --> h, interface
|
||||||
|
[Ex: 2.2.2.0/24 --> 3.3.3.3, eth0]
|
||||||
|
|
||||||
|
Usually, BGP routes are recursive in nature and BGP nexthops get
|
||||||
|
resolved through an IGP route. IGP usually adds its routes pointing to
|
||||||
|
an interface (these are called non-recursive routes).
|
||||||
|
|
||||||
|
When BGP receives a recursive route from a peer, it needs to validate
|
||||||
|
the nexthop. The path is marked valid or invalid based on the
|
||||||
|
reachability status of the nexthop. Nexthop validation is also
|
||||||
|
important for BGP decision process as the metric to reach the nexthop
|
||||||
|
is a parameter to best path selection process.
|
||||||
|
|
||||||
|
As it goes with routing, this is a dynamic process. Route to the
|
||||||
|
nexthop can change. The nexthop can become unreachable or
|
||||||
|
reachable. In the current BGP implementation, the nexthop validation
|
||||||
|
is done periodically in the scanner run. The default scanner run
|
||||||
|
interval is one minute. Every minute, the scanner task walks the
|
||||||
|
entire BGP table. It checks the validity of each nexthop with Zebra
|
||||||
|
(the routing table manager) through a request and response message
|
||||||
|
exchange between BGP and Zebra process. BGP process is blocked for
|
||||||
|
that duration. The mechanism has two major drawbacks:
|
||||||
|
|
||||||
|
(1) The scanner task runs to completion. That can potentially starve
|
||||||
|
the other tasks for long periods of time, based on the BGP table
|
||||||
|
size and number of nexthops.
|
||||||
|
|
||||||
|
(2) Convergence around routing changes that affect the nexthops can be
|
||||||
|
long (around a minute with the default intervals). The interval
|
||||||
|
can be shortened to achieve faster reaction time, but it makes the
|
||||||
|
first problem worse, with the scanner task consuming most of the
|
||||||
|
CPU resources.
|
||||||
|
|
||||||
|
"Next hop tracking" feature makes this process event-driven. It
|
||||||
|
eliminates periodic nexthop validation and introduces an asynchronous
|
||||||
|
communication path between BGP and Zebra for route change notifications
|
||||||
|
that can then be acted upon.
|
||||||
|
|
||||||
|
2. Goal
|
||||||
|
|
||||||
|
Stating the obvious, the main goal is to remove the two limitations we
|
||||||
|
discussed in the previous section. The goals, in a constructive tone,
|
||||||
|
are the following:
|
||||||
|
|
||||||
|
- fairness: the scanner run should not consume an unjustly high amount
|
||||||
|
of CPU time. This should give an overall good performance and
|
||||||
|
response time to other events (route changes, session events,
|
||||||
|
IO/user interface).
|
||||||
|
|
||||||
|
- convergence: BGP must react to nexthop changes instantly and provide
|
||||||
|
sub-second convergence. This may involve diverting the routes from
|
||||||
|
one nexthop to another.
|
||||||
|
|
||||||
|
3. Overview of the changes
|
||||||
|
|
||||||
|
The changes are in both BGP and Zebra modules. The short summary is
|
||||||
|
the following:
|
||||||
|
|
||||||
|
- Zebra implements a registration mechanism by which clients can
|
||||||
|
register for next hop notification. Consequently, it maintains a
|
||||||
|
separate table, per (VRF, AF) pair, of next hops and interested
|
||||||
|
client-list per next hop.
|
||||||
|
|
||||||
|
- When the main routing table changes in Zebra, it evaluates the next
|
||||||
|
hop table: for each next hop, it checks if the route table
|
||||||
|
modifications have changed its state. If so, it notifies the
|
||||||
|
interested clients.
|
||||||
|
|
||||||
|
- BGP is one such client. It registers the next hops corresponding to
|
||||||
|
all of its received routes/paths. It also threads the paths against
|
||||||
|
each nexthop structure.
|
||||||
|
|
||||||
|
- When BGP receives a next hop notification from Zebra, it walks the
|
||||||
|
corresponding path list. It makes them valid or invalid depending
|
||||||
|
on the next hop notification. It then re-computes best path for the
|
||||||
|
corresponding destination. This may result in re-announcing those
|
||||||
|
destinations to peers.
|
||||||
|
|
||||||
|
4. Design
|
||||||
|
|
||||||
|
4.1. Modules
|
||||||
|
|
||||||
|
The core design introduces an "nht" (next hop tracking) module in BGP
|
||||||
|
and "rnh" (recursive nexthop) module in Zebra. The "nht" module
|
||||||
|
provides the following APIs:
|
||||||
|
|
||||||
|
bgp_find_or_add_nexthop() : find or add a nexthop in BGP nexthop table
|
||||||
|
bgp_find_nexthop() : find a nexthop in BGP nexthop table
|
||||||
|
bgp_parse_nexthop_update() : parse a nexthop update message coming
|
||||||
|
from zebra
|
||||||
|
|
||||||
|
The "rnh" module provides the following APIs:
|
||||||
|
|
||||||
|
zebra_add_rnh() : add a recursive nexthop
|
||||||
|
zebra_delete_rnh() : delete a recursive nexthop
|
||||||
|
zebra_lookup_rnh() : lookup a recursive nexthop
|
||||||
|
|
||||||
|
zebra_add_rnh_client() : register a client for nexthop notifications
|
||||||
|
against a recursive nexthop
|
||||||
|
|
||||||
|
zebra_remove_rnh_client(): remove the client registration for a
|
||||||
|
recursive nexthop
|
||||||
|
|
||||||
|
zebra_evaluate_rnh_table(): (re)evaluate the recursive nexthop table
|
||||||
|
(most probably because the main routing
|
||||||
|
table has changed).
|
||||||
|
|
||||||
|
zebra_cleanup_rnh_client(): Cleanup a client from the "rnh" module
|
||||||
|
data structures (most probably because the
|
||||||
|
client is going away).
|
||||||
|
|
||||||
|
4.2. Control flow
|
||||||
|
|
||||||
|
The next hop registration control flow is the following:
|
||||||
|
|
||||||
|
<==== BGP Process ====>|<==== Zebra Process ====>
|
||||||
|
|
|
||||||
|
receive module nht module | zserv module rnh module
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
| | |
|
||||||
|
bgp_update_ | | |
|
||||||
|
main() | bgp_find_or_add_ | |
|
||||||
|
| nexthop() | |
|
||||||
|
| | |
|
||||||
|
| | zserv_nexthop_ |
|
||||||
|
| | register() |
|
||||||
|
| | | zebra_add_rnh()
|
||||||
|
| | |
|
||||||
|
|
||||||
|
|
||||||
|
The next hop notification control flow is the following:
|
||||||
|
|
||||||
|
<==== Zebra Process ====>|<==== BGP Process ====>
|
||||||
|
|
|
||||||
|
rib module rnh module | zebra module nht module
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
| | |
|
||||||
|
meta_queue_ | | |
|
||||||
|
process() | zebra_evaluate_ | |
|
||||||
|
| rnh_table() | |
|
||||||
|
| | |
|
||||||
|
| | bgp_read_nexthop_ |
|
||||||
|
| | update() |
|
||||||
|
| | | bgp_parse_
|
||||||
|
| | | nexthop_update()
|
||||||
|
| | |
|
||||||
|
|
||||||
|
|
||||||
|
4.3. zclient message format
|
||||||
|
|
||||||
|
ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are
|
||||||
|
encoded in the following way:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0 1 2 3
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | AF | prefix len |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . Nexthop prefix .
|
||||||
|
* . .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . .
|
||||||
|
* . .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | AF | prefix len |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . Nexthop prefix .
|
||||||
|
* . .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
|
||||||
|
ZEBRA_NEXTHOP_UPDATE message is encoded as follows:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0 1 2 3
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | AF | prefix len |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . Nexthop prefix getting resolved .
|
||||||
|
* . .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | metric |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | #nexthops |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | nexthop type |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . resolving Nexthop details .
|
||||||
|
* . .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | nexthop type |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* . resolving Nexthop details .
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
|
||||||
|
4.4. BGP data structure
|
||||||
|
|
||||||
|
Legend:
|
||||||
|
|
||||||
|
/\ struct bgp_node: a BGP destination/route/prefix
|
||||||
|
\/
|
||||||
|
|
||||||
|
[ ] struct bgp_info: a BGP path (e.g. route received from a peer)
|
||||||
|
|
||||||
|
_
|
||||||
|
(_) struct bgp_nexthop_cache: a BGP nexthop
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/\ NULL
|
||||||
|
\/--+ ^
|
||||||
|
| :
|
||||||
|
+--[ ]--[ ]--[ ]--> NULL
|
||||||
|
/\ :
|
||||||
|
\/--+ :
|
||||||
|
| :
|
||||||
|
+--[ ]--[ ]--> NULL
|
||||||
|
:
|
||||||
|
_ :
|
||||||
|
(_).............
|
||||||
|
|
||||||
|
|
||||||
|
4.5. Zebra data structure
|
||||||
|
|
||||||
|
rnh table:
|
||||||
|
|
||||||
|
O
|
||||||
|
/ \
|
||||||
|
O O
|
||||||
|
/ \
|
||||||
|
O O
|
||||||
|
|
||||||
|
struct rnh
|
||||||
|
{
|
||||||
|
u_char flags;
|
||||||
|
struct rib *state;
|
||||||
|
struct list *client_list;
|
||||||
|
struct route_node *node;
|
||||||
|
};
|
||||||
|
|
||||||
|
5. User interface changes
|
||||||
|
|
||||||
|
quagga# show ip nht
|
||||||
|
3.3.3.3
|
||||||
|
resolved via kernel
|
||||||
|
via 11.0.0.6, swp1
|
||||||
|
Client list: bgp(fd 12)
|
||||||
|
11.0.0.10
|
||||||
|
resolved via connected
|
||||||
|
is directly connected, swp2
|
||||||
|
Client list: bgp(fd 12)
|
||||||
|
11.0.0.18
|
||||||
|
resolved via connected
|
||||||
|
is directly connected, swp4
|
||||||
|
Client list: bgp(fd 12)
|
||||||
|
11.11.11.11
|
||||||
|
resolved via kernel
|
||||||
|
via 10.0.1.2, eth0
|
||||||
|
Client list: bgp(fd 12)
|
||||||
|
|
||||||
|
quagga# show ip bgp nexthop
|
||||||
|
Current BGP nexthop cache:
|
||||||
|
3.3.3.3 valid [IGP metric 0], #paths 3
|
||||||
|
Last update: Wed Oct 16 04:43:49 2013
|
||||||
|
|
||||||
|
11.0.0.10 valid [IGP metric 1], #paths 1
|
||||||
|
Last update: Wed Oct 16 04:43:51 2013
|
||||||
|
|
||||||
|
11.0.0.18 valid [IGP metric 1], #paths 2
|
||||||
|
Last update: Wed Oct 16 04:43:47 2013
|
||||||
|
|
||||||
|
11.11.11.11 valid [IGP metric 0], #paths 1
|
||||||
|
Last update: Wed Oct 16 04:43:47 2013
|
||||||
|
|
||||||
|
quagga# show ipv6 nht
|
||||||
|
quagga# show ip bgp nexthop detail
|
||||||
|
|
||||||
|
quagga# debug bgp nht
|
||||||
|
quagga# debug zebra nht
|
||||||
|
|
||||||
|
6. Sample test cases
|
||||||
|
|
||||||
|
r2----r3
|
||||||
|
/ \ /
|
||||||
|
r1----r4
|
||||||
|
|
||||||
|
- Verify that a change in IGP cost triggers NHT
|
||||||
|
+ shutdown the r1-r4 and r2-r4 links
|
||||||
|
+ no shut the r1-r4 and r2-r4 links and wait for OSPF to come back
|
||||||
|
up
|
||||||
|
+ We should be back to the original nexthop via r4 now
|
||||||
|
- Verify that a NH becoming unreachable triggers NHT
|
||||||
|
+ Shutdown all links to r4
|
||||||
|
- Verify that a NH becoming reachable triggers NHT
|
||||||
|
+ no shut all links to r4
|
||||||
|
|
||||||
|
7. Future work
|
||||||
|
|
||||||
|
- route-policy for next hop validation (e.g. ignore default route)
|
||||||
|
- damping for rapid next hop changes
|
||||||
|
- prioritized handling of nexthop changes ((un)reachability vs. metric
|
||||||
|
changes)
|
||||||
|
- handling recursion loop, e.g.
|
||||||
|
11.11.11.11/32 -> 12.12.12.12
|
||||||
|
12.12.12.12/32 -> 11.11.11.11
|
||||||
|
11.0.0.0/8 -> <interface>
|
||||||
|
- better statistics
|
@ -12,7 +12,7 @@ libzebra_la_SOURCES = \
|
|||||||
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
|
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
|
||||||
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
|
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
|
||||||
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
|
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
|
||||||
sigevent.c pqueue.c jhash.c memtypes.c workqueue.c
|
sigevent.c pqueue.c jhash.c memtypes.c workqueue.c nexthop.c
|
||||||
|
|
||||||
BUILT_SOURCES = memtypes.h route_types.h gitversion.h
|
BUILT_SOURCES = memtypes.h route_types.h gitversion.h
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ pkginclude_HEADERS = \
|
|||||||
str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
|
str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
|
||||||
plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
|
plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
|
||||||
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
|
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
|
||||||
workqueue.h route_types.h libospf.h
|
workqueue.h route_types.h libospf.h nexthop.h
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
regex.c regex-gnu.h \
|
regex.c regex-gnu.h \
|
||||||
|
@ -845,6 +845,9 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
|
DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
|
||||||
DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
|
DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
|
||||||
DESC_ENTRY (ZEBRA_HELLO),
|
DESC_ENTRY (ZEBRA_HELLO),
|
||||||
|
DESC_ENTRY (ZEBRA_NEXTHOP_REGISTER),
|
||||||
|
DESC_ENTRY (ZEBRA_NEXTHOP_UNREGISTER),
|
||||||
|
DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE),
|
||||||
};
|
};
|
||||||
#undef DESC_ENTRY
|
#undef DESC_ENTRY
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ struct memory_list memory_list_zebra[] =
|
|||||||
{ MTYPE_STATIC_IPV6, "Static IPv6 route" },
|
{ MTYPE_STATIC_IPV6, "Static IPv6 route" },
|
||||||
{ MTYPE_RIB_DEST, "RIB destination" },
|
{ MTYPE_RIB_DEST, "RIB destination" },
|
||||||
{ MTYPE_RIB_TABLE_INFO, "RIB table info" },
|
{ MTYPE_RIB_TABLE_INFO, "RIB table info" },
|
||||||
|
{ MTYPE_RNH, "Nexthop tracking object" },
|
||||||
{ -1, NULL },
|
{ -1, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
100
lib/nexthop.c
Normal file
100
lib/nexthop.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/* A generic nexthop structure
|
||||||
|
* 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 "prefix.h"
|
||||||
|
#include "table.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "if.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "sockunion.h"
|
||||||
|
#include "linklist.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "prefix.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
|
/* check if nexthops are same, non-recursive */
|
||||||
|
int
|
||||||
|
nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2)
|
||||||
|
{
|
||||||
|
if (next1->type != next2->type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (next1->type)
|
||||||
|
{
|
||||||
|
case NEXTHOP_TYPE_IPV4:
|
||||||
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
|
if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
|
||||||
|
return 0;
|
||||||
|
if (next1->ifindex && (next1->ifindex != next2->ifindex))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_IFNAME:
|
||||||
|
if (next1->ifindex != next2->ifindex)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case NEXTHOP_TYPE_IPV6:
|
||||||
|
if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nexthop_type_to_str
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
nexthop_type_to_str (enum nexthop_types_t nh_type)
|
||||||
|
{
|
||||||
|
static const char *desc[] = {
|
||||||
|
"none",
|
||||||
|
"Directly connected",
|
||||||
|
"Interface route",
|
||||||
|
"IPv4 nexthop",
|
||||||
|
"IPv4 nexthop with ifindex",
|
||||||
|
"IPv4 nexthop with ifname",
|
||||||
|
"IPv6 nexthop",
|
||||||
|
"IPv6 nexthop with ifindex",
|
||||||
|
"IPv6 nexthop with ifname",
|
||||||
|
"Null0 nexthop",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (nh_type >= ZEBRA_NUM_OF (desc))
|
||||||
|
return "<Invalid nh type>";
|
||||||
|
|
||||||
|
return desc[nh_type];
|
||||||
|
}
|
89
lib/nexthop.h
Normal file
89
lib/nexthop.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Nexthop structure definition.
|
||||||
|
* 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 _LIB_NEXTHOP_H
|
||||||
|
#define _LIB_NEXTHOP_H
|
||||||
|
|
||||||
|
#include "prefix.h"
|
||||||
|
|
||||||
|
union g_addr {
|
||||||
|
struct in_addr ipv4;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
struct in6_addr ipv6;
|
||||||
|
#endif /* HAVE_IPV6 */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum nexthop_types_t
|
||||||
|
{
|
||||||
|
NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */
|
||||||
|
NEXTHOP_TYPE_IFNAME, /* Interface route. */
|
||||||
|
NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */
|
||||||
|
NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */
|
||||||
|
NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */
|
||||||
|
NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */
|
||||||
|
NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */
|
||||||
|
NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */
|
||||||
|
NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Nexthop structure. */
|
||||||
|
struct nexthop
|
||||||
|
{
|
||||||
|
struct nexthop *next;
|
||||||
|
struct nexthop *prev;
|
||||||
|
|
||||||
|
/* Interface index. */
|
||||||
|
char *ifname;
|
||||||
|
unsigned int ifindex;
|
||||||
|
|
||||||
|
enum nexthop_types_t type;
|
||||||
|
|
||||||
|
u_char flags;
|
||||||
|
#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */
|
||||||
|
#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
|
||||||
|
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
|
||||||
|
#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
|
||||||
|
#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */
|
||||||
|
|
||||||
|
/* Nexthop address */
|
||||||
|
union g_addr gate;
|
||||||
|
union g_addr src;
|
||||||
|
|
||||||
|
/* Nexthops obtained by recursive resolution.
|
||||||
|
*
|
||||||
|
* If the nexthop struct needs to be resolved recursively,
|
||||||
|
* NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
|
||||||
|
* obtained by recursive resolution will be added to `resolved'.
|
||||||
|
* Only one level of recursive resolution is currently supported. */
|
||||||
|
struct nexthop *resolved;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define nexthop_new() \
|
||||||
|
({ \
|
||||||
|
struct nexthop *n = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); \
|
||||||
|
n; \
|
||||||
|
})
|
||||||
|
|
||||||
|
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
|
||||||
|
extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
|
||||||
|
|
||||||
|
#endif /*_LIB_NEXTHOP_H */
|
@ -967,6 +967,12 @@ zclient_read (struct thread *thread)
|
|||||||
if (zclient->ipv6_route_delete)
|
if (zclient->ipv6_route_delete)
|
||||||
(*zclient->ipv6_route_delete) (command, zclient, length);
|
(*zclient->ipv6_route_delete) (command, zclient, length);
|
||||||
break;
|
break;
|
||||||
|
case ZEBRA_NEXTHOP_UPDATE:
|
||||||
|
if (zclient_debug)
|
||||||
|
zlog_debug("zclient rcvd nexthop update\n");
|
||||||
|
if (zclient->nexthop_update)
|
||||||
|
(*zclient->nexthop_update) (command, zclient, length);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ struct zclient
|
|||||||
int (*ipv4_route_delete) (int, struct zclient *, uint16_t);
|
int (*ipv4_route_delete) (int, struct zclient *, uint16_t);
|
||||||
int (*ipv6_route_add) (int, struct zclient *, uint16_t);
|
int (*ipv6_route_add) (int, struct zclient *, uint16_t);
|
||||||
int (*ipv6_route_delete) (int, struct zclient *, uint16_t);
|
int (*ipv6_route_delete) (int, struct zclient *, uint16_t);
|
||||||
|
int (*nexthop_update) (int, struct zclient *, uint16_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Zebra API message flag. */
|
/* Zebra API message flag. */
|
||||||
|
@ -424,7 +424,10 @@ struct in_pktinfo
|
|||||||
#define ZEBRA_ROUTER_ID_DELETE 21
|
#define ZEBRA_ROUTER_ID_DELETE 21
|
||||||
#define ZEBRA_ROUTER_ID_UPDATE 22
|
#define ZEBRA_ROUTER_ID_UPDATE 22
|
||||||
#define ZEBRA_HELLO 23
|
#define ZEBRA_HELLO 23
|
||||||
#define ZEBRA_MESSAGE_MAX 24
|
#define ZEBRA_NEXTHOP_REGISTER 24
|
||||||
|
#define ZEBRA_NEXTHOP_UNREGISTER 25
|
||||||
|
#define ZEBRA_NEXTHOP_UPDATE 26
|
||||||
|
#define ZEBRA_MESSAGE_MAX 27
|
||||||
|
|
||||||
/* Marker value used in new Zserv, in the byte location corresponding
|
/* Marker value used in new Zserv, in the byte location corresponding
|
||||||
* the command value in the old zserv header. To allow old and new
|
* the command value in the old zserv header. To allow old and new
|
||||||
@ -525,6 +528,7 @@ extern const char *zserv_command_string (unsigned int command);
|
|||||||
#define CHECK_FLAG(V,F) ((V) & (F))
|
#define CHECK_FLAG(V,F) ((V) & (F))
|
||||||
#define SET_FLAG(V,F) (V) |= (F)
|
#define SET_FLAG(V,F) (V) |= (F)
|
||||||
#define UNSET_FLAG(V,F) (V) &= ~(F)
|
#define UNSET_FLAG(V,F) (V) &= ~(F)
|
||||||
|
#define RESET_FLAG(V) (V) = 0
|
||||||
|
|
||||||
/* AFI and SAFI type. */
|
/* AFI and SAFI type. */
|
||||||
typedef u_int16_t afi_t;
|
typedef u_int16_t afi_t;
|
||||||
|
@ -34,16 +34,16 @@ zebra_SOURCES = \
|
|||||||
zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \
|
zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \
|
||||||
redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \
|
redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \
|
||||||
irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
|
irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
|
||||||
$(othersrc)
|
$(othersrc) zebra_rnh.c
|
||||||
|
|
||||||
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
|
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
|
||||||
zebra_vty.c \
|
zebra_vty.c \
|
||||||
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c
|
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
|
connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
|
||||||
interface.h ipforward.h irdp.h router-id.h kernel_socket.h \
|
interface.h ipforward.h irdp.h router-id.h kernel_socket.h \
|
||||||
rt_netlink.h zebra_fpm.h zebra_fpm_private.h
|
rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h
|
||||||
|
|
||||||
zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6)
|
zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6)
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ unsigned long zebra_debug_packet;
|
|||||||
unsigned long zebra_debug_kernel;
|
unsigned long zebra_debug_kernel;
|
||||||
unsigned long zebra_debug_rib;
|
unsigned long zebra_debug_rib;
|
||||||
unsigned long zebra_debug_fpm;
|
unsigned long zebra_debug_fpm;
|
||||||
|
unsigned long zebra_debug_nht;
|
||||||
|
|
||||||
DEFUN (show_debugging_zebra,
|
DEFUN (show_debugging_zebra,
|
||||||
show_debugging_zebra_cmd,
|
show_debugging_zebra_cmd,
|
||||||
@ -74,6 +75,8 @@ DEFUN (show_debugging_zebra,
|
|||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_FPM)
|
if (IS_ZEBRA_DEBUG_FPM)
|
||||||
vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE);
|
vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE);
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
vty_out (vty, " Zebra next-hop tracking debugging is on%s", VTY_NEWLINE);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -89,6 +92,17 @@ DEFUN (debug_zebra_events,
|
|||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (debug_zebra_nht,
|
||||||
|
debug_zebra_nht_cmd,
|
||||||
|
"debug zebra nht",
|
||||||
|
DEBUG_STR
|
||||||
|
"Zebra configuration\n"
|
||||||
|
"Debug option set for zebra next hop tracking\n")
|
||||||
|
{
|
||||||
|
zebra_debug_nht = ZEBRA_DEBUG_NHT;
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (debug_zebra_packet,
|
DEFUN (debug_zebra_packet,
|
||||||
debug_zebra_packet_cmd,
|
debug_zebra_packet_cmd,
|
||||||
"debug zebra packet",
|
"debug zebra packet",
|
||||||
@ -196,6 +210,18 @@ DEFUN (no_debug_zebra_events,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (no_debug_zebra_nht,
|
||||||
|
no_debug_zebra_nht_cmd,
|
||||||
|
"no debug zebra nht",
|
||||||
|
NO_STR
|
||||||
|
DEBUG_STR
|
||||||
|
"Zebra configuration\n"
|
||||||
|
"Debug option set for zebra next hop tracking\n")
|
||||||
|
{
|
||||||
|
zebra_debug_nht = 0;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (no_debug_zebra_packet,
|
DEFUN (no_debug_zebra_packet,
|
||||||
no_debug_zebra_packet_cmd,
|
no_debug_zebra_packet_cmd,
|
||||||
"no debug zebra packet",
|
"no debug zebra packet",
|
||||||
@ -352,6 +378,7 @@ zebra_debug_init (void)
|
|||||||
|
|
||||||
install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
|
install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_zebra_events_cmd);
|
install_element (ENABLE_NODE, &debug_zebra_events_cmd);
|
||||||
|
install_element (ENABLE_NODE, &debug_zebra_nht_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
|
install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
|
install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
|
install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
|
||||||
@ -360,6 +387,7 @@ zebra_debug_init (void)
|
|||||||
install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd);
|
install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd);
|
||||||
install_element (ENABLE_NODE, &debug_zebra_fpm_cmd);
|
install_element (ENABLE_NODE, &debug_zebra_fpm_cmd);
|
||||||
install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
|
install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
|
||||||
|
install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd);
|
||||||
install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
|
install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
|
||||||
install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
|
install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
|
||||||
install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd);
|
install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd);
|
||||||
@ -367,6 +395,7 @@ zebra_debug_init (void)
|
|||||||
install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd);
|
install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd);
|
||||||
|
|
||||||
install_element (CONFIG_NODE, &debug_zebra_events_cmd);
|
install_element (CONFIG_NODE, &debug_zebra_events_cmd);
|
||||||
|
install_element (CONFIG_NODE, &debug_zebra_nht_cmd);
|
||||||
install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
|
install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
|
||||||
install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
|
install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
|
||||||
install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
|
install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
|
||||||
@ -375,6 +404,7 @@ zebra_debug_init (void)
|
|||||||
install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd);
|
install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd);
|
||||||
install_element (CONFIG_NODE, &debug_zebra_fpm_cmd);
|
install_element (CONFIG_NODE, &debug_zebra_fpm_cmd);
|
||||||
install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
|
install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd);
|
||||||
install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
|
install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
|
||||||
install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
|
install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
|
||||||
install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd);
|
install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd);
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#define ZEBRA_DEBUG_RIB_Q 0x02
|
#define ZEBRA_DEBUG_RIB_Q 0x02
|
||||||
|
|
||||||
#define ZEBRA_DEBUG_FPM 0x01
|
#define ZEBRA_DEBUG_FPM 0x01
|
||||||
|
#define ZEBRA_DEBUG_NHT 0x01
|
||||||
|
|
||||||
/* Debug related macro. */
|
/* Debug related macro. */
|
||||||
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
|
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
|
||||||
@ -52,12 +53,14 @@
|
|||||||
#define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q)
|
#define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q)
|
||||||
|
|
||||||
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
|
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
|
||||||
|
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
|
||||||
|
|
||||||
extern unsigned long zebra_debug_event;
|
extern unsigned long zebra_debug_event;
|
||||||
extern unsigned long zebra_debug_packet;
|
extern unsigned long zebra_debug_packet;
|
||||||
extern unsigned long zebra_debug_kernel;
|
extern unsigned long zebra_debug_kernel;
|
||||||
extern unsigned long zebra_debug_rib;
|
extern unsigned long zebra_debug_rib;
|
||||||
extern unsigned long zebra_debug_fpm;
|
extern unsigned long zebra_debug_fpm;
|
||||||
|
extern unsigned long zebra_debug_nht;
|
||||||
|
|
||||||
extern void zebra_debug_init (void);
|
extern void zebra_debug_init (void);
|
||||||
|
|
||||||
|
62
zebra/rib.h
62
zebra/rib.h
@ -26,18 +26,10 @@
|
|||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#define DISTANCE_INFINITY 255
|
#define DISTANCE_INFINITY 255
|
||||||
|
|
||||||
/* Routing information base. */
|
|
||||||
|
|
||||||
union g_addr {
|
|
||||||
struct in_addr ipv4;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
struct in6_addr ipv6;
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rib
|
struct rib
|
||||||
{
|
{
|
||||||
/* Link list. */
|
/* Link list. */
|
||||||
@ -224,50 +216,6 @@ struct static_ipv6
|
|||||||
};
|
};
|
||||||
#endif /* HAVE_IPV6 */
|
#endif /* HAVE_IPV6 */
|
||||||
|
|
||||||
enum nexthop_types_t
|
|
||||||
{
|
|
||||||
NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */
|
|
||||||
NEXTHOP_TYPE_IFNAME, /* Interface route. */
|
|
||||||
NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */
|
|
||||||
NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */
|
|
||||||
NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */
|
|
||||||
NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */
|
|
||||||
NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */
|
|
||||||
NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */
|
|
||||||
NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Nexthop structure. */
|
|
||||||
struct nexthop
|
|
||||||
{
|
|
||||||
struct nexthop *next;
|
|
||||||
struct nexthop *prev;
|
|
||||||
|
|
||||||
/* Interface index. */
|
|
||||||
char *ifname;
|
|
||||||
unsigned int ifindex;
|
|
||||||
|
|
||||||
enum nexthop_types_t type;
|
|
||||||
|
|
||||||
u_char flags;
|
|
||||||
#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */
|
|
||||||
#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
|
|
||||||
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
|
|
||||||
#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
|
|
||||||
|
|
||||||
/* Nexthop address */
|
|
||||||
union g_addr gate;
|
|
||||||
union g_addr src;
|
|
||||||
|
|
||||||
/* Nexthops obtained by recursive resolution.
|
|
||||||
*
|
|
||||||
* If the nexthop struct needs to be resolved recursively,
|
|
||||||
* NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
|
|
||||||
* obtained by recursive resolution will be added to `resolved'.
|
|
||||||
* Only one level of recursive resolution is currently supported. */
|
|
||||||
struct nexthop *resolved;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The following for loop allows to iterate over the nexthop
|
/* The following for loop allows to iterate over the nexthop
|
||||||
* structure of routes.
|
* structure of routes.
|
||||||
*
|
*
|
||||||
@ -334,6 +282,9 @@ struct vrf
|
|||||||
|
|
||||||
/* Static route configuration. */
|
/* Static route configuration. */
|
||||||
struct route_table *stable[AFI_MAX][SAFI_MAX];
|
struct route_table *stable[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
|
/* Recursive Nexthop table */
|
||||||
|
struct route_table *rnh_table[AFI_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -373,7 +324,6 @@ typedef struct rib_tables_iter_t_
|
|||||||
rib_tables_iter_state_t state;
|
rib_tables_iter_state_t state;
|
||||||
} rib_tables_iter_t;
|
} rib_tables_iter_t;
|
||||||
|
|
||||||
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
|
|
||||||
extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
|
extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
|
||||||
extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
|
extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
|
||||||
extern struct nexthop *nexthop_blackhole_add (struct rib *);
|
extern struct nexthop *nexthop_blackhole_add (struct rib *);
|
||||||
@ -383,6 +333,10 @@ extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *,
|
|||||||
struct in_addr *,
|
struct in_addr *,
|
||||||
struct in_addr *,
|
struct in_addr *,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
|
extern void nexthop_free (struct nexthop *nexthop);
|
||||||
|
extern void nexthops_free (struct nexthop *nexthop);
|
||||||
|
extern void nexthop_add (struct rib *rib, struct nexthop *nexthop);
|
||||||
|
|
||||||
extern int nexthop_has_fib_child(struct nexthop *);
|
extern int nexthop_has_fib_child(struct nexthop *);
|
||||||
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
|
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
|
||||||
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
|
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "rib.h"
|
#include "rib.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "privs.h"
|
#include "privs.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "zebra/zserv.h"
|
#include "zebra/zserv.h"
|
||||||
#include "zebra/rt.h"
|
#include "zebra/rt.h"
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "rib.h"
|
#include "rib.h"
|
||||||
|
|
||||||
#include "rt_netlink.h"
|
#include "rt_netlink.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "zebra_fpm_private.h"
|
#include "zebra_fpm_private.h"
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "workqueue.h"
|
#include "workqueue.h"
|
||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
#include "routemap.h"
|
#include "routemap.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "zebra/rib.h"
|
#include "zebra/rib.h"
|
||||||
#include "zebra/rt.h"
|
#include "zebra/rt.h"
|
||||||
@ -41,6 +42,7 @@
|
|||||||
#include "zebra/redistribute.h"
|
#include "zebra/redistribute.h"
|
||||||
#include "zebra/debug.h"
|
#include "zebra/debug.h"
|
||||||
#include "zebra/zebra_fpm.h"
|
#include "zebra/zebra_fpm.h"
|
||||||
|
#include "zebra/zebra_rnh.h"
|
||||||
|
|
||||||
/* Default rtm_table for all clients */
|
/* Default rtm_table for all clients */
|
||||||
extern struct zebra_t zebrad;
|
extern struct zebra_t zebrad;
|
||||||
@ -118,6 +120,8 @@ vrf_alloc (const char *name)
|
|||||||
vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init ();
|
vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init ();
|
||||||
vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
|
vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
|
||||||
|
|
||||||
|
vrf->rnh_table[AFI_IP] = route_table_init();
|
||||||
|
vrf->rnh_table[AFI_IP6] = route_table_init();
|
||||||
|
|
||||||
return vrf;
|
return vrf;
|
||||||
}
|
}
|
||||||
@ -177,31 +181,6 @@ vrf_static_table (afi_t afi, safi_t safi, u_int32_t id)
|
|||||||
return vrf->stable[afi][safi];
|
return vrf->stable[afi][safi];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* nexthop_type_to_str
|
|
||||||
*/
|
|
||||||
const char *
|
|
||||||
nexthop_type_to_str (enum nexthop_types_t nh_type)
|
|
||||||
{
|
|
||||||
static const char *desc[] = {
|
|
||||||
"none",
|
|
||||||
"Directly connected",
|
|
||||||
"Interface route",
|
|
||||||
"IPv4 nexthop",
|
|
||||||
"IPv4 nexthop with ifindex",
|
|
||||||
"IPv4 nexthop with ifname",
|
|
||||||
"IPv6 nexthop",
|
|
||||||
"IPv6 nexthop with ifindex",
|
|
||||||
"IPv6 nexthop with ifname",
|
|
||||||
"Null0 nexthop",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (nh_type >= ZEBRA_NUM_OF (desc))
|
|
||||||
return "<Invalid nh type>";
|
|
||||||
|
|
||||||
return desc[nh_type];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add nexthop to the end of a nexthop list. */
|
/* Add nexthop to the end of a nexthop list. */
|
||||||
static void
|
static void
|
||||||
_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
|
_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
|
||||||
@ -218,7 +197,7 @@ _nexthop_add (struct nexthop **target, struct nexthop *nexthop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add nexthop to the end of a rib node's nexthop list */
|
/* Add nexthop to the end of a rib node's nexthop list */
|
||||||
static void
|
void
|
||||||
nexthop_add (struct rib *rib, struct nexthop *nexthop)
|
nexthop_add (struct rib *rib, struct nexthop *nexthop)
|
||||||
{
|
{
|
||||||
_nexthop_add(&rib->nexthop, nexthop);
|
_nexthop_add(&rib->nexthop, nexthop);
|
||||||
@ -238,10 +217,8 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop)
|
|||||||
rib->nexthop_num--;
|
rib->nexthop_num--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nexthops_free(struct nexthop *nexthop);
|
|
||||||
|
|
||||||
/* Free nexthop. */
|
/* Free nexthop. */
|
||||||
static void
|
void
|
||||||
nexthop_free (struct nexthop *nexthop)
|
nexthop_free (struct nexthop *nexthop)
|
||||||
{
|
{
|
||||||
if (nexthop->ifname)
|
if (nexthop->ifname)
|
||||||
@ -252,7 +229,7 @@ nexthop_free (struct nexthop *nexthop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Frees a list of nexthops */
|
/* Frees a list of nexthops */
|
||||||
static void
|
void
|
||||||
nexthops_free (struct nexthop *nexthop)
|
nexthops_free (struct nexthop *nexthop)
|
||||||
{
|
{
|
||||||
struct nexthop *nh, *next;
|
struct nexthop *nh, *next;
|
||||||
@ -1475,6 +1452,18 @@ process_subq (struct list * subq, u_char qindex)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All meta queues have been processed. Trigger next-hop evaluation.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
meta_queue_process_complete (struct work_queue *dummy)
|
||||||
|
{
|
||||||
|
zebra_evaluate_rnh_table(0, AF_INET);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
zebra_evaluate_rnh_table(0, AF_INET6);
|
||||||
|
#endif /* HAVE_IPV6 */
|
||||||
|
}
|
||||||
|
|
||||||
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
|
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
|
||||||
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
|
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
|
||||||
* is pointed to the meta queue structure.
|
* is pointed to the meta queue structure.
|
||||||
@ -1635,6 +1624,7 @@ rib_queue_init (struct zebra_t *zebra)
|
|||||||
/* fill in the work queue spec */
|
/* fill in the work queue spec */
|
||||||
zebra->ribq->spec.workfunc = &meta_queue_process;
|
zebra->ribq->spec.workfunc = &meta_queue_process;
|
||||||
zebra->ribq->spec.errorfunc = NULL;
|
zebra->ribq->spec.errorfunc = NULL;
|
||||||
|
zebra->ribq->spec.completion_func = &meta_queue_process_complete;
|
||||||
/* XXX: TODO: These should be runtime configurable via vty */
|
/* XXX: TODO: These should be runtime configurable via vty */
|
||||||
zebra->ribq->spec.max_retries = 3;
|
zebra->ribq->spec.max_retries = 3;
|
||||||
zebra->ribq->spec.hold = rib_process_hold_time;
|
zebra->ribq->spec.hold = rib_process_hold_time;
|
||||||
|
603
zebra/zebra_rnh.c
Normal file
603
zebra/zebra_rnh.c
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
/* Zebra next hop tracking code
|
||||||
|
* 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 "prefix.h"
|
||||||
|
#include "table.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "if.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "sockunion.h"
|
||||||
|
#include "linklist.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "workqueue.h"
|
||||||
|
#include "prefix.h"
|
||||||
|
#include "routemap.h"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
|
#include "zebra/rib.h"
|
||||||
|
#include "zebra/rt.h"
|
||||||
|
#include "zebra/zserv.h"
|
||||||
|
#include "zebra/redistribute.h"
|
||||||
|
#include "zebra/debug.h"
|
||||||
|
#include "zebra/zebra_rnh.h"
|
||||||
|
|
||||||
|
#define lookup_rnh_table(v, f) \
|
||||||
|
({ \
|
||||||
|
struct vrf *vrf; \
|
||||||
|
struct route_table *t = NULL; \
|
||||||
|
vrf = vrf_lookup(v); \
|
||||||
|
if (vrf) \
|
||||||
|
t = vrf->rnh_table[family2afi(f)]; \
|
||||||
|
t; \
|
||||||
|
})
|
||||||
|
|
||||||
|
static void free_state(struct rib *rib);
|
||||||
|
static void copy_state(struct rnh *rnh, struct rib *rib);
|
||||||
|
static int compare_state(struct rib *r1, struct rib *r2);
|
||||||
|
static int send_client(struct rnh *rnh, struct zserv *client);
|
||||||
|
static void print_rnh(struct route_node *rn, struct vty *vty);
|
||||||
|
|
||||||
|
char *
|
||||||
|
rnh_str (struct rnh *rnh, char *buf, int size)
|
||||||
|
{
|
||||||
|
prefix2str(&(rnh->node->p), buf, size);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rnh *
|
||||||
|
zebra_add_rnh (struct prefix *p, u_int32_t vrfid)
|
||||||
|
{
|
||||||
|
struct route_table *table;
|
||||||
|
struct route_node *rn;
|
||||||
|
struct rnh *rnh = NULL;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
prefix2str(p, buf, INET6_ADDRSTRLEN);
|
||||||
|
zlog_debug("add rnh %s in vrf %d", buf, vrfid);
|
||||||
|
}
|
||||||
|
table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
|
||||||
|
if (!table)
|
||||||
|
{
|
||||||
|
zlog_debug("add_rnh: rnh table not found\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make it sure prefixlen is applied to the prefix. */
|
||||||
|
apply_mask (p);
|
||||||
|
|
||||||
|
/* Lookup (or add) route node.*/
|
||||||
|
rn = route_node_get (table, p);
|
||||||
|
|
||||||
|
if (!rn->info)
|
||||||
|
{
|
||||||
|
rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
|
||||||
|
rnh->client_list = list_new();
|
||||||
|
route_lock_node (rn);
|
||||||
|
rn->info = rnh;
|
||||||
|
rnh->node = rn;
|
||||||
|
}
|
||||||
|
|
||||||
|
route_unlock_node (rn);
|
||||||
|
return (rn->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rnh *
|
||||||
|
zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid)
|
||||||
|
{
|
||||||
|
struct route_table *table;
|
||||||
|
struct route_node *rn;
|
||||||
|
|
||||||
|
table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
|
||||||
|
if (!table)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Make it sure prefixlen is applied to the prefix. */
|
||||||
|
apply_mask (p);
|
||||||
|
|
||||||
|
/* Lookup route node.*/
|
||||||
|
rn = route_node_lookup (table, p);
|
||||||
|
if (!rn)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
route_unlock_node (rn);
|
||||||
|
return (rn->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zebra_delete_rnh (struct rnh *rnh)
|
||||||
|
{
|
||||||
|
struct route_node *rn;
|
||||||
|
|
||||||
|
if (!rnh || !(rn = rnh->node))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
list_free(rnh->client_list);
|
||||||
|
free_state(rnh->state);
|
||||||
|
XFREE(MTYPE_RNH, rn->info);
|
||||||
|
rn->info = NULL;
|
||||||
|
route_unlock_node (rn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zebra_add_rnh_client (struct rnh *rnh, struct zserv *client)
|
||||||
|
{
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
zlog_debug("client %s registers rnh %s",
|
||||||
|
zebra_route_string(client->proto),
|
||||||
|
rnh_str(rnh, buf, INET6_ADDRSTRLEN));
|
||||||
|
}
|
||||||
|
if (!listnode_lookup(rnh->client_list, client))
|
||||||
|
{
|
||||||
|
listnode_add(rnh->client_list, client);
|
||||||
|
send_client(rnh, client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
|
||||||
|
{
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
zlog_debug("client %s unregisters rnh %s",
|
||||||
|
zebra_route_string(client->proto),
|
||||||
|
rnh_str(rnh, buf, INET6_ADDRSTRLEN));
|
||||||
|
}
|
||||||
|
listnode_delete(rnh->client_list, client);
|
||||||
|
if (list_isempty(rnh->client_list))
|
||||||
|
zebra_delete_rnh(rnh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
zebra_evaluate_rnh_table (int vrfid, int family)
|
||||||
|
{
|
||||||
|
struct route_table *ptable;
|
||||||
|
struct route_table *ntable;
|
||||||
|
struct route_node *prn;
|
||||||
|
struct route_node *nrn;
|
||||||
|
struct rnh *rnh;
|
||||||
|
struct zserv *client;
|
||||||
|
struct listnode *node;
|
||||||
|
struct rib *rib;
|
||||||
|
|
||||||
|
ntable = lookup_rnh_table(vrfid, family);
|
||||||
|
if (!ntable)
|
||||||
|
{
|
||||||
|
zlog_debug("evaluate_rnh_table: rnh table not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptable = vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
|
||||||
|
if (!ptable)
|
||||||
|
{
|
||||||
|
zlog_debug("evaluate_rnh_table: prefix table not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
|
||||||
|
{
|
||||||
|
if (!nrn->info)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prn = route_node_match(ptable, &nrn->p);
|
||||||
|
if (!prn)
|
||||||
|
rib = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RNODE_FOREACH_RIB(prn, rib)
|
||||||
|
{
|
||||||
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
|
||||||
|
continue;
|
||||||
|
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rnh = nrn->info;
|
||||||
|
if (compare_state(rib, rnh->state))
|
||||||
|
{
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char bufn[INET6_ADDRSTRLEN];
|
||||||
|
char bufp[INET6_ADDRSTRLEN];
|
||||||
|
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
|
||||||
|
if (prn)
|
||||||
|
prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
|
||||||
|
else
|
||||||
|
strcpy(bufp, "null");
|
||||||
|
zlog_debug("rnh %s resolved through route %s - sending "
|
||||||
|
"nexthop %s event to clients", bufn, bufp,
|
||||||
|
rib ? "reachable" : "unreachable");
|
||||||
|
}
|
||||||
|
copy_state(rnh, rib);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
|
||||||
|
send_client(rnh, client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client)
|
||||||
|
{
|
||||||
|
struct route_table *ntable;
|
||||||
|
struct route_node *nrn;
|
||||||
|
struct rnh *rnh;
|
||||||
|
|
||||||
|
ntable = lookup_rnh_table(vrfid, family);
|
||||||
|
if (!ntable)
|
||||||
|
{
|
||||||
|
zlog_debug("dispatch_rnh_table: rnh table not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
|
||||||
|
{
|
||||||
|
if (!nrn->info)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rnh = nrn->info;
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char bufn[INET6_ADDRSTRLEN];
|
||||||
|
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
|
||||||
|
zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn,
|
||||||
|
rnh->state ? "reachable" : "unreachable",
|
||||||
|
zebra_route_string(client->proto));
|
||||||
|
}
|
||||||
|
send_client(rnh, client);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zebra_print_rnh_table (int vrfid, int af, struct vty *vty)
|
||||||
|
{
|
||||||
|
struct route_table *table;
|
||||||
|
struct route_node *rn;
|
||||||
|
|
||||||
|
table = lookup_rnh_table(vrfid, af);
|
||||||
|
if (!table)
|
||||||
|
{
|
||||||
|
zlog_debug("print_rnhs: rnh table not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (rn = route_top(table); rn; rn = route_next(rn))
|
||||||
|
if (rn->info)
|
||||||
|
print_rnh(rn, vty);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client)
|
||||||
|
{
|
||||||
|
struct route_table *ntable;
|
||||||
|
struct route_node *nrn;
|
||||||
|
struct rnh *rnh;
|
||||||
|
|
||||||
|
ntable = lookup_rnh_table(vrfid, family);
|
||||||
|
if (!ntable)
|
||||||
|
{
|
||||||
|
zlog_debug("cleanup_rnh_client: rnh table not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
|
||||||
|
{
|
||||||
|
if (!nrn->info)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rnh = nrn->info;
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
{
|
||||||
|
char bufn[INET6_ADDRSTRLEN];
|
||||||
|
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
|
||||||
|
zlog_debug("rnh %s - cleaning state for client %s", bufn,
|
||||||
|
zebra_route_string(client->proto));
|
||||||
|
}
|
||||||
|
zebra_remove_rnh_client(rnh, client);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free_state - free up the rib structure associated with the rnh.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
free_state (struct rib *rib)
|
||||||
|
{
|
||||||
|
struct nexthop *nexthop, *next;
|
||||||
|
|
||||||
|
if (!rib)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* free RIB and nexthops */
|
||||||
|
for (nexthop = rib->nexthop; nexthop; nexthop = next)
|
||||||
|
{
|
||||||
|
next = nexthop->next;
|
||||||
|
nexthop_free (nexthop);
|
||||||
|
}
|
||||||
|
XFREE (MTYPE_RIB, rib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copy_nexthop - copy a nexthop to the rib structure.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
copy_nexthop (struct rib *state, struct nexthop *nh)
|
||||||
|
{
|
||||||
|
struct nexthop *nexthop;
|
||||||
|
|
||||||
|
nexthop = nexthop_new();
|
||||||
|
nexthop->flags = nh->flags;
|
||||||
|
nexthop->type = nh->type;
|
||||||
|
nexthop->ifindex = nh->ifindex;
|
||||||
|
if (nh->ifname)
|
||||||
|
nexthop->ifname = XSTRDUP(0, nh->ifname);
|
||||||
|
memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
|
||||||
|
memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
|
||||||
|
|
||||||
|
nexthop_add(state, nexthop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copy_state (struct rnh *rnh, struct rib *rib)
|
||||||
|
{
|
||||||
|
struct rib *state;
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
if (rnh->state)
|
||||||
|
{
|
||||||
|
free_state(rnh->state);
|
||||||
|
rnh->state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rib)
|
||||||
|
return;
|
||||||
|
|
||||||
|
state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
|
||||||
|
state->type = rib->type;
|
||||||
|
state->metric = rib->metric;
|
||||||
|
|
||||||
|
for (nh = rib->nexthop; nh; nh = nh->next)
|
||||||
|
copy_nexthop(state, nh);
|
||||||
|
rnh->state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_state (struct rib *r1, struct rib *r2)
|
||||||
|
{
|
||||||
|
struct nexthop *nh1;
|
||||||
|
struct nexthop *nh2;
|
||||||
|
u_char found_nh = 0;
|
||||||
|
|
||||||
|
if (!r1 && !r2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((!r1 && r2) || (r1 && !r2))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (r1->metric != r2->metric)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (r1->nexthop_num != r2->nexthop_num)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* We need to verify that the nexthops for r1 match the nexthops for r2.
|
||||||
|
* Since it is possible for a rib entry to have the same nexthop multiple
|
||||||
|
* times (Example: [a,a]) we need to keep track of which r2 nexthops we have
|
||||||
|
* already used as a match against a r1 nexthop. We track this
|
||||||
|
* via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you
|
||||||
|
* are finished.
|
||||||
|
*
|
||||||
|
* TRUE: r1 [a,b], r2 [a,b]
|
||||||
|
* TRUE: r1 [a,b], r2 [b,a]
|
||||||
|
* FALSE: r1 [a,b], r2 [a,c]
|
||||||
|
* FALSE: r1 [a,a], r2 [a,b]
|
||||||
|
*/
|
||||||
|
for (nh1 = r1->nexthop; nh1; nh1 = nh1->next)
|
||||||
|
{
|
||||||
|
found_nh = 0;
|
||||||
|
for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
|
||||||
|
{
|
||||||
|
if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nexthop_same_no_recurse(nh1, nh2))
|
||||||
|
{
|
||||||
|
SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
|
||||||
|
found_nh = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_nh)
|
||||||
|
{
|
||||||
|
for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
|
||||||
|
if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
|
||||||
|
UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
|
||||||
|
if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
|
||||||
|
UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
send_client (struct rnh *rnh, struct zserv *client)
|
||||||
|
{
|
||||||
|
struct stream *s;
|
||||||
|
struct rib *rib;
|
||||||
|
unsigned long nump;
|
||||||
|
u_char num;
|
||||||
|
struct nexthop *nexthop;
|
||||||
|
struct route_node *rn;
|
||||||
|
|
||||||
|
rn = rnh->node;
|
||||||
|
rib = rnh->state;
|
||||||
|
|
||||||
|
/* Get output stream. */
|
||||||
|
s = client->obuf;
|
||||||
|
stream_reset (s);
|
||||||
|
|
||||||
|
zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE);
|
||||||
|
|
||||||
|
stream_putw(s, rn->p.family);
|
||||||
|
stream_put_prefix (s, &rn->p);
|
||||||
|
|
||||||
|
if (rib)
|
||||||
|
{
|
||||||
|
stream_putl (s, rib->metric);
|
||||||
|
num = 0;
|
||||||
|
nump = stream_get_endp(s);
|
||||||
|
stream_putc (s, 0);
|
||||||
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
||||||
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
|
{
|
||||||
|
stream_putc (s, nexthop->type);
|
||||||
|
switch (nexthop->type)
|
||||||
|
{
|
||||||
|
case ZEBRA_NEXTHOP_IPV4:
|
||||||
|
stream_put_in_addr (s, &nexthop->gate.ipv4);
|
||||||
|
break;
|
||||||
|
case ZEBRA_NEXTHOP_IFINDEX:
|
||||||
|
case ZEBRA_NEXTHOP_IFNAME:
|
||||||
|
stream_putl (s, nexthop->ifindex);
|
||||||
|
break;
|
||||||
|
case ZEBRA_NEXTHOP_IPV4_IFINDEX:
|
||||||
|
case ZEBRA_NEXTHOP_IPV4_IFNAME:
|
||||||
|
stream_put_in_addr (s, &nexthop->gate.ipv4);
|
||||||
|
stream_putl (s, nexthop->ifindex);
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case ZEBRA_NEXTHOP_IPV6:
|
||||||
|
stream_put (s, &nexthop->gate.ipv6, 16);
|
||||||
|
break;
|
||||||
|
case ZEBRA_NEXTHOP_IPV6_IFINDEX:
|
||||||
|
case ZEBRA_NEXTHOP_IPV6_IFNAME:
|
||||||
|
stream_put (s, &nexthop->gate.ipv6, 16);
|
||||||
|
stream_putl (s, nexthop->ifindex);
|
||||||
|
break;
|
||||||
|
#endif /* HAVE_IPV6 */
|
||||||
|
default:
|
||||||
|
/* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
stream_putc_at (s, nump, num);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream_putl (s, 0);
|
||||||
|
stream_putc (s, 0);
|
||||||
|
}
|
||||||
|
stream_putw_at (s, 0, stream_get_endp (s));
|
||||||
|
return zebra_server_send_message(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_nh (struct nexthop *nexthop, struct vty *vty)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
|
switch (nexthop->type)
|
||||||
|
{
|
||||||
|
case NEXTHOP_TYPE_IPV4:
|
||||||
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
|
vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
|
||||||
|
if (nexthop->ifindex)
|
||||||
|
vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
|
||||||
|
break;
|
||||||
|
case NEXTHOP_TYPE_IPV6:
|
||||||
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||||
|
case NEXTHOP_TYPE_IPV6_IFNAME:
|
||||||
|
vty_out (vty, " %s",
|
||||||
|
inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
||||||
|
vty_out (vty, ", %s", nexthop->ifname);
|
||||||
|
else if (nexthop->ifindex)
|
||||||
|
vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
|
||||||
|
break;
|
||||||
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
|
vty_out (vty, " is directly connected, %s",
|
||||||
|
ifindex2ifname (nexthop->ifindex));
|
||||||
|
break;
|
||||||
|
case NEXTHOP_TYPE_IFNAME:
|
||||||
|
vty_out (vty, " is directly connected, %s", nexthop->ifname);
|
||||||
|
break;
|
||||||
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
|
vty_out (vty, " is directly connected, Null0");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vty_out(vty, "%s", VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_rnh (struct route_node *rn, struct vty *vty)
|
||||||
|
{
|
||||||
|
struct rnh *rnh;
|
||||||
|
struct nexthop *nexthop;
|
||||||
|
struct listnode *node;
|
||||||
|
struct zserv *client;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
|
rnh = rn->info;
|
||||||
|
vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
|
||||||
|
VTY_NEWLINE);
|
||||||
|
if (rnh->state)
|
||||||
|
{
|
||||||
|
vty_out(vty, " resolved via %s%s",
|
||||||
|
zebra_route_string(rnh->state->type), VTY_NEWLINE);
|
||||||
|
for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
|
||||||
|
print_nh(nexthop, vty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vty_out(vty, " unresolved%s", VTY_NEWLINE);
|
||||||
|
|
||||||
|
vty_out(vty, " Client list:");
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
|
||||||
|
vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto),
|
||||||
|
client->sock);
|
||||||
|
vty_out(vty, "%s", VTY_NEWLINE);
|
||||||
|
}
|
48
zebra/zebra_rnh.h
Normal file
48
zebra/zebra_rnh.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Zebra next hop tracking header
|
||||||
|
* 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 _ZEBRA_RNH_H
|
||||||
|
#define _ZEBRA_RNH_H
|
||||||
|
|
||||||
|
#include "prefix.h"
|
||||||
|
#include "vty.h"
|
||||||
|
|
||||||
|
/* Nexthop structure. */
|
||||||
|
struct rnh
|
||||||
|
{
|
||||||
|
u_char flags;
|
||||||
|
struct rib *state;
|
||||||
|
struct list *client_list;
|
||||||
|
struct route_node *node;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct rnh *zebra_add_rnh(struct prefix *p, u_int32_t vrfid);
|
||||||
|
extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid);
|
||||||
|
extern void zebra_delete_rnh(struct rnh *rnh);
|
||||||
|
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client);
|
||||||
|
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
|
||||||
|
extern int zebra_evaluate_rnh_table(int vrfid, int family);
|
||||||
|
extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl);
|
||||||
|
extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty);
|
||||||
|
extern char *rnh_str(struct rnh *rnh, char *buf, int size);
|
||||||
|
extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client);
|
||||||
|
#endif /*_ZEBRA_RNH_H */
|
10
zebra/zebra_rnh_null.c
Normal file
10
zebra/zebra_rnh_null.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <zebra.h>
|
||||||
|
#include "zebra/rib.h"
|
||||||
|
#include "zebra/zserv.h"
|
||||||
|
#include "zebra/zebra_rnh.h"
|
||||||
|
|
||||||
|
int zebra_evaluate_rnh_table (int vrfid, int family)
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
void zebra_print_rnh_table (int vrfid, int family, struct vty *vty)
|
||||||
|
{}
|
@ -28,6 +28,7 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "plist.h"
|
#include "plist.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "zebra/zserv.h"
|
#include "zebra/zserv.h"
|
||||||
|
|
||||||
|
@ -27,8 +27,10 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "rib.h"
|
#include "rib.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "zebra/zserv.h"
|
#include "zebra/zserv.h"
|
||||||
|
#include "zebra/zebra_rnh.h"
|
||||||
|
|
||||||
/* General fucntion for static route. */
|
/* General fucntion for static route. */
|
||||||
static int
|
static int
|
||||||
@ -811,6 +813,28 @@ DEFUN (show_ip_route,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (show_ip_nht,
|
||||||
|
show_ip_nht_cmd,
|
||||||
|
"show ip nht",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
"IP nexthop tracking table\n")
|
||||||
|
{
|
||||||
|
zebra_print_rnh_table(0, AF_INET, vty);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (show_ipv6_nht,
|
||||||
|
show_ipv6_nht_cmd,
|
||||||
|
"show ipv6 nht",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
"IPv6 nexthop tracking table\n")
|
||||||
|
{
|
||||||
|
zebra_print_rnh_table(0, AF_INET6, vty);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (show_ip_route_prefix_longer,
|
DEFUN (show_ip_route_prefix_longer,
|
||||||
show_ip_route_prefix_longer_cmd,
|
show_ip_route_prefix_longer_cmd,
|
||||||
"show ip route A.B.C.D/M longer-prefixes",
|
"show ip route A.B.C.D/M longer-prefixes",
|
||||||
@ -2210,6 +2234,8 @@ zebra_vty_init (void)
|
|||||||
install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd);
|
install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd);
|
||||||
|
|
||||||
install_element (VIEW_NODE, &show_ip_route_cmd);
|
install_element (VIEW_NODE, &show_ip_route_cmd);
|
||||||
|
install_element (VIEW_NODE, &show_ip_nht_cmd);
|
||||||
|
install_element (VIEW_NODE, &show_ipv6_nht_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_route_addr_cmd);
|
install_element (VIEW_NODE, &show_ip_route_addr_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
|
install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
|
install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
|
||||||
@ -2218,6 +2244,8 @@ zebra_vty_init (void)
|
|||||||
install_element (VIEW_NODE, &show_ip_route_summary_cmd);
|
install_element (VIEW_NODE, &show_ip_route_summary_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd);
|
install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd);
|
||||||
install_element (ENABLE_NODE, &show_ip_route_cmd);
|
install_element (ENABLE_NODE, &show_ip_route_cmd);
|
||||||
|
install_element (ENABLE_NODE, &show_ip_nht_cmd);
|
||||||
|
install_element (ENABLE_NODE, &show_ipv6_nht_cmd);
|
||||||
install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
|
install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
|
||||||
install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
|
install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
|
||||||
install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
|
install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
|
||||||
|
@ -36,12 +36,14 @@
|
|||||||
#include "privs.h"
|
#include "privs.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#include "nexthop.h"
|
||||||
|
|
||||||
#include "zebra/zserv.h"
|
#include "zebra/zserv.h"
|
||||||
#include "zebra/router-id.h"
|
#include "zebra/router-id.h"
|
||||||
#include "zebra/redistribute.h"
|
#include "zebra/redistribute.h"
|
||||||
#include "zebra/debug.h"
|
#include "zebra/debug.h"
|
||||||
#include "zebra/ipforward.h"
|
#include "zebra/ipforward.h"
|
||||||
|
#include "zebra/zebra_rnh.h"
|
||||||
|
|
||||||
/* Event list of zebra. */
|
/* Event list of zebra. */
|
||||||
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
|
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
|
||||||
@ -101,7 +103,7 @@ zserv_flush_data(struct thread *thread)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
zebra_server_send_message(struct zserv *client)
|
zebra_server_send_message(struct zserv *client)
|
||||||
{
|
{
|
||||||
if (client->t_suicide)
|
if (client->t_suicide)
|
||||||
@ -130,7 +132,7 @@ zebra_server_send_message(struct zserv *client)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
zserv_create_header (struct stream *s, uint16_t cmd)
|
zserv_create_header (struct stream *s, uint16_t cmd)
|
||||||
{
|
{
|
||||||
/* length placeholder, caller can update */
|
/* length placeholder, caller can update */
|
||||||
@ -599,6 +601,65 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
|
|||||||
return zebra_server_send_message(client);
|
return zebra_server_send_message(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Nexthop register */
|
||||||
|
static int
|
||||||
|
zserv_nexthop_register (struct zserv *client, int sock, u_short length)
|
||||||
|
{
|
||||||
|
struct rnh *rnh;
|
||||||
|
struct stream *s;
|
||||||
|
struct prefix p;
|
||||||
|
u_short l = 0;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
zlog_debug("nexthop_register msg from client %s: length=%d\n",
|
||||||
|
zebra_route_string(client->proto), length);
|
||||||
|
|
||||||
|
s = client->ibuf;
|
||||||
|
|
||||||
|
while (l < length)
|
||||||
|
{
|
||||||
|
p.family = stream_getw(s);
|
||||||
|
p.prefixlen = stream_getc(s);
|
||||||
|
l += 3;
|
||||||
|
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
|
||||||
|
l += PSIZE(p.prefixlen);
|
||||||
|
rnh = zebra_add_rnh(&p, 0);
|
||||||
|
zebra_add_rnh_client(rnh, client);
|
||||||
|
}
|
||||||
|
zebra_evaluate_rnh_table(0, AF_INET);
|
||||||
|
zebra_evaluate_rnh_table(0, AF_INET6);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nexthop register */
|
||||||
|
static int
|
||||||
|
zserv_nexthop_unregister (struct zserv *client, int sock, u_short length)
|
||||||
|
{
|
||||||
|
struct rnh *rnh;
|
||||||
|
struct stream *s;
|
||||||
|
struct prefix p;
|
||||||
|
u_short l = 0;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
|
zlog_debug("nexthop_unregister msg from client %s: length=%d\n",
|
||||||
|
zebra_route_string(client->proto), length);
|
||||||
|
|
||||||
|
s = client->ibuf;
|
||||||
|
|
||||||
|
while (l < length)
|
||||||
|
{
|
||||||
|
p.family = stream_getw(s);
|
||||||
|
p.prefixlen = stream_getc(s);
|
||||||
|
l += 3;
|
||||||
|
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
|
||||||
|
l += PSIZE(p.prefixlen);
|
||||||
|
rnh = zebra_lookup_rnh(&p, 0);
|
||||||
|
if (rnh)
|
||||||
|
zebra_remove_rnh_client(rnh, client);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
|
zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
|
||||||
{
|
{
|
||||||
@ -1171,6 +1232,7 @@ zread_hello (struct zserv *client)
|
|||||||
client->sock);
|
client->sock);
|
||||||
|
|
||||||
route_type_oaths[proto] = client->sock;
|
route_type_oaths[proto] = client->sock;
|
||||||
|
client->proto = proto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1196,6 +1258,9 @@ zebra_score_rib (int client_sock)
|
|||||||
static void
|
static void
|
||||||
zebra_client_close (struct zserv *client)
|
zebra_client_close (struct zserv *client)
|
||||||
{
|
{
|
||||||
|
zebra_cleanup_rnh_client(0, AF_INET, client);
|
||||||
|
zebra_cleanup_rnh_client(0, AF_INET6, client);
|
||||||
|
|
||||||
/* Close file descriptor. */
|
/* Close file descriptor. */
|
||||||
if (client->sock)
|
if (client->sock)
|
||||||
{
|
{
|
||||||
@ -1408,6 +1473,12 @@ zebra_client_read (struct thread *thread)
|
|||||||
case ZEBRA_HELLO:
|
case ZEBRA_HELLO:
|
||||||
zread_hello (client);
|
zread_hello (client);
|
||||||
break;
|
break;
|
||||||
|
case ZEBRA_NEXTHOP_REGISTER:
|
||||||
|
zserv_nexthop_register(client, sock, length);
|
||||||
|
break;
|
||||||
|
case ZEBRA_NEXTHOP_UNREGISTER:
|
||||||
|
zserv_nexthop_unregister(client, sock, length);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
zlog_info ("Zebra received unknown command %d", command);
|
zlog_info ("Zebra received unknown command %d", command);
|
||||||
break;
|
break;
|
||||||
@ -1681,8 +1752,10 @@ DEFUN (show_zebra_client,
|
|||||||
struct zserv *client;
|
struct zserv *client;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
|
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
|
||||||
vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE);
|
vty_out (vty, "Client %s fd %d%s",
|
||||||
|
zebra_route_string(client->proto), client->sock,
|
||||||
|
VTY_NEWLINE);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,9 @@ struct zserv
|
|||||||
|
|
||||||
/* Router-id information. */
|
/* Router-id information. */
|
||||||
u_char ridinfo;
|
u_char ridinfo;
|
||||||
|
|
||||||
|
/* client's protocol */
|
||||||
|
u_char proto;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Zebra instance */
|
/* Zebra instance */
|
||||||
@ -110,4 +113,7 @@ extern int zsend_router_id_update(struct zserv *, struct prefix *);
|
|||||||
|
|
||||||
extern pid_t pid;
|
extern pid_t pid;
|
||||||
|
|
||||||
|
extern void zserv_create_header(struct stream *s, uint16_t cmd);
|
||||||
|
extern int zebra_server_send_message(struct zserv *client);
|
||||||
|
|
||||||
#endif /* _ZEBRA_ZEBRA_H */
|
#endif /* _ZEBRA_ZEBRA_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user