Introduce a struct filterstate and pass this to rde_filter instead of
authorclaudio <claudio@openbsd.org>
Mon, 9 Jul 2018 14:08:48 +0000 (14:08 +0000)
committerclaudio <claudio@openbsd.org>
Mon, 9 Jul 2018 14:08:48 +0000 (14:08 +0000)
passing the asp. This is no longer using asp_get() and should be therefor
be a bit lighter. Will also allow to put more stuff into the state.
OK denis@ sthen@

usr.sbin/bgpd/rde.c
usr.sbin/bgpd/rde.h
usr.sbin/bgpd/rde_filter.c
usr.sbin/bgpd/rde_rib.c
usr.sbin/bgpd/rde_update.c

index f708360..5e179d4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.384 2018/07/05 10:25:26 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.385 2018/07/09 14:08:48 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -1363,7 +1363,7 @@ void
 rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
     struct bgpd_addr *prefix, u_int8_t prefixlen)
 {
-       struct rde_aspath       *fasp;
+       struct filterstate       state;
        struct prefix           *p;
        enum filter_actions      action;
        u_int16_t                i;
@@ -1380,16 +1380,15 @@ rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
        for (i = RIB_LOC_START; i < rib_size; i++) {
                if (*ribs[i].name == '\0')
                        break;
+               rde_filterstate_prep(&state, asp);
                /* input filter */
-               action = rde_filter(ribs[i].in_rules, peer, &fasp, p);
-
-               if (fasp == NULL)
-                       fasp = asp;
+               action = rde_filter(ribs[i].in_rules, peer, p, &state);
 
                if (action == ACTION_ALLOW) {
                        rde_update_log("update", i, peer,
-                           &fasp->nexthop->exit_nexthop, prefix, prefixlen);
-                       path_update(&ribs[i].rib, peer, fasp, prefix,
+                           &state.aspath.nexthop->exit_nexthop, prefix,
+                           prefixlen);
+                       path_update(&ribs[i].rib, peer, &state.aspath, prefix,
                            prefixlen, 0);
                } else if (prefix_remove(&ribs[i].rib, peer, prefix, prefixlen,
                    0)) {
@@ -1397,9 +1396,8 @@ rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
                            NULL, prefix, prefixlen);
                }
 
-               /* free modified aspath */
-               if (fasp != asp)
-                       path_put(fasp);
+               /* clear state */
+               rde_filterstate_clean(&state);
        }
 }
 
@@ -2298,23 +2296,19 @@ void
 rde_dump_filterout(struct rde_peer *peer, struct prefix *p,
     struct ctl_show_rib_request *req)
 {
-       struct bgpd_addr         addr;
-       struct rde_aspath       *fasp;
+       struct filterstate       state;
        enum filter_actions      a;
 
        if (up_test_update(peer, p) != 1)
                return;
 
-       pt_getaddr(p->re->prefix, &addr);
-       a = rde_filter(out_rules, peer, &fasp, p);
-       if (fasp == NULL)
-               fasp = prefix_aspath(p);
+       rde_filterstate_prep(&state, prefix_aspath(p));
+       a = rde_filter(out_rules, peer, p, &state);
 
        if (a == ACTION_ALLOW)
-               rde_dump_rib_as(p, fasp, req->pid, req->flags);
+               rde_dump_rib_as(p, &state.aspath, req->pid, req->flags);
 
-       if (fasp != prefix_aspath(p))
-               path_put(fasp);
+       rde_filterstate_clean(&state);
 }
 
 void
