bgpd-nht-import-check-fix.patch

BGP: Fix network import check use with NHT instead of scanner

When next hop tracking was implemented and the bgp scanner was eliminated,
the "network import-check" command got broken. This patch fixes that
issue. NHT is used to not just track nexthops, but also the static routes
that are announced as part of BGP's network command. The routes are
registered only when import-check is enabled. To optimize performance,
we register static routes only when import-check is enabled.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2015-05-19 18:04:20 -07:00
parent 5b6dc0dddc
commit 078430f609
22 changed files with 612 additions and 237 deletions

View File

@ -48,11 +48,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Route table for next-hop lookup cache. */
struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
static struct bgp_table *cache1_table[AFI_MAX];
/* Route table for connected route. */
static struct bgp_table *bgp_connected_table[AFI_MAX];
/* Route table for import-check */
struct bgp_table *bgp_import_check_table[AFI_MAX];
char *
bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size)
@ -571,15 +572,14 @@ DEFUN (show_ip_bgp_nexthop_detail,
void
bgp_scan_init (void)
{
cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP];
bgp_nexthop_cache_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
bgp_import_check_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
#ifdef HAVE_IPV6
cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6];
bgp_nexthop_cache_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
bgp_import_check_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
#endif /* HAVE_IPV6 */
}
@ -599,20 +599,26 @@ bgp_scan_finish (void)
/* Only the current one needs to be reset. */
bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]);
bgp_table_unlock (cache1_table[AFI_IP]);
cache1_table[AFI_IP] = NULL;
bgp_table_unlock (bgp_nexthop_cache_table[AFI_IP]);
bgp_nexthop_cache_table[AFI_IP] = NULL;
bgp_table_unlock (bgp_connected_table[AFI_IP]);
bgp_connected_table[AFI_IP] = NULL;
bgp_table_unlock (bgp_import_check_table[AFI_IP]);
bgp_import_check_table[AFI_IP] = NULL;
#ifdef HAVE_IPV6
/* Only the current one needs to be reset. */
bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]);
bgp_table_unlock (cache1_table[AFI_IP6]);
cache1_table[AFI_IP6] = NULL;
bgp_table_unlock (bgp_nexthop_cache_table[AFI_IP6]);
bgp_nexthop_cache_table[AFI_IP6] = NULL;
bgp_table_unlock (bgp_connected_table[AFI_IP6]);
bgp_connected_table[AFI_IP6] = NULL;
bgp_table_unlock (bgp_import_check_table[AFI_IP6]);
bgp_import_check_table[AFI_IP6] = NULL;
#endif /* HAVE_IPV6 */
}

View File

@ -41,6 +41,8 @@ struct bgp_nexthop_cache
#define BGP_NEXTHOP_REGISTERED (1 << 1)
#define BGP_NEXTHOP_CONNECTED (1 << 2)
#define BGP_NEXTHOP_PEER_NOTIFIED (1 << 3)
#define BGP_STATIC_ROUTE (1 << 4)
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
u_int16_t change_flags;

View File

