On Mon, Nov 18, 2024 at 12:50:36PM +0100, Frode Nordahl wrote:
> On Mon, Nov 18, 2024 at 12:11 PM Felix Huettner via dev
> <ovs-dev@openvswitch.org> wrote:
> >
> > On Thu, Nov 14, 2024 at 11:10:39AM +0100, Lorenzo Bianconi wrote:
> > > > previously connected routes (so routes based on the networks of the
> > > > LRPs) where handled separately from static routes.
> > > >
> > > > In order to later announce routes from ovn to the fabric we need to have
> > > > a central overview over all routes we want to announce. This includes
> > > > routes based on Logical_Router_Static_Routes as well as the networks on
> > > > Logical_Router_Port.

Hi Frode,

thanks for the review.

> 
> While I can see you have a use case that requires a central overview
> of all routes, it is not required for all use cases. For the use cases
> not requiring it, this approach appears like it would introduce
> duplication of data?
> 
> `northd` already has access to information on LRPs for flow
> generation, and the `ovn-controller` already has access to information
> on LRPs in the Port_Binding table. Is that not sufficient to announce
> connected routes?

I would agree that this is sufficient for connected routes (as long as
you don't want to advertise per-host routes).

However since needed some logic for static routes, connected-routes as
host routes and for learning routes i wanted to keep things uniform.
While this creates such large changes to northd i believe it makes the
whole concept more understandable later as all routing information comes
from a single source.

Thanks
Felix

> 
> Also, when using Netlink plugin for route exchange, the IP/MAC
> addresses of LRPs can be replicated in VRFs in the system which will
> already give the routing protocol daemon the information it needs to
> redistribute connected routes.
> 
> --
> Frode Nordahl
> 
> > > >
> > > > With this change the "routes" engine node will output a complete list of
> > > > all routes in the system. This also serves as a future integration point
> > > > to integrate routes learned from outside of OVN.
> > >
> > > Hi Felix,
> > >
> > > This patch needs a respin. Some nits inline.
> >
> > Hi Lorenzo,
> >
> > thanks for the review
> >
> > >
> > > Regards,
> > > Lorenzo
> > >
> > > >
> > > > Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
> > > > ---
> > > >  northd/northd.c | 270 ++++++++++++++++++++++++++++++------------------
> > > >  northd/northd.h |  11 +-
> > > >  2 files changed, 178 insertions(+), 103 deletions(-)
> > > >
> > > > diff --git a/northd/northd.c b/northd/northd.c
> > > > index 1265e3c81..90ddc2acb 100644
> > > > --- a/northd/northd.c
> > > > +++ b/northd/northd.c
> > > > @@ -11071,6 +11071,20 @@ parsed_route_lookup(struct hmap *routes, 
> > > > size_t hash,
> > > >              continue;
> > > >          }
> > > >
> > > > +        if (pr->source != new_pr->source) {
> > > > +            continue;
> > > > +        }
> > > > +
> > > > +        if (!pr->nexthop != !new_pr->nexthop) {
> > > > +            continue;
> > >
> > > why not if (pr->nexthop != new_pr->nexthop) ?
> >
> > We would then compare the pointers of pr->nexthop to new_pr->nexthop
> > instead of checking if either both of them are null or non-null.
> > I'll add a comment to clarify this.
> >
> > >
> > > > +        }
> > > > +
> > > > +        if (pr->nexthop &&
> > > > +                memcmp(pr->nexthop, new_pr->nexthop,
> > > > +                       sizeof(struct in6_addr))) {
> > >
> > > I guess we can use ipv6_addr_equals() here.
> >
> > Thanks fixed.
> >
> > >
> > > > +            continue;
> > > > +        }
> > > > +
> > > >          if (memcmp(&pr->prefix, &new_pr->prefix, sizeof(struct 
> > > > in6_addr))) {
> > > >              continue;
> > > >          }
> > > > @@ -11111,6 +11125,9 @@ parsed_route_lookup(struct hmap *routes, size_t 
> > > > hash,
> > > >
> > > >  static void
> > > >  parsed_route_free(struct parsed_route *pr) {
> > > > +    if (pr->nexthop) {
> > >
> > > you can remove if () here
> >
> > Thanks fixed.
> >
> > >
> > > > +        free(pr->nexthop);
> > > > +    }
> > > >      if (pr->lrp_addr_s) {
> > > >          free(pr->lrp_addr_s);
> > > >      }
> > > > @@ -11119,31 +11136,77 @@ parsed_route_free(struct parsed_route *pr) {
> > > >  }
> > > >
> > > >  static void
> > > > -parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports,
> > > > +parsed_route_add(const struct ovn_datapath *od,
> > > > +                 struct in6_addr *nexthop,
> > > > +                 const struct in6_addr prefix,
> > > > +                 unsigned int plen,
> > > > +                 bool is_discard_route,
> > > > +                 const char *lrp_addr_s,
> > > > +                 const struct ovn_port *out_port,
> > > > +                 const struct nbrec_logical_router_static_route *route,
> > > > +                 uint32_t route_table_id,
> > > > +                 bool is_src_route,
> > > > +                 bool ecmp_symmetric_reply,
> > > > +                 enum route_source source,
> > > > +                 struct hmap *routes)
> > > > +{
> > > > +
> > > > +    struct parsed_route *new_pr = xzalloc(sizeof *new_pr);
> > > > +    new_pr->prefix = prefix;
> > > > +    new_pr->plen = plen;
> > > > +    new_pr->nexthop = nexthop;
> > > > +    new_pr->route_table_id = route_table_id;
> > > > +    new_pr->is_src_route = is_src_route;
> > > > +    new_pr->hash = route_hash(new_pr);
> > > > +    new_pr->nbr = od->nbr;
> > > > +    new_pr->ecmp_symmetric_reply = ecmp_symmetric_reply;
> > > > +    new_pr->is_discard_route = is_discard_route;
> > > > +    if (!is_discard_route) {
> > > > +        new_pr->lrp_addr_s = xstrdup(lrp_addr_s);
> > > > +    }
> > > > +    new_pr->out_port = out_port;
> > > > +    new_pr->source = source;
> > > > +    new_pr->route = route;
> > > > +
> > > > +    size_t hash = uuid_hash(&od->key);
> > > > +    struct parsed_route *pr = parsed_route_lookup(routes, hash, 
> > > > new_pr);
> > > > +    if (!pr) {
> > > > +        hmap_insert(routes, &new_pr->key_node, hash);
> > > > +    } else {
> > > > +        pr->stale = false;
> > > > +        parsed_route_free(new_pr);
> > > > +    }
> > > > +}
> > > > +
> > > > +static void
> > > > +parsed_routes_add_static(struct ovn_datapath *od, const struct hmap 
> > > > *lr_ports,
> > > >                    const struct nbrec_logical_router_static_route 
> > > > *route,
> > > >                    const struct hmap *bfd_connections,
> > > >                    struct hmap *routes, struct simap *route_tables,
> > > >                    struct hmap *bfd_active_connections)
> > > >  {
> > > >      /* Verify that the next hop is an IP address with an all-ones 
> > > > mask. */
> > > > -    struct in6_addr nexthop;
> > > > +    struct in6_addr *nexthop = NULL;
> > >
> > > if we allow parsed_route_add() to make a private copy of it we can avoid a
> > > pointer for nexthop here and make the patch more readable (e.g. remove all
> > > free(nexthop))
> >
> > I choose this way because on a static route the nexthop field might not
> > be set. OVN currently accepts this as a valid static route and then
> > uses "ip.dst" as nexthop value (see add_route in northd.c).
> >
> > If we don't use a pointer here then parsed_route_add() would need to
> > check based on some magic address to then treat it as NULL. This magic
> > address (even though it might be invalid nexthop) would then be
> > unavailable for the user to set. So i think this would cause a behaviour
> > change.
> >
> > Therefor i decided to stick to the current pointer approach.
> >
> > >
> > > >      unsigned int plen;
> > > >      bool is_discard_route = !strcmp(route->nexthop, "discard");
> > > >      bool valid_nexthop = route->nexthop[0] && !is_discard_route;
> > > >      if (valid_nexthop) {
> > > > -        if (!ip46_parse_cidr(route->nexthop, &nexthop, &plen)) {
> > > > +        nexthop = xmalloc(sizeof(*nexthop));
> > > > +        if (!ip46_parse_cidr(route->nexthop, nexthop, &plen)) {
> > > >              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 
> > > > 1);
> > > >              VLOG_WARN_RL(&rl, "bad 'nexthop' %s in static route "
> > > >                           UUID_FMT, route->nexthop,
> > > >                           UUID_ARGS(&route->header_.uuid));
> > > > +            free(nexthop);
> > > >              return;
> > > >          }
> > > > -        if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) ||
> > > > -            (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) {
> > > > +        if ((IN6_IS_ADDR_V4MAPPED(nexthop) && plen != 32) ||
> > > > +            (!IN6_IS_ADDR_V4MAPPED(nexthop) && plen != 128)) {
> > > >              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 
> > > > 1);
> > > >              VLOG_WARN_RL(&rl, "bad next hop mask %s in static route "
> > > >                           UUID_FMT, route->nexthop,
> > > >                           UUID_ARGS(&route->header_.uuid));
> > > > +            free(nexthop);
> > > >              return;
> > > >          }
> > > >      }
> > > > @@ -11155,17 +11218,19 @@ parsed_routes_add(struct ovn_datapath *od, 
> > > > const struct hmap *lr_ports,
> > > >          VLOG_WARN_RL(&rl, "bad 'ip_prefix' %s in static route "
> > > >                       UUID_FMT, route->ip_prefix,
> > > >                       UUID_ARGS(&route->header_.uuid));
> > > > +        free(nexthop);
> > > >          return;
> > > >      }
> > > >
> > > >      /* Verify that ip_prefix and nexthop have same address familiy. */
> > > >      if (valid_nexthop) {
> > > > -        if (IN6_IS_ADDR_V4MAPPED(&prefix) != 
> > > > IN6_IS_ADDR_V4MAPPED(&nexthop)) {
> > > > +        if (IN6_IS_ADDR_V4MAPPED(&prefix) != 
> > > > IN6_IS_ADDR_V4MAPPED(nexthop)) {
> > > >              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 
> > > > 1);
> > > >              VLOG_WARN_RL(&rl, "Address family doesn't match between 
> > > > 'ip_prefix'"
> > > >                           " %s and 'nexthop' %s in static route 
> > > > "UUID_FMT,
> > > >                           route->ip_prefix, route->nexthop,
> > > >                           UUID_ARGS(&route->header_.uuid));
> > > > +            free(nexthop);
> > > >              return;
> > > >          }
> > > >      }
> > > > @@ -11177,6 +11242,7 @@ parsed_routes_add(struct ovn_datapath *od, 
> > > > const struct hmap *lr_ports,
> > > >          !find_static_route_outport(od, lr_ports, route,
> > > >                                     IN6_IS_ADDR_V4MAPPED(&prefix),
> > > >                                     &lrp_addr_s, &out_port)) {
> > > > +        free(nexthop);
> > > >          return;
> > > >      }
> > > >
> > > > @@ -11186,6 +11252,7 @@ parsed_routes_add(struct ovn_datapath *od, 
> > > > const struct hmap *lr_ports,
> > > >                                                    nb_bt->logical_port,
> > > >                                                    nb_bt->dst_ip);
> > > >          if (!bfd_e) {
> > > > +            free(nexthop);
> > > >              return;
> > > >          }
> > > >
> > > > @@ -11205,36 +11272,58 @@ parsed_routes_add(struct ovn_datapath *od, 
> > > > const struct hmap *lr_ports,
> > > >
> > > >
> > > >          if (!strcmp(bfd_sr->status, "down")) {
> > > > +            free(nexthop);
> > > >              return;
> > > >          }
> > > >      }
> > > >
> > > > -    struct parsed_route *new_pr = xzalloc(sizeof *new_pr);
> > > > -    new_pr->prefix = prefix;
> > > > -    new_pr->plen = plen;
> > > > -    new_pr->route_table_id = get_route_table_id(route_tables,
> > > > -                                                route->route_table);
> > > > -    new_pr->is_src_route = (route->policy &&
> > > > -                            !strcmp(route->policy, "src-ip"));
> > > > -    new_pr->hash = route_hash(new_pr);
> > > > -    new_pr->route = route;
> > > > -    new_pr->nbr = od->nbr;
> > > > -    new_pr->ecmp_symmetric_reply = smap_get_bool(&route->options,
> > > > -                                                 
> > > > "ecmp_symmetric_reply",
> > > > -                                                 false);
> > > > -    new_pr->is_discard_route = is_discard_route;
> > > > -    if (!is_discard_route) {
> > > > -        new_pr->lrp_addr_s = xstrdup(lrp_addr_s);
> > > > -    }
> > > > -    new_pr->out_port = out_port;
> > > > +    uint32_t route_table_id = get_route_table_id(route_tables,
> > > > +                                        route->route_table);
> > > > +    bool is_src_route = (route->policy && !strcmp(route->policy, 
> > > > "src-ip"));
> > > > +    bool ecmp_symmetric_reply = smap_get_bool(&route->options,
> > > > +                                         "ecmp_symmetric_reply",
> > > > +                                         false);
> > > >
> > > > -    size_t hash = uuid_hash(&od->key);
> > > > -    struct parsed_route *pr = parsed_route_lookup(routes, hash, 
> > > > new_pr);
> > > > -    if (!pr) {
> > > > -        hmap_insert(routes, &new_pr->key_node, hash);
> > > > +    enum route_source source;
> > > > +    if (!strcmp(smap_get_def(&route->options, "origin", ""),
> > > > +                                 ROUTE_ORIGIN_CONNECTED)) {
> > > > +        source = ROUTE_SOURCE_CONNECTED;
> > > >      } else {
> > > > -        pr->stale = false;
> > > > -        parsed_route_free(new_pr);
> > > > +        source = ROUTE_SOURCE_STATIC;
> > > > +    }
> > > > +
> > > > +    parsed_route_add(od, nexthop, prefix, plen, is_discard_route, 
> > > > lrp_addr_s,
> > > > +                      out_port, route, route_table_id, is_src_route,
> > > > +                      ecmp_symmetric_reply, source,
> > > > +                      routes);
> > > > +}
> > > > +
> > > > +static void
> > > > +parsed_routes_add_connected(struct ovn_datapath *od, const struct 
> > > > ovn_port *op,
> > > > +                            struct hmap *routes)
> > > > +{
> > > > +    for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
> > > > +        const struct ipv4_netaddr *addr = 
> > > > &op->lrp_networks.ipv4_addrs[i];
> > > > +        struct in6_addr prefix;
> > > > +        ip46_parse(addr->network_s, &prefix);
> > > > +
> > > > +        parsed_route_add(od, NULL, prefix, addr->plen,
> > > > +                          false, addr->addr_s, op,
> > > > +                          NULL, 0, false,
> > > > +                          false, ROUTE_SOURCE_CONNECTED,
> > > > +                          routes);
> > > > +    }
> > > > +
> > > > +    for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
> > > > +        const struct ipv6_netaddr *addr = 
> > > > &op->lrp_networks.ipv6_addrs[i];
> > > > +        struct in6_addr prefix;
> > > > +        ip46_parse(addr->network_s, &prefix);
> > > > +
> > > > +        parsed_route_add(od, NULL, prefix, addr->plen,
> > > > +                          false, addr->addr_s, op,
> > > > +                          NULL, 0, false,
> > > > +                          false, ROUTE_SOURCE_CONNECTED,
> > > > +                          routes);
> > > >      }
> > > >  }
> > > >
> > > > @@ -11252,9 +11341,14 @@ build_parsed_routes(struct ovn_datapath *od, 
> > > > const struct hmap *lr_ports,
> > > >      }
> > > >
> > > >      for (int i = 0; i < od->nbr->n_static_routes; i++) {
> > > > -        parsed_routes_add(od, lr_ports, od->nbr->static_routes[i],
> > > > -                          bfd_connections, routes, route_tables,
> > > > -                          bfd_active_connections);
> > > > +        parsed_routes_add_static(od, lr_ports, 
> > > > od->nbr->static_routes[i],
> > > > +                                 bfd_connections, routes, route_tables,
> > > > +                                 bfd_active_connections);
> > > > +    }
> > > > +
> > > > +    const struct ovn_port *op;
> > > > +    HMAP_FOR_EACH (op, dp_node, &od->ports) {
> > > > +        parsed_routes_add_connected(od, op, routes);
> > > >      }
> > > >
> > > >      HMAP_FOR_EACH_SAFE (pr, key_node, routes) {
> > > > @@ -11279,7 +11373,7 @@ struct ecmp_groups_node {
> > > >      struct in6_addr prefix;
> > > >      unsigned int plen;
> > > >      bool is_src_route;
> > > > -    const char *origin;
> > > > +    enum route_source source;
> > > >      uint32_t route_table_id;
> > > >      uint16_t route_count;
> > > >      struct ovs_list route_list; /* Contains ecmp_route_list_node */
> > > > @@ -11318,7 +11412,7 @@ ecmp_groups_add(struct hmap *ecmp_groups,
> > > >      eg->prefix = route->prefix;
> > > >      eg->plen = route->plen;
> > > >      eg->is_src_route = route->is_src_route;
> > > > -    eg->origin = smap_get_def(&route->route->options, "origin", "");
> > > > +    eg->source = route->source;
> > > >      eg->route_table_id = route->route_table_id;
> > > >      ovs_list_init(&eg->route_list);
> > > >      ecmp_groups_add_route(eg, route);
> > > > @@ -11382,6 +11476,7 @@ unique_routes_remove(struct hmap *unique_routes,
> > > >          if (ipv6_addr_equals(&route->prefix, &ur->route->prefix) &&
> > > >              route->plen == ur->route->plen &&
> > > >              route->is_src_route == ur->route->is_src_route &&
> > > > +            route->source == ur->route->source &&
> > > >              route->route_table_id == ur->route->route_table_id) {
> > > >              hmap_remove(unique_routes, &ur->hmap_node);
> > > >              const struct parsed_route *existed_route = ur->route;
> > > > @@ -11515,7 +11610,7 @@ static void
> > > >  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
> > > >                                 struct ovn_datapath *od,
> > > >                                 const char *port_ip,
> > > > -                               struct ovn_port *out_port,
> > > > +                               const struct ovn_port *out_port,
> > > >                                 const struct parsed_route *route,
> > > >                                 struct ds *route_match,
> > > >                                 struct lflow_ref *lflow_ref)
> > > > @@ -11609,6 +11704,19 @@ add_ecmp_symmetric_reply_flows(struct 
> > > > lflow_table *lflows,
> > > >      ds_destroy(&ecmp_reply);
> > > >  }
> > > >
> > > > +static int
> > > > +route_source_to_offset(enum route_source source)
> > > > +{
> > > > +    switch (source) {
> > > > +        case ROUTE_SOURCE_CONNECTED:
> > > > +            return ROUTE_PRIO_OFFSET_CONNECTED;
> > > > +        case ROUTE_SOURCE_STATIC:
> > > > +            return ROUTE_PRIO_OFFSET_STATIC;
> > > > +        default:
> > > > +            OVS_NOT_REACHED();
> > > > +    }
> > > > +}
> > > > +
> > > >  static void
> > > >  build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath 
> > > > *od,
> > > >                        struct ecmp_groups_node *eg, struct lflow_ref 
> > > > *lflow_ref)
> > > > @@ -11620,8 +11728,7 @@ build_ecmp_route_flow(struct lflow_table 
> > > > *lflows, struct ovn_datapath *od,
> > > >      struct ds route_match = DS_EMPTY_INITIALIZER;
> > > >
> > > >      char *prefix_s = build_route_prefix_s(&eg->prefix, eg->plen);
> > > > -    int ofs = !strcmp(eg->origin, ROUTE_ORIGIN_CONNECTED) ?
> > > > -        ROUTE_PRIO_OFFSET_CONNECTED: ROUTE_PRIO_OFFSET_STATIC;
> > > > +    int ofs = route_source_to_offset(eg->source);
> > > >      build_route_match(NULL, eg->route_table_id, prefix_s, eg->plen,
> > > >                        eg->is_src_route, is_ipv4, &route_match, 
> > > > &priority, ofs);
> > > >      free(prefix_s);
> > > > @@ -11675,13 +11782,14 @@ build_ecmp_route_flow(struct lflow_table 
> > > > *lflows, struct ovn_datapath *od,
> > > >                        REG_ECMP_MEMBER_ID" == %"PRIu16,
> > > >                        eg->id, er->id);
> > > >          ds_clear(&actions);
> > > > -        ds_put_format(&actions, "%s = %s; "
> > > > +        ds_put_format(&actions, "%s = ",
> > > > +                      is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6);
> > > > +        ipv6_format_mapped(route_->nexthop, &actions);
> > > > +        ds_put_format(&actions, "; "
> > > >                        "%s = %s; "
> > > >                        "eth.src = %s; "
> > > >                        "outport = %s; "
> > > >                        "next;",
> > > > -                      is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6,
> > > > -                      route->nexthop,
> > > >                        is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6,
> > > >                        route_->lrp_addr_s,
> > > >                        route_->out_port->lrp_networks.ea_s,
> > > > @@ -11699,17 +11807,19 @@ build_ecmp_route_flow(struct lflow_table 
> > > > *lflows, struct ovn_datapath *od,
> > > >  static void
> > > >  add_route(struct lflow_table *lflows, struct ovn_datapath *od,
> > > >            const struct ovn_port *op, const char *lrp_addr_s,
> > > > -          const char *network_s, int plen, const char *gateway,
> > > > +          const char *network_s, int plen, const struct in6_addr 
> > > > *gateway,
> > > >            bool is_src_route, const uint32_t rtb_id,
> > > >            const struct sset *bfd_ports,
> > > >            const struct ovsdb_idl_row *stage_hint, bool 
> > > > is_discard_route,
> > > > -          int ofs, struct lflow_ref *lflow_ref)
> > > > +          enum route_source source, struct lflow_ref *lflow_ref)
> > > >  {
> > > >      bool is_ipv4 = strchr(network_s, '.') ? true : false;
> > > >      struct ds match = DS_EMPTY_INITIALIZER;
> > > >      uint16_t priority;
> > > >      const struct ovn_port *op_inport = NULL;
> > > >
> > > > +    int ofs = route_source_to_offset(source);
> > > > +
> > > >      /* IPv6 link-local addresses must be scoped to the local router 
> > > > port. */
> > > >      if (!is_ipv4) {
> > > >          struct in6_addr network;
> > > > @@ -11728,8 +11838,8 @@ add_route(struct lflow_table *lflows, struct 
> > > > ovn_datapath *od,
> > > >      } else {
> > > >          ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ",
> > > >                        is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6);
> > > > -        if (gateway && gateway[0]) {
> > > > -            ds_put_cstr(&common_actions, gateway);
> > > > +        if (gateway) {
> > > > +            ipv6_format_mapped(gateway, &common_actions);
> > > >          } else {
> > > >              ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? "4" : 
> > > > "6");
> > > >          }
> > > > @@ -11764,23 +11874,20 @@ add_route(struct lflow_table *lflows, struct 
> > > > ovn_datapath *od,
> > > >  }
> > > >
> > > >  static void
> > > > -build_static_route_flow(struct lflow_table *lflows, struct 
> > > > ovn_datapath *od,
> > > > +build_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
> > > >                          const struct parsed_route *route_,
> > > >                          const struct sset *bfd_ports,
> > > >                          struct lflow_ref *lflow_ref)
> > > >  {
> > > >      const struct nbrec_logical_router_static_route *route = 
> > > > route_->route;
> > > >
> > > > -    int ofs = !strcmp(smap_get_def(&route->options, "origin", ""),
> > > > -                      ROUTE_ORIGIN_CONNECTED) ? 
> > > > ROUTE_PRIO_OFFSET_CONNECTED
> > > > -                                              : 
> > > > ROUTE_PRIO_OFFSET_STATIC;
> > > > -
> > > >      char *prefix_s = build_route_prefix_s(&route_->prefix, 
> > > > route_->plen);
> > > >      add_route(lflows, route_->is_discard_route ? od : 
> > > > route_->out_port->od,
> > > >                route_->out_port, route_->lrp_addr_s, prefix_s,
> > > > -              route_->plen, route->nexthop, route_->is_src_route,
> > > > -              route_->route_table_id, bfd_ports, &route->header_,
> > > > -              route_->is_discard_route, ofs, lflow_ref);
> > > > +              route_->plen, route_->nexthop, route_->is_src_route,
> > > > +              route_->route_table_id, bfd_ports,
> > > > +              route ? &route->header_ : 
> > > > &route_->out_port->nbrp->header_,
> > > > +              route_->is_discard_route, route_->source, lflow_ref);
> > > >
> > > >      free(prefix_s);
> > > >  }
> > > > @@ -13509,51 +13616,8 @@ build_ip_routing_pre_flows_for_lrouter(struct 
> > > > ovn_datapath *od,
> > > >                    REG_ROUTE_TABLE_ID" = 0; next;", lflow_ref);
> > > >  }
> > > >
> > > > -/* Logical router ingress table IP_ROUTING : IP Routing.
> > > > - *
> > > > - * A packet that arrives at this table is an IP packet that should be
> > > > - * routed to the address in 'ip[46].dst'.
> > > > - *
> > > > - * For regular routes without ECMP, table IP_ROUTING sets outport to 
> > > > the
> > > > - * correct output port, eth.src to the output port's MAC address, and
> > > > - * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 to the next-hop IP address
> > > > - * (leaving 'ip[46].dst', the packet’s final destination, unchanged), 
> > > > and
> > > > - * advances to the next table.
> > > > - *
> > > > - * For ECMP routes, i.e. multiple routes with same policy and prefix, 
> > > > table
> > > > - * IP_ROUTING remembers ECMP group id and selects a member id, and 
> > > > advances
> > > > - * to table IP_ROUTING_ECMP, which sets outport, eth.src and
> > > > - * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 for the selected ECMP member.
> > > > - *
> > > > - * This function adds routes for directly connected subnets configured 
> > > > on the
> > > > - * LRP 'op'.
> > > > - */
> > > >  static void
> > > > -build_ip_routing_flows_for_lrp(struct ovn_port *op,
> > > > -                               const struct sset *bfd_ports,
> > > > -                               struct lflow_table *lflows,
> > > > -                               struct lflow_ref *lflow_ref)
> > > > -{
> > > > -    ovs_assert(op->nbrp);
> > > > -    for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
> > > > -        add_route(lflows, op->od, op, 
> > > > op->lrp_networks.ipv4_addrs[i].addr_s,
> > > > -                  op->lrp_networks.ipv4_addrs[i].network_s,
> > > > -                  op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0,
> > > > -                  bfd_ports, &op->nbrp->header_, false,
> > > > -                  ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref);
> > > > -    }
> > > > -
> > > > -    for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
> > > > -        add_route(lflows, op->od, op, 
> > > > op->lrp_networks.ipv6_addrs[i].addr_s,
> > > > -                  op->lrp_networks.ipv6_addrs[i].network_s,
> > > > -                  op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0,
> > > > -                  bfd_ports, &op->nbrp->header_, false,
> > > > -                  ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref);
> > > > -    }
> > > > -}
> > > > -
> > > > -static void
> > > > -build_static_route_flows_for_lrouter(
> > > > +build_route_flows_for_lrouter(
> > > >          struct ovn_datapath *od, struct lflow_table *lflows,
> > > >          struct hmap *parsed_routes,
> > > >          struct simap *route_tables, const struct sset *bfd_ports,
> > > > @@ -13580,6 +13644,10 @@ build_static_route_flows_for_lrouter(
> > > >      struct parsed_route *route;
> > > >      HMAP_FOR_EACH_WITH_HASH (route, key_node, uuid_hash(&od->key),
> > > >                               parsed_routes) {
> > > > +        if (route->source == ROUTE_SOURCE_CONNECTED) {
> > > > +            unique_routes_add(&unique_routes, route);
> > > > +            continue;
> > > > +        }
> > > >          group = ecmp_groups_find(&ecmp_groups, route);
> > > >          if (group) {
> > > >              ecmp_groups_add_route(group, route);
> > > > @@ -13608,7 +13676,7 @@ build_static_route_flows_for_lrouter(
> > > >      }
> > > >      const struct unique_routes_node *ur;
> > > >      HMAP_FOR_EACH (ur, hmap_node, &unique_routes) {
> > > > -        build_static_route_flow(lflows, od, ur->route,
> > > > +        build_route_flow(lflows, od, ur->route,
> > > >                                  bfd_ports, lflow_ref);
> > > >      }
> > > >      ecmp_groups_destroy(&ecmp_groups);
> > > > @@ -16852,7 +16920,7 @@ build_routable_flows_for_router_port(
> > > >                                laddrs->ipv4_addrs[k].network_s,
> > > >                                laddrs->ipv4_addrs[k].plen, NULL, false, 
> > > > 0,
> > > >                                bfd_ports, &router_port->nbrp->header_,
> > > > -                              false, ROUTE_PRIO_OFFSET_CONNECTED,
> > > > +                              false, ROUTE_SOURCE_CONNECTED,
> > > >                                lrp->stateful_lflow_ref);
> > > >                  }
> > > >              }
> > > > @@ -17094,7 +17162,7 @@ build_lswitch_and_lrouter_iterate_by_lr(struct 
> > > > ovn_datapath *od,
> > > >                                             lsi->meter_groups, NULL);
> > > >      build_ND_RA_flows_for_lrouter(od, lsi->lflows, NULL);
> > > >      build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, NULL);
> > > > -    build_static_route_flows_for_lrouter(od, lsi->lflows,
> > > > +    build_route_flows_for_lrouter(od, lsi->lflows,
> > > >                                           lsi->parsed_routes, 
> > > > lsi->route_tables,
> > > >                                           lsi->bfd_ports, NULL);
> > > >      build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> > > > @@ -17167,8 +17235,6 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct 
> > > > ovn_port *op,
> > > >                                            &lsi->actions, 
> > > > op->lflow_ref);
> > > >      build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, 
> > > > &lsi->match,
> > > >                                                  &lsi->actions, 
> > > > op->lflow_ref);
> > > > -    build_ip_routing_flows_for_lrp(op, lsi->bfd_ports,
> > > > -                                   lsi->lflows, op->lflow_ref);
> > > >      build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
> > > >                                         &lsi->actions, 
> > > > lsi->meter_groups,
> > > >                                         op->lflow_ref);
> > > > diff --git a/northd/northd.h b/northd/northd.h
> > > > index f701abd45..eb669f734 100644
> > > > --- a/northd/northd.h
> > > > +++ b/northd/northd.h
> > > > @@ -696,10 +696,18 @@ struct ovn_port {
> > > >      struct lflow_ref *stateful_lflow_ref;
> > > >  };
> > > >
> > > > +enum route_source {
> > > > +    /* the route is directly connected to the logical router */
> > > > +    ROUTE_SOURCE_CONNECTED,
> > >
> > > I know naming is hard but maybe ROUTE_SOURCE_LOCAL?
> >
> > The idea behind this name was to have it similar to what physical
> > routers use. There also the terms "connected" and "static" are used.
> > But if you prefer i can still change it.
> >
> > >
> > > > +    /* the route is derived from a northbound static route entry */
> > > > +    ROUTE_SOURCE_STATIC,
> > > > +};
> > > > +
> > > >  struct parsed_route {
> > > >      struct hmap_node key_node;
> > > >      struct in6_addr prefix;
> > > >      unsigned int plen;
> > > > +    struct in6_addr *nexthop; /* NULL for ROUTE_SOURCE_CONNECTED */
> > > >      bool is_src_route;
> > > >      uint32_t route_table_id;
> > > >      uint32_t hash;
> > > > @@ -708,8 +716,9 @@ struct parsed_route {
> > > >      bool is_discard_route;
> > > >      const struct nbrec_logical_router *nbr;
> > > >      bool stale;
> > > > +    enum route_source source;
> > > >      char *lrp_addr_s;
> > > > -    struct ovn_port *out_port;
> > > > +    const struct ovn_port *out_port;
> > >
> > > can you add this in the patch where you added out_port pointer?
> >
> > Yes will do that.
> >
> > Thanks for the review
> > Felix
> >
> > >
> > > >  };
> > > >
> > > >  void ovnnb_db_run(struct northd_input *input_data,
> > > > --
> > > > 2.47.0
> > > >
> > > >
> > > > _______________________________________________
> > > > dev mailing list
> > > > d...@openvswitch.org
> > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> >
> > > _______________________________________________
> > > dev mailing list
> > > d...@openvswitch.org
> > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> > _______________________________________________
> > dev mailing list
> > d...@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to