> 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. > > Signed-off-by: Felix Huettner <[email protected]> > --- > 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.
Hi Felix, after addressing Dumitru's comments, feel free to add my Acked-by, Acked-by: Lorenzo Bianconi <[email protected]> > > 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 | 186 ++++++++++++++++++++++++++++++ > northd/en-advertised-route-sync.h | 29 +++++ > 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 | 13 +++ > 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 72c5a6339..4ff158014 100644 > --- a/NEWS > +++ b/NEWS > @@ -28,6 +28,10 @@ Post v24.09.0 > this option was not set). TLS ciphersuites for TLSv1.3 and later can > be configured via --ssl-ciphersuites (--ssl-ciphers only applies to > TLSv1.2 and earlier). > + - 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 "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 8320cbea5..948c17f9b 100644 > --- a/ic/ovn-ic.c > +++ b/ic/ovn-ic.c > @@ -1008,27 +1008,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 b78bdbfa1..ed847517a 100644 > --- a/lib/ovn-util.c > +++ b/lib/ovn-util.c > @@ -1351,3 +1351,25 @@ 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)); > +} > + > diff --git a/lib/ovn-util.h b/lib/ovn-util.h > index 899bd9d12..31c2c68df 100644 > --- a/lib/ovn-util.h > +++ b/lib/ovn-util.h > @@ -487,4 +487,6 @@ 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); > + > #endif /* OVN_UTIL_H */ > 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 6566ad299..a2797237a 100644 > --- a/northd/automake.mk > +++ b/northd/automake.mk > @@ -34,6 +34,8 @@ northd_ovn_northd_SOURCES = \ > northd/en-ls-stateful.h \ > northd/en-sampling-app.c \ > northd/en-sampling-app.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..6ddd15512 > --- /dev/null > +++ b/northd/en-advertised-route-sync.c > @@ -0,0 +1,186 @@ > +/* > + * Copyright (c) 2024, 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; > +}; > + > +static struct ar_entry * > +ar_alloc_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 (!smap_get_bool(&route->od->nbr->options, "dynamic-routing", > + false)) { > + continue; > + } > + > + char *ip_prefix = normalize_v46_prefix(&route->prefix, > + route->plen); > + route_e = ar_alloc_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..bd27ecefa > --- /dev/null > +++ b/northd/en-advertised-route-sync.h > @@ -0,0 +1,29 @@ > +/* > + * Copyright (c) 2024, 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 98098d974..555ed2b9e 100644 > --- a/northd/en-northd-output.c > +++ b/northd/en-northd-output.c > @@ -72,3 +72,11 @@ northd_output_fdb_aging_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 5f577b89c..00391ace3 100644 > --- a/northd/en-northd-output.h > +++ b/northd/en-northd-output.h > @@ -17,5 +17,7 @@ bool northd_output_mac_binding_aging_handler(struct > engine_node *node, > void *data OVS_UNUSED); > bool northd_output_fdb_aging_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 6e0aa04c4..12956a5de 100644 > --- a/northd/inc-proc-northd.c > +++ b/northd/inc-proc-northd.c > @@ -41,6 +41,7 @@ > #include "en-sampling-app.h" > #include "en-sync-sb.h" > #include "en-sync-from-sb.h" > +#include "en-advertised-route-sync.h" > #include "unixctl.h" > #include "util.h" > > @@ -102,7 +103,8 @@ static unixctl_cb_func chassis_features_list; > SB_NODE(fdb, "fdb") \ > SB_NODE(static_mac_binding, "static_mac_binding") \ > SB_NODE(chassis_template_var, "chassis_template_var") \ > - SB_NODE(logical_dp_group, "logical_dp_group") > + SB_NODE(logical_dp_group, "logical_dp_group") \ > + SB_NODE(advertised_route, "advertised_route") > > enum sb_engine_node { > #define SB_NODE(NAME, NAME_STR) SB_##NAME, > @@ -161,6 +163,7 @@ static ENGINE_NODE(route_policies, "route_policies"); > static ENGINE_NODE(routes, "routes"); > static ENGINE_NODE(bfd, "bfd"); > static ENGINE_NODE(bfd_sync, "bfd_sync"); > +static ENGINE_NODE(advertised_route_sync, "advertised_route_sync"); > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb) > @@ -263,6 +266,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_bfd_sync, &en_route_policies, NULL); > engine_add_input(&en_bfd_sync, &en_northd, > bfd_sync_northd_change_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); > @@ -344,6 +351,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > northd_output_mac_binding_aging_handler); > engine_add_input(&en_northd_output, &en_fdb_aging, > northd_output_fdb_aging_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 74014de32..1c32ef8f8 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -912,6 +912,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); > } > } > @@ -11127,7 +11129,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); > > @@ -11229,7 +11232,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) { > @@ -11255,11 +11258,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; > @@ -11381,7 +11385,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++) { > @@ -11410,14 +11415,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; > } > } > @@ -11641,13 +11646,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 9457a7be6..98a17d733 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -367,6 +367,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; > @@ -714,7 +716,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; > @@ -745,7 +747,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 aa4c57663..17d6145be 100644 > --- a/northd/ovn-northd.c > +++ b/northd/ovn-northd.c > @@ -941,6 +941,10 @@ main(int argc, char *argv[]) > ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, > &sbrec_logical_dp_group_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); > @@ -968,6 +972,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 24ef12f3b..718d0126e 100644 > --- a/ovn-nb.xml > +++ b/ovn-nb.xml > @@ -2946,6 +2946,19 @@ 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="Route" db="OVN_SB"/> table that are relevant for the > + router. This includes: > + * all "connected" routes implicitly created by networks associated > with > + this Logical Router > + * all <ref table="Logical_Router_Static_Route"/> that are applied to > + this Logical Router > + </column> > </group> > > <group title="Common Columns"> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index edfd5764b..30ea23502 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -14419,3 +14419,140 @@ AT_CHECK([ovn-sbctl lflow-list S1 | grep > ls_out_acl_action | grep priority=500 | > > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD_NO_HV([ > +AT_SETUP([dynamic-routing - sync to sb]) > +AT_KEYWORDS([dynamic-routing]) > +ovn_start > + > +# adding a router - still nothing here > +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(1) > + > +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 > +]) > -- > 2.47.1 > > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
_______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