@ -41,9 +41,12 @@
extern struct zclient *zclient;
extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
extern struct bgp_table *bgp_import_check_table[AFI_MAX];
static void register_nexthop(struct bgp_nexthop_cache *bnc);
static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
int is_bgp_static_route);
static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
int is_bgp_static_route);
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,
@ -81,7 +84,7 @@ bgp_unlink_nexthop (struct bgp_info *path)
zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
bnc_str(bnc, buf, INET6_ADDRSTRLEN));
}
unregister_nexthop(bnc);
unregister_zebra_rnh(bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
bnc->node->info = NULL;
bgp_unlock_node(bnc->node);
bnc_free(bnc);
@ -95,12 +98,15 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
struct bgp_node *rn;
struct bgp_nexthop_cache *bnc;
struct prefix p;
int is_bgp_static_route = 0;
if (ri)
{
/* This will return TRUE if the global IPv6 NH is a link local addr */
if (make_prefix(afi, ri, &p) < 0)
return 1;
is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
(ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
}
else if (peer)
{
@ -133,7 +139,10 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
else
return 0;
rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
if (is_bgp_static_route)
rn = bgp_node_get (bgp_import_check_table[afi], &p);
else
rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
if (!rn->info)
{
@ -142,13 +151,11 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
bnc->node = rn;
bnc->bgp = bgp;
bgp_lock_node(rn);
if (connected)
SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
if (BGP_DEBUG(nht, NHT))
{
char buf[INET6_ADDRSTRLEN];
zlog_debug("Allocated bnc %s peer %p",
zlog_debug("Allocated bnc %s peer %p",
bnc_str(bnc, buf, INET6_ADDRSTRLEN), peer);
}
}
@ -156,8 +163,41 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
bnc = rn->info;
bgp_unlock_node (rn);
if (is_bgp_static_route)
{
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
/* If we're toggling the type, re-register */
if ((bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) &&
!CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
{
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
}
else if ((!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) &&
CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
{
UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
}
}
else if (connected && ! CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
{
SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
}
else if (!connected && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
{
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
}
if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
register_nexthop(bnc);
register_zebra_rnh(bnc, is_bgp_static_route);
if (ri)
{
@ -231,7 +271,7 @@ bgp_delete_connected_nexthop (afi_t afi, struct peer *peer)
if (BGP_DEBUG(nht, NHT))
zlog_debug("Freeing connected NHT node %p for peer %s",
bnc, peer->host);
unregister_nexthop(bnc);
unregister_zebra_rnh(bnc, 0);
bnc->node->info = NULL;
bgp_unlock_node(bnc->node);
bnc_free(bnc);
@ -239,7 +279,7 @@ bgp_delete_connected_nexthop (afi_t afi, struct peer *peer)
}
void
bgp_parse_nexthop_update (void)
bgp_parse_nexthop_update (int command)
{
struct stream *s;
struct bgp_node *rn;
@ -270,7 +310,11 @@ bgp_parse_nexthop_update (void)
break;
}
rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
if (command == ZEBRA_NEXTHOP_UPDATE)
rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
rn = bgp_node_lookup(bgp_import_check_table[family2afi(p.family)], &p);
if (!rn || !rn->info)
{
if (BGP_DEBUG(nht, NHT))
@ -398,13 +442,25 @@ bgp_parse_nexthop_update (void)
static int
make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
{
int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP) &&
(ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
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;
if (is_bgp_static)
{
p->u.prefix4 = ri->net->p.u.prefix4;
p->prefixlen = ri->net->p.prefixlen;
}
else
{
p->u.prefix4 = ri->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
}
break;
#ifdef HAVE_IPV6
case AFI_IP6:
@ -414,8 +470,17 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
return -1;
p->family = AF_INET6;
p->prefixlen = IPV6_MAX_BITLEN;
p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
if (is_bgp_static)
{
p->u.prefix6 = ri->net->p.u.prefix6;
p->prefixlen = ri->net->p.prefixlen;
}
else
{
p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
p->prefixlen = IPV6_MAX_BITLEN;
}
break;
#endif
default:
@ -430,16 +495,16 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
}
/**
* sendmsg_nexthop -- Format and send a nexthop register/Unregister
* sendmsg_zebra_rnh -- 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
* int command -- command to send to zebra
* RETURNS:
* void.
*/
static void
sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
sendmsg_zebra_rnh (struct bgp_nexthop_cache *bnc, int command)
{
struct stream *s;
struct prefix *p;
@ -457,7 +522,8 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
s = zclient->obuf;
stream_reset (s);
zclient_create_header (s, command);
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) ||
CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
stream_putc(s, 1);
else
stream_putc(s, 0);
@ -484,45 +550,53 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
if (ret < 0)
zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
if (command == ZEBRA_NEXTHOP_REGISTER)
if ((command == ZEBRA_NEXTHOP_REGISTER) ||
(command == ZEBRA_IMPORT_ROUTE_REGISTER))
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
else if (command == ZEBRA_NEXTHOP_UNREGISTER)
else if ((command == ZEBRA_NEXTHOP_UNREGISTER) ||
(command == ZEBRA_IMPORT_ROUTE_UNREGISTER))
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
return;
}
/**
* register_nexthop - register a nexthop with Zebra for notification
* when the route to the nexthop changes.
* register_zebra_rnh - register a NH/route with Zebra for notification
* when the route or the route to the nexthop changes.
* ARGUMENTS:
* struct bgp_nexthop_cache *bnc -- the nexthop structure.
* struct bgp_nexthop_cache *bnc
* RETURNS:
* void.
*/
static void
register_nexthop (struct bgp_nexthop_cache *bnc)
register_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route)
{
/* Check if we have already registered */
if (bnc->flags & BGP_NEXTHOP_REGISTERED)
return;
sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
if (is_bgp_import_route)
sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER);
else
sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER);
}
/**
* unregister_nexthop -- Unregister the nexthop from Zebra.
* unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
* ARGUMENTS:
* struct bgp_nexthop_cache *bnc -- the nexthop structure.
* struct bgp_nexthop_cache *bnc
* RETURNS:
* void.
*/
static void
unregister_nexthop (struct bgp_nexthop_cache *bnc)
unregister_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route)
{
/* Check if we have already registered */
if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
return;
sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
if (is_bgp_import_route)
sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER);
else
sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER);
}
/**
@ -544,7 +618,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
LIST_FOREACH(path, &(bnc->paths), nh_thread)
{
if (!(path->type == ZEBRA_ROUTE_BGP &&
path->sub_type == BGP_ROUTE_NORMAL))
(path->sub_type == BGP_ROUTE_NORMAL) ||
(path->sub_type == BGP_ROUTE_STATIC)))
continue;
rn = path->net;

View File

@ -25,7 +25,7 @@
/**
* bgp_parse_nexthop_update() - parse a nexthop update message from Zebra.
*/
extern void bgp_parse_nexthop_update();
extern void bgp_parse_nexthop_update(int command);
/**
* bgp_find_nexthop() - lookup the nexthop cache table for the bnc object

View File

@ -4461,7 +4461,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
if (ri)
{
if (attrhash_cmp (ri->attr, attr_new) &&
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) &&
!bgp_flag_check(bgp, BGP_FLAG_FORCE_STATIC_PROCESS))
{
bgp_unlock_node (rn);
bgp_attr_unintern (&attr_new);
@ -4491,13 +4492,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
if (BGP_DEBUG(nht, NHT))
{
char buf1[INET6_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
buf1, INET6_ADDRSTRLEN);
zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
inet_ntop (p->family, &p->u.prefix, buf1,
INET6_ADDRSTRLEN);
zlog_debug("%s(%s): Route not in table, not advertising",
__FUNCTION__, buf1);
}
bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
}
}
else
{
/* Delete the NHT structure if any, if we're toggling between
* enabling/disabling import check. We deregister the route
* from NHT to avoid overloading NHT and the process interaction
*/
bgp_unlink_nexthop(ri);
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
}
/* Process change. */
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
@ -4520,15 +4531,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
if (BGP_DEBUG(nht, NHT))
{
char buf1[INET6_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
buf1, INET6_ADDRSTRLEN);
zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
inet_ntop(p->family, &p->u.prefix, buf1,
INET6_ADDRSTRLEN);
zlog_debug("%s(%s): Route not in table, not advertising", __FUNCTION__,
buf1);
}
bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
}
}
else
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
{
/* Delete the NHT structure if any, if we're toggling between
* enabling/disabling import check. We deregister the route
* from NHT to avoid overloading NHT and the process interaction
*/
bgp_unlink_nexthop(new);
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
}
/* Register new BGP information. */
bgp_info_add (rn, new);
@ -4608,7 +4627,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
if (ri)
{
if (attrhash_cmp (ri->attr, attr_new) &&
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) &&
!bgp_flag_check(bgp, BGP_FLAG_FORCE_STATIC_PROCESS))
{
bgp_unlock_node (rn);
bgp_attr_unintern (&attr_new);
@ -4640,13 +4660,23 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
if (BGP_DEBUG(nht, NHT))
{
char buf1[INET6_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
buf1, INET6_ADDRSTRLEN);
zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
inet_ntop(p->family, &p->u.prefix, buf1,
INET6_ADDRSTRLEN);
zlog_debug("%s(%s): Route not in table, not advertising",
__FUNCTION__, buf1);
}
bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
}
}
else
{
/* Delete the NHT structure if any, if we're toggling between
* enabling/disabling import check. We deregister the route
* from NHT to avoid overloading NHT and the process interaction
*/
bgp_unlink_nexthop(ri);
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
}
/* Process change. */
bgp_aggregate_increment (bgp, p, ri, afi, safi);
bgp_process (bgp, rn, afi, safi);
@ -4670,15 +4700,24 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
if (BGP_DEBUG(nht, NHT))
{
char buf1[INET6_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1,
inet_ntop(p->family, &p->u.prefix, buf1,
INET6_ADDRSTRLEN);
zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
zlog_debug("%s(%s): Route not in table, not advertising",
__FUNCTION__, buf1);
}
bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
}
}
else
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
{
/* Delete the NHT structure if any, if we're toggling between
* enabling/disabling import check. We deregister the route
* from NHT to avoid overloading NHT and the process interaction
*/
bgp_unlink_nexthop(new);
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
}
/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
@ -5005,6 +5044,29 @@ bgp_static_delete (struct bgp *bgp)
}
}
void
bgp_static_redo_import_check (struct bgp *bgp)
{
afi_t afi;
safi_t safi;
struct bgp_node *rn;
struct bgp_node *rm;
struct bgp_table *table;
struct bgp_static *bgp_static;
/* Use this flag to force reprocessing of the route */
bgp_flag_set(bgp, BGP_FLAG_FORCE_STATIC_PROCESS);
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
if (rn->info != NULL)
{
bgp_static = rn->info;
bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
}
bgp_flag_unset(bgp, BGP_FLAG_FORCE_STATIC_PROCESS);
}
int
bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str,
const char *tag_str)