@@ -3043,11 +3037,12 @@ rde_reload_done(void)
 void
 rde_softreconfig_in(struct rib_entry *re, void *ptr)
 {
+       struct filterstate       state;
        struct rib_desc         *rib = ptr;
        struct prefix           *p, *np;
        struct pt_entry         *pt;
        struct rde_peer         *peer;
-       struct rde_aspath       *asp, *fasp;
+       struct rde_aspath       *asp;
        enum filter_actions      action;
        struct bgpd_addr         addr;
 
@@ -3062,30 +3057,29 @@ rde_softreconfig_in(struct rib_entry *re, void *ptr)
                asp = prefix_aspath(p);
                peer = asp->peer;
 
-               action = rde_filter(rib->in_rules, peer, &fasp, p);
-               fasp = fasp != NULL ? fasp : asp;
+               rde_filterstate_prep(&state, asp);
+               action = rde_filter(rib->in_rules, peer, p, &state);
 
                if (action == ACTION_ALLOW) {
                        /* update Local-RIB */
-                       path_update(&rib->rib, peer, fasp, &addr,
+                       path_update(&rib->rib, peer, &state.aspath, &addr,
                            pt->prefixlen, 0);
                } else if (action == ACTION_DENY) {
                        /* remove from Local-RIB */
                        prefix_remove(&rib->rib, peer, &addr, pt->prefixlen, 0);
                }
 
-               if (fasp != asp)
-                       path_put(fasp);
+               rde_filterstate_clean(&state);
        }
 }
 
 void
 rde_softreconfig_out(struct rib_entry *re, void *ptr)
 {
+       struct filterstate       ostate, nstate;
        struct prefix           *p = re->active;
        struct pt_entry         *pt;
        struct rde_peer         *peer = ptr;
-       struct rde_aspath       *oasp, *nasp;
        enum filter_actions      oa, na;
        struct bgpd_addr         addr;
 
@@ -3101,40 +3095,37 @@ rde_softreconfig_out(struct rib_entry *re, void *ptr)
        if (up_test_update(peer, p) != 1)
                return;
 
-       oa = rde_filter(out_rules_tmp, peer, &oasp, p);
-       na = rde_filter(out_rules, peer, &nasp, p);
-       oasp = oasp != NULL ? oasp : prefix_aspath(p);
-       nasp = nasp != NULL ? nasp : prefix_aspath(p);
+       rde_filterstate_prep(&ostate, prefix_aspath(p));
+       rde_filterstate_prep(&nstate, prefix_aspath(p));
+       oa = rde_filter(out_rules_tmp, peer, p, &ostate);
+       na = rde_filter(out_rules, peer, p, &nstate);
 
        /* go through all 4 possible combinations */
        /* if (oa == ACTION_DENY && na == ACTION_DENY) */
                /* nothing todo */
        if (oa == ACTION_DENY && na == ACTION_ALLOW) {
                /* send update */
-               up_generate(peer, nasp, &addr, pt->prefixlen);
+               up_generate(peer, &nstate.aspath, &addr, pt->prefixlen);
        } else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
                /* send withdraw */
                up_generate(peer, NULL, &addr, pt->prefixlen);
        } else if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
                /* send update if path attributes changed */
-               if (path_compare(nasp, oasp) != 0)
-                       up_generate(peer, nasp, &addr, pt->prefixlen);
+               if (path_compare(&nstate.aspath, &ostate.aspath) != 0)
+                       up_generate(peer, &nstate.aspath, &addr, pt->prefixlen);
        }
 
-       if (oasp != prefix_aspath(p))
-               path_put(oasp);
-       if (nasp != prefix_aspath(p))
-               path_put(nasp);
+       rde_filterstate_clean(&ostate);
+       rde_filterstate_clean(&nstate);
 }
 
 void
 rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
 {
+       struct filterstate       ostate;
        struct rde_peer         *peer = ptr;
        struct prefix           *p = re->active;
        struct pt_entry         *pt;
-       struct rde_aspath       *oasp;
-       enum filter_actions      oa;
        struct bgpd_addr         addr;
 
        pt = re->prefix;
@@ -3144,18 +3135,12 @@ rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
        if (up_test_update(peer, p) != 1)
                return;
 
-       oa = rde_filter(out_rules_tmp, peer, &oasp, p);
-       oasp = oasp != NULL ? oasp : prefix_aspath(p);
-
-       if (oa == ACTION_DENY)
-               /* nothing todo */
-               goto done;
-
-       /* send withdraw */
-       up_generate(peer, NULL, &addr, pt->prefixlen);
-done:
-       if (oasp != prefix_aspath(p))
-               path_put(oasp);
+       rde_filterstate_prep(&ostate, prefix_aspath(p));
+       if (rde_filter(out_rules_tmp, peer, p, &ostate) != ACTION_DENY) {
+               /* send withdraw */
+               up_generate(peer, NULL, &addr, pt->prefixlen);
+       }
+       rde_filterstate_clean(&ostate);
 }
 
 /*
@@ -3570,6 +3555,7 @@ peer_send_eor(struct rde_peer *peer, u_int8_t aid)
 void
 network_add(struct network_config *nc, int flagstatic)
 {
+       struct filterstate       state;
        struct rdomain          *rd;
        struct rde_aspath       *asp;
        struct filter_set_head  *vpnset = NULL;
@@ -3624,15 +3610,18 @@ network_add(struct network_config *nc, int flagstatic)
        }
        if (!flagstatic)
                asp->flags |= F_ANN_DYNAMIC;
-       rde_apply_set(&nc->attrset, asp, nc->prefix.aid, peerself, peerself);
+       rde_filterstate_prep(&state, asp);
+       rde_apply_set(&nc->attrset, &state, nc->prefix.aid, peerself, peerself);
        if (vpnset)
-               rde_apply_set(vpnset, asp, nc->prefix.aid, peerself, peerself);
+               rde_apply_set(vpnset, &state, nc->prefix.aid, peerself,
+                   peerself);
        for (i = RIB_LOC_START; i < rib_size; i++) {
                if (*ribs[i].name == '\0')
                        break;
                path_update(&ribs[i].rib, peerself, asp, &nc->prefix,
                    nc->prefixlen, 0);
        }
+       rde_filterstate_clean(&state);
        path_put(asp);
        filterset_free(&nc->attrset);
 }
index 4e79c17..06a3e0f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.h,v 1.175 2018/06/29 11:45:50 claudio Exp $ */
+/*     $OpenBSD: rde.h,v 1.176 2018/07/09 14:08:48 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -318,6 +318,10 @@ struct prefix {
 
 #define F_PREFIX_USE_UPDATES   0x01    /* linked onto the updates list */
 
