On 2/4/25 2:18 PM, Lorenzo Bianconi wrote:
>> 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 <[email protected]>
> 
> Acked-by: Lorenzo Bianconi <[email protected]> 
> 
>> ---
>> v3: Rebase on top of latest main.
>>     Fix the ARP loop.
>> v2: Rebase on top of latest main.
>>     Slightly adjust IP of GW in the multinode test.
>> ---
>>  controller/lflow.c        |   1 +
>>  controller/lflow.h        |   4 +
>>  controller/physical.c     | 198 +++++++++++++++++++++++++++++++++----
>>  include/ovn/actions.h     |   3 +
>>  lib/actions.c             |  17 ++++
>>  northd/northd.c           |  12 ++-
>>  tests/multinode-macros.at |  48 +++++++++
>>  tests/multinode.at        | 201 ++++++++++++++++++++++++++++++++++++++
>>  tests/ovn-controller.at   |  65 ++++++++++++
>>  tests/ovn-macros.at       |   1 +
>>  tests/ovn.at              |  10 +-
>>  tests/test-ovn.c          |   1 +
>>  tutorial/ovn-sandbox      |  24 ++---

I removed the accidental changes that were done to tutorial/ovn-sandbox.
 I assume all that was for debugging.

>>  utilities/ovn-trace.c     |   3 +
>>  14 files changed, 552 insertions(+), 36 deletions(-)
>>
>> diff --git a/controller/lflow.c b/controller/lflow.c
>> index 856261f40..5314449a0 100644
>> --- a/controller/lflow.c
>> +++ b/controller/lflow.c
>> @@ -896,6 +896,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 bbc97ee30..5d088302a 100644
>> --- a/controller/physical.c
>> +++ b/controller/physical.c
>> @@ -185,6 +185,84 @@ 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
>> +match_set_chassis_flood_remote(struct match *match, uint32_t index)
>> +{
>> +    match_init_catchall(match);
>> +    match_set_reg(match, MFF_REG6 - MFF_REG0, index);
>> +    /* Match if the packet wasn't already received from tunnel.
>> +     * This prevents from looping it back to the tunnel again. */
>> +    match_set_reg_masked(match, MFF_LOG_FLAGS - MFF_REG0, 0,
>> +                         MLF_RX_FROM_TUNNEL);
>> +}
>> +
>> +
>>  static void
>>  put_stack(enum mf_field_id field, struct ofpact_stack *stack)
>>  {
>> @@ -2367,6 +2445,105 @@ 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_set_chassis_flood_remote(&match, 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_load(1, MFF_LOG_FLAGS, MLF_RX_FROM_TUNNEL_BIT, 1,
>> +                 &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_set_chassis_flood_remote(&match, 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,
>> @@ -2531,24 +2708,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,
>> @@ -2800,5 +2960,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_<ENUM> 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 388846eff..14e86478f 100644
>> --- a/lib/actions.c
>> +++ b/lib/actions.c
>> @@ -5527,6 +5527,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)
>> @@ -5754,6 +5769,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 c4368646d..751e89863 100644
>> --- a/northd/northd.c
>> +++ b/northd/northd.c
>> @@ -13155,21 +13155,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);
>>  
>> @@ -13185,7 +13186,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 9602358aa..c1bd3123a 100644
>> --- a/tests/multinode.at
>> +++ b/tests/multinode.at
>> @@ -2575,3 +2575,204 @@ 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.2/24  │ 
>>   │
>> +#    │    │    1000::1/64     │        │     │        │    1000::2/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.$i/24 1000::$i/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
>> +])
>> +
>> +check test $(m_as ovn-chassis-1 grep -c "skipping output to input port" \
>> +    /var/log/openvswitch/ovs-vswitchd.log) -eq 0
>> +check test $(m_as ovn-chassis-2 grep -c "skipping output to input port" \
>> +    /var/log/openvswitch/ovs-vswitchd.log) -eq 0
>> +
>> +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 b1c57fc21..e208723bc 100644
>> --- a/tests/ovn-controller.at
>> +++ b/tests/ovn-controller.at
>> @@ -3646,3 +3646,68 @@ 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
>> +
>> +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 vxlan 192.168.0.14 \
>> +    -- set chassis hv3 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\}//'
>> +}

I changed this to use "ovn-debug uuid-to-cookie" instead.