View File

@ -250,6 +250,7 @@ extern void bgp_redistribute_delete (struct prefix *, u_char, u_short);
extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int, u_short);
extern void bgp_static_delete (struct bgp *);
extern void bgp_static_redo_import_check (struct bgp *);
extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *,
afi_t, safi_t);
extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t);

View File

@ -2114,21 +2114,45 @@ DEFUN (bgp_default_ipv4_unicast,
/* "bgp import-check" configuration. */
DEFUN (bgp_network_import_check,
bgp_network_import_check_cmd,
"bgp network import-check",
"bgp network import-check {exact}",
"BGP specific commands\n"
"BGP network command\n"
"Check BGP network route exists in IGP\n")
"Check BGP network route exists in IGP\n"
"Match route precisely")
{
struct bgp *bgp;
int trigger = 0;
bgp = vty->index;
bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK))
{
bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
trigger = 1;
}
if (argv[0] != NULL)
{
if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH))
{
bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH);
trigger = 1;
}
}
else if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH))
{
bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH);
trigger = 1;
}
if (trigger)
bgp_static_redo_import_check(bgp);
return CMD_SUCCESS;
}
DEFUN (no_bgp_network_import_check,
no_bgp_network_import_check_cmd,
"no bgp network import-check",
"no bgp network import-check {exact}",
NO_STR
"BGP specific commands\n"
"BGP network command\n"
@ -2137,7 +2161,12 @@ DEFUN (no_bgp_network_import_check,
struct bgp *bgp;
bgp = vty->index;
bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK);
if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK))
{
bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK);
bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH);
bgp_static_redo_import_check(bgp);
}
return CMD_SUCCESS;
}

View File

@ -119,7 +119,15 @@ static int
bgp_read_nexthop_update (int command, struct zclient *zclient,
zebra_size_t length)
{
bgp_parse_nexthop_update();
bgp_parse_nexthop_update(command);
return 0;
}
static int
bgp_read_import_check_update(int command, struct zclient *zclient,
zebra_size_t length)
{
bgp_parse_nexthop_update(command);
return 0;
}
@ -1665,6 +1673,7 @@ bgp_zebra_init (void)
zclient->ipv6_route_delete = zebra_read_ipv6;
#endif /* HAVE_IPV6 */
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
/* Interface related init. */
if_init ();

View File

@ -6408,7 +6408,9 @@ bgp_config_write (struct vty *vty)
}
/* BGP network import check. */
if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH))
vty_out (vty, " bgp network import-check exact%s", VTY_NEWLINE);
else if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
vty_out (vty, " bgp network import-check%s", VTY_NEWLINE);
/* BGP flag dampening. */

View File

@ -239,6 +239,8 @@ struct bgp
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15)
#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 16)
#define BGP_FLAG_MULTIPATH_RELAX_NO_AS_SET (1 << 17)
#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 18)
#define BGP_FLAG_IMPORT_CHECK_EXACT_MATCH (1 << 19)
/* BGP Per AF flags */
u_int16_t af_flags[AFI_MAX][SAFI_MAX];

