summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2018-04-24 16:35:00 +0200
committerPhilippe Guibert <philippe.guibert@6wind.com>2018-04-30 11:56:23 +0200
commita6b07429a4b0e4959a33ad2e17de6da5017dc438 (patch)
tree70a8594fceee2f629436c30ccb042df91c9fc400
parentac7c35f8b65785897c7c433250270a232f6b0eb0 (diff)
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>
-rw-r--r--bgpd/bgp_pbr.c85
-rw-r--r--bgpd/bgp_pbr.h4
-rw-r--r--bgpd/bgp_zebra.c5
-rw-r--r--bgpd/bgpd.c2
4 files changed, 93 insertions, 3 deletions
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 88e929f047..04d6314fd7 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -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;
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index d82f125ec3..5129ada37b 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -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);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index a138f7cb2d..93a509c219 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -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:
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 3ed82ccd1e..a331fad5d4 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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)