]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Split route data structure to storage (ro) / manipulation (rw) structures.
authorMaria Matejka <mq@jmq.cz>
Tue, 28 Jan 2020 10:42:46 +0000 (11:42 +0100)
committerMaria Matejka <mq@ucw.cz>
Tue, 9 Nov 2021 18:20:41 +0000 (19:20 +0100)
Routes are now allocated only when they are just to be inserted to the
table. Updating a route needs a locally allocated route structure.
Ownership of the attributes is also now not transfered from protocols to
tables and vice versa but just borrowed which should be easier to handle
in a multithreaded environment.

27 files changed:
filter/f-inst.c
filter/filter.c
filter/filter.h
nest/protocol.h
nest/route.h
nest/rt-dev.c
nest/rt-show.c
nest/rt-table.c
proto/babel/babel.c
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c
proto/mrt/mrt.c
proto/ospf/ospf.c
proto/ospf/rt.c
proto/ospf/topology.c
proto/ospf/topology.h
proto/perf/perf.c
proto/pipe/pipe.c
proto/radv/radv.c
proto/rip/rip.c
proto/rpki/rpki.c
proto/static/static.c
sysdep/bsd/krt-sock.c
sysdep/linux/netlink.c
sysdep/unix/krt.c
sysdep/unix/krt.h