View File

@ -835,6 +835,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE),
DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_ADD),
DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE),
DESC_ENTRY (ZEBRA_IMPORT_CHECK_UPDATE),
};
#undef DESC_ENTRY

View File

@ -134,42 +134,6 @@ redist_del_instance (struct redist_proto *red, u_short instance)
}
}
/* Initialize zebra client. Argument redist_default is unwanted
redistribute route type. */
void
zclient_init (struct zclient *zclient, int redist_default, u_short instance)
{
int afi, i;
/* Enable zebra client connection by default. */
zclient->enable = 1;
/* Set -1 to the default socket value. */
zclient->sock = -1;
/* Clear redistribution flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
memset(&zclient->redist[afi][i], 0, sizeof(struct redist_proto));
/* Set unwanted redistribute route. bgpd does not need BGP route
redistribution. */
zclient->redist_default = redist_default;
zclient->instance = instance;
/* Pending: make afi(s) an arg. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
redist_add_instance (&zclient->redist[afi][redist_default], instance);
/* Set default-information redistribute to zero. */
zclient->default_information = 0;
/* Schedule first zclient connection. */
if (zclient_debug)
zlog_debug ("zclient start scheduled");
zclient_event (ZCLIENT_SCHEDULE, zclient);
}
/* Stop zebra client services. */
void
zclient_stop (struct zclient *zclient)
@ -405,13 +369,6 @@ zclient_start (struct zclient *zclient)
int i;
afi_t afi;
if (zclient_debug)
zlog_debug ("zclient_start is called");
/* zclient is disabled. */
if (! zclient->enable)
return 0;
/* If already connected to the zebra. */
if (zclient->sock >= 0)
return 0;
@ -420,34 +377,6 @@ zclient_start (struct zclient *zclient)
if (zclient->t_connect)
return 0;
if (zclient_socket_connect(zclient) < 0)
{
if (zclient_debug)
zlog_debug ("zclient connection fail");
zclient->fail++;
zclient_event (ZCLIENT_CONNECT, zclient);
return -1;
}
if (set_nonblocking(zclient->sock) < 0)
zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock);
/* Clear fail count. */
zclient->fail = 0;
if (zclient_debug)
zlog_debug ("zclient connect success with socket [%d]", zclient->sock);
/* Create read thread. */
zclient_event (ZCLIENT_READ, zclient);
zebra_hello_send (zclient);
/* We need router-id information. */
zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD);
/* We need interface information. */
zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
/* Flush all redistribute request. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
@ -484,6 +413,73 @@ zclient_connect (struct thread *t)
return zclient_start (zclient);
}
/* Initialize zebra client. Argument redist_default is unwanted
redistribute route type. */
void
zclient_init (struct zclient *zclient, int redist_default, u_short instance)
{
int afi, i;
/* Enable zebra client connection by default. */
zclient->enable = 1;
/* Set -1 to the default socket value. */
zclient->sock = -1;
/* Clear redistribution flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
memset(&zclient->redist[afi][i], 0, sizeof(struct redist_proto));
/* Set unwanted redistribute route. bgpd does not need BGP route
redistribution. */
zclient->redist_default = redist_default;
zclient->instance = instance;
/* Pending: make afi(s) an arg. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
redist_add_instance (&zclient->redist[afi][redist_default], instance);
/* Set default-information redistribute to zero. */
zclient->default_information = 0;
if (zclient_debug)
zlog_debug ("zclient_start is called");
/* zclient is disabled. */
if (! zclient->enable)
return;
if (zclient_socket_connect(zclient) < 0)
{
if (zclient_debug)
zlog_debug ("zclient connection fail");
zclient->fail++;
zclient_event (ZCLIENT_CONNECT, zclient);
return;
}
if (set_nonblocking(zclient->sock) < 0)
zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock);
/* Clear fail count. */
zclient->fail = 0;
if (zclient_debug)
zlog_debug ("zclient connect success with socket [%d]", zclient->sock);
/* Create read thread. */
zclient_event (ZCLIENT_READ, zclient);
zebra_hello_send (zclient);
/* We need router-id information. */
zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD);
/* We need interface information. */
zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
zclient_event (ZCLIENT_SCHEDULE, zclient);
}
/*
* "xdr_encode"-like interface that allows daemon (client) to send
* a message to zebra server for a route that needs to be
@ -1212,6 +1208,12 @@ zclient_read (struct thread *thread)
if (zclient->nexthop_update)
(*zclient->nexthop_update) (command, zclient, length);
break;
case ZEBRA_IMPORT_CHECK_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd import check update\n");
if (zclient->import_check_update)
(*zclient->import_check_update) (command, zclient, length);
break;
default:
break;
}

View File

@ -93,6 +93,7 @@ struct zclient
int (*ipv6_route_add) (int, struct zclient *, uint16_t);
int (*ipv6_route_delete) (int, struct zclient *, uint16_t);
int (*nexthop_update) (int, struct zclient *, uint16_t);
int (*import_check_update) (int, struct zclient *, uint16_t);
};
/* Zebra API message flag. */

View File

