With the last commit the rde_aspath no longer needs to have a list of
prefixes and also the peer no longer need to have a list of aspaths.
This diff removes both and replaces the list of prefixes with a refcount.
The big benefit of this is that struct rde_aspath can now be shared
between sessions and ribs. This is an important set for Adj-RIB-Out
support.

-- 
:wq Claudio

? obj
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.350
diff -u -p -r1.350 bgpd.h
--- bgpd.h      26 Oct 2018 16:53:55 -0000      1.350
+++ bgpd.h      29 Oct 2018 09:46:35 -0000
@@ -1066,6 +1066,7 @@ extern struct rib_names ribnames;
 
 struct rde_memstats {
        int64_t         path_cnt;
+       int64_t         path_refs;
        int64_t         prefix_cnt;
        int64_t         rib_cnt;
        int64_t         pt_cnt[AID_MAX];
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.443
diff -u -p -r1.443 rde.c
--- rde.c       29 Oct 2018 09:28:31 -0000      1.443
+++ rde.c       29 Oct 2018 09:46:36 -0000
@@ -3283,7 +3283,6 @@ peer_add(u_int32_t id, struct peer_confi
        if (peer == NULL)
                fatal("peer_add");
 
-       TAILQ_INIT(&peer->path_h);
        memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
        peer->remote_bgpid = 0;
        peer->loc_rib_id = rib_find(peer->conf.rib);
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.200
diff -u -p -r1.200 rde.h
--- rde.h       29 Oct 2018 09:28:31 -0000      1.200
+++ rde.h       29 Oct 2018 09:46:36 -0000
@@ -76,9 +76,7 @@ struct rib_desc {
 LIST_HEAD(rde_peer_head, rde_peer);
 LIST_HEAD(aspath_list, aspath);
 LIST_HEAD(attr_list, attr);
-TAILQ_HEAD(prefix_queue, prefix);
 LIST_HEAD(aspath_head, rde_aspath);
-TAILQ_HEAD(aspath_queue, rde_aspath);
 RB_HEAD(uptree_prefix, update_prefix);
 RB_HEAD(uptree_attr, update_attr);
 RB_HEAD(uptree_rib, update_rib);
@@ -89,7 +87,6 @@ TAILQ_HEAD(uplist_attr, update_attr);
 struct rde_peer {
        LIST_ENTRY(rde_peer)             hash_l; /* hash list over all peers */
        LIST_ENTRY(rde_peer)             peer_l; /* list of all peers */
-       struct aspath_queue              path_h; /* list of all as paths */
        struct peer_config               conf;
        struct bgpd_addr                 remote_addr;
        struct bgpd_addr                 local_v4_addr;
@@ -209,10 +206,7 @@ struct mpattr {
 
 struct rde_aspath {
        LIST_ENTRY(rde_aspath)           path_l;
-       TAILQ_ENTRY(rde_aspath)          peer_l;
-       struct prefix_queue              prefixes;
        struct attr                     **others;
-       struct rde_peer                 *peer;
        struct aspath                   *aspath;
        u_int64_t                        hash;
        u_int32_t                        flags;         /* internally used */
@@ -220,6 +214,7 @@ struct rde_aspath {
        u_int32_t                        med;           /* multi exit disc */
        u_int32_t                        lpref;         /* local pref */
        u_int32_t                        weight;        /* low prio lpref */
+       int                              refcnt;
        u_int16_t                        rtlabelid;     /* route label id */
        u_int16_t                        pftableid;     /* pf table id */
        u_int8_t                         origin;
@@ -291,7 +286,6 @@ struct pt_entry_vpn4 {
 
 struct prefix {
        LIST_ENTRY(prefix)               rib_l, nexthop_l;
-       TAILQ_ENTRY(prefix)              path_l;
        struct rib_entry                *re;
        struct rde_aspath               *aspath;
        struct rde_peer                 *peer;
@@ -479,7 +473,6 @@ int          path_update(struct rib *, struct r
                     struct filterstate *, struct bgpd_addr *, int, u_int8_t);
 int             path_compare(struct rde_aspath *, struct rde_aspath *);
 u_int32_t       path_remove_stale(struct rde_aspath *, u_int8_t, time_t);
-void            path_destroy(struct rde_aspath *);
 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 *);
Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.182
diff -u -p -r1.182 rde_rib.c
--- rde_rib.c   29 Oct 2018 09:28:31 -0000      1.182
+++ rde_rib.c   29 Oct 2018 09:46:36 -0000
@@ -208,6 +208,8 @@ rib_free(struct rib *rib)
                                break;
                }
        }
+       if (rib->id <= RIB_LOC_START)
+               return; /* never remove the first three ribs */
        rd = &ribs[rib->id];
        filterlist_free(rd->in_rules_tmp);
        filterlist_free(rd->in_rules);
@@ -464,7 +466,8 @@ rib_dump_terminate(u_int16_t id, void *a
 
 static struct rde_aspath *path_lookup(struct rde_aspath *, struct rde_peer *);
 static u_int64_t path_hash(struct rde_aspath *);
-static void path_link(struct rde_aspath *, struct rde_peer *);
+static void path_link(struct rde_aspath *);
+static void path_unlink(struct rde_aspath *);
 
 struct path_table {
        struct aspath_head      *path_hashtbl;
@@ -473,7 +476,27 @@ struct path_table {
 
 SIPHASH_KEY pathtablekey;
 
-#define PATH_HASH(x)   &pathtable.path_hashtbl[x & pathtable.path_hashmask]
+#define        PATH_HASH(x)    &pathtable.path_hashtbl[x & 
pathtable.path_hashmask]
+
+#define        path_empty(asp) ((asp)->refcnt <= 0)
+
+static inline void
+path_ref(struct rde_aspath *asp)
+{
+       if ((asp->flags & F_ATTR_LINKED) == 0)
+               fatalx("%s: unlinked object", __func__);
+       asp->refcnt++;
+       rdemem.path_refs++;
+}
+
+static inline void
+path_unref(struct rde_aspath *asp)
+{
+       if ((asp->flags & F_ATTR_LINKED) == 0)
+               fatalx("%s: unlinked object", __func__);
+       asp->refcnt--;
+       rdemem.path_refs--;
+}
 
 void
 path_init(u_int32_t hashsize)
@@ -564,7 +587,7 @@ path_update(struct rib *rib, struct rde_
        if ((asp = path_lookup(nasp, peer)) == NULL) {
                /* Path not available, create and link a new one. */
                asp = path_copy(path_get(), nasp);
-               path_link(asp, peer);
+               path_link(asp);
        }
 
        /* If the prefix was found move it else add it to the aspath. */
@@ -662,57 +685,43 @@ path_lookup(struct rde_aspath *aspath, s
        head = PATH_HASH(hash);
 
        LIST_FOREACH(asp, head, path_l) {
-               if (asp->hash == hash && peer == asp->peer &&
-                   path_compare(aspath, asp) == 0)
+               if (asp->hash == hash && path_compare(aspath, asp) == 0)
                        return (asp);
        }
        return (NULL);
 }
 
 /*
- * This function can only called when all prefix have been removed first.
- * Normally this happens directly out of the prefix removal functions.
+ * Link this aspath into the global hash table.
+ * The asp had to be alloced with path_get.
  */
-void
-path_destroy(struct rde_aspath *asp)
+static void
+path_link(struct rde_aspath *asp)
 {
-       /* path_destroy can only unlink and free empty rde_aspath */
-       if (!TAILQ_EMPTY(&asp->prefixes))
-               log_warnx("path_destroy: still has prefixes, leaking");
-
-       LIST_REMOVE(asp, path_l);
-       TAILQ_REMOVE(&asp->peer->path_h, asp, peer_l);
-       asp->peer = NULL;
-       asp->flags &= ~F_ATTR_LINKED;
+       struct aspath_head      *head;
 
-       path_put(asp);
-}
+       asp->hash = path_hash(asp);
+       head = PATH_HASH(asp->hash);
 
-int
-path_empty(struct rde_aspath *asp)
-{
-       return TAILQ_EMPTY(&asp->prefixes);
+       LIST_INSERT_HEAD(head, asp, path_l);
+       asp->flags |= F_ATTR_LINKED;
 }
 
 /*
- * the path object is linked into multiple lists for fast access.
- * 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
+ * This function can only be called when all prefix have been removed first.
+ * Normally this happens directly out of the prefix removal functions.
  */
 static void
-path_link(struct rde_aspath *asp, struct rde_peer *peer)
+path_unlink(struct rde_aspath *asp)
 {
-       struct aspath_head      *head;
+       /* make sure no reference is hold for this rde_aspath */
+       if (!path_empty(asp))
+               fatalx("%s: still has prefixes", __func__);
 
-       asp->peer = peer;
-
-       asp->hash = path_hash(asp);
-       head = PATH_HASH(asp->hash);
+       LIST_REMOVE(asp, path_l);
+       asp->flags &= ~F_ATTR_LINKED;
 
-       LIST_INSERT_HEAD(head, asp, path_l);
-       TAILQ_INSERT_HEAD(&peer->path_h, asp, peer_l);
-       asp->flags |= F_ATTR_LINKED;
+       path_put(asp);
 }
 
 /*
@@ -737,6 +746,8 @@ path_copy(struct rde_aspath *dst, const 
        dst->pftableid = pftable_ref(src->pftableid);
 
        dst->flags = src->flags & ~F_ATTR_LINKED;
+       dst->refcnt = 0;        /* not linked so no refcnt */
+
        attr_copy(dst, src);
 
        return (dst);
@@ -747,7 +758,6 @@ struct rde_aspath *
 path_prep(struct rde_aspath *asp)
 {
        memset(asp, 0, sizeof(*asp));
-       TAILQ_INIT(&asp->prefixes);
        asp->origin = ORIGIN_INCOMPLETE;
        asp->lpref = DEFAULT_LPREF;
 
@@ -768,11 +778,12 @@ path_get(void)
        return (path_prep(asp));
 }
 
+/* clean up an asp after use (frees all references to sub-objects) */
 void
 path_clean(struct rde_aspath *asp)
 {
        if (asp->flags & F_ATTR_LINKED)
-               fatalx("path_clean: linked object");
+               fatalx("%s: linked object", __func__);
 
        rtlabel_unref(asp->rtlabelid);
        pftable_unref(asp->pftableid);
@@ -832,7 +843,7 @@ prefix_add(struct bgpd_addr *prefix, int
        if (re == NULL)
                re = rib_add(rib, prefix, prefixlen);
 
-       p = prefix_bypeer(re, asp->peer);
+       p = prefix_bypeer(re, peer);
        if (p == NULL) {
                p = prefix_alloc();
                prefix_link(p, re, peer, asp, state, vstate);
@@ -873,8 +884,8 @@ prefix_move(struct prefix *p, struct rde
        np->nhflags = state->nhflags;
        np->validation_state = vstate;
 
-       /* add to new as path */
-       TAILQ_INSERT_HEAD(&asp->prefixes, np, path_l);
+       /* add reference to new as path */
+       path_ref(asp);
 
        /*
         * no need to update the peer prefix count because we are only moving
@@ -894,7 +905,7 @@ prefix_move(struct prefix *p, struct rde
 
        /* remove old prefix node */
        oasp = prefix_aspath(p);
-       TAILQ_REMOVE(&oasp->prefixes, p, path_l);
+       path_unref(oasp);
        /* as before peer count needs no update because of move */
 
        /* destroy all references to other objects and free the old prefix */
@@ -908,7 +919,7 @@ prefix_move(struct prefix *p, struct rde
 
        /* destroy old path if empty */
        if (path_empty(oasp))
-               path_destroy(oasp);
+               path_unlink(oasp);
 
        return (0);
 }
@@ -1089,7 +1100,7 @@ prefix_destroy(struct prefix *p)
        prefix_free(p);
 
        if (path_empty(asp))
-               path_destroy(asp);
+               path_unlink(asp);
 }
 
 /*
@@ -1099,7 +1110,7 @@ static void
 prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_peer *peer,
     struct rde_aspath *asp, struct filterstate *state, u_int8_t vstate)
 {
-       TAILQ_INSERT_HEAD(&asp->prefixes, pref, path_l);
+       path_ref(asp);
 
        pref->aspath = asp;
        pref->peer = peer;
@@ -1121,15 +1132,13 @@ static void
 prefix_unlink(struct prefix *pref)
 {
        struct rib_entry        *re = pref->re;
-       struct prefix_queue     *pq;
 
        /* make route decision */
        LIST_REMOVE(pref, rib_l);
        prefix_evaluate(NULL, re);
 
-       pq = &prefix_aspath(pref)->prefixes;
+       path_unref(prefix_aspath(pref));
 
-       TAILQ_REMOVE(pq, pref, path_l);
        if (rib_empty(re))
                rib_remove(re);
 

Reply via email to