From: Ondrej Zajicek (work) Date: Thu, 14 Mar 2019 13:44:35 +0000 (+0100) Subject: Static: Allow to set multiple static route with different metric X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=37dbd3fc7ade40f9cc122d589943590255dab0b1;p=thirdparty%2Fbird.git 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; --- diff --git a/proto/static/config.Y b/proto/static/config.Y index 3bb2cd7e5..0d4379b3e 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -45,6 +45,9 @@ CF_DECLS CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) CF_KEYWORDS(ONLINK, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS) +CF_KEYWORDS(METRIC) + +%type stat_metric CF_GRAMMAR @@ -104,12 +107,17 @@ stat_nexthops: | 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)); add_tail(&STATIC_CFG->routes, &this_srt->n); this_srt->net = $2; this_srt_last_cmd = &(this_srt->cmds); this_srt->mp_next = NULL; + this_srt->metric = $3; this_snh = NULL; } ; @@ -135,8 +143,6 @@ stat_route: stat_route_item: 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: diff --git a/proto/static/static.c b/proto/static/static.c index a47fdbd57..0eec3144a 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -53,7 +53,7 @@ static void static_announce_rte(struct static_proto *p, struct static_route *r) { 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->scope = SCOPE_UNIVERSE; a->dest = r->dest; @@ -98,15 +98,25 @@ static_announce_rte(struct static_proto *p, struct static_route *r) if (r->state == SRS_CLEAN) 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 */ rte *e = rte_get_temp(a); e->pflags = 0; - e->pref = r->preference; if (r->cmds) 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); r->state = SRS_CLEAN; @@ -252,7 +262,7 @@ static void static_remove_rte(struct static_proto *p, struct static_route *r) { 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); } @@ -355,6 +365,14 @@ static_bfd_notify(struct bfd_request *req) 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_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)) 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->neigh_notify = static_neigh_notify; + P->rte_better = static_rte_better; P->rte_mergable = static_rte_mergable; 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 ) 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) -{ 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_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_show_rt(struct static_route *r) { @@ -680,5 +706,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, }; diff --git a/proto/static/static.h b/proto/static/static.h index ec9dffb34..d92e1e72d 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -40,7 +40,7 @@ struct static_route { struct static_route *mp_head; /* First nexthop of this route */ struct static_route *mp_next; /* Nexthops for multipath routes */ struct f_inst *cmds; /* List of commands for setting attributes */ - u16 preference; /* Route preference */ + u32 metric; /* Route metric */ byte dest; /* Destination type (RTD_*) */ byte state; /* State of route announcement (SRS_*) */ byte active; /* Next hop is active (nbr/iface/BFD available) */