@ -430,7 +430,10 @@ struct in_pktinfo
#define ZEBRA_INTERFACE_NBR_ADDRESS_ADD 27
#define ZEBRA_INTERFACE_NBR_ADDRESS_DELETE 28
#define ZEBRA_INTERFACE_BFD_DEST_DOWN 29
#define ZEBRA_MESSAGE_MAX 30
#define ZEBRA_IMPORT_ROUTE_REGISTER 30
#define ZEBRA_IMPORT_ROUTE_UNREGISTER 31
#define ZEBRA_IMPORT_CHECK_UPDATE 32
#define ZEBRA_MESSAGE_MAX 33
/* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new

View File

@ -301,6 +301,9 @@ struct vrf
/* Recursive Nexthop table */
struct route_table *rnh_table[AFI_MAX];
/* Import check table (used mostly by BGP */
struct route_table *import_check_table[AFI_MAX];
/* Routing tables off of main table for redistribute table */
struct route_table *other_table[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
};

View File

@ -123,6 +123,9 @@ vrf_alloc (const char *name)
vrf->rnh_table[AFI_IP] = route_table_init();
vrf->rnh_table[AFI_IP6] = route_table_init();
vrf->import_check_table[AFI_IP] = route_table_init();
vrf->import_check_table[AFI_IP6] = route_table_init();
return vrf;
}
@ -1753,9 +1756,11 @@ process_subq (struct list * subq, u_char qindex)
static void
meta_queue_process_complete (struct work_queue *dummy)
{
zebra_evaluate_rnh_table(0, AF_INET, 0);
zebra_evaluate_rnh(0, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL);
zebra_evaluate_rnh(0, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, NULL);
#ifdef HAVE_IPV6
zebra_evaluate_rnh_table(0, AF_INET6, 0);
zebra_evaluate_rnh(0, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL);
zebra_evaluate_rnh(0, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, NULL);
#endif /* HAVE_IPV6 */
}

View File

