Move nexthop and nexthop flags from the rde_aspath to struct prefix.
authorclaudio <claudio@openbsd.org>
Fri, 3 Aug 2018 16:31:22 +0000 (16:31 +0000)
committerclaudio <claudio@openbsd.org>
Fri, 3 Aug 2018 16:31:22 +0000 (16:31 +0000)
struct prefix will be slowly becomming the hub of the rib.
OK phessler@ job@

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 bdb405e..b149451 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.407 2018/08/03 14:10:39 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.408 2018/08/03 16:31:22 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -991,7 +991,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, NULL);
+       rde_filterstate_prep(&state, NULL, NULL, 0);
        if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
                /* parse path attributes */
                while (len > 0) {
@@ -1306,7 +1306,8 @@ 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, in->nexthop);
+               rde_filterstate_prep(&state, &in->aspath, in->nexthop,
+                   in->nhflags);
                /* input filter */
                action = rde_filter(ribs[i].in_rules, peer, p, &state);
 
@@ -2100,7 +2101,8 @@ 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), prefix_nexthop(p));
+       rde_filterstate_prep(&state, prefix_aspath(p), prefix_nexthop(p),
+           prefix_nhflags(p));
        a = rde_filter(out_rules, peer, p, &state);
 
        if (a == ACTION_ALLOW)
@@ -2421,9 +2423,9 @@ rde_send_kroute(struct rib *rib, struct prefix *new, struct prefix *old)
        bzero(&kr, sizeof(kr));
        memcpy(&kr.prefix, &addr, sizeof(kr.prefix));
        kr.prefixlen = p->re->prefix->prefixlen;
-       if (asp->flags & F_NEXTHOP_REJECT)
+       if (prefix_nhflags(p) == NEXTHOP_REJECT)
                kr.flags |= F_REJECT;
-       if (asp->flags & F_NEXTHOP_BLACKHOLE)
+       if (prefix_nhflags(p) == NEXTHOP_BLACKHOLE)
                kr.flags |= F_BLACKHOLE;
        if (type == IMSG_KROUTE_CHANGE)
                memcpy(&kr.nexthop, &prefix_nexthop(p)->true_nexthop,
@@ -2889,7 +2891,8 @@ rde_softreconfig_in(struct rib_entry *re, void *bula)
                        if (*rib->name == '\0')
                                break;
 
-                       rde_filterstate_prep(&state, asp, prefix_nexthop(p));
+                       rde_filterstate_prep(&state, asp, prefix_nexthop(p),
+                           prefix_nhflags(p));
                        action = rde_filter(rib->in_rules, peer, p, &state);
 
                        if (action == ACTION_ALLOW) {
@@ -2922,8 +2925,10 @@ rde_softreconfig_out_peer(struct rib_entry *re, struct rde_peer *peer)
        if (up_test_update(peer, p) != 1)
                return;
 
-       rde_filterstate_prep(&ostate, prefix_aspath(p), prefix_nexthop(p));
-       rde_filterstate_prep(&nstate, prefix_aspath(p), prefix_nexthop(p));
+       rde_filterstate_prep(&ostate, prefix_aspath(p), prefix_nexthop(p),
+           prefix_nhflags(p));
+       rde_filterstate_prep(&nstate, prefix_aspath(p), prefix_nexthop(p),
+           prefix_nhflags(p));
        oa = rde_filter(out_rules_tmp, peer, p, &ostate);
        na = rde_filter(out_rules, peer, p, &nstate);
 
@@ -2937,17 +2942,10 @@ rde_softreconfig_out_peer(struct rib_entry *re, struct rde_peer *peer)
                /* 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)
+               /* send update if anything changed */
+               if (nstate.nhflags != ostate.nhflags ||
+                   nstate.nexthop != ostate.nexthop ||
+                   path_compare(&nstate.aspath, &ostate.aspath) != 0)
                        up_generate(peer, &nstate, &addr, pt->prefixlen);
        }
 
@@ -2985,7 +2983,8 @@ 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), prefix_nexthop(p));
+       rde_filterstate_prep(&ostate, prefix_aspath(p), prefix_nexthop(p),
+           prefix_nhflags(p));
        if (rde_filter(out_rules_tmp, peer, p, &ostate) != ACTION_DENY) {
                /* send withdraw */
                up_generate(peer, NULL, &addr, pt->prefixlen);
@@ -3461,7 +3460,7 @@ network_add(struct network_config *nc, int flagstatic)
        }
        if (!flagstatic)
                asp->flags |= F_ANN_DYNAMIC;
