[ovs-dev] [PATCH ovn v3] ovn-northd: Forward ARP requests on localnet ports.

Numan Siddique numans at ovn.org
Tue Mar 24 11:13:06 UTC 2020


On Tue, Mar 24, 2020 at 3:34 PM Dumitru Ceara <dceara at redhat.com> wrote:
>
> Commit 32f5ebb06226 limited the ARP/ND broadcast domain but in scenarios
> where ARP responder flows are installed only on chassis that own the
> associated logical ports ARP requests should still be forwarded on
> localnet ports because the router pipeline should be executed on the
> chassis that owns the logical port. Only that chassis will reply to the
> ARP/ND request.
>
> Reported-by: Michael Plato <michael.plato at tu-berlin.de>
> Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-March/049856.html
> Fixes: 32f5ebb06226 ("ovn-northd: Limit ARP/ND broadcast domain whenever possible.")
> Signed-off-by: Dumitru Ceara <dceara at redhat.com>

Thanks. I applied this patch to master and branch-20.03

Numan

>
> ---
> V3:
> - Address Numan's comment and add unit test.
> V2:
> - Address Numan's comment and update ovn-northd documentation.
> ---
>  northd/ovn-northd.8.xml |   3 +-
>  northd/ovn-northd.c     |   6 +-
>  tests/ovn.at            | 169 ++++++++++++++++++++++++++++++++++++++++++++----
>  3 files changed, 162 insertions(+), 16 deletions(-)
>
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 7d03cbc..1e0993e 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -1194,7 +1194,8 @@ output;
>          Priority-75 flows for each IP address/VIP/NAT address owned by a
>          router port connected to the switch. These flows match ARP requests
>          and ND packets for the specific IP addresses.  Matched packets are
> -        forwarded only to the router that owns the IP address.
> +        forwarded only to the router that owns the IP address and, if
> +        present, to the localnet port of the logical switch.
>        </li>
>
>        <li>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index f648d2e..b76df05 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -5903,8 +5903,12 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips,
>      ds_put_cstr(&match, "}");
>
>      /* Send a the packet only to the router pipeline and skip flooding it
> -     * in the broadcast domain.
> +     * in the broadcast domain (except for the localnet port).
>       */
> +    if (od->localnet_port) {
> +        ds_put_format(&actions, "clone { outport = %s; output; }; ",
> +                      od->localnet_port->json_key);
> +    }
>      ds_put_format(&actions, "outport = %s; output;", patch_op->json_key);
>      ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, priority,
>                              ds_cstr(&match), ds_cstr(&actions), stage_hint);
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 1b6073f..4baf2e9 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -17928,13 +17928,14 @@ net_add n1
>  sim_add hv1
>  as hv1
>  ovs-vsctl add-br br-phys
> +ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
>  ovn_attach n1 br-phys 192.168.0.1
>
> -ovs-vsctl -- add-port br-int hv1-vif1 -- \
> -    set interface hv1-vif1 external-ids:iface-id=sw-agg-ext \
> -    options:tx_pcap=hv1/vif1-tx.pcap \
> -    options:rxq_pcap=hv1/vif1-rx.pcap \
> -    ofport-request=1
> +sim_add hv2
> +as hv2
> +ovs-vsctl add-br br-phys
> +ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +ovn_attach n1 br-phys 192.168.0.2
>
>  # One Aggregation Switch connected to two Logical networks (routers).
>  ovn-nbctl ls-add sw-agg
> @@ -17950,18 +17951,66 @@ ovn-nbctl lsp-add sw-agg sw-rtr2                   \
>      -- lsp-set-addresses sw-rtr2 00:00:00:00:02:00 \
>      -- lsp-set-options sw-rtr2 router-port=rtr2-sw
>
> -# Configure L3 interface IPv4 & IPv6 on both routers
> +# Localnet port on the Aggregation Switch.
> +ovn-nbctl lsp-add sw-agg sw-agg-ln
> +ovn-nbctl lsp-set-addresses sw-agg-ln unknown
> +ovn-nbctl lsp-set-type sw-agg-ln localnet
> +ovn-nbctl lsp-set-options sw-agg-ln network_name=phys
> +
> +# Configure L3 interface IPv4 & IPv6 on both routers.
>  ovn-nbctl lr-add rtr1
>  ovn-nbctl lrp-add rtr1 rtr1-sw 00:00:00:00:01:00 10.0.0.1/24 10::1/64
>
> +ovn-nbctl lrp-add rtr1 rtr1-sw1 00:00:01:00:00:00 20.0.0.1/24 20::1/64
> +
>  ovn-nbctl lr-add rtr2
>  ovn-nbctl lrp-add rtr2 rtr2-sw 00:00:00:00:02:00 10.0.0.2/24 10::2/64
>
> +# Configure router gateway ports.
> +ovn-nbctl lrp-set-gateway-chassis rtr1-sw hv1 20
> +ovn-nbctl lrp-set-gateway-chassis rtr2-sw hv1 20
> +
> +# One private network behind rtr1 with two VMs.
> +ovn-nbctl ls-add sw1
> +ovn-nbctl lsp-add sw1 sw1-p1 \
> +    -- lsp-set-addresses sw1-p1 00:00:00:01:00:00
> +ovn-nbctl lsp-add sw1 sw1-p2 \
> +    -- lsp-set-addresses sw1-p2 00:00:00:02:00:00
> +ovn-nbctl lsp-add sw1 sw1-rtr1                       \
> +    -- lsp-set-type sw1-rtr1 router                  \
> +    -- lsp-set-addresses sw1-rtr1 00:00:01:00:00:00  \
> +    -- lsp-set-options sw1-rtr1 router-port=rtr1-sw1
> +
> +# Bind a "VM" connected to sw-agg on hv1.
> +as hv1
> +ovs-vsctl -- add-port br-int hv1-vif0 -- \
> +    set interface hv1-vif0 external-ids:iface-id=sw-agg-ext \
> +    options:tx_pcap=hv1/vif0-tx.pcap \
> +    options:rxq_pcap=hv1/vif0-rx.pcap \
> +    ofport-request=1
> +
> +# Bind a "VM" connected to sw1 on hv1.
> +as hv1
> +ovs-vsctl -- add-port br-int hv1-vif1 -- \
> +    set interface hv1-vif1 external-ids:iface-id=sw1-p1 \
> +    options:tx_pcap=hv1/vif1-tx.pcap \
> +    options:rxq_pcap=hv1/vif1-rx.pcap \
> +    ofport-request=2
> +
> +# Bind a "VM" connected to sw1 on hv2.
> +as hv2
> +ovs-vsctl -- add-port br-int hv1-vif2 -- \
> +    set interface hv1-vif2 external-ids:iface-id=sw1-p2 \
> +    options:tx_pcap=hv1/vif2-tx.pcap \
> +    options:rxq_pcap=hv1/vif2-rx.pcap \
> +    ofport-request=3
> +
>  OVN_POPULATE_ARP
>  ovn-nbctl --wait=hv sync
>
>  sw_dp_uuid=$(ovn-sbctl --bare --columns _uuid list datapath_binding sw-agg)
>  sw_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding sw-agg)
> +r1_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding rtr1)
>
>  r1_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr1)
>  r2_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr2)
> @@ -17970,9 +18019,10 @@ mc_key=$(ovn-sbctl --bare --columns tunnel_key find multicast_group datapath=${s
>  mc_key=$(printf "%04x" $mc_key)
>
>  match_sw_metadata="metadata=0x${sw_dp_key}"
> +match_r1_metadata="metadata=0x${r1_dp_key}"
>
>  # Inject ARP request for first router owned IP address.
> -send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 1)
> +send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 1)
>
>  # Verify that the ARP request is sent only to rtr1.
>  match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.1,arp_op=1"
> @@ -18001,7 +18051,7 @@ OVS_WAIT_UNTIL([
>  # Inject ND_NS for ofirst router owned IP address.
>  src_ipv6=00100000000000000000000000000254
>  dst_ipv6=00100000000000000000000000000001
> -send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
> +send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
>
>  # Verify that the ND_NS is sent only to rtr1.
>  match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::1"
> @@ -18038,7 +18088,7 @@ ovn-nbctl lr-lb-add rtr2 lb2-v6
>  ovn-nbctl --wait=hv sync
>
>  # Inject ARP request for first router owned VIP address.
> -send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 11)
> +send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 11)
>
>  # Verify that the ARP request is sent only to rtr1.
>  match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.11,arp_op=1"
> @@ -18067,7 +18117,7 @@ OVS_WAIT_UNTIL([
>  # Inject ND_NS for first router owned VIP address.
>  src_ipv6=00100000000000000000000000000254
>  dst_ipv6=00100000000000000000000000000011
> -send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
> +send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
>
>  # Verify that the ND_NS is sent only to rtr1.
>  match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::11"
> @@ -18091,14 +18141,21 @@ OVS_WAIT_UNTIL([
>      test "0" = "${pkts_flooded}"
>  ])
>
> -# Configure NAT on both routers
> +# Configure NAT on both routers.
>  ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.111 42.42.42.1
>  ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::111 42::1
>  ovn-nbctl lr-nat-add rtr2 dnat_and_snat 10.0.0.222 42.42.42.2
>  ovn-nbctl lr-nat-add rtr2 dnat_and_snat 10::222 42::2
>
> +# Configure FIP1 and FIP2 on rtr1 for sw1-p1 and sw1-p2.
> +ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.121 20.0.0.11 sw1-p1 00:00:00:01:00:00
> +ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::121 20::11 sw1-p1 00:00:00:01:00:00
> +ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.122 20.0.0.12 sw1-p2 00:00:00:02:00:00
> +ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::122 20::12 sw1-p2 00:00:00:02:00:00
> +ovn-nbctl --wait=hv sync
> +
>  # Inject ARP request for first router owned NAT address.
> -send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 111)
> +send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 111)
>
>  # Verify that the ARP request is sent only to rtr1.
>  match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.111,arp_op=1"
> @@ -18124,10 +18181,50 @@ OVS_WAIT_UNTIL([
>      test "0" = "${pkts_flooded}"
>  ])
>
> +# Inject ARP request for FIP1.
> +send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 121)
> +
> +# Verify that the ARP request is replied to from hv1 and not hv2.
> +match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1"
> +
> +as hv1
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_arp_req}" | grep n_packets=1 -c)
> +    test "1" = "${pkts_on_rtr1}"
> +])
> +
> +as hv2
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_arp_req}" | grep n_packets=1 -c)
> +    test "0" = "${pkts_on_rtr1}"
> +])
> +
> +# Inject ARP request for FIP2.
> +send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 122)
> +
> +# Verify that the ARP request is replied to from hv2 and not hv1.
> +match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1"
> +
> +as hv2
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_arp_req}" | grep n_packets=1 -c)
> +    test "1" = "${pkts_on_rtr1}"
> +])
> +
> +as hv1
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_arp_req}" | grep n_packets=1 -c)
> +    test "0" = "${pkts_on_rtr1}"
> +])
> +
>  # Inject ND_NS for first router owned IP address.
>  src_ipv6=00100000000000000000000000000254
>  dst_ipv6=00100000000000000000000000000111
> -send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
> +send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
>
>  # Verify that the ND_NS is sent only to rtr1.
>  match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::111"
> @@ -18151,7 +18248,51 @@ OVS_WAIT_UNTIL([
>      test "0" = "${pkts_flooded}"
>  ])
>
> -OVN_CLEANUP([hv1])
> +# Inject ND_NS for FIP1.
> +src_ipv6=00100000000000000000000000000254
> +dst_ipv6=00100000000000000000000000000121
> +send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72dd
> +
> +# Verify that the ND_NS is replied to from hv1 and not hv2.
> +match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121"
> +
> +as hv1
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
> +    test "1" = "${pkts_on_rtr1}"
> +])
> +
> +as hv2
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
> +    test "0" = "${pkts_on_rtr1}"
> +])
> +
> +# Inject ND_NS for FIP2.
> +src_ipv6=00100000000000000000000000000254
> +dst_ipv6=00100000000000000000000000000122
> +send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72db
> +
> +# Verify that the ND_NS is replied to from hv2 and not hv1.
> +match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122"
> +
> +as hv2
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
> +    test "1" = "${pkts_on_rtr1}"
> +])
> +
> +as hv1
> +OVS_WAIT_UNTIL([
> +    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
> +    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
> +    test "0" = "${pkts_on_rtr1}"
> +])
> +
> +OVN_CLEANUP([hv1], [hv2])
>  AT_CLEANUP
>
>  AT_SETUP([ovn -- trace when flow cookie updated])
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>


More information about the dev mailing list