mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-03 07:31:54 +00:00
Static: Allow to set multiple static route with different metric
Change the usage of preference to distinguish multiple static routes to a separate metric attribute, Reuse igp_metric attribute for that purpose. The static route metric is specified with 'metric' keyword immediately after the network (to signify it is a part of key): route 10.10.0.0/24 metric 10 via 192.168.1.2;
This commit is contained in:
parent
fc50b2196b
commit
37dbd3fc7a
@ -45,6 +45,9 @@ CF_DECLS
|
|||||||
|
|
||||||
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
|
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
|
||||||
CF_KEYWORDS(ONLINK, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS)
|
CF_KEYWORDS(ONLINK, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS)
|
||||||
|
CF_KEYWORDS(METRIC)
|
||||||
|
|
||||||
|
%type <i> stat_metric
|
||||||
|
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
@ -104,12 +107,17 @@ stat_nexthops:
|
|||||||
| stat_nexthops stat_nexthop
|
| stat_nexthops stat_nexthop
|
||||||
;
|
;
|
||||||
|
|
||||||
stat_route0: ROUTE net_any {
|
stat_metric:
|
||||||
|
/* empty */ { $$ = IGP_METRIC_UNKNOWN; }
|
||||||
|
| METRIC expr { $$ = $2; }
|
||||||
|
|
||||||
|
stat_route0: ROUTE net_any stat_metric {
|
||||||
this_srt = cfg_allocz(sizeof(struct static_route));
|
this_srt = cfg_allocz(sizeof(struct static_route));
|
||||||
add_tail(&STATIC_CFG->routes, &this_srt->n);
|
add_tail(&STATIC_CFG->routes, &this_srt->n);
|
||||||
this_srt->net = $2;
|
this_srt->net = $2;
|
||||||
this_srt_last_cmd = &(this_srt->cmds);
|
this_srt_last_cmd = &(this_srt->cmds);
|
||||||
this_srt->mp_next = NULL;
|
this_srt->mp_next = NULL;
|
||||||
|
this_srt->metric = $3;
|
||||||
this_snh = NULL;
|
this_snh = NULL;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -135,8 +143,6 @@ stat_route:
|
|||||||
|
|
||||||
stat_route_item:
|
stat_route_item:
|
||||||
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
|
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
|
||||||
| PREFERENCE expr ';' { this_srt->preference = $2; check_u16($2); }
|
|
||||||
| DISTANCE expr ';' { this_srt->preference = $2; check_u16($2); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
stat_route_opts:
|
stat_route_opts:
|
||||||
|
@ -53,7 +53,7 @@ static void
|
|||||||
static_announce_rte(struct static_proto *p, struct static_route *r)
|
static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||||
{
|
{
|
||||||
rta *a = allocz(RTA_MAX_SIZE);
|
rta *a = allocz(RTA_MAX_SIZE);
|
||||||
a->src = rt_get_source(&p->p, r->preference);
|
a->src = rt_get_source(&p->p, r->metric);
|
||||||
a->source = RTS_STATIC;
|
a->source = RTS_STATIC;
|
||||||
a->scope = SCOPE_UNIVERSE;
|
a->scope = SCOPE_UNIVERSE;
|
||||||
a->dest = r->dest;
|
a->dest = r->dest;
|
||||||
@ -98,15 +98,25 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
|
|||||||
if (r->state == SRS_CLEAN)
|
if (r->state == SRS_CLEAN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (r->metric != IGP_METRIC_UNKNOWN)
|
||||||
|
{
|
||||||
|
ea_list *ea = allocz(sizeof(struct ea_list) + sizeof(eattr));
|
||||||
|
a->eattrs = ea;
|
||||||
|
|
||||||
|
ea->count = 1;
|
||||||
|
ea->attrs[0].id = EA_GEN_IGP_METRIC;
|
||||||
|
ea->attrs[0].flags = 0;
|
||||||
|
ea->attrs[0].type = EAF_TYPE_INT;
|
||||||
|
ea->attrs[0].u.data = r->metric;
|
||||||
|
}
|
||||||
|
|
||||||
/* We skip rta_lookup() here */
|
/* We skip rta_lookup() here */
|
||||||
rte *e = rte_get_temp(a);
|
rte *e = rte_get_temp(a);
|
||||||
e->pflags = 0;
|
e->pflags = 0;
|
||||||
e->pref = r->preference;
|
|
||||||
|
|
||||||
if (r->cmds)
|
if (r->cmds)
|
||||||
f_eval_rte(r->cmds, &e, static_lp);
|
f_eval_rte(r->cmds, &e, static_lp);
|
||||||
|
|
||||||
e->pref = r->preference; /* Avoid preference from filter */
|
|
||||||
rte_update2(p->p.main_channel, r->net, e, a->src);
|
rte_update2(p->p.main_channel, r->net, e, a->src);
|
||||||
r->state = SRS_CLEAN;
|
r->state = SRS_CLEAN;
|
||||||
|
|
||||||
@ -252,7 +262,7 @@ static void
|
|||||||
static_remove_rte(struct static_proto *p, struct static_route *r)
|
static_remove_rte(struct static_proto *p, struct static_route *r)
|
||||||
{
|
{
|
||||||
if (r->state)
|
if (r->state)
|
||||||
rte_update2(p->p.main_channel, r->net, NULL, rt_get_source(&p->p, r->preference));
|
rte_update2(p->p.main_channel, r->net, NULL, rt_get_source(&p->p, r->metric));
|
||||||
|
|
||||||
static_reset_rte(p, r);
|
static_reset_rte(p, r);
|
||||||
}
|
}
|
||||||
@ -355,6 +365,14 @@ static_bfd_notify(struct bfd_request *req)
|
|||||||
static_mark_rte(p, r->mp_head);
|
static_mark_rte(p, r->mp_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
static_rte_better(struct rte *new, struct rte *old)
|
||||||
|
{
|
||||||
|
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 int
|
||||||
static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED)
|
static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED)
|
||||||
{
|
{
|
||||||
@ -385,9 +403,6 @@ static_postconfig(struct proto_config *CF)
|
|||||||
{
|
{
|
||||||
if (r->net && (r->net->type != CF->net_type))
|
if (r->net && (r->net->type != CF->net_type))
|
||||||
cf_error("Route %N incompatible with channel type", r->net);
|
cf_error("Route %N incompatible with channel type", r->net);
|
||||||
|
|
||||||
if (!r->preference)
|
|
||||||
r->preference = cc->preference;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,6 +416,7 @@ static_init(struct proto_config *CF)
|
|||||||
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
|
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
|
||||||
|
|
||||||
P->neigh_notify = static_neigh_notify;
|
P->neigh_notify = static_neigh_notify;
|
||||||
|
P->rte_better = static_rte_better;
|
||||||
P->rte_mergable = static_rte_mergable;
|
P->rte_mergable = static_rte_mergable;
|
||||||
|
|
||||||
if (cf->igp_table_ip4)
|
if (cf->igp_table_ip4)
|
||||||
@ -496,10 +512,10 @@ static_dump(struct proto *P)
|
|||||||
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
|
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
|
||||||
|
|
||||||
static inline int srt_equal(struct static_route *a, struct static_route *b)
|
static inline int srt_equal(struct static_route *a, struct static_route *b)
|
||||||
{ return net_equal(a->net, b->net) && (a->preference == b->preference); }
|
{ return net_equal(a->net, b->net) && (a->metric == b->metric); }
|
||||||
|
|
||||||
static inline int srt_compare(struct static_route *a, struct static_route *b)
|
static inline int srt_compare(struct static_route *a, struct static_route *b)
|
||||||
{ return net_compare(a->net, b->net) ?: uint_cmp(a->preference, b->preference); }
|
{ return net_compare(a->net, b->net) ?: uint_cmp(a->metric, b->metric); }
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
static_cmp_rte(const void *X, const void *Y)
|
static_cmp_rte(const void *X, const void *Y)
|
||||||
@ -617,6 +633,16 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
static_get_route_info(rte *rte, byte *buf, ea_list *attrs)
|
||||||
|
{
|
||||||
|
eattr *a = ea_find(attrs, 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 void
|
||||||
static_show_rt(struct static_route *r)
|
static_show_rt(struct static_route *r)
|
||||||
{
|
{
|
||||||
@ -680,5 +706,6 @@ struct protocol proto_static = {
|
|||||||
.shutdown = static_shutdown,
|
.shutdown = static_shutdown,
|
||||||
.cleanup = static_cleanup,
|
.cleanup = static_cleanup,
|
||||||
.reconfigure = static_reconfigure,
|
.reconfigure = static_reconfigure,
|
||||||
.copy_config = static_copy_config
|
.copy_config = static_copy_config,
|
||||||
|
.get_route_info = static_get_route_info,
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,7 @@ struct static_route {
|
|||||||
struct static_route *mp_head; /* First nexthop of this route */
|
struct static_route *mp_head; /* First nexthop of this route */
|
||||||
struct static_route *mp_next; /* Nexthops for multipath routes */
|
struct static_route *mp_next; /* Nexthops for multipath routes */
|
||||||
struct f_inst *cmds; /* List of commands for setting attributes */
|
struct f_inst *cmds; /* List of commands for setting attributes */
|
||||||
u16 preference; /* Route preference */
|
u32 metric; /* Route metric */
|
||||||
byte dest; /* Destination type (RTD_*) */
|
byte dest; /* Destination type (RTD_*) */
|
||||||
byte state; /* State of route announcement (SRS_*) */
|
byte state; /* State of route announcement (SRS_*) */
|
||||||
byte active; /* Next hop is active (nbr/iface/BFD available) */
|
byte active; /* Next hop is active (nbr/iface/BFD available) */
|
||||||
|
Loading…
Reference in New Issue
Block a user