On Mon, Feb 03, 2025 at 04:18:29PM +0100, Dumitru Ceara wrote:
> On 1/29/25 12:15 PM, Felix Huettner via dev wrote:
> > When we stop ovn-controller without immediately restarting it we now
> > cleanup routes.
> > This allows the routing agents to stop advertising this chassis to the
> > fabric.
> >
> > Signed-off-by: Felix Huettner <[email protected]>
> > ---
>
> Hi Felix,
>
> This patch looks OK to me (except the few small nits I mentioned below).
> I won't ack it in this version though because we probably need to
> figure out the reason why some vrfs don't get cleaned up in the system
> tests (reported by Martin earlier on this thread).
>
> In any case, I'll have another look at this patch in v6.
Hi Dumitru,
thanks a lot for the review.
I'll address the small things in the next patch, for the other topic
i'll answer on the other thread.
Thanks a lot,
Felix
>
> Thanks,
> Dumitru
>
> > v3->v4:
> > - addressed review comments.
> >
> > controller/route-exchange-netlink.c | 34 +++++++++++----
> > controller/route-exchange-netlink.h | 2 +
> > controller/route-exchange.c | 66 +++++++++++++++++++++++++++-
> > tests/system-ovn.at | 67 ++++++++++++++++++++++++++++-
> > 4 files changed, 159 insertions(+), 10 deletions(-)
> >
> > diff --git a/controller/route-exchange-netlink.c
> > b/controller/route-exchange-netlink.c
> > index 6a9612a7e..93b3057c8 100644
> > --- a/controller/route-exchange-netlink.c
> > +++ b/controller/route-exchange-netlink.c
> > @@ -223,6 +223,9 @@ handle_route_msg(const struct route_table_msg *msg,
> > void *data)
> >
> > /* This route is not from us, so we learn it. */
> > if (rd->rtm_protocol != RTPROT_OVN) {
> > + if (!handle_data->learned_routes) {
> > + return;
> > + }
> > if (prefix_is_link_local(&rd->rta_dst, rd->rtm_dst_len)) {
> > return;
> > }
> > @@ -244,14 +247,16 @@ handle_route_msg(const struct route_table_msg *msg,
> > void *data)
> > return;
> > }
> >
> > - struct hmapx_node *hn;
> > - HMAPX_FOR_EACH_SAFE (hn, handle_data->routes_to_advertise) {
> > - ar = hn->data;
> > - if (ipv6_addr_equals(&ar->addr, &rd->rta_dst)
> > - && ar->plen == rd->rtm_dst_len
> > - && ar->priority == rd->rta_priority) {
> > - hmapx_delete(handle_data->routes_to_advertise, hn);
> > - return;
> > + if (handle_data->routes_to_advertise) {
> > + struct hmapx_node *hn;
> > + HMAPX_FOR_EACH_SAFE (hn, handle_data->routes_to_advertise) {
> > + ar = hn->data;
> > + if (ipv6_addr_equals(&ar->addr, &rd->rta_dst)
> > + && ar->plen == rd->rtm_dst_len
> > + && ar->priority == rd->rta_priority) {
> > + hmapx_delete(handle_data->routes_to_advertise, hn);
> > + return;
> > + }
> > }
> > }
> >
> > @@ -309,3 +314,16 @@ re_nl_sync_routes(uint32_t table_id, const struct hmap
> > *routes,
> > }
> > hmapx_destroy(&routes_to_advertise);
> > }
> > +
> > +void
> > +re_nl_cleanup_routes(uint32_t table_id)
> > +{
> > + /* Remove routes from the system that are not in the host_routes hmap
> > and
> > + * remove entries from host_routes hmap that match routes already
> > installed
> > + * in the system. */
> > + struct route_msg_handle_data data = {
> > + .routes_to_advertise = NULL,
> > + .learned_routes = NULL,
> > + };
> > + route_table_dump_one_table(table_id, handle_route_msg, &data);
> > +}
> > diff --git a/controller/route-exchange-netlink.h
> > b/controller/route-exchange-netlink.h
> > index b930f05a2..7a3ae1dda 100644
> > --- a/controller/route-exchange-netlink.h
> > +++ b/controller/route-exchange-netlink.h
> > @@ -55,4 +55,6 @@ void re_nl_sync_routes(uint32_t table_id, const struct
> > hmap *routes,
> > struct ovs_list *learned_routes,
> > const struct sbrec_datapath_binding *db);
> >
> > +void re_nl_cleanup_routes(uint32_t table_id);
> > +
> > #endif /* route-exchange-netlink.h */
> > diff --git a/controller/route-exchange.c b/controller/route-exchange.c
> > index e7a85eecf..47ff2350e 100644
> > --- a/controller/route-exchange.c
> > +++ b/controller/route-exchange.c
> > @@ -19,6 +19,7 @@
> >
> > #include <errno.h>
> > #include <net/if.h>
> > +#include <stdbool.h>
> >
> > #include "openvswitch/vlog.h"
> > #include "openvswitch/list.h"
> > @@ -37,6 +38,13 @@
> > VLOG_DEFINE_THIS_MODULE(route_exchange);
> > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
> >
> > +struct maintained_route_table_entry {
> > + struct hmap_node node;
> > + uint32_t table_id;
> > +};
> > +
> > +static struct hmap _maintained_route_tables = HMAP_INITIALIZER(
> > + &_maintained_route_tables);
>
> Nit: I think I prefer:
>
> static struct hmap _maintained_route_tables =
> HMAP_INITIALIZER(&_maintained_route_tables);
>
> > static struct sset _maintained_vrfs = SSET_INITIALIZER(&_maintained_vrfs);
> >
> > struct route_entry {
> > @@ -45,6 +53,38 @@ struct route_entry {
> > const struct sbrec_learned_route *sb_route;
> > };
> >
> > +static uint32_t
> > +maintained_route_table_hash(uint32_t table_id)
> > +{
> > + return hash_int(table_id, 0);
> > +}
> > +
> > +static bool
> > +maintained_route_table_contains(uint32_t table_id)
> > +{
> > + uint32_t hash = maintained_route_table_hash(table_id);
> > + struct maintained_route_table_entry *mrt;
> > + HMAP_FOR_EACH_WITH_HASH (mrt, node, hash,
> > + &_maintained_route_tables) {
> > + if (mrt->table_id == table_id) {
> > + return true;
> > + }
> > + }
> > + return false;
> > +}
> > +
> > +static void
> > +maintained_route_table_add(uint32_t table_id)
> > +{
> > + if (maintained_route_table_contains(table_id)) {
> > + return;
> > + }
> > + uint32_t hash = maintained_route_table_hash(table_id);
> > + struct maintained_route_table_entry *mrt = xzalloc(sizeof(*mrt));
> > + mrt->table_id = table_id;
> > + hmap_insert(&_maintained_route_tables, &mrt->node, hash);
> > +}
> > +
> > static struct route_entry *
> > route_alloc_entry(struct hmap *routes,
> > const struct sbrec_learned_route *sb_route)
> > @@ -174,6 +214,9 @@ route_exchange_run(struct route_exchange_ctx_in
> > *r_ctx_in,
> > {
> > struct sset old_maintained_vrfs =
> > SSET_INITIALIZER(&old_maintained_vrfs);
> > sset_swap(&_maintained_vrfs, &old_maintained_vrfs);
> > + struct hmap old_maintained_route_table = HMAP_INITIALIZER(
> > + &old_maintained_route_table);
>
> Similar here:
>
> struct hmap old_maintained_route_table =
> HMAP_INITIALIZER(&old_maintained_route_table);
>
> > + hmap_swap(&_maintained_route_tables, &old_maintained_route_table);
> >
> > const struct advertise_datapath_entry *ad;
> > HMAP_FOR_EACH (ad, node, r_ctx_in->announce_routes) {
> > @@ -201,9 +244,10 @@ route_exchange_run(struct route_exchange_ctx_in
> > *r_ctx_in,
> > sset_find_and_delete(&old_maintained_vrfs, vrf_name);
> > }
> >
> > + maintained_route_table_add(table_id);
> > +
> > struct ovs_list received_routes = OVS_LIST_INITIALIZER(
> > &received_routes);
> > -
> > re_nl_sync_routes(ad->db->tunnel_key, &ad->routes,
> > &received_routes, ad->db);
> >
> > @@ -218,6 +262,15 @@ route_exchange_run(struct route_exchange_ctx_in
> > *r_ctx_in,
> > re_nl_learned_routes_destroy(&received_routes);
> > }
> >
> > + /* Remove routes in tables previously maintained by us. */
> > + struct maintained_route_table_entry *mrt;
> > + HMAP_FOR_EACH_POP (mrt, node, &old_maintained_route_table) {
> > + if (!maintained_route_table_contains(mrt->table_id)) {
> > + re_nl_cleanup_routes(mrt->table_id);
> > + }
> > + free(mrt);
> > + }
> > + hmap_destroy(&old_maintained_route_table);
> >
> > /* Remove VRFs previously maintained by us not found in the above
> > loop. */
> > const char *vrf_name;
> > @@ -233,6 +286,11 @@ route_exchange_run(struct route_exchange_ctx_in
> > *r_ctx_in,
> > void
> > route_exchange_cleanup_vrfs(void)
> > {
> > + struct maintained_route_table_entry *mrt;
> > + HMAP_FOR_EACH (mrt, node, &_maintained_route_tables) {
> > + re_nl_cleanup_routes(mrt->table_id);
> > + }
> > +
> > const char *vrf_name;
> > SSET_FOR_EACH (vrf_name, &_maintained_vrfs) {
> > re_nl_delete_vrf(vrf_name);
> > @@ -242,10 +300,16 @@ route_exchange_cleanup_vrfs(void)
> > void
> > route_exchange_destroy(void)
> > {
> > + struct maintained_route_table_entry *mrt;
> > + HMAP_FOR_EACH_POP (mrt, node, &_maintained_route_tables) {
> > + free(mrt);
> > + }
> > +
> > const char *vrf_name;
> > SSET_FOR_EACH_SAFE (vrf_name, &_maintained_vrfs) {
> > sset_delete(&_maintained_vrfs, SSET_NODE_FROM_NAME(vrf_name));
> > }
> >
> > sset_destroy(&_maintained_vrfs);
> > + hmap_destroy(&_maintained_route_tables);
> > }
> > diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> > index 3f5672dad..963a67e0c 100644
> > --- a/tests/system-ovn.at
> > +++ b/tests/system-ovn.at
> > @@ -15090,8 +15090,39 @@ check ovn-nbctl --wait=hv set Logical_Router_Port
> > internet-phys \
> > options:dynamic-routing-ifname=lo
> > check_row_count Learned_Route 1
> >
> > -
> > +# Stopping the ovn-controller will clean up the route entries created by
> > it.
> > +# We first need to unset dynamic-routing-maintain-vrf as otherwise it will
> > +# delete the whole vrf.
> > +check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> > + options:dynamic-routing-maintain-vrf=false
> > OVS_APP_EXIT_AND_WAIT([ovn-controller])
> > +AT_CHECK([ip route list vrf ovnvrf1337 | awk '{$1=$1};1'], [0], [dnl
> > +233.252.0.0/24 via 192.168.10.10 dev lo onlink
> > +])
> > +
> > +# Starting it again will add the routes again.
> > +# The 2 sync commands ensure that we wait until the routes are actually
> > +# installed. Otherwise this is racy.
> > +start_daemon ovn-controller
> > +OVS_WAIT_UNTIL([test "$(ovn-appctl -t ovn-controller debug/status)" ==
> > "running"])
> > +OVS_WAIT_UNTIL_EQUAL([ip route list vrf ovnvrf1337 | awk '{$1=$1};1'], [dnl
> > +blackhole 192.0.2.1 proto 84 metric 1000
> > +blackhole 192.0.2.2 proto 84 metric 100
> > +blackhole 192.0.2.3 proto 84 metric 100
> > +blackhole 192.0.2.10 proto 84 metric 100
> > +blackhole 198.51.100.0/24 proto 84 metric 1000
> > +233.252.0.0/24 via 192.168.10.10 dev lo onlink])
> > +
> > +# Stoping with --restart will not touch the routes.
> > +check ovn-appctl -t ovn-controller exit --restart
> > +OVS_WAIT_UNTIL([test "$(ovn-appctl -t ovn-controller debug/status)" !=
> > "running"])
> > +OVS_WAIT_UNTIL_EQUAL([ip route list vrf ovnvrf1337 | awk '{$1=$1};1'], [dnl
> > +blackhole 192.0.2.1 proto 84 metric 1000
> > +blackhole 192.0.2.2 proto 84 metric 100
> > +blackhole 192.0.2.3 proto 84 metric 100
> > +blackhole 192.0.2.10 proto 84 metric 100
> > +blackhole 198.51.100.0/24 proto 84 metric 1000
> > +233.252.0.0/24 via 192.168.10.10 dev lo onlink])
> >
> > as ovn-sb
> > OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > @@ -15337,6 +15368,40 @@ check ovn-nbctl --wait=hv set Logical_Router_Port
> > internet-phys \
> > options:dynamic-routing-ifname=lo
> > check_row_count Learned_Route 1
> >
> > +# Stopping the ovn-controller will clean up the route entries created by
> > it.
> > +# We first need to unset dynamic-routing-maintain-vrf as otherwise it will
> > +# delete the whole vrf
> > +check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> > + options:dynamic-routing-maintain-vrf=false
> > +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> > +AT_CHECK([ip route list vrf ovnvrf1337 | awk '{$1=$1};1'], [0], [dnl
> > +233.252.0.0/24 via 192.168.10.10 dev lo onlink
> > +])
> > +
> > +# Starting it again will add the routes again.
> > +# The 2 sync commands ensure that we wait until the routes are actually
> > +# installed. Otherwise this is racy.
> > +start_daemon ovn-controller
> > +OVS_WAIT_UNTIL([test "$(ovn-appctl -t ovn-controller debug/status)" ==
> > "running"])
> > +OVS_WAIT_UNTIL_EQUAL([ip route list vrf ovnvrf1337 | awk '{$1=$1};1'], [dnl
> > +blackhole 192.0.2.1 proto 84 metric 100
> > +blackhole 192.0.2.2 proto 84 metric 100
> > +blackhole 192.0.2.3 proto 84 metric 100
> > +blackhole 192.0.2.10 proto 84 metric 100
> > +blackhole 198.51.100.0/24 proto 84 metric 1000
> > +233.252.0.0/24 via 192.168.10.10 dev lo onlink])
> > +
> > +# Stoping with --restart will not touch the routes.
> > +check ovn-appctl -t ovn-controller exit --restart
> > +OVS_WAIT_UNTIL([test "$(ovn-appctl -t ovn-controller debug/status)" !=
> > "running"])
> > +OVS_WAIT_UNTIL_EQUAL([ip route list vrf ovnvrf1337 | awk '{$1=$1};1'], [dnl
> > +blackhole 192.0.2.1 proto 84 metric 100
> > +blackhole 192.0.2.2 proto 84 metric 100
> > +blackhole 192.0.2.3 proto 84 metric 100
> > +blackhole 192.0.2.10 proto 84 metric 100
> > +blackhole 198.51.100.0/24 proto 84 metric 1000
> > +233.252.0.0/24 via 192.168.10.10 dev lo onlink])
> > +
> > as ovn-sb
> > OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> >
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev