diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/route.h | 5 | ||||
-rw-r--r-- | nest/rt-attr.c | 2 | ||||
-rw-r--r-- | nest/rt-table.c | 60 |
3 files changed, 59 insertions, 8 deletions
diff --git a/nest/route.h b/nest/route.h index 4dd43750..d062e600 100644 --- a/nest/route.h +++ b/nest/route.h @@ -173,6 +173,7 @@ struct hostentry { struct iface *iface; /* Chosen outgoing interface */ ip_addr gw; /* Chosen next hop */ byte dest; /* Chosen route destination type (RTD_...) */ + u32 igp_metric; /* Chosen route IGP metric */ }; typedef struct rte { @@ -276,6 +277,7 @@ typedef struct rta { byte flags; /* Route flags (RTF_...), now unused */ byte aflags; /* Attribute cache flags (RTAF_...) */ u16 hash_key; /* Hash over important fields */ + u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */ ip_addr gw; /* Next hop */ ip_addr from; /* Advertising router */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */ @@ -311,6 +313,9 @@ typedef struct rta { #define RTAF_CACHED 1 /* This is a cached rta */ +#define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other + protocol-specific metric is availabe */ + /* * Extended Route Attributes */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 9caee8d5..d7148188 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -584,9 +584,11 @@ rta_same(rta *x, rta *y) x->cast == y->cast && x->dest == y->dest && x->flags == y->flags && + x->igp_metric == y->igp_metric && ipa_equal(x->gw, y->gw) && ipa_equal(x->from, y->from) && x->iface == y->iface && + x->hostentry == y->hostentry && ea_same(x->eattrs, y->eattrs)); } diff --git a/nest/rt-table.c b/nest/rt-table.c index 1f84e975..b73f52fa 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -59,6 +59,24 @@ static void rt_prune(rtable *tab); static inline void rt_schedule_gc(rtable *tab); +/* Like fib_route(), but skips empty net entries */ +static net * +net_route(rtable *tab, ip_addr a, int len) +{ + ip_addr a0; + net *n; + + while (len >= 0) + { + a0 = ipa_and(a, ipa_mkmask(len)); + n = fib_find(&tab->fib, &a0, len); + if (n && n->routes) + return n; + len--; + } + return NULL; +} + static void rte_init(struct fib_node *N) { @@ -945,16 +963,18 @@ rt_preconfig(struct config *c) */ static inline int -hostentry_diff(struct hostentry *he, struct iface *iface, ip_addr gw, byte dest) +hostentry_diff(struct hostentry *he, struct iface *iface, ip_addr gw, + byte dest, u32 igp_metric) { - return (he->iface != iface) || !ipa_equal(he->gw, gw) || (he->dest != dest); + return (he->iface != iface) || !ipa_equal(he->gw, gw) || + (he->dest != dest) || (he->igp_metric != igp_metric); } static inline int rta_next_hop_outdated(rta *a) { struct hostentry *he = a->hostentry; - return he && hostentry_diff(he, a->iface, a->gw, a->dest); + return he && hostentry_diff(he, a->iface, a->gw, a->dest, a->igp_metric); } static inline void @@ -964,6 +984,7 @@ rta_apply_hostentry(rta *a, struct hostentry *he) a->iface = he->iface; a->gw = he->gw; a->dest = he->dest; + a->igp_metric = he->igp_metric; } static inline rte * @@ -1449,16 +1470,36 @@ if_local_addr(ip_addr a, struct iface *i) return 0; } +static u32 +rt_get_igp_metric(rte *rt) +{ + rta *a = rt->attrs; + if ((a->source == RTS_OSPF) || + (a->source == RTS_OSPF_IA) || + (a->source == RTS_OSPF_EXT1)) + return rt->u.ospf.metric1; + + if (a->source == RTS_RIP) + return rt->u.rip.metric; + + /* Device routes */ + if (a->dest != RTD_ROUTER) + return 0; + + return IGP_METRIC_UNKNOWN; +} + static int rt_update_hostentry(rtable *tab, struct hostentry *he) { struct iface *old_iface = he->iface; ip_addr old_gw = he->gw; byte old_dest = he->dest; + u32 old_metric = he->igp_metric; int pxlen = 0; - net *n = fib_route(&tab->fib, he->addr, MAX_PREFIX_LENGTH); - if (n && n->routes) + net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH); + if (n) { rta *a = n->routes->attrs; pxlen = n->n.pxlen; @@ -1489,6 +1530,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) he->gw = a->gw; he->dest = a->dest; } + + he->igp_metric = he->iface ? rt_get_igp_metric(n->routes) : 0; } else { @@ -1496,12 +1539,13 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) he->iface = NULL; he->gw = IPA_NONE; he->dest = RTD_UNREACHABLE; + he->igp_metric = 0; } /* Add a prefix range to the trie */ trie_add_prefix(tab->hostcache->trie, he->addr, MAX_PREFIX_LENGTH, pxlen, MAX_PREFIX_LENGTH); - return hostentry_diff(he, old_iface, old_gw, old_dest); + return hostentry_diff(he, old_iface, old_gw, old_dest, old_metric); } static void @@ -1730,9 +1774,9 @@ rt_show(struct rt_show_data *d) else { if (d->show_for) - n = fib_route(&d->table->fib, d->prefix, d->pxlen); + n = net_route(d->table, d->prefix, d->pxlen); else - n = fib_find(&d->table->fib, &d->prefix, d->pxlen); + n = net_find(d->table, d->prefix, d->pxlen); if (n) { rt_show_net(this_cli, n, d); |