index 938864948407ceefdd1592784a2d433697588890..00e22383d6b01b6e1ca5454f8bcb353e00160f53 100644 (file)
     {
       STATIC_ATTR;
       ACCESS_RTE;
-      struct rta *rta = (*fs->rte)->attrs;
+      struct rta *rta = fs->rte->attrs;
 
       switch (sa.sa_code)
       {
       case SA_FROM:    RESULT(sa.f_type, ip, rta->from); break;
       case SA_GW:      RESULT(sa.f_type, ip, rta->nh.gw); break;
-      case SA_NET:     RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
-      case SA_PROTO:   RESULT(sa.f_type, s, (*fs->rte)->src->proto->name); break;
+      case SA_NET:     RESULT(sa.f_type, net, fs->rte->net); break;
+      case SA_PROTO:   RESULT(sa.f_type, s, fs->rte->src->proto->name); break;
       case SA_SOURCE:  RESULT(sa.f_type, i, rta->source); break;
       case SA_SCOPE:   RESULT(sa.f_type, i, rta->scope); break;
       case SA_DEST:    RESULT(sa.f_type, i, rta->dest); break;
 
     f_rta_cow(fs);
     {
-      struct rta *rta = (*fs->rte)->attrs;
+      struct rta *rta = fs->rte->attrs;
 
       switch (sa.sa_code)
       {
        {
          ip_addr ip = v1.val.ip;
          struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
-         neighbor *n = neigh_find((*fs->rte)->src->proto, ip, ifa, 0);
+         neighbor *n = neigh_find(fs->rte->src->proto, ip, ifa, 0);
          if (!n || (n->scope == SCOPE_HOST))
            runtime( "Invalid gw address" );
 
     struct rtable *table = rtc->table;
     ACCESS_RTE;
     ACCESS_EATTRS;
-    const net_addr *net = (*fs->rte)->net->n.addr;
+    const net_addr *net = fs->rte->net;
 
     /* We ignore temporary attributes, probably not a problem here */
     /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
index 7004b96d63beb9f24307db2c364be9de144f7429..6f1e6ea051853a398469ff827f5ab1e5cbd41e43 100644 (file)
@@ -74,10 +74,7 @@ struct filter_state {
   } stack;
 
   /* The route we are processing. This may be NULL to indicate no route available. */
-  struct rte **rte;
-
-  /* The old rta to be freed after filters are done. */
-  struct rta *old_rta;
+  struct rte *rte;
 
   /* Cached pointer to ea_list */
   struct ea_list **eattrs;
@@ -102,15 +99,7 @@ void (*bt_assert_hook)(int result, const struct f_line_item *assert);
 
 static inline void f_cache_eattrs(struct filter_state *fs)
 {
-  fs->eattrs = &((*fs->rte)->attrs->eattrs);
-}
-
-static inline void f_rte_cow(struct filter_state *fs)
-{
-  if (!((*fs->rte)->flags & REF_COW))
-    return;
-
-  *fs->rte = rte_cow(*fs->rte);
+  fs->eattrs = &(fs->rte->attrs->eattrs);
 }
 
 /*
@@ -119,22 +108,16 @@ static inline void f_rte_cow(struct filter_state *fs)
 static void
 f_rta_cow(struct filter_state *fs)
 {
-  if (!rta_is_cached((*fs->rte)->attrs))
+  if (!rta_is_cached(fs->rte->attrs))
     return;
 
-  /* Prepare to modify rte */
-  f_rte_cow(fs);
-
-  /* Store old rta to free it later, it stores reference from rte_cow() */
-  fs->old_rta = (*fs->rte)->attrs;
-
   /*
    * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
    * with fs->old_rta (they will be copied when the cached rta will be obtained
    * at the end of f_run()), also the lock of hostentry is inherited (we
    * suppose hostentry is not changed by filters).
    */
-  (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool);
+  fs->rte->attrs = rta_do_cow(fs->rte->attrs, fs->pool);
 
   /* Re-cache the ea_list */
   f_cache_eattrs(fs);
@@ -246,29 +229,15 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
 /**
  * f_run - run a filter for a route
  * @filter: filter to run
- * @rte: route being filtered, may be modified
+ * @rte: route being filtered, must be write-able
  * @tmp_pool: all filter allocations go from this pool
  * @flags: flags
  *
- * If filter needs to modify the route, there are several
- * posibilities. @rte might be read-only (with REF_COW flag), in that
- * case rw copy is obtained by rte_cow() and @rte is replaced. If
- * @rte is originally rw, it may be directly modified (and it is never
- * copied).
- *
- * The returned rte may reuse the (possibly cached, cloned) rta, or
- * (if rta was modified) contains a modified uncached rta, which
- * uses parts allocated from @tmp_pool and parts shared from original
- * rta. There is one exception - if @rte is rw but contains a cached
- * rta and that is modified, rta in returned rte is also cached.
- *
- * Ownership of cached rtas is consistent with rte, i.e.
- * if a new rte is returned, it has its own clone of cached rta
- * (and cached rta of read-only source rte is intact), if rte is
- * modified in place, old cached rta is possibly freed.
+ * If @rte->attrs is cached, the returned rte allocates a new rta on
+ * tmp_pool, otherwise the filters may modify it.
  */
 enum filter_return
-f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
+f_run(const struct filter *filter, struct rte *rte, struct linpool *tmp_pool, int flags)
 {
   if (filter == FILTER_ACCEPT)
     return F_ACCEPT;
@@ -276,7 +245,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
   if (filter == FILTER_REJECT)
     return F_REJECT;
 
-  int rte_cow = ((*rte)->flags & REF_COW);
   DBG( "Running filter `%s'...", filter->name );
 
   /* Initialize the filter state */
@@ -293,32 +261,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
   /* Run the interpreter itself */
   enum filter_return fret = interpret(&filter_state, filter->root, NULL);
 
-  if (filter_state.old_rta) {
-    /*
-     * Cached rta was modified and filter_state->rte contains now an uncached one,
-     * sharing some part with the cached one. The cached rta should
-     * be freed (if rte was originally COW, filter_state->old_rta is a clone
-     * obtained during rte_cow()).
-     *
-     * This also implements the exception mentioned in f_run()
-     * description. The reason for this is that rta reuses parts of
-     * filter_state->old_rta, and these may be freed during rta_free(filter_state->old_rta).
-     * This is not the problem if rte was COW, because original rte
-     * also holds the same rta.
-     */
-    if (!rte_cow) {
-      /* Cache the new attrs */
-      (*filter_state.rte)->attrs = rta_lookup((*filter_state.rte)->attrs);
-
-      /* Drop cached ea_list pointer */
-      filter_state.eattrs = NULL;
-    }
-
-    /* Uncache the old attrs and drop the pointer as it is invalid now. */
-    rta_free(filter_state.old_rta);
-    filter_state.old_rta = NULL;
-  }
-
   /* Process the filter output, log it and return */
   if (fret < F_ACCEPT) {
     if (!(filter_state.flags & FF_SILENT))
@@ -343,7 +285,7 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
  */
 
 enum filter_return
-f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
+f_eval_rte(const struct f_line *expr, struct rte *rte, struct linpool *tmp_pool)
 {
   filter_state = (struct filter_state) {
     .rte = rte,
@@ -354,8 +296,7 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool
 
   LOG_BUFFER_INIT(filter_state.buf);
 
-  ASSERT(!((*rte)->flags & REF_COW));
-  ASSERT(!rta_is_cached((*rte)->attrs));
+  ASSERT(!rta_is_cached(rte->attrs));
 
   return interpret(&filter_state, expr, NULL);
 }
index 26c1037b71f815491019220636cd4222e0096861..9964831cc5803a5e73d846ff0b7f36041abf3de0 100644 (file)
@@ -51,8 +51,8 @@ struct filter {
 
 struct rte;
 
-enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
-enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
+enum filter_return f_run(const struct filter *filter, struct rte *rte, struct linpool *tmp_pool, int flags);
+enum filter_return f_eval_rte(const struct f_line *expr, struct rte *rte, struct linpool *tmp_pool);
 uint f_eval_int(const struct f_line *expr);
 enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
 
index e05dd7ecacbf39f365078eebd28a5dbab5685c03..80b4509bf573e8d6118636cbbf673187f2f41b69 100644 (file)
@@ -211,9 +211,9 @@ struct proto {
 
   void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
   void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
-  void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
+  void (*rt_notify)(struct proto *, struct channel *, const net_addr *net, struct rte *new, const struct rte *old);
   void (*neigh_notify)(struct neighbor *neigh);
-  int (*preexport)(struct proto *, struct rte *rt);
+  int (*preexport)(struct channel *, struct rte *rt);
   void (*reload_routes)(struct channel *);
   void (*feed_begin)(struct channel *, int initial);
   void (*feed_end)(struct channel *);
@@ -232,7 +232,7 @@ struct proto {
   int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
   int (*rte_better)(struct rte *, struct rte *);
   int (*rte_mergable)(struct rte *, struct rte *);
-  struct rte * (*rte_modify)(struct rte *, struct linpool *);
+  struct rte *(*rte_modify)(struct rte *, struct linpool *);
   void (*rte_insert)(struct network *, struct rte *);
   void (*rte_remove)(struct network *, struct rte *);
   u32 (*rte_igp_metric)(struct rte *);
@@ -542,7 +542,7 @@ struct channel {
   struct rtable *in_table;             /* Internal table for received routes */
   struct event *reload_event;          /* Event responsible for reloading from in_table */
   struct fib_iterator reload_fit;      /* FIB iterator in in_table used during reloading */
-  struct rte *reload_next_rte;         /* Route iterator in in_table used during reloading */
+  struct rte_storage *reload_next_rte; /* Route iterator in in_table used during reloading */
   u8 reload_active;                    /* Iterator reload_fit is linked */
 
   u8 reload_pending;                   /* Reloading and another reload is scheduled */
@@ -632,18 +632,4 @@ void *channel_config_new(const struct channel_class *cc, const char *name, uint
 void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
 int channel_reconfigure(struct channel *c, struct channel_config *cf);
 
-
-/* Moved from route.h to avoid dependency conflicts */
-static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); }
-
-static inline void
-rte_update3(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
-{
-  if (c->in_table && !rte_update_in(c, n, new, src))
-    return;
-
-  rte_update2(c, n, new, src);
-}
-
-
 #endif
index bb23152b803bc1b9f1985531a842333569f81a82..ade14857bf0c5b2fd0fb89eee417e96edb0b86a4 100644 (file)
@@ -157,6 +157,7 @@ typedef struct rtable {
   resource r;
   node n;                              /* Node in list of all tables */
   pool *rp;                            /* Resource pool to allocate everything from, including itself */
+  struct slab *rte_slab;               /* Slab to allocate route objects */
   struct fib fib;
   char *name;                          /* Name of this table */
   list channels;                       /* List of attached channels (struct channel) */
@@ -202,7 +203,7 @@ struct rt_subscription {
 #define NHU_DIRTY      3
 
 typedef struct network {
-  struct rte *routes;                  /* Available routes for this network */
+  struct rte_storage *routes;                  /* Available routes for this network */
   struct fib_node n;                   /* FIB flags reserved for kernel syncer */
 } net;
 
@@ -234,18 +235,24 @@ struct hostentry {
 };
 
 typedef struct rte {
-  struct rte *next;
-  net *net;                            /* Network this RTE belongs to */
+  struct rta *attrs;                   /* Attributes of this route */
+  const net_addr *net;                 /* Network this RTE belongs to */
   struct rte_src *src;                 /* Route source that created the route */
   struct channel *sender;              /* Channel used to send the route to the routing table */
-  struct rta *attrs;                   /* Attributes of this route */
+  btime lastmod;                       /* Last modified (set by table) */
   u32 id;                              /* Table specific route id */
-  byte flags;                          /* Flags (REF_...) */
+  byte flags;                          /* Table-specific flags */
   byte pflags;                         /* Protocol-specific flags */
-  btime lastmod;                       /* Last modified */
 } rte;
 
-#define REF_COW                1               /* Copy this rte on write */
+struct rte_storage {
+  struct rte_storage *next;            /* Next in chain */
+  struct rte rte;                      /* Route data */
+};
+
+#define RTE_COPY(r, l) ((r) ? (((*(l)) = (r)->rte), (l)) : NULL)
+#define RTE_OR_NULL(r) ((r) ? &((r)->rte) : NULL)
+
 #define REF_FILTERED   2               /* Route is rejected by import filter */
 #define REF_STALE      4               /* Route is stale in a refresh cycle */
 #define REF_DISCARD    8               /* Route is scheduled for discard */
@@ -271,6 +278,40 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
 #define RIC_REJECT     -1              /* Rejected by protocol */
 #define RIC_DROP       -2              /* Silently dropped by protocol */
 
+/**
+ * rte_update - enter a new update to a routing table
+ * @c: channel doing the update
+ * @net: network address
+ * @rte: a &rte representing the new route
+ * @src: old route source identifier
+ *
+ * This function imports a new route to the appropriate table (via the channel).
+ * Table keys are @net (obligatory) and @rte->attrs->src.
+ * Both the @net and @rte pointers can be local.
+ *
+ * The route attributes (@rte->attrs) are obligatory. They can be also allocated
+ * locally. Anyway, if you use an already-cached attribute object, you shall
+ * call rta_clone() on that object yourself. (This semantics may change in future.)
+ *
+ * If the route attributes are local, you may set @rte->attrs->src to NULL, then
+ * the protocol's default route source will be supplied.
+ *
+ * When rte_update() gets a route, it automatically validates it. This includes
+ * checking for validity of the given network and next hop addresses and also
+ * checking for host-scope or link-scope routes. Then the import filters are
+ * processed and if accepted, the route is passed to route table recalculation.
+ *
+ * The accepted routes are then inserted into the table, replacing the old route
+ * for the same @net identified by @src. Then the route is announced
+ * to all the channels connected to the table using the standard export mechanism.
+ * Setting @rte to NULL makes this a withdraw, otherwise @rte->src must be the same
+ * as @src.
+ *
+ * All memory used for temporary allocations is taken from a special linpool
+ * @rte_update_pool and freed when rte_update() finishes.
+ */
+void rte_update(struct channel *c, const net_addr *net, struct rte *rte, struct rte_src *src);
+
 extern list routing_tables;
 struct config;
 
@@ -286,34 +327,27 @@ static inline void rt_shutdown(rtable *r) { rfree(r->rp); }
 
 static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
 static inline net *net_find_valid(rtable *tab, const net_addr *addr)
-{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
+{ net *n = net_find(tab, addr); return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; }
 static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
 void *net_route(rtable *tab, const net_addr *n);
 int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
-rte *rte_find(net *net, struct rte_src *src);
-rte *rte_get_temp(struct rta *, struct rte_src *src);
-void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
-/* rte_update() moved to protocol.h to avoid dependency conflicts */
-int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
-rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
+int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
+rte *rt_export_merged(struct channel *c, net *net, linpool *pool, int silent);
 void rt_refresh_begin(rtable *t, struct channel *c);
 void rt_refresh_end(rtable *t, struct channel *c);
 void rt_modify_stale(rtable *t, struct channel *c);
 void rt_schedule_prune(rtable *t);
-void rte_dump(rte *);
-void rte_free(rte *);
-rte *rte_do_cow(rte *);
-static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
-rte *rte_cow_rta(rte *r, linpool *lp);
+void rte_dump(struct rte_storage *);
+void rte_free(struct rte_storage *, rtable *);
+struct rte_storage *rte_store(const rte *, net *net, rtable *);
 void rt_dump(rtable *);
 void rt_dump_all(void);
 int rt_feed_channel(struct channel *c);
 void rt_feed_channel_abort(struct channel *c);
-int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
 int rt_reload_channel(struct channel *c);
 void rt_reload_channel_abort(struct channel *c);
 void rt_prune_sync(rtable *t, int all);
-int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, rte **old_exported, int refeed);
+int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported, int refeed);
 struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
 
 
@@ -634,7 +668,7 @@ void rta_dump(rta *);
 void rta_dump_all(void);
 void rta_show(struct cli *, rta *);
 
-u32 rt_get_igp_metric(rte *rt);
+u32 rt_get_igp_metric(rte *);
 struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep);
 void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls);
 
index e2e6592609abb31df0b31a6bc7245fbd44ea9cd7..5d1e57b3960492a6d8147a9e9d0a28452067080a 100644 (file)
@@ -67,13 +67,10 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
 
       /* Use iface ID as local source ID */
       struct rte_src *src = rt_get_source(P, ad->iface->index);
-      rte_update2(c, net, NULL, src);
+      rte_update(c, net, NULL, src);
     }
   else if (flags & IF_CHANGE_UP)
     {
-      rta *a;
-      rte *e;
-
       DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
 
       if (cf->check_link && !(ad->iface->flags & IF_LINK_UP))
@@ -90,10 +87,12 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
        .nh.iface = ad->iface,
       };
 
-      a = rta_lookup(&a0);
-      e = rte_get_temp(a, src);
-      e->pflags = 0;
-      rte_update2(c, net, e, src);
+      rte e0 = {
+       .attrs = rta_lookup(&a0),
+       .src = src,
+      };
+
+      rte_update(c, net, &e0, src);
     }
 }
 
index 99f29691360911307936b2d3b15a8ca8e18d5783..ae5000f51f6c82be38688e0eb06ae28731712c98 100644 (file)
@@ -101,7 +101,6 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
 static void
 rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
 {
-  rte *e, *ee;
   byte ia[NET_MAX_TEXT_LENGTH+1];
   struct channel *ec = d->tab->export_channel;
 
@@ -114,9 +113,9 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
 
   bsnprintf(ia, sizeof(ia), "%N", n->n.addr);
 
-  for (e = n->routes; e; e = e->next)
+  for (struct rte_storage *er = n->routes; er; er = er->next)
     {
-      if (rte_is_filtered(e) != d->filtered)
+      if (rte_is_filtered(&er->rte) != d->filtered)
        continue;
 
       d->rt_counter++;
@@ -126,7 +125,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
       if (pass)
        continue;
 
-      ee = e;
+      struct rte e = er->rte;
 
       /* Export channel is down, do not try to export routes to it */
       if (ec && (ec->export_state == ES_DOWN))
@@ -134,7 +133,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
 
       if (d->export_mode == RSEM_EXPORTED)
         {
-         if (!bmap_test(&ec->export_map, ee->id))
+         if (!bmap_test(&ec->export_map, e.id))
            goto skip;
 
          // if (ec->ra_mode != RA_ANY)
@@ -143,17 +142,17 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
       else if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
        {
          /* Special case for merged export */
-         rte *rt_free;
-         e = rt_export_merged(ec, n, &rt_free, c->show_pool, 1);
          pass = 1;
-
-         if (!e)
-         { e = ee; goto skip; }
+         rte *em = rt_export_merged(ec, n, c->show_pool, 1);
+         if (em)
+           e = *em;
+         else
+           goto skip;
        }
       else if (d->export_mode)
        {
          struct proto *ep = ec->proto;
-         int ic = ep->preexport ? ep->preexport(ep, e) : 0;
+         int ic = ep->preexport ? ep->preexport(ec, &e) : 0;
 
          if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
            pass = 1;
@@ -179,24 +178,19 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
            }
        }
 
-      if (d->show_protocol && (d->show_protocol != e->src->proto))
+      if (d->show_protocol && (d->show_protocol != e.src->proto))
        goto skip;
 
       if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT)
        goto skip;
 
       if (d->stats < 2)
-       rt_show_rte(c, ia, e, d, (e->net->routes == ee));
+       rt_show_rte(c, ia, &e, d, (n->routes == er));
 
       d->show_counter++;
       ia[0] = 0;
 
     skip:
-      if (e != ee)
-      {
-       rte_free(e);
-       e = ee;
-      }
       lp_flush(c->show_pool);
 
       if (d->primary_only)
index 468624ff28eba1d04bb1737713a43ced776e66de..ee69d7c41d850c0f0738a172d71cda8546f07a2f 100644 (file)
@@ -47,7 +47,6 @@
 
 pool *rt_table_pool;
 
-static slab *rte_slab;
 static linpool *rte_update_pool;
 
 list routing_tables;
@@ -171,7 +170,7 @@ net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn)
       net_addr_roa4 *roa = (void *) fn->addr;
       net *r = fib_node_to_user(&tab->fib, fn);
 
-      if (net_equal_prefix_roa4(roa, &n) && rte_is_valid(r->routes))
+      if (net_equal_prefix_roa4(roa, &n) && r->routes && rte_is_valid(&r->routes->rte))
       {
        anything = 1;
        if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
@@ -203,7 +202,7 @@ net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn)
       net_addr_roa6 *roa = (void *) fn->addr;
       net *r = fib_node_to_user(&tab->fib, fn);
 
-      if (net_equal_prefix_roa6(roa, &n) && rte_is_valid(r->routes))
+      if (net_equal_prefix_roa6(roa, &n) && r->routes && rte_is_valid(&r->routes->rte))
       {
        anything = 1;
        if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
@@ -252,106 +251,53 @@ net_roa_check(rtable *tab, const net_addr *n, u32 asn)
  * @net: network node
  * @src: route source
  *
- * The rte_find() function returns a route for destination @net
- * which is from route source @src.
+ * The rte_find() function returns a pointer to a route for destination @net
+ * which is from route source @src. List end pointer is returned if no route is found.
  */
-rte *
+static struct rte_storage **
 rte_find(net *net, struct rte_src *src)
 {
-  rte *e = net->routes;
-
-  while (e && e->src != src)
-    e = e->next;
-  return e;
-}
+  struct rte_storage **e = &net->routes;
 
-/**
- * rte_get_temp - get a temporary &rte
- * @a: attributes to assign to the new route (a &rta; in case it's
- * un-cached, rte_update() will create a cached copy automatically)
- *
- * Create a temporary &rte and bind it with the attributes @a.
- * Also set route preference to the default preference set for
- * the protocol.
- */
-rte *
-rte_get_temp(rta *a, struct rte_src *src)
-{
-  rte *e = sl_alloc(rte_slab);
+  while ((*e) && (*e)->rte.src != src)
+    e = &(*e)->next;
 
-  e->attrs = a;
-  e->id = 0;
-  e->flags = 0;
-  rt_lock_source(e->src = src);
   return e;
 }
 
-rte *
-rte_do_cow(rte *r)
+
+struct rte_storage *
+rte_store(const rte *r, net *net, rtable *tab)
 {
-  rte *e = sl_alloc(rte_slab);
+  struct rte_storage *e = sl_alloc(tab->rte_slab);
 
-  memcpy(e, r, sizeof(rte));
+  e->rte = *r;
+  e->rte.net = net->n.addr;
 
-  rt_lock_source(e->src);
-  e->attrs = rta_clone(r->attrs);
-  e->flags = 0;
-  return e;
-}
+  rt_lock_source(e->rte.src);
 
-/**
- * rte_cow_rta - get a private writable copy of &rte with writable &rta
- * @r: a route entry to be copied
- * @lp: a linpool from which to allocate &rta
- *
- * rte_cow_rta() takes a &rte and prepares it and associated &rta for
- * modification. There are three possibilities: First, both &rte and &rta are
- * private copies, in that case they are returned unchanged.  Second, &rte is
- * private copy, but &rta is cached, in that case &rta is duplicated using
- * rta_do_cow(). Third, both &rte is shared and &rta is cached, in that case
- * both structures are duplicated by rte_do_cow() and rta_do_cow().
- *
- * Note that in the second case, cached &rta loses one reference, while private
- * copy created by rta_do_cow() is a shallow copy sharing indirect data (eattrs,
- * nexthops, ...) with it. To work properly, original shared &rta should have
- * another reference during the life of created private copy.
- *
- * Result: a pointer to the new writable &rte with writable &rta.
- */
-rte *
-rte_cow_rta(rte *r, linpool *lp)
-{
-  if (!rta_is_cached(r->attrs))
-    return r;
+  if (e->rte.attrs->cached)
+    e->rte.attrs = rta_clone(e->rte.attrs);
+  else
+    e->rte.attrs = rta_lookup(e->rte.attrs);
 
-  r = rte_cow(r);
-  rta *a = rta_do_cow(r->attrs, lp);
-  rta_free(r->attrs);
-  r->attrs = a;
-  return r;
+  return e;
 }
 
 /**
  * rte_free - delete a &rte
- * @e: &rte to be deleted
+ * @e: &struct rte_storage to be deleted
+ * @tab: the table which the rte belongs to
  *
  * rte_free() deletes the given &rte from the routing table it's linked to.
  */
-void
-rte_free(rte *e)
-{
-  rt_unlock_source(e->src);
-  if (rta_is_cached(e->attrs))
-    rta_free(e->attrs);
-  sl_free(rte_slab, e);
-}
 
-static inline void
-rte_free_quick(rte *e)
+void
+rte_free(struct rte_storage *e, rtable *tab)
 {
-  rt_unlock_source(e->src);
-  rta_free(e->attrs);
-  sl_free(rte_slab, e);
+  rt_unlock_source(e->rte.src);
+  rta_free(e->rte.attrs);
+  sl_free(tab->rte_slab, e);
 }
 
 static int                             /* Actually better or at least as good as */
@@ -406,7 +352,7 @@ static void
 rte_trace(struct channel *c, rte *e, int dir, char *msg)
 {
   log(L_TRACE "%s.%s %c %s %N %uL %uG %s",
-      c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, e->src->private_id, e->src->global_id,
+      c->proto->name, c->name ?: "?", dir, msg, e->net, e->src->private_id, e->src->global_id,
       rta_dest_name(e->attrs->dest));
 }
 
@@ -425,18 +371,14 @@ rte_trace_out(uint flag, struct channel *c, rte *e, char *msg)
 }
 
 static rte *
-export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
+export_filter_(struct channel *c, rte *rt, linpool *pool, int silent)
 {
   struct proto *p = c->proto;
   const struct filter *filter = c->out_filter;
   struct proto_stats *stats = &c->stats;
-  rte *rt;
   int v;
 
-  rt = rt0;
-  *rt_free = NULL;
-
-  v = p->preexport ? p->preexport(p, rt) : 0;
+  v = p->preexport ? p->preexport(c, rt) : 0;
   if (v < 0)
     {
       if (silent)
@@ -455,7 +397,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
     }
 
   v = filter && ((filter == FILTER_REJECT) ||
-                (f_run(filter, &rt, pool,
+                (f_run(filter, rt, pool,
                        (silent ? FF_SILENT : 0)) > F_ACCEPT));
   if (v)
     {
@@ -468,25 +410,21 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
     }
 
  accept:
-  if (rt != rt0)
-    *rt_free = rt;
   return rt;
 
  reject:
   /* Discard temporary rte */
-  if (rt != rt0)
-    rte_free(rt);
   return NULL;
 }
 
 static inline rte *
-export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent)
+export_filter(struct channel *c, rte *rt, int silent)
 {
-  return export_filter_(c, rt0, rt_free, rte_update_pool, silent);
+  return export_filter_(c, rt, rte_update_pool, silent);
 }
 
 static void
-do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
+do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int refeed)
 {
   struct proto *p = c->proto;
   struct proto_stats *stats = &c->stats;
@@ -510,14 +448,12 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
   }
 
   /* Apply export table */
-  struct rte *old_exported = NULL;
+  struct rte_storage *old_exported = NULL;
   if (c->out_table)
   {
-    if (!rte_update_out(c, net->n.addr, new, old, &old_exported, refeed))
+    if (!rte_update_out(c, net, new, old, &old_exported, refeed))
       return;
   }
-  else if (c->out_filter == FILTER_ACCEPT)
-    old_exported = old;
 
   if (new)
     stats->exp_updates_accepted++;
@@ -546,25 +482,22 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
       rte_trace_out(D_ROUTES, c, old, "removed");
   }
 
-  p->rt_notify(p, c, net, new, old);
+  p->rt_notify(p, c, net, new, old_exported ? &old_exported->rte : old);
 
   if (c->out_table && old_exported)
-    rte_free_quick(old_exported);
+    rte_free(old_exported, c->out_table);
 }
 
 static void
-rt_notify_basic(struct channel *c, net *net, rte *new, rte *old, int refeed)
+rt_notify_basic(struct channel *c, const net_addr *net, rte *new, rte *old, int refeed)
 {
-  // struct proto *p = c->proto;
-  rte *new_free = NULL;
-
   if (new)
     c->stats.exp_updates_received++;
   else
     c->stats.exp_withdraws_received++;
 
   if (new)
-    new = export_filter(c, new, &new_free, 0);
+    new = export_filter(c, new, 0);
 
   if (old && !bmap_test(&c->export_map, old->id))
     old = NULL;
@@ -573,19 +506,15 @@ rt_notify_basic(struct channel *c, net *net, rte *new, rte *old, int refeed)
     return;
 
   do_rt_notify(c, net, new, old, refeed);
-
-  /* Discard temporary rte */
-  if (new_free)
-    rte_free(new_free);
 }
 
 static void
 rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, int refeed)
 {
   // struct proto *p = c->proto;
+  rte nb0;
   rte *new_best = NULL;
   rte *old_best = NULL;
-  rte *new_free = NULL;
   int new_first = 0;
 
   /*
@@ -614,16 +543,16 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
     old_best = old_changed;
   else
   {
-    for (rte *r = net->routes; rte_is_valid(r); r = r->next)
+    for (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next)
     {
-      if (bmap_test(&c->export_map, r->id))
+      if (bmap_test(&c->export_map, r->rte.id))
       {
-       old_best = r;
+       old_best = &r->rte;
        break;
       }
 
       /* Note if new_changed found before old_best */
-      if (r == new_changed)
+      if (&r->rte == new_changed)
        new_first = 1;
     }
   }
@@ -632,14 +561,14 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
   if ((new_changed == old_changed) || (old_best == old_changed))
   {
     /* Feed or old_best changed -> find first accepted by filters */
-    for (rte *r = net->routes; rte_is_valid(r); r = r->next)
-      if (new_best = export_filter(c, r, &new_free, 0))
+    for (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next)
+      if (new_best = export_filter(c, ((nb0 = r->rte), &nb0), 0))
        break;
   }
   else
   {
     /* Other cases -> either new_changed, or old_best (and nothing changed) */
-    if (new_first && (new_changed = export_filter(c, new_changed, &new_free, 0)))
+    if (new_first && (new_changed = export_filter(c, new_changed, 0)))
       new_best = new_changed;
     else
       return;
@@ -648,11 +577,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
   if (!new_best && !old_best)
     return;
 
-  do_rt_notify(c, net, new_best, old_best, refeed);
-
-  /* Discard temporary rte */
-  if (new_free)
-    rte_free(new_free);
+  do_rt_notify(c, net->n.addr, new_best, old_best, refeed);
 }
 
 
@@ -663,38 +588,35 @@ nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max)
 }
 
 rte *
-rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent)
+rt_export_merged(struct channel *c, net *net, linpool *pool, int silent)
 {
   // struct proto *p = c->proto;
   struct nexthop *nhs = NULL;
-  rte *best0, *best, *rt0, *rt, *tmp;
+  _Thread_local static rte rme;
+  struct rte_storage *best0 = net->routes;
+  rte *best;
 
-  best0 = net->routes;
-  *rt_free = NULL;
-
-  if (!rte_is_valid(best0))
+  if (!best0 || !rte_is_valid(&best0->rte))
     return NULL;
 
-  best = export_filter_(c, best0, rt_free, pool, silent);
+  best = export_filter_(c, ((rme = best0->rte), &rme), pool, silent);
 
   if (!best || !rte_is_reachable(best))
     return best;
 
-  for (rt0 = best0->next; rt0; rt0 = rt0->next)
+  for (struct rte_storage *rt0 = best0->next; rt0; rt0 = rt0->next)
   {
-    if (!rte_mergable(best0, rt0))
+    if (!rte_mergable(best, &rt0->rte))
       continue;
 
-    rt = export_filter_(c, rt0, &tmp, pool, 1);
+    rte rnh = rt0->rte;
+    rte *rt = export_filter_(c, &rnh, pool, 1);
 
     if (!rt)
       continue;
 
     if (rte_is_reachable(rt))
       nhs = nexthop_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
-
-    if (tmp)
-      rte_free(tmp);
   }
 
   if (nhs)
@@ -703,14 +625,11 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
 
     if (nhs->next)
     {
-      best = rte_cow_rta(best, pool);
+      best->attrs = rta_cow(best->attrs, pool);
       nexthop_link(best->attrs, nhs);
     }
   }
 
-  if (best != best0)
-    *rt_free = best;
-
   return best;
 }
 
