Skip to content

Commit

Permalink
bgpd: handle bgp pbr hash list destroy upon BGP destroy
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
pguibert6WIND committed Apr 30, 2018
1 parent ac7c35f commit a6b0742
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 3 deletions.
85 changes: 85 additions & 0 deletions bgpd/bgp_pbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion bgpd/bgp_pbr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion bgpd/bgpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit a6b0742

Please sign in to comment.