From patchwork Tue Dec 3 11:08:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ales Musil X-Patchwork-Id: 2017705 X-Patchwork-Delegate: nusiddiq@redhat.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=EG4r3Ln5; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Y2dG204DNz1yQZ for ; Tue, 3 Dec 2024 22:09:30 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 6B19E40D57; Tue, 3 Dec 2024 11:09:28 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id NzOG3cI8EGWy; Tue, 3 Dec 2024 11:09:23 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 61F0F40EC1 Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=EG4r3Ln5 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 61F0F40EC1; Tue, 3 Dec 2024 11:09:22 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id AABDBC0889; Tue, 3 Dec 2024 11:09:22 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1EDE0C08AA for ; Tue, 3 Dec 2024 11:09:21 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id BFB2060826 for ; Tue, 3 Dec 2024 11:09:19 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 36omf2R2tDDa for ; Tue, 3 Dec 2024 11:09:08 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org B77CD607F5 Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org B77CD607F5 Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=EG4r3Ln5 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id B77CD607F5 for ; Tue, 3 Dec 2024 11:09:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733224146; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eTVOcEoSCKmJJcnjCtt7dco445aGxUYTgIQg0iiCdkc=; b=EG4r3Ln563sWmwO5T4yhKNvVXq8OFgvd0QFgedvGN7gFAStB7gVTPWSIIioyUaBavzCzs1 WPXSK93xzAl6vHqxdvbEbGn2MGzVzWlq57X4Tebj1qmALDTxTTiyZNGmy6IE2WR/LG2UVe aVdqKkUIOc5SEusOmbcXpNvRXsPrxB4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-47-nBH-lgzOPjSVFjuqAETccA-1; Tue, 03 Dec 2024 06:09:05 -0500 X-MC-Unique: nBH-lgzOPjSVFjuqAETccA-1 X-Mimecast-MFC-AGG-ID: nBH-lgzOPjSVFjuqAETccA Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 690C31955BF9 for ; Tue, 3 Dec 2024 11:09:04 +0000 (UTC) Received: from amusil.brq.redhat.com (unknown [10.43.17.32]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4CFF11955EA7; Tue, 3 Dec 2024 11:09:03 +0000 (UTC) From: Ales Musil To: dev@openvswitch.org Date: Tue, 3 Dec 2024 12:08:48 +0100 Message-ID: <20241203110853.201377-7-amusil@redhat.com> In-Reply-To: <20241203110853.201377-1-amusil@redhat.com> References: <20241203110853.201377-1-amusil@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: M5WMJfpV0mEN0D6iTLXGkIIanrul2uMUZJZ1bJVbQfs_1733224144 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn 6/6] northd, controller: Flood ARP and NA packet on transit router. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" When packets goes between AZs through transit router for the first time there isn't any MAC binding for the remote port equivalent. The TR will properly generate ARP/ND NS packet that will arrive to the remote AZ, however the response would never leave the remote AZ as a consequence the local AZ would never learn this MAC binding. To prevent the described behavior add a new table that will contain all remote chassis and corresponding encapsulations that allow us to just flood all chassis with any packet that will be sent to this table. At the same time add a new action that sends the packet to this table. In order to properly generate MAC binding we need to redirect the ARP into ingress instead of egress as usual for reception from tunnels. Add flows that will match on ARP and ND NA with combination of 0 outport which should indicate that this is the remote flood flow. Only exception is VXLAN which doesn't have enough space for outport encoding, in that case we need to send the packet to both ingress and egress as we cannot determine if it was part of the remote flood or regular packet that arrived from another chassis in the same AZ. Signed-off-by: Ales Musil --- controller/lflow.c | 1 + controller/lflow.h | 4 + controller/physical.c | 188 ++++++++++++++++++++++++++++++++---- include/ovn/actions.h | 3 + lib/actions.c | 17 ++++ northd/northd.c | 12 ++- tests/multinode-macros.at | 48 ++++++++++ tests/multinode.at | 196 ++++++++++++++++++++++++++++++++++++++ tests/ovn-controller.at | 76 +++++++++++++++ tests/ovn-macros.at | 1 + tests/ovn.at | 10 +- tests/test-ovn.c | 1 + utilities/ovn-trace.c | 3 + 13 files changed, 536 insertions(+), 24 deletions(-) diff --git a/controller/lflow.c b/controller/lflow.c index 6c49484f1..c94e68c3f 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -889,6 +889,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .ct_nw_dst_load_table = OFTABLE_CT_ORIG_NW_DST_LOAD, .ct_ip6_dst_load_table = OFTABLE_CT_ORIG_IP6_DST_LOAD, .ct_tp_dst_load_table = OFTABLE_CT_ORIG_TP_DST_LOAD, + .flood_remote_table = OFTABLE_FLOOD_REMOTE_CHASSIS, .ctrl_meter_id = ctrl_meter_id, .common_nat_ct_zone = get_common_nat_zone(ldp), }; diff --git a/controller/lflow.h b/controller/lflow.h index 206328f9e..b27721baa 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -98,6 +98,10 @@ struct uuid; #define OFTABLE_CT_ORIG_NW_DST_LOAD 81 #define OFTABLE_CT_ORIG_IP6_DST_LOAD 82 #define OFTABLE_CT_ORIG_TP_DST_LOAD 83 +#define OFTABLE_FLOOD_REMOTE_CHASSIS 84 + +/* Common defines shared between some controller components. */ +#define CHASSIS_FLOOD_INDEX_START 0x8000 struct lflow_ctx_in { diff --git a/controller/physical.c b/controller/physical.c index 1adc0a5f6..b6a8ba396 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -185,6 +185,73 @@ put_encapsulation(enum mf_field_id mff_ovn_geneve, } } +static void +put_decapsulation(enum mf_field_id mff_ovn_geneve, + const struct chassis_tunnel *tun, + struct ofpbuf *ofpacts) +{ + if (tun->type == GENEVE) { + put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 24, ofpacts); + put_move(mff_ovn_geneve, 16, MFF_LOG_INPORT, 0, 15, ofpacts); + put_move(mff_ovn_geneve, 0, MFF_LOG_OUTPORT, 0, 16, ofpacts); + } else if (tun->type == STT) { + put_move(MFF_TUN_ID, 40, MFF_LOG_INPORT, 0, 15, ofpacts); + put_move(MFF_TUN_ID, 24, MFF_LOG_OUTPORT, 0, 16, ofpacts); + put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 24, ofpacts); + } else if (tun->type == VXLAN) { + /* Add flows for non-VTEP tunnels. Split VNI into two 12-bit + * sections and use them for datapath and outport IDs. */ + put_move(MFF_TUN_ID, 12, MFF_LOG_OUTPORT, 0, 12, ofpacts); + put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 12, ofpacts); + } else { + OVS_NOT_REACHED(); + } +} + + +static void +put_remote_chassis_flood_encap(struct ofpbuf *ofpacts, + enum chassis_tunnel_type type, + enum mf_field_id mff_ovn_geneve) +{ + if (type == GENEVE) { + put_move(MFF_LOG_DATAPATH, 0, MFF_TUN_ID, 0, 24, ofpacts); + put_load(0, mff_ovn_geneve, 0, 32, ofpacts); + put_move(MFF_LOG_INPORT, 0, mff_ovn_geneve, 16, 15, ofpacts); + } else if (type == STT) { + put_move(MFF_LOG_INPORT, 0, MFF_TUN_ID, 40, 15, ofpacts); + put_load(0, MFF_TUN_ID, 24, 16, ofpacts); + put_move(MFF_LOG_DATAPATH, 0, MFF_TUN_ID, 0, 24, ofpacts); + } else if (type == VXLAN) { + put_move(MFF_LOG_INPORT, 0, MFF_TUN_ID, 12, 12, ofpacts); + put_move(MFF_LOG_DATAPATH, 0, MFF_TUN_ID, 0, 12, ofpacts); + } else { + OVS_NOT_REACHED(); + } +} + +static void +match_set_chassis_flood_outport(struct match *match, + enum chassis_tunnel_type type, + enum mf_field_id mff_ovn_geneve) +{ + if (type == GENEVE) { + /* Outport occupies the lower half of tunnel metadata (0-15). */ + union mf_value value, mask; + memset(&value, 0, sizeof value); + memset(&mask, 0, sizeof mask); + + const struct mf_field *mf_ovn_geneve = mf_from_id(mff_ovn_geneve); + memset(&mask.tun_metadata[mf_ovn_geneve->n_bytes - 2], 0xff, 2); + + tun_metadata_set_match(mf_ovn_geneve, &value, &mask, match, NULL); + } else if (type == STT) { + /* Outport occupies bits 24-39. */ + match_set_tun_id_masked(match, 0, htonll(UINT64_C(0xffff) << 24)); + } +} + + static void put_stack(enum mf_field_id field, struct ofpact_stack *stack) { @@ -2349,6 +2416,106 @@ consider_mc_group(const struct physical_ctx *ctx, sset_destroy(&vtep_chassis); } +#define CHASSIS_FLOOD_MAX_MSG_SIZE MC_OFPACTS_MAX_MSG_SIZE + +static void +physical_eval_remote_chassis_flows(const struct physical_ctx *ctx, + struct ofpbuf *egress_ofpacts, + struct ovn_desired_flow_table *flow_table) +{ + struct match match = MATCH_CATCHALL_INITIALIZER; + uint32_t index = CHASSIS_FLOOD_INDEX_START; + struct chassis_tunnel *prev = NULL; + + uint8_t actions_stub[256]; + struct ofpbuf ingress_ofpacts; + ofpbuf_use_stub(&ingress_ofpacts, actions_stub, sizeof(actions_stub)); + + ofpbuf_clear(egress_ofpacts); + + const struct sbrec_chassis *chassis; + SBREC_CHASSIS_TABLE_FOR_EACH (chassis, ctx->chassis_table) { + if (!smap_get_bool(&chassis->other_config, "is-remote", false)) { + continue; + } + + struct chassis_tunnel *tun = + chassis_tunnel_find(ctx->chassis_tunnels, chassis->name, + NULL, NULL); + if (!tun) { + continue; + } + + if (!(prev && prev->type == tun->type)) { + put_remote_chassis_flood_encap(egress_ofpacts, tun->type, + ctx->mff_ovn_geneve); + } + + ofpact_put_OUTPUT(egress_ofpacts)->port = tun->ofport; + prev = tun; + + if (egress_ofpacts->size > CHASSIS_FLOOD_MAX_MSG_SIZE) { + match_init_catchall(&match); + match_set_reg(&match, MFF_REG6 - MFF_REG0, index++); + + put_split_buf_function(index, 0, OFTABLE_FLOOD_REMOTE_CHASSIS, + egress_ofpacts); + + ofctrl_add_flow(flow_table, OFTABLE_FLOOD_REMOTE_CHASSIS, 100, 0, + &match, egress_ofpacts, hc_uuid); + + ofpbuf_clear(egress_ofpacts); + prev = NULL; + } + + + ofpbuf_clear(&ingress_ofpacts); + put_decapsulation(ctx->mff_ovn_geneve, tun, &ingress_ofpacts); + put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ingress_ofpacts); + if (tun->type == VXLAN) { + /* VXLAN doesn't carry the inport information, we cannot set + * the outport to 0 then and match on it. */ + put_resubmit(OFTABLE_LOCAL_OUTPUT, &ingress_ofpacts); + } + + /* Add match on ARP response coming from remote chassis. */ + match_init_catchall(&match); + match_set_in_port(&match, tun->ofport); + match_set_dl_type(&match, htons(ETH_TYPE_ARP)); + match_set_arp_opcode_masked(&match, 2, UINT8_MAX); + match_set_chassis_flood_outport(&match, tun->type, + ctx->mff_ovn_geneve); + + ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 120, + chassis->header_.uuid.parts[0], + &match, &ingress_ofpacts, hc_uuid); + + /* Add match on ND NA coming from remote chassis. */ + match_init_catchall(&match); + match_set_in_port(&match, tun->ofport); + match_set_dl_type(&match, htons(ETH_TYPE_IPV6)); + match_set_nw_proto(&match, IPPROTO_ICMPV6); + match_set_icmp_type(&match, 136); + match_set_icmp_code(&match, 0); + match_set_chassis_flood_outport(&match, tun->type, + ctx->mff_ovn_geneve); + + ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 120, + chassis->header_.uuid.parts[0], + &match, &ingress_ofpacts, hc_uuid); + } + + if (egress_ofpacts->size > 0) { + match_init_catchall(&match); + match_set_reg(&match, MFF_REG6 - MFF_REG0, index); + + ofctrl_add_flow(flow_table, OFTABLE_FLOOD_REMOTE_CHASSIS, 100, 0, + &match, egress_ofpacts, hc_uuid); + } + + ofpbuf_uninit(&ingress_ofpacts); +} + static void physical_eval_port_binding(struct physical_ctx *p_ctx, const struct sbrec_port_binding *pb, @@ -2504,24 +2671,7 @@ physical_run(struct physical_ctx *p_ctx, match_set_in_port(&match, tun->ofport); ofpbuf_clear(&ofpacts); - if (tun->type == GENEVE) { - put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 24, &ofpacts); - put_move(p_ctx->mff_ovn_geneve, 16, MFF_LOG_INPORT, 0, 15, - &ofpacts); - put_move(p_ctx->mff_ovn_geneve, 0, MFF_LOG_OUTPORT, 0, 16, - &ofpacts); - } else if (tun->type == STT) { - put_move(MFF_TUN_ID, 40, MFF_LOG_INPORT, 0, 15, &ofpacts); - put_move(MFF_TUN_ID, 24, MFF_LOG_OUTPORT, 0, 16, &ofpacts); - put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 24, &ofpacts); - } else if (tun->type == VXLAN) { - /* Add flows for non-VTEP tunnels. Split VNI into two 12-bit - * sections and use them for datapath and outport IDs. */ - put_move(MFF_TUN_ID, 12, MFF_LOG_OUTPORT, 0, 12, &ofpacts); - put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 12, &ofpacts); - } else { - OVS_NOT_REACHED(); - } + put_decapsulation(p_ctx->mff_ovn_geneve, tun, &ofpacts); put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0, &match, @@ -2773,5 +2923,7 @@ physical_run(struct physical_ctx *p_ctx, ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_IP6_DST_LOAD, 100, 0, &match, &ofpacts, hc_uuid); + physical_eval_remote_chassis_flows(p_ctx, &ofpacts, flow_table); + ofpbuf_uninit(&ofpacts); } diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 7e0670a11..73beeeee9 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -134,6 +134,7 @@ struct collector_set_ids; OVNACT(CT_ORIG_NW_DST, ovnact_result) \ OVNACT(CT_ORIG_IP6_DST, ovnact_result) \ OVNACT(CT_ORIG_TP_DST, ovnact_result) \ + OVNACT(FLOOD_REMOTE, ovnact_null) \ /* enum ovnact_type, with a member OVNACT_ for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -945,6 +946,8 @@ struct ovnact_encode_params { * to resubmit. */ uint32_t ct_tp_dst_load_table; /* OpenFlow table for 'ct_tp_dst' * to resubmit. */ + uint32_t flood_remote_table; /* OpenFlow table for 'chassis_flood' + * to resubmit. */ }; void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, diff --git a/lib/actions.c b/lib/actions.c index 4a328b03d..3973b7346 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -5531,6 +5531,21 @@ format_CT_ORIG_TP_DST(const struct ovnact_result *res, struct ds *s) ds_put_cstr(s, " = ct_tp_dst();"); } +static void +format_FLOOD_REMOTE(const struct ovnact_null *null OVS_UNUSED, struct ds *s) +{ + ds_put_cstr(s, "flood_remote;"); +} + +static void +encode_FLOOD_REMOTE(const struct ovnact_null *null OVS_UNUSED, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + put_load(CHASSIS_FLOOD_INDEX_START, MFF_REG6, 0, 32, ofpacts); + emit_resubmit(ofpacts, ep->flood_remote_table); +} + /* Parses an assignment or exchange or put_dhcp_opts action. */ static void parse_set_action(struct action_context *ctx) @@ -5758,6 +5773,8 @@ parse_action(struct action_context *ctx) parse_sample(ctx); } else if (lexer_match_id(ctx->lexer, "mac_cache_use")) { ovnact_put_MAC_CACHE_USE(ctx->ovnacts); + } else if (lexer_match_id(ctx->lexer, "flood_remote")) { + ovnact_put_FLOOD_REMOTE(ctx->ovnacts); } else { lexer_syntax_error(ctx->lexer, "expecting action"); } diff --git a/northd/northd.c b/northd/northd.c index f3ef090f4..e3bcf22cb 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -13390,21 +13390,22 @@ build_neigh_learning_flows_for_lrouter( * */ /* Flows for LOOKUP_NEIGHBOR. */ + const char *flood = od->is_transit_router ? "flood_remote; " : ""; bool learn_from_arp_request = smap_get_bool(&od->nbr->options, "always_learn_from_arp_request", true); ds_clear(actions); ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_arp(inport, arp.spa, arp.sha); %snext;", + " = lookup_arp(inport, arp.spa, arp.sha); %s%snext;", learn_from_arp_request ? "" : - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; ", flood); ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "arp.op == 2", ds_cstr(actions), lflow_ref); ds_clear(actions); ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_nd(inport, nd.target, nd.tll); %snext;", + " = lookup_nd(inport, nd.target, nd.tll); %s%snext;", learn_from_arp_request ? "" : - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; ", flood); ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na", ds_cstr(actions), lflow_ref); @@ -13420,7 +13421,8 @@ build_neigh_learning_flows_for_lrouter( ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT " = lookup_nd(inport, nd.target, nd.tll); " REGBIT_LOOKUP_NEIGHBOR_IP_RESULT - " = lookup_nd_ip(inport, nd.target); next;"); + " = lookup_nd_ip(inport, nd.target); %snext;", + flood); ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 110, "nd_na && ip6.src == fe80::/10 && ip6.dst == ff00::/8", ds_cstr(actions), lflow_ref); diff --git a/tests/multinode-macros.at b/tests/multinode-macros.at index 698d2c625..29f0711e6 100644 --- a/tests/multinode-macros.at +++ b/tests/multinode-macros.at @@ -112,6 +112,54 @@ cleanup_multinode_resources_by_nodes() { done } +# multinode_cleanup_northd NODE +# +# Removes previously set nothd on specified node +multinode_cleanup_northd() { + c=$1 + # Cleanup existing one + m_as $c /usr/share/ovn/scripts/ovn-ctl stop_northd + m_as $c rm -f /etc/ovn/*.db +} + +# multinode_setup_northd NODE +# +# Sets up northd on specified node. +multinode_setup_northd() { + c=$1 + + multinode_cleanup_northd $c + + m_as $c /usr/share/ovn/scripts/ovn-ctl start_northd + m_as $c ovn-nbctl set-connection ptcp:6641 + m_as $c ovn-sbctl set-connection ptcp:6642 +} + +# multinode_setup_controller NODE ENCAP_IP REMOTE_IP [ENCAP_TYPE] +# +# Sets up controller on specified node. +multinode_setup_controller() { + c=$1 + encap_ip=$3 + remote_ip=$4 + encap_type=${5:-"geneve"} + + # Cleanup existing one + m_as $c /usr/share/openvswitch/scripts/ovs-ctl stop + m_as $c /usr/share/ovn/scripts/ovn-ctl stop_controller + m_as $c rm -f /etc/openvswitch/*.db + + m_as $c /usr/share/openvswitch/scripts/ovs-ctl start --system-id=$c + m_as $c /usr/share/ovn/scripts/ovn-ctl start_controller + + m_as $c ovs-vsctl set open . external_ids:ovn-encap-ip=$encap_ip + m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=$encap_type + m_as $c ovs-vsctl set open . external-ids:ovn-remote=tcp:$remote_ip:6642 + m_as $c ovs-vsctl set open . external-ids:ovn-openflow-probe-interval=60 + m_as $c ovs-vsctl set open . external-ids:ovn-remote-probe-interval=180000 + m_as $c ovs-vsctl set open . external-ids:ovn-bridge-datapath-type=system +} + # m_count_rows TABLE [CONDITION...] # # Prints the number of rows in TABLE (that satisfy CONDITION). diff --git a/tests/multinode.at b/tests/multinode.at index a45dc55cc..2962f54d0 100644 --- a/tests/multinode.at +++ b/tests/multinode.at @@ -2582,3 +2582,199 @@ Connected to 10.0.2.4 (10.0.2.4) port 8080 fi AT_CLEANUP + +AT_SETUP([ovn multinode - Transit Router basic functionality]) + +# Check that ovn-fake-multinode setup is up and running +check_fake_multinode_setup + +# Delete the multinode NB and OVS resources before starting the test. +cleanup_multinode_resources + +# Network topology +# ┌─────────────────────────────────� ┌────────────────────────────────� +# │ │ │ │ +# │ ┌───────────────────� AZ1 │ │ AZ2 ┌───────────────────� │ +# │ │ external │ │ │ │ │ │ +# │ │ │ │ │ │ │ │ +# │ │ 192.168.100.10/24 │ │ │ │ ................. │ │ +# │ │ 1000::10/64 │ │ │ │ │ │ +# │ └─────────┬─────────┘ │ │ └─────────┬─────────┘ │ +# │ │ │ │ │ │ +# │ │ │ │ │ │ +# │ ┌─────────┴─────────� │ │ ┌─────────┴─────────� │ +# │ │ 192.168.100.1/24 │ │ │ │ 192.168.100.1/24 │ │ +# │ │ 1000::1/64 │ │ │ │ 1000::1/64 │ │ +# │ │ │ │ │ │ │ │ +# │ │ GW │ │ │ │ GW │ │ +# │ │ │ │ │ │ │ │ +# │ │ 100.65.0.1/30 │ │ │ │ 100.65.0.5/30 │ │ +# │ │ 100:65::1/126 │ │ │ │ 100:65::5/126 │ │ +# │ └─────────┬─────────┘ │ │ └───────────────────┘ │ +# │ │ │ │ │ │ +# │ │ Peer ports │ │ │ Peer ports │ +# │ │ │ │ │ │ +# │ ┌─────────┴──────────────────│─────│──────────────────┴─────────� │ +# │ │ 100.65.0.2/30 │ │ 100.65.0.6/30 │ │ +# │ │ 100:65::2/126 │ │ 100:65::6/126 │ │ +# │ │ │ │ │ │ +# │ │ │ TR │ │ │ +# │ │ │ │ │ │ +# │ │ 10.100.200.1/24 │ │ 10.100.200.1/24 │ │ +# │ │ 10:200::1/64 │ │ 10:200::1/64 │ │ +# │ └─────────┬──────────────────│─────│────────────────────────────┘ │ +# │ │ │ │ │ │ +# │ │ │ │ │ │ +# │ │ │ │ │ │ +# │ ┌─────────┴──────────────────│─────│────────────────────────────� │ +# │ │ │ TS │ │ │ +# │ └─────────┬──────────────────│─────│────────────────────────────┘ │ +# │ │ │ │ │ │ +# │ │ │ │ │ │ +# │ │ │ │ │ │ +# │ ┌─────────┴─────────� │ │ ┌─────────┴─────────� │ +# │ │ pod10 │ │ │ │ pod20 │ │ +# │ │ │ │ │ │ │ │ +# │ │ 10.100.200.10/24 │ │ │ │ 10.100.200.20/24 │ │ +# │ │ 10:200::10/64 │ │ │ │ 10:200::20/64 │ │ +# │ └───────────────────┘ │ │ └───────────────────┘ │ +# └─────────────────────────────────┘ └────────────────────────────────┘ + +for i in 1 2; do + chassis="ovn-chassis-$i" + ip=$(m_as $chassis ip -4 addr show eth1 | grep inet | awk '{print $2}' | cut -d'/' -f1) + + multinode_setup_northd $chassis + multinode_setup_controller $chassis $chassis $ip $ip + + check m_as $chassis ovs-vsctl set open . external_ids:ovn-monitor-all=true + check m_as $chassis ovs-vsctl set open . external_ids:ovn-is-interconn=true + + check m_as $chassis ovn-nbctl ls-add public + + check m_as $chassis ovn-nbctl lsp-add public public-gw + check m_as $chassis ovn-nbctl lsp-set-type public-gw router + check m_as $chassis ovn-nbctl lsp-set-addresses public-gw router + check m_as $chassis ovn-nbctl lsp-set-options public-gw router-port=gw-public + + check m_as $chassis ovn-nbctl lr-add gw + check m_as $chassis ovn-nbctl lrp-add gw gw-public 00:00:00:00:20:00 192.168.100.1/24 1000::1/64 + + check m_as $chassis ovn-nbctl set logical_router gw options:chassis=$chassis + + # Add TR and set the same tunnel key for both chassis + check m_as $chassis ovn-nbctl ls-add ts + check m_as $chassis ovn-nbctl set logical_switch ts other_config:requested-tnl-key=10 + + check m_as $chassis ovn-nbctl lsp-add ts ts-tr + check m_as $chassis ovn-nbctl lsp-set-type ts-tr router + check m_as $chassis ovn-nbctl lsp-set-addresses ts-tr router + check m_as $chassis ovn-nbctl lsp-set-options ts-tr router-port=tr-ts + + check m_as $chassis ovn-nbctl lr-add tr + check m_as $chassis ovn-nbctl lrp-add tr tr-ts 00:00:00:00:10:00 10.100.200.1/24 10:200::1/64 + check m_as $chassis ovn-nbctl set logical_router tr options:requested-tnl-key=20 + + # Add TS pods, with the same tunnel keys on both sides + check m_as $chassis ovn-nbctl lsp-add ts pod10 + check m_as $chassis ovn-nbctl lsp-set-addresses pod10 "00:00:00:00:10:10 10.100.200.10 10:200::10" + check m_as $chassis ovn-nbctl set logical_switch_port pod10 options:requested-tnl-key=10 + + check m_as $chassis ovn-nbctl lsp-add ts pod20 + check m_as $chassis ovn-nbctl lsp-set-addresses pod20 "00:00:00:00:10:20 10.100.200.20 10:200::20" + check m_as $chassis ovn-nbctl set logical_switch_port pod20 options:requested-tnl-key=20 +done + +# Add SNAT for the GW router that corresponds to "gw-tr" LRP IP +check m_as ovn-chassis-1 ovn-nbctl lr-nat-add gw snat 100.65.0.1 192.168.100.0/24 +check m_as ovn-chassis-1 ovn-nbctl lr-nat-add gw snat 100:65::1 1000::/64 +check m_as ovn-chassis-2 ovn-nbctl lr-nat-add gw snat 100.65.0.5 192.168.100.0/24 +check m_as ovn-chassis-2 ovn-nbctl lr-nat-add gw snat 100:65::5 1000::/64 + +# Add peer ports between GW and TR +check m_as ovn-chassis-1 ovn-nbctl lrp-add gw gw-tr 00:00:00:00:30:01 100.65.0.1/30 100:65::1/126 peer=tr-gw +check m_as ovn-chassis-1 ovn-nbctl lrp-add tr tr-gw 00:00:00:00:30:02 100.65.0.2/30 100:65::2/126 peer=gw-tr + +check m_as ovn-chassis-2 ovn-nbctl lrp-add gw gw-tr 00:00:00:00:30:05 100.65.0.5/30 100:65::5/126 peer=tr-gw +check m_as ovn-chassis-2 ovn-nbctl lrp-add tr tr-gw 00:00:00:00:30:06 100.65.0.6/30 100:65::6/126 peer=gw-tr + +# Add routes for the TS subnet +check m_as ovn-chassis-1 ovn-nbctl lr-route-add gw 10.100.200.0/24 100.65.0.2 +check m_as ovn-chassis-1 ovn-nbctl lr-route-add gw 10:200::/64 100:65::2 +check m_as ovn-chassis-2 ovn-nbctl lr-route-add gw 10.100.200.0/24 100.65.0.6 +check m_as ovn-chassis-2 ovn-nbctl lr-route-add gw 10:200::/64 100:65::6 + +# Add mutual remote ports +check m_as ovn-chassis-1 ovn-nbctl lrp-add tr tr-az2 00:00:00:00:30:06 100.65.0.6/30 100:65::6/126 +check m_as ovn-chassis-1 ovn-nbctl set logical_router_port tr-az2 options:requested-chassis=ovn-chassis-2 + +check m_as ovn-chassis-2 ovn-nbctl lrp-add tr tr-az1 00:00:00:00:30:02 100.65.0.2/30 100:65::2/126 +check m_as ovn-chassis-2 ovn-nbctl set logical_router_port tr-az1 options:requested-chassis=ovn-chassis-1 + +# Important set the proper tunnel keys +check m_as ovn-chassis-1 ovn-nbctl set logical_router_port tr-gw options:requested-tnl-key=10 +check m_as ovn-chassis-1 ovn-nbctl set logical_router_port tr-az2 options:requested-tnl-key=20 + +check m_as ovn-chassis-2 ovn-nbctl set logical_router_port tr-gw options:requested-tnl-key=20 +check m_as ovn-chassis-2 ovn-nbctl set logical_router_port tr-az1 options:requested-tnl-key=10 + +check m_as ovn-chassis-1 ovn-nbctl lsp-add public external +check m_as ovn-chassis-1 ovn-nbctl lsp-set-addresses external "00:00:00:00:20:10 192.168.100.10 1000::10" + +# Add mutual chassis +check m_as ovn-chassis-1 ovn-sbctl chassis-add ovn-chassis-2 geneve $(m_as ovn-chassis-2 ip -4 addr show eth1 | grep inet | awk '{print $2}' | cut -d'/' -f1) +check m_as ovn-chassis-1 ovn-sbctl set chassis ovn-chassis-2 other_config:is-remote=true + +check m_as ovn-chassis-2 ovn-sbctl chassis-add ovn-chassis-1 geneve $(m_as ovn-chassis-1 ip -4 addr show eth1 | grep inet | awk '{print $2}' | cut -d'/' -f1) +check m_as ovn-chassis-2 ovn-sbctl set chassis ovn-chassis-1 other_config:is-remote=true + +# Configure ports on the transit switch as remotes +check m_as ovn-chassis-1 ovn-nbctl lsp-set-type pod20 remote +check m_as ovn-chassis-1 ovn-nbctl lsp-set-options pod10 requested-chassis=ovn-chassis-1 +check m_as ovn-chassis-1 ovn-nbctl lsp-set-options pod20 requested-chassis=ovn-chassis-2 + +check m_as ovn-chassis-2 ovn-nbctl lsp-set-type pod10 remote +check m_as ovn-chassis-2 ovn-nbctl lsp-set-options pod10 requested-chassis=ovn-chassis-1 +check m_as ovn-chassis-2 ovn-nbctl lsp-set-options pod20 requested-chassis=ovn-chassis-2 + +m_as ovn-chassis-1 /data/create_fake_vm.sh external external 00:00:00:00:20:10 1500 192.168.100.10 24 192.168.100.1 1000::10/64 1000::1 +m_as ovn-chassis-1 /data/create_fake_vm.sh pod10 pod10 00:00:00:00:10:10 1500 10.100.200.10 24 10.100.200.1 10:200::10/64 10:200::1 +m_as ovn-chassis-2 /data/create_fake_vm.sh pod20 pod20 00:00:00:00:10:20 1500 10.100.200.20 24 10.100.200.1 10:200::20/64 10:200::1 + +# We cannot use any of the helpers as they assume that there is only single ovn-northd instance running +check m_as ovn-chassis-1 ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([test -n "$(m_as ovn-chassis-1 ovn-sbctl --bare --columns _uuid find Port_Binding logical_port=external up=true)"]) +OVS_WAIT_UNTIL([test -n "$(m_as ovn-chassis-1 ovn-sbctl --bare --columns _uuid find Port_Binding logical_port=pod10 up=true)"]) +check m_as ovn-chassis-2 ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([test -n "$(m_as ovn-chassis-2 ovn-sbctl --bare --columns _uuid find Port_Binding logical_port=pod20 up=true)"]) + +M_NS_CHECK_EXEC([ovn-chassis-1], [external], [ping -q -c 5 -i 0.3 -w 2 10.100.200.20 | FORMAT_PING], \ +[0], [dnl +5 packets transmitted, 5 received, 0% packet loss, time 0ms +]) + +M_NS_CHECK_EXEC([ovn-chassis-1], [external], [ping -q -c 5 -i 0.3 -w 2 10:200::20 | FORMAT_PING], \ +[0], [dnl +5 packets transmitted, 5 received, 0% packet loss, time 0ms +]) + +echo "Chassis1" +m_as ovn-chassis-1 ovn-sbctl show +m_as ovn-chassis-1 ovn-nbctl show +m_as ovn-chassis-1 ovs-vsctl show + +echo "Chassis2" +m_as ovn-chassis-2 ovn-sbctl show +m_as ovn-chassis-2 ovn-nbctl show +m_as ovn-chassis-2 ovs-vsctl show + +# Connect the chassis back to the original northd and remove northd per chassis. +for i in 1 2; do + chassis="ovn-chassis-$i" + ip=$(m_as $chassis ip -4 addr show eth1 | grep inet | awk '{print $2}' | cut -d'/' -f1) + + multinode_setup_controller $chassis $chassis $ip "170.168.0.2" + multinode_cleanup_northd $chassis +done + +AT_CLEANUP diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index b2bb6e2d0..7c6f69975 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -3536,3 +3536,79 @@ AT_CHECK([grep -c "cookie=$lr1_peer_cookie," log_to_phy_flows], [0], [dnl OVN_CLEANUP([hv1]) AT_CLEANUP + +AT_SETUP([Remote chassis flood flows]) +ovn_start + +net_add n1 +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.11 24 geneve,vxlan,stt + +check ovs-vsctl set open . external_ids:ovn-is-interconn=true + +check ovn-sbctl chassis-add hv2 geneve 192.168.0.12 \ + -- set chassis hv2 other_config:is-remote=true + +check ovn-sbctl chassis-add hv3 stt 192.168.0.13 \ + -- set chassis hv3 other_config:is-remote=true + +check ovn-sbctl chassis-add hv4 vxlan 192.168.0.14 \ + -- set chassis hv4 other_config:is-remote=true + +check ovn-nbctl --wait=hv sync + +chassis_cookie() { + name=$1 + fetch_column chassis _uuid name=$name |\ + cut -d '-' -f 1 | tr -d '\n' | sed 's/^0\{0,8\}//' +} + +ovs-ofctl dump-flows --names --no-stats br-int table=OFTABLE_PHY_TO_LOG > phy_to_log_flows +ovs-ofctl dump-flows --names --no-stats br-int table=OFTABLE_FLOOD_REMOTE_CHASSIS > flood_flows + +# Check that we have all encap + output actions one by one because the order can change +# Geneve +AT_CHECK([grep -c 'move:OXM_OF_METADATA\[[0..23\]]->NXM_NX_TUN_ID\[[0..23\]],set_field:0->tun_metadata0,move:NXM_NX_REG14\[[0..14\]]->NXM_NX_TUN_METADATA0\[[16..30\]],output:"ovn-hv2-0"' flood_flows], [0], [dnl +1 +]) + +# STT +AT_CHECK([grep -c 'move:NXM_NX_REG14\[[0..14\]]->NXM_NX_TUN_ID\[[40..54\]],load:0->NXM_NX_TUN_ID\[[24..39\]],move:OXM_OF_METADATA\[[0..23\]]->NXM_NX_TUN_ID\[[0..23\]],output:"ovn-hv3-0"' flood_flows], [0], [dnl +1 +]) + +# VXLAN +AT_CHECK([grep -c 'move:NXM_NX_REG14\[[0..11\]]->NXM_NX_TUN_ID\[[12..23\]],move:OXM_OF_METADATA\[[0..11\]]->NXM_NX_TUN_ID\[[0..11\]],output:"ovn-hv4-0"' flood_flows], [0], [dnl +1 +]) + +AT_CHECK([grep -c "reg6=0x8000" flood_flows], [0], [dnl +1 +]) + +# Check ingress flows for ARP and ND NA +# Geneve +hv2_cookie="0x$(chassis_cookie hv2)" +AT_CHECK_UNQUOTED([grep "cookie=$hv2_cookie," phy_to_log_flows], [0], [dnl + cookie=$hv2_cookie, priority=120,arp,tun_metadata0=0,in_port="ovn-hv2-0",arp_op=2 actions=move:NXM_NX_TUN_ID[[0..23]]->OXM_OF_METADATA[[0..23]],move:NXM_NX_TUN_METADATA0[[16..30]]->NXM_NX_REG14[[0..14]],move:NXM_NX_TUN_METADATA0[[0..15]]->NXM_NX_REG15[[0..15]],resubmit(,OFTABLE_LOG_INGRESS_PIPELINE) + cookie=$hv2_cookie, priority=120,icmp6,tun_metadata0=0,in_port="ovn-hv2-0",icmp_type=136,icmp_code=0 actions=move:NXM_NX_TUN_ID[[0..23]]->OXM_OF_METADATA[[0..23]],move:NXM_NX_TUN_METADATA0[[16..30]]->NXM_NX_REG14[[0..14]],move:NXM_NX_TUN_METADATA0[[0..15]]->NXM_NX_REG15[[0..15]],resubmit(,OFTABLE_LOG_INGRESS_PIPELINE) +]) + +# STT +hv3_cookie="0x$(chassis_cookie hv3)" +AT_CHECK_UNQUOTED([grep "cookie=$hv3_cookie," phy_to_log_flows], [0], [dnl + cookie=$hv3_cookie, priority=120,icmp6,tun_id=0/0xffff000000,in_port="ovn-hv3-0",icmp_type=136,icmp_code=0 actions=move:NXM_NX_TUN_ID[[40..54]]->NXM_NX_REG14[[0..14]],move:NXM_NX_TUN_ID[[24..39]]->NXM_NX_REG15[[0..15]],move:NXM_NX_TUN_ID[[0..23]]->OXM_OF_METADATA[[0..23]],resubmit(,OFTABLE_LOG_INGRESS_PIPELINE) + cookie=$hv3_cookie, priority=120,arp,tun_id=0/0xffff000000,in_port="ovn-hv3-0",arp_op=2 actions=move:NXM_NX_TUN_ID[[40..54]]->NXM_NX_REG14[[0..14]],move:NXM_NX_TUN_ID[[24..39]]->NXM_NX_REG15[[0..15]],move:NXM_NX_TUN_ID[[0..23]]->OXM_OF_METADATA[[0..23]],resubmit(,OFTABLE_LOG_INGRESS_PIPELINE) +]) + +# VXLAN +hv4_cookie="0x$(chassis_cookie hv4)" +AT_CHECK_UNQUOTED([grep "cookie=$hv4_cookie," phy_to_log_flows], [0], [dnl + cookie=$hv4_cookie, priority=120,icmp6,in_port="ovn-hv4-0",icmp_type=136,icmp_code=0 actions=move:NXM_NX_TUN_ID[[12..23]]->NXM_NX_REG15[[0..11]],move:NXM_NX_TUN_ID[[0..11]]->OXM_OF_METADATA[[0..11]],resubmit(,OFTABLE_LOG_INGRESS_PIPELINE),resubmit(,OFTABLE_LOCAL_OUTPUT) + cookie=$hv4_cookie, priority=120,arp,in_port="ovn-hv4-0",arp_op=2 actions=move:NXM_NX_TUN_ID[[12..23]]->NXM_NX_REG15[[0..11]],move:NXM_NX_TUN_ID[[0..11]]->OXM_OF_METADATA[[0..11]],resubmit(,OFTABLE_LOG_INGRESS_PIPELINE),resubmit(,OFTABLE_LOCAL_OUTPUT) +]) + +OVN_CLEANUP([hv1]) +AT_CLEANUP diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at index efb333a47..dfe6240d8 100644 --- a/tests/ovn-macros.at +++ b/tests/ovn-macros.at @@ -1409,5 +1409,6 @@ m4_define([OFTABLE_CT_ZONE_LOOKUP], [80]) m4_define([OFTABLE_CT_ORIG_NW_DST_LOAD], [81]) m4_define([OFTABLE_CT_ORIG_IP6_DST_LOAD], [82]) m4_define([OFTABLE_CT_ORIG_TP_DST_LOAD], [83]) +m4_define([OFTABLE_FLOOD_REMOTE_CHASSIS], [84]) m4_define([OFTABLE_SAVE_INPORT_HEX], [m4_eval(OFTABLE_SAVE_INPORT, 16)]) diff --git a/tests/ovn.at b/tests/ovn.at index 2fdf1a88c..d1c317a8b 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -2279,6 +2279,12 @@ ct_tp_dst; ct_tp_dst(); Syntax error at `ct_tp_dst' expecting action. +flood_remote; + encodes as set_field:0x8000->reg6,resubmit(,OFTABLE_FLOOD_REMOTE_CHASSIS) + +flood_remote(); + Syntax error at `(' expecting `;'. + # Miscellaneous negative tests. ; Syntax error at `;'. @@ -35636,7 +35642,9 @@ check_default_flows() { # respectively and it's OK if they don't have a default action. # Tables 81, 82 and 83 are part of ct_nw_dst(), ct_ip6_dst() and ct_tp_dst() # actions respectively and its OK for them to not have default flows. - if test ${table} -eq 68 -o ${table} -eq 70 -o ${table} -eq 81 -o ${table} -eq 82 -o ${table} -eq 83; then + # Table 84 is part of flood_remote; action and its OK for + # it to not have default flows. + if test ${table} -eq 68 -o ${table} -eq 70 -o ${table} -eq 81 -o ${table} -eq 82 -o ${table} -eq 83 -o ${table} -eq 84; then continue; fi AT_CHECK([grep -qe "table=$table.* priority=0\(,metadata=0x\w*\)\? actions" oflows], [0], [ignore], [ignore], [echo "Table $table does not contain a default action"]) diff --git a/tests/test-ovn.c b/tests/test-ovn.c index 7954bb98a..c3463e4cf 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1379,6 +1379,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) .ct_nw_dst_load_table = OFTABLE_CT_ORIG_NW_DST_LOAD, .ct_ip6_dst_load_table = OFTABLE_CT_ORIG_IP6_DST_LOAD, .ct_tp_dst_load_table = OFTABLE_CT_ORIG_TP_DST_LOAD, + .flood_remote_table = OFTABLE_FLOOD_REMOTE_CHASSIS, .lflow_uuid.parts = { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd}, .dp_key = 0xabcdef, diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index 806bdf3d9..423245f3d 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -3453,6 +3453,9 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, break; case OVNACT_CT_ORIG_TP_DST: break; + case OVNACT_FLOOD_REMOTE: + ovntrace_node_append(super, OVNTRACE_NODE_OUTPUT, + "/* Flood to all remote chassis */"); } } ofpbuf_uninit(&stack);