@@ -719,9 +638,6 @@ static void
 rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
                 rte *new_best, rte *old_best, int refeed)
 {
-  // struct proto *p = c->proto;
-  rte *new_free = NULL;
-
   /* We assume that all rte arguments are either NULL or rte_is_valid() */
 
   /* This check should be done by the caller */
@@ -742,7 +658,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
 
   /* Prepare new merged route */
   if (new_best)
-    new_best = rt_export_merged(c, net, &new_free, rte_update_pool, 0);
+    new_best = rt_export_merged(c, net, rte_update_pool, 0);
 
   /* Check old merged route */
   if (old_best && !bmap_test(&c->export_map, old_best->id))
@@ -751,11 +667,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
   if (!new_best && !old_best)
     return;
 
-  do_rt_notify(c, net, new_best, old_best, refeed);
-
-  /* Discard temporary rte */
-  if (new_free)
-    rte_free(new_free);
+  do_rt_notify(c, net->n.addr, new_best, old_best, refeed);
 }
 
 
@@ -799,19 +711,19 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
  * done outside of scope of rte_announce().
  */
 static void
-rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
-            rte *new_best, rte *old_best)
+rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct rte_storage *old,
+            struct rte_storage *new_best, struct rte_storage *old_best)
 {
-  if (!rte_is_valid(new))
+  if (!new || !rte_is_valid(&new->rte))
     new = NULL;
 
-  if (!rte_is_valid(old))
+  if (!old || !rte_is_valid(&old->rte))
     old = NULL;
 
-  if (!rte_is_valid(new_best))
+  if (!new_best || !rte_is_valid(&new_best->rte))
     new_best = NULL;
 
-  if (!rte_is_valid(old_best))
+  if (!old_best || !rte_is_valid(&old_best->rte))
     old_best = NULL;
 
   if (!new && !old && !new_best && !old_best)
@@ -820,9 +732,9 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
   if (new_best != old_best)
   {
     if (new_best)
-      new_best->sender->stats.pref_routes++;
+      new_best->rte.sender->stats.pref_routes++;
     if (old_best)
-      old_best->sender->stats.pref_routes--;
+      old_best->rte.sender->stats.pref_routes--;
 
     if (tab->hostcache)
       rt_notify_hostcache(tab, net);
@@ -839,24 +751,25 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
     if (type && (type != c->ra_mode))
       continue;
 
+    rte n0;
     switch (c->ra_mode)
     {
     case RA_OPTIMAL:
       if (new_best != old_best)
-       rt_notify_basic(c, net, new_best, old_best, 0);
+       rt_notify_basic(c, net->n.addr, RTE_COPY(new_best, &n0), RTE_OR_NULL(old_best), 0);
       break;
 
     case RA_ANY:
       if (new != old)
-       rt_notify_basic(c, net, new, old, 0);
+       rt_notify_basic(c, net->n.addr, RTE_COPY(new, &n0), RTE_OR_NULL(old), 0);
       break;
 
     case RA_ACCEPTED:
-      rt_notify_accepted(c, net, new, old, 0);
+      rt_notify_accepted(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), 0);
       break;
 
     case RA_MERGED:
-      rt_notify_merged(c, net, new, old, new_best, old_best, 0);
+      rt_notify_merged(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), RTE_OR_NULL(new_best), RTE_OR_NULL(old_best), 0);
       break;
     }
   }
@@ -866,36 +779,36 @@ static inline int
 rte_validate(rte *e)
 {
   int c;
-  net *n = e->net;
+  const net_addr *n = e->net;
 
-  if (!net_validate(n->n.addr))
+  if (!net_validate(n))
   {
     log(L_WARN "Ignoring bogus prefix %N received via %s",
-       n->n.addr, e->sender->proto->name);
+       n, e->sender->proto->name);
     return 0;
   }
 
   /* FIXME: better handling different nettypes */
-  c = !net_is_flow(n->n.addr) ?
-    net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE);
+  c = !net_is_flow(n) ?
+    net_classify(n): (IADDR_HOST | SCOPE_UNIVERSE);
   if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
   {
     log(L_WARN "Ignoring bogus route %N received via %s",
-       n->n.addr, e->sender->proto->name);
+       n, e->sender->proto->name);
     return 0;
   }
 
-  if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
+  if (net_type_match(n, NB_DEST) == !e->attrs->dest)
   {
     log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
-       n->n.addr, e->attrs->dest, e->sender->proto->name);
+       n, e->attrs->dest, e->sender->proto->name);
     return 0;
   }
 
   if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh)))
   {
     log(L_WARN "Ignoring unsorted multipath route %N received via %s",
-       n->n.addr, e->sender->proto->name);
+       n, e->sender->proto->name);
     return 0;
   }
 
@@ -922,16 +835,17 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
   struct rtable *table = c->table;
   struct proto_stats *stats = &c->stats;
   static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
-  rte *before_old = NULL;
-  rte *old_best = net->routes;
+  struct rte_storage *old_best_stored = net->routes, *old_stored = NULL;
+  rte *old_best = old_best_stored ? &old_best_stored->rte : NULL;
   rte *old = NULL;
-  rte **k;
 
-  k = &net->routes;                    /* Find and remove original route from the same protocol */
-  while (old = *k)
+  /* Find and remove original route from the same protocol */
+  struct rte_storage **before_old = rte_find(net, src);
+
+  if (*before_old)
     {
-      if (old->src == src)
-       {
+      old = &(old_stored = (*before_old))->rte;
+
          /* If there is the same route in the routing table but from
           * a different sender, then there are two paths from the
           * source protocol to this routing table through transparent
@@ -944,11 +858,8 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
          if (old->sender->proto != p)
            {
              if (new)
-               {
                  log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %N to table %s",
                      net->n.addr, table->name);
-                 rte_free_quick(new);
-               }
              return;
            }
 
@@ -964,23 +875,13 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
                  rte_trace_in(D_ROUTES, c, new, "ignored");
                }
 
-             rte_free_quick(new);
              return;
            }
-         *k = old->next;
+
+         *before_old = (*before_old)->next;
          table->rt_count--;
-         break;
-       }
-      k = &old->next;
-      before_old = old;
     }
 
-  /* Save the last accessed position */
-  rte **pos = k;
-
-  if (!old)
-    before_old = NULL;
-
   if (!old && !new)
     {
       stats->imp_withdraws_ignored++;
@@ -1005,7 +906,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
 
          stats->imp_updates_ignored++;
          rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
-         rte_free_quick(new);
          return;
        }
     }
@@ -1031,7 +931,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
          if (c->in_keep_filtered)
            new->flags |= REF_FILTERED;
          else
-           { rte_free_quick(new); new = NULL; }
+           new = NULL;
 
          /* Note that old && !new could be possible when
             c->in_keep_filtered changed in the recent past. */
@@ -1054,7 +954,8 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
   if (old_ok || new_ok)
     table->last_rt_change = current_time();
 
- skip_stats1:
+ skip_stats1:;
+  struct rte_storage *new_stored = new ? rte_store(new, net, table) : NULL;
 
   if (new)
     rte_is_filtered(new) ? stats->filt_routes++ : stats->imp_routes++;
@@ -1064,19 +965,20 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
   if (table->config->sorted)
     {
       /* If routes are sorted, just insert new route to appropriate position */
-      if (new)
+      if (new_stored)
        {
-         if (before_old && !rte_better(new, before_old))
-           k = &before_old->next;
+         struct rte_storage **k;
+         if ((before_old != &net->routes) && !rte_better(new, &SKIP_BACK(struct rte_storage, next, before_old)->rte))
+           k = before_old;
          else
            k = &net->routes;
 
          for (; *k; k=&(*k)->next)
-           if (rte_better(new, *k))
+           if (rte_better(new, &(*k)->rte))
              break;
 
-         new->next = *k;
-         *k = new;
+         new_stored->next = *k;
+         *k = new_stored;
 
          table->rt_count++;
        }
@@ -1086,16 +988,17 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
       /* If routes are not sorted, find the best route and move it on
         the first position. There are several optimized cases. */
 
-      if (src->proto->rte_recalculate && src->proto->rte_recalculate(table, net, new, old, old_best))
+      if (src->proto->rte_recalculate &&
+         src->proto->rte_recalculate(table, net, new_stored ? &new_stored->rte : NULL, old, old_best))
        goto do_recalculate;
 
-      if (new && rte_better(new, old_best))
+      if (new_stored && rte_better(&new_stored->rte, old_best))
        {
          /* The first case - the new route is cleary optimal,
             we link it at the first position */
 
-         new->next = net->routes;
-         net->routes = new;
+         new_stored->next = net->routes;
+         net->routes = new_stored;
 
          table->rt_count++;
        }
@@ -1109,10 +1012,10 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
 
        do_recalculate:
          /* Add the new route to the list */
-         if (new)
+         if (new_stored)
            {
-             new->next = *pos;
-             *pos = new;
+             new_stored->next = *before_old;
+             *before_old = new_stored;
 
              table->rt_count++;
            }
@@ -1120,56 +1023,56 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
          /* Find a new optimal route (if there is any) */
          if (net->routes)
            {
-             rte **bp = &net->routes;
-             for (k=&(*bp)->next; *k; k=&(*k)->next)
-               if (rte_better(*k, *bp))
+             struct rte_storage **bp = &net->routes;
+             for (struct rte_storage **k=&(*bp)->next; *k; k=&(*k)->next)
+               if (rte_better(&(*k)->rte, &(*bp)->rte))
                  bp = k;
 
              /* And relink it */
-             rte *best = *bp;
+             struct rte_storage *best = *bp;
              *bp = best->next;
              best->next = net->routes;
              net->routes = best;
            }
        }
-      else if (new)
+      else if (new_stored)
        {
          /* The third case - the new route is not better than the old
             best route (therefore old_best != NULL) and the old best
             route was not removed (therefore old_best == net->routes).
             We just link the new route to the old/last position. */
 
-         new->next = *pos;
-         *pos = new;
+         new_stored->next = *before_old;
+         *before_old = new_stored;
 
          table->rt_count++;
        }
       /* The fourth (empty) case - suboptimal route was removed, nothing to do */
     }
 
-  if (new)
+  if (new_stored)
     {
-      new->lastmod = current_time();
+      new_stored->rte.lastmod = current_time();
 
       if (!old)
         {
-         new->id = hmap_first_zero(&table->id_map);
-         hmap_set(&table->id_map, new->id);
+         new_stored->rte.id = hmap_first_zero(&table->id_map);
+         hmap_set(&table->id_map, new_stored->rte.id);
        }
       else
-       new->id = old->id;
+       new_stored->rte.id = old->id;
     }
 
   /* Log the route change */
   if ((c->debug & D_ROUTES) || (p->debug & D_ROUTES))
     {
       if (new_ok)
-       rte_trace(c, new, '>', new == net->routes ? "added [best]" : "added");
+       rte_trace(c, &new_stored->rte, '>', new_stored == net->routes ? "added [best]" : "added");
       else if (old_ok)
        {
          if (old != old_best)
            rte_trace(c, old, '>', "removed");
-         else if (rte_is_ok(net->routes))
+         else if (net->routes && rte_is_ok(&net->routes->rte))
            rte_trace(c, old, '>', "removed [replaced]");
          else
            rte_trace(c, old, '>', "removed [sole]");
@@ -1177,7 +1080,8 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
     }
 
   /* Propagate the route change */
-  rte_announce(table, RA_UNDEF, net, new, old, net->routes, old_best);
+  rte_announce(table, RA_UNDEF, net, new_stored, old_stored,
+      net->routes, old_best_stored);
 
   if (!net->routes &&
       (table->gc_counter++ >= table->config->gc_max_ops) &&
@@ -1187,14 +1091,14 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
   if (old_ok && p->rte_remove)
     p->rte_remove(net, old);
   if (new_ok && p->rte_insert)
-    p->rte_insert(net, new);
+    p->rte_insert(net, &new_stored->rte);
 
   if (old)
     {
-      if (!new)
+      if (!new_stored)
        hmap_clear(&table->id_map, old->id);
 
-      rte_free_quick(old);
+      rte_free(old_stored, table);
     }
 }
 
@@ -1213,51 +1117,14 @@ rte_update_unlock(void)
     lp_flush(rte_update_pool);
 }
 
