]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Do not initialize route metrics in import_control hook
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 24 May 2018 12:51:05 +0000 (14:51 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 24 May 2018 12:51:05 +0000 (14:51 +0200)
During route export, the receiving protocol often initialized route
metrics to default value in its import_control hook before export filter
was executed. This is inconsistent with the expectation that an export
filter would process the same route as one in the routing table and it
breaks setting these metrics before (e.g. for static routes directly in
static protocol).

The patch removes the initialization of route metrics in import_control
hook, the default values are already handled in rt_notify hook called
after export filters.

The patch also changed the behavior of OSPF to keep metrics when a route
is reannounced between OSPF instances (to be consistent with other
protocols) and the behavior when both ospf_metric1 and ospf_metric2
are specified (to have more expected behavior).

doc/bird.sgml
proto/babel/babel.c
proto/ospf/ospf.c
proto/ospf/topology.c
proto/rip/rip.c

index ae308d4cd8de0f20a6e6c69cd902668a1330bbf8..b4d9ea4e957d6224652b56d973828fed2d2ec5a7 100644 (file)
@@ -1618,9 +1618,7 @@ regarded as empty bgppath/*clist for most purposes.
        The optional attribute that can be used to specify a distance to the
        network for routes that do not have a native protocol metric attribute
        (like <cf/ospf_metric1/ for OSPF routes). It is used mainly by BGP to
-       compare internal distances to boundary routers (see below). It is also
-       used when the route is exported to OSPF as a default value for OSPF type
-       1 metric.
+       compare internal distances to boundary routers (see below).
 </descrip>
 
 <p>There also exist protocol-specific attributes which are described in the
@@ -3536,8 +3534,15 @@ protocol ospf [v2|v3] &lt;name&gt; {
 with internal <cf/metric/, a <cf/metric of type 2/ is always longer than any
 <cf/metric of type 1/ or any <cf/internal metric/. <cf/Internal metric/ or
 <cf/metric of type 1/ is stored in attribute <cf/ospf_metric1/, <cf/metric type
-2/ is stored in attribute <cf/ospf_metric2/. If you specify both metrics only
-metric1 is used.
+2/ is stored in attribute <cf/ospf_metric2/.
+
+When both metrics are specified then <cf/metric of type 2/ is used. This is
+relevant e.g. when a type 2 external route is propagated from one OSPF domain to
+another and <cf/ospf_metric1/ is an internal distance to the original ASBR,
+while <cf/ospf_metric2/ stores the type 2 metric. Note that in such cases if
+<cf/ospf_metric1/ is non-zero then <cf/ospf_metric2/ is increased by one to
+ensure monotonicity of metric, as internal distance is reset to zero when an
+external route is announced.
 
 <p>Each external route can also carry attribute <cf/ospf_tag/ which is a 32-bit
 integer which is used when exporting routes to other protocols; otherwise, it
index ce05191c147e4a4927b260aefe616cc1ec67f602..44c6adb86ae19fc54a9fad1d5a9d58f9e178f4df 100644 (file)
@@ -2087,20 +2087,14 @@ babel_prepare_attrs(struct linpool *pool, ea_list *next, uint metric, u64 router
 
 
 static int
-babel_import_control(struct proto *P, struct rte **new, struct ea_list **attrs, struct linpool *pool)
+babel_import_control(struct proto *P, struct rte **new, struct ea_list **attrs UNUSED, struct linpool *pool UNUSED)
 {
-  struct babel_proto *p = (void *) P;
-  rte *rt = *new;
+  rte *e = *new;
 
   /* Reject our own unreachable routes */
-  if ((rt->attrs->dest == RTD_UNREACHABLE) && (rt->attrs->src->proto == P))
+  if ((e->attrs->dest == RTD_UNREACHABLE) && (e->attrs->src->proto == P))
     return -1;
 
-
-  /* Prepare attributes with initial values */
-  if (rt->attrs->source != RTS_BABEL)
-    *attrs = babel_prepare_attrs(pool, NULL, 0, p->router_id);
-
   return 0;
 }
 
index df6c452e7fe55ca1909c503f9842d0fcb62569c7..0a9efd195c677475704482a08510bd53cfa32e59 100644 (file)
@@ -446,34 +446,21 @@ ospf_disp(timer * timer)
  * import to the filters.
  */
 static int
-ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
+ospf_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
 {
   struct ospf_proto *p = (struct ospf_proto *) P;
   struct ospf_area *oa = ospf_main_area(p);
   rte *e = *new;
 
+  /* Reject our own routes */
   if (e->attrs->src->proto == P)
-    return -1;                 /* Reject our own routes */
+    return -1;
 
+  /* Do not export routes to stub areas */
   if (oa_is_stub(oa))
-    return -1;                 /* Do not export routes to stub areas */
-
-  ea_list *ea = e->attrs->eattrs;
-  u32 m0 = ea_get_int(ea, EA_GEN_IGP_METRIC, LSINFINITY);
-  u32 m1 = MIN(m0, LSINFINITY);
-  u32 m2 = 10000;
-  u32 tag = 0;
-
-  /* Hack for setting attributes directly in static protocol */
-  if (e->attrs->source == RTS_STATIC)
-  {
-    m1 = ea_get_int(ea, EA_OSPF_METRIC1, m1);
-    m2 = ea_get_int(ea, EA_OSPF_METRIC2, 10000);
-    tag = ea_get_int(ea, EA_OSPF_TAG, 0);
-  }
+    return -1;
 
-  *attrs = ospf_build_attrs(*attrs, pool, m1, m2, tag, 0);
-  return 0;                    /* Leave decision to the filters */
+  return 0;
 }
 
 static struct ea_list *
index 717c8280843f8dcab4124d8672d1f145c71c768b..e909bbe99aa357b1f8cd7f551156ee4b7950573f 100644 (file)
@@ -1281,14 +1281,34 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
 
   /* Get route attributes */
   rta *a = new->attrs;
-  u32 m1 = ea_get_int(ea, EA_OSPF_METRIC1, LSINFINITY);
-  u32 m2 = ea_get_int(ea, EA_OSPF_METRIC2, 10000);
-  int ebit = (m1 == LSINFINITY);
-  u32 metric = ebit ? m2 : m1;
-  u32 tag = ea_get_int(ea, EA_OSPF_TAG, 0);
-  ip_addr fwd = IPA_NONE;
+  eattr *m1a = ea_find(ea, EA_OSPF_METRIC1);
+  eattr *m2a = ea_find(ea, EA_OSPF_METRIC2);
+  uint m1 = m1a ? m1a->u.data : 0;
+  uint m2 = m2a ? m2a->u.data : 10000;
 
+  if (m1 > LSINFINITY)
+  {
+    log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N",
+       p->p.name, m1, n->n.addr);
+    m1 = LSINFINITY;
+  }
 
+  if (m2 > LSINFINITY)
+  {
+    log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N",
+       p->p.name, m2, n->n.addr);
+    m2 = LSINFINITY;
+  }
+
+  /* Ensure monotonicity of metric if both m1 and m2 are used */
+  if ((m1 > 0) && (m2 < LSINFINITY))
+    m2++;
+
+  uint ebit = m2a || !m1a;
+  uint metric = ebit ? m2 : m1;
+  uint tag = ea_get_int(ea, EA_OSPF_TAG, 0);
+
+  ip_addr fwd = IPA_NONE;
   if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface))
     fwd = a->nh.gw;
 
index 85e37cea2ea08b8cc5257a01d8625e7f9c70a592..baf987374e06c18ed12cd6097c89878482a8d066 100644 (file)
@@ -1020,16 +1020,6 @@ rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
   return l;
 }
 
-static int
-rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
-{
-  /* Prepare attributes with initial values */
-  if ((*rt)->attrs->source != RTS_RIP)
-    *attrs = rip_prepare_attrs(pool, *attrs, 1, 0);
-
-  return 0;
-}
-
 static void
 rip_reload_routes(struct channel *C)
 {
@@ -1091,7 +1081,7 @@ rip_init(struct proto_config *CF)
   P->if_notify = rip_if_notify;
   P->rt_notify = rip_rt_notify;
   P->neigh_notify = rip_neigh_notify;
-  P->import_control = rip_import_control;
+  // P->import_control = rip_import_control;
   P->reload_routes = rip_reload_routes;
   P->make_tmp_attrs = rip_make_tmp_attrs;
   P->store_tmp_attrs = rip_store_tmp_attrs;