summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r--nest/rt-table.c378
1 files changed, 72 insertions, 306 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index a10979e6..fbfdb1e6 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -548,7 +548,7 @@ rte_find(net *net, struct rte_src *src)
{
rte *e = net->routes;
- while (e && e->attrs->src != src)
+ while (e && e->src != src)
e = e->next;
return e;
}
@@ -563,14 +563,14 @@ rte_find(net *net, struct rte_src *src)
* the protocol.
*/
rte *
-rte_get_temp(rta *a)
+rte_get_temp(rta *a, struct rte_src *src)
{
rte *e = sl_alloc(rte_slab);
e->attrs = a;
e->id = 0;
e->flags = 0;
- e->pref = 0;
+ rt_lock_source(e->src = src);
return e;
}
@@ -580,6 +580,8 @@ rte_do_cow(rte *r)
rte *e = sl_alloc(rte_slab);
memcpy(e, r, sizeof(rte));
+
+ rt_lock_source(e->src);
e->attrs = rta_clone(r->attrs);
e->flags = 0;
return e;
@@ -617,176 +619,29 @@ rte_cow_rta(rte *r, linpool *lp)
return r;
}
-
-/**
- * rte_init_tmp_attrs - initialize temporary ea_list for route
- * @r: route entry to be modified
- * @lp: linpool from which to allocate attributes
- * @max: maximum number of added temporary attribus
- *
- * This function is supposed to be called from make_tmp_attrs() and
- * store_tmp_attrs() hooks before rte_make_tmp_attr() / rte_store_tmp_attr()
- * functions. It allocates &ea_list with length for @max items for temporary
- * attributes and puts it on top of eattrs stack.
- */
-void
-rte_init_tmp_attrs(rte *r, linpool *lp, uint max)
-{
- struct ea_list *e = lp_alloc(lp, sizeof(struct ea_list) + max * sizeof(eattr));
-
- e->next = r->attrs->eattrs;
- e->flags = EALF_SORTED | EALF_TEMP;
- e->count = 0;
-
- r->attrs->eattrs = e;
-}
-
-/**
- * rte_make_tmp_attr - make temporary eattr from private route fields
- * @r: route entry to be modified
- * @id: attribute ID
- * @type: attribute type
- * @val: attribute value (u32 or adata ptr)
- *
- * This function is supposed to be called from make_tmp_attrs() hook for
- * each temporary attribute, after temporary &ea_list was initialized by
- * rte_init_tmp_attrs(). It checks whether temporary attribute is supposed to
- * be defined (based on route pflags) and if so then it fills &eattr field in
- * preallocated temporary &ea_list on top of route @r eattrs stack.
- *
- * Note that it may require free &eattr in temporary &ea_list, so it must not be
- * called more times than @max argument of rte_init_tmp_attrs().
- */
-void
-rte_make_tmp_attr(rte *r, uint id, uint type, uintptr_t val)
-{
- if (r->pflags & EA_ID_FLAG(id))
- {
- ea_list *e = r->attrs->eattrs;
- eattr *a = &e->attrs[e->count++];
- a->id = id;
- a->type = type;
- a->flags = 0;
-
- if (type & EAF_EMBEDDED)
- a->u.data = (u32) val;
- else
- a->u.ptr = (struct adata *) val;
- }
-}
-
-/**
- * rte_store_tmp_attr - store temporary eattr to private route fields
- * @r: route entry to be modified
- * @id: attribute ID
- *
- * This function is supposed to be called from store_tmp_attrs() hook for
- * each temporary attribute, after temporary &ea_list was initialized by
- * rte_init_tmp_attrs(). It checks whether temporary attribute is defined in
- * route @r eattrs stack, updates route pflags accordingly, undefines it by
- * filling &eattr field in preallocated temporary &ea_list on top of the eattrs
- * stack, and returns the value. Caller is supposed to store it in the
- * appropriate private field.
- *
- * Note that it may require free &eattr in temporary &ea_list, so it must not be
- * called more times than @max argument of rte_init_tmp_attrs()
- */
-uintptr_t
-rte_store_tmp_attr(rte *r, uint id)
-{
- ea_list *e = r->attrs->eattrs;
- eattr *a = ea_find(e->next, id);
-
- if (a)
- {
- e->attrs[e->count++] = (struct eattr) { .id = id, .type = EAF_TYPE_UNDEF };
- r->pflags |= EA_ID_FLAG(id);
- return (a->type & EAF_EMBEDDED) ? a->u.data : (uintptr_t) a->u.ptr;
- }
- else
- {
- r->pflags &= ~EA_ID_FLAG(id);
- return 0;
- }
-}
-
/**
- * rte_make_tmp_attrs - prepare route by adding all relevant temporary route attributes
- * @r: route entry to be modified (may be replaced if COW)
- * @lp: linpool from which to allocate attributes
- * @old_attrs: temporary ref to old &rta (may be NULL)
- *
- * This function expands privately stored protocol-dependent route attributes
- * to a uniform &eattr / &ea_list representation. It is essentially a wrapper
- * around protocol make_tmp_attrs() hook, which does some additional work like
- * ensuring that route @r is writable.
- *
- * The route @r may be read-only (with %REF_COW flag), in that case rw copy is
- * obtained by rte_cow() and @r is replaced. If @rte is originally rw, it may be
- * directly modified (and it is never copied).
- *
- * If the @old_attrs ptr is supplied, the function obtains another reference of
- * old cached &rta, that is necessary in some cases (see rte_cow_rta() for
- * details). It is freed by rte_store_tmp_attrs(), or manually by rta_free().
+ * rte_free - delete a &rte
+ * @e: &rte to be deleted
*
- * Generally, if caller ensures that @r is read-only (e.g. in route export) then
- * it may ignore @old_attrs (and set it to NULL), but must handle replacement of
- * @r. If caller ensures that @r is writable (e.g. in route import) then it may
- * ignore replacement of @r, but it must handle @old_attrs.
+ * rte_free() deletes the given &rte from the routing table it's linked to.
*/
void
-rte_make_tmp_attrs(rte **r, linpool *lp, rta **old_attrs)
+rte_free(rte *e)
{
- void (*make_tmp_attrs)(rte *r, linpool *lp);
- make_tmp_attrs = (*r)->attrs->src->proto->make_tmp_attrs;
-
- if (!make_tmp_attrs)
- return;
-
- /* We may need to keep ref to old attributes, will be freed in rte_store_tmp_attrs() */
- if (old_attrs)
- *old_attrs = rta_is_cached((*r)->attrs) ? rta_clone((*r)->attrs) : NULL;
-
- *r = rte_cow_rta(*r, lp);
- make_tmp_attrs(*r, lp);
+ rt_unlock_source(e->src);
+ if (rta_is_cached(e->attrs))
+ rta_free(e->attrs);
+ sl_free(e);
}
-/**
- * rte_store_tmp_attrs - store temporary route attributes back to private route fields
- * @r: route entry to be modified
- * @lp: linpool from which to allocate attributes
- * @old_attrs: temporary ref to old &rta
- *
- * This function stores temporary route attributes that were expanded by
- * rte_make_tmp_attrs() back to private route fields and also undefines them.
- * It is essentially a wrapper around protocol store_tmp_attrs() hook, which
- * does some additional work like shortcut if there is no change and cleanup
- * of @old_attrs reference obtained by rte_make_tmp_attrs().
- */
-static void
-rte_store_tmp_attrs(rte *r, linpool *lp, rta *old_attrs)
+static inline void
+rte_free_quick(rte *e)
{
- void (*store_tmp_attrs)(rte *rt, linpool *lp);
- store_tmp_attrs = r->attrs->src->proto->store_tmp_attrs;
-
- if (!store_tmp_attrs)
- return;
-
- ASSERT(!rta_is_cached(r->attrs));
-
- /* If there is no new ea_list, we just skip the temporary ea_list */
- ea_list *ea = r->attrs->eattrs;
- if (ea && (ea->flags & EALF_TEMP))
- r->attrs->eattrs = ea->next;
- else
- store_tmp_attrs(r, lp);
-
- /* Free ref we got in rte_make_tmp_attrs(), have to do rta_lookup() first */
- r->attrs = rta_lookup(r->attrs);
- rta_free(old_attrs);
+ rt_unlock_source(e->src);
+ rta_free(e->attrs);
+ sl_free(e);
}
-
static int /* Actually better or at least as good as */
rte_better(rte *new, rte *old)
{
@@ -797,20 +652,20 @@ rte_better(rte *new, rte *old)
if (!rte_is_valid(new))
return 0;
- if (new->pref > old->pref)
+ if (new->attrs->pref > old->attrs->pref)
return 1;
- if (new->pref < old->pref)
+ if (new->attrs->pref < old->attrs->pref)
return 0;
- if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
+ if (new->src->proto->proto != old->src->proto->proto)
{
/*
* If the user has configured protocol preferences, so that two different protocols
* have the same preference, try to break the tie by comparing addresses. Not too
* useful, but keeps the ordering of routes unambiguous.
*/
- return new->attrs->src->proto->proto > old->attrs->src->proto->proto;
+ return new->src->proto->proto > old->src->proto->proto;
}
- if (better = new->attrs->src->proto->rte_better)
+ if (better = new->src->proto->rte_better)
return better(new, old);
return 0;
}
@@ -823,13 +678,13 @@ rte_mergable(rte *pri, rte *sec)
if (!rte_is_valid(pri) || !rte_is_valid(sec))
return 0;
- if (pri->pref != sec->pref)
+ if (pri->attrs->pref != sec->attrs->pref)
return 0;
- if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto)
+ if (pri->src->proto->proto != sec->src->proto->proto)
return 0;
- if (mergable = pri->attrs->src->proto->rte_mergable)
+ if (mergable = pri->src->proto->rte_mergable)
return mergable(pri, sec);
return 0;
@@ -838,8 +693,8 @@ rte_mergable(rte *pri, rte *sec)
static void
rte_trace(struct channel *c, rte *e, int dir, char *msg)
{
- log(L_TRACE "%s.%s %c %s %N %s",
- c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr,
+ 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,
rta_dest_name(e->attrs->dest));
}
@@ -869,7 +724,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
rt = rt0;
*rt_free = NULL;
- v = p->preexport ? p->preexport(p, &rt, pool) : 0;
+ v = p->preexport ? p->preexport(p, rt) : 0;
if (v < 0)
{
if (silent)
@@ -887,8 +742,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
goto accept;
}
- rte_make_tmp_attrs(&rt, pool, NULL);
-
v = filter && ((filter == FILTER_REJECT) ||
(f_run(filter, &rt, pool,
(silent ? FF_SILENT : 0)) > F_ACCEPT));
@@ -902,12 +755,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
goto reject;
}
-#ifdef CONFIG_PIPE
- /* Pipes need rte with stored tmpattrs, remaining protocols need expanded tmpattrs */
- if (p->proto == &proto_pipe)
- rte_store_tmp_attrs(rt, pool, NULL);
-#endif
-
accept:
if (rt != rt0)
*rt_free = rt;
@@ -951,8 +798,14 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
/* Apply export table */
- if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed))
- return;
+ struct rte *old_exported = NULL;
+ if (c->out_table)
+ {
+ if (!rte_update_out(c, net->n.addr, new, old, &old_exported, refeed))
+ return;
+ }
+ else if (c->out_filter == FILTER_ACCEPT)
+ old_exported = old;
if (new)
stats->exp_updates_accepted++;
@@ -982,6 +835,9 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
p->rt_notify(p, c, net, new, old);
+
+ if (c->out_table && old_exported)
+ rte_free_quick(old_exported);
}
static void
@@ -1341,27 +1197,6 @@ rte_validate(rte *e)
return 1;
}
-/**
- * rte_free - delete a &rte
- * @e: &rte to be deleted
- *
- * rte_free() deletes the given &rte from the routing table it's linked to.
- */
-void
-rte_free(rte *e)
-{
- if (rta_is_cached(e->attrs))
- rta_free(e->attrs);
- sl_free(rte_slab, e);
-}
-
-static inline void
-rte_free_quick(rte *e)
-{
- rta_free(e->attrs);
- sl_free(rte_slab, e);
-}
-
static int
rte_same(rte *x, rte *y)
{
@@ -1369,8 +1204,7 @@ rte_same(rte *x, rte *y)
return
x->attrs == y->attrs &&
x->pflags == y->pflags &&
- x->pref == y->pref &&
- (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y)) &&
+ x->src == y->src &&
rte_is_filtered(x) == rte_is_filtered(y);
}
@@ -1391,7 +1225,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
- if (old->attrs->src == src)
+ if (old->src == src)
{
/* If there is the same route in the routing table but from
* a different sender, then there are two paths from the
@@ -1674,26 +1508,6 @@ rte_update_unlock(void)
lp_flush(rte_update_pool);
}
-static inline void
-rte_hide_dummy_routes(net *net, rte **dummy)
-{
- if (net->routes && net->routes->attrs->source == RTS_DUMMY)
- {
- *dummy = net->routes;
- net->routes = (*dummy)->next;
- }
-}
-
-static inline void
-rte_unhide_dummy_routes(net *net, rte **dummy)
-{
- if (*dummy)
- {
- (*dummy)->next = net->routes;
- net->routes = *dummy;
- }
-}
-
/**
* rte_update - enter a new update to a routing table
* @table: table to be updated
@@ -1742,7 +1556,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
// struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
const struct filter *filter = c->in_filter;
- rte *dummy = NULL;
net *nn;
ASSERT(c->channel_state == CS_UP);
@@ -1758,9 +1571,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
new->net = nn;
new->sender = c;
- if (!new->pref)
- new->pref = c->preference;
-
stats->imp_updates_received++;
if (!rte_validate(new))
{
@@ -1782,9 +1592,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
}
else if (filter)
{
- rta *old_attrs = NULL;
- rte_make_tmp_attrs(&new, rte_update_pool, &old_attrs);
-
int fr = f_run(filter, &new, rte_update_pool, 0);
if (fr > F_ACCEPT)
{
@@ -1792,15 +1599,10 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
rte_trace_in(D_FILTERS, c, new, "filtered out");
if (! c->in_keep_filtered)
- {
- rta_free(old_attrs);
goto drop;
- }
new->flags |= REF_FILTERED;
}
-
- rte_store_tmp_attrs(new, rte_update_pool, old_attrs);
}
if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
new->attrs = rta_lookup(new->attrs);
@@ -1824,9 +1626,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
recalc:
/* And recalculate the best route */
- rte_hide_dummy_routes(nn, &dummy);
rte_recalculate(c, nn, new, src);
- rte_unhide_dummy_routes(nn, &dummy);
rte_update_unlock();
return;
@@ -1855,7 +1655,7 @@ static inline void
rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
{
rte_update_lock();
- rte_recalculate(old->sender, old->net, NULL, old->attrs->src);
+ rte_recalculate(old->sender, old->net, NULL, old->src);
rte_update_unlock();
}
@@ -1875,7 +1675,7 @@ rte_modify(rte *old)
new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
}
- rte_recalculate(old->sender, old->net, new, old->attrs->src);
+ rte_recalculate(old->sender, old->net, new, old->src);
}
rte_update_unlock();
@@ -1894,12 +1694,9 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter)
rte_update_lock();
/* Rest is stripped down export_filter() */
- int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0;
+ int v = p->preexport ? p->preexport(p, rt) : 0;
if (v == RIC_PROCESS)
- {
- rte_make_tmp_attrs(&rt, rte_update_pool, NULL);
v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
- }
/* Discard temporary rte */
if (rt != n->routes)
@@ -1999,10 +1796,8 @@ rte_dump(rte *e)
{
net *n = e->net;
debug("%-1N ", n->n.addr);
- debug("PF=%02x pref=%d ", e->pflags, e->pref);
+ debug("PF=%02x ", e->pflags);
rta_dump(e->attrs);
- if (e->attrs->src->proto->proto->dump_attrs)
- e->attrs->src->proto->proto->dump_attrs(e);
debug("\n");
}
@@ -2299,12 +2094,7 @@ static struct resclass rt_class = {
rtable *
rt_setup(pool *pp, struct rtable_config *cf)
{
- int ns = strlen("Routing table ") + strlen(cf->name) + 1;
- void *nb = mb_alloc(pp, ns);
- ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name));
-
- pool *p = rp_new(pp, nb);
- mb_move(nb, p);
+ pool *p = rp_newf(pp, "Routing table %s", cf->name);
rtable *t = ralloc(p, &rt_class);
t->rp = p;
@@ -2716,11 +2506,12 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32));
rta_apply_hostentry(a, old->attrs->hostentry, &mls);
- a->aflags = 0;
+ a->cached = 0;
rte *e = sl_alloc(rte_slab);
memcpy(e, old, sizeof(rte));
e->attrs = rta_lookup(a);
+ rt_lock_source(e->src);
return e;
}
@@ -2844,12 +2635,16 @@ static rte *
rt_flowspec_update_rte(rtable *tab, rte *r)
{
#ifdef CONFIG_BGP
- if ((r->attrs->source != RTS_BGP) || !r->u.bgp.base_table)
+ if (r->attrs->source != RTS_BGP)
+ return NULL;
+
+ struct bgp_channel *bc = (struct bgp_channel *) r->sender;
+ if (!bc->base_table)
return NULL;
const net_addr *n = r->net->n.addr;
- struct bgp_proto *p = (void *) r->attrs->src->proto;
- int valid = rt_flowspec_check(r->u.bgp.base_table, tab, n, r->attrs, p->is_interior);
+ struct bgp_proto *p = (void *) r->src->proto;
+ int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior);
int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
if (dest == r->attrs->dest)
@@ -2858,7 +2653,7 @@ rt_flowspec_update_rte(rtable *tab, rte *r)
rta *a = alloca(RTA_MAX_SIZE);
memcpy(a, r->attrs, rta_size(r->attrs));
a->dest = dest;
- a->aflags = 0;
+ a->cached = 0;
rte *new = sl_alloc(rte_slab);
memcpy(new, r, sizeof(rte));
@@ -2898,8 +2693,8 @@ rt_next_hop_update_net(rtable *tab, net *n)
/* Call a pre-comparison hook */
/* Not really an efficient way to compute this */
- if (e->attrs->src->proto->rte_recalculate)
- e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL);
+ if (e->src->proto->rte_recalculate)
+ e->src->proto->rte_recalculate(tab, n, new, e, NULL);
if (e != old_best)
rte_free_quick(e);
@@ -3232,9 +3027,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
{
net = net_get(tab, n);
- if (!new->pref)
- new->pref = c->preference;
-
if (!rta_is_cached(new->attrs))
new->attrs = rta_lookup(new->attrs);
}
@@ -3248,7 +3040,7 @@ 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->attrs->src == src)
+ if (old->src == src)
{
if (new && rte_same(old, new))
{
@@ -3353,7 +3145,7 @@ rt_reload_channel(struct channel *c)
return 0;
}
- rte_update2(c, e->net->n.addr, rte_do_cow(e), e->attrs->src);
+ rte_update2(c, e->net->n.addr, rte_do_cow(e), e->src);
}
c->reload_next_rte = NULL;
@@ -3426,7 +3218,7 @@ again:
*/
int
-rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed)
+rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **old_exported, int refeed)
{
struct rtable *tab = c->out_table;
struct rte_src *src;
@@ -3436,9 +3228,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
if (new)
{
net = net_get(tab, n);
- src = new->attrs->src;
-
- rte_store_tmp_attrs(new, rte_update_pool, NULL);
+ src = new->src;
if (!rta_is_cached(new->attrs))
new->attrs = rta_lookup(new->attrs);
@@ -3446,7 +3236,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
else
{
net = net_find(tab, n);
- src = old0->attrs->src;
+ src = old0->src;
if (!net)
goto drop_withdraw;
@@ -3454,7 +3244,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
/* Find the old rte */
for (pos = &net->routes; old = *pos; pos = &old->next)
- if ((c->ra_mode != RA_ANY) || (old->attrs->src == src))
+ if ((c->ra_mode != RA_ANY) || (old->src == src))
{
if (new && rte_same(old, new))
{
@@ -3472,7 +3262,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
/* Remove the old rte */
*pos = old->next;
- rte_free_quick(old);
+ *old_exported = old;
tab->rt_count--;
break;
@@ -3603,7 +3393,7 @@ hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he)
rem_node(&he->ln);
hc_remove(hc, he);
- sl_free(hc->slab, he);
+ sl_free(he);
hc->hash_items--;
if (hc->hash_items < hc->hash_min)
@@ -3620,7 +3410,7 @@ rt_init_hostcache(rtable *tab)
hc_alloc_table(hc, tab->rp, HC_DEF_ORDER);
hc->slab = sl_new(tab->rp, sizeof(struct hostentry));
- hc->lp = lp_new(tab->rp, LP_GOOD_SIZE(1024));
+ hc->lp = lp_new(tab->rp);
hc->trie = f_new_trie(hc->lp, 0);
tab->hostcache = hc;
@@ -3679,36 +3469,12 @@ rt_get_igp_metric(rte *rt)
if (ea)
return ea->u.data;
- rta *a = rt->attrs;
-
-#ifdef CONFIG_OSPF
- if ((a->source == RTS_OSPF) ||
- (a->source == RTS_OSPF_IA) ||
- (a->source == RTS_OSPF_EXT1))
- return rt->u.ospf.metric1;
-#endif
-
-#ifdef CONFIG_RIP
- if (a->source == RTS_RIP)
- return rt->u.rip.metric;
-#endif
-
-#ifdef CONFIG_BGP
- if (a->source == RTS_BGP)
- {
- u64 metric = bgp_total_aigp_metric(rt);
- return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN);
- }
-#endif
-
-#ifdef CONFIG_BABEL
- if (a->source == RTS_BABEL)
- return rt->u.babel.metric;
-#endif
-
- if (a->source == RTS_DEVICE)
+ if (rt->attrs->source == RTS_DEVICE)
return 0;
+ if (rt->src->proto->rte_igp_metric)
+ return rt->src->proto->rte_igp_metric(rt);
+
return IGP_METRIC_UNKNOWN;
}