-/**
- * rte_update - enter a new update to a routing table
- * @table: table to be updated
- * @c: channel doing the update
- * @net: network node
- * @p: protocol submitting the update
- * @src: protocol originating the update
- * @new: a &rte representing the new route or %NULL for route removal.
- *
- * This function is called by the routing protocols whenever they discover
- * a new route or wish to update/remove an existing route. The right announcement
- * sequence is to build route attributes first (either un-cached with @aflags set
- * to zero or a cached one using rta_lookup(); in this case please note that
- * you need to increase the use count of the attributes yourself by calling
- * rta_clone()), call rte_get_temp() to obtain a temporary &rte, fill in all
- * the appropriate data and finally submit the new &rte by calling rte_update().
- *
- * @src specifies the protocol that originally created the route and the meaning
- * of protocol-dependent data of @new. If @new is not %NULL, @src have to be the
- * same value as @new->attrs->proto. @p specifies the protocol that called
- * rte_update(). In most cases it is the same protocol as @src. rte_update()
- * stores @p in @new->sender;
- *
- * When rte_update() gets any route, it automatically validates it (checks,
- * whether the network and next hop address are valid IP addresses and also
- * whether a normal routing protocol doesn't try to smuggle a host or link
- * scope route to the table), converts all protocol dependent attributes stored
- * in the &rte to temporary extended attributes, consults import filters of the
- * protocol to see if the route should be accepted and/or its attributes modified,
- * stores the temporary attributes back to the &rte.
- *
- * Now, having a "public" version of the route, we
- * automatically find any old route defined by the protocol @src
- * for network @n, replace it by the new one (or removing it if @new is %NULL),
- * recalculate the optimal route for this destination and finally broadcast
- * the change (if any) to all routing protocols by calling rte_announce().
- *
- * All memory used for attribute lists and other temporary allocations is taken
- * from a special linear pool @rte_update_pool and freed when rte_update()
- * finishes.
- */
+static int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
 
 void
-rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
+rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 {
+  if (c->in_table && !rte_update_in(c, n, new, src))
+    return;
+
   // struct proto *p = c->proto;
   struct proto_stats *stats = &c->stats;
   const struct filter *filter = c->in_filter;
@@ -1268,12 +1135,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
   rte_update_lock();
   if (new)
     {
-      /* Create a temporary table node */
-      nn = alloca(sizeof(net) + n->length);
-      memset(nn, 0, sizeof(net) + n->length);
-      net_copy(nn->n.addr, n);
-
-      new->net = nn;
+      new->net = n;
       new->sender = c;
 
       stats->imp_updates_received++;
@@ -1297,7 +1159,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
        }
       else if (filter)
        {
-         int fr = f_run(filter, &new, rte_update_pool, 0);
+         int fr = f_run(filter, new, rte_update_pool, 0);
          if (fr > F_ACCEPT)
          {
            stats->imp_updates_filtered++;
@@ -1309,13 +1171,10 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
            new->flags |= REF_FILTERED;
          }
        }
-      if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
-       new->attrs = rta_lookup(new->attrs);
-      new->flags |= REF_COW;
 
       /* Use the actual struct network, not the dummy one */
       nn = net_get(c->table, n);
-      new->net = nn;
+      new->net = nn->n.addr;
     }
   else
     {
@@ -1337,7 +1196,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
   return;
 
  drop:
-  rte_free(new);
   new = NULL;
   if (nn = net_find(c->table, n))
     goto recalc;
@@ -1348,8 +1206,8 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 /* Independent call to rte_announce(), used from next hop
    recalculation, outside of rte_update(). new must be non-NULL */
 static inline void
-rte_announce_i(rtable *tab, uint type, net *net, rte *new, rte *old,
-              rte *new_best, rte *old_best)
+rte_announce_i(rtable *tab, uint type, net *net, struct rte_storage *new, struct rte_storage *old,
+              struct rte_storage *new_best, struct rte_storage *old_best)
 {
   rte_update_lock();
   rte_announce(tab, type, net, new, old, new_best, old_best);
@@ -1357,16 +1215,16 @@ rte_announce_i(rtable *tab, uint type, net *net, rte *new, rte *old,
 }
 
 static inline void
-rte_discard(rte *old)  /* Non-filtered route deletion, used during garbage collection */
+rte_discard(net *net, rte *old)        /* Non-filtered route deletion, used during garbage collection */
 {
   rte_update_lock();
-  rte_recalculate(old->sender, old->net, NULL, old->src);
+  rte_recalculate(old->sender, net, NULL, old->src);
   rte_update_unlock();
 }
 
 /* Modify existing route by protocol hook, used for long-lived graceful restart */
 static inline void
-rte_modify(rte *old)
+rte_modify(net *net, rte *old)
 {
   rte_update_lock();
 
@@ -1374,13 +1232,9 @@ rte_modify(rte *old)
   if (new != old)
   {
     if (new)
-    {
-      if (!rta_is_cached(new->attrs))
-       new->attrs = rta_lookup(new->attrs);
-      new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
-    }
+      new->flags = old->flags & ~REF_MODIFY;
 
-    rte_recalculate(old->sender, old->net, new, old->src);
+    rte_recalculate(old->sender, net, new, old->src);
   }
 
   rte_update_unlock();
@@ -1388,25 +1242,25 @@ rte_modify(rte *old)
 
 /* Check rtable for best route to given net whether it would be exported do p */
 int
-rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter)
+rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter)
 {
   net *n = net_find(t, a);
-  rte *rt = n ? n->routes : NULL;
 
-  if (!rte_is_valid(rt))
+  if (!n || !n->routes)
+    return 0;
+
+  rte rt = n->routes->rte;
+
+  if (!rte_is_valid(&rt))
     return 0;
 
   rte_update_lock();
 
   /* Rest is stripped down export_filter() */
-  int v = p->preexport ? p->preexport(p, rt) : 0;
+  int v = c->proto->preexport ? c->proto->preexport(c, &rt) : 0;
   if (v == RIC_PROCESS)
     v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
 
-  /* Discard temporary rte */
-  if (rt != n->routes)
-    rte_free(rt);
-
   rte_update_unlock();
 
   return v > 0;
@@ -1432,10 +1286,9 @@ rt_refresh_begin(rtable *t, struct channel *c)
 {
   FIB_WALK(&t->fib, net, n)
     {
-      rte *e;
-      for (e = n->routes; e; e = e->next)
-       if (e->sender == c)
-         e->flags |= REF_STALE;
+      for (struct rte_storage *e = n->routes; e; e = e->next)
+       if (e->rte.sender == c)
+         e->rte.flags |= REF_STALE;
     }
   FIB_WALK_END;
 }
@@ -1455,11 +1308,10 @@ rt_refresh_end(rtable *t, struct channel *c)
 
   FIB_WALK(&t->fib, net, n)
     {
-      rte *e;
-      for (e = n->routes; e; e = e->next)
-       if ((e->sender == c) && (e->flags & REF_STALE))
+      for (struct rte_storage *e = n->routes; e; e = e->next)
+       if ((e->rte.sender == c) && (e->rte.flags & REF_STALE))
          {
-           e->flags |= REF_DISCARD;
+           e->rte.flags |= REF_DISCARD;
            prune = 1;
          }
     }
@@ -1476,11 +1328,10 @@ rt_modify_stale(rtable *t, struct channel *c)
 
   FIB_WALK(&t->fib, net, n)
     {
-      rte *e;
-      for (e = n->routes; e; e = e->next)
-       if ((e->sender == c) && (e->flags & REF_STALE) && !(e->flags & REF_FILTERED))
+      for (struct rte_storage *e = n->routes; e; e = e->next)
+       if ((e->rte.sender == c) && (e->rte.flags & REF_STALE) && !(e->rte.flags & REF_FILTERED))
          {
-           e->flags |= REF_MODIFY;
+           e->rte.flags |= REF_MODIFY;
            prune = 1;
          }
     }
@@ -1497,12 +1348,11 @@ rt_modify_stale(rtable *t, struct channel *c)
  * This functions dumps contents of a &rte to debug output.
  */
 void
-rte_dump(rte *e)
+rte_dump(struct rte_storage *e)
 {
-  net *n = e->net;
-  debug("%-1N ", n->n.addr);
-  debug("PF=%02x ", e->pflags);
-  rta_dump(e->attrs);
+  debug("%-1N ", e->rte.net);
+  debug("PF=%02x ", e->rte.pflags);
+  rta_dump(e->rte.attrs);
   debug("\n");
 }
 
@@ -1521,8 +1371,7 @@ rt_dump(rtable *t)
 #endif
   FIB_WALK(&t->fib, net, n)
     {
-      rte *e;
-      for(e=n->routes; e; e=e->next)
+      for(struct rte_storage *e=n->routes; e; e=e->next)
        rte_dump(e);
     }
   FIB_WALK_END;
@@ -1725,6 +1574,8 @@ rt_setup(pool *pp, struct rtable_config *cf)
   rtable *t = ralloc(p, &rt_class);
   t->rp = p;
 
+  t->rte_slab = sl_new(p, sizeof(struct rte_storage));
+
   t->name = cf->name;
   t->config = cf;
   t->addr_type = cf->addr_type;
@@ -1758,7 +1609,6 @@ rt_init(void)
   rta_init();
   rt_table_pool = rp_new(&root_pool, "Routing tables");
   rte_update_pool = lp_new_default(rt_table_pool);
-  rte_slab = sl_new(rt_table_pool, sizeof(rte));
   init_list(&routing_tables);
 }
 
@@ -1808,12 +1658,10 @@ rt_prune_table(rtable *tab)
 again:
   FIB_ITERATE_START(&tab->fib, fit, net, n)
     {
-      rte *e;
-
     rescan:
-      for (e=n->routes; e; e=e->next)
+      for (struct rte_storage *e=n->routes; e; e=e->next)
       {
-       if (e->sender->flush_active || (e->flags & REF_DISCARD))
+       if (e->rte.sender->flush_active || (e->rte.flags & REF_DISCARD))
          {
            if (limit <= 0)
              {
@@ -1822,13 +1670,13 @@ again:
                return;
              }
 
-           rte_discard(e);
+           rte_discard(n, &e->rte);
            limit--;
 
            goto rescan;
          }
 
-       if (e->flags & REF_MODIFY)
+       if (e->rte.flags & REF_MODIFY)
          {
            if (limit <= 0)
              {
@@ -1837,7 +1685,7 @@ again:
                return;
              }
 
-           rte_modify(e);
+           rte_modify(n, &e->rte);
            limit--;
 
            goto rescan;
@@ -2001,8 +1849,8 @@ no_nexthop:
     }
 }
 
-static inline rte *
-rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
+static inline struct rte_storage *
+rt_next_hop_update_rte(rtable *tab, net *n, rte *old)
 {
   rta *a = alloca(RTA_MAX_SIZE);
   memcpy(a, old->attrs, rta_size(old->attrs));
@@ -2013,18 +1861,16 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
   rta_apply_hostentry(a, old->attrs->hostentry, &mls);
   a->cached = 0;
 
-  rte *e = sl_alloc(rte_slab);
-  memcpy(e, old, sizeof(rte));
-  e->attrs = rta_lookup(a);
-  rt_lock_source(e->src);
+  rte e0 = *old;
+  e0.attrs = a;
 
-  return e;
+  return rte_store(&e0, n, tab);
 }
 
 static inline int
 rt_next_hop_update_net(rtable *tab, net *n)
 {
-  rte **k, *e, *new, *old_best, **new_best;
+  struct rte_storage **k, *e, *new, *old_best, **new_best;
   int count = 0;
   int free_old_best = 0;
 
@@ -2033,21 +1879,22 @@ rt_next_hop_update_net(rtable *tab, net *n)
     return 0;
 
   for (k = &n->routes; e = *k; k = &e->next)
-    if (rta_next_hop_outdated(e->attrs))
+    if (rta_next_hop_outdated(e->rte.attrs))
       {
-       new = rt_next_hop_update_rte(tab, e);
+       new = rt_next_hop_update_rte(tab, n, &e->rte);
+       new->next = e->next;
        *k = new;
 
-       rte_trace_in(D_ROUTES, new->sender, new, "updated");
+       rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated");
        rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
 
        /* Call a pre-comparison hook */
        /* Not really an efficient way to compute this */
-       if (e->src->proto->rte_recalculate)
-         e->src->proto->rte_recalculate(tab, n, new, e, NULL);
+       if (e->rte.src->proto->rte_recalculate)
+         e->rte.src->proto->rte_recalculate(tab, n, &new->rte, &e->rte, NULL);
 
        if (e != old_best)
-         rte_free_quick(e);
+         rte_free(e, tab);
        else /* Freeing of the old best rte is postponed */
          free_old_best = 1;
 
@@ -2062,7 +1909,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
   new_best = NULL;
   for (k = &n->routes; e = *k; k = &e->next)
     {
-      if (!new_best || rte_better(e, *new_best))
+      if (!new_best || rte_better(&e->rte, &(*new_best)->rte))
        new_best = k;
     }
 
@@ -2077,13 +1924,13 @@ rt_next_hop_update_net(rtable *tab, net *n)
 
   /* Announce the new best route */
   if (new != old_best)
-    rte_trace_in(D_ROUTES, new->sender, new, "updated [best]");
+    rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated [best]");
 
   /* Propagate changes */
   rte_announce_i(tab, RA_UNDEF, n, NULL, NULL, n->routes, old_best);
 
   if (free_old_best)
-    rte_free_quick(old_best);
+    rte_free(old_best, tab);
 
   return count;
 }
@@ -2262,7 +2109,10 @@ do_feed_channel(struct channel *c, net *n, rte *e)
   else if (c->ra_mode == RA_MERGED)
     rt_notify_merged(c, n, NULL, NULL, e, e, c->refeeding);
   else /* RA_BASIC */
-    rt_notify_basic(c, n, e, e, c->refeeding);
+  {
+    rte e0 = *e;
+    rt_notify_basic(c, n->n.addr, &e0, &e0, c->refeeding);
+  }
   rte_update_unlock();
 }
 
@@ -2291,7 +2141,7 @@ rt_feed_channel(struct channel *c)
 
   FIB_ITERATE_START(&c->table->fib, fit, net, n)
     {
-      rte *e = n->routes;
+      struct rte_storage *e = n->routes;
       if (max_feed <= 0)
        {
          FIB_ITERATE_PUT(fit);
@@ -2301,13 +2151,13 @@ rt_feed_channel(struct channel *c)
       if ((c->ra_mode == RA_OPTIMAL) ||
          (c->ra_mode == RA_ACCEPTED) ||
          (c->ra_mode == RA_MERGED))
-       if (rte_is_valid(e))
+       if (e && rte_is_valid(&e->rte))
          {
            /* In the meantime, the protocol may fell down */
            if (c->export_state != ES_FEEDING)
              goto done;
 
-           do_feed_channel(c, n, e);
+           do_feed_channel(c, n, &e->rte);
            max_feed--;
          }
 
@@ -2318,10 +2168,10 @@ rt_feed_channel(struct channel *c)
            if (c->export_state != ES_FEEDING)
              goto done;
 
-           if (!rte_is_valid(e))
+           if (!rte_is_valid(&e->rte))
              continue;
 
-           do_feed_channel(c, n, e);
+           do_feed_channel(c, n, &e->rte);
            max_feed--;
          }
     }
@@ -2355,20 +2205,14 @@ rt_feed_channel_abort(struct channel *c)
  *     Import table
  */
 
-int
+static int
 rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 {
   struct rtable *tab = c->in_table;
-  rte *old, **pos;
   net *net;
 
   if (new)
-  {
     net = net_get(tab, n);
-
-    if (!rta_is_cached(new->attrs))
-      new->attrs = rta_lookup(new->attrs);
-  }
   else
   {
     net = net_find(tab, n);
@@ -2378,9 +2222,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
   }
 
   /* Find the old rte */
-  for (pos = &net->routes; old = *pos; pos = &old->next)
-    if (old->src == src)
+  struct rte_storage **pos = rte_find(net, src);
+  if (*pos)
     {
+      rte *old = &(*pos)->rte;
       if (new && rte_same(old, new))
       {
        /* Refresh the old rte, continue with update to main rtable */
@@ -2394,22 +2239,20 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
       }
 
       /* Move iterator if needed */
-      if (old == c->reload_next_rte)
-       c->reload_next_rte = old->next;
+      if (*pos == c->reload_next_rte)
+       c->reload_next_rte = (*pos)->next;
 
       /* Remove the old rte */
-      *pos = old->next;
-      rte_free_quick(old);
+      struct rte_storage *del = *pos;
+      *pos = (*pos)->next;
+      rte_free(del, tab);
       tab->rt_count--;
-
-      break;
     }
+  else if (!new)
+    goto drop_withdraw;
 
   if (!new)
   {
-    if (!old)
-      goto drop_withdraw;
-
     if (!net->routes)
       fib_delete(&tab->fib, net);
 
@@ -2417,7 +2260,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
   }
 
   struct channel_limit *l = &c->rx_limit;
-  if (l->action && !old)
+  if (l->action && !*pos)
   {
     if (tab->rt_count >= l->limit)
       channel_notify_limit(c, l, PLD_RX, tab->rt_count);
@@ -2425,7 +2268,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
     if (l->state == PLS_BLOCKED)
     {
       /* Required by rte_trace_in() */
-      new->net = net;
+      new->net = n;
 
       rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
       goto drop_update;
@@ -2433,11 +2276,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
   }
 
   /* Insert the new rte */
-  rte *e = rte_do_cow(new);
-  e->flags |= REF_COW;
-  e->net = net;
-  e->sender = c;
-  e->lastmod = current_time();
+  struct rte_storage *e = rte_store(new, net, tab);
+  e->rte.sender = c;
+  e->rte.lastmod = current_time();
   e->next = *pos;
   *pos = e;
   tab->rt_count++;
@@ -2446,7 +2287,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
 drop_update:
   c->stats.imp_updates_received++;
   c->stats.imp_updates_ignored++;
-  rte_free(new);
 
   if (!net->routes)
     fib_delete(&tab->fib, net);
@@ -2475,7 +2315,7 @@ rt_reload_channel(struct channel *c)
   }
 
   do {
-    for (rte *e = c->reload_next_rte; e; e = e->next)
+    for (struct rte_storage *e = c->reload_next_rte; e; e = e->next)
     {
       if (max_feed-- <= 0)
       {
@@ -2484,7 +2324,8 @@ rt_reload_channel(struct channel *c)
        return 0;
       }
 
-      rte_update2(c, e->net->n.addr, rte_do_cow(e), e->src);
+      rte r = e->rte;
+      rte_update(c, r.net, &r, r.src);
     }
 
     c->reload_next_rte = NULL;
@@ -2527,14 +2368,14 @@ rt_prune_sync(rtable *t, int all)
 again:
   FIB_ITERATE_START(&t->fib, &fit, net, n)
   {
-    rte *e, **ee = &n->routes;
+    struct rte_storage *e, **ee = &n->routes;
 
     while (e = *ee)
     {
-      if (all || (e->flags & (REF_STALE | REF_DISCARD)))
+      if (all || (e->rte.flags & (REF_STALE | REF_DISCARD)))
       {
        *ee = e->next;
-       rte_free_quick(e);
+       rte_free(e, t);
        t->rt_count--;
       }
       else
@@ -2557,20 +2398,16 @@ again:
  */
 
 int
-rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **old_exported, int refeed)
+rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct rte_storage **old_exported, int refeed)
 {
   struct rtable *tab = c->out_table;
   struct rte_src *src;
-  rte *old, **pos;
   net *net;
 
   if (new)
   {
     net = net_get(tab, n);
     src = new->src;
-
-    if (!rta_is_cached(new->attrs))
-      new->attrs = rta_lookup(new->attrs);
   }
   else
   {
@@ -2582,30 +2419,19 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **
   }
 
   /* Find the old rte */
-  for (pos = &net->routes; old = *pos; pos = &old->next)
-    if ((c->ra_mode != RA_ANY) || (old->src == src))
-    {
-      if (new && rte_same(old, new))
-      {
-       /* REF_STALE / REF_DISCARD not used in export table */
-       /*
-       if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
-       {
-         old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
-         return 1;
-       }
-       */
+  struct rte_storage **pos = (c->ra_mode == RA_ANY) ? rte_find(net, src) : &net->routes;
+  struct rte_storage *old = NULL;
 
-       goto drop_update;
-      }
-
-      /* Remove the old rte */
-      *pos = old->next;
-      *old_exported = old;
-      tab->rt_count--;
+  if (old = *pos)
+  {
+    if (new && rte_same(&(*pos)->rte, new))
+      goto drop_update;
 
-      break;
-    }
+    /* Remove the old rte */
+    *pos = old->next;
+    *old_exported = old;
+    tab->rt_count--;
+  }
 
   if (!new)
   {
@@ -2619,11 +2445,8 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **
   }
 
   /* Insert the new rte */
-  rte *e = rte_do_cow(new);
-  e->flags |= REF_COW;
-  e->net = net;
-  e->sender = c;
-  e->lastmod = current_time();
+  struct rte_storage *e = rte_store(new, net, tab);
+  e->rte.lastmod = current_time();
   e->next = *pos;
   *pos = e;
   tab->rt_count++;
@@ -2835,8 +2658,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
   net *n = net_route(tab, &he_addr);
   if (n)
     {
-      rte *e = n->routes;
-      rta *a = e->attrs;
+      struct rte_storage *e = n->routes;
+      rta *a = e->rte.attrs;
       pxlen = n->n.addr->pxlen;
 
       if (a->hostentry)
@@ -2867,7 +2690,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
       he->src = rta_clone(a);
       he->dest = a->dest;
       he->nexthop_linkable = !direct;
-      he->igp_metric = rt_get_igp_metric(e);
+      he->igp_metric = rt_get_igp_metric(&e->rte);
     }
 
 done:
index 07213c8c581a113628d30485c658dbdbbada3a1a..03c85b7d5d59bf501a706e32528d168da1da9f1f 100644 (file)
@@ -681,11 +681,13 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
     if (!neigh_find(&p->p, r->next_hop, r->neigh->ifa->iface, 0))
       a0.nh.flags = RNF_ONLINK;
 
-    rta *a = rta_lookup(&a0);
-    rte *rte = rte_get_temp(a, p->p.main_source);
+    rte e0 = {
+      .attrs = &a0,
+      .src = p->p.main_source,
+    };
 
     e->unreachable = 0;
-    rte_update2(c, e->n.addr, rte, p->p.main_source);
+    rte_update(c, e->n.addr, &e0, p->p.main_source);
   }
   else if (e->valid && (e->router_id != p->router_id))
   {
@@ -697,18 +699,19 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
       .pref = 1,
     };
 
-    rta *a = rta_lookup(&a0);
-    rte *rte = rte_get_temp(a, p->p.main_source);
-    rte->pflags = 0;
+    rte e0 = {
+      .attrs = &a0,
+      .src = p->p.main_source,
+    };
 
     e->unreachable = 1;
-    rte_update2(c, e->n.addr, rte, p->p.main_source);
+    rte_update(c, e->n.addr, &e0, p->p.main_source);
   }
   else
   {
     /* Retraction */
     e->unreachable = 0;
-    rte_update2(c, e->n.addr, NULL, p->p.main_source);
+    rte_update(c, e->n.addr, NULL, p->p.main_source);
   }
 }
 
@@ -718,7 +721,7 @@ babel_announce_retraction(struct babel_proto *p, struct babel_entry *e)
 {
   struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
   e->unreachable = 0;
-  rte_update2(c, e->n.addr, NULL, p->p.main_source);
+  rte_update(c, e->n.addr, NULL, p->p.main_source);
 }
 
 
@@ -2257,11 +2260,11 @@ babel_kick_timer(struct babel_proto *p)
 
 
 static int
-babel_preexport(struct proto *P, struct rte *new)
+babel_preexport(struct channel *c, struct rte *new)
 {
   struct rta *a = new->attrs;
   /* Reject our own unreachable routes */
-  if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P))
+  if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == c->proto))
     return -1;
 
   return 0;
