On Mon, Jan 20, 2025 at 9:25 PM Lorenzo Bianconi < [email protected]> 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. > > Hi Ales, > > I think this patch is mostly fine, just a couple of nits inline. Moreover, > it > seems the CI fails applying the full series so I am not sure if the issue > is > actually due to the latest patch. > Hi Lorenzo, thank you for the review. The CI failure should be solved in v2, there was small change needed due to a rebase. > Regards, > Lorenzo > > > > > Signed-off-by: Ales Musil <[email protected]> > > --- > > 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)) { > > why does it have to be of the same type? > If it's not the same type we need to put the encap actions in because it's slightly different for each tunnel 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_<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 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 > > even if it is not strictly required in this case, I guess it is better to > use different IPs for gw-public port. > Makes sense, it's changed to use $i as the ending of the IP in v2. > > > + > > + 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); > > -- > > 2.47.0 > > > > > _______________________________________________ > > dev mailing list > > [email protected] > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > Thanks, Ales _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