+struct filterstate {
+       struct rde_aspath       aspath;
+};
+
 extern struct rde_memstats rdemem;
 
 /* prototypes */
@@ -402,9 +406,11 @@ u_char             *community_ext_delete_non_trans(u_char *, u_int16_t,
 void            prefix_evaluate(struct prefix *, struct rib_entry *);
 
 /* rde_filter.c */
+void            rde_filterstate_prep(struct filterstate *, struct rde_aspath *);
+void            rde_filterstate_clean(struct filterstate *);
 enum filter_actions rde_filter(struct filter_head *, struct rde_peer *,
-                    struct rde_aspath **, struct prefix *);
-void            rde_apply_set(struct filter_set_head *, struct rde_aspath *,
+                    struct prefix *, struct filterstate *);
+void            rde_apply_set(struct filter_set_head *, struct filterstate *,
                     u_int8_t, struct rde_peer *, struct rde_peer *);
 int             rde_filter_equal(struct filter_head *, struct filter_head *,
                     struct rde_peer *, struct prefixset_head *);
@@ -476,6 +482,7 @@ int          path_empty(struct rde_aspath *);
 struct rde_aspath *path_copy(struct rde_aspath *, const struct rde_aspath *);
 struct rde_aspath *path_prep(struct rde_aspath *);
 struct rde_aspath *path_get(void);
+void            path_clean(struct rde_aspath *);
 void            path_put(struct rde_aspath *);
 
 #define        PREFIX_SIZE(x)  (((x) + 7) / 8 + 1)
index 9ce19c0..08ce4cf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_filter.c,v 1.94 2018/06/29 11:45:50 claudio Exp $ */
+/*     $OpenBSD: rde_filter.c,v 1.95 2018/07/09 14:08:48 claudio Exp $ */
 
 /*
  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -35,7 +35,7 @@ int   rde_prefix_match(struct filter_prefix *, struct prefix *);
 int    filterset_equal(struct filter_set_head *, struct filter_set_head *);
 
 void
-rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
+rde_apply_set(struct filter_set_head *sh, struct filterstate *state,
     u_int8_t aid, struct rde_peer *from, struct rde_peer *peer)
 {
        struct filter_set       *set;
@@ -46,76 +46,80 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
        u_int16_t                nl;
        u_int8_t                 prepend;
 
-       if (asp == NULL)
+       if (state == NULL)
                return;
 
-       if (asp->flags & F_ATTR_LINKED)
-               fatalx("rde_apply_set: trying to modify linked asp");
-
        TAILQ_FOREACH(set, sh, entry) {
                switch (set->type) {
                case ACTION_SET_LOCALPREF:
-                       asp->lpref = set->action.metric;
+                       state->aspath.lpref = set->action.metric;
                        break;
                case ACTION_SET_RELATIVE_LOCALPREF:
                        if (set->action.relative > 0) {
-                               if (set->action.relative + asp->lpref <
-                                   asp->lpref)
-                                       asp->lpref = UINT_MAX;
+                               if (set->action.relative + state->aspath.lpref <
+                                   state->aspath.lpref)
+                                       state->aspath.lpref = UINT_MAX;
                                else
-                                       asp->lpref += set->action.relative;
+                                       state->aspath.lpref +=
+                                           set->action.relative;
                        } else {
                                if ((u_int32_t)-set->action.relative >
-                                   asp->lpref)
-                                       asp->lpref = 0;
+                                   state->aspath.lpref)
+                                       state->aspath.lpref = 0;
                                else
-                                       asp->lpref += set->action.relative;
+                                       state->aspath.lpref +=
+                                           set->action.relative;
                        }
                        break;
                case ACTION_SET_MED:
-                       asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
-                       asp->med = set->action.metric;
+                       state->aspath.flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
+                       state->aspath.med = set->action.metric;
                        break;
                case ACTION_SET_RELATIVE_MED:
-                       asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
+                       state->aspath.flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
                        if (set->action.relative > 0) {
-                               if (set->action.relative + asp->med <
-                                   asp->med)
-                                       asp->med = UINT_MAX;
+                               if (set->action.relative + state->aspath.med <
+                                   state->aspath.med)
+                                       state->aspath.med = UINT_MAX;
                                else
-                                       asp->med += set->action.relative;
+                                       state->aspath.med +=
+                                           set->action.relative;
                        } else {
                                if ((u_int32_t)-set->action.relative >
-                                   asp->med)
-                                       asp->med = 0;
+                                   state->aspath.med)
+                                       state->aspath.med = 0;
                                else
-                                       asp->med += set->action.relative;
+                                       state->aspath.med +=
+                                           set->action.relative;
                        }
                        break;
                case ACTION_SET_WEIGHT:
-                       asp->weight = set->action.metric;
+                       state->aspath.weight = set->action.metric;
                        break;
                case ACTION_SET_RELATIVE_WEIGHT:
                        if (set->action.relative > 0) {
-                               if (set->action.relative + asp->weight <
-                                   asp->weight)
-                                       asp->weight = UINT_MAX;
+                               if (set->action.relative + state->aspath.weight <
+                                   state->aspath.weight)
+                                       state->aspath.weight = UINT_MAX;
                                else
-                                       asp->weight += set->action.relative;
+                                       state->aspath.weight +=
+                                           set->action.relative;
                        } else {
                                if ((u_int32_t)-set->action.relative >
-                                   asp->weight)
-                                       asp->weight = 0;
+                                   state->aspath.weight)
+                                       state->aspath.weight = 0;
                                else
-                                       asp->weight += set->action.relative;
+                                       state->aspath.weight +=
+                                           set->action.relative;
                        }
                        break;
                case ACTION_SET_PREPEND_SELF:
                        prep_as = peer->conf.local_as;
                        prepend = set->action.prepend;
-                       np = aspath_prepend(asp->aspath, prep_as, prepend, &nl);
-                       aspath_put(asp->aspath);
-                       asp->aspath = aspath_get(np, nl);
+                       np = aspath_prepend(state->aspath.aspath, prep_as,
+                           prepend, &nl);
+                       aspath_put(state->aspath.aspath);
+                       state->aspath.aspath = aspath_get(np, nl);
                        free(np);
                        break;
                case ACTION_SET_PREPEND_PEER:
@@ -123,9 +127,10 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                                break;
                        prep_as = from->conf.remote_as;
                        prepend = set->action.prepend;
-                       np = aspath_prepend(asp->aspath, prep_as, prepend, &nl);
-                       aspath_put(asp->aspath);
-                       asp->aspath = aspath_get(np, nl);
+                       np = aspath_prepend(state->aspath.aspath, prep_as,
+                           prepend, &nl);
+                       aspath_put(state->aspath.aspath);
+                       state->aspath.aspath = aspath_get(np, nl);
                        free(np);
                        break;
                case ACTION_SET_NEXTHOP:
@@ -134,7 +139,7 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                case ACTION_SET_NEXTHOP_NOMODIFY:
                case ACTION_SET_NEXTHOP_SELF:
                        nexthop_modify(set->action.nh, set->type, aid,
-                           &asp->nexthop, &asp->flags);
+                           &state->aspath.nexthop, &state->aspath.flags);
                        break;
                case ACTION_SET_COMMUNITY:
                        switch (set->action.community.as) {
@@ -167,7 +172,7 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                                break;
                        }
 
-                       community_set(asp, as, type);
+                       community_set(&state->aspath, as, type);
                        break;
                case ACTION_DEL_COMMUNITY:
                        switch (set->action.community.as) {
@@ -200,7 +205,7 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                                break;
                        }
 
-                       community_delete(asp, as, type);
+                       community_delete(&state->aspath, as, type);
                        break;
                case ACTION_SET_LARGE_COMMUNITY:
                        switch (set->action.large_community.as) {
@@ -248,7 +253,7 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                                break;
                        }
 
-                       community_large_set(asp, las, ld1, ld2);
+                       community_large_set(&state->aspath, las, ld1, ld2);
                        break;
                case ACTION_DEL_LARGE_COMMUNITY:
                        switch (set->action.large_community.as) {
@@ -296,7 +301,7 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                                break;
                        }
 
-                       community_large_delete(asp, las, ld1, ld2);
+                       community_large_delete(&state->aspath, las, ld1, ld2);
                        break;
                case ACTION_PFTABLE:
                        /* convert pftable name to an id */
@@ -304,8 +309,8 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                        set->type = ACTION_PFTABLE_ID;
                        /* FALLTHROUGH */
                case ACTION_PFTABLE_ID:
-                       pftable_unref(asp->pftableid);
-                       asp->pftableid = pftable_ref(set->action.id);
+                       pftable_unref(state->aspath.pftableid);
+                       state->aspath.pftableid = pftable_ref(set->action.id);
                        break;
                case ACTION_RTLABEL:
                        /* convert the route label to an id for faster access */
@@ -313,18 +318,18 @@ rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
                        set->type = ACTION_RTLABEL_ID;
                        /* FALLTHROUGH */
                case ACTION_RTLABEL_ID:
-                       rtlabel_unref(asp->rtlabelid);
-                       asp->rtlabelid = rtlabel_ref(set->action.id);
+                       rtlabel_unref(state->aspath.rtlabelid);
+                       state->aspath.rtlabelid = rtlabel_ref(set->action.id);
                        break;
                case ACTION_SET_ORIGIN:
-                       asp->origin = set->action.origin;
+                       state->aspath.origin = set->action.origin;
                        break;
                case ACTION_SET_EXT_COMMUNITY:
-                       community_ext_set(asp, &set->action.ext_community,
+                       community_ext_set(&state->aspath, &set->action.ext_community,
                            peer->conf.remote_as);
                        break;
                case ACTION_DEL_EXT_COMMUNITY:
-                       community_ext_delete(asp, &set->action.ext_community,
+                       community_ext_delete(&state->aspath, &set->action.ext_community,
                            peer->conf.remote_as);
                        break;
                }
@@ -629,6 +634,20 @@ rde_filter_equal(struct filter_head *a, struct filter_head *b,
        return (1);
 }
 
+void
+rde_filterstate_prep(struct filterstate *state, struct rde_aspath *asp)
+{
+       memset(state, 0, sizeof(*state));
+
+       path_copy(path_prep(&state->aspath), asp);
+}
+
+void
+rde_filterstate_clean(struct filterstate *state)
+{
+       path_clean(&state->aspath);
+}
+
 void
 filterlist_free(struct filter_head *fh)
 {
@@ -983,15 +1002,12 @@ rde_filter_calc_skip_steps(struct filter_head *rules)
 
 enum filter_actions
 rde_filter(struct filter_head *rules, struct rde_peer *peer,
-    struct rde_aspath **new, struct prefix *p)
+    struct prefix *p, struct filterstate *state)
 {
        struct filter_rule      *f;
        struct rde_aspath       *asp = prefix_aspath(p);
        enum filter_actions      action = ACTION_DENY; /* default deny */
 
-       if (new != NULL)
-               *new = NULL;
-
        if (asp->flags & F_ATTR_PARSE_ERR)
                /*
                 * don't try to filter bad updates just deny them
@@ -1018,15 +1034,9 @@ rde_filter(struct filter_head *rules, struct rde_peer *peer,
                     f->skip[RDE_FILTER_SKIP_PEERID].ptr);
 
                if (rde_filter_match(f, peer, asp, p)) {
-                       if (asp != NULL && new != NULL) {
-                               /* asp may get modified so create a copy */
-                               if (*new == NULL) {
-                                       *new = path_copy(path_get(), asp);
-                                       /* ... and use the copy from now on */
-                                       asp = *new;
-                               }
-                               rde_apply_set(&f->set, asp, p->re->prefix->aid,
-                                   prefix_peer(p), peer);
+                       if (state != NULL) {
+                               rde_apply_set(&f->set, state,
+                                   p->re->prefix->aid, prefix_peer(p), peer);
                        }
                        if (f->action != ACTION_NONE)
                                action = f->action;
index 94cb628..6c8cb13 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_rib.c,v 1.165 2018/06/29 11:45:50 claudio Exp $ */
+/*     $OpenBSD: rde_rib.c,v 1.166 2018/07/09 14:08:48 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -693,13 +693,9 @@ path_get(void)
        return (path_prep(asp));
 }
 
-/* free an unlinked element */
 void
-path_put(struct rde_aspath *asp)
+path_clean(struct rde_aspath *asp)
 {
-       if (asp == NULL)
-               return;
-
        if (asp->flags & F_ATTR_LINKED)
                fatalx("path_put: linked object");
 
@@ -708,6 +704,17 @@ path_put(struct rde_aspath *asp)
        aspath_put(asp->aspath);
        nexthop_put(asp->nexthop);
        attr_freeall(asp);
+}
+
+/* free an unlinked element */
+void
+path_put(struct rde_aspath *asp)
+{
+       if (asp == NULL)
+               return;
+
+       path_clean(asp);
+
        rdemem.path_cnt--;
        free(asp);
 }
index c3c88bf..c30d1db 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_update.c,v 1.93 2018/06/28 09:54:48 claudio Exp $ */
+/*     $OpenBSD: rde_update.c,v 1.94 2018/07/09 14:08:48 claudio Exp $ */
 
 /*
  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -398,8 +398,8 @@ void
 up_generate_updates(struct filter_head *rules, struct rde_peer *peer,
     struct prefix *new, struct prefix *old)
 {
-       struct rde_aspath               *asp, *fasp;
-       struct bgpd_addr                 addr;
+       struct filterstate              state;
+       struct bgpd_addr                addr;
 
        if (peer->state != PEER_UP)
                return;
@@ -410,7 +410,7 @@ withdraw:
                        return;
 
                pt_getaddr(old->re->prefix, &addr);
-               if (rde_filter(rules, peer, NULL, old) == ACTION_DENY)
+               if (rde_filter(rules, peer, old, NULL) == ACTION_DENY)
                        return;
 
                /* withdraw prefix */
@@ -425,20 +425,17 @@ withdraw:
                        return;
                }
 
-               asp = prefix_aspath(new);
-               if (rde_filter(rules, peer, &fasp, new) == ACTION_DENY) {
-                       path_put(fasp);
+               rde_filterstate_prep(&state, prefix_aspath(new));
+               if (rde_filter(rules, peer, new, &state) == ACTION_DENY) {
+                       rde_filterstate_clean(&state);
                        goto withdraw;
                }
-               if (fasp == NULL)
-                       fasp = asp;
 
                pt_getaddr(new->re->prefix, &addr);
-               up_generate(peer, fasp, &addr, new->re->prefix->prefixlen);
+               up_generate(peer, &state.aspath, &addr,
+                   new->re->prefix->prefixlen);
 
-               /* free modified aspath */
-               if (fasp != asp)
-                       path_put(fasp);
+               rde_filterstate_clean(&state);
        }
 }
 
@@ -451,7 +448,8 @@ void
 up_generate_default(struct filter_head *rules, struct rde_peer *peer,
     u_int8_t aid)
 {
-       struct rde_aspath       *asp, *fasp;
+       struct filterstate       state;
+       struct rde_aspath       *asp;
        struct prefix            p;
        struct rib_entry        *re;
        struct bgpd_addr         addr;
@@ -486,20 +484,16 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
        p.flags = 0;
 
        /* filter as usual */
-       if (rde_filter(rules, peer, &fasp, &p) == ACTION_DENY) {
-               path_put(fasp);
-               path_put(asp);
+       rde_filterstate_prep(&state, asp);
+       if (rde_filter(rules, peer, &p, &state) == ACTION_DENY) {
+               rde_filterstate_clean(&state);
                return;
        }
 
-       if (fasp == NULL)
-               fasp = asp;
-
-       up_generate(peer, fasp, &addr, 0);
+       up_generate(peer, &state.aspath, &addr, 0);
 
        /* no longer needed */
-       if (fasp != asp)
-               path_put(fasp);
+       rde_filterstate_clean(&state);
        path_put(asp);
 
        if (rib_empty(re))