@@ -2272,8 +2275,8 @@ babel_preexport(struct proto *P, struct rte *new)
  * so store it into our data structures.
  */
 static void
-babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
-               struct rte *new, struct rte *old UNUSED)
+babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
+               struct rte *new, const struct rte *old UNUSED)
 {
   struct babel_proto *p = (void *) P;
   struct babel_entry *e;
@@ -2301,11 +2304,11 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
     if (rt_metric > BABEL_INFINITY)
     {
       log(L_WARN "%s: Invalid babel_metric value %u for route %N",
-         p->p.name, rt_metric, net->n.addr);
+         p->p.name, rt_metric, net);
       rt_metric = BABEL_INFINITY;
     }
 
-    e = babel_get_entry(p, net->n.addr);
+    e = babel_get_entry(p, net);
 
     /* Activate triggered updates */
     if ((e->valid != BABEL_ENTRY_VALID) ||
@@ -2323,7 +2326,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
   else
   {
     /* Withdraw */
-    e = babel_find_entry(p, net->n.addr);
+    e = babel_find_entry(p, net);
 
     if (!e || e->valid != BABEL_ENTRY_VALID)
       return;
index 0ed2623e2d97f95a1b8ce04827cb041a6caff471..90490b4f46419a72b09461dec37cb73591893aae 100644 (file)
@@ -333,26 +333,26 @@ bgp_aigp_set_metric(struct linpool *pool, const struct adata *ad, u64 metric)
 }
 
 int
-bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad)
+bgp_total_aigp_metric_(struct rta *a, u64 *metric, const struct adata **ad)
 {
-  eattr *a = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP));
-  if (!a)
+  eattr *ea = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP));
+  if (!ea)
     return 0;
 
-  const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC);
+  const byte *b = bgp_aigp_get_tlv(ea->u.ptr, BGP_AIGP_METRIC);
   if (!b)
     return 0;
 
   u64 aigp = get_u64(b + 3);
-  u64 step = e->attrs->igp_metric;
+  u64 step = a->igp_metric;
 
-  if (!rte_resolvable(e) || (step >= IGP_METRIC_UNKNOWN))
+  if (!rta_resolvable(a) || (step >= IGP_METRIC_UNKNOWN))
     step = BGP_AIGP_MAX;
 
   if (!step)
     step = 1;
 
-  *ad = a->u.ptr;
+  *ad = ea->u.ptr;
   *metric = aigp + step;
   if (*metric < aigp)
     *metric = BGP_AIGP_MAX;
@@ -374,7 +374,7 @@ bgp_init_aigp_metric(rte *e, u64 *metric, const struct adata **ad)
 u32
 bgp_rte_igp_metric(struct rte *rt)
 {
-  u64 metric = bgp_total_aigp_metric(rt);
+  u64 metric = bgp_total_aigp_metric(rt->attrs);
   return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN);
 }
 
