Skip to content

Commit

Permalink
controller: Watch for route changes.
Browse files Browse the repository at this point in the history
for each vrf/network namespace we use we open a netlink watcher.
This allows us to reconcile on changed route entries from outside
routing agents.

Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
felixhuettner authored and ovsrobot committed Dec 17, 2024
1 parent d4d8c38 commit ac35ba5
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 11 deletions.
7 changes: 5 additions & 2 deletions controller/automake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,20 @@ controller_ovn_controller_SOURCES = \
controller/ovn-dns.c \
controller/ovn-dns.h \
controller/route-exchange.h \
controller/route-table-notify.h \
controller/route.h \
controller/route.c

if HAVE_NETLINK
controller_ovn_controller_SOURCES += \
controller/route-exchange-netlink.h \
controller/route-exchange-netlink.c \
controller/route-exchange.c
controller/route-exchange.c \
controller/route-table-notify.c
else
controller_ovn_controller_SOURCES += \
controller/route-exchange-stub.c
controller/route-exchange-stub.c \
controller/route-table-notify-stub.c
endif

controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la
Expand Down
48 changes: 48 additions & 0 deletions controller/ovn-controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
#include "ovn-dns.h"
#include "route.h"
#include "route-exchange.h"
#include "route-table-notify.h"

VLOG_DEFINE_THIS_MODULE(main);

Expand Down Expand Up @@ -5061,9 +5062,13 @@ en_route_exchange_run(struct engine_node *node, void *data OVS_UNUSED)

struct route_exchange_ctx_out r_ctx_out = {
};
hmap_init(&r_ctx_out.route_table_watches);

route_exchange_run(&r_ctx_in, &r_ctx_out);

route_table_notify_update_watches(&r_ctx_out.route_table_watches);
hmap_destroy(&r_ctx_out.route_table_watches);

engine_set_node_state(node, EN_UPDATED);
}

Expand All @@ -5079,6 +5084,38 @@ static void
en_route_exchange_cleanup(void *data OVS_UNUSED)
{}

struct ed_type_route_table_notify {
/* For incremental processing this could be tracked per datapath in
* the future. */
bool changed;
};

static void
en_route_table_notify_run(struct engine_node *node, void *data)
{
struct ed_type_route_table_notify *rtn = data;
if (rtn->changed) {
engine_set_node_state(node, EN_UPDATED);
} else {
engine_set_node_state(node, EN_UNCHANGED);
}
rtn->changed = false;
}


static void *
en_route_table_notify_init(struct engine_node *node OVS_UNUSED,
struct engine_arg *arg OVS_UNUSED)
{
struct ed_type_route_table_notify *rtn = xzalloc(sizeof(*rtn));
rtn->changed = true;
return rtn;
}

static void
en_route_table_notify_cleanup(void *data OVS_UNUSED)
{}

/* Returns false if the northd internal version stored in SB_Global
* and ovn-controller internal version don't match.
*/
Expand Down Expand Up @@ -5377,6 +5414,7 @@ main(int argc, char *argv[])
ENGINE_NODE(bfd_chassis, "bfd_chassis");
ENGINE_NODE(dns_cache, "dns_cache");
ENGINE_NODE(route, "route");
ENGINE_NODE(route_table_notify, "route_table_notify");
ENGINE_NODE(route_exchange, "route_exchange");

#define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
Expand Down Expand Up @@ -5414,6 +5452,7 @@ main(int argc, char *argv[])
engine_noop_handler);
engine_add_input(&en_route_exchange, &en_sb_port_binding,
engine_noop_handler);
engine_add_input(&en_route_exchange, &en_route_table_notify, NULL);

engine_add_input(&en_addr_sets, &en_sb_address_set,
addr_sets_sb_address_set_handler);
Expand Down Expand Up @@ -5931,6 +5970,14 @@ main(int argc, char *argv[])
&transport_zones,
bridge_table);

if (route_table_notify_run()) {
struct ed_type_route_table_notify *rtn =
engine_get_internal_data(&en_route_table_notify);
if (rtn) {
rtn->changed = true;
}
}

stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME,
time_msec());

Expand Down Expand Up @@ -6206,6 +6253,7 @@ main(int argc, char *argv[])
}

binding_wait();
route_table_notify_wait();
}

unixctl_server_run(unixctl);
Expand Down
6 changes: 0 additions & 6 deletions controller/route-exchange-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@
#include "openvswitch/compiler.h"
#include "route-exchange.h"

bool
route_exchange_relevant_port(const struct sbrec_port_binding *pb OVS_UNUSED)
{
return false;
}

void
route_exchange_run(struct route_exchange_ctx_in *r_ctx_in OVS_UNUSED,
struct route_exchange_ctx_out *r_ctx_out OVS_UNUSED)
Expand Down
8 changes: 7 additions & 1 deletion controller/route-exchange.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "ha-chassis.h"
#include "local_data.h"
#include "route.h"
#include "route-table-notify.h"
#include "route-exchange.h"
#include "route-exchange-netlink.h"

