Btw:  Donald -- this patch is very early in the Cumulus tree;  I assume
it's been part of previous stable releases that are in active use at
customer installations?  Have you received any reports of breakage?

-David

On Fri, May 20, 2016 at 04:37:37PM +0200, David Lamparter wrote:
> On Fri, May 20, 2016 at 02:12:51PM +0100, Paul Jakma wrote:
> > Could we agree that at a minimum there needs to be a config knob, so 
> > admins can at least manage rolling out updates without introducing 
> > mixed-environments?
> 
> I haven't seen any technical argument that led me to change my opinion
> on migration, i.e. I still strongly believe this needs to be fixed ASAP,
> getting RFC-compliant behaviour without user interaction.  That means
> I'm continuing to oppose patches that don't make RFC behaviour the
> default.
> 
> The event most likely to change my opinion on this is being presented
> with an actual real-world setup that sees breakage from this.  From the
> way this bug works, I guess it'd need to be a Quagga-only production
> network.
> 
> If there is an additional default-off "ospf spf-maxcost-quagga" switch,
> I don't see a problem with that.
> 
> > I think more transparent migration that avoids exposing Quagga networks 
> > (currently fine) to any loop risk, ought to be possible, e.g. with RIs 
> > (which we'd have to support at some stage even for H-bit), but that can 
> > be another discussion.
> 
> Funnily enough, the prefixes for which traffic could loop in a mixed
> setup are the prefixes which would default to a less specific route if
> the router to be maintenance'd is fully removed; i.e. it's the prefixes
> for which service is likely degraded anyway...
> 
> 
> -David
> 
> 
> > From 8142989d465d6dd2e41b0bb7a17069b5c0c3a8bb Mon Sep 17 00:00:00 2001
> > From: Paul Jakma <paul.ja...@hpe.com>
> > Date: Fri, 20 May 2016 09:54:34 +0100
> > Subject: ospfd: Add compatibility setting for max-cost link SPF behaviour
> > 
> > * Quagga OSPF has long treated max-cost links as not suitable for
> >    inclusion into the transit SPF tree (doesn't affect reachability of
> >    the node itself).  Other implementations treat it as just another
> >    cost.
> > 
> >    In mixed environments there is therefore a risk of routing loops.
> >    It may be a rare risk, though when hit it could be quite
> >    troublesome.
> > 
> >    Just flipping the default would not address that risk.  It need not
> >    fix the risk on networks currently exposed, while exposing other
> >    networks to the risk that would otherwise not be affected.  Which
> >    administrators of the latter networks might find less than ideal.
> > 
> >    TBD: A good transition strategy, that avoids bothering currently
> >    unaffected networks with this problem.  E.g.  RIs could be used to
> >    transparently do the right thing for a greater number of networks
> >    and minise the risks.
> > 
> >    Also, the OSPF WG are standardising a method to signal Quagga's
> >    current behaviour conformantly.  So it might also be good to
> >    minimise churn in behaviour, but that depends on when that comes
> >    along.
> > 
> >    Regardless, it would be good to at least give administrators who
> >    are exposed a configuration setting.
> > 
> > * ospfd.h: Add a OSPF_MAX_METRIC_LINK_FOLLOW flag to (struct ospf).
> > * lib/libospf.h: Add OSPF_OUTPUT_COST_MAX, and a
> >    OSPF_OUTPUT_COST_DISCOURAGE - latter metric works universally to
> >    signal 'discourage but still allow transit'.
> > 
> > * ospf_lsa.c: (ospf_link_cost) Use the DISCOURAGE cost to signal
> >    stub-router, if SPF is set to 'follow'.  These are somewhat
> >    separate, and with ways to signal the transit/no-transit intent of
> >    the local router this might be done differently, but for this patch
> >    probably best done together.
> > 
> > * ospf_spf.c: (ospf_spf_next) make the behaviour on max-cost links
> >    configurable.
> > 
> > * ospf_vty.c: (show_ip_ospf) Print the status of the SPF max-cost
> >    behaviour in 'show ip ospf'.
> > 
> >    (ospf_compatible_max_metric) Add  "compatible max-metric
> >    (infinite|follow)" to control the SPF behaviour.
> > 
> >    (no_ospf_compatible_max_metric) clear back to default, which will
> >    still be written out explicitly, as below.
> > 
> >    (config_write_stub_router) Write out the config for the "compatible
> >    max-metric (infinite|follow)" flag.  In this version, the flag
> >    state is always written out explicitly - the default state is not
> >    suppressed.  There's pros and cons to this of course.
> > 
> >    (ospf_vty_init) add prev.
> > 
> > * docs/ospfd.texi: docs on the "compatible max-metric
> >    (infinite|follow)" command.
> > 
> > diff --git a/doc/ospfd.texi b/doc/ospfd.texi
> > index 86cabe4..da6608f 100644
> > --- a/doc/ospfd.texi
> > +++ b/doc/ospfd.texi
> > @@ -172,6 +172,8 @@ releases.
> >   @deffn {OSPF Command} {max-metric router-lsa [on-startup|on-shutdown] 
> > <5-86400>} {}
> >   @deffnx {OSPF Command} {max-metric router-lsa administrative} {}
> >   @deffnx {OSPF Command} {no max-metric router-lsa 
> > [on-startup|on-shutdown|administrative]} {}
> > +@anchor{OSPF stub-router}
> > +@anchor{max-metric router-lsa}
> >   This enables @cite{RFC3137, OSPF Stub Router Advertisement} support,
> >   where the OSPF process describes its transit links in its router-LSA as
> >   having infinite distance so that other routers will avoid calculating
> > @@ -202,6 +204,51 @@ number of second remaining till on-startup or 
> > on-shutdown ends, can be
> >   viewed with the @ref{show ip ospf} command.
> >   @end deffn
> > 
> > +
> > +@deffn {OSPF Command} {compatible max-metric (infinite|follow)} {}
> > +@deffnx {OSPF Command} {no compatible max-metric} {}
> > +
> > +This flag controls the behaviour of SPF, and how it treats links in
> > +Router-LSAs with the maximum possible metric value.  It toggles between the
> > +@cite{RFC2328} specified behaviour, and a Quagga variation.
> > +
> > +When this flag is set to @var{follow}, then the standard RFC2328
> > +behaviour applies.  The SPF calculation will still take links with
> > +the maximum value metric of 0xffff into consideration when
> > +calculating transit paths out of remote routers.
> > +
> > +When this flag is set to @var{infinite}, then Quagga deviates from
> > +RFC2328.  The SPF transit tree calculation will treat the maximum
> > +link metric of 0xffff as an infinite cost.  Such links will not be
> > +considered for the transit tree.  This only affects whether links
> > +@emph{out} of a remote router will be used for transit - it does not
> > +affect the reachability to the router itself, or to its stub
> > +addresses and networks. 
> > +
> > +The @var{infinite} behaviour exists in Quagga as it allows routers to
> > +advertise links as @emph{strictly} non-transit or merely as
> > +discouraged, but still available for transit. The @var{infinite}
> > +behaviour is the default, and is the only possible behaviour on most
> > +older releases of Quagga.
> > +
> > +In networks with routers with mixed behaviour, if links are
> > +advertised with the 0xffff maximum metric (e.g., through the
> > +@ref{OSPF stub-router} functionality) then routing loops may
> > +potentially occur depending on the topology.
> > +
> > +The appropriate behaviour to configure depends on whether the
> > +administrator prefers stub-routers to be strictly not available for
> > +transit or not, on whether the network is mixed, and the consequences
> > +of routing loops.
> > +
> > +The default behaviour is @var{infinite} for compatibility with
> > +previous Quagga releases, for now.  In older Quagga releases this
> > +behaviour is not configurable.  The default is likely to change from
> > +@var{infinite} to @var{follow} in a future release.
> > +
> > +@end deffn
> > +
> > +
> >   @deffn {OSPF Command} {auto-cost reference-bandwidth <1-4294967>} {}
> >   @deffnx {OSPF Command} {no auto-cost reference-bandwidth} {}
> >   @anchor{OSPF auto-cost reference-bandwidth}This sets the reference
> > diff --git a/lib/libospf.h b/lib/libospf.h
> > index 9265ca5..8d9e40f 100644
> > --- a/lib/libospf.h
> > +++ b/lib/libospf.h
> > @@ -63,6 +63,8 @@
> >   /* OSPF interface default values. */
> >   #define OSPF_OUTPUT_COST_DEFAULT           10
> >   #define OSPF_OUTPUT_COST_INFINITE    UINT16_MAX
> > +#define OSPF_OUTPUT_COST_MAX               OSPF_OUTPUT_COST_INFINITE
> > +#define OSPF_OUTPUT_COST_DISCOURAGE        (OSPF_OUTPUT_COST_MAX - 1)
> >   #define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT  40
> >   #define OSPF_ROUTER_DEAD_INTERVAL_MINIMAL   1
> >   #define OSPF_HELLO_INTERVAL_DEFAULT        10
> > diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
> > index 634bc43..84dc5de 100644
> > --- a/ospfd/ospf_lsa.c
> > +++ b/ospfd/ospf_lsa.c
> > @@ -488,7 +488,8 @@ ospf_link_cost (struct ospf_interface *oi)
> >     if (!CHECK_FLAG (oi->area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED))
> >       return oi->output_cost;
> >     else
> > -    return OSPF_OUTPUT_COST_INFINITE;
> > +    return CHECK_FLAG(oi->area->ospf->config, OSPF_MAX_METRIC_LINK_FOLLOW)
> > +           ? OSPF_OUTPUT_COST_DISCOURAGE : OSPF_OUTPUT_COST_INFINITE;
> >   }
> > 
> >   /* Set a link information. */
> > diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
> > index 58a3992..43a6619 100644
> > --- a/ospfd/ospf_spf.c
> > +++ b/ospfd/ospf_spf.c
> > @@ -837,11 +837,55 @@ ospf_spf_next (struct vertex *v, struct ospf_area 
> > *area,
> >             if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
> >               continue;
> > 
> > -          /* Infinite distance links shouldn't be followed, except
> > -           * for local links (a stub-routed router still wants to
> > -           * calculate tree, so must follow its own links).
> > +          /* RFC3137 has wording in places that suggests non-transit
> > +           * links / links out of a stub-routed node shouldn't be
> > +           * followed, RFC6987 even uses "should not".  Unfortunately
> > +           * however, it seems these RFCs were never intended to
> > +           * change the behaviour of OSPF.  It seems they weren't
> > +           * meant amount to anything more than notes to say
> > +           * "increasing link costs may discourage traffic through a
> > +           * router" and there wasn't actually intended to be
> > +           * anything special about 0xffff.
> > +           *
> > +           * Quagga however interpreted 0xffff as special, as meaning
> > +           * infinite cost and hence untraversable / strictly "no
> > +           * transit", as it appeared to be useful (and the
> > +           * implementor specifically wanted that behaviour on his
> > +           * network).  As did original OSPF, prior to 1583.
> > +           *
> > +           * Other implementations treat 0xffff costs as just a very
> > +           * high cost, OSPF_OUTPUT_COST_MAX, but will still include
> > +           * them in the transit tree.
> > +           *
> > +           * Mixed environments of the two behaviours can therefore
> > +           * lead to routing loops.
> > +           * 
> > +           * In some use-cases, the administrator may even  prefer
> > +           * "no transit stub-router" to really mean that.
> > +           *
> > +           * This behaviour is configurable, via the OSPF instance
> > +           * OSPF_MAX_METRIC_LINK_FOLLOW config flag, defaulting to
> > +           * the long-standing Quagga behaviour to not follow 0xfff
> > +           * links out for now, to avoid causing issues on networks
> > +           * that currently are not exposed to routing-loop risks
> > +           * from this, but may be if the default is flipped.
> > +           *
> > +           * TBD: A transition strategy to OSPF conformance that
> > +           * minimises exposing /further/ networks to risks of loops.
> > +           *
> > +           * Note: this has no effect on stub networks attached to
> > +           * the router, such as local loopback and PtP addresses,
> > +           * and broadcast networks without any established OSPF
> > +           * adjacencies.  These should always be reachable,
> > +           * regardless.
> > +           *
> > +           * Note: a cost of 0xfffe or lower works universally to
> > +           * signal "use of this link is discouraged, but it is still
> > +           * available to transit through".
> >              */
> > -          if ((v != area->spf) && l->m[0].metric >= 
> > OSPF_OUTPUT_COST_INFINITE)
> > +          if ((v != area->spf)
> > +              && l->m[0].metric >= OSPF_OUTPUT_COST_MAX
> > +              && !CHECK_FLAG(area->ospf->config, 
> > OSPF_MAX_METRIC_LINK_FOLLOW))
> >               continue;
> > 
> >             /* (b) Otherwise, W is a transit vertex (router or transit
> > diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
> > index fb17dff..b34aa4c 100644
> > --- a/ospfd/ospf_vty.c
> > +++ b/ospfd/ospf_vty.c
> > @@ -2836,6 +2836,12 @@ DEFUN (show_ip_ospf,
> >        CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ?
> >              "enabled" : "disabled",
> >              VTY_NEWLINE);
> > +  vty_out (vty, " SPF treats max-metric links as:%s   %s%s",
> > +           VTY_NEWLINE,
> > +           CHECK_FLAG(ospf->config, OSPF_MAX_METRIC_LINK_FOLLOW)
> > +             ? "low preference but transit capable (RFC standard)"
> > +             : "infinite cost and not transit capable (RFC deviation)",
> > +           VTY_NEWLINE);
> > 
> >     /* Show stub-router configuration */
> >     if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED
> > @@ -6417,10 +6423,51 @@ ALIAS (no_ip_ospf_mtu_ignore,
> >         "OSPF interface commands\n"
> >         "Disable mtu mismatch detection\n")
> > 
> > +#define OSPF_CMD_MAX_METRIC_STR \
> > +  "OSPF maximum / infinite-distance metric links\n"
> > +
> > +DEFUN (ospf_compatible_max_metric,
> > +       ospf_compatible_max_metric_cmd,
> > +       "compatible max-metric (infinite|follow)",
> > +       "OSPF compatibility list\n"
> > +       "Behaviour for " OSPF_CMD_MAX_METRIC_STR
> > +       "SPF treats max-cost links as infinite and not considered when"
> > +         " examining LSAs for transit out of a router (RFC deviation)\n"
> > +       "SPF treats max-cost links as lowest-preference links, "
> > +         "but still available for transit\n")
> > +{
> > +  struct ospf *ospf = vty->index;
> > +  switch (argv[0][0])
> > +    {
> > +      case 'i':
> > +        UNSET_FLAG (ospf->config, OSPF_MAX_METRIC_LINK_FOLLOW);
> > +        break;
> > +      case 'f':
> > +        SET_FLAG (ospf->config, OSPF_MAX_METRIC_LINK_FOLLOW);
> > +        break;
> > +      default:
> > +        vty_out (vty, "%% Unknown argument %s%s", argv[0], VTY_NEWLINE);
> > +        return CMD_WARNING;
> > +    } 
> > +  return CMD_SUCCESS;
> > +}
> > +
> > +DEFUN (no_ospf_compatible_max_metric,
> > +       no_ospf_compatible_max_metric_cmd,
> > +       "no compatible max-metric",
> > +       NO_STR
> > +       "OSPF compatibility list\n"
> > +       "Behaviour for " OSPF_CMD_MAX_METRIC_STR)
> > +{
> > +  struct ospf *ospf = vty->index;
> > +  UNSET_FLAG (ospf->config, OSPF_MAX_METRIC_LINK_FOLLOW);
> > +  return CMD_SUCCESS;
> > +}
> > +
> >   DEFUN (ospf_max_metric_router_lsa_admin,
> >          ospf_max_metric_router_lsa_admin_cmd,
> >          "max-metric router-lsa administrative",
> > -       "OSPF maximum / infinite-distance metric\n"
> > +       OSPF_CMD_MAX_METRIC_STR
> >          "Advertise own Router-LSA with infinite distance (stub router)\n"
> >          "Administratively applied, for an indefinite period\n")
> >   {
> > @@ -6446,7 +6493,7 @@ DEFUN (no_ospf_max_metric_router_lsa_admin,
> >          no_ospf_max_metric_router_lsa_admin_cmd,
> >          "no max-metric router-lsa administrative",
> >          NO_STR
> > -       "OSPF maximum / infinite-distance metric\n"
> > +       OSPF_CMD_MAX_METRIC_STR
> >          "Advertise own Router-LSA with infinite distance (stub router)\n"
> >          "Administratively applied, for an indefinite period\n")
> >   {
> > @@ -6473,7 +6520,7 @@ DEFUN (no_ospf_max_metric_router_lsa_admin,
> >   DEFUN (ospf_max_metric_router_lsa_startup,
> >          ospf_max_metric_router_lsa_startup_cmd,
> >          "max-metric router-lsa on-startup <5-86400>",
> > -       "OSPF maximum / infinite-distance metric\n"
> > +       OSPF_CMD_MAX_METRIC_STR
> >          "Advertise own Router-LSA with infinite distance (stub router)\n"
> >          "Automatically advertise stub Router-LSA on startup of OSPF\n"
> >          "Time (seconds) to advertise self as stub-router\n")
> > @@ -6498,7 +6545,7 @@ DEFUN (no_ospf_max_metric_router_lsa_startup,
> >          no_ospf_max_metric_router_lsa_startup_cmd,
> >          "no max-metric router-lsa on-startup",
> >          NO_STR
> > -       "OSPF maximum / infinite-distance metric\n"
> > +       OSPF_CMD_MAX_METRIC_STR
> >          "Advertise own Router-LSA with infinite distance (stub router)\n"
> >          "Automatically advertise stub Router-LSA on startup of OSPF\n")
> >   {
> > @@ -6526,7 +6573,7 @@ DEFUN (no_ospf_max_metric_router_lsa_startup,
> >   DEFUN (ospf_max_metric_router_lsa_shutdown,
> >          ospf_max_metric_router_lsa_shutdown_cmd,
> >          "max-metric router-lsa on-shutdown <5-86400>",
> > -       "OSPF maximum / infinite-distance metric\n"
> > +       OSPF_CMD_MAX_METRIC_STR
> >          "Advertise own Router-LSA with infinite distance (stub router)\n"
> >          "Advertise stub-router prior to full shutdown of OSPF\n"
> >          "Time (seconds) to wait till full shutdown\n")
> > @@ -6551,7 +6598,7 @@ DEFUN (no_ospf_max_metric_router_lsa_shutdown,
> >          no_ospf_max_metric_router_lsa_shutdown_cmd,
> >          "no max-metric router-lsa on-shutdown",
> >          NO_STR
> > -       "OSPF maximum / infinite-distance metric\n"
> > +       OSPF_CMD_MAX_METRIC_STR
> >          "Advertise own Router-LSA with infinite distance (stub router)\n"
> >          "Advertise stub-router prior to full shutdown of OSPF\n")
> >   {
> > @@ -6568,6 +6615,10 @@ config_write_stub_router (struct vty *vty, struct 
> > ospf *ospf)
> >     struct listnode *ln;
> >     struct ospf_area *area;
> > 
> > +  vty_out (vty, " compatible max-metric %s%s",
> > +           CHECK_FLAG (ospf->config, OSPF_MAX_METRIC_LINK_FOLLOW)
> > +             ? "follow" : "infinite",
> > +           VTY_NEWLINE);
> >     if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED)
> >       vty_out (vty, " max-metric router-lsa on-startup %u%s",
> >                ospf->stub_router_startup_time, VTY_NEWLINE);
> > @@ -7877,6 +7928,8 @@ ospf_vty_init (void)
> >     install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd);
> > 
> >     /* max-metric commands */
> > +  install_element (OSPF_NODE, &ospf_compatible_max_metric_cmd);
> > +  install_element (OSPF_NODE, &no_ospf_compatible_max_metric_cmd);
> >     install_element (OSPF_NODE, &ospf_max_metric_router_lsa_admin_cmd);
> >     install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_admin_cmd);
> >     install_element (OSPF_NODE, &ospf_max_metric_router_lsa_startup_cmd);
> > diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
> > index 098fc5f..1c4d2c4 100644
> > --- a/ospfd/ospfd.h
> > +++ b/ospfd/ospfd.h
> > @@ -130,6 +130,7 @@ struct ospf
> >   #define OSPF_OPAQUE_CAPABLE               (1 << 2)
> >   #define OSPF_LOG_ADJACENCY_CHANGES        (1 << 3)
> >   #define OSPF_LOG_ADJACENCY_DETAIL (1 << 4)
> > +#define OSPF_MAX_METRIC_LINK_FOLLOW     (1 << 5)
> > 
> >     /* Opaque-LSA administrative flags. */
> >     u_char opaque;
> > 
> > regards,
> > -- 
> > Paul Jakma  p...@jakma.org  @pjakma Key ID: 64A2FF6A
> > Fortune:
> > You are not dead yet.  But watch for further reports.

_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to