From patchwork Tue Aug 11 10:16:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1343261 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BQpfc5cMxz9sPB for ; Tue, 11 Aug 2020 20:17:12 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id CC672204D7; Tue, 11 Aug 2020 10:17:09 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2v-7d32SxOvX; Tue, 11 Aug 2020 10:17:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 073F8203D7; Tue, 11 Aug 2020 10:17:05 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DE03DC07FF; Tue, 11 Aug 2020 10:17:04 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id B81B4C004D for ; Tue, 11 Aug 2020 10:17:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id B46D985D41 for ; Tue, 11 Aug 2020 10:17:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KzvITdlPSHoA for ; Tue, 11 Aug 2020 10:17:02 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 139F5857B0 for ; Tue, 11 Aug 2020 10:17:01 +0000 (UTC) X-Originating-IP: 60.243.255.170 Received: from nusiddiq.home.org.com (unknown [60.243.255.170]) (Authenticated sender: numans@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 56A61FF811; Tue, 11 Aug 2020 10:16:56 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 11 Aug 2020 15:46:43 +0530 Message-Id: <20200811101643.2319203-1-numans@ovn.org> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Cc: Alexander Constantinescu Subject: [ovs-dev] [PATCH ovn v2] ovn-northd: Add ARP responder flows for SNAT entries. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Numan Siddique If the below SNAT entry is added: ovn-nbctl lr-nat-add snat 172.168.0.120 10.0.0.5 And when the logical port with IP - 10.0.0.5, sends a packet destined to outside, gets SNATted to 172.168.0.120 as expected, but for the reverse traffic if the upstream switch sends an ARP request for 172.168.0.120, then OVN doesn't reply and the reply traffic never reaches the logical port. This patch fixes this issue by addding ARP responder flows for SNAT entries. Note that, if 172.168.0.120 happens to be the logical router IP, then it works. Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1861294 Reported-by: Alexander Constantinescu Signed-off-by: Numan Siddique Acked-by: Dumitru Ceara --- v1 -> v2 --- * Addressed comments from Dumitru by adding system test. northd/ovn-northd.8.xml | 18 ++++----- northd/ovn-northd.c | 13 +++++- tests/ovn-northd.at | 8 ++++ tests/system-ovn.at | 89 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 20fd19450..ee21c825d 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -1952,15 +1952,15 @@ nd_na_router {
  • These flows reply to ARP requests or IPv6 neighbor solicitation - for the virtual IP addresses configured in the router for DNAT - or load balancing. + for the virtual IP addresses configured in the router for NAT + (both DNAT and SNAT) or load balancing.

    - IPv4: For a configured DNAT IP address or a load balancer - IPv4 VIP A, for each router port P with - Ethernet address E, a priority-90 flow matches - arp.op == 1 && arp.tpa == A + IPv4: For a configured NAT (both DNAT and SNAT) IP address or a + load balancer IPv4 VIP A, for each router port + P with Ethernet address E, a priority-90 flow + matches arp.op == 1 && arp.tpa == A (ARP request) with the following actions:

    @@ -1990,9 +1990,9 @@ output;

    - IPv6: For a configured DNAT IP address or a load balancer - IPv6 VIP A, solicited node address S, - for each router port P with + IPv6: For a configured NAT (both DNAT and SNAT) IP address or a + load balancer IPv6 VIP A, solicited node address + S, for each router port P with Ethernet address E, a priority-90 flow matches inport == P && nd_ns && ip6.dst == {A, S} && diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 99eb582c3..a27d4b13d 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -8648,6 +8648,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * per logical port but DNAT addresses can be handled per datapath * for non gateway router ports. */ + struct sset snat_ips = SSET_INITIALIZER(&snat_ips); for (int i = 0; i < od->nbr->n_nat; i++) { struct ovn_nat *nat_entry = &od->nat_entries[i]; const struct nbrec_nat *nat = nat_entry->nb; @@ -8657,15 +8658,22 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; + char *ext_addr = nat_entry_is_v6(nat_entry) ? + ext_addrs->ipv6_addrs[0].addr_s : + ext_addrs->ipv4_addrs[0].addr_s; + if (!strcmp(nat->type, "snat")) { - continue; + if (sset_contains(&snat_ips, ext_addr)) { + continue; + } + sset_add(&snat_ips, ext_addr); } /* Priority 91 and 92 flows are added for each gateway router * port to handle the special cases. In case we get the packet * on a regular port, just reply with the port's ETH address. */ - struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; if (nat_entry_is_v6(nat_entry)) { build_lrouter_nd_flow(od, NULL, "nd_na", ext_addrs->ipv6_addrs[0].addr_s, @@ -8679,6 +8687,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, &nat->header_, lflows); } } + sset_destroy(&snat_ips); /* Drop ARP packets (priority 85). ARP request packets for router's own * IPs are handled with priority-90 flows. diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 7872d5051..8344c7f5e 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -1572,6 +1572,8 @@ ovn-nbctl set logical_router lr options:chassis=ch ovn-nbctl lr-nat-add lr dnat_and_snat 43.43.43.2 42.42.42.2 ovn-nbctl lr-nat-add lr dnat 43.43.43.3 42.42.42.3 ovn-nbctl lr-nat-add lr dnat_and_snat 43.43.43.4 42.42.42.4 ls-vm 00:00:00:00:00:02 +ovn-nbctl lr-nat-add lr snat 43.43.43.150 43.43.43.50 +ovn-nbctl lr-nat-add lr snat 43.43.43.150 43.43.43.51 ovn-nbctl --wait=sb sync @@ -1594,6 +1596,9 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;) # Ingress router port ETH address is used for ARP reply/NA in lr_in_ip_input. AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | grep "arp\|nd" | sort], [0], [dnl table=3 (lr_in_ip_input ), priority=90 , dnl +match=(arp.op == 1 && arp.tpa == 43.43.43.150), dnl +action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.150; outport = inport; flags.loopback = 1; output;) + table=3 (lr_in_ip_input ), priority=90 , dnl match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;) table=3 (lr_in_ip_input ), priority=90 , dnl @@ -1648,6 +1653,9 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;) # Priority 90 flows (per router). AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | grep "arp\|nd" | sort], [0], [dnl table=3 (lr_in_ip_input ), priority=90 , dnl +match=(arp.op == 1 && arp.tpa == 43.43.43.150), dnl +action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.150; outport = inport; flags.loopback = 1; output;) + table=3 (lr_in_ip_input ), priority=90 , dnl match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;) table=3 (lr_in_ip_input ), priority=90 , dnl diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 5fda0960f..40ba6e44c 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -5308,3 +5308,92 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /could not open network device p1*/d"]) AT_CLEANUP + +AT_SETUP([ovn -- ARP resolution for SNAT IP]) +ovn_start +OVS_TRAFFIC_VSWITCHD_START() + +ADD_BR([br-int]) +ADD_BR([br-ext]) + +ovs-ofctl add-flow br-ext action=normal +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +ovn-nbctl lr-add R1 + +ovn-nbctl ls-add sw0 +ovn-nbctl ls-add public + +ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 +ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \ + -- set Logical_Router_Port rp-public options:redirect-chassis=hv1 + +ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.1.0/24 +ovn-nbctl lr-nat-add R1 snat 172.16.1.20 192.168.1.2 + +ADD_NAMESPACES(sw01-x) +ADD_VETH(sw01-x, sw01-x, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ + "192.168.1.1") +ovn-nbctl lsp-add sw0 sw01-x \ + -- lsp-set-addresses sw01-x "f0:00:00:01:02:03 192.168.1.2" + +OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw01-x) = xup]) + +ADD_NAMESPACES(ext-foo) +ADD_VETH(ext-foo, ext-foo, br-ext, "172.16.1.100/24", "00:10:10:01:02:13", \ + "172.16.1.1") + +OVS_WAIT_UNTIL([test "$(ip netns exec ext-foo ip a | grep fe80 | grep tentative)" = ""]) + +AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) +ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +ovn-nbctl --wait=hv sync + +# Send ping from sw01-x to ext-foo. +NS_CHECK_EXEC([sw01-x], [ping -q -c 3 -i 0.3 -w 2 172.16.1.100 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# Check conntrack entries. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.100) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmp,orig=(src=192.168.1.2,dst=172.16.1.100,id=,type=8,code=0),reply=(src=172.16.1.100,dst=172.16.1.20,id=,type=0,code=0),zone= +]) + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d +/.*terminating with signal 15.*/d"]) +AT_CLEANUP