#include "filter.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"
DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
-char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
+int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
+ const struct bgp_nexthop_cache *b)
{
- prefix2str(bgp_dest_get_prefix(bnc->dest), buf, size);
- return buf;
+ return prefix_cmp(&a->prefix, &b->prefix);
+}
+
+const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
+{
+ return prefix2str(&bnc->prefix, buf, size);
}
void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
nexthops_free(bnc->nexthop);
}
-struct bgp_nexthop_cache *bnc_new(void)
+struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix)
{
struct bgp_nexthop_cache *bnc;
bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
sizeof(struct bgp_nexthop_cache));
+ bnc->prefix = *prefix;
+ bnc->tree = tree;
LIST_INIT(&(bnc->paths));
+ bgp_nexthop_cache_add(tree, bnc);
+
return bnc;
}
void bnc_free(struct bgp_nexthop_cache *bnc)
{
bnc_nexthop_free(bnc);
+ bgp_nexthop_cache_del(bnc->tree, bnc);
XFREE(MTYPE_BGP_NEXTHOP_CACHE, bnc);
}
+struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix)
+{
+ struct bgp_nexthop_cache bnc = {};
+
+ if (!tree)
+ return NULL;
+
+ bnc.prefix = *prefix;
+ return bgp_nexthop_cache_find(tree, &bnc);
+}
+
/* Reset and free all BGP nexthop cache. */
-static void bgp_nexthop_cache_reset(struct bgp_table *table)
+static void bgp_nexthop_cache_reset(struct bgp_nexthop_cache_head *tree)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
- for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
+ while (bgp_nexthop_cache_count(tree) > 0) {
+ bnc = bgp_nexthop_cache_first(tree);
while (!LIST_EMPTY(&(bnc->paths))) {
struct bgp_path_info *path = LIST_FIRST(&(bnc->paths));
}
bnc_free(bnc);
- bgp_dest_set_bgp_nexthop_info(dest, NULL);
- bgp_dest_unlock_node(dest);
}
}
}
static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
- struct bgp_dest *dest,
struct bgp_nexthop_cache *bnc,
bool specific)
{
char buf[PREFIX2STR_BUFFER];
time_t tbuf;
struct peer *peer;
- const struct prefix *p = bgp_dest_get_prefix(dest);
peer = (struct peer *)bnc->nht_info;
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
vty_out(vty, " %s valid [IGP metric %d], #paths %d",
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
bnc->metric, bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
bgp_show_nexthops_detail(vty, bgp, bnc);
} else {
vty_out(vty, " %s invalid, #paths %d",
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
bool import_table)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
afi_t afi;
- struct bgp_table **table;
+ struct bgp_nexthop_cache_head(*tree)[AFI_MAX];
if (import_table)
vty_out(vty, "Current BGP import check cache:\n");
else
vty_out(vty, "Current BGP nexthop cache:\n");
if (import_table)
- table = bgp->import_check_table;
+ tree = &bgp->import_check_table;
else
- table = bgp->nexthop_cache_table;
+ tree = &bgp->nexthop_cache_table;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!table || !table[afi])
- continue;
- for (dest = bgp_table_top(table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
- bgp_show_nexthop(vty, bgp, dest, bnc, false);
- }
+ frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc)
+ bgp_show_nexthop(vty, bgp, bnc, false);
}
}
if (nhopip_str) {
struct prefix nhop;
- struct bgp_table **table;
- struct bgp_dest *dest;
+ struct bgp_nexthop_cache_head (*tree)[AFI_MAX];
struct bgp_nexthop_cache *bnc;
if (!str2prefix(nhopip_str, &nhop)) {
vty_out(vty, "nexthop address is malformed\n");
return CMD_WARNING;
}
- table = import_table ? \
- bgp->import_check_table : bgp->nexthop_cache_table;
- dest = bgp_node_lookup(table[family2afi(nhop.family)], &nhop);
- if (!dest) {
- vty_out(vty, "specified nexthop is not found\n");
- return CMD_SUCCESS;
- }
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ tree = import_table ? &bgp->import_check_table
+ : &bgp->nexthop_cache_table;
+ bnc = bnc_find(tree[family2afi(nhop.family)], &nhop, 0);
if (!bnc) {
vty_out(vty, "specified nexthop does not have entry\n");
return CMD_SUCCESS;
}
- bgp_show_nexthop(vty, bgp, dest, bnc, true);
+ bgp_show_nexthop(vty, bgp, bnc, true);
} else
bgp_show_nexthops(vty, bgp, import_table);
afi_t afi;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- bgp->nexthop_cache_table[afi] =
- bgp_table_init(bgp, afi, SAFI_UNICAST);
+ bgp_nexthop_cache_init(&bgp->nexthop_cache_table[afi]);
+ bgp_nexthop_cache_init(&bgp->import_check_table[afi]);
bgp->connected_table[afi] = bgp_table_init(bgp, afi,
SAFI_UNICAST);
- bgp->import_check_table[afi] =
- bgp_table_init(bgp, afi, SAFI_UNICAST);
}
}
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
/* Only the current one needs to be reset. */
- bgp_nexthop_cache_reset(bgp->nexthop_cache_table[afi]);
- bgp_table_unlock(bgp->nexthop_cache_table[afi]);
- bgp->nexthop_cache_table[afi] = NULL;
+ bgp_nexthop_cache_reset(&bgp->nexthop_cache_table[afi]);
+ bgp_nexthop_cache_reset(&bgp->import_check_table[afi]);
bgp->connected_table[afi]->route_table->cleanup =
bgp_connected_cleanup;
bgp_table_unlock(bgp->connected_table[afi]);
bgp->connected_table[afi] = NULL;
-
- bgp_table_unlock(bgp->import_check_table[afi]);
- bgp->import_check_table[afi] = NULL;
}
}
#include "if.h"
#include "queue.h"
#include "prefix.h"
+#include "bgp_table.h"
#define NEXTHOP_FAMILY(nexthop_len) \
(((nexthop_len) == 4 || (nexthop_len) == 12 \
#define BGP_MP_NEXTHOP_FAMILY NEXTHOP_FAMILY
+PREDECL_RBTREE_UNIQ(bgp_nexthop_cache);
+
/* BGP nexthop cache value structure. */
struct bgp_nexthop_cache {
+ /* RB-tree entry. */
+ struct bgp_nexthop_cache_item entry;
+
/* IGP route's metric. */
uint32_t metric;
#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
- struct bgp_dest *dest;
+ /* Back pointer to the cache tree this entry belongs to. */
+ struct bgp_nexthop_cache_head *tree;
+
+ struct prefix prefix;
void *nht_info; /* In BGP, peer session */
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
struct bgp *bgp;
};
+extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
+ const struct bgp_nexthop_cache *b);
+DECLARE_RBTREE_UNIQ(bgp_nexthop_cache, struct bgp_nexthop_cache, entry,
+ bgp_nexthop_cache_compare);
+
/* Own tunnel-ip address structure */
struct tip_addr {
struct in_addr addr;
struct list *ifp_name_list;
};
+/* Forward declaration(s). */
+struct peer;
+struct update_subgroup;
+struct bgp_dest;
+struct attr;
+
extern void bgp_connected_add(struct bgp *bgp, struct connected *c);
extern void bgp_connected_delete(struct bgp *bgp, struct connected *c);
extern bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
extern bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
uint8_t sub_type, struct attr *attr,
struct bgp_dest *dest);
-extern struct bgp_nexthop_cache *bnc_new(void);
+extern struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix);
extern void bnc_free(struct bgp_nexthop_cache *bnc);
+extern struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix);
extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
-extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
+extern const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
extern void bgp_scan_init(struct bgp *bgp);
extern void bgp_scan_finish(struct bgp *bgp);
extern void bgp_scan_vty_init(void);
}
unregister_zebra_rnh(bnc,
CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
- bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL);
- bgp_dest_unlock_node(bnc->dest);
- bnc->dest = NULL;
bnc_free(bnc);
}
}
void bgp_unlink_nexthop_by_peer(struct peer *peer)
{
struct prefix p;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
afi_t afi = family2afi(peer->su.sa.sa_family);
if (!sockunion2hostprefix(&peer->su, &p))
return;
- dest = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p);
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p);
if (!bnc)
return;
afi_t afi, struct bgp_path_info *pi,
struct peer *peer, int connected)
{
- struct bgp_dest *dest;
+ struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc;
struct prefix p;
int is_bgp_static_route = 0;
- const struct prefix *bnc_p;
if (pi) {
is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP)
return 0;
if (is_bgp_static_route)
- dest = bgp_node_get(bgp_nexthop->import_check_table[afi], &p);
+ tree = &bgp_nexthop->import_check_table[afi];
else
- dest = bgp_node_get(bgp_nexthop->nexthop_cache_table[afi], &p);
+ tree = &bgp_nexthop->nexthop_cache_table[afi];
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(tree, &p);
if (!bnc) {
- bnc = bnc_new();
- bgp_dest_set_bgp_nexthop_info(dest, bnc);
- bnc->dest = dest;
+ bnc = bnc_new(tree, &p);
bnc->bgp = bgp_nexthop;
- bgp_dest_lock_node(dest);
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
}
}
- bnc_p = bgp_dest_get_prefix(bnc->dest);
-
- bgp_dest_unlock_node(dest);
if (is_bgp_static_route) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
} else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)
- && !is_default_host_route(bnc_p))
+ && !is_default_host_route(&bnc->prefix))
register_zebra_rnh(bnc, is_bgp_static_route);
if (pi && pi->nexthop != bnc) {
void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct prefix p;
if (!sockunion2hostprefix(&peer->su, &p))
return;
- dest = bgp_node_lookup(
- peer->bgp->nexthop_cache_table[family2afi(p.family)], &p);
- if (!dest) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug(
- "Cannot find connected NHT node for peer %s(%s)",
- peer->host, peer->bgp->name_pretty);
- return;
- }
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)],
+ &p);
if (!bnc) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
- "Cannot find connected NHT node for peer %s(%s) on route_node as expected",
+ "Cannot find connected NHT node for peer %s(%s)",
peer->host, peer->bgp->name_pretty);
- bgp_dest_unlock_node(dest);
return;
}
- bgp_dest_unlock_node(dest);
if (bnc->nht_info != peer) {
if (BGP_DEBUG(nht, NHT))
"Freeing connected NHT node %p for peer %s(%s)",
bnc, peer->host, bnc->bgp->name_pretty);
unregister_zebra_rnh(bnc, 0);
- bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL);
- bgp_dest_unlock_node(bnc->dest);
bnc_free(bnc);
}
}
void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
{
- struct bgp_dest *dest = NULL;
+ struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc;
struct nexthop *nexthop;
struct nexthop *oldnh;
}
if (command == ZEBRA_NEXTHOP_UPDATE)
- dest = bgp_node_lookup(
- bgp->nexthop_cache_table[family2afi(nhr.prefix.family)],
- &nhr.prefix);
+ tree = &bgp->nexthop_cache_table[family2afi(nhr.prefix.family)];
else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
- dest = bgp_node_lookup(
- bgp->import_check_table[family2afi(nhr.prefix.family)],
- &nhr.prefix);
-
- if (!dest) {
- if (BGP_DEBUG(nht, NHT)) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&nhr.prefix, buf, sizeof(buf));
- zlog_debug("parse nexthop update(%s(%s)): rn not found",
- buf, bgp->name_pretty);
- }
- return;
- }
+ tree = &bgp->import_check_table[family2afi(nhr.prefix.family)];
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(tree, &nhr.prefix);
if (!bnc) {
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
prefix2str(&nhr.prefix, buf, sizeof(buf));
zlog_debug(
- "parse nexthop update(%s(%s)): bnc node info not found",
+ "parse nexthop update(%s(%s)): bnc info not found",
buf, bgp->name_pretty);
}
- bgp_dest_unlock_node(dest);
return;
}
- bgp_dest_unlock_node(dest);
bnc->last_update = bgp_clock();
bnc->change_flags = 0;
*/
void bgp_cleanup_nexthops(struct bgp *bgp)
{
- afi_t afi;
- struct bgp_dest *dest;
- struct bgp_nexthop_cache *bnc;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!bgp->nexthop_cache_table[afi])
- continue;
-
- for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
+ struct bgp_nexthop_cache *bnc;
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc) {
/* Clear relevant flags. */
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
*/
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
{
- const struct prefix *p;
bool exact_match = false;
int ret;
"%s: We have not connected yet, cannot send nexthops",
__func__);
}
- p = bgp_dest_get_prefix(bnc->dest);
if ((command == ZEBRA_NEXTHOP_REGISTER
|| command == ZEBRA_IMPORT_ROUTE_REGISTER)
&& (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
exact_match = true;
- if (BGP_DEBUG(zebra, ZEBRA)) {
- char buf[PREFIX2STR_BUFFER];
-
- prefix2str(p, buf, PREFIX2STR_BUFFER);
- zlog_debug("%s: sending cmd %s for %s (vrf %s)",
- __func__, zserv_command_string(command), buf,
- bnc->bgp->name_pretty);
- }
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__,
+ zserv_command_string(command), &bnc->prefix,
+ bnc->bgp->name_pretty);
- ret = zclient_send_rnh(zclient, command, p, exact_match,
+ ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match,
bnc->bgp->vrf_id);
/* TBD: handle the failure */
if (ret < 0)
*/
void bgp_nht_register_nexthops(struct bgp *bgp)
{
- struct bgp_dest *dest;
- struct bgp_nexthop_cache *bnc;
- afi_t afi;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!bgp->nexthop_cache_table[afi])
- continue;
-
- for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
-
- if (!bnc)
- continue;
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
+ struct bgp_nexthop_cache *bnc;
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc) {
register_zebra_rnh(bnc, 0);
}
}
void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
{
struct bgp *bgp;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct nexthop *nhop;
struct interface *ifp;
return;
bgp = peer->bgp;
-
- if (!bgp->nexthop_cache_table[AFI_IP6])
- return;
-
if (!sockunion2hostprefix(&peer->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host);
if (p.family != AF_INET6)
return;
- dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
- if (!dest)
- return;
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p);
if (!bnc)
return;
void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
{
struct bgp *bgp;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct nexthop *nhop;
struct interface *ifp;
bgp = peer->bgp;
- if (!bgp->nexthop_cache_table[AFI_IP6])
- return;
-
if (!sockunion2hostprefix(&peer->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host);
if (p.family != AF_INET6)
return;
- dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
- if (!dest)
- return;
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p);
if (!bnc)
return;
#include "vxlan.h"
#include "bgp_labelpool.h"
#include "bgp_addpath_types.h"
+#include "bgp_nexthop.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
- /* Route table for next-hop lookup cache. */
- struct bgp_table *nexthop_cache_table[AFI_MAX];
+ /* Tree for next-hop lookup cache. */
+ struct bgp_nexthop_cache_head nexthop_cache_table[AFI_MAX];
- /* Route table for import-check */
- struct bgp_table *import_check_table[AFI_MAX];
+ /* Tree for import-check */
+ struct bgp_nexthop_cache_head import_check_table[AFI_MAX];
struct bgp_table *connected_table[AFI_MAX];