summaryrefslogtreecommitdiff
path: root/bgpd/bgp_clist.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_clist.c')
-rw-r--r--bgpd/bgp_clist.c113
1 files changed, 84 insertions, 29 deletions
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index c4a20ca233..84a00488c1 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -26,6 +26,7 @@
#include "queue.h"
#include "filter.h"
#include "stream.h"
+#include "jhash.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community.h"
@@ -35,6 +36,31 @@
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
+static uint32_t bgp_clist_hash_key_community_list(void *data)
+{
+ struct community_list *cl = data;
+
+ if (cl->name_hash)
+ return cl->name_hash;
+
+ cl->name_hash = bgp_clist_hash_key(cl->name);
+ return cl->name_hash;
+}
+
+static bool bgp_clist_hash_cmp_community_list(const void *a1, const void *a2)
+{
+ const struct community_list *cl1 = a1;
+ const struct community_list *cl2 = a2;
+
+ if (cl1->name_hash != cl2->name_hash)
+ return false;
+
+ if (strcmp(cl1->name, cl2->name) == 0)
+ return true;
+
+ return false;
+}
+
/* Lookup master structure for community-list or
extcommunity-list. */
struct community_list_master *
@@ -125,6 +151,10 @@ community_list_insert(struct community_list_handler *ch, const char *name,
/* Allocate new community_list and copy given name. */
new = community_list_new();
new->name = XSTRDUP(MTYPE_COMMUNITY_LIST_NAME, name);
+ new->name_hash = bgp_clist_hash_key_community_list(new);
+
+ /* Save for later */
+ hash_get(cm->hash, new, hash_alloc_intern);
/* If name is made by all digit character. We treat it as
number. */
@@ -194,9 +224,11 @@ community_list_insert(struct community_list_handler *ch, const char *name,
}
struct community_list *community_list_lookup(struct community_list_handler *ch,
- const char *name, int master)
+ const char *name,
+ uint32_t name_hash,
+ int master)
{
- struct community_list *list;
+ struct community_list lookup;
struct community_list_master *cm;
if (!name)
@@ -206,14 +238,9 @@ struct community_list *community_list_lookup(struct community_list_handler *ch,
if (!cm)
return NULL;
- for (list = cm->num.head; list; list = list->next)
- if (strcmp(list->name, name) == 0)
- return list;
- for (list = cm->str.head; list; list = list->next)
- if (strcmp(list->name, name) == 0)
- return list;
-
- return NULL;
+ lookup.name = (char *)name;
+ lookup.name_hash = name_hash;
+ return hash_get(cm->hash, &lookup, NULL);
}
static struct community_list *
@@ -222,13 +249,14 @@ community_list_get(struct community_list_handler *ch, const char *name,
{
struct community_list *list;
- list = community_list_lookup(ch, name, master);
+ list = community_list_lookup(ch, name, 0, master);
if (!list)
list = community_list_insert(ch, name, master);
return list;
}
-static void community_list_delete(struct community_list *list)
+static void community_list_delete(struct community_list_master *cm,
+ struct community_list *list)
{
struct community_list_list *clist;
struct community_entry *entry, *next;
@@ -250,6 +278,7 @@ static void community_list_delete(struct community_list *list)
else
clist->head = list->next;
+ hash_release(cm->hash, list);
community_list_free(list);
}
@@ -273,7 +302,8 @@ static void community_list_entry_add(struct community_list *list,
}
/* Delete community-list entry from the list. */
-static void community_list_entry_delete(struct community_list *list,
+static void community_list_entry_delete(struct community_list_master *cm,
+ struct community_list *list,
struct community_entry *entry)
{
if (entry->next)
@@ -289,7 +319,7 @@ static void community_list_entry_delete(struct community_list *list,
community_entry_free(entry);
if (community_list_empty_p(list))
- community_list_delete(list);
+ community_list_delete(cm, list);
}
/* Lookup community-list entry from the list. */
@@ -882,18 +912,20 @@ int community_list_set(struct community_list_handler *ch, const char *name,
int community_list_unset(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style)
{
+ struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
struct community_list *list;
struct community *com = NULL;
/* Lookup community list. */
- list = community_list_lookup(ch, name, COMMUNITY_LIST_MASTER);
+ list = community_list_lookup(ch, name, 0, COMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ cm = community_list_master_lookup(ch, COMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this community-list. */
if (!str) {
- community_list_delete(list);
+ community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
}
@@ -910,7 +942,7 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
- community_list_entry_delete(list, entry);
+ community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
@@ -1031,19 +1063,21 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style)
{
+ struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
struct community_list *list;
struct lcommunity *lcom = NULL;
regex_t *regex = NULL;
/* Lookup community list. */
- list = community_list_lookup(ch, name, LARGE_COMMUNITY_LIST_MASTER);
+ list = community_list_lookup(ch, name, 0, LARGE_COMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ cm = community_list_master_lookup(ch, LARGE_COMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this community-list. */
if (!str) {
- community_list_delete(list);
+ community_list_delete(cm, list);
return 0;
}
@@ -1068,7 +1102,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
- community_list_entry_delete(list, entry);
+ community_list_entry_delete(cm, list, entry);
return 0;
}
@@ -1147,18 +1181,20 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style)
{
+ struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
struct community_list *list;
struct ecommunity *ecom = NULL;
/* Lookup extcommunity list. */
- list = community_list_lookup(ch, name, EXTCOMMUNITY_LIST_MASTER);
+ list = community_list_lookup(ch, name, 0, EXTCOMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ cm = community_list_master_lookup(ch, EXTCOMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this extcommunity-list. */
if (!str) {
- community_list_delete(list);
+ community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
@@ -1175,7 +1211,7 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
- community_list_entry_delete(list, entry);
+ community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
@@ -1187,6 +1223,22 @@ struct community_list_handler *community_list_init(void)
struct community_list_handler *ch;
ch = XCALLOC(MTYPE_COMMUNITY_LIST_HANDLER,
sizeof(struct community_list_handler));
+
+ ch->community_list.hash =
+ hash_create_size(4, bgp_clist_hash_key_community_list,
+ bgp_clist_hash_cmp_community_list,
+ "Community List Number Quick Lookup");
+
+ ch->extcommunity_list.hash =
+ hash_create_size(4, bgp_clist_hash_key_community_list,
+ bgp_clist_hash_cmp_community_list,
+ "Extended Community List Quick Lookup");
+
+ ch->lcommunity_list.hash =
+ hash_create_size(4, bgp_clist_hash_key_community_list,
+ bgp_clist_hash_cmp_community_list,
+ "Large Community List Quick Lookup");
+
return ch;
}
@@ -1198,21 +1250,24 @@ void community_list_terminate(struct community_list_handler *ch)
cm = &ch->community_list;
while ((list = cm->num.head) != NULL)
- community_list_delete(list);
+ community_list_delete(cm, list);
while ((list = cm->str.head) != NULL)
- community_list_delete(list);
+ community_list_delete(cm, list);
+ hash_free(cm->hash);
cm = &ch->lcommunity_list;
while ((list = cm->num.head) != NULL)
- community_list_delete(list);
+ community_list_delete(cm, list);
while ((list = cm->str.head) != NULL)
- community_list_delete(list);
+ community_list_delete(cm, list);
+ hash_free(cm->hash);
cm = &ch->extcommunity_list;
while ((list = cm->num.head) != NULL)
- community_list_delete(list);
+ community_list_delete(cm, list);
while ((list = cm->str.head) != NULL)
- community_list_delete(list);
+ community_list_delete(cm, list);
+ hash_free(cm->hash);
XFREE(MTYPE_COMMUNITY_LIST_HANDLER, ch);
}