]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: handle bgp pbr hash list destroy upon BGP destroy
authorPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 24 Apr 2018 14:35:00 +0000 (16:35 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 3 May 2018 13:15:08 +0000 (15:15 +0200)
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>
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h
bgpd/bgp_zebra.c
bgpd/bgpd.c

index 88e929f047cf2f29ce4614773701bb141f47dce7..04d6314fd7282681e88a1443b8b1e77b83b92d37 100644 (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;
index d82f125ec36d99c0b8a7ab4dab6761a5f81d11f1..5129ada37b57d8a6b4ae4dfa3b55146efb6e355a 100644 (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);
index a138f7cb2d258a5a0f78ff678cf3efb269f89138..93a509c219c30477f694311a0bd397429bc3639c 100644 (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:
index 3ed82ccd1e58fdf082b70fd6124710083e137d86..a331fad5d4a242397050bf1438a2c3df959745d8 100644 (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)