Move nexthop into struct filterstate (including nexthop flags) and use
authorclaudio <claudio@openbsd.org>
Sun, 22 Jul 2018 16:59:08 +0000 (16:59 +0000)
committerclaudio <claudio@openbsd.org>
Sun, 22 Jul 2018 16:59:08 +0000 (16:59 +0000)
them whereever possible. In some places (path_update, softreconfig_out
handler) the nexthop state is temporarily folded back into the rde_aspath.
Tested and OK benno@

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 686c1be..899e45d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.398 2018/07/22 06:03:17 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.399 2018/07/22 16:59:08 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -990,7 +990,7 @@ rde_update_dispatch(struct imsg *imsg)
            imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;
        bzero(&mpa, sizeof(mpa));
 
-       rde_filterstate_prep(&state, NULL);
+       rde_filterstate_prep(&state, NULL, NULL);
        if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
                /* parse path attributes */
                while (len > 0) {
@@ -1213,14 +1213,9 @@ rde_update_dispatch(struct imsg *imsg)
                        goto done;
                }
 
-               /*
-                * this works because asp is not linked.
-                * But first unlock the previously locked nexthop.
-                */
-               if (state.aspath.nexthop) {
-                       (void)nexthop_put(state.aspath.nexthop);
-                       state.aspath.nexthop = NULL;
-               }
+               /* unlock the previously locked nexthop, it is no longer used */
+               (void)nexthop_put(state.nexthop);
+               state.nexthop = NULL;
                if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, &state)) == -1) {
                        log_peer_warnx(&peer->conf, "bad nlri nexthop");
                        rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
@@ -1310,13 +1305,13 @@ rde_update_update(struct rde_peer *peer, struct filterstate *in,
        for (i = RIB_LOC_START; i < rib_size; i++) {
                if (*ribs[i].name == '\0')
                        break;
-               rde_filterstate_prep(&state, &in->aspath);
+               rde_filterstate_prep(&state, &in->aspath, in->nexthop);
                /* input filter */
                action = rde_filter(ribs[i].in_rules, peer, p, &state);
 
                if (action == ACTION_ALLOW) {
                        rde_update_log("update", i, peer,
-                           &state.aspath.nexthop->exit_nexthop, prefix,
+                           &state.nexthop->exit_nexthop, prefix,
                            prefixlen);
                        path_update(&ribs[i].rib, peer, &state, prefix,
                            prefixlen, 0);
@@ -1491,7 +1486,8 @@ bad_flags:
                            op, len);
                        return (-1);
                }
-               a->nexthop = nexthop_get(&nexthop);
+               nexthop_put(state->nexthop);    /* just to be sure */
+               state->nexthop = nexthop_get(&nexthop);
                break;
        case ATTR_MED:
                if (attr_len != 4)
@@ -1824,7 +1820,8 @@ rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int8_t aid,
                return (-1);
        }
 
-       state->aspath.nexthop = nexthop_get(&nexthop);
+       nexthop_put(state->nexthop);    /* just to be sure */
+       state->nexthop = nexthop_get(&nexthop);
 
        /* ignore reserved (old SNPA) field as per RFC4760 */
        totlen += nhlen + 1;
@@ -2102,7 +2099,7 @@ rde_dump_filterout(struct rde_peer *peer, struct prefix *p,
        if (up_test_update(peer, p) != 1)
                return;
 
-       rde_filterstate_prep(&state, prefix_aspath(p));
+       rde_filterstate_prep(&state, prefix_aspath(p), prefix_nexthop(p));
        a = rde_filter(out_rules, peer, p, &state);
 
        if (a == ACTION_ALLOW)
@@ -2857,7 +2854,7 @@ rde_softreconfig_in(struct rib_entry *re, void *ptr)
                asp = prefix_aspath(p);
                peer = asp->peer;
 
-               rde_filterstate_prep(&state, asp);
+               rde_filterstate_prep(&state, asp, prefix_nexthop(p));
                action = rde_filter(rib->in_rules, peer, p, &state);
 
                if (action == ACTION_ALLOW) {
@@ -2895,8 +2892,8 @@ rde_softreconfig_out(struct rib_entry *re, void *ptr)
        if (up_test_update(peer, p) != 1)
                return;
 
-       rde_filterstate_prep(&ostate, prefix_aspath(p));
-       rde_filterstate_prep(&nstate, prefix_aspath(p));
+       rde_filterstate_prep(&ostate, prefix_aspath(p), prefix_nexthop(p));
+       rde_filterstate_prep(&nstate, prefix_aspath(p), prefix_nexthop(p));
        oa = rde_filter(out_rules_tmp, peer, p, &ostate);
        na = rde_filter(out_rules, peer, p, &nstate);
 
@@ -2905,14 +2902,23 @@ rde_softreconfig_out(struct rib_entry *re, void *ptr)
                /* nothing todo */
        if (oa == ACTION_DENY && na == ACTION_ALLOW) {
                /* send update */
-               up_generate(peer, &nstate.aspath, &addr, pt->prefixlen);
+               up_generate(peer, &nstate, &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) {
+               /* XXX update nexthop for now, ugly but will go away */
+               nexthop_put(nstate.aspath.nexthop);
+               nstate.aspath.nexthop = nexthop_ref(nstate.nexthop);
+               nstate.aspath.flags = (nstate.aspath.flags & ~F_NEXTHOP_MASK) |
+                   (nstate.nhflags & F_NEXTHOP_MASK);
+               nexthop_put(ostate.aspath.nexthop);
+               ostate.aspath.nexthop = nexthop_ref(ostate.nexthop);
+               ostate.aspath.flags = (ostate.aspath.flags & ~F_NEXTHOP_MASK) |
+                   (ostate.nhflags & F_NEXTHOP_MASK);
                /* send update if path attributes changed */
                if (path_compare(&nstate.aspath, &ostate.aspath) != 0)
-                       up_generate(peer, &nstate.aspath, &addr, pt->prefixlen);
+                       up_generate(peer, &nstate, &addr, pt->prefixlen);
        }
 
        rde_filterstate_clean(&ostate);
@@ -2935,7 +2941,7 @@ rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
        if (up_test_update(peer, p) != 1)
                return;
 
-       rde_filterstate_prep(&ostate, prefix_aspath(p));
+       rde_filterstate_prep(&ostate, prefix_aspath(p), prefix_nexthop(p));
        if (rde_filter(out_rules_tmp, peer, p, &ostate) != ACTION_DENY) {
                /* send withdraw */
                up_generate(peer, NULL, &addr, pt->prefixlen);
@@ -3410,7 +3416,7 @@ network_add(struct network_config *nc, int flagstatic)
        }
        if (!flagstatic)
                asp->flags |= F_ANN_DYNAMIC;
-       rde_filterstate_prep(&state, asp);
+       rde_filterstate_prep(&state, asp, NULL); /* nexthop is not set */
        rde_apply_set(&nc->attrset, &state, nc->prefix.aid, peerself, peerself);
        if (vpnset)
                rde_apply_set(vpnset, &state, nc->prefix.aid, peerself,
index fbcdb94..5d933b4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.h,v 1.180 2018/07/20 14:58:20 claudio Exp $ */
+/*     $OpenBSD: rde.h,v 1.181 2018/07/22 16:59:08 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -316,6 +316,8 @@ struct prefix {
 
 struct filterstate {
        struct rde_aspath       aspath;
+       struct nexthop          *nexthop;
+       unsigned int            nhflags;
 };
 
 extern struct rde_memstats rdemem;
@@ -399,7 +401,7 @@ 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_prep(struct filterstate *, struct rde_aspath *,                    struct nexthop *);
 void            rde_filterstate_clean(struct filterstate *);
 enum filter_actions rde_filter(struct filter_head *, struct rde_peer *,
                     struct prefix *, struct filterstate *);
@@ -500,6 +502,12 @@ prefix_aspath(struct prefix *p)
        return (p->aspath);
 }
 
+static inline struct nexthop *
+prefix_nexthop(struct prefix *p)
+{
+       return (p->aspath->nexthop);
+}
+
 static inline struct rde_peer *
 prefix_peer(struct prefix *p)
 {
@@ -522,7 +530,7 @@ int          nexthop_compare(struct nexthop *, struct nexthop *);
 void            up_init(struct rde_peer *);
 void            up_down(struct rde_peer *);
 int             up_test_update(struct rde_peer *, struct prefix *);
-int             up_generate(struct rde_peer *, struct rde_aspath *,
+int             up_generate(struct rde_peer *, struct filterstate *,
                     struct bgpd_addr *, u_int8_t);
 void            up_generate_updates(struct filter_head *, struct rde_peer *,
                     struct prefix *, struct prefix *);
index 53bf0b0..4ba3129 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_filter.c,v 1.96 2018/07/16 09:09:20 claudio Exp $ */
+/*     $OpenBSD: rde_filter.c,v 1.97 2018/07/22 16:59:08 claudio Exp $ */
 
 /*
  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -30,7 +30,7 @@
 #include "log.h"
 
 int    rde_filter_match(struct filter_rule *, struct rde_peer *,
-           struct rde_aspath *, struct prefix *);
+           struct filterstate *, struct prefix *);
 int    rde_prefix_match(struct filter_prefix *, struct prefix *);
 int    filterset_equal(struct filter_set_head *, struct filter_set_head *);
 
@@ -139,7 +139,7 @@ rde_apply_set(struct filter_set_head *sh, struct filterstate *state,
                case ACTION_SET_NEXTHOP_NOMODIFY:
                case ACTION_SET_NEXTHOP_SELF:
                        nexthop_modify(set->action.nh, set->type, aid,
-                           &state->aspath.nexthop, &state->aspath.flags);
+                           &state->nexthop, &state->nhflags);
                        break;
                case ACTION_SET_COMMUNITY:
                        switch (set->action.community.as) {
@@ -338,12 +338,16 @@ rde_apply_set(struct filter_set_head *sh, struct filterstate *state,
 
 int
 rde_filter_match(struct filter_rule *f, struct rde_peer *peer,
-    struct rde_aspath *asp, struct prefix *p)
+    struct filterstate *state, struct prefix *p)
 {
        u_int32_t       pas;
        int             cas, type;
        int64_t         las, ld1, ld2;
-       struct prefixset_item *psi;
+       struct prefixset_item   *psi;
+       struct rde_aspath       *asp = NULL;
+
+       if (state != NULL)
+               asp = &state->aspath;
 
        if (asp != NULL && f->match.as.type != AS_NONE) {
                if (f->match.as.flags & AS_FLAG_NEIGHBORAS)
@@ -355,10 +359,10 @@ rde_filter_match(struct filter_rule *f, struct rde_peer *peer,
                        return (0);
        }
 
-       if (asp != NULL && f->peer.ebgp && !peer->conf.ebgp)
-                       return (0);
-       if (asp != NULL && f->peer.ibgp && peer->conf.ebgp)
-                       return (0);
+       if (f->peer.ebgp && !peer->conf.ebgp)
+               return (0);
+       if (f->peer.ibgp && peer->conf.ebgp)
+               return (0);
 
        if (asp != NULL && f->match.aslen.type != ASLEN_NONE)
                if (aspath_lenmatch(asp->aspath, f->match.aslen.type,
@@ -450,12 +454,12 @@ rde_filter_match(struct filter_rule *f, struct rde_peer *peer,
                        return (0);
        }
 
-       if (f->match.nexthop.flags != 0) {
+       if (state != NULL && f->match.nexthop.flags != 0) {
                struct bgpd_addr *nexthop, *cmpaddr;
-               if (asp != NULL && asp->nexthop == NULL)
+               if (state->nexthop == NULL)
                        /* no nexthop, skip */
                        return (0);
-               nexthop = &asp->nexthop->exit_nexthop;
+               nexthop = &state->nexthop->exit_nexthop;
                if (f->match.nexthop.flags == FILTER_NEXTHOP_ADDR)
                        cmpaddr = &f->match.nexthop.addr;
                else
@@ -635,19 +639,26 @@ rde_filter_equal(struct filter_head *a, struct filter_head *b,
 }
 
 void
-rde_filterstate_prep(struct filterstate *state, struct rde_aspath *asp)
+rde_filterstate_prep(struct filterstate *state, struct rde_aspath *asp,
+    struct nexthop *nh)
 {
        memset(state, 0, sizeof(*state));
 
        path_prep(&state->aspath);
        if (asp)
                path_copy(&state->aspath, asp);
+       state->nexthop = nexthop_ref(nh);
+       /* XXX the flag handling needs improvement */
+       if (asp)
+               state->nhflags |= asp->flags & F_NEXTHOP_MASK;
 }
 
 void
 rde_filterstate_clean(struct filterstate *state)
 {
        path_clean(&state->aspath);
+       nexthop_put(state->nexthop);
+       state->nexthop = NULL;
 }
 
 void
@@ -1007,10 +1018,9 @@ rde_filter(struct filter_head *rules, struct rde_peer *peer,
     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 (asp->flags & F_ATTR_PARSE_ERR)
+       if (state && state->aspath.flags & F_ATTR_PARSE_ERR)
                /*
                 * don't try to filter bad updates just deny them
                 * so they act as implicit withdraws
@@ -1035,7 +1045,7 @@ rde_filter(struct filter_head *rules, struct rde_peer *peer,
                     f->peer.peerid != peer->conf.id),
                     f->skip[RDE_FILTER_SKIP_PEERID].ptr);
 
-               if (rde_filter_match(f, peer, asp, p)) {
+               if (rde_filter_match(f, peer, state, p)) {
                        if (state != NULL) {
                                rde_apply_set(&f->set, state,
                                    p->re->prefix->aid, prefix_peer(p), peer);
index 10757a3..f566017 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_rib.c,v 1.171 2018/07/16 09:09:20 claudio Exp $ */
+/*     $OpenBSD: rde_rib.c,v 1.172 2018/07/22 16:59:08 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -423,6 +423,11 @@ path_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
        struct prefix           *p;
        int                      pflag = 0;
 
+       nexthop_put(nasp->nexthop);
+       nasp->nexthop = nexthop_ref(state->nexthop);
+       nasp->flags = (nasp->flags & ~F_NEXTHOP_MASK) |
+           (state->nhflags & F_NEXTHOP_MASK);
+
        if (nasp->pftableid) {
                rde_send_pftable(nasp->pftableid, prefix, prefixlen, 0);
                rde_send_pftable_commit();
@@ -1467,4 +1472,3 @@ nexthop_hash(struct bgpd_addr *nexthop)
        }
        return (&nexthoptable.nexthop_hashtbl[h & nexthoptable.nexthop_hashmask]);
 }
-
index c30d1db..c4af0dd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_update.c,v 1.94 2018/07/09 14:08:48 claudio Exp $ */
+/*     $OpenBSD: rde_update.c,v 1.95 2018/07/22 16:59:08 claudio Exp $ */
 
 /*
  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
 #include "rde.h"
 #include "log.h"
 
-in_addr_t      up_get_nexthop(struct rde_peer *, struct rde_aspath *);
+in_addr_t      up_get_nexthop(struct rde_peer *, struct filterstate *);
 int            up_generate_mp_reach(struct rde_peer *, struct update_attr *,
-                   struct rde_aspath *, u_int8_t);
+                   struct filterstate *, u_int8_t);
 int            up_generate_attr(struct rde_peer *, struct update_attr *,
-                   struct rde_aspath *, u_int8_t);
+                   struct filterstate *, u_int8_t);
 
 /* update stuff. */
 struct update_prefix {
@@ -354,19 +354,19 @@ up_test_update(struct rde_peer *peer, struct prefix *p)
 }
 
 int
-up_generate(struct rde_peer *peer, struct rde_aspath *asp,
+up_generate(struct rde_peer *peer, struct filterstate *state,
     struct bgpd_addr *addr, u_int8_t prefixlen)
 {
        struct update_attr              *ua = NULL;
        struct update_prefix            *up;
        SIPHASH_CTX                     ctx;
 
-       if (asp) {
+       if (state) {
                ua = calloc(1, sizeof(struct update_attr));
                if (ua == NULL)
                        fatal("up_generate");
 
-               if (up_generate_attr(peer, ua, asp, addr->aid) == -1) {
+               if (up_generate_attr(peer, ua, state, addr->aid) == -1) {
                        log_warnx("generation of bgp path attributes failed");
                        free(ua);
                        return (-1);
@@ -425,14 +425,15 @@ withdraw:
                        return;
                }
 
-               rde_filterstate_prep(&state, prefix_aspath(new));
+               rde_filterstate_prep(&state, prefix_aspath(new),
+                   prefix_nexthop(new));
                if (rde_filter(rules, peer, new, &state) == ACTION_DENY) {
                        rde_filterstate_clean(&state);
                        goto withdraw;
                }
 
                pt_getaddr(new->re->prefix, &addr);
-               up_generate(peer, &state.aspath, &addr,
+               up_generate(peer, &state, &addr,
                    new->re->prefix->prefixlen);
 
                rde_filterstate_clean(&state);
@@ -484,13 +485,13 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
        p.flags = 0;
 
        /* filter as usual */
-       rde_filterstate_prep(&state, asp);
+       rde_filterstate_prep(&state, asp, NULL);
        if (rde_filter(rules, peer, &p, &state) == ACTION_DENY) {
                rde_filterstate_clean(&state);
                return;
        }
 
-       up_generate(peer, &state.aspath, &addr, 0);
+       up_generate(peer, &state, &addr, 0);
 
        /* no longer needed */
        rde_filterstate_clean(&state);
@@ -541,27 +542,27 @@ u_char    up_attr_buf[4096];
 
 /* only for IPv4 */
 in_addr_t
-up_get_nexthop(struct rde_peer *peer, struct rde_aspath *a)
+up_get_nexthop(struct rde_peer *peer, struct filterstate *state)
 {
        in_addr_t       mask;
 
        /* nexthop, already network byte order */
-       if (a->flags & F_NEXTHOP_NOMODIFY) {
+       if (state->nhflags & F_NEXTHOP_NOMODIFY) {
                /* no modify flag set */
-               if (a->nexthop == NULL)
+               if (state->nexthop == NULL)
                        return (peer->local_v4_addr.v4.s_addr);
                else
-                       return (a->nexthop->exit_nexthop.v4.s_addr);
-       } else if (a->flags & F_NEXTHOP_SELF)
+                       return (state->nexthop->exit_nexthop.v4.s_addr);
+       } else if (state->nhflags & F_NEXTHOP_SELF)
                return (peer->local_v4_addr.v4.s_addr);
        else if (!peer->conf.ebgp) {
                /*
                 * If directly connected use peer->local_v4_addr
                 * this is only true for announced networks.
                 */
-               if (a->nexthop == NULL)
+               if (state->nexthop == NULL)
                        return (peer->local_v4_addr.v4.s_addr);
-               else if (a->nexthop->exit_nexthop.v4.s_addr ==
+               else if (state->nexthop->exit_nexthop.v4.s_addr ==
                    peer->remote_addr.v4.s_addr)
                        /*
                         * per RFC: if remote peer address is equal to
@@ -570,17 +571,17 @@ up_get_nexthop(struct rde_peer *peer, struct rde_aspath *a)
                         */
                        return (peer->local_v4_addr.v4.s_addr);
                else
-                       return (a->nexthop->exit_nexthop.v4.s_addr);
+                       return (state->nexthop->exit_nexthop.v4.s_addr);
        } else if (peer->conf.distance == 1) {
                /* ebgp directly connected */
-               if (a->nexthop != NULL &&
-                   a->nexthop->flags & NEXTHOP_CONNECTED) {
+               if (state->nexthop != NULL &&
+                   state->nexthop->flags & NEXTHOP_CONNECTED) {
                        mask = htonl(
-                           prefixlen2mask(a->nexthop->nexthop_netlen));
+                           prefixlen2mask(state->nexthop->nexthop_netlen));
                        if ((peer->remote_addr.v4.s_addr & mask) ==
-                           (a->nexthop->nexthop_net.v4.s_addr & mask))
+                           (state->nexthop->nexthop_net.v4.s_addr & mask))
                                /* nexthop and peer are in the same net */
-                               return (a->nexthop->exit_nexthop.v4.s_addr);
+                               return (state->nexthop->exit_nexthop.v4.s_addr);
                        else
                                return (peer->local_v4_addr.v4.s_addr);
                } else
@@ -597,7 +598,7 @@ up_get_nexthop(struct rde_peer *peer, struct rde_aspath *a)
 
 int
 up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
-    struct rde_aspath *a, u_int8_t aid)
+    struct filterstate *state, u_int8_t aid)
 {
        u_int16_t       tmp;
 
@@ -615,43 +616,43 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
                upa->mpattr[20] = 0; /* Reserved must be 0 */
 
                /* nexthop dance see also up_get_nexthop() */
-               if (a->flags & F_NEXTHOP_NOMODIFY) {
+               if (state->nhflags & F_NEXTHOP_NOMODIFY) {
                        /* no modify flag set */
-                       if (a->nexthop == NULL)
+                       if (state->nexthop == NULL)
                                memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
                                    sizeof(struct in6_addr));
                        else
                                memcpy(&upa->mpattr[4],
-                                   &a->nexthop->exit_nexthop.v6,
+                                   &state->nexthop->exit_nexthop.v6,
                                    sizeof(struct in6_addr));
-               } else if (a->flags & F_NEXTHOP_SELF)
+               } else if (state->nhflags & F_NEXTHOP_SELF)
                        memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
                            sizeof(struct in6_addr));
                else if (!peer->conf.ebgp) {
                        /* ibgp */
-                       if (a->nexthop == NULL ||
-                           (a->nexthop->exit_nexthop.aid == AID_INET6 &&
-                           !memcmp(&a->nexthop->exit_nexthop.v6,
+                       if (state->nexthop == NULL ||
+                           (state->nexthop->exit_nexthop.aid == AID_INET6 &&
+                           !memcmp(&state->nexthop->exit_nexthop.v6,
                            &peer->remote_addr.v6, sizeof(struct in6_addr))))
                                memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
                                    sizeof(struct in6_addr));
                        else
                                memcpy(&upa->mpattr[4],
-                                   &a->nexthop->exit_nexthop.v6,
+                                   &state->nexthop->exit_nexthop.v6,
                                    sizeof(struct in6_addr));
                } else if (peer->conf.distance == 1) {
                        /* ebgp directly connected */
-                       if (a->nexthop != NULL &&
-                           a->nexthop->flags & NEXTHOP_CONNECTED)
+                       if (state->nexthop != NULL &&
+                           state->nexthop->flags & NEXTHOP_CONNECTED)
                                if (prefix_compare(&peer->remote_addr,
-                                   &a->nexthop->nexthop_net,
-                                   a->nexthop->nexthop_netlen) == 0) {
+                                   &state->nexthop->nexthop_net,
+                                   state->nexthop->nexthop_netlen) == 0) {
                                        /*
                                         * nexthop and peer are in the same
                                         * subnet
                                         */
                                        memcpy(&upa->mpattr[4],
-                                           &a->nexthop->exit_nexthop.v6,
+                                           &state->nexthop->exit_nexthop.v6,
                                            sizeof(struct in6_addr));
                                        return (0);
                                }
@@ -674,46 +675,46 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
                upa->mpattr[3] = sizeof(u_int64_t) + sizeof(struct in_addr);
 
                /* nexthop dance see also up_get_nexthop() */
-               if (a->flags & F_NEXTHOP_NOMODIFY) {
+               if (state->nhflags & F_NEXTHOP_NOMODIFY) {
                        /* no modify flag set */
-                       if (a->nexthop == NULL)
+                       if (state->nexthop == NULL)
                                memcpy(&upa->mpattr[12],
                                    &peer->local_v4_addr.v4,
                                    sizeof(struct in_addr));
                        else
                                /* nexthops are stored as IPv4 addrs */
                                memcpy(&upa->mpattr[12],
-                                   &a->nexthop->exit_nexthop.v4,
+                                   &state->nexthop->exit_nexthop.v4,
                                    sizeof(struct in_addr));
-               } else if (a->flags & F_NEXTHOP_SELF)
+               } else if (state->nhflags & F_NEXTHOP_SELF)
                        memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4,
                            sizeof(struct in_addr));
                else if (!peer->conf.ebgp) {
                        /* ibgp */
-                       if (a->nexthop == NULL ||
-                           (a->nexthop->exit_nexthop.aid == AID_INET &&
-                           !memcmp(&a->nexthop->exit_nexthop.v4,
+                       if (state->nexthop == NULL ||
+                           (state->nexthop->exit_nexthop.aid == AID_INET &&
+                           !memcmp(&state->nexthop->exit_nexthop.v4,
                            &peer->remote_addr.v4, sizeof(struct in_addr))))
                                memcpy(&upa->mpattr[12],
                                    &peer->local_v4_addr.v4,
                                    sizeof(struct in_addr));
                        else
                                memcpy(&upa->mpattr[12],
-                                   &a->nexthop->exit_nexthop.v4,
+                                   &state->nexthop->exit_nexthop.v4,
                                    sizeof(struct in_addr));
                } else if (peer->conf.distance == 1) {
                        /* ebgp directly connected */
-                       if (a->nexthop != NULL &&
-                           a->nexthop->flags & NEXTHOP_CONNECTED)
+                       if (state->nexthop != NULL &&
+                           state->nexthop->flags & NEXTHOP_CONNECTED)
                                if (prefix_compare(&peer->remote_addr,
-                                   &a->nexthop->nexthop_net,
-                                   a->nexthop->nexthop_netlen) == 0) {
+                                   &state->nexthop->nexthop_net,
+                                   state->nexthop->nexthop_netlen) == 0) {
                                        /*
                                         * nexthop and peer are in the same
                                         * subnet
                                         */
                                        memcpy(&upa->mpattr[12],
-                                           &a->nexthop->exit_nexthop.v4,
+                                           &state->nexthop->exit_nexthop.v4,
                                            sizeof(struct in_addr));
                                        return (0);
                                }
@@ -732,8 +733,9 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
 
 int
 up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
-    struct rde_aspath *a, u_int8_t aid)
+    struct filterstate *state, u_int8_t aid)
 {
+       struct rde_aspath *asp = &state->aspath;
        struct attr     *oa, *newaggr = NULL;
        u_char          *pdata;
        u_int32_t        tmp32;
@@ -746,17 +748,17 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
 
        /* origin */
        if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,
-           ATTR_ORIGIN, &a->origin, 1)) == -1)
+           ATTR_ORIGIN, &asp->origin, 1)) == -1)
                return (-1);
        wlen += r; len -= r;
 
        /* aspath */
        if (!peer->conf.ebgp ||
            peer->conf.flags & PEERFLAG_TRANS_AS)
-               pdata = aspath_prepend(a->aspath, peer->conf.local_as, 0,
+               pdata = aspath_prepend(asp->aspath, peer->conf.local_as, 0,
                    &plen);
        else
-               pdata = aspath_prepend(a->aspath, peer->conf.local_as, 1,
+               pdata = aspath_prepend(asp->aspath, peer->conf.local_as, 1,
                    &plen);
 
        if (!rde_as4byte(peer))
@@ -770,7 +772,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
 
        switch (aid) {
        case AID_INET:
-               nexthop = up_get_nexthop(peer, a);
+               nexthop = up_get_nexthop(peer, state);
                if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,
                    ATTR_NEXTHOP, &nexthop, 4)) == -1)
                        return (-1);
@@ -786,10 +788,10 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
         * unless the MED is originating from us or the peer is an IBGP one.
         * Only exception are routers with "transparent-as yes" set.
         */
-       if (a->flags & F_ATTR_MED && (!peer->conf.ebgp ||
-           a->flags & F_ATTR_MED_ANNOUNCE ||
+       if (asp->flags & F_ATTR_MED && (!peer->conf.ebgp ||
+           asp->flags & F_ATTR_MED_ANNOUNCE ||
            peer->conf.flags & PEERFLAG_TRANS_AS)) {
-               tmp32 = htonl(a->med);
+               tmp32 = htonl(asp->med);
                if ((r = attr_write(up_attr_buf + wlen, len, ATTR_OPTIONAL,
                    ATTR_MED, &tmp32, 4)) == -1)
                        return (-1);
@@ -798,7 +800,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
 
        if (!peer->conf.ebgp) {
                /* local preference, only valid for ibgp */
-               tmp32 = htonl(a->lpref);
+               tmp32 = htonl(asp->lpref);
                if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,
                    ATTR_LOCALPREF, &tmp32, 4)) == -1)
                        return (-1);
@@ -814,8 +816,8 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
         *  3. transitive known attrs: announce unmodified
         *  4. transitive unknown attrs: set partial bit and re-announce
         */
-       for (l = 0; l < a->others_len; l++) {
-               if ((oa = a->others[l]) == NULL)
+       for (l = 0; l < asp->others_len; l++) {
+               if ((oa = asp->others[l]) == NULL)
                        break;
                switch (oa->type) {
                case ATTR_ATOMIC_AGGREGATE:
@@ -912,13 +914,13 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
        if (neednewpath) {
                if (!peer->conf.ebgp ||
                    peer->conf.flags & PEERFLAG_TRANS_AS)
-                       pdata = aspath_prepend(a->aspath, peer->conf.local_as,
+                       pdata = aspath_prepend(asp->aspath, peer->conf.local_as,
                            0, &plen);
                else
-                       pdata = aspath_prepend(a->aspath, peer->conf.local_as,
+                       pdata = aspath_prepend(asp->aspath, peer->conf.local_as,
                            1, &plen);
                flags = ATTR_OPTIONAL|ATTR_TRANSITIVE;
-               if (!(a->flags & F_PREFIX_ANNOUNCED))
+               if (!(asp->flags & F_PREFIX_ANNOUNCED))
                        flags |= ATTR_PARTIAL;
                if (plen == 0)
                        r = 0;
@@ -930,7 +932,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
        }
        if (newaggr) {
                flags = ATTR_OPTIONAL|ATTR_TRANSITIVE;
-               if (!(a->flags & F_PREFIX_ANNOUNCED))
+               if (!(asp->flags & F_PREFIX_ANNOUNCED))
                        flags |= ATTR_PARTIAL;
                if ((r = attr_write(up_attr_buf + wlen, len, flags,
                    ATTR_AS4_AGGREGATOR, newaggr->data, newaggr->len)) == -1)
@@ -940,7 +942,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
 
        /* write mp attribute to different buffer */
        if (ismp)
-               if (up_generate_mp_reach(peer, upa, a, aid) == -1)
+               if (up_generate_mp_reach(peer, upa, state, aid) == -1)
                        return (-1);
 
        /* the bgp path attributes are now stored in the global buf */