On 10/26/26 7:17 AM, Han Zhou via dev wrote:
> A route can describe its next hop with a separate nexthop object (see
> 'ip nexthop') that it refers to through a nexthop id carried in the
> RTA_NH_ID attribute, instead of encoding the next hop inline.  Routing
> daemons commonly install routes this way, as it lets many routes share
> one next hop and be redirected at once.
> 
> Parse RTA_NH_ID and report it in 'struct route_data'.  The kernel reports
> the next hop inline as well, so such a route is parsed as any other and
> the id is extra information, which users of the library that keep track
> of the kernel nexthop table themselves can follow.
> 
> Nothing in the tree resolves the id.  ovs-router in particular relies on
> the inline next hop, which the kernel leaves out when the
> net.ipv4.nexthop_compat_mode sysctl is turned off, so OVS still needs
> that sysctl at its default.  A route that then carries none of RTA_OIF,
> RTA_GATEWAY, RTA_VIA and RTA_MULTIPATH is no longer dropped as
> unparseable though: it is reported with an empty nexthop list next to a
> non-zero id, which tells a user of the library that it has to resolve the
> id itself.
> 
> Assisted-by: Claude Opus 5, Cursor
> Signed-off-by: Han Zhou <[email protected]>
> ---
> v2: Addressed Ilya's comments.
> v3: Addressed more comments from Ilya. Also rebased.
> 
>  lib/route-table.c            | 19 ++++++++++---
>  lib/route-table.h            |  3 +++
>  tests/system-route.at        | 52 ++++++++++++++++++++++++++++++++++++
>  tests/test-lib-route-table.c |  5 ++--
>  4 files changed, 74 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/route-table.c b/lib/route-table.c
> index 2a13a5cc7d93..ac6f8e74e50f 100644
> --- a/lib/route-table.c
> +++ b/lib/route-table.c
> @@ -45,6 +45,7 @@
>   * in case we're building with old headers. (We can't test for it with #ifdef
>   * because it's an enum.) */
>  #define RTA_MARK 16 /* Linux 2.6.36 */
> +#define RTA_NH_ID 30 /* Linux 5.3 */
>  #define FRA_SUPPRESS_PREFIXLEN 14 /* Linux 3.12 */
>  #define FRA_TABLE 15 /* Linux 2.6.19 */
>  #define FRA_PROTOCOL 21 /* Linux 4.17 */
> @@ -468,6 +469,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>          [RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
>          [RTA_VIA] = { .type = NL_A_RTA_VIA, .optional = true },
>          [RTA_MULTIPATH] = { .type = NL_A_NESTED, .optional = true },
> +        [RTA_NH_ID] = { .type = NL_A_U32, .optional = true },
>      };
>  
>      static const struct nl_policy policy6[] = {
> @@ -480,6 +482,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>          [RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
>          [RTA_VIA] = { .type = NL_A_RTA_VIA, .optional = true },
>          [RTA_MULTIPATH] = { .type = NL_A_NESTED, .optional = true },
> +        [RTA_NH_ID] = { .type = NL_A_U32, .optional = true },
>      };
>  
>      struct nlattr *attrs[ARRAY_SIZE(policy)];
> @@ -585,6 +588,9 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>          if (attrs[RTA_PRIORITY]) {
>              change->rd.rta_priority = nl_attr_get_u32(attrs[RTA_PRIORITY]);
>          }
> +        if (attrs[RTA_NH_ID]) {
> +            change->rd.rta_nhid = nl_attr_get_u32(attrs[RTA_NH_ID]);
> +        }
>          if (attrs[RTA_VIA]) {
>              const struct rtvia *rtvia = nl_attr_get(attrs[RTA_VIA]);
>              ovs_be32 addr;
> @@ -673,9 +679,16 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>          if (route_type_needs_nexthop(rtm->rtm_type)
>              && !attrs[RTA_OIF] && !attrs[RTA_GATEWAY]
>              && !attrs[RTA_VIA] && !attrs[RTA_MULTIPATH]) {
> -            VLOG_DBG_RL(&rl, "route message needs an RTA_OIF, RTA_GATEWAY, "
> -                             "RTA_VIA or RTA_MULTIPATH attribute");
> -            goto error_out;
> +            if (!attrs[RTA_NH_ID]) {
> +                VLOG_DBG_RL(&rl, "route message needs an RTA_OIF, "
> +                                 "RTA_GATEWAY, RTA_VIA, RTA_MULTIPATH or "
> +                                 "RTA_NH_ID attribute");
> +                goto error_out;
> +            }
> +
> +            /* The next hop is in the nexthop object named by RTA_NH_ID, so
> +             * the entry added at the start of parsing was never filled in. 
> */
> +            route_data_destroy_nexthops__(&change->rd);
>          }
>          /* Add any additional RTA attribute processing before RTA_MULTIPATH. 
> */
>  
> diff --git a/lib/route-table.h b/lib/route-table.h
> index b49fbb14ebe0..45a9a012480a 100644
> --- a/lib/route-table.h
> +++ b/lib/route-table.h
> @@ -141,6 +141,9 @@ struct route_data {
>      uint32_t rta_mark;           /* 0 if missing. */
>      uint32_t rta_table_id;       /* 0 if missing. */
>      uint32_t rta_priority;       /* 0 if missing. */
> +    uint32_t rta_nhid;           /* Nexthop object id, 0 if missing.  
> Resolved
> +                                    by the user; 'nexthops' is empty unless 
> the
> +                                    kernel also reported it inline. */

nit: need a star on each line.

I fixed that and applied that patch.  Thanks!

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to