Up until now all advertised routes wouldn't have a nexthop and would be installed purely as blackhole. Add the "dynamic-routing-v4-prefix-nexthop" and "dynamic-routing-v6-prefix-nexthop" option. That allows to define the nexthop for IPv4 and IPv6 advertised routes on given Logical Router. This option also allows to install IPv4 routes with IPv6 nexthop.
Reported-at: https://issues.redhat.com/browse/FDP-2735 Signed-off-by: Ales Musil <[email protected]> --- v2: Rebase on top of current main. Shorten the option name. --- NEWS | 4 + controller/ovn-controller.c | 36 +++++++ controller/route.c | 38 ++++++- controller/route.h | 3 + northd/en-datapath-logical-router.c | 12 +++ ovn-nb.xml | 28 ++++++ tests/ovn-inc-proc-graph-dump.at | 1 + tests/system-ovn.at | 149 ++++++++++++++++++++++++++++ 8 files changed, 267 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index a4c8557ee..be1c9a47c 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,10 @@ Post v25.09.0 EVPN domain. * Add the option "dynamic-routing-vrf-id" to Logical Routers which allows CMS to specify the Linux routing table id for a given vrf. + * Add the option "dynamic-routing-v4-prefix-nexthop" to Logical Routers + which allows CMS to specify nexthop for IPv4 Advertised routes. + * Add the option "dynamic-routing-v6-prefix-nexthop" to Logical Routers + which allows CMS to specify nexthop for IPv6 Advertised routes. - Add support for Network Function insertion in OVN with stateful traffic redirection capability in Logical Switch datapath. The feature introduces three new NB database tables: diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index d42172dce..c0e7b8d5f 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -5408,6 +5408,40 @@ route_sb_advertised_route_data_handler(struct engine_node *node, void *data) return EN_HANDLED_UNCHANGED; } +static enum engine_input_handler_result +route_sb_datapath_binding_handler(struct engine_node *node, + void *data OVS_UNUSED) +{ + const struct sbrec_datapath_binding_table *dp_table = + EN_OVSDB_GET(engine_get_input("SB_datapath_binding", node)); + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + const struct sbrec_datapath_binding *dp; + SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (dp, dp_table) { + if (sbrec_datapath_binding_is_new(dp) || + sbrec_datapath_binding_is_deleted(dp)) { + /* We are reflecting only datapaths that are becoming or are + * removed from being local, that is taken care of by runtime_data + * handler. */ + return EN_HANDLED_UNCHANGED; + } + + struct local_datapath *ld = + get_local_datapath(&rt_data->local_datapaths, dp->tunnel_key); + if (!ld || ld->is_switch) { + continue; + } + + if (sbrec_datapath_binding_is_updated( + dp, SBREC_DATAPATH_BINDING_COL_EXTERNAL_IDS)) { + return EN_UNHANDLED; + } + } + + return EN_HANDLED_UNCHANGED; +} + struct ed_type_route_exchange { /* We need the idl to check if the Learned_Route table exists. */ struct ovsdb_idl *sb_idl; @@ -6623,6 +6657,8 @@ inc_proc_ovn_controller_init( route_runtime_data_handler); engine_add_input(&en_route, &en_sb_advertised_route, route_sb_advertised_route_data_handler); + engine_add_input(&en_route, &en_sb_datapath_binding, + route_sb_datapath_binding_handler); engine_add_input(&en_route_exchange, &en_route, NULL); engine_add_input(&en_route_exchange, &en_sb_learned_route, diff --git a/controller/route.c b/controller/route.c index 082a4630d..213508ccb 100644 --- a/controller/route.c +++ b/controller/route.c @@ -164,6 +164,37 @@ advertise_datapath_find(const struct hmap *datapaths, return NULL; } +static struct advertise_datapath_entry * +advertised_datapath_alloc(const struct sbrec_datapath_binding *datapath) +{ + struct advertise_datapath_entry *ad = xmalloc(sizeof *ad); + *ad = (struct advertise_datapath_entry) { + .db = datapath, + .routes = HMAP_INITIALIZER(&ad->routes), + .bound_ports = SMAP_INITIALIZER(&ad->bound_ports), + }; + + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10); + + const char *nh4 = + smap_get(&datapath->external_ids, "dynamic-routing-v4-prefix-nexthop"); + if (nh4 && !ip46_parse(nh4, &ad->ipv4_nexthop)) { + memset(&ad->ipv4_nexthop, 0, sizeof ad->ipv4_nexthop); + VLOG_WARN_RL(&rl, "Couldn't parse IPv4 prefix nexthop %s, " + "routes will be installed as blackhole.", nh4); + } + + const char *nh6 = + smap_get(&datapath->external_ids, "dynamic-routing-v6-prefix-nexthop"); + if (nh6 && !ipv6_parse(nh6, &ad->ipv6_nexthop)) { + memset(&ad->ipv6_nexthop, 0, sizeof ad->ipv6_nexthop); + VLOG_WARN_RL(&rl, "Couldn't parse IPv6 prefix nexthop %s, " + "routes will be installed as blackhole.", nh6); + } + + return ad; +} + void route_run(struct route_ctx_in *r_ctx_in, struct route_ctx_out *r_ctx_out) @@ -199,10 +230,7 @@ route_run(struct route_ctx_in *r_ctx_in, } if (!ad) { - ad = xzalloc(sizeof(*ad)); - ad->db = ld->datapath; - hmap_init(&ad->routes); - smap_init(&ad->bound_ports); + ad = advertised_datapath_alloc(ld->datapath); } ad->maintain_vrf |= @@ -324,6 +352,8 @@ route_run(struct route_ctx_in *r_ctx_in, .addr = prefix, .plen = plen, .priority = priority, + .nexthop = IN6_IS_ADDR_V4MAPPED(&prefix) + ? ad->ipv4_nexthop : ad->ipv6_nexthop, }; hmap_insert(&ad->routes, &ar->node, advertise_route_hash(&ar->addr, &ar->nexthop, plen)); diff --git a/controller/route.h b/controller/route.h index cf84a3079..69e9bc276 100644 --- a/controller/route.h +++ b/controller/route.h @@ -65,6 +65,9 @@ struct advertise_datapath_entry { const struct sbrec_datapath_binding *db; bool maintain_vrf; char vrf_name[IFNAMSIZ + 1]; + struct in6_addr ipv4_nexthop; + struct in6_addr ipv6_nexthop; + struct hmap routes; /* The name of the port bindings locally bound for this datapath and diff --git a/northd/en-datapath-logical-router.c b/northd/en-datapath-logical-router.c index 56785ebfb..a4b5e2383 100644 --- a/northd/en-datapath-logical-router.c +++ b/northd/en-datapath-logical-router.c @@ -95,6 +95,18 @@ gather_external_ids(const struct nbrec_logical_router *nbr, vrf_id); } + const char *nh4 = + smap_get(&nbr->options, "dynamic-routing-v4-prefix-nexthop"); + if (nh4 && nh4[0]) { + smap_add(external_ids, "dynamic-routing-v4-prefix-nexthop", nh4); + } + + const char *nh6 = + smap_get(&nbr->options, "dynamic-routing-v6-prefix-nexthop"); + if (nh6 && nh6[0]) { + smap_add(external_ids, "dynamic-routing-v6-prefix-nexthop", nh6); + } + /* For backwards-compatibility, also store the NB UUID in * external-ids:logical-router. This is useful if ovn-controller * has not updated and expects this to be where to find the diff --git a/ovn-nb.xml b/ovn-nb.xml index b5fe44e53..177c7dd9c 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -3421,6 +3421,34 @@ or </p> </column> + <column name="options" key="dynamic-routing-v4-prefix-nexthop" + type='{"type": "string"}'> + <p> + Only relevant if <ref column="options" key="dynamic-routing"/> + is set to <code>true</code>. + </p> + + <p> + This defines nexthop used by IPv4 advertised routes instead of the + routes being advertised as blackhole. This can be either valid IPv4 + or IPv6 address. + </p> + </column> + + <column name="options" key="dynamic-routing-v6-prefix-nexthop" + type='{"type": "string"}'> + <p> + Only relevant if <ref column="options" key="dynamic-routing"/> + is set to <code>true</code>. + </p> + + <p> + This defines nexthop used by IPv6 advertised routes instead of the + routes being advertised as blackhole. This can be only valid IPv6 + address. + </p> + </column> + <column name="options" key="ct-commit-all" type='{"type": "boolean"}'> When enabled the LR will commit traffic in a zone that is stateful. The traffic is not commited to both zones but it is selective based diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ovn-inc-proc-graph-dump.at index 2d7780a13..eb00ccc7d 100644 --- a/tests/ovn-inc-proc-graph-dump.at +++ b/tests/ovn-inc-proc-graph-dump.at @@ -447,6 +447,7 @@ digraph "Incremental-Processing-Engine" { SB_port_binding -> route [[label="route_sb_port_binding_data_handler"]]; runtime_data -> route [[label="route_runtime_data_handler"]]; SB_advertised_route -> route [[label="route_sb_advertised_route_data_handler"]]; + SB_datapath_binding -> route [[label="route_sb_datapath_binding_handler"]]; SB_learned_route [[style=filled, shape=box, fillcolor=white, label="SB_learned_route"]]; route_table_notify [[style=filled, shape=box, fillcolor=white, label="route_table_notify"]]; route_exchange_status [[style=filled, shape=box, fillcolor=white, label="route_exchange_status"]]; diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 33aaa4cd7..f5afd4995 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -18831,3 +18831,152 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d AT_CLEANUP ]) ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([dynamic-routing - Advertised route nexthop]) +AT_KEYWORDS([dynamic-routing]) + +CHECK_VRF() +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() + +vrf=1002 +VRF_RESERVE([$vrf]) +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext], [set Bridge br-ext fail-mode=standalone]) + +# Set external-ids in br-int needed for ovn-controller. +check ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller. +start_daemon ovn-controller + +OVS_WAIT_WHILE([ip link | grep -q ovnvrf$vrf:.*UP]) + +check ovn-nbctl \ + -- lr-add R1 \ + -- set Logical_Router R1 \ + options:dynamic-routing-vrf-id=$vrf \ + options:dynamic-routing=true \ + -- ls-add sw0 \ + -- ls-add public \ + -- lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 \ + 2001:db8:100::1/64 \ + -- lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \ + 2001:db8:1003::1/64 \ + -- lrp-set-options rp-public \ + dynamic-routing-maintain-vrf=true \ + dynamic-routing-redistribute=connected-as-host,nat,lb \ + -- set logical_router R1 options:chassis=hv1 \ + -- lsp-add sw0 sw0-rp \ + -- set Logical_Switch_Port sw0-rp type=router \ + options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router \ + -- lsp-add public public-rp \ + -- set Logical_Switch_Port public-rp type=router \ + options:router-port=rp-public \ + -- lsp-set-addresses public-rp router \ + -- lsp-add-localnet-port public public1 phynet \ + -- lr-nat-add R1 dnat_and_snat 172.16.1.10 192.168.1.10 \ + -- lr-nat-add R1 dnat 172.16.1.11 192.168.1.11 \ + -- lr-nat-add R1 dnat_and_snat 2001:db8:1003::150 2001:db8:100::100 \ + -- lr-nat-add R1 dnat 2001:db8:1003::151 2001:db8:100::100 \ + -- lb-add lb1 172.16.1.20 192.168.1.10,192.168.1.20 \ + -- lb-add lb2 2001:db8:1003::20 2001:db8:100::10,2001:db8:100::20 \ + -- lr-lb-add R1 lb1 \ + -- lr-lb-add R1 lb2 + +OVN_POPULATE_ARP +check ovn-nbctl --wait=hv sync +wait_for_ports_up + +AT_CHECK([test `ip route show table $vrf | wc -l` -eq 2], [1]) +AT_CHECK([ip link | grep -q ovnvrf$vrf:.*UP]) + +check ip link add lo-test type dummy +on_exit 'ip link del lo-test' +check ip link set lo-test master ovnvrf$vrf +check ip link set lo-test address 00:00:00:00:00:10 +check ip addr add 20.0.0.10/24 dev lo-test +check ip addr add 2000:db8:1000::10/96 dev lo-test nodad +check ip link set up lo-test + +OVN_ROUTE_EQUAL([ovnvrf$vrf], [dnl +20.0.0.0/24 dev lo-test proto kernel scope link src 20.0.0.10 +blackhole 172.16.1.1 proto ovn metric 100 +blackhole 172.16.1.10 proto ovn metric 1000 +blackhole 172.16.1.11 proto ovn metric 1000 +blackhole 172.16.1.20 proto ovn metric 1000]) + +OVN_ROUTE_V6_EQUAL([ovnvrf$vrf], [dnl +2000:db8:1000::/96 dev lo-test proto kernel metric 256 pref medium +blackhole 2001:db8:1003::1 dev lo proto ovn metric 100 pref medium +blackhole 2001:db8:1003::20 dev lo proto ovn metric 1000 pref medium +blackhole 2001:db8:1003::150 dev lo proto ovn metric 1000 pref medium +blackhole 2001:db8:1003::151 dev lo proto ovn metric 1000 pref medium +fe80::/64 dev lo-test proto kernel metric 256 pref medium +multicast ff00::/8 dev lo-test proto kernel metric 256 pref medium]) + +check ovn-nbctl --wait=hv set logical_router R1 \ + options:dynamic-routing-v4-prefix-nexthop="20.0.0.1" +OVN_ROUTE_EQUAL([ovnvrf$vrf], [dnl +20.0.0.0/24 dev lo-test proto kernel scope link src 20.0.0.10 +172.16.1.1 via 20.0.0.1 dev lo-test proto ovn metric 100 +172.16.1.10 via 20.0.0.1 dev lo-test proto ovn metric 1000 +172.16.1.11 via 20.0.0.1 dev lo-test proto ovn metric 1000 +172.16.1.20 via 20.0.0.1 dev lo-test proto ovn metric 1000]) + +check ovn-nbctl --wait=hv set logical_router R1 \ + options:dynamic-routing-v4-prefix-nexthop="2000:db8:1000::1" +OVN_ROUTE_EQUAL([ovnvrf$vrf], [dnl +20.0.0.0/24 dev lo-test proto kernel scope link src 20.0.0.10 +172.16.1.1 via inet6 2000:db8:1000::1 dev lo-test proto ovn metric 100 +172.16.1.10 via inet6 2000:db8:1000::1 dev lo-test proto ovn metric 1000 +172.16.1.11 via inet6 2000:db8:1000::1 dev lo-test proto ovn metric 1000 +172.16.1.20 via inet6 2000:db8:1000::1 dev lo-test proto ovn metric 1000]) + +check ovn-nbctl --wait=hv set logical_router R1 \ + options:dynamic-routing-v6-prefix-nexthop="20.0.0.1" +OVN_ROUTE_V6_EQUAL([ovnvrf$vrf], [dnl +2000:db8:1000::/96 dev lo-test proto kernel metric 256 pref medium +blackhole 2001:db8:1003::1 dev lo proto ovn metric 100 pref medium +blackhole 2001:db8:1003::20 dev lo proto ovn metric 1000 pref medium +blackhole 2001:db8:1003::150 dev lo proto ovn metric 1000 pref medium +blackhole 2001:db8:1003::151 dev lo proto ovn metric 1000 pref medium +fe80::/64 dev lo-test proto kernel metric 256 pref medium +multicast ff00::/8 dev lo-test proto kernel metric 256 pref medium]) + +check ovn-nbctl --wait=hv set logical_router R1 \ + options:dynamic-routing-v6-prefix-nexthop="2000:db8:1000::1" +OVN_ROUTE_V6_EQUAL([ovnvrf$vrf], [dnl +2000:db8:1000::/96 dev lo-test proto kernel metric 256 pref medium +2001:db8:1003::1 via 2000:db8:1000::1 dev lo-test proto ovn metric 100 pref medium +2001:db8:1003::20 via 2000:db8:1000::1 dev lo-test proto ovn metric 1000 pref medium +2001:db8:1003::150 via 2000:db8:1000::1 dev lo-test proto ovn metric 1000 pref medium +2001:db8:1003::151 via 2000:db8:1000::1 dev lo-test proto ovn metric 1000 pref medium +fe80::/64 dev lo-test proto kernel metric 256 pref medium +multicast ff00::/8 dev lo-test proto kernel metric 256 pref medium]) + +OVN_CLEANUP_CONTROLLER([hv1]) + +# Ensure system resources are cleaned up. +AT_CHECK([ip link | grep -q ovnvrf$vrf:.*UP], [1]) +AT_CHECK([test `ip route show table $vrf | wc -l` -eq 1], [1]) + +OVN_CLEANUP_NORTHD + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/Failed to acquire.*/d +/connection dropped.*/d +/Couldn't parse IPv6 prefix nexthop.*/d"]) +AT_CLEANUP +]) -- 2.51.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
