mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
Static: Support for multiple routes with the same network
Add support for proper handling of multiple routes with the same network to the static protocol. Routes are distinguished by internal index, which is assigned automatically (sequentially for routes within each network). Having different route preference or igp_metric attribute is optional.
This commit is contained in:
@@ -49,11 +49,14 @@
|
||||
|
||||
static linpool *static_lp;
|
||||
|
||||
static inline struct rte_src * static_get_source(struct static_proto *p, uint i)
|
||||
{ return i ? rt_get_source(&p->p, i) : p->p.main_source; }
|
||||
|
||||
static void
|
||||
static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||
{
|
||||
rta *a = allocz(RTA_MAX_SIZE);
|
||||
a->src = p->p.main_source;
|
||||
a->src = static_get_source(p, r->index);
|
||||
a->source = RTS_STATIC;
|
||||
a->scope = SCOPE_UNIVERSE;
|
||||
a->dest = r->dest;
|
||||
@@ -105,7 +108,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||
if (r->cmds)
|
||||
f_eval_rte(r->cmds, &e, static_lp);
|
||||
|
||||
rte_update(&p->p, r->net, e);
|
||||
rte_update2(p->p.main_channel, r->net, e, a->src);
|
||||
r->state = SRS_CLEAN;
|
||||
|
||||
if (r->cmds)
|
||||
@@ -117,7 +120,7 @@ withdraw:
|
||||
if (r->state == SRS_DOWN)
|
||||
return;
|
||||
|
||||
rte_update(&p->p, r->net, NULL);
|
||||
rte_update2(p->p.main_channel, r->net, NULL, a->src);
|
||||
r->state = SRS_DOWN;
|
||||
}
|
||||
|
||||
@@ -250,7 +253,7 @@ static void
|
||||
static_remove_rte(struct static_proto *p, struct static_route *r)
|
||||
{
|
||||
if (r->state)
|
||||
rte_update(&p->p, r->net, NULL);
|
||||
rte_update2(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
|
||||
|
||||
static_reset_rte(p, r);
|
||||
}
|
||||
@@ -354,11 +357,22 @@ static_bfd_notify(struct bfd_request *req)
|
||||
}
|
||||
|
||||
static int
|
||||
static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED)
|
||||
static_rte_better(rte *new, rte *old)
|
||||
{
|
||||
return 1;
|
||||
u32 n = ea_get_int(new->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
u32 o = ea_get_int(old->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
return n < o;
|
||||
}
|
||||
|
||||
static int
|
||||
static_rte_mergable(rte *pri, rte *sec)
|
||||
{
|
||||
u32 a = ea_get_int(pri->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
u32 b = ea_get_int(sec->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
return a == b;
|
||||
}
|
||||
|
||||
static void static_index_routes(struct static_config *cf);
|
||||
|
||||
static void
|
||||
static_postconfig(struct proto_config *CF)
|
||||
@@ -382,6 +396,8 @@ static_postconfig(struct proto_config *CF)
|
||||
WALK_LIST(r, cf->routes)
|
||||
if (r->net && (r->net->type != CF->net_type))
|
||||
cf_error("Route %N incompatible with channel type", r->net);
|
||||
|
||||
static_index_routes(cf);
|
||||
}
|
||||
|
||||
static struct proto *
|
||||
@@ -394,6 +410,7 @@ static_init(struct proto_config *CF)
|
||||
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
|
||||
|
||||
P->neigh_notify = static_neigh_notify;
|
||||
P->rte_better = static_rte_better;
|
||||
P->rte_mergable = static_rte_mergable;
|
||||
|
||||
if (cf->igp_table_ip4)
|
||||
@@ -463,7 +480,7 @@ static_cleanup(struct proto *P)
|
||||
static void
|
||||
static_dump_rte(struct static_route *r)
|
||||
{
|
||||
debug("%-1N: ", r->net);
|
||||
debug("%-1N (%u): ", r->net, r->index);
|
||||
if (r->dest == RTD_UNICAST)
|
||||
if (r->iface && ipa_zero(r->via))
|
||||
debug("dev %s\n", r->iface->name);
|
||||
@@ -486,11 +503,48 @@ static_dump(struct proto *P)
|
||||
|
||||
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
|
||||
|
||||
static inline int
|
||||
static_cmp_rte(const void *X, const void *Y)
|
||||
static inline int srt_equal(const struct static_route *a, const struct static_route *b)
|
||||
{ return net_equal(a->net, b->net) && (a->index == b->index); }
|
||||
|
||||
static inline int srt_compare(const struct static_route *a, const struct static_route *b)
|
||||
{ return net_compare(a->net, b->net) ?: uint_cmp(a->index, b->index); }
|
||||
|
||||
static inline int srt_compare_qsort(const void *A, const void *B)
|
||||
{
|
||||
struct static_route *x = *(void **)X, *y = *(void **)Y;
|
||||
return net_compare(x->net, y->net);
|
||||
return srt_compare(*(const struct static_route * const *)A,
|
||||
*(const struct static_route * const *)B);
|
||||
}
|
||||
|
||||
static void
|
||||
static_index_routes(struct static_config *cf)
|
||||
{
|
||||
struct static_route *rt, **buf;
|
||||
uint num, i, v;
|
||||
|
||||
num = list_length(&cf->routes);
|
||||
buf = xmalloc(num * sizeof(void *));
|
||||
|
||||
/* Initialize with sequential indexes to ensure stable sorting */
|
||||
i = 0;
|
||||
WALK_LIST(rt, cf->routes)
|
||||
{
|
||||
buf[i] = rt;
|
||||
rt->index = i++;
|
||||
}
|
||||
|
||||
qsort(buf, num, sizeof(struct static_route *), srt_compare_qsort);
|
||||
|
||||
/* Compute proper indexes - sequential for routes with same network */
|
||||
for (i = 0, v = 0, rt = NULL; i < num; i++, v++)
|
||||
{
|
||||
if (rt && !net_equal(buf[i]->net, rt->net))
|
||||
v = 0;
|
||||
|
||||
rt = buf[i];
|
||||
rt->index = v;
|
||||
}
|
||||
|
||||
xfree(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -519,7 +573,7 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
|
||||
/* Reconfigure initial matching sequence */
|
||||
for (or = HEAD(o->routes), nr = HEAD(n->routes);
|
||||
NODE_VALID(or) && NODE_VALID(nr) && net_equal(or->net, nr->net);
|
||||
NODE_VALID(or) && NODE_VALID(nr) && srt_equal(or, nr);
|
||||
or = NODE_NEXT(or), nr = NODE_NEXT(nr))
|
||||
static_reconfigure_rte(p, or, nr);
|
||||
|
||||
@@ -545,12 +599,12 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
for (i = 0, nr2 = nr; i < nrnum; i++, nr2 = NODE_NEXT(nr2))
|
||||
nrbuf[i] = nr2;
|
||||
|
||||
qsort(orbuf, ornum, sizeof(struct static_route *), static_cmp_rte);
|
||||
qsort(nrbuf, nrnum, sizeof(struct static_route *), static_cmp_rte);
|
||||
qsort(orbuf, ornum, sizeof(struct static_route *), srt_compare_qsort);
|
||||
qsort(nrbuf, nrnum, sizeof(struct static_route *), srt_compare_qsort);
|
||||
|
||||
while ((orpos < ornum) && (nrpos < nrnum))
|
||||
{
|
||||
int x = net_compare(orbuf[orpos]->net, nrbuf[nrpos]->net);
|
||||
int x = srt_compare(orbuf[orpos], nrbuf[nrpos]);
|
||||
if (x < 0)
|
||||
static_remove_rte(p, orbuf[orpos++]);
|
||||
else if (x > 0)
|
||||
@@ -602,6 +656,16 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static_get_route_info(rte *rte, byte *buf)
|
||||
{
|
||||
eattr *a = ea_find(rte->attrs->eattrs, EA_GEN_IGP_METRIC);
|
||||
if (a)
|
||||
buf += bsprintf(buf, " (%d/%u)", rte->pref, a->u.data);
|
||||
else
|
||||
buf += bsprintf(buf, " (%d)", rte->pref);
|
||||
}
|
||||
|
||||
static void
|
||||
static_show_rt(struct static_route *r)
|
||||
{
|
||||
@@ -665,5 +729,6 @@ struct protocol proto_static = {
|
||||
.shutdown = static_shutdown,
|
||||
.cleanup = static_cleanup,
|
||||
.reconfigure = static_reconfigure,
|
||||
.copy_config = static_copy_config
|
||||
.copy_config = static_copy_config,
|
||||
.get_route_info = static_get_route_info,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user