This reverts commit 82e241542cbf19a144257a72324bc3278f76ee99. Turns out the dataplane performance issue was not caused by the zero-snat feature: https://bugzilla.redhat.com/show_bug.cgi?id=1992012#c24
The upgrade problem will be addressed as a separate patch. Signed-off-by: Dumitru Ceara <[email protected]> --- controller/ovn-controller.c | 115 +++++++++++++++++++------ include/ovn/actions.h | 1 include/ovn/features.h | 18 ++++ lib/actions.c | 31 +++++++ lib/automake.mk | 1 lib/features.c | 84 ++++++++++++++++++ lib/test-ovn-features.c | 56 ++++++++++++ tests/automake.mk | 3 + tests/ovn-controller.at | 11 +- tests/ovn-features.at | 8 ++ tests/system-common-macros.at | 4 + tests/system-ovn.at | 190 +++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 13 files changed, 490 insertions(+), 33 deletions(-) create mode 100644 lib/features.c create mode 100644 lib/test-ovn-features.c create mode 100644 tests/ovn-features.at diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 4927187c5..739048cf8 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -48,6 +48,7 @@ #include "openvswitch/vconn.h" #include "openvswitch/vlog.h" #include "ovn/actions.h" +#include "ovn/features.h" #include "lib/chassis-index.h" #include "lib/extend-table.h" #include "lib/ip-mcast-index.h" @@ -90,6 +91,7 @@ static unixctl_cb_func lflow_cache_show_stats_cmd; static unixctl_cb_func debug_delay_nb_cfg_report; #define DEFAULT_BRIDGE_NAME "br-int" +#define DEFAULT_DATAPATH "system" #define DEFAULT_PROBE_INTERVAL_MSEC 5000 #define OFCTRL_DEFAULT_PROBE_INTERVAL_SEC 0 @@ -329,10 +331,6 @@ static const struct ovsrec_bridge * create_br_int(struct ovsdb_idl_txn *ovs_idl_txn, const struct ovsrec_open_vswitch_table *ovs_table) { - if (!ovs_idl_txn) { - return NULL; - } - const struct ovsrec_open_vswitch *cfg; cfg = ovsrec_open_vswitch_table_first(ovs_table); if (!cfg) { @@ -396,6 +394,21 @@ create_br_int(struct ovsdb_idl_txn *ovs_idl_txn, return bridge; } +static const struct ovsrec_datapath * +create_br_datapath(struct ovsdb_idl_txn *ovs_idl_txn, + const struct ovsrec_open_vswitch *cfg, + const char *datapath_type) +{ + ovsdb_idl_txn_add_comment(ovs_idl_txn, + "ovn-controller: creating bridge datapath '%s'", + datapath_type); + + struct ovsrec_datapath *dp = ovsrec_datapath_insert(ovs_idl_txn); + ovsrec_open_vswitch_verify_datapaths(cfg); + ovsrec_open_vswitch_update_datapaths_setkey(cfg, datapath_type, dp); + return dp; +} + static const struct ovsrec_bridge * get_br_int(const struct ovsrec_bridge_table *bridge_table, const struct ovsrec_open_vswitch_table *ovs_table) @@ -409,33 +422,69 @@ get_br_int(const struct ovsrec_bridge_table *bridge_table, return get_bridge(bridge_table, br_int_name(cfg)); } -static const struct ovsrec_bridge * +static const struct ovsrec_datapath * +get_br_datapath(const struct ovsrec_open_vswitch *cfg, + const char *datapath_type) +{ + for (size_t i = 0; i < cfg->n_datapaths; i++) { + if (!strcmp(cfg->key_datapaths[i], datapath_type)) { + return cfg->value_datapaths[i]; + } + } + return NULL; +} + +static void process_br_int(struct ovsdb_idl_txn *ovs_idl_txn, const struct ovsrec_bridge_table *bridge_table, - const struct ovsrec_open_vswitch_table *ovs_table) + const struct ovsrec_open_vswitch_table *ovs_table, + const struct ovsrec_bridge **br_int_, + const struct ovsrec_datapath **br_int_dp_) { - const struct ovsrec_bridge *br_int = get_br_int(bridge_table, - ovs_table); - if (!br_int) { - br_int = create_br_int(ovs_idl_txn, ovs_table); - } - if (br_int && ovs_idl_txn) { - const struct ovsrec_open_vswitch *cfg; - cfg = ovsrec_open_vswitch_table_first(ovs_table); - ovs_assert(cfg); - const char *datapath_type = smap_get(&cfg->external_ids, - "ovn-bridge-datapath-type"); - /* Check for the datapath_type and set it only if it is defined in - * cfg. */ - if (datapath_type && strcmp(br_int->datapath_type, datapath_type)) { - ovsrec_bridge_set_datapath_type(br_int, datapath_type); + const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table); + const struct ovsrec_datapath *br_int_dp = NULL; + + ovs_assert(br_int_ && br_int_dp_); + if (ovs_idl_txn) { + if (!br_int) { + br_int = create_br_int(ovs_idl_txn, ovs_table); } - if (!br_int->fail_mode || strcmp(br_int->fail_mode, "secure")) { - ovsrec_bridge_set_fail_mode(br_int, "secure"); - VLOG_WARN("Integration bridge fail-mode changed to 'secure'."); + + if (br_int) { + const struct ovsrec_open_vswitch *cfg = + ovsrec_open_vswitch_table_first(ovs_table); + ovs_assert(cfg); + + /* Propagate "ovn-bridge-datapath-type" from OVS table, if any. + * Otherwise use the datapath-type set in br-int, if any. + * Finally, assume "system" datapath if none configured. + */ + const char *datapath_type = + smap_get(&cfg->external_ids, "ovn-bridge-datapath-type"); + + if (!datapath_type) { + if (br_int->datapath_type[0]) { + datapath_type = br_int->datapath_type; + } else { + datapath_type = DEFAULT_DATAPATH; + } + } + if (strcmp(br_int->datapath_type, datapath_type)) { + ovsrec_bridge_set_datapath_type(br_int, datapath_type); + } + if (!br_int->fail_mode || strcmp(br_int->fail_mode, "secure")) { + ovsrec_bridge_set_fail_mode(br_int, "secure"); + VLOG_WARN("Integration bridge fail-mode changed to 'secure'."); + } + br_int_dp = get_br_datapath(cfg, datapath_type); + if (!br_int_dp) { + br_int_dp = create_br_datapath(ovs_idl_txn, cfg, + datapath_type); + } } } - return br_int; + *br_int_ = br_int; + *br_int_dp_ = br_int_dp; } static const char * @@ -879,6 +928,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids); ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_other_config); ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_bridges); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_datapaths); ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface); ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_name); ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd); @@ -901,6 +951,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_add_column(ovs_idl, &ovsrec_ssl_col_ca_cert); ovsdb_idl_add_column(ovs_idl, &ovsrec_ssl_col_certificate); ovsdb_idl_add_column(ovs_idl, &ovsrec_ssl_col_private_key); + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_datapath); + ovsdb_idl_add_column(ovs_idl, &ovsrec_datapath_col_capabilities); chassis_register_ovs_idl(ovs_idl); encaps_register_ovs_idl(ovs_idl); binding_register_ovs_idl(ovs_idl); @@ -3465,8 +3517,10 @@ main(int argc, char *argv[]) ovsrec_bridge_table_get(ovs_idl_loop.idl); const struct ovsrec_open_vswitch_table *ovs_table = ovsrec_open_vswitch_table_get(ovs_idl_loop.idl); - const struct ovsrec_bridge *br_int = - process_br_int(ovs_idl_txn, bridge_table, ovs_table); + const struct ovsrec_bridge *br_int = NULL; + const struct ovsrec_datapath *br_int_dp = NULL; + process_br_int(ovs_idl_txn, bridge_table, ovs_table, + &br_int, &br_int_dp); /* Enable ACL matching for double tagged traffic. */ if (ovs_idl_txn) { @@ -3509,6 +3563,13 @@ main(int argc, char *argv[]) &chassis_private); } + /* If any OVS feature support changed, force a full recompute. */ + if (br_int_dp + && ovs_feature_support_update(&br_int_dp->capabilities)) { + VLOG_INFO("OVS feature set changed, force recompute."); + engine_set_force_recompute(true); + } + if (br_int) { ct_zones_data = engine_get_data(&en_ct_zones); if (ct_zones_data) { diff --git a/include/ovn/actions.h b/include/ovn/actions.h index b2f2f57c6..f023a37b9 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -25,6 +25,7 @@ #include "openvswitch/hmap.h" #include "openvswitch/uuid.h" #include "util.h" +#include "ovn/features.h" struct expr; struct lexer; diff --git a/include/ovn/features.h b/include/ovn/features.h index 10ee46fcd..c35d59b14 100644 --- a/include/ovn/features.h +++ b/include/ovn/features.h @@ -16,7 +16,25 @@ #ifndef OVN_FEATURES_H #define OVN_FEATURES_H 1 +#include <stdbool.h> + +#include "smap.h" + /* ovn-controller supported feature names. */ #define OVN_FEATURE_PORT_UP_NOTIF "port-up-notif" +/* OVS datapath supported features. Based on availability OVN might generate + * different types of openflows. + */ +enum ovs_feature_support_bits { + OVS_CT_ZERO_SNAT_SUPPORT_BIT, +}; + +enum ovs_feature_value { + OVS_CT_ZERO_SNAT_SUPPORT = (1 << OVS_CT_ZERO_SNAT_SUPPORT_BIT), +}; + +bool ovs_feature_is_supported(enum ovs_feature_value feature); +bool ovs_feature_support_update(const struct smap *ovs_capabilities); + #endif diff --git a/lib/actions.c b/lib/actions.c index f0291afef..c572e88ae 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -742,6 +742,22 @@ encode_CT_COMMIT_V1(const struct ovnact_ct_commit_v1 *cc, ct->zone_src.ofs = 0; ct->zone_src.n_bits = 16; + /* If the datapath supports all-zero SNAT then use it to avoid tuple + * collisions at commit time between NATed and firewalled-only sessions. + */ + + if (ovs_feature_is_supported(OVS_CT_ZERO_SNAT_SUPPORT)) { + size_t nat_offset = ofpacts->size; + ofpbuf_pull(ofpacts, nat_offset); + + struct ofpact_nat *nat = ofpact_put_NAT(ofpacts); + nat->flags = 0; + nat->range_af = AF_UNSPEC; + nat->flags |= NX_NAT_F_SRC; + ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset); + ct = ofpacts->header; + } + size_t set_field_offset = ofpacts->size; ofpbuf_pull(ofpacts, set_field_offset); @@ -792,6 +808,21 @@ encode_CT_COMMIT_V2(const struct ovnact_nest *on, ct->zone_src.ofs = 0; ct->zone_src.n_bits = 16; + /* If the datapath supports all-zero SNAT then use it to avoid tuple + * collisions at commit time between NATed and firewalled-only sessions. + */ + if (ovs_feature_is_supported(OVS_CT_ZERO_SNAT_SUPPORT)) { + size_t nat_offset = ofpacts->size; + ofpbuf_pull(ofpacts, nat_offset); + + struct ofpact_nat *nat = ofpact_put_NAT(ofpacts); + nat->flags = 0; + nat->range_af = AF_UNSPEC; + nat->flags |= NX_NAT_F_SRC; + ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset); + ct = ofpacts->header; + } + size_t set_field_offset = ofpacts->size; ofpbuf_pull(ofpacts, set_field_offset); diff --git a/lib/automake.mk b/lib/automake.mk index f73e1c9aa..ddfe33948 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -15,6 +15,7 @@ lib_libovn_la_SOURCES = \ lib/expr.c \ lib/extend-table.h \ lib/extend-table.c \ + lib/features.c \ lib/ovn-parallel-hmap.h \ lib/ovn-parallel-hmap.c \ lib/ip-mcast-index.c \ diff --git a/lib/features.c b/lib/features.c new file mode 100644 index 000000000..87d04ee3f --- /dev/null +++ b/lib/features.c @@ -0,0 +1,84 @@ +/* Copyright (c) 2021, Red Hat, Inc. + * + * 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 <stdint.h> +#include <stdlib.h> + +#include "lib/util.h" +#include "openvswitch/vlog.h" +#include "ovn/features.h" + +VLOG_DEFINE_THIS_MODULE(features); + +struct ovs_feature { + enum ovs_feature_value value; + const char *name; +}; + +static struct ovs_feature all_ovs_features[] = { + { + .value = OVS_CT_ZERO_SNAT_SUPPORT, + .name = "ct_zero_snat" + }, +}; + +/* A bitmap of OVS features that have been detected as 'supported'. */ +static uint32_t supported_ovs_features; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + +static bool +ovs_feature_is_valid(enum ovs_feature_value feature) +{ + switch (feature) { + case OVS_CT_ZERO_SNAT_SUPPORT: + return true; + default: + return false; + } +} + +bool +ovs_feature_is_supported(enum ovs_feature_value feature) +{ + ovs_assert(ovs_feature_is_valid(feature)); + return supported_ovs_features & feature; +} + +/* Returns 'true' if the set of tracked OVS features has been updated. */ +bool +ovs_feature_support_update(const struct smap *ovs_capabilities) +{ + bool updated = false; + + for (size_t i = 0; i < ARRAY_SIZE(all_ovs_features); i++) { + enum ovs_feature_value value = all_ovs_features[i].value; + const char *name = all_ovs_features[i].name; + bool old_state = supported_ovs_features & value; + bool new_state = smap_get_bool(ovs_capabilities, name, false); + if (new_state != old_state) { + updated = true; + if (new_state) { + supported_ovs_features |= value; + } else { + supported_ovs_features &= ~value; + } + VLOG_INFO_RL(&rl, "OVS Feature: %s, state: %s", name, + new_state ? "supported" : "not supported"); + } + } + return updated; +} diff --git a/lib/test-ovn-features.c b/lib/test-ovn-features.c new file mode 100644 index 000000000..deb97581e --- /dev/null +++ b/lib/test-ovn-features.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2021, Red Hat, Inc. + * + * 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 "ovn/features.h" +#include "tests/ovstest.h" + +static void +test_ovn_features(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + ovs_assert(!ovs_feature_is_supported(OVS_CT_ZERO_SNAT_SUPPORT)); + + struct smap features = SMAP_INITIALIZER(&features); + + smap_add(&features, "ct_zero_snat", "false"); + ovs_assert(!ovs_feature_support_update(&features)); + ovs_assert(!ovs_feature_is_supported(OVS_CT_ZERO_SNAT_SUPPORT)); + + smap_replace(&features, "ct_zero_snat", "true"); + ovs_assert(ovs_feature_support_update(&features)); + ovs_assert(ovs_feature_is_supported(OVS_CT_ZERO_SNAT_SUPPORT)); + + smap_add(&features, "unknown_feature", "true"); + ovs_assert(!ovs_feature_support_update(&features)); + + smap_destroy(&features); +} + +static void +test_ovn_features_main(int argc, char *argv[]) +{ + set_program_name(argv[0]); + static const struct ovs_cmdl_command commands[] = { + {"run", NULL, 0, 0, test_ovn_features, OVS_RO}, + {NULL, NULL, 0, 0, NULL, OVS_RO}, + }; + struct ovs_cmdl_context ctx; + ctx.argc = argc - 1; + ctx.argv = argv + 1; + ovs_cmdl_run_command(&ctx, commands); +} + +OVSTEST_REGISTER("test-ovn-features", test_ovn_features_main); diff --git a/tests/automake.mk b/tests/automake.mk index 60c732aae..5b890d644 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -36,6 +36,7 @@ TESTSUITE_AT = \ tests/ovn-performance.at \ tests/ovn-ofctrl-seqno.at \ tests/ovn-ipam.at \ + tests/ovn-features.at \ tests/ovn-lflow-cache.at \ tests/ovn-ipsec.at @@ -234,6 +235,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac noinst_PROGRAMS += tests/ovstest tests_ovstest_SOURCES = \ + include/ovn/features.h \ tests/ovstest.c \ tests/ovstest.h \ tests/test-utils.c \ @@ -245,6 +247,7 @@ tests_ovstest_SOURCES = \ controller/lflow-cache.h \ controller/ofctrl-seqno.c \ controller/ofctrl-seqno.h \ + lib/test-ovn-features.c \ northd/test-ipam.c \ northd/ipam.c \ northd/ipam.h diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index 29ddd742f..4ae218ed6 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -151,23 +151,24 @@ sysid=$(ovs-vsctl get Open_vSwitch . external_ids:system-id) check_datapath_type () { datapath_type=$1 chassis_datapath_type=$(ovn-sbctl get Chassis ${sysid} other_config:datapath-type | sed -e 's/"//g') #" - test "${datapath_type}" = "${chassis_datapath_type}" + ovs_datapath_type=$(ovs-vsctl get Bridge br-int datapath-type) + test "${datapath_type}" = "${chassis_datapath_type}" && test "${datapath_type}" = "${ovs_datapath_type}" } -OVS_WAIT_UNTIL([check_datapath_type ""]) +OVS_WAIT_UNTIL([check_datapath_type system]) ovs-vsctl set Bridge br-int datapath-type=foo OVS_WAIT_UNTIL([check_datapath_type foo]) # Change "ovn-bridge-mappings" value. It should not change the "datapath-type". ovs-vsctl set Open_vSwitch . external_ids:ovn-bridge-mappings=foo-mapping -check_datapath_type foo +AT_CHECK([check_datapath_type foo]) ovs-vsctl set Bridge br-int datapath-type=bar OVS_WAIT_UNTIL([check_datapath_type bar]) ovs-vsctl set Bridge br-int datapath-type=\"\" -OVS_WAIT_UNTIL([check_datapath_type ""]) +OVS_WAIT_UNTIL([check_datapath_type system]) # Set the datapath_type in external_ids:ovn-bridge-datapath-type. ovs-vsctl set Open_vSwitch . external_ids:ovn-bridge-datapath-type=foo @@ -176,11 +177,9 @@ OVS_WAIT_UNTIL([check_datapath_type foo]) # Change the br-int's datapath type to bar. # It should be reset to foo since ovn-bridge-datapath-type is configured. ovs-vsctl set Bridge br-int datapath-type=bar -OVS_WAIT_UNTIL([test foo = `ovs-vsctl get Bridge br-int datapath-type`]) OVS_WAIT_UNTIL([check_datapath_type foo]) ovs-vsctl set Open_vSwitch . external_ids:ovn-bridge-datapath-type=foobar -OVS_WAIT_UNTIL([test foobar = `ovs-vsctl get Bridge br-int datapath-type`]) OVS_WAIT_UNTIL([check_datapath_type foobar]) expected_iface_types=$(ovs-vsctl get Open_vSwitch . iface_types | tr -d '[[]] ""') diff --git a/tests/ovn-features.at b/tests/ovn-features.at new file mode 100644 index 000000000..7910c57e9 --- /dev/null +++ b/tests/ovn-features.at @@ -0,0 +1,8 @@ +# +# Unit tests for the lib/features.c module. +# +AT_BANNER([OVN unit tests - features]) + +AT_SETUP([unit test -- OVS feature detection tests]) +AT_CHECK([ovstest test-ovn-features run], [0], []) +AT_CLEANUP diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at index c23804f6f..616a87fcf 100644 --- a/tests/system-common-macros.at +++ b/tests/system-common-macros.at @@ -330,3 +330,7 @@ m4_define([OVS_CHECK_IPROUTE_ENCAP], # OVS_CHECK_CT_CLEAR() m4_define([OVS_CHECK_CT_CLEAR], [AT_SKIP_IF([! grep -q "Datapath supports ct_clear action" ovs-vswitchd.log])]) + +# OVS_CHECK_CT_ZERO_SNAT() +m4_define([OVS_CHECK_CT_ZERO_SNAT], + [AT_SKIP_IF([! grep -q "Datapath supports ct_zero_snat" ovs-vswitchd.log])])) diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 9487dde49..aadd68634 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -5319,6 +5319,196 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([load-balancer and firewall tuple conflict IPv4]) +AT_SKIP_IF([test $HAVE_NC = no]) +AT_KEYWORDS([ovnlb]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +OVS_CHECK_CT_ZERO_SNAT() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +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 bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# 1 logical switch connetected to one logical router. +# 2 VMs, one used as backend for a load balancer. + +check ovn-nbctl \ + -- lr-add rtr \ + -- lrp-add rtr rtr-ls 00:00:00:00:01:00 42.42.42.1/24 \ + -- ls-add ls \ + -- lsp-add ls ls-rtr \ + -- lsp-set-addresses ls-rtr 00:00:00:00:01:00 \ + -- lsp-set-type ls-rtr router \ + -- lsp-set-options ls-rtr router-port=rtr-ls \ + -- lsp-add ls vm1 -- lsp-set-addresses vm1 00:00:00:00:00:01 \ + -- lsp-add ls vm2 -- lsp-set-addresses vm2 00:00:00:00:00:02 \ + -- lb-add lb-test 66.66.66.66:666 42.42.42.2:4242 tcp \ + -- ls-lb-add ls lb-test + +ADD_NAMESPACES(vm1) +ADD_VETH(vm1, vm1, br-int, "42.42.42.2/24", "00:00:00:00:00:01", "42.42.42.1") + +ADD_NAMESPACES(vm2) +ADD_VETH(vm2, vm2, br-int, "42.42.42.3/24", "00:00:00:00:00:02", "42.42.42.1") + +# Wait for ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Start IPv4 TCP server on vm1. +NETNS_DAEMONIZE([vm1], [nc -k -l 42.42.42.2 4242], [nc-vm1.pid]) + +# Make sure connecting to the VIP works. +NS_CHECK_EXEC([vm2], [nc 66.66.66.66 666 -p 2000 -z]) + +# Start IPv4 TCP connection to VIP from vm2. +NS_CHECK_EXEC([vm2], [nc 66.66.66.66 666 -p 2001 -z]) + +# Check conntrack. We expect two entries: +# - one in vm1's zone (firewall) +# - one in vm2's zone (dnat) +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 2001 | \ +grep "orig=.src=42\.42\.42\.3" | \ +sed -e 's/port=2001/port=<clnt_s_port>/g' \ + -e 's/sport=4242,dport=[[0-9]]\+/sport=4242,dport=<rnd_port>/g' \ + -e 's/state=[[0-9_A-Z]]*/state=<cleared>/g' \ + -e 's/zone=[[0-9]]*/zone=<cleared>/' | sort], [0], [dnl +tcp,orig=(src=42.42.42.3,dst=42.42.42.2,sport=<clnt_s_port>,dport=4242),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=42.42.42.3,dst=66.66.66.66,sport=<clnt_s_port>,dport=666),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,labels=0x2,protoinfo=(state=<cleared>) +]) + +# Start IPv4 TCP connection to backend IP from vm2 which would require +# additional source port translation to avoid a tuple conflict. +NS_CHECK_EXEC([vm2], [nc 42.42.42.2 4242 -p 2001 -z]) + +# Check conntrack. We expect three entries: +# - one in vm1's zone (firewall) - reused from the previous connection. +# - one in vm2's zone (dnat) - still in TIME_WAIT after the previous connection. +# - one in vm2's zone (firewall + additional all-zero SNAT) +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 2001 | \ +grep "orig=.src=42\.42\.42\.3" | \ +sed -e 's/port=2001/port=<clnt_s_port>/g' \ + -e 's/sport=4242,dport=[[0-9]]\+/sport=4242,dport=<rnd_port>/g' \ + -e 's/state=[[0-9_A-Z]]*/state=<cleared>/g' \ + -e 's/zone=[[0-9]]*/zone=<cleared>/' | sort], [0], [dnl +tcp,orig=(src=42.42.42.3,dst=42.42.42.2,sport=<clnt_s_port>,dport=4242),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=42.42.42.3,dst=42.42.42.2,sport=<clnt_s_port>,dport=4242),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=<rnd_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=42.42.42.3,dst=66.66.66.66,sport=<clnt_s_port>,dport=666),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,labels=0x2,protoinfo=(state=<cleared>) +]) + +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([load-balancer and firewall tuple conflict IPv6]) +AT_SKIP_IF([test $HAVE_NC = no]) +AT_KEYWORDS([ovnlb]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +OVS_CHECK_CT_ZERO_SNAT() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +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 bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# 1 logical switch connetected to one logical router. +# 2 VMs, one used as backend for a load balancer. + +check ovn-nbctl \ + -- lr-add rtr \ + -- lrp-add rtr rtr-ls 00:00:00:00:01:00 4242::1/64 \ + -- ls-add ls \ + -- lsp-add ls ls-rtr \ + -- lsp-set-addresses ls-rtr 00:00:00:00:01:00 \ + -- lsp-set-type ls-rtr router \ + -- lsp-set-options ls-rtr router-port=rtr-ls \ + -- lsp-add ls vm1 -- lsp-set-addresses vm1 00:00:00:00:00:01 \ + -- lsp-add ls vm2 -- lsp-set-addresses vm2 00:00:00:00:00:02 \ + -- lb-add lb-test [[6666::1]]:666 [[4242::2]]:4242 tcp \ + -- ls-lb-add ls lb-test + +ADD_NAMESPACES(vm1) +ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1") +OVS_WAIT_UNTIL([test "$(ip netns exec vm1 ip a | grep 4242::2 | grep tentative)" = ""]) + +ADD_NAMESPACES(vm2) +ADD_VETH(vm2, vm2, br-int, "4242::3/64", "00:00:00:00:00:02", "4242::1") +OVS_WAIT_UNTIL([test "$(ip netns exec vm2 ip a | grep 4242::3 | grep tentative)" = ""]) + +# Wait for ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Start IPv6 TCP server on vm1. +NETNS_DAEMONIZE([vm1], [nc -k -l 4242::2 4242], [nc-vm1.pid]) + +# Make sure connecting to the VIP works. +NS_CHECK_EXEC([vm2], [nc 6666::1 666 -p 2000 -z]) + +# Start IPv6 TCP connection to VIP from vm2. +NS_CHECK_EXEC([vm2], [nc 6666::1 666 -p 2001 -z]) + +# Check conntrack. We expect two entries: +# - one in vm1's zone (firewall) +# - one in vm2's zone (dnat) +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 2001 | \ +grep "orig=.src=4242::3" | \ +sed -e 's/port=2001/port=<clnt_s_port>/g' \ + -e 's/sport=4242,dport=[[0-9]]\+/sport=4242,dport=<rnd_port>/g' \ + -e 's/state=[[0-9_A-Z]]*/state=<cleared>/g' \ + -e 's/zone=[[0-9]]*/zone=<cleared>/' | sort], [0], [dnl +tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=4242::3,dst=6666::1,sport=<clnt_s_port>,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,labels=0x2,protoinfo=(state=<cleared>) +]) + +# Start IPv6 TCP connection to backend IP from vm2 which would require +# additional source port translation to avoid a tuple conflict. +NS_CHECK_EXEC([vm2], [nc 4242::2 4242 -p 2001 -z]) + +# Check conntrack. We expect three entries: +# - one in vm1's zone (firewall) - reused from the previous connection. +# - one in vm2's zone (dnat) - still in TIME_WAIT after the previous connection. +# - one in vm2's zone (firewall + additional all-zero SNAT) +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 2001 | \ +grep "orig=.src=4242::3" | \ +sed -e 's/port=2001/port=<clnt_s_port>/g' \ + -e 's/sport=4242,dport=[[0-9]]\+/sport=4242,dport=<rnd_port>/g' \ + -e 's/state=[[0-9_A-Z]]*/state=<cleared>/g' \ + -e 's/zone=[[0-9]]*/zone=<cleared>/' | sort], [0], [dnl +tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=4242::3,dst=4242::2,sport=<clnt_s_port>,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<rnd_port>),zone=<cleared>,protoinfo=(state=<cleared>) +tcp,orig=(src=4242::3,dst=6666::1,sport=<clnt_s_port>,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=<clnt_s_port>),zone=<cleared>,labels=0x2,protoinfo=(state=<cleared>) +]) + +AT_CLEANUP +]) + # When a lport is released on a chassis, ovn-controller was # not clearing some of the flowss in the table 33 leading # to packet drops if ct() is hit. diff --git a/tests/testsuite.at b/tests/testsuite.at index ddc3f11d6..b716a1ad9 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,6 +27,7 @@ m4_include([tests/ovn.at]) m4_include([tests/ovn-performance.at]) m4_include([tests/ovn-northd.at]) m4_include([tests/ovn-nbctl.at]) +m4_include([tests/ovn-features.at]) m4_include([tests/ovn-lflow-cache.at]) m4_include([tests/ovn-ofctrl-seqno.at]) m4_include([tests/ovn-sbctl.at]) _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
