On Mon, Feb 03, 2025 at 02:48:24PM +0100, Dumitru Ceara wrote:
> On 1/29/25 12:15 PM, Felix Huettner via dev wrote:
> > Previously we just assumed that if a LR had multiple LRPs bound to the
> > local chassis that all routes where valid for all of these LRPs.
> > This commit handles a previous option in ovn-nb that allowes the user to
> > specify the interface name that a route needs to use to be acceptable
> > for a given LRP.
> > The users can then have a 1:1 relationship between LRPs and interfaces
> > to allow ovn-controller to determine which route belongs to which LRP.
> > 
> > This can e.g. be used if a chassis has multiple uplinks. Each of these
> > uplinks could be assigned to a different LRP of the same LR connected to
> > the same localnet.
> > The option allows then to map e.g. a learned default route to each
> > individual LRP. If one of the links would go down just one of the
> > learned routes would be removed, causing ECMP across multiple chassis to
> > be correctly weighted.
> > 
> > Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
> > ---
> 
> Hi Felix,
> 
> I only have two minor comments below.  If addressing those is the only
> diff in v6, feel free to also add my ack:
> 
> Acked-by: Dumitru Ceara <dce...@redhat.com>

Hi Dumitru,

thanks a lot for the review.
The changes will be in the next version.

Thanks a lot,
Felix

> 
> > v3->v4:
> >   - addressed review comments.
> >   - updated commit message to be more descriptive.
> > 
> >  controller/route-exchange-netlink.c |  1 +
> >  controller/route-exchange-netlink.h |  3 +++
> >  controller/route-exchange.c         | 20 ++++++++++++++------
> >  controller/route.c                  | 14 +++++++++-----
> >  controller/route.h                  |  6 ++++--
> >  tests/system-ovn.at                 | 23 ++++++++++++++++++++++-
> >  6 files changed, 53 insertions(+), 14 deletions(-)
> > 
> > diff --git a/controller/route-exchange-netlink.c 
> > b/controller/route-exchange-netlink.c
> > index 74741a3fd..c5a77efe4 100644
> > --- a/controller/route-exchange-netlink.c
> > +++ b/controller/route-exchange-netlink.c
> > @@ -237,6 +237,7 @@ handle_route_msg(const struct route_table_msg *msg, 
> > void *data)
> >              rr->addr = rd->rta_dst;
> >              rr->plen = rd->rtm_dst_len;
> >              rr->nexthop = nexthop->addr;
> > +            memcpy(rr->ifname, nexthop->ifname, IFNAMSIZ);
> 
> As mentioned on patch 6/11 I think I'd just set rr->ifname[IFNAMSIZ] = 0
> and use xmalloc() instead of xzalloc().
> 
> >          }
> >          return;
> >      }
> > diff --git a/controller/route-exchange-netlink.h 
> > b/controller/route-exchange-netlink.h
> > index bc77504ae..e4fe81977 100644
> > --- a/controller/route-exchange-netlink.h
> > +++ b/controller/route-exchange-netlink.h
> > @@ -21,6 +21,7 @@
> >  #include <stdint.h>
> >  #include "openvswitch/list.h"
> >  #include <netinet/in.h>
> > +#include <net/if.h>
> >  
> >  /* This value is arbitrary but currently unused.
> >   * See 
> > https://github.com/iproute2/iproute2/blob/main/etc/iproute2/rt_protos */
> > @@ -35,6 +36,8 @@ struct re_nl_received_route_node {
> >      struct in6_addr addr;
> >      unsigned int plen;
> >      struct in6_addr nexthop;
> > +    /* Adding 1 to this to be sure we actually have a terminating '\0' */
> > +    char ifname[IFNAMSIZ + 1];
> >  };
> >  
> >  int re_nl_create_vrf(const char *ifname, uint32_t table_id);
> > diff --git a/controller/route-exchange.c b/controller/route-exchange.c
> > index a163968a7..dc3e5657c 100644
> > --- a/controller/route-exchange.c
> > +++ b/controller/route-exchange.c
> > @@ -97,7 +97,7 @@ route_lookup(struct hmap *route_map,
> >  static void
> >  sb_sync_learned_routes(const struct ovs_list *learned_routes,
> >                         const struct sbrec_datapath_binding *datapath,
> > -                       const struct sset *bound_ports,
> > +                       const struct smap *bound_ports,
> >                         struct ovsdb_idl_txn *ovnsb_idl_txn,
> >                         struct ovsdb_idl_index *sbrec_port_binding_by_name,
> >                         struct ovsdb_idl_index 
> > *sbrec_learned_route_by_datapath)
> > @@ -112,8 +112,9 @@ sb_sync_learned_routes(const struct ovs_list 
> > *learned_routes,
> >      SBREC_LEARNED_ROUTE_FOR_EACH_EQUAL (sb_route, filter,
> >                                          sbrec_learned_route_by_datapath) {
> >          /* If the port is not local we don't care about it.
> > -         * Some other ovn-controller will handle it. */
> > -        if (!sset_contains(bound_ports,
> > +         * Some other ovn-controller will handle it.
> > +         * We may not use smap_get since the value might be validly NULL. 
> > */
> > +        if (!smap_get_node(bound_ports,
> >                             sb_route->logical_port->logical_port)) {
> >              continue;
> >          }
> > @@ -127,11 +128,18 @@ sb_sync_learned_routes(const struct ovs_list 
> > *learned_routes,
> >                                                 learned_route->plen);
> >          char *nexthop = normalize_v46(&learned_route->nexthop);
> >  
> > -        const char *logical_port_name;
> > -        SSET_FOR_EACH (logical_port_name, bound_ports) {
> > +        struct smap_node *port_node;
> > +        SMAP_FOR_EACH (port_node, bound_ports) {
> > +            /* The user specified an ifname, but we learned it on a 
> > different
> > +             * port. */
> > +            if (port_node->value && strcmp(port_node->value,
> > +                                           learned_route->ifname)) {
> > +                continue;
> > +            }
> > +
> >              const struct sbrec_port_binding *logical_port =
> >                  lport_lookup_by_name(sbrec_port_binding_by_name,
> > -                                     logical_port_name);
> > +                                     port_node->key);
> >              if (!logical_port) {
> >                  continue;
> >              }
> > diff --git a/controller/route.c b/controller/route.c
> > index 49e76ee73..22f38976b 100644
> > --- a/controller/route.c
> > +++ b/controller/route.c
> > @@ -87,7 +87,7 @@ advertise_datapath_cleanup(struct 
> > advertise_datapath_entry *ad)
> >          free(ar);
> >      }
> >      hmap_destroy(&ad->routes);
> > -    sset_destroy(&ad->bound_ports);
> > +    smap_destroy(&ad->bound_ports);
> >      free(ad);
> >  }
> >  
> > @@ -108,8 +108,8 @@ void
> >  route_run(struct route_ctx_in *r_ctx_in,
> >            struct route_ctx_out *r_ctx_out)
> >  {
> > -    struct advertise_datapath_entry *ad;
> >      const struct local_datapath *ld;
> > +    struct advertise_datapath_entry *ad;
> 
> I actually think it looks better in the other order (reverse xmas tree). :)
> 
> >  
> >      HMAP_FOR_EACH (ld, hmap_node, r_ctx_in->local_datapaths) {
> >          if (!ld->n_peer_ports || ld->is_switch) {
> > @@ -119,7 +119,7 @@ route_run(struct route_ctx_in *r_ctx_in,
> >          ad = xzalloc(sizeof(*ad));
> >          ad->db = ld->datapath;
> >          hmap_init(&ad->routes);
> > -        sset_init(&ad->bound_ports);
> > +        smap_init(&ad->bound_ports);
> >  
> >          /* This is a LR datapath, find LRPs with route exchange options
> >           * that are bound locally. */
> > @@ -137,10 +137,14 @@ route_run(struct route_ctx_in *r_ctx_in,
> >  
> >              ad->maintain_vrf |= smap_get_bool(
> >                  &repb->options, "dynamic-routing-maintain-vrf", false);
> > -            sset_add(&ad->bound_ports, local_peer->logical_port);
> > +            char *ifname = nullable_xstrdup(
> > +                                    smap_get(&repb->options,
> > +                                             "dynamic-routing-ifname"));
> > +            smap_add_nocopy(&ad->bound_ports,
> > +                            xstrdup(local_peer->logical_port), ifname);
> >          }
> >  
> > -        if (sset_is_empty(&ad->bound_ports)) {
> > +        if (smap_is_empty(&ad->bound_ports)) {
> >              advertise_datapath_cleanup(ad);
> >              continue;
> >          }
> > diff --git a/controller/route.h b/controller/route.h
> > index 6fc5963a5..f23115abb 100644
> > --- a/controller/route.h
> > +++ b/controller/route.h
> > @@ -22,6 +22,7 @@
> >  #include <netinet/in.h>
> >  #include "openvswitch/hmap.h"
> >  #include "sset.h"
> > +#include "smap.h"
> >  
> >  struct hmap;
> >  struct ovsdb_idl_index;
> > @@ -50,8 +51,9 @@ struct advertise_datapath_entry {
> >      struct hmap routes;
> >  
> >      /* The name of the port bindings locally bound for this datapath and
> > -     * running route exchange logic. */
> > -    struct sset bound_ports;
> > +     * running route exchange logic.
> > +     * The key is the port name and the value is the ifname if set. */
> > +    struct smap bound_ports;
> >  };
> >  
> >  struct advertise_route_entry {
> > diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> > index dc99d4c57..e17d9534e 100644
> > --- a/tests/system-ovn.at
> > +++ b/tests/system-ovn.at
> > @@ -15058,6 +15058,17 @@ check_row_count Learned_Route 1
> >  lp=$(fetch_column port_binding _uuid logical_port=internet-phys)
> >  check_row_count Learned_Route 1 logical_port=$lp ip_prefix=233.252.0.0/24 
> > nexthop=192.168.10.10
> >  
> > +# By setting a learning interface filter we will now forget about this 
> > route.
> > +check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> > +      options:dynamic-routing-ifname=thisdoesnotexist
> > +check_row_count Learned_Route 0
> > +
> > +# Changing it to "lo" will allow us to learn the route again.
> > +check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> > +      options:dynamic-routing-ifname=lo
> > +check_row_count Learned_Route 1
> > +
> > +
> >  OVS_APP_EXIT_AND_WAIT([ovn-controller])
> >  
> >  as ovn-sb
> > @@ -15268,10 +15279,20 @@ check ip route add 233.252.0.0/24 via 
> > 192.168.10.10 dev lo onlink vrf ovnvrf1337
> >  # For now we trigger a recompute as route watching is not yet implemented.
> >  check ovn-appctl -t ovn-controller inc-engine/recompute
> >  check ovn-nbctl --wait=hv sync
> > -check_row_count Learned_Route 2
> > +check_row_count Learned_Route 1
> >  lp=$(fetch_column port_binding _uuid logical_port=internet-phys)
> >  check_row_count Learned_Route 1 logical_port=$lp ip_prefix=233.252.0.0/24 
> > nexthop=192.168.10.10
> >  
> > +# By setting a learning interface filter we will now forget about this 
> > route.
> > +check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> > +      options:dynamic-routing-ifname=thisdoesnotexist
> > +check_row_count Learned_Route 0
> > +
> > +# Changing it to "lo" will allow us to learn the route again.
> > +check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> > +      options:dynamic-routing-ifname=lo
> > +check_row_count Learned_Route 1
> > +
> >  as ovn-sb
> >  OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> >  
> 
> Thanks,
> Dumitru
> 
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to