-       rde_filterstate_prep(&state, asp, NULL); /* nexthop is not set */
+       rde_filterstate_prep(&state, asp, NULL, 0); /* 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 aece90b..551beb0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.h,v 1.182 2018/07/31 15:30:04 claudio Exp $ */
+/*     $OpenBSD: rde.h,v 1.183 2018/08/03 16:31:22 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -166,11 +166,6 @@ struct mpattr {
 #define        F_ATTR_LOOP             0x00200 /* path would cause a route loop */
 #define        F_PREFIX_ANNOUNCED      0x00400
 #define        F_ANN_DYNAMIC           0x00800
-#define        F_NEXTHOP_SELF          0x01000
-#define        F_NEXTHOP_REJECT        0x02000
-#define        F_NEXTHOP_BLACKHOLE     0x04000
-#define        F_NEXTHOP_NOMODIFY      0x08000
-#define        F_NEXTHOP_MASK          0x0f000
 #define        F_ATTR_PARSE_ERR        0x10000 /* parse error, not eligable */
 #define        F_ATTR_LINKED           0x20000 /* if set path is on various lists */
 #define        F_ATTR_UPDATE           0x20000 /* if set linked on update_l */
@@ -183,13 +178,12 @@ struct mpattr {
 #define DEFAULT_LPREF          100
 
 struct rde_aspath {
-       LIST_ENTRY(rde_aspath)           path_l, nexthop_l;
+       LIST_ENTRY(rde_aspath)           path_l;
        TAILQ_ENTRY(rde_aspath)          peer_l, update_l;
        struct prefix_queue              prefixes, updates;
        struct attr                     **others;
        struct rde_peer                 *peer;
        struct aspath                   *aspath;
-       struct nexthop                  *nexthop;       /* may be NULL */
        u_int64_t                        hash;
        u_int32_t                        flags;         /* internally used */
        u_int32_t                        med;           /* multi exit disc */
@@ -209,7 +203,7 @@ enum nexthop_state {
 
 struct nexthop {
        LIST_ENTRY(nexthop)     nexthop_l;
-       struct aspath_head      path_h;
+       struct prefix_list      prefix_h;
        struct bgpd_addr        exit_nexthop;
        struct bgpd_addr        true_nexthop;
        struct bgpd_addr        nexthop_net;
@@ -303,21 +297,28 @@ struct rib_desc {
 #define RIB_LOC_START  2
 
 struct prefix {
-       LIST_ENTRY(prefix)               rib_l;
+       LIST_ENTRY(prefix)               rib_l, nexthop_l;
        TAILQ_ENTRY(prefix)              path_l;
        struct rib_entry                *re;
        struct rde_aspath               *aspath;
        struct rde_peer                 *peer;
+       struct nexthop                  *nexthop;       /* may be NULL */
        time_t                           lastchange;
-       int                              flags;
+       u_int8_t                         flags;
+       u_int8_t                         nhflags;
 };
 
 #define F_PREFIX_USE_UPDATES   0x01    /* linked onto the updates list */
 
+#define        NEXTHOP_SELF            0x01
+#define        NEXTHOP_REJECT          0x02
+#define        NEXTHOP_BLACKHOLE       0x04
+#define        NEXTHOP_NOMODIFY        0x08
+
 struct filterstate {
-       struct rde_aspath       aspath;
+       struct rde_aspath        aspath;
        struct nexthop          *nexthop;
-       unsigned int            nhflags;
+       u_int8_t                 nhflags;
 };
 
 extern struct rde_memstats rdemem;
@@ -401,7 +402,8 @@ 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 *,                    struct nexthop *);
+void            rde_filterstate_prep(struct filterstate *, struct rde_aspath *,
+                    struct nexthop *, u_int8_t);
 void            rde_filterstate_clean(struct filterstate *);
 enum filter_actions rde_filter(struct filter_head *, struct rde_peer *,
                     struct prefix *, struct filterstate *);
@@ -490,12 +492,18 @@ int                prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t, int);
 int             prefix_writebuf(struct ibuf *, struct bgpd_addr *, u_int8_t);
 struct prefix  *prefix_bypeer(struct rib_entry *, struct rde_peer *,
                     u_int32_t);
-void            prefix_updateall(struct rde_aspath *, enum nexthop_state,
+void            prefix_updateall(struct prefix *, enum nexthop_state,
                     enum nexthop_state);
 void            prefix_destroy(struct prefix *);
 void            prefix_network_clean(struct rde_peer *, time_t, u_int32_t);
 void            prefix_relink(struct prefix *, struct rde_aspath *, int);
 
+static inline struct rde_peer *
+prefix_peer(struct prefix *p)
+{
+       return (p->peer);
+}
+
 static inline struct rde_aspath *
 prefix_aspath(struct prefix *p)
 {
@@ -505,21 +513,21 @@ prefix_aspath(struct prefix *p)
 static inline struct nexthop *
 prefix_nexthop(struct prefix *p)
 {
-       return (p->aspath->nexthop);
+       return (p->nexthop);
 }
 
-static inline struct rde_peer *
-prefix_peer(struct prefix *p)
+static inline u_int8_t
+prefix_nhflags(struct prefix *p)
 {
-       return (p->peer);
+       return (p->nhflags);
 }
 
 void            nexthop_init(u_int32_t);
 void            nexthop_shutdown(void);
 void            nexthop_modify(struct nexthop *, enum action_types, u_int8_t,
-                   struct nexthop **, u_int32_t *);
-void            nexthop_link(struct rde_aspath *);
-void            nexthop_unlink(struct rde_aspath *);
+                   struct nexthop **, u_int8_t *);
+void            nexthop_link(struct prefix *);
+void            nexthop_unlink(struct prefix *);
 void            nexthop_update(struct kroute_nexthop *);
 struct nexthop *nexthop_get(struct bgpd_addr *);
 struct nexthop *nexthop_ref(struct nexthop *);
index c67a19d..5d287b6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_filter.c,v 1.98 2018/08/02 14:41:42 claudio Exp $ */
+/*     $OpenBSD: rde_filter.c,v 1.99 2018/08/03 16:31:22 claudio Exp $ */
 
 /*
  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -640,7 +640,7 @@ rde_filter_equal(struct filter_head *a, struct filter_head *b,
 
 void
 rde_filterstate_prep(struct filterstate *state, struct rde_aspath *asp,
-    struct nexthop *nh)
+    struct nexthop *nh, u_int8_t nhflags)
 {
        memset(state, 0, sizeof(*state));
 
@@ -648,9 +648,7 @@ rde_filterstate_prep(struct filterstate *state, struct rde_aspath *asp,
        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;
+       state->nhflags = nhflags;
 }
 
 void
index f566017..1efcd0f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_rib.c,v 1.172 2018/07/22 16:59:08 claudio Exp $ */
+/*     $OpenBSD: rde_rib.c,v 1.173 2018/08/03 16:31:22 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -48,9 +48,11 @@ struct rib_entry *rib_restart(struct rib_context *);
 RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare);
 RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare);
 
-int             prefix_add(struct rib *, struct rde_aspath *,
-                   struct bgpd_addr *, int, int);
-void            prefix_move(struct rde_aspath *, struct prefix *, int);
+int             prefix_add(struct bgpd_addr *, int, struct rib *,
+                   struct rde_peer *, struct rde_aspath *,
+                   struct filterstate *, int);
+int             prefix_move(struct prefix *, struct rde_peer *,
+                   struct rde_aspath *, struct filterstate *, int);
 
 static inline void
 re_lock(struct rib_entry *re)
@@ -423,11 +425,6 @@ 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();
@@ -437,7 +434,9 @@ path_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
         * First try to find a prefix in the specified RIB.
         */
        if ((p = prefix_get(rib, peer, prefix, prefixlen, 0)) != NULL) {
-               if (path_compare(nasp, prefix_aspath(p)) == 0) {
+               if (path_compare(nasp, prefix_aspath(p)) == 0 &&
+                   prefix_nexthop(p) == state->nexthop &&
+                   prefix_nhflags(p) == state->nhflags) {
                        /* no change, update last change */
                        p->lastchange = time(NULL);
                        return (0);
@@ -457,10 +456,10 @@ path_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
 
        /* If the prefix was found move it else add it to the aspath. */
        if (p != NULL)
-               prefix_move(asp, p, pflag);
+               return (prefix_move(p, peer, asp, state, pflag));
        else
-               return (prefix_add(rib, asp, prefix, prefixlen, pflag));
-       return (0);
+               return (prefix_add(prefix, prefixlen, rib, peer, asp,
+                   state, pflag));
 }
 
 int
@@ -506,8 +505,6 @@ path_compare(struct rde_aspath *a, struct rde_aspath *b)
                return (-1);
 
        r = aspath_compare(a->aspath, b->aspath);
-       if (r == 0)
-               r = nexthop_compare(a->nexthop, b->nexthop);
        if (r > 0)
                return (1);
        if (r < 0)
@@ -658,7 +655,6 @@ path_destroy(struct rde_aspath *asp)
        if (!TAILQ_EMPTY(&asp->prefixes) || !TAILQ_EMPTY(&asp->updates))
                log_warnx("path_destroy: still has prefixes, leaking");
 
-       nexthop_unlink(asp);
        LIST_REMOVE(asp, path_l);
        TAILQ_REMOVE(&asp->peer->path_h, asp, peer_l);
        asp->peer = NULL;
@@ -678,7 +674,6 @@ path_empty(struct rde_aspath *asp)
  * These are peer_l, path_l and nexthop_l.
  * peer_l: list of all aspaths that belong to that peer
  * path_l: hash list to find paths quickly
- * nexthop_l: list of all aspaths with an equal exit nexthop
  */
 static void
 path_link(struct rde_aspath *asp, struct rde_peer *peer)
@@ -692,7 +687,6 @@ path_link(struct rde_aspath *asp, struct rde_peer *peer)
 
        LIST_INSERT_HEAD(head, asp, path_l);
        TAILQ_INSERT_HEAD(&peer->path_h, asp, peer_l);
-       nexthop_link(asp);
        asp->flags |= F_ATTR_LINKED;
 }
 
@@ -708,7 +702,6 @@ path_copy(struct rde_aspath *dst, const struct rde_aspath *src)
                dst->aspath->refcnt++;
                rdemem.aspath_refs++;
        }
-       dst->nexthop = nexthop_ref(src->nexthop);
        dst->hash = 0;
        dst->med = src->med;
        dst->lpref = src->lpref;
@@ -759,7 +752,6 @@ path_clean(struct rde_aspath *asp)
        rtlabel_unref(asp->rtlabelid);
        pftable_unref(asp->pftableid);
        aspath_put(asp->aspath);
-       nexthop_put(asp->nexthop);
        attr_freeall(asp);
 }
 
@@ -781,7 +773,8 @@ path_put(struct rde_aspath *asp)
 static struct prefix   *prefix_alloc(void);
 static void             prefix_free(struct prefix *);
 static void             prefix_link(struct prefix *, struct rib_entry *,
-                            struct rde_aspath *, int);
+                            struct rde_peer *, struct rde_aspath *,
+                            struct filterstate *, int);
 static void             prefix_unlink(struct prefix *);
 
 /*
@@ -803,9 +796,9 @@ prefix_get(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix,
  * Adds or updates a prefix.
  */
 int
-prefix_add(struct rib *rib, struct rde_aspath *asp, struct bgpd_addr *prefix,
-    int prefixlen, int flag)
-
+prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
+    struct rde_peer *peer, struct rde_aspath *asp, struct filterstate *state,
+    int flag)
 {
        struct prefix           *p;
        struct rib_entry        *re;
@@ -817,14 +810,16 @@ prefix_add(struct rib *rib, struct rde_aspath *asp, struct bgpd_addr *prefix,
        p = prefix_bypeer(re, asp->peer, asp->flags);
        if (p == NULL) {
                p = prefix_alloc();
-               prefix_link(p, re, asp, flag);
+               prefix_link(p, re, peer, asp, state, flag);
                return (1);
        } else {
-               if (prefix_aspath(p) != asp) {
-                       /* prefix belongs to a different aspath so move */
-                       prefix_move(asp, p, flag);
-               } else
-                       p->lastchange = time(NULL);
+               if (prefix_aspath(p) != asp ||
+                   prefix_nexthop(p) != state->nexthop ||
+                   prefix_nhflags(p) != state->nhflags) {
+                       /* prefix metadata changed therefor move */
+                       return (prefix_move(p, peer, asp, state, flag));
+               } 
+               p->lastchange = time(NULL);
                return (0);
        }
 }
@@ -832,22 +827,25 @@ prefix_add(struct rib *rib, struct rde_aspath *asp, struct bgpd_addr *prefix,
 /*
  * Move the prefix to the specified as path, removes the old asp if needed.
  */
-void
-prefix_move(struct rde_aspath *asp, struct prefix *p, int flag)
+int
+prefix_move(struct prefix *p, struct rde_peer *peer,
+    struct rde_aspath *asp, struct filterstate *state, int flag)
 {
        struct prefix           *np;
        struct rde_aspath       *oasp;
 
-       if (asp->peer != prefix_peer(p))
+       if (peer != prefix_peer(p))
                fatalx("prefix_move: cross peer move");
 
-       /* create new prefix node */
        np = prefix_alloc();
        np->aspath = asp;
-       np->peer = asp->peer;
+       np->nexthop = nexthop_ref(state->nexthop);
+       nexthop_link(np);
+       np->peer = peer;
        np->re = p->re;
        np->lastchange = time(NULL);
        np->flags = flag;
+       np->nhflags = state->nhflags;
 
        /* add to new as path */
        if (np->flags & F_PREFIX_USE_UPDATES)
@@ -882,11 +880,16 @@ prefix_move(struct rde_aspath *asp, struct prefix *p, int flag)
        p->aspath = NULL;
        p->peer = NULL;
        p->re = NULL;
+       nexthop_unlink(p);
+       nexthop_put(p->nexthop);
+       p->nexthop = NULL;
        prefix_free(p);
 
        /* destroy old path if empty */
        if (path_empty(oasp))
                path_destroy(oasp);
+
+       return (0);
 }
 
 /*
@@ -1020,47 +1023,43 @@ prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, u_int32_t flags)
 }
 
 void
-prefix_updateall(struct rde_aspath *asp, enum nexthop_state state,
+prefix_updateall(struct prefix *p, enum nexthop_state state,
     enum nexthop_state oldstate)
 {
-       struct prefix   *p;
-
-       TAILQ_FOREACH(p, &asp->prefixes, path_l) {
-               /*
-                * Skip non local-RIBs or RIBs that are flagged as noeval.
-                * There is no need to run over updates since that is only
-                * used on the Adj-RIB-Out.
-                */
-               if (re_rib(p->re)->flags & F_RIB_NOEVALUATE)
-                       continue;
-
-               if (oldstate == state && state == NEXTHOP_REACH) {
-                       /*
-                        * The state of the nexthop did not change. The only
-                        * thing that may have changed is the true_nexthop
-                        * or other internal infos. This will not change
-                        * the routing decision so shortcut here.
-                        */
-                       if ((re_rib(p->re)->flags & F_RIB_NOFIB) == 0 &&
-                           p == p->re->active)
-                               rde_send_kroute(re_rib(p->re), p, NULL);
-                       continue;
-               }
+       /*
+        * Skip non local-RIBs or RIBs that are flagged as noeval.
+        * There is no need to run over updates since that is only
+        * used on the Adj-RIB-Out.
+        */
+       if (re_rib(p->re)->flags & F_RIB_NOEVALUATE)
+               return;
 
-               /* redo the route decision */
-               LIST_REMOVE(p, rib_l);
+       if (oldstate == state && state == NEXTHOP_REACH) {
                /*
-                * If the prefix is the active one remove it first,
-                * this has to be done because we can not detect when
-                * the active prefix changes its state. In this case
-                * we know that this is a withdrawal and so the second
-                * prefix_evaluate() will generate no update because
-                * the nexthop is unreachable or ineligible.
+                * The state of the nexthop did not change. The only
+                * thing that may have changed is the true_nexthop
+                * or other internal infos. This will not change
+                * the routing decision so shortcut here.
                 */
-               if (p == p->re->active)
-                       prefix_evaluate(NULL, p->re);
-               prefix_evaluate(p, p->re);
+               if ((re_rib(p->re)->flags & F_RIB_NOFIB) == 0 &&
+                   p == p->re->active)
+                       rde_send_kroute(re_rib(p->re), p, NULL);
+               return;
        }
+
+       /* redo the route decision */
+       LIST_REMOVE(p, rib_l);
+       /*
+        * If the prefix is the active one remove it first,
+        * this has to be done because we can not detect when
+        * the active prefix changes its state. In this case
+        * we know that this is a withdrawal and so the second
+        * prefix_evaluate() will generate no update because
+        * the nexthop is unreachable or ineligible.
+        */
+       if (p == p->re->active)
+               prefix_evaluate(NULL, p->re);
+       prefix_evaluate(p, p->re);
 }
 
 /* kill a prefix. */
@@ -1107,8 +1106,8 @@ prefix_network_clean(struct rde_peer *peer, time_t reloadtime, u_int32_t flags)
  * Link a prefix into the different parent objects.
  */
 static void
-prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp,
-    int flag)
+prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_peer *peer,
+    struct rde_aspath *asp, struct filterstate *state, int flag)
 {
        if (flag & F_PREFIX_USE_UPDATES)
                TAILQ_INSERT_HEAD(&asp->updates, pref, path_l);
@@ -1116,10 +1115,13 @@ prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp,
                TAILQ_INSERT_HEAD(&asp->prefixes, pref, path_l);
 
        pref->aspath = asp;
-       pref->peer = asp->peer;
+       pref->peer = peer;
+       pref->nexthop = nexthop_ref(state->nexthop);
+       nexthop_link(pref);
        pref->re = re;
        pref->lastchange = time(NULL);
        pref->flags = flag;
+       pref->nhflags = state->nhflags;
 
        /* make route decision */
        prefix_evaluate(pref, re);
@@ -1148,6 +1150,9 @@ prefix_unlink(struct prefix *pref)
                rib_remove(re);
 
        /* destroy all references to other objects */
+       nexthop_unlink(pref);
+       nexthop_put(pref->nexthop);
+       pref->nexthop = NULL;
        pref->aspath = NULL;
        pref->peer = NULL;
        pref->re = NULL;
@@ -1248,7 +1253,7 @@ void
 nexthop_update(struct kroute_nexthop *msg)
 {
        struct nexthop          *nh;
-       struct rde_aspath       *asp;
+       struct prefix           *p;
        enum nexthop_state       oldstate;
 
        nh = nexthop_lookup(&msg->nexthop);
@@ -1289,28 +1294,27 @@ nexthop_update(struct kroute_nexthop *msg)
                 */
                return;
 
-       LIST_FOREACH(asp, &nh->path_h, nexthop_l) {
-               prefix_updateall(asp, nh->state, oldstate);
+       LIST_FOREACH(p, &nh->prefix_h, nexthop_l) {
+               prefix_updateall(p, nh->state, oldstate);
        }
 }
 
 void
 nexthop_modify(struct nexthop *setnh, enum action_types type, u_int8_t aid,
-    struct nexthop **nexthop, u_int32_t *flags)
+    struct nexthop **nexthop, u_int8_t *flags)
 {
-       *flags &= ~F_NEXTHOP_MASK;
        switch (type) {
        case ACTION_SET_NEXTHOP_REJECT:
-               *flags |= F_NEXTHOP_REJECT;
+               *flags NEXTHOP_REJECT;
                break;
        case ACTION_SET_NEXTHOP_BLACKHOLE:
-               *flags |= F_NEXTHOP_BLACKHOLE;
+               *flags NEXTHOP_BLACKHOLE;
                break;
        case ACTION_SET_NEXTHOP_NOMODIFY:
-               *flags |= F_NEXTHOP_NOMODIFY;
+               *flags NEXTHOP_NOMODIFY;
                break;
        case ACTION_SET_NEXTHOP_SELF:
-               *flags |= F_NEXTHOP_SELF;
+               *flags NEXTHOP_SELF;
                break;
        case ACTION_SET_NEXTHOP:
                /*
@@ -1321,6 +1325,7 @@ nexthop_modify(struct nexthop *setnh, enum action_types type, u_int8_t aid,
                        break;
                nexthop_put(*nexthop);
                *nexthop = nexthop_ref(setnh);
+               *flags = 0;
                break;
        default:
                break;
@@ -1328,29 +1333,21 @@ nexthop_modify(struct nexthop *setnh, enum action_types type, u_int8_t aid,
 }
 
 void
-nexthop_link(struct rde_aspath *asp)
+nexthop_link(struct prefix *p)
 {
-       if (asp->nexthop == NULL)
+       if (p->nexthop == NULL)
                return;
 
-       LIST_INSERT_HEAD(&asp->nexthop->path_h, asp, nexthop_l);
+       LIST_INSERT_HEAD(&p->nexthop->prefix_h, p, nexthop_l);
 }
 
 void
-nexthop_unlink(struct rde_aspath *asp)
+nexthop_unlink(struct prefix *p)
 {
-       struct nexthop  *nh;
-
-       if (asp->nexthop == NULL)
+       if (p->nexthop == NULL)
                return;
 
-       LIST_REMOVE(asp, nexthop_l);
-
-       /* remove reference to nexthop */
-       nh = asp->nexthop;
-       asp->nexthop = NULL;
-
-       (void)nexthop_put(nh);
+       LIST_REMOVE(p, nexthop_l);
 }
 
 struct nexthop *
@@ -1365,7 +1362,7 @@ nexthop_get(struct bgpd_addr *nexthop)
                        fatal("nexthop_alloc");
                rdemem.nexthop_cnt++;
 
-               LIST_INIT(&nh->path_h);
+               LIST_INIT(&nh->prefix_h);
                nh->state = NEXTHOP_LOOKUP;
                nexthop_ref(nh);        /* take reference for lookup */
                nh->exit_nexthop = *nexthop;
@@ -1396,7 +1393,7 @@ nexthop_put(struct nexthop *nh)
                return (0);
 
        /* sanity check */
-       if (!LIST_EMPTY(&nh->path_h) || nh->state == NEXTHOP_LOOKUP)
+       if (!LIST_EMPTY(&nh->prefix_h) || nh->state == NEXTHOP_LOOKUP)
                fatalx("nexthop_put: refcnt error");
 
        LIST_REMOVE(nh, nexthop_l);
index c4af0dd..d7270fb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_update.c,v 1.95 2018/07/22 16:59:08 claudio Exp $ */
+/*     $OpenBSD: rde_update.c,v 1.96 2018/08/03 16:31:22 claudio Exp $ */
 
 /*
  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -426,7 +426,7 @@ withdraw:
                }
 
                rde_filterstate_prep(&state, prefix_aspath(new),
-                   prefix_nexthop(new));
+                   prefix_nexthop(new), prefix_nhflags(new));
                if (rde_filter(rules, peer, new, &state) == ACTION_DENY) {
                        rde_filterstate_clean(&state);
                        goto withdraw;
@@ -485,7 +485,7 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
        p.flags = 0;
 
        /* filter as usual */
-       rde_filterstate_prep(&state, asp, NULL);
+       rde_filterstate_prep(&state, asp, NULL, 0);
        if (rde_filter(rules, peer, &p, &state) == ACTION_DENY) {
                rde_filterstate_clean(&state);
                return;
@@ -547,13 +547,13 @@ up_get_nexthop(struct rde_peer *peer, struct filterstate *state)
        in_addr_t       mask;
 
        /* nexthop, already network byte order */
-       if (state->nhflags & F_NEXTHOP_NOMODIFY) {
+       if (state->nhflags & NEXTHOP_NOMODIFY) {
                /* no modify flag set */
                if (state->nexthop == NULL)
                        return (peer->local_v4_addr.v4.s_addr);
                else
                        return (state->nexthop->exit_nexthop.v4.s_addr);
-       } else if (state->nhflags & F_NEXTHOP_SELF)
+       } else if (state->nhflags & NEXTHOP_SELF)
                return (peer->local_v4_addr.v4.s_addr);
        else if (!peer->conf.ebgp) {
                /*
@@ -616,7 +616,7 @@ 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 (state->nhflags & F_NEXTHOP_NOMODIFY) {
+               if (state->nhflags & NEXTHOP_NOMODIFY) {
                        /* no modify flag set */
                        if (state->nexthop == NULL)
                                memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
@@ -625,7 +625,7 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
                                memcpy(&upa->mpattr[4],
                                    &state->nexthop->exit_nexthop.v6,
                                    sizeof(struct in6_addr));
-               } else if (state->nhflags & F_NEXTHOP_SELF)
+               } else if (state->nhflags & NEXTHOP_SELF)
                        memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
                            sizeof(struct in6_addr));
                else if (!peer->conf.ebgp) {
@@ -675,7 +675,7 @@ 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 (state->nhflags & F_NEXTHOP_NOMODIFY) {
+               if (state->nhflags & NEXTHOP_NOMODIFY) {
                        /* no modify flag set */
                        if (state->nexthop == NULL)
                                memcpy(&upa->mpattr[12],
@@ -686,7 +686,7 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
                                memcpy(&upa->mpattr[12],
                                    &state->nexthop->exit_nexthop.v4,
                                    sizeof(struct in_addr));
-               } else if (state->nhflags & F_NEXTHOP_SELF)
+               } else if (state->nhflags & NEXTHOP_SELF)
                        memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4,
                            sizeof(struct in_addr));
                else if (!peer->conf.ebgp) {