Implements IGP metric comparison for BGP routes.
This commit is contained in:
parent
ac3ac49a71
commit
d1e146f2f8
7 changed files with 82 additions and 11 deletions
|
@ -173,6 +173,7 @@ struct hostentry {
|
||||||
struct iface *iface; /* Chosen outgoing interface */
|
struct iface *iface; /* Chosen outgoing interface */
|
||||||
ip_addr gw; /* Chosen next hop */
|
ip_addr gw; /* Chosen next hop */
|
||||||
byte dest; /* Chosen route destination type (RTD_...) */
|
byte dest; /* Chosen route destination type (RTD_...) */
|
||||||
|
u32 igp_metric; /* Chosen route IGP metric */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rte {
|
typedef struct rte {
|
||||||
|
@ -276,6 +277,7 @@ typedef struct rta {
|
||||||
byte flags; /* Route flags (RTF_...), now unused */
|
byte flags; /* Route flags (RTF_...), now unused */
|
||||||
byte aflags; /* Attribute cache flags (RTAF_...) */
|
byte aflags; /* Attribute cache flags (RTAF_...) */
|
||||||
u16 hash_key; /* Hash over important fields */
|
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 gw; /* Next hop */
|
||||||
ip_addr from; /* Advertising router */
|
ip_addr from; /* Advertising router */
|
||||||
struct hostentry *hostentry; /* Hostentry for recursive next-hops */
|
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 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
|
* Extended Route Attributes
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -584,9 +584,11 @@ rta_same(rta *x, rta *y)
|
||||||
x->cast == y->cast &&
|
x->cast == y->cast &&
|
||||||
x->dest == y->dest &&
|
x->dest == y->dest &&
|
||||||
x->flags == y->flags &&
|
x->flags == y->flags &&
|
||||||
|
x->igp_metric == y->igp_metric &&
|
||||||
ipa_equal(x->gw, y->gw) &&
|
ipa_equal(x->gw, y->gw) &&
|
||||||
ipa_equal(x->from, y->from) &&
|
ipa_equal(x->from, y->from) &&
|
||||||
x->iface == y->iface &&
|
x->iface == y->iface &&
|
||||||
|
x->hostentry == y->hostentry &&
|
||||||
ea_same(x->eattrs, y->eattrs));
|
ea_same(x->eattrs, y->eattrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,24 @@ static void rt_prune(rtable *tab);
|
||||||
|
|
||||||
static inline void rt_schedule_gc(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
|
static void
|
||||||
rte_init(struct fib_node *N)
|
rte_init(struct fib_node *N)
|
||||||
{
|
{
|
||||||
|
@ -945,16 +963,18 @@ rt_preconfig(struct config *c)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline int
|
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
|
static inline int
|
||||||
rta_next_hop_outdated(rta *a)
|
rta_next_hop_outdated(rta *a)
|
||||||
{
|
{
|
||||||
struct hostentry *he = a->hostentry;
|
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
|
static inline void
|
||||||
|
@ -964,6 +984,7 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
|
||||||
a->iface = he->iface;
|
a->iface = he->iface;
|
||||||
a->gw = he->gw;
|
a->gw = he->gw;
|
||||||
a->dest = he->dest;
|
a->dest = he->dest;
|
||||||
|
a->igp_metric = he->igp_metric;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline rte *
|
static inline rte *
|
||||||
|
@ -1449,16 +1470,36 @@ if_local_addr(ip_addr a, struct iface *i)
|
||||||
return 0;
|
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
|
static int
|
||||||
rt_update_hostentry(rtable *tab, struct hostentry *he)
|
rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||||
{
|
{
|
||||||
struct iface *old_iface = he->iface;
|
struct iface *old_iface = he->iface;
|
||||||
ip_addr old_gw = he->gw;
|
ip_addr old_gw = he->gw;
|
||||||
byte old_dest = he->dest;
|
byte old_dest = he->dest;
|
||||||
|
u32 old_metric = he->igp_metric;
|
||||||
int pxlen = 0;
|
int pxlen = 0;
|
||||||
|
|
||||||
net *n = fib_route(&tab->fib, he->addr, MAX_PREFIX_LENGTH);
|
net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH);
|
||||||
if (n && n->routes)
|
if (n)
|
||||||
{
|
{
|
||||||
rta *a = n->routes->attrs;
|
rta *a = n->routes->attrs;
|
||||||
pxlen = n->n.pxlen;
|
pxlen = n->n.pxlen;
|
||||||
|
@ -1489,6 +1530,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||||
he->gw = a->gw;
|
he->gw = a->gw;
|
||||||
he->dest = a->dest;
|
he->dest = a->dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
he->igp_metric = he->iface ? rt_get_igp_metric(n->routes) : 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1496,12 +1539,13 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||||
he->iface = NULL;
|
he->iface = NULL;
|
||||||
he->gw = IPA_NONE;
|
he->gw = IPA_NONE;
|
||||||
he->dest = RTD_UNREACHABLE;
|
he->dest = RTD_UNREACHABLE;
|
||||||
|
he->igp_metric = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a prefix range to the trie */
|
/* Add a prefix range to the trie */
|
||||||
trie_add_prefix(tab->hostcache->trie, he->addr, MAX_PREFIX_LENGTH, pxlen, MAX_PREFIX_LENGTH);
|
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
|
static void
|
||||||
|
@ -1730,9 +1774,9 @@ rt_show(struct rt_show_data *d)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (d->show_for)
|
if (d->show_for)
|
||||||
n = fib_route(&d->table->fib, d->prefix, d->pxlen);
|
n = net_route(d->table, d->prefix, d->pxlen);
|
||||||
else
|
else
|
||||||
n = fib_find(&d->table->fib, &d->prefix, d->pxlen);
|
n = net_find(d->table, d->prefix, d->pxlen);
|
||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
rt_show_net(this_cli, n, d);
|
rt_show_net(this_cli, n, d);
|
||||||
|
|
|
@ -1084,8 +1084,13 @@ bgp_rte_better(rte *new, rte *old)
|
||||||
if (new_bgp->is_internal < old_bgp->is_internal)
|
if (new_bgp->is_internal < old_bgp->is_internal)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Skipping RFC 4271 9.1.2.2. e) */
|
/* RFC 4271 9.1.2.2. e) Compare IGP metrics */
|
||||||
/* We don't have interior distances */
|
n = new_bgp->cf->igp_metric ? new->attrs->igp_metric : 0;
|
||||||
|
o = old_bgp->cf->igp_metric ? old->attrs->igp_metric : 0;
|
||||||
|
if (n < o)
|
||||||
|
return 1;
|
||||||
|
if (n > o)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* RFC 4271 9.1.2.2. f) Compare BGP identifiers */
|
/* RFC 4271 9.1.2.2. f) Compare BGP identifiers */
|
||||||
/* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighor ID */
|
/* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighor ID */
|
||||||
|
@ -1494,7 +1499,18 @@ bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
|
||||||
eattr *o = ea_find(attrs, EA_CODE(EAP_BGP, BA_ORIGIN));
|
eattr *o = ea_find(attrs, EA_CODE(EAP_BGP, BA_ORIGIN));
|
||||||
u32 origas;
|
u32 origas;
|
||||||
|
|
||||||
buf += bsprintf(buf, " (%d) [", e->pref);
|
buf += bsprintf(buf, " (%d", e->pref);
|
||||||
|
if (e->attrs->hostentry)
|
||||||
|
{
|
||||||
|
if (!e->attrs->iface)
|
||||||
|
buf += bsprintf(buf, "/-");
|
||||||
|
else if (e->attrs->igp_metric >= IGP_METRIC_UNKNOWN)
|
||||||
|
buf += bsprintf(buf, "/?");
|
||||||
|
else
|
||||||
|
buf += bsprintf(buf, "/%d", e->attrs->igp_metric);
|
||||||
|
}
|
||||||
|
buf += bsprintf(buf, ") [");
|
||||||
|
|
||||||
if (p && as_path_get_last(p->u.ptr, &origas))
|
if (p && as_path_get_last(p->u.ptr, &origas))
|
||||||
buf += bsprintf(buf, "AS%u", origas);
|
buf += bsprintf(buf, "AS%u", origas);
|
||||||
if (o)
|
if (o)
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct bgp_config {
|
||||||
int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */
|
int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */
|
||||||
int gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */
|
int gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */
|
||||||
int compare_path_lengths; /* Use path lengths when selecting best route */
|
int compare_path_lengths; /* Use path lengths when selecting best route */
|
||||||
|
int igp_metric; /* Use IGP metrics when selecting best route */
|
||||||
int prefer_older; /* Prefer older routes according to RFC 5004 */
|
int prefer_older; /* Prefer older routes according to RFC 5004 */
|
||||||
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */
|
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */
|
||||||
u32 default_med; /* Default value for MULTI_EXIT_DISC attribute */
|
u32 default_med; /* Default value for MULTI_EXIT_DISC attribute */
|
||||||
|
|
|
@ -38,6 +38,7 @@ bgp_proto_start: proto_start BGP {
|
||||||
BGP_CFG->connect_retry_time = 120;
|
BGP_CFG->connect_retry_time = 120;
|
||||||
BGP_CFG->initial_hold_time = 240;
|
BGP_CFG->initial_hold_time = 240;
|
||||||
BGP_CFG->compare_path_lengths = 1;
|
BGP_CFG->compare_path_lengths = 1;
|
||||||
|
BGP_CFG->igp_metric = 1;
|
||||||
BGP_CFG->start_delay_time = 5;
|
BGP_CFG->start_delay_time = 5;
|
||||||
BGP_CFG->error_amnesia_time = 300;
|
BGP_CFG->error_amnesia_time = 300;
|
||||||
BGP_CFG->error_delay_time_min = 60;
|
BGP_CFG->error_delay_time_min = 60;
|
||||||
|
@ -78,6 +79,7 @@ bgp_proto:
|
||||||
| bgp_proto GATEWAY DIRECT ';' { BGP_CFG->gw_mode = GW_DIRECT; }
|
| bgp_proto GATEWAY DIRECT ';' { BGP_CFG->gw_mode = GW_DIRECT; }
|
||||||
| bgp_proto GATEWAY RECURSIVE ';' { BGP_CFG->gw_mode = GW_RECURSIVE; }
|
| bgp_proto GATEWAY RECURSIVE ';' { BGP_CFG->gw_mode = GW_RECURSIVE; }
|
||||||
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
|
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
|
||||||
|
| bgp_proto IGP METRIC bool ';' { BGP_CFG->igp_metric = $4; }
|
||||||
| bgp_proto PREFER OLDER bool ';' { BGP_CFG->prefer_older = $4; }
|
| bgp_proto PREFER OLDER bool ';' { BGP_CFG->prefer_older = $4; }
|
||||||
| bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; }
|
| bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; }
|
||||||
| bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; }
|
| bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; }
|
||||||
|
|
|
@ -823,6 +823,7 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a)
|
||||||
a->gw = ng->addr;
|
a->gw = ng->addr;
|
||||||
a->iface = ng->iface;
|
a->iface = ng->iface;
|
||||||
a->hostentry = NULL;
|
a->hostentry = NULL;
|
||||||
|
a->igp_metric = 0;
|
||||||
}
|
}
|
||||||
else /* GW_RECURSIVE */
|
else /* GW_RECURSIVE */
|
||||||
rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second);
|
rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second);
|
||||||
|
|
Loading…
Reference in a new issue