bgpd: handle bgp pbr hash list destroy upon BGP destroy

Upon BGP destroy, the hash list related to PBR are removed.
The pbr_match entries, as well as the contained pbr_match_entries
entries.
Then the pbr_action entries. The order is important, since the former
are referencing pbr_action. So the references must be removed, prior to
remove pbr action.
Also, the zebra associated contexts are removed.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2018-04-24 16:35:00 +02:00
parent ac7c35f8b6
commit a6b07429a4
4 changed files with 93 additions and 3 deletions

View File

@ -309,6 +309,48 @@ static int bgp_pbr_build_and_validate_entry(struct prefix *p,
return 0;
}
static void bgp_pbr_match_entry_free(void *arg)
{
struct bgp_pbr_match_entry *bpme;
bpme = (struct bgp_pbr_match_entry *)arg;
if (bpme->installed) {
bgp_send_pbr_ipset_entry_match(bpme, false);
bpme->installed = false;
bpme->backpointer = NULL;
}
XFREE(MTYPE_PBR_MATCH_ENTRY, bpme);
}
static void bgp_pbr_match_free(void *arg)
{
struct bgp_pbr_match *bpm;
bpm = (struct bgp_pbr_match *)arg;
hash_clean(bpm->entry_hash, bgp_pbr_match_entry_free);
if (hashcount(bpm->entry_hash) == 0) {
/* delete iptable entry first */
/* then delete ipset match */
if (bpm->installed) {
if (bpm->installed_in_iptable) {
bgp_send_pbr_iptable(bpm->action,
bpm, false);
bpm->installed_in_iptable = false;
bpm->action->refcnt--;
}
bgp_send_pbr_ipset_match(bpm, false);
bpm->installed = false;
bpm->action = NULL;
}
}
hash_free(bpm->entry_hash);
XFREE(MTYPE_PBR_MATCH, bpm);
}
static void *bgp_pbr_match_alloc_intern(void *arg)
{
struct bgp_pbr_match *bpm, *new;
@ -321,6 +363,24 @@ static void *bgp_pbr_match_alloc_intern(void *arg)
return new;
}
static void bgp_pbr_action_free(void *arg)
{
struct bgp_pbr_action *bpa;
bpa = (struct bgp_pbr_action *)arg;
if (bpa->refcnt == 0) {
if (bpa->installed && bpa->table_id != 0) {
bgp_send_pbr_rule_action(bpa, false);
bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
AFI_IP,
bpa->table_id,
false);
}
}
XFREE(MTYPE_PBR_ACTION, bpa);
}
static void *bgp_pbr_action_alloc_intern(void *arg)
{
struct bgp_pbr_action *bpa, *new;
@ -515,6 +575,20 @@ struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
return bpmiu.bpm_found;
}
void bgp_pbr_cleanup(struct bgp *bgp)
{
if (bgp->pbr_match_hash) {
hash_clean(bgp->pbr_match_hash, bgp_pbr_match_free);
hash_free(bgp->pbr_match_hash);
bgp->pbr_match_hash = NULL;
}
if (bgp->pbr_action_hash) {
hash_clean(bgp->pbr_action_hash, bgp_pbr_action_free);
hash_free(bgp->pbr_action_hash);
bgp->pbr_action_hash = NULL;
}
}
void bgp_pbr_init(struct bgp *bgp)
{
bgp->pbr_match_hash =
@ -685,6 +759,7 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
bgp_send_pbr_iptable(bpm->action,
bpm, false);
bpm->installed_in_iptable = false;
bpm->action->refcnt--;
}
bgp_send_pbr_ipset_match(bpm, false);
bpm->installed = false;
@ -695,6 +770,15 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
* note that drop does not need to call send_pbr_action
*/
}
if (bpa->refcnt == 0) {
if (bpa->installed && bpa->table_id != 0) {
bgp_send_pbr_rule_action(bpa, false);
bgp_zebra_announce_default(bpa->bgp, &(bpa->nh),
AFI_IP,
bpa->table_id,
false);
}
}
}
struct bgp_pbr_match_entry_remain {
@ -821,6 +905,7 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
bpa->table_id = bpa->fwmark;
bpa->installed = false;
}
bpa->bgp = bgp;
bpa->unique = ++bgp_pbr_action_counter_unique;
/* 0 value is forbidden */
bpa->install_in_progress = false;

View File

@ -215,7 +215,8 @@ struct bgp_pbr_action {
bool installed;
bool install_in_progress;
uint32_t refcnt;
struct bgp *bgp;
};
extern struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
@ -230,6 +231,7 @@ extern struct bgp_pbr_match_entry *bgp_pbr_match_ipset_entry_lookup(
extern struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
uint32_t unique);
extern void bgp_pbr_cleanup(struct bgp *bgp);
extern void bgp_pbr_init(struct bgp *bgp);
extern uint32_t bgp_pbr_action_hash_key(void *arg);

View File

@ -2112,6 +2112,7 @@ static int iptable_notify_owner(int command, struct zclient *zclient,
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: Received IPTABLE_INSTALLED",
__PRETTY_FUNCTION__);
bgpm->action->refcnt++;
break;
case ZAPI_IPTABLE_REMOVED:
if (BGP_DEBUG(zebra, ZEBRA))
@ -2580,8 +2581,10 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
bgp_encode_pbr_iptable_match(s, pba, pbm);
stream_putw_at(s, 0, stream_get_endp(s));
if (!zclient_send_message(zclient) && install)
if (!zclient_send_message(zclient) && install) {
pbm->install_iptable_in_progress = true;
pba->refcnt++;
}
}
/* inject in table <table_id> a default route to:

View File

@ -3403,7 +3403,7 @@ void bgp_free(struct bgp *bgp)
bf_release_index(bm->rd_idspace, bgp->vrf_rd_id);
bgp_evpn_cleanup(bgp);
bgp_pbr_cleanup(bgp);
if (bgp->name)
XFREE(MTYPE_BGP, bgp->name);
if (bgp->name_pretty)