diff options
Diffstat (limited to 'bgpd/bgp_clist.c')
| -rw-r--r-- | bgpd/bgp_clist.c | 113 |
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); } |