@ -44,37 +44,48 @@
#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; \
})
/* Default rtm_table for all clients */
extern struct zebra_t zebrad;
static void free_state(struct rib *rib, struct route_node *rn);
static void copy_state(struct rnh *rnh, struct rib *rib, struct route_node *rn);
static void copy_state(struct rnh *rnh, struct rib *rib,
struct route_node *rn);
static int compare_state(struct rib *r1, struct rib *r2);
static int send_client(struct rnh *rnh, struct zserv *client);
static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type);
static void print_rnh(struct route_node *rn, struct vty *vty);
int zebra_rnh_ip_default_route = 0;
int zebra_rnh_ipv6_default_route = 0;
char *
rnh_str (struct rnh *rnh, char *buf, int size)
static inline struct route_table *get_rnh_table(int vrfid, int family,
rnh_type_t type)
{
struct vrf *vrf;
struct route_table *t = NULL;
vrf = vrf_lookup(vrfid);
if (vrf)
switch (type)
{
case RNH_NEXTHOP_TYPE:
t = vrf->rnh_table[family2afi(family)];
break;
case RNH_IMPORT_CHECK_TYPE:
t = vrf->import_check_table[family2afi(family)];
break;
}
return t;
}
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)
zebra_add_rnh (struct prefix *p, u_int32_t vrfid, rnh_type_t type)
{
struct route_table *table;
struct route_node *rn;
@ -86,7 +97,7 @@ zebra_add_rnh (struct prefix *p, u_int32_t vrfid)
prefix2str(p, buf, INET6_ADDRSTRLEN);
zlog_debug("add rnh %s in vrf %d", buf, vrfid);
}
table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
if (!table)
{
zlog_debug("add_rnh: rnh table not found\n");
@ -114,12 +125,12 @@ zebra_add_rnh (struct prefix *p, u_int32_t vrfid)
}
struct rnh *
zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid)
zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid, rnh_type_t type)
{
struct route_table *table;
struct route_node *rn;
table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
if (!table)
return NULL;
@ -136,7 +147,7 @@ zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid)
}
void
zebra_delete_rnh (struct rnh *rnh)
zebra_delete_rnh (struct rnh *rnh, rnh_type_t type)
{
struct route_node *rn;
@ -160,7 +171,7 @@ zebra_delete_rnh (struct rnh *rnh)
}
void
zebra_add_rnh_client (struct rnh *rnh, struct zserv *client)
zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
{
if (IS_ZEBRA_DEBUG_NHT)
{
@ -172,12 +183,11 @@ zebra_add_rnh_client (struct rnh *rnh, struct zserv *client)
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)
zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
{
if (IS_ZEBRA_DEBUG_NHT)
{
@ -189,7 +199,7 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
listnode_delete(rnh->client_list, client);
if (list_isempty(rnh->client_list) &&
list_isempty(rnh->zebra_static_route_list))
zebra_delete_rnh(rnh);
zebra_delete_rnh(rnh, type);
}
void
@ -197,7 +207,7 @@ zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
{
struct rnh *rnh;
rnh = zebra_add_rnh(nh, 0);
rnh = zebra_add_rnh(nh, 0, RNH_NEXTHOP_TYPE);
if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn))
{
listnode_add(rnh->zebra_static_route_list, static_rn);
@ -209,7 +219,7 @@ zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
{
struct rnh *rnh;
rnh = zebra_lookup_rnh(nh, 0);
rnh = zebra_lookup_rnh(nh, 0, RNH_NEXTHOP_TYPE);
if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED))
return;
@ -217,7 +227,7 @@ zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
if (list_isempty(rnh->client_list) &&
list_isempty(rnh->zebra_static_route_list))
zebra_delete_rnh(rnh);
zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
}
static inline int
@ -276,12 +286,13 @@ zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn,
}
int
zebra_evaluate_rnh_table (int vrfid, int family, int force)
zebra_evaluate_rnh (int vrfid, int family, int force, rnh_type_t type,
struct prefix *p)
{
struct route_table *ptable;
struct route_table *ntable;
struct route_node *prn;
struct route_node *nrn;
struct route_node *prn = NULL;
struct route_node *nrn = NULL;
struct rnh *rnh;
struct zserv *client;
struct listnode *node;
@ -292,9 +303,10 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
char bufp[INET6_ADDRSTRLEN];
char bufs[INET6_ADDRSTRLEN];
struct route_node *static_rn;
struct nexthop *nexthop;
struct nexthop *nexthop, *tnexthop;
int recursing;
ntable = lookup_rnh_table(vrfid, family);
ntable = get_rnh_table(vrfid, family, type);
if (!ntable)
{
zlog_debug("evaluate_rnh_table: rnh table not found\n");
@ -308,17 +320,38 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
return -1;
}
for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
if (p)
nrn = route_node_lookup(ntable, p);
else
nrn = route_top (ntable);
while (nrn != NULL)
{
if (!nrn->info)
continue;
goto loopend;
rnh = nrn->info;
at_least_one = 0;
/* free stale stuff first */
if (prn)
route_unlock_node(prn);
prn = route_node_match(ptable, &nrn->p);
if (!prn || (zebra_rnh_is_default_route(&prn->p) &&
!zebra_rnh_resolve_via_default(prn->p.family)))
/* Do not resolve over default route unless allowed &&
* match route to be exact if so specified
*/
if (!prn)
rib = NULL;
else if ((type == RNH_NEXTHOP_TYPE) &&
(zebra_rnh_is_default_route(&prn->p) &&
!zebra_rnh_resolve_via_default(prn->p.family)))
rib = NULL;
else if ((type == RNH_IMPORT_CHECK_TYPE) &&
((zebra_rnh_is_default_route(&prn->p)) ||
((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) &&
!prefix_same(&nrn->p, &prn->p))))
rib = NULL;
else
{
@ -333,6 +366,9 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
if (rib->type == ZEBRA_ROUTE_CONNECT)
break;
}
else if ((type == RNH_IMPORT_CHECK_TYPE) &&
(rib->type == ZEBRA_ROUTE_BGP))
continue;
else
break;
}
@ -341,6 +377,42 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
state_changed = 0;
/* Handle import check first as its simpler */
if (type == RNH_IMPORT_CHECK_TYPE)
{
if (rib && (rnh->state == NULL))
{
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
state_changed = 1;
break;
}
}
else if (!rib && (rnh->state != NULL))
state_changed = 1;
if (compare_state(rib, rnh->state))
copy_state(rnh, rib, nrn);
if (state_changed || force)
{
if (IS_ZEBRA_DEBUG_NHT)
{
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
zlog_debug("rnh import check %s for %s, notifying clients\n",
rnh->state ? "passed" : "failed", bufn);
}
/* state changed, notify clients */
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
{
send_client(rnh, client, RNH_IMPORT_CHECK_TYPE);
}
}
goto loopend;
}
/* Ensure prefixes we're resolving over have stayed the same */
if (!prefix_same(&rnh->resolved_route, &prn->p))
{
@ -401,7 +473,7 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
at_least_one ? "":"(filtered)", bufn, bufp,
rib ? "reachable" : "unreachable");
send_client(rnh, client); /* Route-map passed */
send_client(rnh, client, RNH_NEXTHOP_TYPE); /* Route-map passed */
}
/* Now evaluate static client */
@ -482,18 +554,34 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
}
}
}
loopend:
if (p)
{
route_unlock_node(nrn);
nrn = NULL;
}
else
{
/* route_next takes care of unlocking nrn */
nrn = route_next(nrn);
}
}
if (prn)
route_unlock_node(prn);
return 1;
}
int
zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client)
zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client,
rnh_type_t type)
{
struct route_table *ntable;
struct route_node *nrn;
struct rnh *rnh;
ntable = lookup_rnh_table(vrfid, family);
ntable = get_rnh_table(vrfid, family, type);
if (!ntable)
{
zlog_debug("dispatch_rnh_table: rnh table not found\n");
@ -514,18 +602,18 @@ zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client)
rnh->state ? "reachable" : "unreachable",
zebra_route_string(client->proto));
}
send_client(rnh, client);
send_client(rnh, client, RNH_NEXTHOP_TYPE);
}
return 1;
}
void
zebra_print_rnh_table (int vrfid, int af, struct vty *vty)
zebra_print_rnh_table (int vrfid, int af, struct vty *vty, rnh_type_t type)
{
struct route_table *table;
struct route_node *rn;
table = lookup_rnh_table(vrfid, af);
table = get_rnh_table(vrfid, af, type);
if (!table)
{
zlog_debug("print_rnhs: rnh table not found\n");
@ -538,13 +626,14 @@ zebra_print_rnh_table (int vrfid, int af, struct vty *vty)
}
int
zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client)
zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client,
rnh_type_t type)
{
struct route_table *ntable;
struct route_node *nrn;
struct rnh *rnh;
ntable = lookup_rnh_table(vrfid, family);
ntable = get_rnh_table(vrfid, family, type);
if (!ntable)
{
zlog_debug("cleanup_rnh_client: rnh table not found\n");
@ -564,7 +653,7 @@ zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client)
zlog_debug("rnh %s - cleaning state for client %s", bufn,
zebra_route_string(client->proto));
}
zebra_remove_rnh_client(rnh, client);
zebra_remove_rnh_client(rnh, client, type);
}
return 1;
}
@ -631,7 +720,7 @@ compare_state (struct rib *r1, struct rib *r2)
}
static int
send_client (struct rnh *rnh, struct zserv *client)
send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
{
struct stream *s;
struct rib *rib;
@ -639,6 +728,8 @@ send_client (struct rnh *rnh, struct zserv *client)
u_char num;
struct nexthop *nexthop;
struct route_node *rn;
int cmd = (type == RNH_IMPORT_CHECK_TYPE)
? ZEBRA_IMPORT_CHECK_UPDATE : ZEBRA_NEXTHOP_UPDATE;
rn = rnh->node;
rib = rnh->state;
@ -647,11 +738,23 @@ send_client (struct rnh *rnh, struct zserv *client)
s = client->obuf;
stream_reset (s);
zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE);
zserv_create_header (s, cmd);
stream_putw(s, rn->p.family);
stream_put_prefix (s, &rn->p);
switch (rn->p.family)
{
case AF_INET:
stream_putc(s, rn->p.prefixlen);
stream_put_in_addr(s, &rn->p.u.prefix4);
break;
case AF_INET6:
stream_putc(s, rn->p.prefixlen);
stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
break;
default:
zlog_err("%s: Unknown family (%d) notification attempted\n",
__FUNCTION__, rn->p.family);
break;
}
if (rib)
{
stream_putl (s, rib->metric);
@ -704,7 +807,7 @@ send_client (struct rnh *rnh, struct zserv *client)
stream_putw_at (s, 0, stream_get_endp (s));
client->nh_last_upd_time = quagga_time(NULL);
client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
client->last_write_cmd = cmd;
return zebra_server_send_message(client);
}

