]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Static: Allow to set multiple static route with different metric
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 14 Mar 2019 13:44:35 +0000 (14:44 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 14 Mar 2019 13:44:35 +0000 (14:44 +0100)
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;

proto/static/config.Y
proto/static/static.c
proto/static/static.h

index 3bb2cd7e5e6565cf0a7ff61eb0f872107e414973..0d4379b3e4f0078f9b4b0b8059ee90b41668afbd 100644 (file)
@@ -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 <i> 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:
index a47fdbd572b8f0eafe4ce3f8076027cc2a5b098f..0eec3144a64aa8f7d4719dd4d07eff3629c427d8 100644 (file)
@@ -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,
 };
index ec9dffb34a4dab655b677f8541a00ffa0c6e1344..d92e1e72ddd676b9c0c89c06ac2996de0cd10dcd 100644 (file)
@@ -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) */