/* 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)
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 */
}
/* 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 */
}
#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;
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,
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);
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)
{
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)
{
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);
}
}
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)
{
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);
}
void
-bgp_parse_nexthop_update (void)
+bgp_parse_nexthop_update (int command)
{
struct stream *s;
struct bgp_node *rn;
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))
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:
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:
}
/**
- * 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;
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);
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);
}
/**
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;
/**
* 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
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);
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);
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);
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);
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);
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);
}
}
+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)
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);
/* "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"
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;
}
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;
}
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 ();
}
/* 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. */
#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];
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
}
}
-/* 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)
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;
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++)
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
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;
}
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. */
#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
/* 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];
};
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;
}
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 */
}
#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;
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");
}
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;
}
void
-zebra_delete_rnh (struct rnh *rnh)
+zebra_delete_rnh (struct rnh *rnh, rnh_type_t type)
{
struct route_node *rn;
}
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)
{
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)
{
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
{
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);
{
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;
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
}
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;
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");
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
{
if (rib->type == ZEBRA_ROUTE_CONNECT)
break;
}
+ else if ((type == RNH_IMPORT_CHECK_TYPE) &&
+ (rib->type == ZEBRA_ROUTE_BGP))
+ continue;
else
break;
}
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))
{
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 */
}
}
}
+ 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");
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");
}
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");
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;
}
}
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;
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;
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);
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);
}
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;
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 */
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)
}
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;
}
{
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;
}
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;
}
{
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;
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);
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
/* 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);
-
- client->nh_reg_time = quagga_time(NULL);
- zebra_add_rnh_client(rnh, client);
+ 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);
+ }
+
+ 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;
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)
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);