On 2/11/25 9:35 AM, Felix Huettner via dev wrote:
> in order to exchange routes between OVN and the network fabric we
> use the new Advertised_Route sb table. Northd here advertises all routes
> where the user explicitly opted-in.
>
> ovn-controller will later use this table to share these routes to the
> outside.
>
> Acked-by: Dumitru Ceara <[email protected]>
> Signed-off-by: Felix Huettner <[email protected]>
> ---
Hi Felix,
I applied this patch to main with the following minor style changes:
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index 053a8fb607..72e6e23030 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -1389,4 +1389,3 @@ lport_lookup_by_name(struct ovsdb_idl_index
*sbrec_port_binding_by_name,
return retval;
}
-
diff --git a/northd/en-advertised-route-sync.c
b/northd/en-advertised-route-sync.c
index 3c50651541..a9d16d9ba8 100644
--- a/northd/en-advertised-route-sync.c
+++ b/northd/en-advertised-route-sync.c
@@ -30,9 +30,9 @@ advertised_route_table_sync(
const struct sbrec_advertised_route_table *sbrec_advertised_route_table,
const struct hmap *parsed_routes);
-void
-*en_advertised_route_sync_init(struct engine_node *node OVS_UNUSED,
- struct engine_arg *arg OVS_UNUSED)
+void *
+en_advertised_route_sync_init(struct engine_node *node OVS_UNUSED,
+ struct engine_arg *arg OVS_UNUSED)
{
return NULL;
}
@@ -99,17 +99,16 @@ ar_find(struct hmap *route_map, const struct
sbrec_datapath_binding *sb_db,
hash = uuid_hash(&sb_db->header_.uuid);
hash = hash_string(logical_port->logical_port, hash);
hash = hash_string(ip_prefix, hash);
+
HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) {
if (!uuid_equals(&sb_db->header_.uuid,
&route_e->sb_db->header_.uuid)) {
continue;
}
-
if (!uuid_equals(&logical_port->header_.uuid,
&route_e->logical_port->header_.uuid)) {
continue;
}
-
if (strcmp(ip_prefix, route_e->ip_prefix)) {
continue;
}
diff --git a/northd/northd.h b/northd/northd.h
index 9aa0934faf..46e1583b92 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -371,7 +371,7 @@ struct ovn_datapath {
...skipping...
-
diff --git a/northd/en-advertised-route-sync.c
b/northd/en-advertised-route-sync.c
index 3c50651541..a9d16d9ba8 100644
--- a/northd/en-advertised-route-sync.c
+++ b/northd/en-advertised-route-sync.c
@@ -30,9 +30,9 @@ advertised_route_table_sync(
const struct sbrec_advertised_route_table *sbrec_advertised_route_table,
const struct hmap *parsed_routes);
-void
-*en_advertised_route_sync_init(struct engine_node *node OVS_UNUSED,
- struct engine_arg *arg OVS_UNUSED)
+void *
+en_advertised_route_sync_init(struct engine_node *node OVS_UNUSED,
+ struct engine_arg *arg OVS_UNUSED)
{
return NULL;
}
@@ -99,17 +99,16 @@ ar_find(struct hmap *route_map, const struct
sbrec_datapath_binding *sb_db,
hash = uuid_hash(&sb_db->header_.uuid);
hash = hash_string(logical_port->logical_port, hash);
hash = hash_string(ip_prefix, hash);
+
HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) {
if (!uuid_equals(&sb_db->header_.uuid,
&route_e->sb_db->header_.uuid)) {
continue;
}
-
if (!uuid_equals(&logical_port->header_.uuid,
&route_e->logical_port->header_.uuid)) {
continue;
}
-
if (strcmp(ip_prefix, route_e->ip_prefix)) {
continue;
}
diff --git a/northd/northd.h b/northd/northd.h
index 9aa0934faf..46e1583b92 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -371,7 +371,7 @@ struct ovn_datapath {
/* router datapath has a logical port with redirect-type set to bridged. */
bool redirect_bridged;
- /* nbr has the option "dynamic-routing" set to true. */
+ /* router datapath has the option "dynamic-routing" set to true. */
bool dynamic_routing;
struct ovn_port **localnet_ports;
--
Regards,
Dumitru
> v7->v8:
> * addressed review comments
> v6->v7:
> * addressed review comments
> v5->v6:
> * addressed review comments
> v4->v5: skipped
> v3->v4:
> * fix use after free
> v2->v3:
> * A lot of minor review comments.
> * Sync logic reworked to no longer need a "stale" field.
> * Stop watching Advertised_Route table for changes.
>
> NEWS | 4 +
> ic/ovn-ic.c | 21 ----
> lib/ovn-util.c | 22 ++++
> lib/ovn-util.h | 2 +
> lib/stopwatch-names.h | 1 +
> northd/automake.mk | 2 +
> northd/en-advertised-route-sync.c | 181 ++++++++++++++++++++++++++++++
> northd/en-advertised-route-sync.h | 28 +++++
> northd/en-northd-output.c | 8 ++
> northd/en-northd-output.h | 2 +
> northd/inc-proc-northd.c | 11 +-
> northd/northd.c | 29 +++--
> northd/northd.h | 6 +-
> northd/ovn-northd.c | 5 +
> ovn-nb.xml | 19 ++++
> tests/ovn-northd.at | 137 ++++++++++++++++++++++
> 16 files changed, 443 insertions(+), 35 deletions(-)
> create mode 100644 northd/en-advertised-route-sync.c
> create mode 100644 northd/en-advertised-route-sync.h
>
> diff --git a/NEWS b/NEWS
> index df0085077..8c1c5c863 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -54,6 +54,10 @@ Post v24.09.0
> encapsulation type in OVN-interconnect mode.
> - Added vxlan_mode parameter in IC_NB_GLOBAL option column to enable or
> disable VXLAN encapsulation type in OVN-interconnect mode.
> + - Dynamic Routing:
> + * Add the option "dynamic-routing" to Logical Routers. If set to true
> all
> + static and connected routes attached to the router are shared to the
> + southbound "Advertised_Route" table for sharing outside of OVN.
>
> OVN v24.09.0 - 13 Sep 2024
> --------------------------
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index 6b6c6a2a1..ea68b1c12 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -1069,27 +1069,6 @@ get_nexthop_from_lport_addresses(bool is_v4,
> return true;
> }
>
> -static bool
> -prefix_is_link_local(struct in6_addr *prefix, unsigned int plen)
> -{
> - if (IN6_IS_ADDR_V4MAPPED(prefix)) {
> - /* Link local range is "169.254.0.0/16". */
> - if (plen < 16) {
> - return false;
> - }
> - ovs_be32 lla;
> - inet_pton(AF_INET, "169.254.0.0", &lla);
> - return ((in6_addr_get_mapped_ipv4(prefix) & htonl(0xffff0000)) ==
> lla);
> - }
> -
> - /* ipv6, link local range is "fe80::/10". */
> - if (plen < 10) {
> - return false;
> - }
> - return (((prefix->s6_addr[0] & 0xff) == 0xfe) &&
> - ((prefix->s6_addr[1] & 0xc0) == 0x80));
> -}
> -
> static bool
> prefix_is_deny_listed(const struct smap *nb_options,
> struct in6_addr *prefix,
> diff --git a/lib/ovn-util.c b/lib/ovn-util.c
> index 949078eee..053a8fb60 100644
> --- a/lib/ovn-util.c
> +++ b/lib/ovn-util.c
> @@ -1353,6 +1353,27 @@ ovn_update_swconn_at(struct rconn *swconn, const char
> *target,
> return notify;
> }
>
> +bool
> +prefix_is_link_local(const struct in6_addr *prefix, unsigned int plen)
> +{
> + if (IN6_IS_ADDR_V4MAPPED(prefix)) {
> + /* Link local range is "169.254.0.0/16". */
> + if (plen < 16) {
> + return false;
> + }
> + ovs_be32 lla;
> + inet_pton(AF_INET, "169.254.0.0", &lla);
> + return ((in6_addr_get_mapped_ipv4(prefix) & htonl(0xffff0000)) ==
> lla);
> + }
> +
> + /* ipv6, link local range is "fe80::/10". */
> + if (plen < 10) {
> + return false;
> + }
> + return (((prefix->s6_addr[0] & 0xff) == 0xfe) &&
> + ((prefix->s6_addr[1] & 0xc0) == 0x80));
> +}
> +
> const struct sbrec_port_binding *
> lport_lookup_by_name(struct ovsdb_idl_index *sbrec_port_binding_by_name,
> const char *name)
> @@ -1368,3 +1389,4 @@ lport_lookup_by_name(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
>
> return retval;
> }
> +
> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
> index dabe72254..b4391180f 100644
> --- a/lib/ovn-util.h
> +++ b/lib/ovn-util.h
> @@ -489,6 +489,8 @@ void ovn_exit_args_finish(struct ovn_exit_args
> *exit_args);
> bool ovn_update_swconn_at(struct rconn *swconn, const char *target,
> int probe_interval, const char *where);
>
> +bool prefix_is_link_local(const struct in6_addr *prefix, unsigned int plen);
> +
> const struct sbrec_port_binding *lport_lookup_by_name(
> struct ovsdb_idl_index *sbrec_port_binding_by_name,
> const char *name);
> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h
> index 660c653fb..dc4129ee5 100644
> --- a/lib/stopwatch-names.h
> +++ b/lib/stopwatch-names.h
> @@ -34,5 +34,6 @@
> #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run"
> #define LR_STATEFUL_RUN_STOPWATCH_NAME "lr_stateful"
> #define LS_STATEFUL_RUN_STOPWATCH_NAME "ls_stateful"
> +#define ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME "advertised_route_sync"
>
> #endif
> diff --git a/northd/automake.mk b/northd/automake.mk
> index 5715a867d..4d66776a8 100644
> --- a/northd/automake.mk
> +++ b/northd/automake.mk
> @@ -40,6 +40,8 @@ northd_ovn_northd_SOURCES = \
> northd/en-sampling-app.h \
> northd/en-acl-ids.c \
> northd/en-acl-ids.h \
> + northd/en-advertised-route-sync.c \
> + northd/en-advertised-route-sync.h \
> northd/inc-proc-northd.c \
> northd/inc-proc-northd.h \
> northd/ipam.c \
> diff --git a/northd/en-advertised-route-sync.c
> b/northd/en-advertised-route-sync.c
> new file mode 100644
> index 000000000..3c5065154
> --- /dev/null
> +++ b/northd/en-advertised-route-sync.c
> @@ -0,0 +1,181 @@
> +/*
> + * Copyright (c) 2025, STACKIT GmbH & Co. KG
> + *
> + * 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 "stopwatch.h"
> +#include "northd.h"
> +
> +#include "en-advertised-route-sync.h"
> +#include "lib/stopwatch-names.h"
> +#include "openvswitch/hmap.h"
> +#include "ovn-util.h"
> +
> +static void
> +advertised_route_table_sync(
> + struct ovsdb_idl_txn *ovnsb_txn,
> + const struct sbrec_advertised_route_table *sbrec_advertised_route_table,
> + const struct hmap *parsed_routes);
> +
> +void
> +*en_advertised_route_sync_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + return NULL;
> +}
> +
> +void
> +en_advertised_route_sync_cleanup(void *data OVS_UNUSED)
> +{
> +}
> +
> +void
> +en_advertised_route_sync_run(struct engine_node *node, void *data OVS_UNUSED)
> +{
> + struct routes_data *routes_data
> + = engine_get_input_data("routes", node);
> + const struct engine_context *eng_ctx = engine_get_context();
> + const struct sbrec_advertised_route_table *sbrec_advertised_route_table =
> + EN_OVSDB_GET(engine_get_input("SB_advertised_route", node));
> +
> + stopwatch_start(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME, time_msec());
> +
> + advertised_route_table_sync(eng_ctx->ovnsb_idl_txn,
> + sbrec_advertised_route_table,
> + &routes_data->parsed_routes);
> +
> + stopwatch_stop(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME, time_msec());
> + engine_set_node_state(node, EN_UPDATED);
> +}
> +
> +struct ar_entry {
> + struct hmap_node hmap_node;
> +
> + const struct sbrec_datapath_binding *sb_db;
> +
> + const struct sbrec_port_binding *logical_port;
> + char *ip_prefix;
> +};
> +
> +/* Add a new entries to the to-be-advertised routes.
> + * Takes ownership of ip_prefix. */
> +static struct ar_entry *
> +ar_add_entry(struct hmap *routes, const struct sbrec_datapath_binding *sb_db,
> + const struct sbrec_port_binding *logical_port, char *ip_prefix)
> +{
> + struct ar_entry *route_e = xzalloc(sizeof *route_e);
> +
> + route_e->sb_db = sb_db;
> + route_e->logical_port = logical_port;
> + route_e->ip_prefix = ip_prefix;
> + uint32_t hash = uuid_hash(&sb_db->header_.uuid);
> + hash = hash_string(logical_port->logical_port, hash);
> + hash = hash_string(ip_prefix, hash);
> + hmap_insert(routes, &route_e->hmap_node, hash);
> +
> + return route_e;
> +}
> +
> +static struct ar_entry *
> +ar_find(struct hmap *route_map, const struct sbrec_datapath_binding *sb_db,
> + const struct sbrec_port_binding *logical_port, const char *ip_prefix)
> +{
> + struct ar_entry *route_e;
> + uint32_t hash;
> +
> + hash = uuid_hash(&sb_db->header_.uuid);
> + hash = hash_string(logical_port->logical_port, hash);
> + hash = hash_string(ip_prefix, hash);
> + HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) {
> + if (!uuid_equals(&sb_db->header_.uuid,
> + &route_e->sb_db->header_.uuid)) {
> + continue;
> + }
> +
> + if (!uuid_equals(&logical_port->header_.uuid,
> + &route_e->logical_port->header_.uuid)) {
> + continue;
> + }
> +
> + if (strcmp(ip_prefix, route_e->ip_prefix)) {
> + continue;
> + }
> +
> + return route_e;
> + }
> +
> + return NULL;
> +}
> +
> +static void
> +ar_entry_free(struct ar_entry *route_e)
> +{
> + free(route_e->ip_prefix);
> + free(route_e);
> +}
> +
> +static void
> +advertised_route_table_sync(
> + struct ovsdb_idl_txn *ovnsb_txn,
> + const struct sbrec_advertised_route_table *sbrec_advertised_route_table,
> + const struct hmap *parsed_routes)
> +{
> + struct hmap sync_routes = HMAP_INITIALIZER(&sync_routes);
> + const struct parsed_route *route;
> +
> + struct ar_entry *route_e;
> + const struct sbrec_advertised_route *sb_route;
> + HMAP_FOR_EACH (route, key_node, parsed_routes) {
> + if (route->is_discard_route) {
> + continue;
> + }
> + if (prefix_is_link_local(&route->prefix, route->plen)) {
> + continue;
> + }
> + if (!route->od->dynamic_routing) {
> + continue;
> + }
> +
> + char *ip_prefix = normalize_v46_prefix(&route->prefix, route->plen);
> + route_e = ar_add_entry(&sync_routes, route->od->sb,
> + route->out_port->sb, ip_prefix);
> + }
> +
> + SBREC_ADVERTISED_ROUTE_TABLE_FOR_EACH_SAFE (sb_route,
> +
> sbrec_advertised_route_table) {
> + route_e = ar_find(&sync_routes, sb_route->datapath,
> + sb_route->logical_port,
> + sb_route->ip_prefix);
> + if (route_e) {
> + hmap_remove(&sync_routes, &route_e->hmap_node);
> + ar_entry_free(route_e);
> + } else {
> + sbrec_advertised_route_delete(sb_route);
> + }
> + }
> +
> + HMAP_FOR_EACH_POP (route_e, hmap_node, &sync_routes) {
> + const struct sbrec_advertised_route *sr =
> + sbrec_advertised_route_insert(ovnsb_txn);
> + sbrec_advertised_route_set_datapath(sr, route_e->sb_db);
> + sbrec_advertised_route_set_logical_port(sr, route_e->logical_port);
> + sbrec_advertised_route_set_ip_prefix(sr, route_e->ip_prefix);
> + ar_entry_free(route_e);
> + }
> +
> + hmap_destroy(&sync_routes);
> +}
> +
> diff --git a/northd/en-advertised-route-sync.h
> b/northd/en-advertised-route-sync.h
> new file mode 100644
> index 000000000..30e7cae1f
> --- /dev/null
> +++ b/northd/en-advertised-route-sync.h
> @@ -0,0 +1,28 @@
> +/*
> + * Copyright (c) 2025, STACKIT GmbH & Co. KG
> + *
> + * 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.
> + */
> +#ifndef EN_ADVERTISED_ROUTE_SYNC_H
> +#define EN_ADVERTISED_ROUTE_SYNC_H 1
> +
> +#include "lib/inc-proc-eng.h"
> +
> +struct advertised_route_sync_data {
> +};
> +
> +void *en_advertised_route_sync_init(struct engine_node *, struct engine_arg
> *);
> +void en_advertised_route_sync_cleanup(void *data);
> +void en_advertised_route_sync_run(struct engine_node *, void *data);
> +
> +#endif /* EN_ADVERTISED_ROUTE_SYNC_H */
> diff --git a/northd/en-northd-output.c b/northd/en-northd-output.c
> index 1f34dae6c..e69a7eebb 100644
> --- a/northd/en-northd-output.c
> +++ b/northd/en-northd-output.c
> @@ -88,3 +88,11 @@ northd_output_acl_id_handler(struct engine_node *node,
> engine_set_node_state(node, EN_UPDATED);
> return true;
> }
> +
> +bool
> +northd_output_advertised_route_sync_handler(struct engine_node *node,
> + void *data OVS_UNUSED)
> +{
> + engine_set_node_state(node, EN_UPDATED);
> + return true;
> +}
> diff --git a/northd/en-northd-output.h b/northd/en-northd-output.h
> index 6d6b54fb0..783587cb6 100644
> --- a/northd/en-northd-output.h
> +++ b/northd/en-northd-output.h
> @@ -21,5 +21,7 @@ bool northd_output_ecmp_nexthop_handler(struct engine_node
> *node,
> void *data OVS_UNUSED);
> bool northd_output_acl_id_handler(struct engine_node *node,
> void *data OVS_UNUSED);
> +bool northd_output_advertised_route_sync_handler(struct engine_node *node,
> + void *data OVS_UNUSED);
>
> #endif
> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> index 9232eb6c6..f872312a6 100644
> --- a/northd/inc-proc-northd.c
> +++ b/northd/inc-proc-northd.c
> @@ -44,6 +44,7 @@
> #include "en-sync-from-sb.h"
> #include "en-ecmp-nexthop.h"
> #include "en-acl-ids.h"
> +#include "en-advertised-route-sync.h"
> #include "unixctl.h"
> #include "util.h"
>
> @@ -107,7 +108,8 @@ static unixctl_cb_func chassis_features_list;
> SB_NODE(chassis_template_var, "chassis_template_var") \
> SB_NODE(logical_dp_group, "logical_dp_group") \
> SB_NODE(ecmp_nexthop, "ecmp_nexthop") \
> - SB_NODE(acl_id, "acl_id")
> + SB_NODE(acl_id, "acl_id") \
> + SB_NODE(advertised_route, "advertised_route")
>
> enum sb_engine_node {
> #define SB_NODE(NAME, NAME_STR) SB_##NAME,
> @@ -169,6 +171,7 @@ static ENGINE_NODE(bfd_sync, "bfd_sync");
> static ENGINE_NODE(ecmp_nexthop, "ecmp_nexthop");
> static ENGINE_NODE(multicast_igmp, "multicast_igmp");
> static ENGINE_NODE(acl_id, "acl_id");
> +static ENGINE_NODE(advertised_route_sync, "advertised_route_sync");
>
> void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> struct ovsdb_idl_loop *sb)
> @@ -283,6 +286,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> engine_add_input(&en_ecmp_nexthop, &en_sb_mac_binding,
> ecmp_nexthop_mac_binding_handler);
>
> + engine_add_input(&en_advertised_route_sync, &en_routes, NULL);
> + engine_add_input(&en_advertised_route_sync, &en_sb_advertised_route,
> + NULL);
> +
> engine_add_input(&en_sync_meters, &en_nb_acl, NULL);
> engine_add_input(&en_sync_meters, &en_nb_meter, NULL);
> engine_add_input(&en_sync_meters, &en_sb_meter, NULL);
> @@ -376,6 +383,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> northd_output_ecmp_nexthop_handler);
> engine_add_input(&en_northd_output, &en_acl_id,
> northd_output_acl_id_handler);
> + engine_add_input(&en_northd_output, &en_advertised_route_sync,
> + northd_output_advertised_route_sync_handler);
>
> struct engine_arg engine_arg = {
> .nb_idl = nb->idl,
> diff --git a/northd/northd.c b/northd/northd.c
> index 7e2e6881a..261a02e17 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -910,6 +910,8 @@ join_datapaths(const struct nbrec_logical_switch_table
> *nbrec_ls_table,
> if (smap_get(&od->nbr->options, "chassis")) {
> od->is_gw_router = true;
> }
> + od->dynamic_routing = smap_get_bool(&od->nbr->options,
> + "dynamic-routing", false);
> ovs_list_push_back(lr_list, &od->lr_list);
> }
> }
> @@ -10867,7 +10869,8 @@ route_hash(struct parsed_route *route)
> }
>
> static bool
> -find_static_route_outport(struct ovn_datapath *od, const struct hmap
> *lr_ports,
> +find_static_route_outport(const struct ovn_datapath *od,
> + const struct hmap *lr_ports,
> const struct nbrec_logical_router_static_route *route, bool is_ipv4,
> const char **p_lrp_addr_s, struct ovn_port **p_out_port);
>
> @@ -10969,7 +10972,7 @@ parsed_route_add(const struct ovn_datapath *od,
> 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->od = od;
> new_pr->ecmp_symmetric_reply = ecmp_symmetric_reply;
> new_pr->is_discard_route = is_discard_route;
> if (!is_discard_route) {
> @@ -10995,11 +10998,12 @@ parsed_route_add(const struct ovn_datapath *od,
> }
>
> 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)
> +parsed_routes_add_static(const 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 = NULL;
> @@ -11121,7 +11125,8 @@ parsed_routes_add_static(struct ovn_datapath *od,
> const struct hmap *lr_ports,
> }
>
> static void
> -parsed_routes_add_connected(struct ovn_datapath *od, const struct ovn_port
> *op,
> +parsed_routes_add_connected(const struct ovn_datapath *od,
> + const struct ovn_port *op,
> struct hmap *routes)
> {
> for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
> @@ -11150,14 +11155,14 @@ parsed_routes_add_connected(struct ovn_datapath
> *od, const struct ovn_port *op,
> }
>
> void
> -build_parsed_routes(struct ovn_datapath *od, const struct hmap *lr_ports,
> +build_parsed_routes(const struct ovn_datapath *od, const struct hmap
> *lr_ports,
> const struct hmap *bfd_connections, struct hmap *routes,
> struct simap *route_tables,
> struct hmap *bfd_active_connections)
> {
> struct parsed_route *pr;
> HMAP_FOR_EACH (pr, key_node, routes) {
> - if (pr->nbr == od->nbr) {
> + if (pr->od == od) {
> pr->stale = true;
> }
> }
> @@ -11381,13 +11386,15 @@ build_route_match(const struct ovn_port *op_inport,
> uint32_t rtb_id,
>
> /* Output: p_lrp_addr_s and p_out_port. */
> static bool
> -find_static_route_outport(struct ovn_datapath *od, const struct hmap
> *lr_ports,
> +find_static_route_outport(const struct ovn_datapath *od,
> + const struct hmap *lr_ports,
> const struct nbrec_logical_router_static_route *route, bool is_ipv4,
> const char **p_lrp_addr_s, struct ovn_port **p_out_port)
> {
> const char *lrp_addr_s = NULL;
> struct ovn_port *out_port = NULL;
> if (route->output_port) {
> + /* XXX: we should be able to use &od->ports instead of lr_ports. */
> out_port = ovn_port_find(lr_ports, route->output_port);
> if (!out_port) {
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> diff --git a/northd/northd.h b/northd/northd.h
> index 5fca3526b..9aa0934fa 100644
> --- a/northd/northd.h
> +++ b/northd/northd.h
> @@ -371,6 +371,8 @@ struct ovn_datapath {
>
> /* router datapath has a logical port with redirect-type set to bridged.
> */
> bool redirect_bridged;
> + /* nbr has the option "dynamic-routing" set to true. */
> + bool dynamic_routing;
>
> struct ovn_port **localnet_ports;
> size_t n_localnet_ports;
> @@ -720,7 +722,7 @@ struct parsed_route {
> const struct nbrec_logical_router_static_route *route;
> bool ecmp_symmetric_reply;
> bool is_discard_route;
> - const struct nbrec_logical_router *nbr;
> + const struct ovn_datapath *od;
> bool stale;
> struct sset ecmp_selection_fields;
> enum route_source source;
> @@ -751,7 +753,7 @@ void northd_indices_create(struct northd_data *data,
>
> void route_policies_init(struct route_policies_data *);
> void route_policies_destroy(struct route_policies_data *);
> -void build_parsed_routes(struct ovn_datapath *, const struct hmap *,
> +void build_parsed_routes(const struct ovn_datapath *, const struct hmap *,
> const struct hmap *, struct hmap *, struct simap *,
> struct hmap *);
> uint32_t get_route_table_id(struct simap *, const char *);
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 40b3e3a7f..0883d5de7 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -949,6 +949,10 @@ main(int argc, char *argv[])
> ovsdb_idl_omit_alert(ovnsb_idl_loop.idl,
> &sbrec_acl_id_columns[i]);
> }
> + for (size_t i = 0; i < SBREC_ADVERTISED_ROUTE_N_COLUMNS; i++) {
> + ovsdb_idl_omit_alert(ovnsb_idl_loop.idl,
> + &sbrec_advertised_route_columns[i]);
> + }
>
> unixctl_command_register("sb-connection-status", "", 0, 0,
> ovn_conn_show, ovnsb_idl_loop.idl);
> @@ -976,6 +980,7 @@ main(int argc, char *argv[])
> stopwatch_create(LR_NAT_RUN_STOPWATCH_NAME, SW_MS);
> stopwatch_create(LR_STATEFUL_RUN_STOPWATCH_NAME, SW_MS);
> stopwatch_create(LS_STATEFUL_RUN_STOPWATCH_NAME, SW_MS);
> + stopwatch_create(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME, SW_MS);
>
> /* Initialize incremental processing engine for ovn-northd */
> inc_proc_northd_init(&ovnnb_idl_loop, &ovnsb_idl_loop);
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 864307314..2a178ab06 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -3023,6 +3023,25 @@ or
> option is not present the limit is not set and the zone limit is
> derived from OvS default datapath limit.
> </column>
> +
> + <column name="options" key="dynamic-routing" type='{"type":
> "boolean"}'>
> + If set to <code>true</code> then this <ref table="Logical_Router"/>
> + can participate in dynamic routing with components outside of OVN.
> +
> + It will synchronize all routes to the soutbound
> + <ref table="Advertised_Route" db="OVN_SB"/> table that are relevant
> + for the router. This includes:
> + <ul>
> + <li>
> + all "connected" routes implicitly created by networks
> + associated with this Logical Router
> + </li>
> + <li>
> + all <ref table="Logical_Router_Static_Route"/> that are
> + applied to this Logical Router
> + </li>
> + </ul>
> + </column>
> </group>
>
> <group title="Common Columns">
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 352339296..850c6aeb7 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -14917,3 +14917,140 @@ AT_CHECK([ovn-sbctl lflow-list sw | grep
> ls_out_acl_eval | grep priority=2002 |
>
> AT_CLEANUP
> ])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([dynamic-routing - sync to sb])
> +AT_KEYWORDS([dynamic-routing])
> +ovn_start
> +
> +# Adding a router - no route advertised.
> +check ovn-nbctl lr-add lr0
> +check ovn-nbctl --wait=sb set Logical_Router lr0 option:dynamic-routing=true
> +check_row_count Advertised_Route 0
> +datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr0)
> +
> +# Adding a LRP adds a route entry for the associated network.
> +check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
> +pb=$(fetch_column port_binding _uuid logical_port=lr0-sw0)
> +check_row_count Advertised_Route 1
> +check_column 10.0.0.0/24 Advertised_Route ip_prefix datapath=$datapath
> logical_port=$pb
> +
> +# Adding a second LRP adds an additional route entry.
> +check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 10.0.1.1/24
> +pb2=$(fetch_column port_binding _uuid logical_port=lr0-sw1)
> +check_row_count Advertised_Route 2
> +check_column 10.0.0.0/24 Advertised_Route ip_prefix datapath=$datapath
> logical_port=$pb
> +check_column 10.0.1.0/24 Advertised_Route ip_prefix datapath=$datapath
> logical_port=$pb2
> +
> +# Adding a static route adds an additional entry.
> +check ovn-nbctl --wait=sb lr-route-add lr0 192.168.0.0/24 10.0.0.10
> +check_row_count Advertised_Route 3
> +check_row_count Advertised_Route 2 logical_port=$pb
> +check_row_count Advertised_Route 1 logical_port=$pb ip_prefix=192.168.0.0/24
> +
> +# Adding an ipv6 LRP adds an addition route entry.
> +check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw2 00:00:00:00:ff:03
> 2001:db8::1/64 fe80::1/64
> +pb3=$(fetch_column port_binding _uuid logical_port=lr0-sw2)
> +check_row_count Advertised_Route 4
> +check_row_count Advertised_Route 2 logical_port=$pb
> +check_row_count Advertised_Route 1 logical_port=$pb ip_prefix=192.168.0.0/24
> +check_column 10.0.1.0/24 Advertised_Route ip_prefix datapath=$datapath
> logical_port=$pb2
> +check_column 2001:db8::/64 Advertised_Route ip_prefix datapath=$datapath
> logical_port=$pb3
> +
> +# Removing the option:dynamic-routing removes all routes.
> +check ovn-nbctl --wait=sb remove Logical_Router lr0 option dynamic-routing
> +check_row_count Advertised_Route 0
> +
> +# And setting it again adds them again.
> +check ovn-nbctl --wait=sb set Logical_Router lr0 option:dynamic-routing=true
> +check_row_count Advertised_Route 4
> +
> +# Removing the lrp used for the static route removes both route entries.
> +check ovn-nbctl --wait=sb lrp-del lr0-sw0
> +check_row_count Advertised_Route 2
> +check_row_count Advertised_Route 1 logical_port=$pb2
> +check_row_count Advertised_Route 1 logical_port=$pb3
> +
> +# Removing the lr will remove all routes.
> +check ovn-nbctl --wait=sb lr-del lr0
> +check_row_count Advertised_Route 0
> +
> +AT_CLEANUP
> +])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([dynamic-routing incremental processing])
> +AT_KEYWORDS([dynamic-routing])
> +ovn_start
> +
> +# Test I-P for dynamic-routing.
> +# Presently ovn-northd has no I-P for Advertised_Route.
> +# Wait for sb to be connected before clearing stats.
> +check ovn-nbctl --wait=sb sync
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl lr-add lr0
> +check ovn-nbctl --wait=sb set Logical_Router lr0 option:dynamic-routing=true
> +
> +check_engine_stats northd recompute nocompute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
> +check_engine_stats northd recompute compute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 10.0.1.1/24
> +check_engine_stats northd recompute compute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lr-route-add lr0 192.168.0.0/24 10.0.0.10
> +check_engine_stats northd recompute nocompute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw2 00:00:00:00:ff:03
> 2001:db8::1/64 fe80::1/64
> +check_engine_stats northd recompute compute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb remove Logical_Router lr0 option dynamic-routing
> +check_engine_stats northd recompute nocompute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb set Logical_Router lr0 option:dynamic-routing=true
> +check_engine_stats northd recompute nocompute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lrp-del lr0-sw0
> +check_engine_stats northd recompute compute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lr-del lr0
> +check_engine_stats northd recompute nocompute
> +check_engine_stats routes recompute nocompute
> +check_engine_stats advertised_route_sync recompute nocompute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +AT_CLEANUP
> +])
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev