diff options
Diffstat (limited to 'pbrd/pbr_nht.c')
| -rw-r--r-- | pbrd/pbr_nht.c | 289 |
1 files changed, 206 insertions, 83 deletions
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 63d509bf6b..7586790c85 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -26,10 +26,10 @@ #include <jhash.h> #include <vty.h> #include <zclient.h> +#include <debug.h> #include "pbrd/pbr_nht.h" #include "pbrd/pbr_map.h" -#include "pbrd/pbr_event.h" #include "pbrd/pbr_zebra.h" #include "pbrd/pbr_memory.h" #include "pbrd/pbr_debug.h" @@ -37,6 +37,7 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups") static struct hash *pbr_nhg_hash; +static struct hash *pbr_nhrc_hash; static uint32_t pbr_nhg_low_table; static uint32_t pbr_nhg_high_table; @@ -44,18 +45,55 @@ static uint32_t pbr_nhg_low_rule; static uint32_t pbr_nhg_high_rule; static bool nhg_tableid[65535]; +static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, + struct nexthop_group nhg); + +/* + * Nexthop refcount. + */ +struct nhrc { + struct nexthop nexthop; + unsigned int refcount; +}; + +/* Hash functions for pbr_nhrc_hash ---------------------------------------- */ + +static void *pbr_nhrc_hash_alloc(void *p) +{ + struct nhrc *nhrc = XCALLOC(MTYPE_PBR_NHG, sizeof(struct nhrc)); + nhrc->nexthop = *(struct nexthop *)p; + return nhrc; +} + +static int pbr_nhrc_hash_equal(const void *arg1, const void *arg2) +{ + const struct nexthop *nh1, *nh2; + + nh1 = arg1; + nh2 = arg2; + + return nexthop_same(nh1, nh2); +} + +/* ------------------------------------------------------------------------- */ + static void *pbr_nh_alloc(void *p) { struct pbr_nexthop_cache *new; struct pbr_nexthop_cache *pnhc = (struct pbr_nexthop_cache *)p; + struct nhrc *nhrc; new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new)); - memcpy(&new->nexthop, &pnhc->nexthop, sizeof(struct nexthop)); + nhrc = hash_get(pbr_nhrc_hash, pnhc->nexthop, pbr_nhrc_hash_alloc); + new->nexthop = &nhrc->nexthop; + + /* Decremented again in pbr_nh_delete */ + ++nhrc->refcount; DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra", __PRETTY_FUNCTION__); - pbr_send_rnh(&new->nexthop, true); + pbr_send_rnh(new->nexthop, true); new->valid = false; return new; @@ -63,20 +101,36 @@ static void *pbr_nh_alloc(void *p) static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc) { - pbr_send_rnh(&(*pnhc)->nexthop, false); + struct nhrc *nhrc; + + nhrc = hash_lookup(pbr_nhrc_hash, (*pnhc)->nexthop); + + if (nhrc) + --nhrc->refcount; + if (!nhrc || nhrc->refcount == 0) { + DEBUGD(&pbr_dbg_nht, "%s: Removing nexthop from Zebra", + __PRETTY_FUNCTION__); + pbr_send_rnh((*pnhc)->nexthop, false); + } + if (nhrc && nhrc->refcount == 0) { + hash_release(pbr_nhrc_hash, nhrc); + XFREE(MTYPE_PBR_NHG, nhrc); + } XFREE(MTYPE_PBR_NHG, *pnhc); } +static void pbr_nh_delete_iterate(struct hash_backet *b, void *p) +{ + pbr_nh_delete((struct pbr_nexthop_cache **)&b->data); +} + static uint32_t pbr_nh_hash_key(void *arg) { uint32_t key; struct pbr_nexthop_cache *pbrnc = (struct pbr_nexthop_cache *)arg; - key = jhash_1word(pbrnc->nexthop.vrf_id, 0x45afe398); - key = jhash_1word(pbrnc->nexthop.ifindex, key); - key = jhash_1word(pbrnc->nexthop.type, key); - key = jhash(&pbrnc->nexthop.gate, sizeof(union g_addr), key); + key = nexthop_hash(pbrnc->nexthop); return key; } @@ -88,28 +142,28 @@ static int pbr_nh_hash_equal(const void *arg1, const void *arg2) const struct pbr_nexthop_cache *pbrnc2 = (const struct pbr_nexthop_cache *)arg2; - if (pbrnc1->nexthop.vrf_id != pbrnc2->nexthop.vrf_id) + if (pbrnc1->nexthop->vrf_id != pbrnc2->nexthop->vrf_id) return 0; - if (pbrnc1->nexthop.ifindex != pbrnc2->nexthop.ifindex) + if (pbrnc1->nexthop->ifindex != pbrnc2->nexthop->ifindex) return 0; - if (pbrnc1->nexthop.type != pbrnc2->nexthop.type) + if (pbrnc1->nexthop->type != pbrnc2->nexthop->type) return 0; - switch (pbrnc1->nexthop.type) { + switch (pbrnc1->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: return 1; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: - return pbrnc1->nexthop.gate.ipv4.s_addr - == pbrnc2->nexthop.gate.ipv4.s_addr; + return pbrnc1->nexthop->gate.ipv4.s_addr + == pbrnc2->nexthop->gate.ipv4.s_addr; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: - return !memcmp(&pbrnc1->nexthop.gate.ipv6, - &pbrnc2->nexthop.gate.ipv6, 16); + return !memcmp(&pbrnc1->nexthop->gate.ipv6, + &pbrnc2->nexthop->gate.ipv6, 16); case NEXTHOP_TYPE_BLACKHOLE: - return pbrnc1->nexthop.bh_type == pbrnc2->nexthop.bh_type; + return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type; } /* @@ -118,50 +172,118 @@ static int pbr_nh_hash_equal(const void *arg1, const void *arg2) return 0; } +static void pbr_nhgc_delete(struct pbr_nexthop_group_cache *p) +{ + hash_iterate(p->nhh, pbr_nh_delete_iterate, NULL); + hash_free(p->nhh); + XFREE(MTYPE_PBR_NHG, p); +} + +static void *pbr_nhgc_alloc(void *p) +{ + struct pbr_nexthop_group_cache *new; + struct pbr_nexthop_group_cache *pnhgc = + (struct pbr_nexthop_group_cache *)p; + + new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new)); + + strcpy(new->name, pnhgc->name); + new->table_id = pbr_nht_get_next_tableid(); + + DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u", + __PRETTY_FUNCTION__, new->name, new->table_id); + + new->nhh = hash_create_size(8, pbr_nh_hash_key, pbr_nh_hash_equal, + "PBR NH Cache Hash"); + return new; +} + + void pbr_nhgroup_add_cb(const char *name) { - struct pbr_event *pbre; + struct pbr_nexthop_group_cache *pnhgc; + struct nexthop_group_cmd *nhgc; - pbre = pbr_event_new(PBR_NHG_NEW, name); + nhgc = nhgc_find(name); + pnhgc = pbr_nht_add_group(name); - pbr_event_enqueue(pbre); - DEBUGD(&pbr_dbg_nht, "%s: Received ADD cb for %s", __PRETTY_FUNCTION__, + DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__, name); + + pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); + pbr_map_check_nh_group_change(name); } -void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhg, +void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop) { - struct pbr_event *pbre; + char debugstr[256]; + struct pbr_nexthop_group_cache pnhgc_find = {}; + struct pbr_nexthop_group_cache *pnhgc; + struct pbr_nexthop_cache pnhc_find = {}; + struct pbr_nexthop_cache *pnhc; + + /* find pnhgc by name */ + strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name)); + pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc); - pbre = pbr_event_new(PBR_NHG_ADD_NEXTHOP, nhg->name); + /* create & insert new pnhc into pnhgc->nhh */ + pnhc_find.nexthop = (struct nexthop *)nhop; + pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc); + pnhc_find.nexthop = NULL; + + /* set parent pnhgc */ + pnhc->parent = pnhgc; - pbr_event_enqueue(pbre); - DEBUGD(&pbr_dbg_nht, "%s: Received NEXTHOP_ADD cb for %s", - __PRETTY_FUNCTION__, nhg->name); + if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) { + nexthop2str(nhop, debugstr, sizeof(debugstr)); + DEBUGD(&pbr_dbg_nht, "%s: Added %s to nexthop-group %s", + __PRETTY_FUNCTION__, debugstr, nhgc->name); + } + + pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); + pbr_map_check_nh_group_change(nhgc->name); } -void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhg, +void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop) { - struct pbr_event *pbre; + char debugstr[256]; + struct pbr_nexthop_group_cache pnhgc_find = {}; + struct pbr_nexthop_group_cache *pnhgc; + struct pbr_nexthop_cache pnhc_find = {}; + struct pbr_nexthop_cache *pnhc; + + /* find pnhgc by name */ + strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name)); + pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc); + + /* delete pnhc from pnhgc->nhh */ + pnhc_find.nexthop = (struct nexthop *)nhop; + pnhc = hash_release(pnhgc->nhh, &pnhc_find); + + /* delete pnhc */ + pbr_nh_delete(&pnhc); - pbre = pbr_event_new(PBR_NHG_DEL_NEXTHOP, nhg->name); + if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) { + nexthop2str(nhop, debugstr, sizeof(debugstr)); + DEBUGD(&pbr_dbg_nht, "%s: Removed %s from nexthop-group %s", + __PRETTY_FUNCTION__, debugstr, nhgc->name); + } - pbr_event_enqueue(pbre); - DEBUGD(&pbr_dbg_nht, "%s: Received NEXTHOP_DEL cb for %s", - __PRETTY_FUNCTION__, nhg->name); + pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); + pbr_map_check_nh_group_change(nhgc->name); } void pbr_nhgroup_delete_cb(const char *name) { - struct pbr_event *pbre; + /* delete group from all pbrms's */ + pbr_nht_delete_group(name); - pbre = pbr_event_new(PBR_NHG_DELETE, name); - - pbr_event_enqueue(pbre); - DEBUGD(&pbr_dbg_nht, "%s: Received DELETE cb for %s", + DEBUGD(&pbr_dbg_nht, "%s: Removed nexthop-group %s", __PRETTY_FUNCTION__, name); + + pbr_map_check_nh_group_change(name); } #if 0 @@ -307,7 +429,7 @@ void pbr_nht_change_group(const char *name) struct pbr_nexthop_cache lookup; struct pbr_nexthop_cache *pnhc; - memcpy(&lookup.nexthop, nhop, sizeof(*nhop)); + lookup.nexthop = nhop; pnhc = hash_lookup(pnhgc->nhh, &lookup); if (!pnhc) { pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc); @@ -324,35 +446,13 @@ char *pbr_nht_nexthop_make_name(char *name, size_t l, return buffer; } -static void *pbr_nhgc_alloc(void *p) -{ - struct pbr_nexthop_group_cache *new; - struct pbr_nexthop_group_cache *pnhgc = - (struct pbr_nexthop_group_cache *)p; - - new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new)); - - strcpy(new->name, pnhgc->name); - new->table_id = pbr_nht_get_next_tableid(); - - DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u", - __PRETTY_FUNCTION__, new->name, new->table_id); - - new->nhh = hash_create_size(8, pbr_nh_hash_key, pbr_nh_hash_equal, - "PBR NH Cache Hash"); - return new; -} - -void pbr_nht_add_individual_nexthop(const char *name, uint32_t seqno) +void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms) { struct pbr_nexthop_group_cache *pnhgc; struct pbr_nexthop_group_cache find; struct pbr_nexthop_cache *pnhc; - struct pbr_map_sequence *pbrms; struct pbr_nexthop_cache lookup; - pbrms = pbrms_get(name, seqno); - memset(&find, 0, sizeof(find)); pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_MAP_NAMELEN, pbrms->seqno, find.name); @@ -361,29 +461,39 @@ void pbr_nht_add_individual_nexthop(const char *name, uint32_t seqno) pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc); - memcpy(&lookup.nexthop, pbrms->nhg->nexthop, sizeof(struct nexthop)); + lookup.nexthop = pbrms->nhg->nexthop; pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc); pnhc->parent = pnhgc; pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg); } -void pbr_nht_delete_individual_nexthop(const char *name, uint32_t seqno) +void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) { struct pbr_nexthop_group_cache *pnhgc; struct pbr_nexthop_group_cache find; struct pbr_nexthop_cache *pnhc; struct pbr_nexthop_cache lup; - struct pbr_map_sequence *pbrms; + struct pbr_map *pbrm = pbrms->parent; + struct listnode *node; + struct pbr_map_interface *pmi; struct nexthop *nh; - pbrms = pbrms_get(name, seqno); + if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { + for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) + pbr_send_pbr_map(pbrms, pmi, false); + } + + pbrm->valid = false; + pbrms->nhs_installed = false; + pbrms->installed = false; + pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; memset(&find, 0, sizeof(find)); strcpy(&find.name[0], pbrms->internal_nhg_name); pnhgc = hash_lookup(pbr_nhg_hash, &find); nh = pbrms->nhg->nexthop; - memcpy(&lup.nexthop, nh, sizeof(struct nexthop)); + lup.nexthop = nh; pnhc = hash_lookup(pnhgc->nhh, &lup); pnhc->parent = NULL; hash_release(pnhgc->nhh, pnhc); @@ -398,7 +508,7 @@ void pbr_nht_delete_individual_nexthop(const char *name, uint32_t seqno) XFREE(MTYPE_TMP, pbrms->internal_nhg_name); } -void pbr_nht_add_group(const char *name) +struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name) { struct nexthop *nhop; struct nexthop_group_cmd *nhgc; @@ -410,7 +520,7 @@ void pbr_nht_add_group(const char *name) if (!nhgc) { zlog_warn("%s: Could not find group %s to add", __PRETTY_FUNCTION__, name); - return; + return NULL; } strcpy(lookup.name, name); @@ -422,13 +532,15 @@ void pbr_nht_add_group(const char *name) struct pbr_nexthop_cache lookup; struct pbr_nexthop_cache *pnhc; - memcpy(&lookup.nexthop, nhop, sizeof(*nhop)); + lookup.nexthop = nhop; pnhc = hash_lookup(pnhgc->nhh, &lookup); if (!pnhc) { pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc); pnhc->parent = pnhgc; } } + + return pnhgc; } void pbr_nht_delete_group(const char *name) @@ -436,16 +548,25 @@ void pbr_nht_delete_group(const char *name) struct pbr_map_sequence *pbrms; struct listnode *snode; struct pbr_map *pbrm; + struct pbr_nexthop_group_cache pnhgc_find; + struct pbr_nexthop_group_cache *pnhgc; RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) { if (pbrms->nhgrp_name - && strcmp(pbrms->nhgrp_name, name) == 0) { + && strmatch(pbrms->nhgrp_name, name)) { pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; + nexthop_group_delete(&pbrms->nhg); + pbrms->nhg = NULL; + pbrms->internal_nhg_name = NULL; pbrm->valid = false; } } } + + strlcpy(pnhgc_find.name, name, sizeof(pnhgc_find.name)); + pnhgc = hash_release(pbr_nhg_hash, &pnhgc_find); + pbr_nhgc_delete(pnhgc); } bool pbr_nht_nexthop_valid(struct nexthop_group *nhg) @@ -491,13 +612,14 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b, switch (pnhi->nhr->prefix.family) { case AF_INET: - if (pnhc->nexthop.gate.ipv4.s_addr + if (pnhc->nexthop->gate.ipv4.s_addr == pnhi->nhr->prefix.u.prefix4.s_addr) pnhc->valid = !!pnhi->nhr->nexthop_num; break; case AF_INET6: - if (memcmp(&pnhc->nexthop.gate.ipv6, - &pnhi->nhr->prefix.u.prefix6, 16) == 0) + if (memcmp(&pnhc->nexthop->gate.ipv6, + &pnhi->nhr->prefix.u.prefix6, 16) + == 0) pnhc->valid = !!pnhi->nhr->nexthop_num; break; } @@ -506,14 +628,6 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b, prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid, pnhc->valid); - if (old_valid != pnhc->valid) { - struct pbr_event *pbre; - - pbre = pbr_event_new(PBR_NH_CHANGED, pnhc->parent->name); - - pbr_event_enqueue(pbre); - } - if (pnhc->valid) pnhi->valid += 1; } @@ -522,6 +636,9 @@ static void pbr_nht_nexthop_update_lookup(struct hash_backet *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_individual pnhi; + bool old_valid; + + old_valid = pnhgc->valid; pnhi.nhr = (struct zapi_route *)data; pnhi.valid = 0; @@ -532,6 +649,9 @@ static void pbr_nht_nexthop_update_lookup(struct hash_backet *b, void *data) * If any of the specified nexthops are valid we are valid */ pnhgc->valid = !!pnhi.valid; + + if (old_valid != pnhgc->valid) + pbr_map_check_nh_group_change(pnhgc->name); } void pbr_nht_nexthop_update(struct zapi_route *nhr) @@ -652,7 +772,7 @@ static void pbr_nht_show_nhg_nexthops(struct hash_backet *b, void *data) struct vty *vty = data; vty_out(vty, "\tValid: %d", pnhc->valid); - nexthop_group_write_nexthop(vty, &pnhc->nexthop); + nexthop_group_write_nexthop(vty, pnhc->nexthop); } struct pbr_nht_show { @@ -690,6 +810,9 @@ void pbr_nht_init(void) { pbr_nhg_hash = hash_create_size( 16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash"); + pbr_nhrc_hash = + hash_create_size(16, (unsigned int (*)(void *))nexthop_hash, + pbr_nhrc_hash_equal, "PBR NH Hash"); pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID; pbr_nhg_high_table = PBR_NHT_DEFAULT_HIGH_TABLEID; |