View File

@ -30,8 +30,11 @@
struct rnh
{
u_char flags;
#define ZEBRA_NHT_CONNECTED 0x1
#define ZEBRA_NHT_DELETED 0x2
#define ZEBRA_NHT_EXACT_MATCH 0x4
struct rib *state;
struct prefix resolved_route;
struct list *client_list;
@ -40,19 +43,30 @@ struct rnh
int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */
};
typedef enum
{
RNH_NEXTHOP_TYPE,
RNH_IMPORT_CHECK_TYPE
} rnh_type_t;
extern int zebra_rnh_ip_default_route;
extern int zebra_rnh_ipv6_default_route;
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 struct rnh *zebra_add_rnh(struct prefix *p, u_int32_t vrfid,
rnh_type_t type);
extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid,
rnh_type_t type);
extern void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type);
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type);
extern void zebra_register_rnh_static_nh(struct prefix *, struct route_node *);
extern void zebra_deregister_rnh_static_nh(struct prefix *, struct route_node *);
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
extern int zebra_evaluate_rnh_table(int vrfid, int family, int force);
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 void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
rnh_type_t type);
extern int zebra_evaluate_rnh(int vrfid, int family, int force, rnh_type_t type,
struct prefix *p);
extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl, rnh_type_t);
extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty, rnh_type_t);
extern char *rnh_str(struct rnh *rnh, char *buf, int size);
extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client);
extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client,
rnh_type_t type);
#endif /*_ZEBRA_RNH_H */

View File

@ -6,10 +6,12 @@
int zebra_rnh_ip_default_route = 0;
int zebra_rnh_ipv6_default_route = 0;
int zebra_evaluate_rnh_table (int vrfid, int family, int force)
int zebra_evaluate_rnh (int vrfid, int family, int force, rnh_type_t type,
struct prefix *p)
{ return 0; }
void zebra_print_rnh_table (int vrfid, int family, struct vty *vty)
void zebra_print_rnh_table (int vrfid, int family, struct vty *vty,
rnh_type_t type)
{}
void zebra_register_rnh_static_nh(struct prefix *p, struct route_node *rn)

View File