Expand Down Expand Up @@ -182,7 +183,7 @@ sb_sync_learned_routes(const struct sbrec_datapath_binding *datapath,

void
route_exchange_run(struct route_exchange_ctx_in *r_ctx_in,
struct route_exchange_ctx_out *r_ctx_out OVS_UNUSED)
struct route_exchange_ctx_out *r_ctx_out)
{
struct sset old_maintained_vrfs = SSET_INITIALIZER(&old_maintained_vrfs);
sset_swap(&_maintained_vrfs, &old_maintained_vrfs);
Expand Down Expand Up @@ -222,6 +223,11 @@ route_exchange_run(struct route_exchange_ctx_in *r_ctx_in,
r_ctx_in->sbrec_learned_route_by_datapath,
r_ctx_in->sbrec_port_binding_by_name);

struct route_table_watch_request *wr = xzalloc(sizeof(*wr));
wr->table_id = ad->key;
hmap_insert(&r_ctx_out->route_table_watches, &wr->node,
route_table_notify_hash_watch(wr->table_id));

out:
re_nl_received_routes_destroy(&received_routes);
}
Expand Down
3 changes: 3 additions & 0 deletions controller/route-exchange.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define ROUTE_EXCHANGE_H 1

#include <stdbool.h>
#include "openvswitch/hmap.h"

struct route_exchange_ctx_in {
struct ovsdb_idl_txn *ovnsb_idl_txn;
Expand All @@ -26,6 +27,8 @@ struct route_exchange_ctx_in {
};

struct route_exchange_ctx_out {
/* contains route_table_watch */
struct hmap route_table_watches;
};

void route_exchange_run(struct route_exchange_ctx_in *,
Expand Down
37 changes: 37 additions & 0 deletions controller/route-table-notify-stub.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <config.h>

#include <stdbool.h>

#include "openvswitch/compiler.h"
#include "route-table-notify.h"

bool
route_table_notify_run(void)
{
return false;
}

void
route_table_notify_wait(void)
{
}

void
route_table_notify_update_watches(struct hmap *route_table_watches OVS_UNUSED)
{
}

148 changes: 148 additions & 0 deletions controller/route-table-notify.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <config.h>

#include <net/if.h>
#include <linux/rtnetlink.h>

#include "netlink-notifier.h"
#include "openvswitch/vlog.h"

#include "binding.h"
#include "route-table.h"
#include "route.h"
#include "route-table-notify.h"
#include "route-exchange-netlink.h"


VLOG_DEFINE_THIS_MODULE(route_table_notify);

struct route_table_watch_entry {
struct hmap_node node;
uint32_t table_id;
bool is_netns;
struct nln *nln;
struct nln_notifier *route_notifier;
struct nln_notifier *route6_notifier;
/* used in update_watches to ensure we clean up */
bool stale;
};

static struct hmap watches = HMAP_INITIALIZER(&watches);
static bool any_route_table_changed = false;
static struct route_table_msg rtmsg;

static struct route_table_watch_entry*
find_watch_entry(uint32_t table_id)
{
struct route_table_watch_entry *we;
uint32_t hash = route_table_notify_hash_watch(table_id);
HMAP_FOR_EACH_WITH_HASH (we, node, hash, &watches) {
if (table_id == we->table_id) {
return we;
}
}
return NULL;
}

static void
route_table_change(const struct route_table_msg *change OVS_UNUSED,
void *aux OVS_UNUSED)
{
if (change && change->rd.rtm_protocol != RTPROT_OVN) {
any_route_table_changed = true;
}
}

static void
add_watch_entry(uint32_t table_id)
{
struct route_table_watch_entry *we;
uint32_t hash = route_table_notify_hash_watch(table_id);
we = xzalloc(sizeof(*we));
we->table_id = table_id;
we->stale = false;
VLOG_DBG("registering new route table watcher for table %d",
table_id);
we->nln = nln_create( NETLINK_ROUTE, route_table_parse, &rtmsg);

we->route_notifier =
nln_notifier_create(we->nln, RTNLGRP_IPV4_ROUTE,
(nln_notify_func *) route_table_change, NULL);
we->route6_notifier =
nln_notifier_create(we->nln, RTNLGRP_IPV6_ROUTE,
(nln_notify_func *) route_table_change, NULL);
hmap_insert(&watches, &we->node, hash);
}

static void
remove_watch_entry(struct route_table_watch_entry *we)
{
hmap_remove(&watches, &we->node);
nln_notifier_destroy(we->route_notifier);
nln_notifier_destroy(we->route6_notifier);
nln_destroy(we->nln);
free(we);
}

bool
route_table_notify_run(void)
{
any_route_table_changed = false;

struct route_table_watch_entry *we;
HMAP_FOR_EACH (we, node, &watches) {
nln_run(we->nln);
}

return any_route_table_changed;
}

void
route_table_notify_wait(void)
{
struct route_table_watch_entry *we;
HMAP_FOR_EACH (we, node, &watches) {
nln_wait(we->nln);
}
}

void
route_table_notify_update_watches(struct hmap *route_table_watches)
{
struct route_table_watch_entry *we;
HMAP_FOR_EACH (we, node, &watches) {
we->stale = true;
}

struct route_table_watch_request *wr;
HMAP_FOR_EACH_SAFE (wr, node, route_table_watches) {
we = find_watch_entry(wr->table_id);
if (we) {
we->stale = false;
} else {
add_watch_entry(wr->table_id);
}
hmap_remove(route_table_watches, &wr->node);
free(wr);
}

HMAP_FOR_EACH_SAFE (we, node, &watches) {
if (we->stale) {
remove_watch_entry(we);
}
}

}
Loading

0 comments on commit ac35ba5

Please sign in to comment.