@@ -903,7 +903,7 @@ bgp_decode_large_community(struct bgp_parse_state *s, uint code UNUSED, uint fla
 static void
 bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
 {
-  net_addr *n = s->route->net->n.addr;
+  const net_addr *n = s->route->net;
   u32 *labels = (u32 *) a->u.ptr->data;
   uint lnum = a->u.ptr->length / 4;
 
@@ -1624,7 +1624,7 @@ bgp_free_prefix_table(struct bgp_channel *c)
 }
 
 static struct bgp_prefix *
-bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
+bgp_get_prefix(struct bgp_channel *c, const net_addr *net, u32 path_id)
 {
   u32 hash = net_hash(net) ^ u32_hash(path_id);
   struct bgp_prefix *px = HASH_FIND(c->prefix_hash, PXH, net, path_id, hash);
@@ -1668,10 +1668,10 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
  */
 
 int
-bgp_preexport(struct proto *P, rte *e)
+bgp_preexport(struct channel *c, rte *e)
 {
   struct proto *SRC = e->src->proto;
-  struct bgp_proto *p = (struct bgp_proto *) P;
+  struct bgp_proto *p = (struct bgp_proto *) (c->proto);
   struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
 
   /* Reject our routes */
@@ -1696,11 +1696,11 @@ bgp_preexport(struct proto *P, rte *e)
   }
 
   /* Handle well-known communities, RFC 1997 */
-  struct eattr *c;
+  struct eattr *com;
   if (p->cf->interpret_communities &&
-      (c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
+      (com = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
   {
-    const struct adata *d = c->u.ptr;
+    const struct adata *d = com->u.ptr;
 
     /* Do not export anywhere */
     if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
@@ -1780,7 +1780,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
   /* AIGP attribute - accumulate local metric or originate new one */
   u64 metric;
   if (s.local_next_hop &&
-      (bgp_total_aigp_metric_(e, &metric, &ad) ||
+      (bgp_total_aigp_metric_(e->attrs, &metric, &ad) ||
        (c->cf->aigp_originate && bgp_init_aigp_metric(e, &metric, &ad))))
   {
     ad = bgp_aigp_set_metric(pool, ad, metric);
@@ -1839,7 +1839,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
 }
 
 void
-bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
+bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old)
 {
   struct bgp_proto *p = (void *) P;
   struct bgp_channel *c = (void *) C;
@@ -1863,7 +1863,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
     path = old->src->global_id;
   }
 
-  px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0);
+  px = bgp_get_prefix(c, n, c->add_path_tx ? path : 0);
   add_tail(&buck->prefixes, &px->buck_node);
 
   bgp_schedule_packet(p->conn, c, PKT_UPDATE);
@@ -1924,8 +1924,8 @@ bgp_rte_better(rte *new, rte *old)
     return 1;
 
   /* RFC 4271 9.1.2.1. Route resolvability test */
-  n = rte_resolvable(new);
-  o = rte_resolvable(old);
+  n = rta_resolvable(new->attrs);
+  o = rta_resolvable(old->attrs);
   if (n > o)
     return 1;
   if (n < o)
@@ -1950,8 +1950,8 @@ bgp_rte_better(rte *new, rte *old)
     return 0;
 
   /* RFC 7311 4.1 - Apply AIGP metric */
-  u64 n2 = bgp_total_aigp_metric(new);
-  u64 o2 = bgp_total_aigp_metric(old);
+  u64 n2 = bgp_total_aigp_metric(new->attrs);
+  u64 o2 = bgp_total_aigp_metric(old->attrs);
   if (n2 < o2)
     return 1;
   if (n2 > o2)
@@ -2066,7 +2066,7 @@ bgp_rte_mergable(rte *pri, rte *sec)
     return 0;
 
   /* RFC 4271 9.1.2.1. Route resolvability test */
-  if (rte_resolvable(pri) != rte_resolvable(sec))
+  if (rta_resolvable(pri->attrs) != rta_resolvable(sec->attrs))
     return 0;
 
   /* Start with local preferences */
@@ -2135,16 +2135,15 @@ same_group(rte *r, u32 lpref, u32 lasn)
 }
 
 static inline int
-use_deterministic_med(rte *r)
+use_deterministic_med(struct rte_storage *r)
 {
-  struct proto *P = r->src->proto;
+  struct proto *P = r->rte.src->proto;
   return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
 }
 
 int
 bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
 {
-  rte *r, *s;
   rte *key = new ? new : old;
   u32 lpref = key->attrs->pref;
   u32 lasn = bgp_get_neighbor(key);
@@ -2212,13 +2211,13 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
   }
 
   /* The default case - find a new best-in-group route */
-  r = new; /* new may not be in the list */
-  for (s=net->routes; rte_is_valid(s); s=s->next)
-    if (use_deterministic_med(s) && same_group(s, lpref, lasn))
+  rte *r = new; /* new may not be in the list */
+  for (struct rte_storage *s = net->routes; rte_is_valid(&s->rte); s = s->next)
+    if (use_deterministic_med(s) && same_group(&s->rte, lpref, lasn))
     {
-      s->pflags |= BGP_REF_SUPPRESSED;
-      if (!r || bgp_rte_better(s, r))
-       r = s;
+      s->rte.pflags |= BGP_REF_SUPPRESSED;
+      if (!r || bgp_rte_better(&s->rte, r))
+       r = &s->rte;
     }
 
   /* Simple case - the last route in group disappears */
@@ -2230,10 +2229,10 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
     new->pflags &= ~BGP_REF_SUPPRESSED;
 
   /* Found all existing routes mergable with best-in-group */
-  for (s=net->routes; rte_is_valid(s); s=s->next)
-    if (use_deterministic_med(s) && same_group(s, lpref, lasn))
-      if ((s != r) && bgp_rte_mergable(r, s))
-       s->pflags &= ~BGP_REF_SUPPRESSED;
+  for (struct rte_storage *s = net->routes; rte_is_valid(&s->rte); s = s->next)
+    if (use_deterministic_med(s) && same_group(&s->rte, lpref, lasn))
+      if ((&s->rte != r) && bgp_rte_mergable(r, &s->rte))
+       s->rte.pflags &= ~BGP_REF_SUPPRESSED;
 
   /* Found best-in-group */
   r->pflags &= ~BGP_REF_SUPPRESSED;
@@ -2268,12 +2267,12 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
     return !old_suppressed;
 }
 
-struct rte *
+rte *
 bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
 {
-  eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
-  const struct adata *ad = a ? a->u.ptr : NULL;
-  uint flags = a ? a->flags : BAF_PARTIAL;
+  eattr *ea = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
+  const struct adata *ad = ea ? ea->u.ptr : NULL;
+  uint flags = ea ? ea->flags : BAF_PARTIAL;
 
   if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
     return NULL;
@@ -2281,12 +2280,17 @@ bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
   if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE))
     return r;
 
-  r = rte_cow_rta(r, pool);
-  bgp_set_attr_ptr(&(r->attrs->eattrs), pool, BA_COMMUNITY, flags,
+  rta *a = rta_do_cow(r->attrs, pool);
+  
+  _Thread_local static rte e0;
+  e0 = *r;
+  e0.attrs = a;
+
+  bgp_set_attr_ptr(&(a->eattrs), pool, BA_COMMUNITY, flags,
                   int_set_add(pool, ad, BGP_COMM_LLGR_STALE));
-  r->pflags |= BGP_REF_STALE;
+  e0.pflags |= BGP_REF_STALE;
 
-  return r;
+  return &e0;
 }
 
 
@@ -2377,14 +2381,14 @@ bgp_get_route_info(rte *e, byte *buf)
   if (rte_stale(e))
     buf += bsprintf(buf, "s");
 
-  u64 metric = bgp_total_aigp_metric(e);
+  u64 metric = bgp_total_aigp_metric(e->attrs);
   if (metric < BGP_AIGP_MAX)
   {
     buf += bsprintf(buf, "/%lu", metric);
   }
   else if (e->attrs->igp_metric)
   {
-    if (!rte_resolvable(e))
+    if (!rta_resolvable(e->attrs))
       buf += bsprintf(buf, "/-");
     else if (e->attrs->igp_metric >= IGP_METRIC_UNKNOWN)
       buf += bsprintf(buf, "/?");
index b770956bcff83782e09927c83e2389d19c40c299..c79dd1b2480aa1a30376e21126d95b66e356460d 100644 (file)
@@ -517,9 +517,9 @@ struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
 struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
 
 static inline int
-rte_resolvable(rte *rt)
+rta_resolvable(rta *a)
 {
-  return rt->attrs->dest == RTD_UNICAST;
+  return a->dest == RTD_UNICAST;
 }
 
 
@@ -587,22 +587,22 @@ int bgp_rte_mergable(rte *pri, rte *sec);
 int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
 struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
 u32 bgp_rte_igp_metric(struct rte *);
-void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
-int bgp_preexport(struct proto *, struct rte *);
+void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old);
+int bgp_preexport(struct channel *, struct rte *);
 int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
-void bgp_get_route_info(struct rte *, byte *buf);
-int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);
+void bgp_get_route_info(struct rte *, byte *);
+int bgp_total_aigp_metric_(rta *a, u64 *metric, const struct adata **ad);
 
 #define BGP_AIGP_METRIC                1
 #define BGP_AIGP_MAX           U64(0xffffffffffffffff)
 
 static inline u64
-bgp_total_aigp_metric(rte *r)
+bgp_total_aigp_metric(rta *a)
 {
   u64 metric = BGP_AIGP_MAX;
   const struct adata *ad;
 
-  bgp_total_aigp_metric_(r, &metric, &ad);
+  bgp_total_aigp_metric_(a, &metric, &ad);
   return metric;
 }
 
index 6bc71623e15cbde5ea60f00f99b6145c51a8cda2..647551e5f99c6e373fda547777a0ddb4354e5bb9 100644 (file)
@@ -1349,7 +1349,7 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
   if (!a0)
   {
     /* Route withdraw */
-    rte_update3(&s->channel->c, n, NULL, s->last_src);
+    rte_update(&s->channel->c, n, NULL, s->last_src);
     return;
   }
 
@@ -1362,11 +1362,12 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
     a0->eattrs = ea;
   }
 
-  rta *a = rta_clone(s->cached_rta);
-  rte *e = rte_get_temp(a, s->last_src);
+  rte e0 = {
+    .attrs = s->cached_rta,
+    .src = s->last_src,
+  };
 
-  e->pflags = 0;
-  rte_update3(&s->channel->c, n, e, s->last_src);
+  rte_update(&s->channel->c, n, &e0, s->last_src);
 }
 
 static void
index e885611aa9158bfdc7653939ea851894dfe87ec6..03f0d59e7ccd7012657ceda50ab7e69ca62bcbf9 100644 (file)
@@ -460,7 +460,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
   return;
 
 fail:
-  mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
+  mrt_log(s, "Attribute list too long for %N", r->net);
 }
 #endif
 
@@ -512,24 +512,21 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
   mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
   mrt_rib_table_header(s, n->n.addr);
 
-  rte *rt, *rt0;
-  for (rt0 = n->routes; rt = rt0; rt0 = rt0->next)
+  for (struct rte_storage *rt, *rt0 = n->routes; rt = rt0; rt0 = rt0->next)
   {
-    if (rte_is_filtered(rt))
+    if (rte_is_filtered(&rt->rte))
       continue;
 
     /* Skip routes that should be reported in the other phase */
-    if (!s->always_add_path && (!rt->src->private_id != !s->add_path))
+    if (!s->always_add_path && (!rt->rte.src->private_id != !s->add_path))
     {
       s->want_add_path = 1;
       continue;
     }
 
-    if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT)
-      mrt_rib_table_entry(s, rt);
-
-    if (rt != rt0)
-      rte_free(rt);
+    rte e = rt->rte;
+    if (f_run(s->filter, &e, s->linpool, 0) <= F_ACCEPT)
+      mrt_rib_table_entry(s, &e);
 
     lp_flush(s->linpool);
   }
index f9aa6cd19e3963e487bf9c1ff32b5f8df1d5d2b7..221505900b7b0600c5227a762a7efc6a3c03d07c 100644 (file)
 #include <stdlib.h>
 #include "ospf.h"
 
-static int ospf_preexport(struct proto *P, rte *new);
+static int ospf_preexport(struct channel *C, rte *new);
 static void ospf_reload_routes(struct channel *C);
 static int ospf_rte_better(struct rte *new, struct rte *old);
 static u32 ospf_rte_igp_metric(struct rte *rt);
@@ -482,13 +482,13 @@ ospf_disp(timer * timer)
  * import to the filters.
  */
 static int
-ospf_preexport(struct proto *P, rte *e)
+ospf_preexport(struct channel *c, rte *e)
 {
-  struct ospf_proto *p = (struct ospf_proto *) P;
+  struct ospf_proto *p = (struct ospf_proto *) c->proto;
   struct ospf_area *oa = ospf_main_area(p);
 
   /* Reject our own routes */
-  if (e->src->proto == P)
+  if (e->src->proto == c->proto)
     return -1;
 
   /* Do not export routes to stub areas */
index 471bb5860d8282878ce046fcc7a7e387d96a58bc..3e20802308177f78e30c51d83cd903c8468e96ad 100644 (file)
@@ -2096,15 +2096,18 @@ again1:
          .u.data = nf->n.rid,
        };
 
-       rta *a = rta_lookup(&a0);
-       rte *e = rte_get_temp(a, p->p.main_source);
-
        rta_free(nf->old_rta);
-       nf->old_rta = rta_clone(a);
+       nf->old_rta = rta_lookup(&a0);
+
+       rte e0 = {
+         .attrs = nf->old_rta,
+         .src = p->p.main_source,
+       };
 
        DBG("Mod rte type %d - %N via %I on iface %s, met %d\n",
            a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
-       rte_update(&p->p, nf->fn.addr, e);
+
+       rte_update(p->p.main_channel, nf->fn.addr, &e0, p->p.main_source);
       }
     }
     else if (nf->old_rta)
@@ -2113,7 +2116,7 @@ again1:
       rta_free(nf->old_rta);
       nf->old_rta = NULL;
 
-      rte_update(&p->p, nf->fn.addr, NULL);
+      rte_update(p->p.main_channel, nf->fn.addr, NULL, p->p.main_source);
     }
 
     /* Remove unused rt entry, some special entries are persistent */
@@ -2129,7 +2132,6 @@ again1:
   }
   FIB_ITERATE_END;
 
-
   WALK_LIST(oa, p->area_list)
   {
     /* Cleanup ASBR hash tables */
index 52c2a0cecaa2f817cdb33c838a22416e6c6839a6..bb88d20a091502f841ea4836f66abff4018de3bb 100644 (file)
@@ -1300,7 +1300,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
 }
 
 void
-ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
+ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED)
 {
   struct ospf_proto *p = (struct ospf_proto *) P;
   struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */
@@ -1319,7 +1319,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
 
   if (!new)
   {
-    nf = fib_find(&p->rtf, n->n.addr);
+    nf = fib_find(&p->rtf, n);
 
     if (!nf || !nf->external_rte)
       return;
@@ -1346,14 +1346,14 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
   if (m1 > LSINFINITY)
   {
     log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N",
-       p->p.name, m1, n->n.addr);
+       p->p.name, m1, n);
     m1 = LSINFINITY;
   }
 
   if (m2 > LSINFINITY)
   {
     log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N",
-       p->p.name, m2, n->n.addr);
+       p->p.name, m2, n);
     m2 = LSINFINITY;
   }
 
@@ -1377,12 +1377,12 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
     if (ipa_zero(fwd))
     {
       log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N",
-         p->p.name, n->n.addr);
+         p->p.name, n);
       return;
     }
   }
 
-  nf = fib_get(&p->rtf, n->n.addr);
+  nf = fib_get(&p->rtf, n);
   ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
   nf->external_rte = 1;
 }
index 535d1f1bb9aa3a83e779a1e631c2c8ac1b69b44d..c36d0b50d3ca67a8121c5a29273709206dbfcd6e 100644 (file)
@@ -200,7 +200,7 @@ void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 d
 void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn);
 void ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa);
 
-void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old);
+void ospf_rt_notify(struct proto *P, struct channel *ch, const net_addr *n, rte *new, const rte *old);
 void ospf_update_topology(struct ospf_proto *p);
 
 struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
index 52784c148ce48462f89033e0b2bbc15983811e9c..8b2cb69f1dae376f69a2d0e53e320d97c151fca4 100644 (file)
@@ -160,18 +160,17 @@ perf_loop(void *data)
 
   clock_gettime(CLOCK_MONOTONIC, &ts_generated);
 
-  for (uint i=0; i<N; i++) {
-    rte *e = rte_get_temp(p->data[i].a, p->p.main_source);
-    e->pflags = 0;
-
-    rte_update(P, &(p->data[i].net), e);
+  for (uint i=0; i<N; i++)
+  {
+    rte e0 = { .attrs = p->data[i].a, .src = P->main_source, };
+    rte_update(P->main_channel, &(p->data[i].net), &e0, P->main_source);
   }
 
   clock_gettime(CLOCK_MONOTONIC, &ts_update);
 
   if (!p->keep)
     for (uint i=0; i<N; i++)
-      rte_update(P, &(p->data[i].net), NULL);
+      rte_update(P->main_channel, &(p->data[i].net), NULL, P->main_source);
 
   clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);
 
@@ -204,7 +203,7 @@ perf_loop(void *data)
 }
 
 static void
-perf_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net UNUSED, struct rte *new UNUSED, struct rte *old UNUSED)
+perf_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net UNUSED, struct rte *new UNUSED, const struct rte *old UNUSED)
 {
   struct perf_proto *p = (struct perf_proto *) P;
   p->exp++;
index 978627804ca9e8f9f2be5dcffd87142afac95d13..3caa85d0496c9071ea12b4b3e2d6fcfd3b19b676 100644 (file)
 #endif
 
 static void
-pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old)
+pipe_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte *new, const rte *old)
 {
   struct pipe_proto *p = (void *) P;
   struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri;
-  struct rte_src *src;
-
-  rte *e;
-  rta *a;
 
   if (!new && !old)
     return;
@@ -63,45 +59,39 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
   if (dst->table->pipe_busy)
     {
       log(L_ERR "Pipe loop detected when sending %N to table %s",
-         n->n.addr, dst->table->name);
+         n, dst->table->name);
       return;
     }
 
+  src_ch->table->pipe_busy = 1;
+
   if (new)
     {
-      src = new->src;
-
-      a = alloca(rta_size(new->attrs));
+      rta *a = alloca(rta_size(new->attrs));
       memcpy(a, new->attrs, rta_size(new->attrs));
 
       a->cached = 0;
       a->hostentry = NULL;
-      e = rte_get_temp(a, src);
-      e->pflags = new->pflags;
 
-#ifdef CONFIG_BGP
-      /* Hack to cleanup cached value */
-      if (e->src->proto->proto == &proto_bgp)
-       e->pflags &= ~(BGP_REF_STALE | BGP_REF_NOT_STALE);
-#endif
+      rte e0 = {
+       .attrs = a,
+       .src = new->src,
+      };
+
+      rte_update(dst, n, &e0, new->src);
     }
   else
-    {
-      e = NULL;
-      src = old->src;
-    }
+    rte_update(dst, n, NULL, old->src);
 
-  src_ch->table->pipe_busy = 1;
-  rte_update2(dst, n->n.addr, e, src);
   src_ch->table->pipe_busy = 0;
 }
 
 static int
-pipe_preexport(struct proto *P, rte *e)
+pipe_preexport(struct channel *c, rte *e)
 {
   struct proto *pp = e->sender->proto;
 
-  if (pp == P)
+  if (pp == c->proto)
     return -1; /* Avoid local loops automatically */
 
   return 0;
index 540ff2a7a418e305c27bb55f88cc0086fbb7a9e5..fa228c6971082b6ad61c17c0a68d50f7e79aabc9 100644 (file)
@@ -385,16 +385,16 @@ radv_trigger_valid(struct radv_config *cf)
 }
 
 static inline int
-radv_net_match_trigger(struct radv_config *cf, net *n)
+radv_net_match_trigger(struct radv_config *cf, const net_addr *n)
 {
-  return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
+  return radv_trigger_valid(cf) && net_equal(n, &cf->trigger);
 }
 
 int
-radv_preexport(struct proto *P, rte *new)
+radv_preexport(struct channel *c, rte *new)
 {
   // struct radv_proto *p = (struct radv_proto *) P;
-  struct radv_config *cf = (struct radv_config *) (P->cf);
+  struct radv_config *cf = (struct radv_config *) (c->proto->cf);
 
   if (radv_net_match_trigger(cf, new->net))
     return RIC_PROCESS;
@@ -406,7 +406,7 @@ radv_preexport(struct proto *P, rte *new)
 }
 
 static void
-radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
+radv_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED)
 {
   struct radv_proto *p = (struct radv_proto *) P;
   struct radv_config *cf = (struct radv_config *) (P->cf);
@@ -457,14 +457,14 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
        (preference != RA_PREF_HIGH))
     {
       log(L_WARN "%s: Invalid ra_preference value %u on route %N",
-         p->p.name, preference, n->n.addr);
+         p->p.name, preference, n);
       preference = RA_PREF_MEDIUM;
       preference_set = 1;
       lifetime = 0;
       lifetime_set = 1;
     }
 
-    rt = fib_get(&p->routes, n->n.addr);
+    rt = fib_get(&p->routes, n);
 
     /* Ignore update if nothing changed */
     if (rt->valid &&
@@ -487,7 +487,7 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
   else
   {
     /* Withdraw */
-    rt = fib_find(&p->routes, n->n.addr);
+    rt = fib_find(&p->routes, n);
 
     if (!rt || !rt->valid)
       return;
@@ -555,7 +555,7 @@ radv_check_active(struct radv_proto *p)
     return 1;
 
   struct channel *c = p->p.main_channel;
-  return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
+  return rt_examine(c->table, &cf->trigger, c, c->out_filter);
 }
 
 static void
index a501a78434becc345eda94ce26ca2912478ad0c6..0a9844f30117e1b181b5f173004ba5ae0117b979 100644 (file)
@@ -207,16 +207,15 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
       .u.data = (uintptr_t) a0.nh.iface,
     };
 
-    rta *a = rta_lookup(&a0);
-    rte *e = rte_get_temp(a, p->p.main_source);
+    rte e0 = {
+      .attrs = &a0,
+      .src = p->p.main_source,
+    };
 
-    rte_update(&p->p, en->n.addr, e);
+    rte_update(p->p.main_channel, en->n.addr, &e0, p->p.main_source);
   }
   else
-  {
-    /* Withdraw */
-    rte_update(&p->p, en->n.addr, NULL);
-  }
+    rte_update(p->p.main_channel, en->n.addr, NULL, p->p.main_source);
 }
 
 /**
@@ -311,8 +310,8 @@ rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
  * it into our data structures.
  */
 static void
-rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
-             struct rte *old UNUSED)
+rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, struct rte *new,
+             const struct rte *old UNUSED)
 {
   struct rip_proto *p = (struct rip_proto *) P;
   struct rip_entry *en;
@@ -328,14 +327,14 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
     if (rt_metric > p->infinity)
     {
       log(L_WARN "%s: Invalid rip_metric value %u for route %N",
-         p->p.name, rt_metric, net->n.addr);
+         p->p.name, rt_metric, net);
       rt_metric = p->infinity;
     }
 
     if (rt_tag > 0xffff)
     {
       log(L_WARN "%s: Invalid rip_tag value %u for route %N",
-         p->p.name, rt_tag, net->n.addr);
+         p->p.name, rt_tag, net);
       rt_metric = p->infinity;
       rt_tag = 0;
     }
@@ -347,7 +346,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
      * collection.
      */
 
-    en = fib_get(&p->rtable, net->n.addr);
+    en = fib_get(&p->rtable, net);
 
     old_metric = en->valid ? en->metric : -1;
 
@@ -361,7 +360,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
   else
   {
     /* Withdraw */
-    en = fib_find(&p->rtable, net->n.addr);
+    en = fib_find(&p->rtable, net);
 
     if (!en || en->valid != RIP_ENTRY_VALID)
       return;
index be3d19abdfa1d559e7c519eaffd9f01ca2a5b779..72fbc967f8eefdf922c65d13680ddba4e5fbf504 100644 (file)
@@ -127,19 +127,16 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
     .dest = RTD_NONE,
   };
 
-  rta *a = rta_lookup(&a0);
-  rte *e = rte_get_temp(a, p->p.main_source);
+  rte e0 = { .attrs = &a0, .src = p->p.main_source, };
 
-  e->pflags = 0;
-
-  rte_update2(channel, &pfxr->n, e, e->src);
+  rte_update(channel, &pfxr->n, &e0, p->p.main_source);
 }
 
 void
 rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr)
 {
   struct rpki_proto *p = cache->p;
-  rte_update2(channel, &pfxr->n, NULL, p->p.main_source);
+  rte_update(channel, &pfxr->n, NULL, p->p.main_source);
 }
 
 
index 6d3871cc5946f82a09e6ec4ed098342405bb4773..6e258f6f3d2442cd7af8b80200bbe7f83e7b7174 100644 (file)
@@ -103,24 +103,13 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
     return;
 
   /* We skip rta_lookup() here */
-  rte *e = rte_get_temp(a, src);
-  e->pflags = 0;
+  rte e0 = { .attrs = a, .src = src, .net = r->net, }, *e = &e0;
 
+  /* Evaluate the filter */
   if (r->cmds)
-  {
-    /* Create a temporary table node */
-    e->net = alloca(sizeof(net) + r->net->length);
-    memset(e->net, 0, sizeof(net) + r->net->length);
-    net_copy(e->net->n.addr, r->net);
-
-    /* Evaluate the filter */
-    f_eval_rte(r->cmds, &e, static_lp);
-
-    /* Remove the temporary node */
-    e->net = NULL;
-  }
+    f_eval_rte(r->cmds, e, static_lp);
 
-  rte_update2(p->p.main_channel, r->net, e, src);
+  rte_update(p->p.main_channel, r->net, e, src);
   r->state = SRS_CLEAN;
 
   if (r->cmds)
@@ -132,7 +121,7 @@ withdraw:
   if (r->state == SRS_DOWN)
     return;
 
-  rte_update2(p->p.main_channel, r->net, NULL, src);
+  rte_update(p->p.main_channel, r->net, NULL, src);
   r->state = SRS_DOWN;
 }
 
@@ -298,7 +287,7 @@ static void
 static_remove_rte(struct static_proto *p, struct static_route *r)
 {
   if (r->state)
-    rte_update2(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
+    rte_update(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
 
   static_reset_rte(p, r);
 }
index 1b0384ce7839dcd917911fafec8a7c360f1fcde9..6f788ac230241f3b2320e1df11098445aa653a84 100644 (file)
@@ -374,7 +374,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
   /* p is NULL iff KRT_SHARED_SOCKET and !scan */
 
   int ipv6;
-  rte *e;
   net *net;
   sockaddr dst, gate, mask;
   ip_addr idst, igate, imask;
@@ -495,7 +494,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
   net = net_get(p->p.main_channel->table, &ndst);
 
   rta a = {
-    .src = p->p.main_source,
     .source = RTS_INHERIT,
     .scope = SCOPE_UNIVERSE,
   };
@@ -549,13 +547,12 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
       }
   }
 
- done:
-  e = rte_get_temp(&a);
-  e->net = net;
+ done:;
+  rte e0 = { .attrs = &a, .net = net, };
 
   ea_list *ea = alloca(sizeof(ea_list) + 1 * sizeof(eattr));
-  *ea = (ea_list) { .count = 1, .next = e->attrs->eattrs };
-  e->attrs->eattrs = ea;
+  *ea = (ea_list) { .count = 1, .next = e0.attrs->eattrs };
+  e0.attrs->eattrs = ea;
 
   ea->attrs[0] = (eattr) {
     .id = EA_KRT_SOURCE,
@@ -564,9 +561,9 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
   };
 
   if (scan)
-    krt_got_route(p, e, src);
+    krt_got_route(p, &e0, src);
   else
-    krt_got_route_async(p, e, new, src);
+    krt_got_route_async(p, &e0, new, src);
 }
 
 static void
index 4ecd887870916b9de5a31c5429face35fac7b9d2..bff2d579f4eb265d85bdbcdef1e1da3b6e38650e 100644 (file)
@@ -105,7 +105,7 @@ struct nl_parse_state
   int scan;
   int merge;
 
-  net *net;
+  net_addr *net;
   rta *attrs;
   struct krt_proto *proto;
   s8 new;
@@ -1233,10 +1233,9 @@ nh_bufsize(struct nexthop *nh)
 }
 
 static int
-nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
+nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nexthop *nh)
 {
   eattr *ea;
-  net *net = e->net;
   rta *a = e->attrs;
   ea_list *eattrs = a->eattrs;
   int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh));
@@ -1251,7 +1250,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
   int rsize = sizeof(*r) + bufsize;
   r = alloca(rsize);
 
-  DBG("nl_send_route(%N,op=%x)\n", net->n.addr, op);
+  DBG("nl_send_route(%N,op=%x)\n", e->net, op);
 
   bzero(&r->h, sizeof(r->h));
   bzero(&r->r, sizeof(r->r));
@@ -1260,7 +1259,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
   r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
 
   r->r.rtm_family = p->af;
-  r->r.rtm_dst_len = net_pxlen(net->n.addr);
+  r->r.rtm_dst_len = net_pxlen(e->net);
   r->r.rtm_protocol = RTPROT_BIRD;
   r->r.rtm_scope = RT_SCOPE_NOWHERE;
 #ifdef HAVE_MPLS_KERNEL
@@ -1272,7 +1271,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
      * 2) Never use RTA_PRIORITY
      */
 
-    u32 label = net_mpls(net->n.addr);
+    u32 label = net_mpls(e->net);
     nl_add_attr_mpls(&r->h, rsize, RTA_DST, 1, &label);
     r->r.rtm_scope = RT_SCOPE_UNIVERSE;
     r->r.rtm_type = RTN_UNICAST;
@@ -1280,12 +1279,12 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
   else
 #endif
   {
-    nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
+    nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(e->net));
 
     /* Add source address for IPv6 SADR routes */
-    if (net->n.addr->type == NET_IP6_SADR)
+    if (e->net->type == NET_IP6_SADR)
     {
-      net_addr_ip6_sadr *a = (void *) &net->n.addr;
+      net_addr_ip6_sadr *a = (void *) &e->net;
       nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix);
       r->r.rtm_src_len = a->src_pxlen;
     }
@@ -1406,7 +1405,7 @@ nl_add_rte(struct krt_proto *p, rte *e)
 }
 
 static inline int
-nl_delete_rte(struct krt_proto *p, rte *e)
+nl_delete_rte(struct krt_proto *p, const rte *e)
 {
   int err = 0;
 
@@ -1427,7 +1426,7 @@ nl_replace_rte(struct krt_proto *p, rte *e)
 
 
 void
-krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
+krt_replace_rte(struct krt_proto *p, const net_addr *n UNUSED, rte *new, const rte *old)
 {
   int err = 0;
 
@@ -1466,7 +1465,7 @@ krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
 }
 
 static int
-nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family)
+nl_mergable_route(struct nl_parse_state *s, const net_addr *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family)
 {
   /* Route merging is used for IPv6 scans */
   if (!s->scan || (rtm_family != AF_INET6))
@@ -1486,12 +1485,14 @@ nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint
 static void
 nl_announce_route(struct nl_parse_state *s)
 {
-  rte *e = rte_get_temp(s->attrs, s->proto->p.main_source);
-  e->net = s->net;
+  rte e0 = {
+    .attrs = s->attrs,
+    .net = s->net,
+  };
 
   ea_list *ea = alloca(sizeof(ea_list) + 2 * sizeof(eattr));
-  *ea = (ea_list) { .count = 2, .next = e->attrs->eattrs };
-  e->attrs->eattrs = ea;
+  *ea = (ea_list) { .count = 2, .next = e0.attrs->eattrs };
+  e0.attrs->eattrs = ea;
 
   ea->attrs[0] = (eattr) {
     .id = EA_KRT_SOURCE,
@@ -1505,9 +1506,9 @@ nl_announce_route(struct nl_parse_state *s)
   };
 
   if (s->scan)
-    krt_got_route(s->proto, e, s->krt_src);
+    krt_got_route(s->proto, &e0, s->krt_src);
   else
-    krt_got_route_async(s->proto, e, s->new, s->krt_src);
+    krt_got_route_async(s->proto, &e0, s->new, s->krt_src);
 
   s->net = NULL;
   s->attrs = NULL;
@@ -1653,16 +1654,14 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
       krt_src = KRT_SRC_ALIEN;
     }
 
-  net_addr *n = &dst;
+  net_addr *net = &dst;
   if (p->p.net_type == NET_IP6_SADR)
   {
-    n = alloca(sizeof(net_addr_ip6_sadr));
-    net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst),
+    net = alloca(sizeof(net_addr_ip6_sadr));
+    net_fill_ip6_sadr(net, net6_prefix(&dst), net6_pxlen(&dst),
                      net6_prefix(&src), net6_pxlen(&src));
   }
 
-  net *net = net_get(p->p.main_channel->table, n);
-
   if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type, i->rtm_family))
     nl_announce_route(s);
 
@@ -1685,7 +1684,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
          struct nexthop *nh = nl_parse_multipath(s, p, a[RTA_MULTIPATH], i->rtm_family);
          if (!nh)
            {
-             log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
+             log(L_ERR "KRT: Received strange multipath route %N", net);
              return;
            }
 
@@ -1699,7 +1698,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
       ra->nh.iface = if_find_by_index(oif);
       if (!ra->nh.iface)
        {
-         log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif);
+         log(L_ERR "KRT: Received route %N with unknown ifindex %u", net, oif);
          return;
        }
 
@@ -1726,8 +1725,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
                           (ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
          if (!nbr || (nbr->scope == SCOPE_HOST))
            {
-             log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr,
-                  ra->nh.gw);
+             log(L_ERR "KRT: Received route %N with strange next-hop %I", net, ra->nh.gw);
              return;
            }
        }
@@ -1826,7 +1824,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
 
       if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
         {
-         log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
+         log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net);
          return;
        }
 
@@ -1860,7 +1858,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
   if (!s->net)
   {
     /* Store the new route */
-    s->net = net;
+    s->net = lp_alloc(s->pool, net->length);
+    net_copy(s->net, net);
+
     s->attrs = ra;
     s->proto = p;
     s->new = new;
index 7d7ec7e6e606a73bb16708f0bc2e0ade3222ec93..0a746631c1fadeab4c69a94649e7882df8e965ad 100644 (file)
@@ -251,14 +251,14 @@ static inline void
 krt_trace_in(struct krt_proto *p, rte *e, char *msg)
 {
   if (p->p.debug & D_PACKETS)
-    log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
+    log(L_TRACE "%s: %N: %s", p->p.name, e->net, msg);
 }
 
 static inline void
 krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
 {
   if (p->p.debug & D_PACKETS)
-    log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
+    log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net, msg);
 }
 
 /*
@@ -299,54 +299,56 @@ krt_uptodate(rte *a, rte *b)
 static void
 krt_learn_announce_update(struct krt_proto *p, rte *e)
 {
-  net *n = e->net;
-  rta *aa = rta_clone(e->attrs);
-  rte *ee = rte_get_temp(aa, p->p.main_source);
-  rte_update(&p->p, n->n.addr, ee);
+  rte e0 = {
+    .attrs = rta_clone(e->attrs),
+    .src = p->p.main_source,
+  };
+
+  rte_update(p->p.main_channel, e->net, &e0, p->p.main_source);
 }
 
 static void
-krt_learn_announce_delete(struct krt_proto *p, net *n)
+krt_learn_announce_delete(struct krt_proto *p, net_addr *n)
 {
-  rte_update(&p->p, n->n.addr, NULL);
+  rte_update(p->p.main_channel, n, NULL, p->p.main_source);
 }
 
 /* Called when alien route is discovered during scan */
 static void
 krt_learn_scan(struct krt_proto *p, rte *e)
 {
-  net *n0 = e->net;
-  net *n = net_get(p->krt_table, n0->n.addr);
-  rte *m, **mm;
+  net *n = net_get(p->krt_table, e->net);
+  struct rte_storage *m, **mm;
 
-  e->attrs = rta_lookup(e->attrs);
+  struct rte_storage *ee = rte_store(e, n, p->krt_table);
 
-  for(mm=&n->routes; m = *mm; mm=&m->next)
-    if (krt_same_key(m, e))
+  for(mm = &n->routes; m = *mm; mm = &m->next)
+    if (krt_same_key(&m->rte, e))
       break;
   if (m)
     {
-      if (krt_uptodate(m, e))
+      if (krt_uptodate(&m->rte, e))
        {
          krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
-         rte_free(e);
-         m->pflags |= KRT_REF_SEEN;
+         rte_free(ee, p->krt_table);
+         m->rte.pflags |= KRT_REF_SEEN;
        }
       else
        {
          krt_trace_in(p, e, "[alien] updated");
          *mm = m->next;
-         rte_free(m);
+         rte_free(m, p->krt_table);
          m = NULL;
        }
     }
   else
     krt_trace_in(p, e, "[alien] created");
+
   if (!m)
     {
-      e->next = n->routes;
-      n->routes = e;
-      e->pflags |= KRT_REF_SEEN;
+      ee->next = n->routes;
+      n->routes = ee;
+      ee->rte.pflags |= KRT_REF_SEEN;
     }
 }
 
@@ -362,7 +364,7 @@ krt_learn_prune(struct krt_proto *p)
 again:
   FIB_ITERATE_START(fib, &fit, net, n)
     {
-      rte *e, **ee, *best, **pbest, *old_best;
+      struct rte_storage *e, **ee, *best, **pbest, *old_best;
 
       /*
        * Note that old_best may be NULL even if there was an old best route in
@@ -376,48 +378,48 @@ again:
       ee = &n->routes;
       while (e = *ee)
        {
-         if (e->pflags & KRT_REF_BEST)
+         if (e->rte.pflags & KRT_REF_BEST)
            old_best = e;
 
-         if (!(e->pflags & KRT_REF_SEEN))
+         if (!(e->rte.pflags & KRT_REF_SEEN))
            {
              *ee = e->next;
-             rte_free(e);
+             rte_free(e, p->krt_table);
              continue;
            }
 
-         if (!best || krt_metric(best) > krt_metric(e))
+         if (!best || krt_metric(&best->rte) > krt_metric(&e->rte))
            {
              best = e;
              pbest = ee;
            }
 
-         e->pflags &= ~(KRT_REF_SEEN | KRT_REF_BEST);
+         e->rte.pflags &= ~(KRT_REF_SEEN | KRT_REF_BEST);
          ee = &e->next;
        }
       if (!n->routes)
        {
          DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
          if (old_best)
-           krt_learn_announce_delete(p, n);
+           krt_learn_announce_delete(p, n->n.addr);
 
          FIB_ITERATE_PUT(&fit);
          fib_delete(fib, n);
          goto again;
        }
 
-      best->pflags |= KRT_REF_BEST;
+      best->rte.pflags |= KRT_REF_BEST;
       *pbest = best->next;
       best->next = n->routes;
       n->routes = best;
 
       if ((best != old_best) || p->reload)
        {
-         DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best));
-         krt_learn_announce_update(p, best);
+         DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(&best->rte));
+         krt_learn_announce_update(p, &best->rte);
        }
       else
-       DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best));
+       DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(&best->rte));
     }
   FIB_ITERATE_END;
 
@@ -427,68 +429,67 @@ again:
 static void
 krt_learn_async(struct krt_proto *p, rte *e, int new)
 {
-  net *n0 = e->net;
-  net *n = net_get(p->krt_table, n0->n.addr);
-  rte *g, **gg, *best, **bestp, *old_best;
+  net *n = net_get(p->krt_table, e->net);
+  struct rte_storage *g, **gg, *best, **bestp, *old_best;
 
   ASSERT(!e->attrs->cached);
   e->attrs->pref = p->p.main_channel->preference;
 
-  e->attrs = rta_lookup(e->attrs);
+  struct rte_storage *ee = rte_store(e, n, p->krt_table);
 
   old_best = n->routes;
   for(gg=&n->routes; g = *gg; gg = &g->next)
-    if (krt_same_key(g, e))
+    if (krt_same_key(&g->rte, e))
       break;
   if (new)
     {
       if (g)
        {
-         if (krt_uptodate(g, e))
+         if (krt_uptodate(&g->rte, e))
            {
              krt_trace_in(p, e, "[alien async] same");
-             rte_free(e);
+             rte_free(ee, p->krt_table);
              return;
            }
          krt_trace_in(p, e, "[alien async] updated");
          *gg = g->next;
-         rte_free(g);
+         rte_free(g, p->krt_table);
        }
       else
        krt_trace_in(p, e, "[alien async] created");
 
-      e->next = n->routes;
-      n->routes = e;
+      ee->next = n->routes;
+      n->routes = ee;
     }
   else if (!g)
     {
       krt_trace_in(p, e, "[alien async] delete failed");
-      rte_free(e);
+      rte_free(ee, p->krt_table);
       return;
     }
   else
     {
       krt_trace_in(p, e, "[alien async] removed");
       *gg = g->next;
-      rte_free(e);
-      rte_free(g);
+      rte_free(ee, p->krt_table);
+      rte_free(g, p->krt_table);
     }
   best = n->routes;
   bestp = &n->routes;
   for(gg=&n->routes; g=*gg; gg=&g->next)
   {
-    if (krt_metric(best) > krt_metric(g))
+    if (krt_metric(&best->rte) > krt_metric(&g->rte))
       {
        best = g;
        bestp = gg;
       }
 
-    g->pflags &= ~KRT_REF_BEST;
+    g->rte.pflags &= ~KRT_REF_BEST;
   }
 
   if (best)
     {
-      best->pflags |= KRT_REF_BEST;
+      best->rte.pflags |= KRT_REF_BEST;
       *bestp = best->next;
       best->next = n->routes;
       n->routes = best;
@@ -498,9 +499,9 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
     {
       DBG("krt_learn_async: distributing change\n");
       if (best)
-       krt_learn_announce_update(p, best);
+       krt_learn_announce_update(p, &best->rte);
       else
-       krt_learn_announce_delete(p, n);
+       krt_learn_announce_delete(p, n->n.addr);
     }
 }
 
@@ -538,7 +539,7 @@ krt_dump(struct proto *P)
 static inline int
 krt_is_installed(struct krt_proto *p, net *n)
 {
-  return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id);
+  return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->rte.id);
 }
 
 static void
@@ -552,26 +553,25 @@ krt_flush_routes(struct krt_proto *p)
       if (krt_is_installed(p, n))
        {
          /* FIXME: this does not work if gw is changed in export filter */
-         krt_replace_rte(p, n, NULL, n->routes);
+         krt_replace_rte(p, n->n.addr, NULL, &n->routes->rte);
        }
     }
   FIB_WALK_END;
 }
 
 static struct rte *
-krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
+krt_export_net(struct krt_proto *p, net *net)
 {
   struct channel *c = p->p.main_channel;
   const struct filter *filter = c->out_filter;
-  rte *rt;
 
   if (c->ra_mode == RA_MERGED)
-    return rt_export_merged(c, net, rt_free, krt_filter_lp, 1);
+    return rt_export_merged(c, net, krt_filter_lp, 1);
 
-  rt = net->routes;
-  *rt_free = NULL;
+  static _Thread_local rte rt;
+  rt = net->routes->rte;
 
-  if (!rte_is_valid(rt))
+  if (!rte_is_valid(&rt))
     return NULL;
 
   if (filter == FILTER_REJECT)
@@ -587,13 +587,9 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
 
 
 accept:
-  if (rt != net->routes)
-    *rt_free = rt;
-  return rt;
+  return &rt;
 
 reject:
-  if (rt != net->routes)
-    rte_free(rt);
   return NULL;
 }
 
@@ -619,8 +615,7 @@ krt_same_dest(rte *k, rte *e)
 void
 krt_got_route(struct krt_proto *p, rte *e, s8 src)
 {
-  rte *new = NULL, *rt_free = NULL;
-  net *n = e->net;
+  rte *new = NULL;
   e->pflags = 0;
 
 #ifdef KRT_ALLOW_LEARN
@@ -636,10 +631,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
       if (KRT_CF->learn)
        krt_learn_scan(p, e);
       else
-       {
-         krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
-         rte_free(e);
-       }
+       krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
       return;
     }
 #endif
@@ -650,10 +642,11 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
   if (!p->ready)
     goto ignore;
 
-  if (!krt_is_installed(p, n))
+  net *net = net_find(p->p.main_channel->table, e->net);
+  if (!net || !krt_is_installed(p, net))
     goto delete;
 
-  new = krt_export_net(p, n, &rt_free);
+  new = krt_export_net(p, net);
 
   /* Rejected by filters */
   if (!new)
@@ -686,20 +679,15 @@ ignore:
 
 update:
   krt_trace_in(p, new, "updating");
-  krt_replace_rte(p, n, new, e);
+  krt_replace_rte(p, e->net, new, e);
   goto done;
 
 delete:
   krt_trace_in(p, e, "deleting");
-  krt_replace_rte(p, n, NULL, e);
+  krt_replace_rte(p, e->net, NULL, e);
   goto done;
 
 done:
-  rte_free(e);
-
-  if (rt_free)
-    rte_free(rt_free);
-
   lp_flush(krt_filter_lp);
 }
 
@@ -717,20 +705,16 @@ krt_prune(struct krt_proto *p)
   KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
   FIB_WALK(&t->fib, net, n)
   {
-    if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id))
+    if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->rte.id))
     {
-      rte *rt_free = NULL;
-      rte *new = krt_export_net(p, n, &rt_free);
+      rte *new = krt_export_net(p, n);
 
       if (new)
       {
        krt_trace_in(p, new, "installing");
-       krt_replace_rte(p, n, new, NULL);
+       krt_replace_rte(p, n->n.addr, new, NULL);
       }
 
-      if (rt_free)
-       rte_free(rt_free);
-
       lp_flush(krt_filter_lp);
     }
   }
@@ -748,7 +732,6 @@ krt_prune(struct krt_proto *p)
 void
 krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
 {
-  net *net = e->net;
   e->pflags = 0;
 
   switch (src)
@@ -761,7 +744,7 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
       if (new)
        {
          krt_trace_in(p, e, "[redirect] deleting");
-         krt_replace_rte(p, net, NULL, e);
+         krt_replace_rte(p, e->net, NULL, e);
        }
       /* If !new, it is probably echo of our deletion */
       break;
@@ -775,7 +758,6 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
        }
 #endif
     }
-  rte_free(e);
 }
 
 /*
@@ -882,10 +864,9 @@ krt_scan_timer_kick(struct krt_proto *p)
  */
 
 static int
-krt_preexport(struct proto *P, rte *e)
+krt_preexport(struct channel *c, rte *e)
 {
-  // struct krt_proto *p = (struct krt_proto *) P;
-  if (e->src->proto == P)
+  if (e->src->proto == c->proto)
     return -1;
 
   if (!krt_capable(e))
@@ -895,8 +876,8 @@ krt_preexport(struct proto *P, rte *e)
 }
 
 static void
-krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net,
-             rte *new, rte *old)
+krt_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net,
+             rte *new, const rte *old)
 {
   struct krt_proto *p = (struct krt_proto *) P;
 
index 20858cd79fedd731c2661489528fcbedeb6ce393..cd4bd07d90c8e84863da3992bff2902d62635a89 100644 (file)
@@ -143,7 +143,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *);
 
 int  krt_capable(rte *e);
 void krt_do_scan(struct krt_proto *);
-void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old);
+void krt_replace_rte(struct krt_proto *p, const net_addr *n, rte *new, const rte *old);
 int krt_sys_get_attr(const eattr *a, byte *buf, int buflen);