>> +
>> +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
>> +])
>> +
>> +# 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-hv3-0"'
>>  flood_flows], [0], [dnl
>> +1
>> +])
>> +
>> +AT_CHECK([grep -c "reg6=0x8000" flood_flows], [0], [dnl
>> +1
>> +])
>> +
>> +AT_CHECK([grep -c "reg10=0/0x10000" 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=load:0x1->NXM_NX_REG10[[16]],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=load:0x1->NXM_NX_REG10[[16]],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)
>> +])
>> +
>> +# VXLAN
>> +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,in_port="ovn-hv3-0",icmp_type=136,icmp_code=0 
>> actions=load:0x1->NXM_NX_REG10[[16]],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=$hv3_cookie, priority=120,arp,in_port="ovn-hv3-0",arp_op=2 
>> actions=load:0x1->NXM_NX_REG10[[16]],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 7cbd01489..e5a132684 100644
>> --- a/tests/ovn-macros.at
>> +++ b/tests/ovn-macros.at
>> @@ -1434,5 +1434,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 8ecf1f6bf..8ad2ae596 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 `;'.
>> @@ -35676,7 +35682,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 b097ec084..0fec97e19 100644
>> --- a/tests/test-ovn.c
>> +++ b/tests/test-ovn.c
>> @@ -1385,6 +1385,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/tutorial/ovn-sandbox b/tutorial/ovn-sandbox
>> index ed334d1c3..f3d11fd9b 100755
>> --- a/tutorial/ovn-sandbox
>> +++ b/tutorial/ovn-sandbox
>> @@ -613,8 +613,8 @@ The backup database file is sandbox/${db}2.db
>>  backup_note=
>>  ovn_start_db nb "$nbdb_model" "$nbdb_servers" "$ovnnb_source"
>>  ovn_start_db sb "$sbdb_model" "$sbdb_servers" "$ovnsb_source"
>> -ovn_start_db ic_nb "$ic_nb_model" "$ic_nb_servers" "$ic_nb_schema"
>> -ovn_start_db ic_sb "$ic_sb_model" "$ic_sb_servers" "$ic_sb_schema"
>> +#ovn_start_db ic_nb "$ic_nb_model" "$ic_nb_servers" "$ic_nb_schema"
>> +#ovn_start_db ic_sb "$ic_sb_model" "$ic_sb_servers" "$ic_sb_schema"
>>  
>>  #Add a small delay to allow ovsdb-server to launch.
>>  sleep 0.1
>> @@ -637,8 +637,8 @@ rungdb $gdb_vswitchd $gdb_vswitchd_ex ovs-vswitchd 
>> --detach --no-chdir --pidfile
>>  
>>  run ovn-nbctl init
>>  run ovn-sbctl init
>> -run ovn-ic-nbctl init
>> -run ovn-ic-sbctl init
>> +#run ovn-ic-nbctl init
>> +#run ovn-ic-sbctl init
>>  run ovn-nbctl set NB_Global . name=az-1
>>  
>>  run ovs-vsctl set open . external-ids:system-id=chassis-1
>> @@ -661,14 +661,14 @@ else
>>      run ovs-vsctl set open . external-ids:ovn-remote=$OVN_SB_DB
>>      OVN_CTRLR_PKI=""
>>  fi
>> -for i in $(seq $n_ics); do
>> -    if [ $i -eq 1 ]; then inst=""; else inst=$i; fi
>> -    rungdb $gdb_ovn_ic $gdb_ovn_ic_ex ovn-ic --detach \
>> -            --no-chdir --pidfile=ovn-ic${inst}.pid -vconsole:off \
>> -            --log-file=ovn-ic${inst}.log -vsyslog:off \
>> -            --ovnsb-db="$OVN_SB_DB" --ovnnb-db="$OVN_NB_DB" \
>> -            --ic-sb-db="$OVN_IC_SB_DB" --ic-nb-db="$OVN_IC_NB_DB"
>> -done
>> +#for i in $(seq $n_ics); do
>> +#    if [ $i -eq 1 ]; then inst=""; else inst=$i; fi
>> +#    rungdb $gdb_ovn_ic $gdb_ovn_ic_ex ovn-ic --detach \
>> +#            --no-chdir --pidfile=ovn-ic${inst}.pid -vconsole:off \
>> +#            --log-file=ovn-ic${inst}.log -vsyslog:off \
>> +#            --ovnsb-db="$OVN_SB_DB" --ovnnb-db="$OVN_NB_DB" \
>> +#            --ic-sb-db="$OVN_IC_SB_DB" --ic-nb-db="$OVN_IC_NB_DB"
>> +#done
>>  
>>  northd_args=
>>  OVN_NORTHD=ovn-northd
>> diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
>> index bd31cdbf5..d25c612c7 100644
>> --- a/utilities/ovn-trace.c
>> +++ b/utilities/ovn-trace.c
>> @@ -3460,6 +3460,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);
>> -- 

Thanks, Ales, Lorenzo and Quique.  I added Quique's "Tested-by" [0] and
pushed this patch to main.

Regards,
Dumitru

[0] https://mail.openvswitch.org/pipermail/ovs-dev/2025-February/420423.html

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to