On 3/4/25 12:41 PM, Ales Musil wrote:
> The option activation-strategy supported only "rarp", add "garp" and
> "na" to supported protocols. At the same time change to option to
> accept comma separated list, which allows CMS to set any combination
> of the supported protocols for activation.
> 
> Reported-at: https://issues.redhat.com/browse/FDP-1042
> Signed-off-by: Ales Musil <[email protected]>
> ---

Hi Ales,

Thanks for the patch!

>  NEWS                  |   3 +
>  controller/physical.c | 191 ++++++++++++++++++-----
>  ovn-nb.xml            |  10 +-
>  ovn-sb.xml            |  17 +-
>  tests/ovn.at          | 355 ++++++++++++++++++++++--------------------
>  5 files changed, 364 insertions(+), 212 deletions(-)
> 
> diff --git a/NEWS b/NEWS
> index 455fc12b6..1243c47ec 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -1,5 +1,8 @@
>  Post v25.03.0
>  -------------
> +  - Add additional protocol support for options:activation-strategy. The new
> +    supported protocols are gARP and NA. The option now supports comma
> +    separated to specify selected group of protocols.
>  
>  OVN v25.03.0 - xx xxx xxxx
>  --------------------------
> diff --git a/controller/physical.c b/controller/physical.c
> index 69bf05347..6737e812c 100644
> --- a/controller/physical.c
> +++ b/controller/physical.c
> @@ -1228,33 +1228,124 @@ enum access_type {
>      PORT_HA_REMOTE,
>  };
>  
> +enum activation_strategy {
> +    ACTIVATION_RARP = 1 << 0,
> +    ACTIVATION_GARP = 1 << 1,
> +    ACTIVATION_NA = 1 << 2,
> +    ACTIVATION_IP4 = ACTIVATION_GARP | ACTIVATION_RARP,
> +    ACTIVATION_IP6 = ACTIVATION_NA,
> +};
> +
>  static void
> -setup_rarp_activation_strategy(const struct sbrec_port_binding *binding,
> -                               ofp_port_t ofport, struct zone_ids *zone_ids,
> -                               struct ovn_desired_flow_table *flow_table)
> +setup_arp_activation_strategy(const struct sbrec_port_binding *binding,
> +                              ofp_port_t  ofport, struct zone_ids *zone_ids,
> +                              struct ofpbuf *ofpacts, struct eth_addr mac,
> +                              ovs_be32 ip, bool arp,
> +                              struct ovn_desired_flow_table *flow_table)
>  {
>      struct match match = MATCH_CATCHALL_INITIALIZER;
> -    uint64_t stub[1024 / 8];
> -    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
>  
> -    /* Unblock the port on ingress RARP. */
> -    match_set_dl_type(&match, htons(ETH_TYPE_RARP));
> +    /* match: arp/rarp, in_port=<OFPORT>, dl_src=<MAC>, arp_sha=<MAC>,
> +     * arp_spa=<IP>, arp_tpa=<IP> */
> +    match_set_dl_type(&match, htons(arp ? ETH_TYPE_ARP : ETH_TYPE_RARP));
>      match_set_in_port(&match, ofport);
> +    match_set_dl_src(&match, mac);
> +    match_set_arp_sha(&match, mac);
> +    match_set_arp_spa_masked(&match, ip, OVS_BE32_MAX);
> +    match_set_arp_tpa_masked(&match, ip, OVS_BE32_MAX);
>  
> -    load_logical_ingress_metadata(binding, zone_ids, 0, NULL, &ofpacts, 
> true);
> -
> +    load_logical_ingress_metadata(binding, zone_ids, 0, NULL, ofpacts, true);
> +    /* Unblock the traffic when it matches specified strategy. */
>      encode_controller_op(ACTION_OPCODE_ACTIVATION_STRATEGY_RARP,
> -                         NX_CTLR_NO_METER, &ofpacts);
> +                         NX_CTLR_NO_METER, ofpacts);
> +    put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts);
>  
> -    put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts);
> +    ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 1010,
> +                    binding->header_.uuid.parts[0],
> +                    &match, ofpacts, &binding->header_.uuid);
> +    ofpbuf_clear(ofpacts);
> +}
> +
> +static void
> +setup_nd_na_activation_strategy(const struct sbrec_port_binding *binding,
> +                                ofp_port_t  ofport, struct zone_ids 
> *zone_ids,
> +                                struct ofpbuf *ofpacts, struct eth_addr mac,
> +                                const struct in6_addr *ip,
> +                                struct ovn_desired_flow_table *flow_table)
> +{
> +    struct match match = MATCH_CATCHALL_INITIALIZER;
> +
> +    /* match: icmp6, in_port=<OFPORT>, icmp_type=136, icmp_code=0,
> +     * ipv6_src=<IP>, nd_target=<IP>, nd_tll=<MAC> */
> +    match_set_dl_type(&match, htons(ETH_TYPE_IPV6));
> +    match_set_in_port(&match, ofport);
> +    match_set_nw_proto(&match, IPPROTO_ICMPV6);
> +    match_set_icmp_type(&match, 136);
> +    match_set_icmp_code(&match, 0);
> +    match_set_ipv6_src(&match, ip);
> +    match_set_nd_target(&match, ip);
> +    match_set_arp_tha(&match, mac);

This confused me a bit.. it's because arp_tha and nd_tll are the same
thing in OVS and because there's no match_set_nd_tll().

> +
> +    load_logical_ingress_metadata(binding, zone_ids, 0, NULL, ofpacts, true);
> +    /* Unblock the traffic when it matches specified strategy. */
> +    encode_controller_op(ACTION_OPCODE_ACTIVATION_STRATEGY_RARP,

Nit: this looks a bit weird to me, we're setting up an ND_NA activation
strategy but we're using the ACTION_OPCODE_ACTIVATION_STRATEGY_RARP
opcode.  I understand why it works but I think I'd just rename:

/* activation_strategy_rarp() */
ACTION_OPCODE(ACTIVATION_STRATEGY_RARP)

to

/* activation_strategy() */
ACTION_OPCODE(ACTIVATION_STRATEGY)

and while at it rename the pinctrl_rarp_activation_strategy_handler()
function to pinctrl_activation_strategy_handler() as it's really
protocol independent; it only reads the logical ingress port and
datapath from the flow.

> +                         NX_CTLR_NO_METER, ofpacts);
> +    put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts);
>  
>      ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 1010,
>                      binding->header_.uuid.parts[0],
> -                    &match, &ofpacts, &binding->header_.uuid);
> -    ofpbuf_clear(&ofpacts);
> +                    &match, ofpacts, &binding->header_.uuid);
> +    ofpbuf_clear(ofpacts);
> +}
> +
> +static void
> +setup_activation_strategy_flows(const struct sbrec_port_binding *binding,
> +                                ofp_port_t ofport, struct zone_ids *zone_ids,
> +                                uint32_t activation_strategies,
> +                                const struct lport_addresses *addresses,
> +                                struct ovn_desired_flow_table *flow_table)
> +{
> +    uint64_t stub[1024 / 8];
> +    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
> +
> +    bool ip4_activation = (activation_strategies & ACTIVATION_IP4) != 0;
> +    bool ip6_activation = (activation_strategies & ACTIVATION_IP6) != 0;
> +
> +    for (size_t i = 0; ip4_activation && i < addresses->n_ipv4_addrs; i++) {
> +        const struct ipv4_netaddr *address = &addresses->ipv4_addrs[i];
> +        if (activation_strategies & ACTIVATION_GARP) {
> +            setup_arp_activation_strategy(binding, ofport, zone_ids, 
> &ofpacts,
> +                                          addresses->ea, address->addr, true,
> +                                          flow_table);
> +        }
> +
> +        if (activation_strategies & ACTIVATION_RARP) {
> +            setup_arp_activation_strategy(binding, ofport, zone_ids, 
> &ofpacts,
> +                                          addresses->ea, address->addr, 
> false,
> +                                          flow_table);
> +        }

I'm afraid this will potentially break live migration with
activation_strategy=rarp for the case when it's used for logical switch
ports that either:
- have "unknown" addresses
- only have a MAC address configured (no IPv4 address).

We should probably maintain the old behavior, i.e., if
activation-strategy includes "rarp" then activate the port on any RARP
received on the LSP VIF.

> +    }
> +
> +    /* Always add LLA address activation if there is any IPv6 address. */
> +    if (ip6_activation && addresses->n_ipv6_addrs) {
> +        struct in6_addr lla;
> +        in6_generate_lla(addresses->ea, &lla);
> +
> +        setup_nd_na_activation_strategy(binding, ofport, zone_ids, &ofpacts,
> +                                        addresses->ea, &lla, flow_table);
> +    }
> +
> +    for (size_t i = 0; ip6_activation && i < addresses->n_ipv6_addrs; i++) {
> +        const struct ipv6_netaddr *address = &addresses->ipv6_addrs[i];
> +        if (activation_strategies & ACTIVATION_NA) {
> +            setup_nd_na_activation_strategy(binding, ofport, zone_ids,
> +                                            &ofpacts, addresses->ea,
> +                                            &address->addr, flow_table);
> +        }
> +    }
>  
>      /* Block all non-RARP traffic for the port, both directions. */
> -    match_init_catchall(&match);
> +    struct match match = MATCH_CATCHALL_INITIALIZER;
>      match_set_in_port(&match, ofport);
>  
>      ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 1000,
> @@ -1274,6 +1365,36 @@ setup_rarp_activation_strategy(const struct 
> sbrec_port_binding *binding,
>      ofpbuf_uninit(&ofpacts);
>  }
>  
> +static uint32_t
> +pb_parse_activation_strategy(const struct sbrec_port_binding *pb)
> +{
> +    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +    uint32_t strategies = 0;
> +
> +    const char *strategy = smap_get(&pb->options, "activation-strategy");
> +    if (strategy) {
> +        char *save_ptr;
> +        char *tokstr = xstrdup(strategy);
> +        for (const char *name = strtok_r(tokstr, ",", &save_ptr);
> +             name != NULL;
> +             name = strtok_r(NULL, ",", &save_ptr)) {
> +            if (!strcmp(name, "rarp")) {
> +                strategies |= ACTIVATION_RARP;
> +            } else if (!strcmp(name, "garp")) {
> +                strategies |= ACTIVATION_GARP;
> +            } else if (!strcmp(name, "na")) {
> +                strategies |= ACTIVATION_NA;
> +            } else {
> +                VLOG_WARN_RL(&rl, "Unknown activation strategy defined for "
> +                             "port %s: %s", pb->logical_port, name);
> +            }
> +        }
> +        free(tokstr);
> +    }
> +
> +    return strategies;
> +}
> +
>  static void
>  setup_activation_strategy(const struct sbrec_port_binding *binding,
>                            const struct sbrec_chassis *chassis,
> @@ -1281,28 +1402,28 @@ setup_activation_strategy(const struct 
> sbrec_port_binding *binding,
>                            ofp_port_t ofport, struct zone_ids *zone_ids,
>                            struct ovn_desired_flow_table *flow_table)
>  {
> -    for (size_t i = 0; i < binding->n_additional_chassis; i++) {
> -        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> -        if (binding->additional_chassis[i] == chassis) {
> -            const char *strategy = smap_get(&binding->options,
> -                                            "activation-strategy");
> -            if (strategy
> -                    && !lport_is_activated_by_activation_strategy(binding,
> -                                                                  chassis)
> -                    && !pinctrl_is_port_activated(dp_key, port_key)) {
> -                if (!strcmp(strategy, "rarp")) {
> -                    setup_rarp_activation_strategy(binding, ofport,
> -                                                   zone_ids, flow_table);
> -                } else {
> -                    VLOG_WARN_RL(&rl,
> -                                 "Unknown activation strategy defined for "
> -                                 "port %s: %s",
> -                                 binding->logical_port, strategy);
> -                    return;
> -                }
> -            }
> -            return;
> +    if (!is_additional_chassis(binding, chassis)) {
> +        return;
> +    }
> +
> +    if (lport_is_activated_by_activation_strategy(binding, chassis) ||
> +        pinctrl_is_port_activated(dp_key, port_key)) {
> +        return;
> +    }
> +
> +    uint32_t strategies = pb_parse_activation_strategy(binding);
> +    if (!strategies) {
> +        return;
> +    }
> +
> +    for (size_t i = 0; i < binding->n_mac; i++) {
> +        struct lport_addresses addresses;
> +        if (!extract_lsp_addresses(binding->mac[i], &addresses)) {
> +            continue;
>          }
> +        setup_activation_strategy_flows(binding, ofport, zone_ids, 
> strategies,
> +                                        &addresses, flow_table);
> +        destroy_lport_addresses(&addresses);
>      }
>  }
>  
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 3ab514651..48f00632a 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -1360,10 +1360,12 @@
>            <ref column="requested-chassis"/>, specifies an activation strategy
>            for all additional chassis. By default, no activation strategy is
>            used, meaning additional port locations are immediately available 
> for
> -          use. When set to "rarp", the port is blocked for ingress and egress
> -          communication until a RARP packet is sent from a new location. The
> -          "rarp" strategy is useful in live migration scenarios for virtual
> -          machines.
> +          use. The option supports comma separated list where you can combine

Nit: "a comma separated list".

> +          3 protocols, "rarp", "garp" and "na". When any of the protocols is
> +          set, the port is blocked for ingress and egress communication until
> +          a specified protocol packet is sent from a new location. The
> +          activation strategy is useful in live migration scenarios for
> +          virtual machines.
>          </column>
>  
>          <column name="options" key="iface-id-ver">
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index 39acb81a4..072c88ddb 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -3784,13 +3784,16 @@ tcp.flags = RST;
>        </column>
>  
>        <column name="options" key="activation-strategy">
> -        If used with multiple chassis set in <ref 
> column="requested-chassis"/>,
> -        specifies an activation strategy for all additional chassis. By
> -        default, no activation strategy is used, meaning additional port
> -        locations are immediately available for use. When set to "rarp", the
> -        port is blocked for ingress and egress communication until a RARP
> -        packet is sent from a new location. The "rarp" strategy is useful
> -        in live migration scenarios for virtual machines.
> +        If used with multiple chassis set in
> +        <ref column="requested-chassis"/>, specifies an activation strategy
> +        for all additional chassis. By default, no activation strategy is
> +        used, meaning additional port locations are immediately available for
> +        use. The option supports comma separated list where you can combine

Nit: "a comma separated list".

> +        3 protocols, "rarp", "garp" and "na". When any of the protocols is
> +        set, the port is blocked for ingress and egress communication until
> +        a specified protocol packet is sent from a new location. The
> +        activation strategy is useful in live migration scenarios for
> +        virtual machines.
>        </column>
>  
>        <column name="options" key="additional-chassis-activated">
> diff --git a/tests/ovn.at b/tests/ovn.at
> index ec8ee8de7..ad31d8482 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -5428,7 +5428,7 @@ test_arp() {
>  test_na() {
>      local inport=$1 sha=$2 spa=$3 src=${4-$3}
>      local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${sha}')/ \
> -                             IPv6(dst='ff01::1', src='${src}')/ \
> +                             IPv6(dst='ff02::1', src='${src}')/ \

Is this an accidental change?  We don't use test_na() in the activation
strategy tests.  Or am I missing something?

>                               ICMPv6ND_NA(tgt='${spa}')/ \
>                               ICMPv6NDOptDstLLAddr(lladdr='${sha}')")
>  
> @@ -16487,205 +16487,228 @@ MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv6], 
> [geneve], [1404])
>  MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv4], [vxlan], [1432])
>  MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv6], [vxlan], [1412])
>  
> -OVN_FOR_EACH_NORTHD([
> -AT_SETUP([options:activation-strategy for logical port])
> -AT_KEYWORDS([multi-chassis])
> -AT_KEYWORDS([slowtest])
> -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
> -
> -sim_add hv2
> -as hv2
> -check ovs-vsctl add-br br-phys
> -ovn_attach n1 br-phys 192.168.0.12
> -
> -sim_add hv3
> -as hv3
> -check ovs-vsctl add-br br-phys
> -ovn_attach n1 br-phys 192.168.0.13
> -
> -# Disable local ARP responder to pass ARP requests through tunnels
> -check ovn-nbctl ls-add ls0 -- add Logical_Switch ls0 other_config 
> vlan-passthru=true
> -
> -check ovn-nbctl lsp-add ls0 migrator
> -check ovn-nbctl lsp-set-options migrator requested-chassis=hv1,hv2 \
> -                                         activation-strategy=rarp
> -
> -check ovn-nbctl lsp-add ls0 first
> -check ovn-nbctl lsp-set-options first requested-chassis=hv1
> -check ovn-nbctl lsp-add ls0 second
> -check ovn-nbctl lsp-set-options second requested-chassis=hv2
> -check ovn-nbctl lsp-add ls0 outside
> -check ovn-nbctl lsp-set-options outside requested-chassis=hv3
> -
> -check ovn-nbctl lsp-set-addresses migrator "00:00:00:00:00:10 10.0.0.10"
> -check ovn-nbctl lsp-set-addresses first "00:00:00:00:00:01 10.0.0.1"
> -check ovn-nbctl lsp-set-addresses second "00:00:00:00:00:02 10.0.0.2"
> -check ovn-nbctl lsp-set-addresses outside "00:00:00:00:00:03 10.0.0.3"
> -
> -for hv in hv1 hv2; do
> -    as $hv check ovs-vsctl -- add-port br-int migrator -- \
> -        set Interface migrator external-ids:iface-id=migrator \
> -                               options:tx_pcap=$hv/migrator-tx.pcap \
> -                               options:rxq_pcap=$hv/migrator-rx.pcap
> -done
> -
> -as hv1 check ovs-vsctl -- add-port br-int first -- \
> -    set Interface first external-ids:iface-id=first
> -as hv2 check ovs-vsctl -- add-port br-int second -- \
> -    set Interface second external-ids:iface-id=second
> -as hv3 check ovs-vsctl -- add-port br-int outside -- \
> -    set Interface outside external-ids:iface-id=outside
> -
> -for hv in hv1 hv2 hv3; do
> -    wait_row_count Chassis 1 name=$hv
> -done
> -hv1_uuid=$(fetch_column Chassis _uuid name=hv1)
> -hv2_uuid=$(fetch_column Chassis _uuid name=hv2)
> -hv3_uuid=$(fetch_column Chassis _uuid name=hv3)
> +m4_define([ACTIVATION_STRATEGY_TEST],
> +  [OVN_FOR_EACH_NORTHD([
> +    AT_SETUP([options:activation-strategy=$1 for logical port])
> +    AT_KEYWORDS([multi-chassis])
> +    AT_KEYWORDS([slowtest])
> +    AT_SKIP_IF([test $HAVE_SCAPY = no])
> +    ovn_start
>  
> -wait_column "$hv1_uuid" Port_Binding chassis logical_port=migrator
> -wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=migrator
> -wait_column "$hv2_uuid" Port_Binding additional_chassis logical_port=migrator
> -wait_column "$hv2_uuid" Port_Binding requested_additional_chassis 
> logical_port=migrator
> +    net_add n1
>  
> -wait_column "$hv1_uuid" Port_Binding chassis logical_port=first
> -wait_column "$hv2_uuid" Port_Binding chassis logical_port=second
> -wait_column "$hv3_uuid" Port_Binding chassis logical_port=outside
> -
> -OVN_POPULATE_ARP
> +    sim_add hv1
> +    as hv1
> +    check ovs-vsctl add-br br-phys
> +    ovn_attach n1 br-phys 192.168.0.11
>  
> -send_arp() {
> -    local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6
> -    local 
> request=${eth_dst}${eth_src}08060001080006040001${eth_src}${spa}${eth_dst}${tpa}
> -    as ${hv} ovs-appctl netdev-dummy/receive $inport $request
> -    echo "${request}"
> -}
> +    sim_add hv2
> +    as hv2
> +    check ovs-vsctl add-br br-phys
> +    ovn_attach n1 br-phys 192.168.0.12
>  
> -send_rarp() {
> -    local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6
> -    local 
> request=${eth_dst}${eth_src}80350001080006040001${eth_src}${spa}${eth_dst}${tpa}
> -    as ${hv} ovs-appctl netdev-dummy/receive $inport $request
> -    echo "${request}"
> -}
> +    sim_add hv3
> +    as hv3
> +    check ovs-vsctl add-br br-phys
> +    ovn_attach n1 br-phys 192.168.0.13
> +
> +    # Disable local ARP responder to pass ARP requests through tunnels
> +    check ovn-nbctl ls-add ls0 -- add Logical_Switch ls0 other_config 
> vlan-passthru=true
> +
> +    check ovn-nbctl lsp-add ls0 migrator
> +    check ovn-nbctl lsp-set-options migrator requested-chassis=hv1,hv2 \
> +                                             activation-strategy=$1
> +
> +    check ovn-nbctl lsp-add ls0 first
> +    check ovn-nbctl lsp-set-options first requested-chassis=hv1
> +    check ovn-nbctl lsp-add ls0 second
> +    check ovn-nbctl lsp-set-options second requested-chassis=hv2
> +    check ovn-nbctl lsp-add ls0 outside
> +    check ovn-nbctl lsp-set-options outside requested-chassis=hv3
> +
> +    check ovn-nbctl lsp-set-addresses migrator "00:00:00:00:00:10 10.0.0.10 
> fd10::10"
> +    check ovn-nbctl lsp-set-addresses first "00:00:00:00:00:01 10.0.0.1"
> +    check ovn-nbctl lsp-set-addresses second "00:00:00:00:00:02 10.0.0.2"
> +    check ovn-nbctl lsp-set-addresses outside "00:00:00:00:00:03 10.0.0.3"
> +
> +    for hv in hv1 hv2; do
> +        as $hv check ovs-vsctl -- add-port br-int migrator -- \
> +            set Interface migrator external-ids:iface-id=migrator \
> +                                   options:tx_pcap=$hv/migrator-tx.pcap \
> +                                   options:rxq_pcap=$hv/migrator-rx.pcap
> +    done
>  
> -reset_env() {
> -    as hv1 reset_pcap_file migrator hv1/migrator
> -    as hv2 reset_pcap_file migrator hv2/migrator
> -    as hv1 reset_pcap_file first hv1/first
> -    as hv2 reset_pcap_file second hv2/second
> -    as hv3 reset_pcap_file outside hv3/outside
> +    as hv1 check ovs-vsctl -- add-port br-int first -- \
> +        set Interface first external-ids:iface-id=first
> +    as hv2 check ovs-vsctl -- add-port br-int second -- \
> +        set Interface second external-ids:iface-id=second
> +    as hv3 check ovs-vsctl -- add-port br-int outside -- \
> +        set Interface outside external-ids:iface-id=outside
>  
> -    for port in hv1/migrator hv2/migrator hv1/first hv2/second hv3/outside; 
> do
> -        : > $port.expected
> +    for hv in hv1 hv2 hv3; do
> +        wait_row_count Chassis 1 name=$hv
>      done
> -}
> +    hv1_uuid=$(fetch_column Chassis _uuid name=hv1)
> +    hv2_uuid=$(fetch_column Chassis _uuid name=hv2)
> +    hv3_uuid=$(fetch_column Chassis _uuid name=hv3)
> +
> +    wait_column "$hv1_uuid" Port_Binding chassis logical_port=migrator
> +    wait_column "$hv1_uuid" Port_Binding requested_chassis 
> logical_port=migrator
> +    wait_column "$hv2_uuid" Port_Binding additional_chassis 
> logical_port=migrator
> +    wait_column "$hv2_uuid" Port_Binding requested_additional_chassis 
> logical_port=migrator
> +
> +    wait_column "$hv1_uuid" Port_Binding chassis logical_port=first
> +    wait_column "$hv2_uuid" Port_Binding chassis logical_port=second
> +    wait_column "$hv3_uuid" Port_Binding chassis logical_port=outside
> +
> +    OVN_POPULATE_ARP
> +
> +    send_arp() {
> +        local hv=${1} inport=${2} op=${3} eth_src=${4} eth_dst=${5} spa=${6} 
> tpa=${7}
> +        local request=$(fmt_pkt "Ether(dst='${eth_dst}', src='${eth_src}')/ \
> +                        ARP(op=${op}, hwsrc='${eth_src}', 
> hwdst='${eth_dst}', \
> +                        psrc='${spa}', pdst='${tpa}')")
> +        as ${hv} ovs-appctl netdev-dummy/receive $inport $request
> +        echo "${request}"
> +    }
> +
> +    send_rarp() {
> +        local hv=${1} inport=${2} eth_src=${3} spa=${4}
> +        local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', 
> src='${eth_src}', type=0x8035)/ \
> +                        ARP(op=1, hwsrc='${eth_src}', 
> hwdst='00:00:00:00:00:00', \
> +                        psrc='${spa}', pdst='${spa}')")
> +        as ${hv} ovs-appctl netdev-dummy/receive $inport $request
> +        echo "${request}"
> +    }
> +
> +    send_na() {
> +        local hv=${1} inport=${2} eth_src=${3} spa=${4}
> +        local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', 
> src='${eth_src}')/ \
> +                                 IPv6(dst='ff02::1', src='${spa}')/ \
> +                                 ICMPv6ND_NA(tgt='${spa}')/ \
> +                                 ICMPv6NDOptDstLLAddr(lladdr='${eth_src}')")
> +        as ${hv} ovs-appctl netdev-dummy/receive $inport $request
> +        echo "${request}"
> +    }
> +
> +
> +    reset_env() {
> +        as hv1 reset_pcap_file migrator hv1/migrator
> +        as hv2 reset_pcap_file migrator hv2/migrator
> +        as hv1 reset_pcap_file first hv1/first
> +        as hv2 reset_pcap_file second hv2/second
> +        as hv3 reset_pcap_file outside hv3/outside
> +
> +        for port in hv1/migrator hv2/migrator hv1/first hv2/second 
> hv3/outside; do
> +            : > $port.expected
> +        done
> +    }
>  
> -check_packets() {
> -    OVN_CHECK_PACKETS([hv1/migrator-tx.pcap], [hv1/migrator.expected])
> -    OVN_CHECK_PACKETS([hv2/migrator-tx.pcap], [hv2/migrator.expected])
> -    OVN_CHECK_PACKETS([hv3/outside-tx.pcap], [hv3/outside.expected])
> -    OVN_CHECK_PACKETS([hv1/first-tx.pcap], [hv1/first.expected])
> -    OVN_CHECK_PACKETS([hv2/second-tx.pcap], [hv2/second.expected])
> -}
> +    check_packets() {
> +        OVN_CHECK_PACKETS([hv1/migrator-tx.pcap], [hv1/migrator.expected])
> +        OVN_CHECK_PACKETS([hv2/migrator-tx.pcap], [hv2/migrator.expected])
> +        OVN_CHECK_PACKETS([hv3/outside-tx.pcap], [hv3/outside.expected])
> +        OVN_CHECK_PACKETS([hv1/first-tx.pcap], [hv1/first.expected])
> +        OVN_CHECK_PACKETS([hv2/second-tx.pcap], [hv2/second.expected])
> +    }
>  
> -migrator_spa=$(ip_to_hex 10 0 0 10)
> -first_spa=$(ip_to_hex 10 0 0 1)
> -second_spa=$(ip_to_hex 10 0 0 2)
> -outside_spa=$(ip_to_hex 10 0 0 3)
> +    reset_env
>  
> -reset_env
> +    # Packet from hv3:Outside arrives to hv1:Migrator
> +    # hv3:Outside cannot reach hv2:Migrator because it is blocked by 
> activation strategy
> +    request=$(send_arp hv3 outside 1 "00:00:00:00:00:03" "00:00:00:00:00:10" 
> "10.0.0.3" "10.0.0.10")
> +    echo $request >> hv1/migrator.expected
>  
> -# Packet from hv3:Outside arrives to hv1:Migrator
> -# hv3:Outside cannot reach hv2:Migrator because it is blocked by RARP 
> strategy
> -request=$(send_arp hv3 outside 000000000003 000000000010 $outside_spa 
> $migrator_spa)
> -echo $request >> hv1/migrator.expected
> +    # Packet from hv1:First arrives to hv1:Migrator
> +    # hv1:First cannot reach hv2:Migrator because it is blocked by 
> activation strategy
> +    request=$(send_arp hv1 first 1 "00:00:00:00:00:01" "00:00:00:00:00:10" 
> "10.0.0.1" "10.0.0.10")
> +    echo $request >> hv1/migrator.expected
>  
> -# Packet from hv1:First arrives to hv1:Migrator
> -# hv1:First cannot reach hv2:Migrator because it is blocked by RARP strategy
> -request=$(send_arp hv1 first 000000000001 000000000010 $first_spa 
> $migrator_spa)
> -echo $request >> hv1/migrator.expected
> +    # Packet from hv2:Second arrives to hv1:Migrator
> +    # hv2:Second cannot reach hv2:Migrator because it is blocked by 
> activation strategy
> +    request=$(send_arp hv2 second 1 "00:00:00:00:00:02" "00:00:00:00:00:10" 
> "10.0.0.2" "10.0.0.10")
> +    echo $request >> hv1/migrator.expected
>  
> -# Packet from hv2:Second arrives to hv1:Migrator
> -# hv2:Second cannot reach hv2:Migrator because it is blocked by RARP strategy
> -request=$(send_arp hv2 second 000000000002 000000000010 $second_spa 
> $migrator_spa)
> -echo $request >> hv1/migrator.expected
> +    check_packets
> +    reset_env
>  
> -check_packets
> -reset_env
> +    # Packet from hv1:Migrator arrives to hv3:Outside
> +    request=$(send_arp hv1 migrator 1 "00:00:00:00:00:10" 
> "00:00:00:00:00:03" "10.0.0.10" "10.0.0.3")
> +    echo $request >> hv3/outside.expected
>  
> -# Packet from hv1:Migrator arrives to hv3:Outside
> -request=$(send_arp hv1 migrator 000000000010 000000000003 $migrator_spa 
> $outside_spa)
> -echo $request >> hv3/outside.expected
> +    # Packet from hv1:Migrator arrives to hv1:First
> +    request=$(send_arp hv1 migrator 1 "00:00:00:00:00:10" 
> "00:00:00:00:00:01" "10.0.0.10" "10.0.0.1")
> +    echo $request >> hv1/first.expected
>  
> -# Packet from hv1:Migrator arrives to hv1:First
> -request=$(send_arp hv1 migrator 000000000010 000000000001 $migrator_spa 
> $first_spa)
> -echo $request >> hv1/first.expected
> +    # Packet from hv1:Migrator arrives to hv2:Second
> +    request=$(send_arp hv1 migrator 1 "00:00:00:00:00:10" 
> "00:00:00:00:00:02" "10.0.0.10" "10.0.0.2")
> +    echo $request >> hv2/second.expected
>  
> -# Packet from hv1:Migrator arrives to hv2:Second
> -request=$(send_arp hv1 migrator 000000000010 000000000002 $migrator_spa 
> $second_spa)
> -echo $request >> hv2/second.expected
> +    check_packets
> +    reset_env
>  
> -check_packets
> -reset_env
> +    # hv2:Migrator cannot reach to hv3:Outside because it is blocked by 
> activation strategy
> +    request=$(send_arp hv2 migrator 1 "00:00:00:00:00:10" 
> "00:00:00:00:00:03" "10.0.0.10" "10.0.0.3")
>  
> -# hv2:Migrator cannot reach to hv3:Outside because it is blocked by RARP 
> strategy
> -request=$(send_arp hv2 migrator 000000000010 000000000003 $migrator_spa 
> $outside_spa)
> +    check_packets
> +    reset_env
>  
> -check_packets
> -reset_env
> +    AT_CHECK([ovn-sbctl find port_binding logical_port=migrator | grep -q 
> additional-chassis-activated], [1])
>  
> -AT_CHECK([ovn-sbctl find port_binding logical_port=migrator | grep -q 
> additional-chassis-activated], [1])
> +    # Now activate hv2:Migrator location
> +    if [[ "$1" == "rarp" ]]; then
> +        request=$(send_rarp hv2 migrator "00:00:00:00:00:10" "10.0.0.10")
> +    elif [[ "$1" == "na" ]]; then
> +        request=$(send_na hv2 migrator "00:00:00:00:00:10" "fd10::10")
> +        echo $request
> +    else
> +        request=$(send_arp hv2 migrator 1 "00:00:00:00:00:10" 
> "ff:ff:ff:ff:ff:ff" "10.0.0.10" "10.0.0.10")
> +    fi
>  
> -# Now activate hv2:Migrator location
> -request=$(send_rarp hv2 migrator 000000000010 ffffffffffff $migrator_spa 
> $migrator_spa)
> +    # Activation packet was reinjected into the pipeline
> +    echo $request >> hv3/outside.expected
> +    echo $request >> hv1/first.expected
> +    echo $request >> hv2/second.expected
>  
> -# RARP was reinjected into the pipeline
> -echo $request >> hv3/outside.expected
> -echo $request >> hv1/first.expected
> -echo $request >> hv2/second.expected
> +    check_packets
> +    reset_env
>  
> -check_packets
> -reset_env
> +    pb_uuid=$(ovn-sbctl --bare --columns _uuid find Port_Binding 
> logical_port=migrator)
> +    OVS_WAIT_UNTIL([test xhv2 = x$(ovn-sbctl get Port_Binding $pb_uuid 
> options:additional-chassis-activated | tr -d '""')])
>  
> -pb_uuid=$(ovn-sbctl --bare --columns _uuid find Port_Binding 
> logical_port=migrator)
> -OVS_WAIT_UNTIL([test xhv2 = x$(ovn-sbctl get Port_Binding $pb_uuid 
> options:additional-chassis-activated | tr -d '""')])
> +    # Now packet arrives to both locations
> +    request=$(send_arp hv3 outside 1 "00:00:00:00:00:03" "00:00:00:00:00:10" 
> "10.0.0.3" "10.0.0.10")
> +    echo $request >> hv1/migrator.expected
> +    echo $request >> hv2/migrator.expected
>  
> -# Now packet arrives to both locations
> -request=$(send_arp hv3 outside 000000000003 000000000010 $outside_spa 
> $migrator_spa)
> -echo $request >> hv1/migrator.expected
> -echo $request >> hv2/migrator.expected
> +    check_packets
> +    reset_env
>  
> -check_packets
> -reset_env
> +    # Packet from hv1:Migrator still arrives to hv3:Outside
> +    request=$(send_arp hv1 migrator 1 "00:00:00:00:00:10" 
> "00:00:00:00:00:03" "10.0.0.10" "10.0.0.3")
> +    echo $request >> hv3/outside.expected
>  
> -# Packet from hv1:Migrator still arrives to hv3:Outside
> -request=$(send_arp hv1 migrator 000000000010 000000000003 $migrator_spa 
> $outside_spa)
> -echo $request >> hv3/outside.expected
> +    check_packets
> +    reset_env
>  
> -check_packets
> -reset_env
> +    # hv2:Migrator can now reach to hv3:Outside because it was activated
> +    request=$(send_arp hv2 migrator 1 "00:00:00:00:00:10" 
> "00:00:00:00:00:03" "10.0.0.10" "10.0.0.3")
> +    echo $request >> hv3/outside.expected
>  
> -# hv2:Migrator can now reach to hv3:Outside because RARP strategy activated 
> it
> -request=$(send_arp hv2 migrator 000000000010 000000000003 $migrator_spa 
> $outside_spa)
> -echo $request >> hv3/outside.expected
> +    check_packets
>  
> -check_packets
> +    # complete port migration and check that -activated flag is reset
> +    check ovn-nbctl lsp-set-options migrator requested-chassis=hv2
> +    OVS_WAIT_UNTIL([test x = x$(ovn-sbctl get Port_Binding $pb_uuid 
> options:additional-chassis-activated)])
>  
> -# complete port migration and check that -activated flag is reset
> -check ovn-nbctl lsp-set-options migrator requested-chassis=hv2
> -OVS_WAIT_UNTIL([test x = x$(ovn-sbctl get Port_Binding $pb_uuid 
> options:additional-chassis-activated)])
> +    OVN_CLEANUP([hv1],[hv2],[hv3])
>  
> -OVN_CLEANUP([hv1],[hv2],[hv3])
> +    AT_CLEANUP
> +])])
>  
> -AT_CLEANUP
> -])
> +ACTIVATION_STRATEGY_TEST([rarp])
> +ACTIVATION_STRATEGY_TEST([garp])
> +ACTIVATION_STRATEGY_TEST([na])
>  
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([options:activation-strategy=rarp is not waiting for southbound db])

Regards,
Dumitru


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

Reply via email to