@ -846,7 +846,7 @@ DEFUN (ip_protocol_nht_rmap,
}
nht_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
zebra_evaluate_rnh_table(0, AF_INET, 1);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@ -879,7 +879,7 @@ DEFUN (no_ip_protocol_nht_rmap,
{
XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
nht_rm[AFI_IP][i] = NULL;
zebra_evaluate_rnh_table(0, AF_INET, 1);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
}
return CMD_SUCCESS;
}
@ -944,7 +944,7 @@ DEFUN (ipv6_protocol_nht_rmap,
if (nht_rm[AFI_IP6][i])
XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
nht_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
zebra_evaluate_rnh_table(0, AF_INET6, 1);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@ -977,7 +977,7 @@ DEFUN (no_ipv6_protocol_nht_rmap,
{
XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
nht_rm[AFI_IP6][i] = NULL;
zebra_evaluate_rnh_table(0, AF_INET6, 1);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
}
return CMD_SUCCESS;
@ -1446,8 +1446,8 @@ zebra_route_map_update_timer (struct thread *thread)
zlog_debug("Event driven route-map update triggered");
rib_update();
zebra_evaluate_rnh_table(0, AF_INET, 1);
zebra_evaluate_rnh_table(0, AF_INET6, 1);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
return (0);
}

View File

@ -1180,7 +1180,7 @@ DEFUN (show_ip_nht,
IP_STR
"IP nexthop tracking table\n")
{
zebra_print_rnh_table(0, AF_INET, vty);
zebra_print_rnh_table(0, AF_INET, vty, RNH_NEXTHOP_TYPE);
return CMD_SUCCESS;
}
@ -1191,7 +1191,7 @@ DEFUN (show_ipv6_nht,
IP_STR
"IPv6 nexthop tracking table\n")
{
zebra_print_rnh_table(0, AF_INET6, vty);
zebra_print_rnh_table(0, AF_INET6, vty, RNH_NEXTHOP_TYPE);
return CMD_SUCCESS;
}
@ -1206,7 +1206,7 @@ DEFUN (ip_nht_default_route,
return CMD_SUCCESS;
zebra_rnh_ip_default_route = 1;
zebra_evaluate_rnh_table(0, AF_INET, 1);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@ -1222,7 +1222,7 @@ DEFUN (no_ip_nht_default_route,
return CMD_SUCCESS;
zebra_rnh_ip_default_route = 0;
zebra_evaluate_rnh_table(0, AF_INET, 1);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@ -1237,7 +1237,7 @@ DEFUN (ipv6_nht_default_route,
return CMD_SUCCESS;
zebra_rnh_ipv6_default_route = 1;
zebra_evaluate_rnh_table(0, AF_INET6, 1);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@ -1253,7 +1253,7 @@ DEFUN (no_ipv6_nht_default_route,
return CMD_SUCCESS;
zebra_rnh_ipv6_default_route = 0;
zebra_evaluate_rnh_table(0, AF_INET6, 1);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}

View File

@ -786,69 +786,114 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
/* Nexthop register */
static int
zserv_nexthop_register (struct zserv *client, int sock, u_short length)
zserv_rnh_register (struct zserv *client, int sock, u_short length,
rnh_type_t type)
{
struct rnh *rnh;
struct stream *s;
struct prefix p;
u_short l = 0;
u_char connected;
u_char flags = 0;
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug("nexthop_register msg from client %s: length=%d\n",
zebra_route_string(client->proto), length);
zlog_debug("rnh_register msg from client %s: length=%d, type=%s\n",
zebra_route_string(client->proto), length,
(type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route");
s = client->ibuf;
client->nh_reg_time = quagga_time(NULL);
while (l < length)
{
connected = stream_getc(s);
flags = stream_getc(s);
p.family = stream_getw(s);
p.prefixlen = stream_getc(s);
l += 4;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
rnh = zebra_add_rnh(&p, 0);
if (connected)
SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
if (p.family == AF_INET)
{
p.u.prefix4.s_addr = stream_get_ipv4(s);
l += IPV4_MAX_BYTELEN;
}
else if (p.family == AF_INET6)
{
stream_get(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
l += IPV6_MAX_BYTELEN;
}
else
{
zlog_err("rnh_register: Received unknown family type %d\n",
p.family);
return -1;
}
rnh = zebra_add_rnh(&p, 0, type);
if (type == RNH_NEXTHOP_TYPE)
{
if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
else if (!flags && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
}
else if (type == RNH_IMPORT_CHECK_TYPE)
{
if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH))
SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
else if (!flags && CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH))
UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
}
client->nh_reg_time = quagga_time(NULL);
zebra_add_rnh_client(rnh, client);
zebra_add_rnh_client(rnh, client, type);
/* Anything not AF_INET/INET6 has been filtered out above */
zebra_evaluate_rnh(0, p.family, 1, type, &p);
}
zebra_evaluate_rnh_table(0, AF_INET, 0);
zebra_evaluate_rnh_table(0, AF_INET6, 0);
return 0;
}
/* Nexthop register */
static int
zserv_nexthop_unregister (struct zserv *client, int sock, u_short length)
zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
rnh_type_t type)
{
struct rnh *rnh;
struct stream *s;
struct prefix p;
u_short l = 0;
u_char connected;
u_char flags;
u_char exact_match;
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug("nexthop_unregister msg from client %s: length=%d\n",
zlog_debug("rnh_unregister msg from client %s: length=%d\n",
zebra_route_string(client->proto), length);
s = client->ibuf;
while (l < length)
{
connected = stream_getc(s);
flags = stream_getc(s);
p.family = stream_getw(s);
p.prefixlen = stream_getc(s);
l += 4;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
rnh = zebra_lookup_rnh(&p, 0);
if (p.family == AF_INET)
{
p.u.prefix4.s_addr = stream_get_ipv4(s);
l += IPV4_MAX_BYTELEN;
}
else if (p.family == AF_INET6)
{
stream_get(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
l += IPV6_MAX_BYTELEN;
}
else
{
zlog_err("rnh_register: Received unknown family type %d\n",
p.family);
return -1;
}
rnh = zebra_lookup_rnh(&p, 0, type);
if (rnh)
{
client->nh_dereg_time = quagga_time(NULL);
zebra_remove_rnh_client(rnh, client);
zebra_remove_rnh_client(rnh, client, type);
}
}
return 0;
@ -1496,8 +1541,10 @@ zread_hello (struct zserv *client)
static void
zebra_client_close (struct zserv *client)
{
zebra_cleanup_rnh_client(0, AF_INET, client);
zebra_cleanup_rnh_client(0, AF_INET6, client);
zebra_cleanup_rnh_client(0, AF_INET, client, RNH_NEXTHOP_TYPE);
zebra_cleanup_rnh_client(0, AF_INET6, client, RNH_NEXTHOP_TYPE);
zebra_cleanup_rnh_client(0, AF_INET, client, RNH_IMPORT_CHECK_TYPE);
zebra_cleanup_rnh_client(0, AF_INET6, client, RNH_IMPORT_CHECK_TYPE);
/* Close file descriptor. */
if (client->sock)
@ -1721,10 +1768,16 @@ zebra_client_read (struct thread *thread)
zread_hello (client);
break;
case ZEBRA_NEXTHOP_REGISTER:
zserv_nexthop_register(client, sock, length);
zserv_rnh_register(client, sock, length, RNH_NEXTHOP_TYPE);
break;
case ZEBRA_NEXTHOP_UNREGISTER:
zserv_nexthop_unregister(client, sock, length);
zserv_rnh_unregister(client, sock, length, RNH_NEXTHOP_TYPE);
break;
case ZEBRA_IMPORT_ROUTE_REGISTER:
zserv_rnh_register(client, sock, length, RNH_IMPORT_CHECK_TYPE);
break;
case ZEBRA_IMPORT_ROUTE_UNREGISTER:
zserv_rnh_unregister(client, sock, length, RNH_IMPORT_CHECK_TYPE);
break;
default:
zlog_info ("Zebra received unknown command %d", command);