From patchwork Thu Sep 17 12:50:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dumitru Ceara X-Patchwork-Id: 1366103 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.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KEBNCEmc; dkim-atps=neutral Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BscKN0vhxz9sSC for ; Thu, 17 Sep 2020 22:51:19 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 20FAA87604; Thu, 17 Sep 2020 12:51:17 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Z8LTr9-hkIaP; Thu, 17 Sep 2020 12:51:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id BA12A875D5; Thu, 17 Sep 2020 12:51:15 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 96F15C0890; Thu, 17 Sep 2020 12:51:15 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 187F1C0051 for ; Thu, 17 Sep 2020 12:51:15 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 084F8878A4 for ; Thu, 17 Sep 2020 12:51:15 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id x+yBIA61Tjpg for ; Thu, 17 Sep 2020 12:51:13 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-delivery-1.mimecast.com (us-smtp-1.mimecast.com [205.139.110.61]) by whitealder.osuosl.org (Postfix) with ESMTPS id 9264A87869 for ; Thu, 17 Sep 2020 12:51:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1600347072; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wU8ZZ13TPTULQpdT0PkNBySqUgAera/Lipra2rVrp3s=; b=KEBNCEmc/X8uv8a6t2pAZ++KFsUzpoc5Bw9swry7S7zSwd2yn/ns1t5xLhihtMKmhkgJ/r UKRUZnpZWJK+OnoB2IXOQG/3obUL0ymP83yu89d12ssa7kH+uRvdMUdqgZKAvkC+v++7og VR6UnzFFScralppxhgMrsJ9Xq1DX9gQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-366-y47T71aZPn655mBz-QA9Rw-1; Thu, 17 Sep 2020 08:50:57 -0400 X-MC-Unique: y47T71aZPn655mBz-QA9Rw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id ED54E800400 for ; Thu, 17 Sep 2020 12:50:56 +0000 (UTC) Received: from dceara.remote.csb (ovpn-113-244.ams2.redhat.com [10.36.113.244]) by smtp.corp.redhat.com (Postfix) with ESMTP id 52A1C2C31E for ; Thu, 17 Sep 2020 12:50:56 +0000 (UTC) From: Dumitru Ceara To: dev@openvswitch.org Date: Thu, 17 Sep 2020 14:50:53 +0200 Message-Id: <20200917125050.19729.41529.stgit@dceara.remote.csb> In-Reply-To: <20200917125025.19729.19409.stgit@dceara.remote.csb> References: <20200917125025.19729.19409.stgit@dceara.remote.csb> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v3 ovn 1/4] ovn-northd: Drop IP packets destined to router owned IPs (after NAT). 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" OVN was dropping IP packets destined to IPs owned by logical routers but only if those IPs are not used for SNAT rules. However, if a packet doesn't match an existing NAT session and its destination is still a router owned IP, it can be safely dropped. Otherwise it will trigger an unnecessary packet-in in stage lr_in_arp_request. To achieve that we add flows that drop traffic to router owned SNAT IPs in table lr_in_arp_resolve. Reported-by: Tim Rozet Reported-at: https://bugzilla.redhat.com/1876174 Signed-off-by: Dumitru Ceara Acked-by: Han Zhou --- northd/ovn-northd.8.xml | 24 ++++++ northd/ovn-northd.c | 194 +++++++++++++++++++++++++++-------------------- tests/ovn.at | 88 +++++++++++++++++++++ 3 files changed, 225 insertions(+), 81 deletions(-) diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index bd42105..f1c7c9b 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -3089,6 +3089,30 @@ outport = P;
  • + Traffic with IP destination an address owned by the router should be + dropped. Such traffic is normally dropped in ingress table + IP Input except for IPs that are also shared with SNAT + rules. However, if there was no unSNAT operation that happened + successfully until this point in the pipeline and the destination IP + of the packet is still a router owned IP, the packets can be safely + dropped. +

    + +

    + A priority-1 logical flow with match ip4.dst = {..} + matches on traffic destined to router owned IPv4 addresses which are + also SNAT IPs. This flow has action drop;. +

    + +

    + A priority-1 logical flow with match ip6.dst = {..} + matches on traffic destined to router owned IPv6 addresses which are + also SNAT IPs. This flow has action drop;. +

    +
  • + +
  • +

    Dynamic MAC bindings. These flows resolve MAC-to-IP bindings that have become known dynamically through ARP or neighbor discovery. (The ingress table ARP Request will diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index cfec6a2..d5d7631 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -623,6 +623,9 @@ struct ovn_datapath { /* NAT entries configured on the router. */ struct ovn_nat *nat_entries; + /* SNAT IPs used by the router. */ + struct sset snat_ips; + struct ovn_port **localnet_ports; size_t n_localnet_ports; @@ -641,6 +644,10 @@ struct ovn_nat { struct lport_addresses ext_addrs; }; +static bool +get_force_snat_ip(struct ovn_datapath *od, const char *key_type, + struct lport_addresses *laddrs); + /* Returns true if a 'nat_entry' is valid, i.e.: * - parsing was successful. * - the string yielded exactly one IPv4 address or exactly one IPv6 address. @@ -663,7 +670,35 @@ nat_entry_is_v6(const struct ovn_nat *nat_entry) static void init_nat_entries(struct ovn_datapath *od) { - if (!od->nbr || od->nbr->n_nat == 0) { + struct lport_addresses snat_addrs; + + if (!od->nbr) { + return; + } + + sset_init(&od->snat_ips); + if (get_force_snat_ip(od, "dnat", &snat_addrs)) { + if (snat_addrs.n_ipv4_addrs) { + sset_add(&od->snat_ips, snat_addrs.ipv4_addrs[0].addr_s); + } + if (snat_addrs.n_ipv6_addrs) { + sset_add(&od->snat_ips, snat_addrs.ipv6_addrs[0].addr_s); + } + destroy_lport_addresses(&snat_addrs); + } + + memset(&snat_addrs, 0, sizeof(snat_addrs)); + if (get_force_snat_ip(od, "lb", &snat_addrs)) { + if (snat_addrs.n_ipv4_addrs) { + sset_add(&od->snat_ips, snat_addrs.ipv4_addrs[0].addr_s); + } + if (snat_addrs.n_ipv6_addrs) { + sset_add(&od->snat_ips, snat_addrs.ipv6_addrs[0].addr_s); + } + destroy_lport_addresses(&snat_addrs); + } + + if (!od->nbr->n_nat) { return; } @@ -682,6 +717,13 @@ init_nat_entries(struct ovn_datapath *od) VLOG_WARN_RL(&rl, "Bad ip address %s in nat configuration " "for router %s", nat->external_ip, od->nbr->name); + continue; + } + + if (!nat_entry_is_v6(nat_entry)) { + sset_add(&od->snat_ips, nat_entry->ext_addrs.ipv4_addrs[0].addr_s); + } else { + sset_add(&od->snat_ips, nat_entry->ext_addrs.ipv6_addrs[0].addr_s); } } } @@ -693,6 +735,7 @@ destroy_nat_entries(struct ovn_datapath *od) return; } + sset_destroy(&od->snat_ips); for (size_t i = 0; i < od->nbr->n_nat; i++) { destroy_lport_addresses(&od->nat_entries[i].ext_addrs); } @@ -8744,6 +8787,68 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, op, lflows, &match, &actions); } + /* Drop IP traffic destined to router owned IPs. Part of it is dropped + * in stage "lr_in_ip_input" but traffic that could have been unSNATed + * but didn't match any existing session might still end up here. + */ + HMAP_FOR_EACH (op, key_node, ports) { + if (!op->nbrp) { + continue; + } + + if (op->lrp_networks.n_ipv4_addrs) { + ds_clear(&match); + for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + if (!sset_find(&op->od->snat_ips, + op->lrp_networks.ipv4_addrs[i].addr_s)) { + continue; + } + ds_put_format(&match, "%s, ", + op->lrp_networks.ipv4_addrs[i].addr_s); + } + + if (ds_last(&match) != EOF) { + ds_chomp(&match, ' '); + ds_chomp(&match, ','); + + char *drop_match = xasprintf("ip4.dst == {%s}", + ds_cstr(&match)); + /* Drop traffic with IP.dest == router-ip. */ + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_ARP_RESOLVE, 1, + drop_match, "drop;", + &op->nbrp->header_); + free(drop_match); + } + } + + if (op->lrp_networks.n_ipv6_addrs) { + ds_clear(&match); + for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + if (!sset_find(&op->od->snat_ips, + op->lrp_networks.ipv6_addrs[i].addr_s)) { + continue; + } + ds_put_format(&match, "%s, ", + op->lrp_networks.ipv6_addrs[i].addr_s); + } + + if (ds_last(&match) != EOF) { + ds_chomp(&match, ' '); + ds_chomp(&match, ','); + + char *drop_match = xasprintf("ip6.dst == {%s}", + ds_cstr(&match)); + /* Drop traffic with IP.dest == router-ip. */ + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_ARP_RESOLVE, 1, + drop_match, "drop;", + &op->nbrp->header_); + free(drop_match); + } + } + } + HMAP_FOR_EACH (od, key_node, datapaths) { if (!od->nbr) { continue; @@ -9035,77 +9140,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } /* A gateway router can have 4 SNAT IP addresses to force DNATed and - * LBed traffic respectively to be SNATed. In addition, there can be - * a number of SNAT rules in the NAT table. */ - struct v46_ip *snat_ips = xmalloc(sizeof *snat_ips - * (op->od->nbr->n_nat + 4)); - size_t n_snat_ips = 0; - struct lport_addresses snat_addrs; - - if (get_force_snat_ip(op->od, "dnat", &snat_addrs)) { - if (snat_addrs.n_ipv4_addrs) { - snat_ips[n_snat_ips].family = AF_INET; - snat_ips[n_snat_ips++].ipv4 = snat_addrs.ipv4_addrs[0].addr; - } - if (snat_addrs.n_ipv6_addrs) { - snat_ips[n_snat_ips].family = AF_INET6; - snat_ips[n_snat_ips++].ipv6 = snat_addrs.ipv6_addrs[0].addr; - } - destroy_lport_addresses(&snat_addrs); - } - - memset(&snat_addrs, 0, sizeof(snat_addrs)); - if (get_force_snat_ip(op->od, "lb", &snat_addrs)) { - if (snat_addrs.n_ipv4_addrs) { - snat_ips[n_snat_ips].family = AF_INET; - snat_ips[n_snat_ips++].ipv4 = snat_addrs.ipv4_addrs[0].addr; - } - if (snat_addrs.n_ipv6_addrs) { - snat_ips[n_snat_ips].family = AF_INET6; - snat_ips[n_snat_ips++].ipv6 = snat_addrs.ipv6_addrs[0].addr; - } - destroy_lport_addresses(&snat_addrs); - } - - for (size_t i = 0; i < op->od->nbr->n_nat; i++) { - struct ovn_nat *nat_entry = &op->od->nat_entries[i]; - const struct nbrec_nat *nat = nat_entry->nb; - - /* Skip entries we failed to parse. */ - if (!nat_entry_is_valid(nat_entry)) { - continue; - } - - if (!strcmp(nat->type, "snat")) { - if (nat_entry_is_v6(nat_entry)) { - struct in6_addr *ipv6 = - &nat_entry->ext_addrs.ipv6_addrs[0].addr; - - snat_ips[n_snat_ips].family = AF_INET6; - snat_ips[n_snat_ips++].ipv6 = *ipv6; - } else { - ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr; - snat_ips[n_snat_ips].family = AF_INET; - snat_ips[n_snat_ips++].ipv4 = ip; - } - } - } - + * LBed traffic respectively to be SNATed. In addition, there can be + * a number of SNAT rules in the NAT table. + * Skip all of them for drop flows. */ ds_clear(&match); ds_put_cstr(&match, "ip4.dst == {"); bool has_drop_ips = false; for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - bool snat_ip_is_router_ip = false; - for (int j = 0; j < n_snat_ips; j++) { - /* Packets to SNAT IPs should not be dropped. */ - if (snat_ips[j].family == AF_INET - && op->lrp_networks.ipv4_addrs[i].addr - == snat_ips[j].ipv4) { - snat_ip_is_router_ip = true; - break; - } - } - if (snat_ip_is_router_ip) { + if (sset_find(&op->od->snat_ips, + op->lrp_networks.ipv4_addrs[i].addr_s)) { continue; } ds_put_format(&match, "%s, ", @@ -9122,17 +9165,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - bool snat_ip_is_router_ip = false; - for (int j = 0; j < n_snat_ips; j++) { - /* Packets to SNAT IPs should not be dropped. */ - if (snat_ips[j].family == AF_INET6 - && !memcmp(&op->lrp_networks.ipv6_addrs[i].addr, - &snat_ips[j].ipv6, sizeof snat_ips[j].ipv6)) { - snat_ip_is_router_ip = true; - break; - } - } - if (snat_ip_is_router_ip) { + if (sset_find(&op->od->snat_ips, + op->lrp_networks.ipv6_addrs[i].addr_s)) { continue; } ds_put_format(&match, "%s, ", @@ -9151,8 +9185,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, &op->nbrp->header_); } - free(snat_ips); - /* ARP/NS packets are taken care of per router. The only exception * is on the l3dgw_port where we might need to use a different * ETH address. diff --git a/tests/ovn.at b/tests/ovn.at index a6f1fb5..cb7e7cc 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -21659,6 +21659,94 @@ OVS_WAIT_UNTIL([test x$(as hv1 ovn-appctl -t ovn-controller debug/status) = "xru OVN_CLEANUP([hv1]) AT_CLEANUP +# Test dropping traffic destined to router owned IPs. +AT_SETUP([ovn -- gateway router drop traffic for own IPs]) +ovn_start + +ovn-nbctl lr-add r1 -- set logical_router r1 options:chassis=hv1 +ovn-nbctl ls-add s1 + +# Connnect r1 to s1. +ovn-nbctl lrp-add r1 lrp-r1-s1 00:00:00:00:01:01 10.0.1.1/24 +ovn-nbctl lsp-add s1 lsp-s1-r1 -- set Logical_Switch_Port lsp-s1-r1 type=router \ + options:router-port=lrp-r1-s1 addresses=router + +# Create logical port p1 in s1 +ovn-nbctl lsp-add s1 p1 \ +-- lsp-set-addresses p1 "f0:00:00:00:01:02 10.0.1.2" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br 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=p1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +ovn-nbctl --wait=hv sync + +sw_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding r1) + +AT_CHECK([ovn-sbctl lflow-list | grep lr_in_arp_resolve | grep 10.0.1.1], [1], []) + +ip_to_hex() { + printf "%02x%02x%02x%02x" "$@" +} + +# Send ip packets from p1 to lrp-r1-s1 +src_mac="f00000000102" +dst_mac="000000000101" +src_ip=`ip_to_hex 10 0 1 2` +dst_ip=`ip_to_hex 10 0 1 1` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet + +# No packet-ins should reach ovn-controller. +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep -v n_packets=0 -c], [1], [dnl +0 +]) + +# The packet should have been dropped in the lr_in_ip_input stage. +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=11, n_packets=1,.* priority=60,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl +1 +]) + +# Use the router IP as SNAT IP. +ovn-nbctl set logical_router r1 options:lb_force_snat_ip=10.0.1.1 +ovn-nbctl --wait=hv sync + +# Send ip packets from p1 to lrp-r1-s1 +src_mac="f00000000102" +dst_mac="000000000101" +src_ip=`ip_to_hex 10 0 1 2` +dst_ip=`ip_to_hex 10 0 1 1` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet + +# Even after configuring a router owned IP for SNAT, no packet-ins should +# reach ovn-controller. +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep -v n_packets=0 -c], [1], [dnl +0 +]) + +# The packet should've been dropped in the lr_in_arp_resolve stage. +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=21, n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl +1 +]) + +OVN_CLEANUP([hv1]) +AT_CLEANUP + AT_SETUP([ovn -- nb_cfg timestamp]) ovn_start From patchwork Thu Sep 17 12:51:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dumitru Ceara X-Patchwork-Id: 1366104 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.138; helo=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=LZmkVUD6; dkim-atps=neutral Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BscKb5Wsvz9sS8 for ; Thu, 17 Sep 2020 22:51:30 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 2F53F878B7; Thu, 17 Sep 2020 12:51:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YofILjxT9Oy3; Thu, 17 Sep 2020 12:51:25 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id 83E85878BE; Thu, 17 Sep 2020 12:51:25 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5CCE5C0864; Thu, 17 Sep 2020 12:51:25 +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 72EF0C0864 for ; Thu, 17 Sep 2020 12:51:23 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 6F8E487029 for ; Thu, 17 Sep 2020 12:51:23 +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 lKcfj05AR_te for ; Thu, 17 Sep 2020 12:51:22 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 5A1AB87034 for ; Thu, 17 Sep 2020 12:51:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1600347081; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yGMXlPFfuHUKM97Uj8Gj752w7wDZ+R6iV4FqcQU4+zI=; b=LZmkVUD6gvgDn9ALwjnnOpujcGo4o2+a+TUF9BBuuNOoXm1xC87xLd5Zdy9NjMs9thXA/H QmPuumzRO8f6QQgn4p5H3AzlS8rTyQN8uL7Aa0Fh57eJ3apJQ/TjXm2ItxkdgZ98ffrDnm wadF0IguowKlxPeoqbJ+Svl3X5vnA8U= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-171-NIKcb7_dPbK75n7xWT9C0Q-1; Thu, 17 Sep 2020 08:51:17 -0400 X-MC-Unique: NIKcb7_dPbK75n7xWT9C0Q-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B53E11006714 for ; Thu, 17 Sep 2020 12:51:16 +0000 (UTC) Received: from dceara.remote.csb (ovpn-113-244.ams2.redhat.com [10.36.113.244]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3F1802C31E for ; Thu, 17 Sep 2020 12:51:16 +0000 (UTC) From: Dumitru Ceara To: dev@openvswitch.org Date: Thu, 17 Sep 2020 14:51:09 +0200 Message-Id: <20200917125102.19729.95989.stgit@dceara.remote.csb> In-Reply-To: <20200917125025.19729.19409.stgit@dceara.remote.csb> References: <20200917125025.19729.19409.stgit@dceara.remote.csb> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v3 ovn 2/4] ovn-northd: Move NAT ARP/ND resolution to separate functions. 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" To avoid duplicating code later on, move out the code that generates ARP/ND replies for NAT external IPs to separate functions. Signed-off-by: Dumitru Ceara Acked-by: Han Zhou --- northd/ovn-northd.c | 172 ++++++++++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 78 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index d5d7631..f79ed99 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -8636,6 +8636,94 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, } static void +build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od, + struct ovn_nat *nat_entry, + struct hmap *lflows) +{ + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; + const struct nbrec_nat *nat = nat_entry->nb; + + if (nat_entry_is_v6(nat_entry)) { + build_lrouter_nd_flow(od, NULL, "nd_na", + ext_addrs->ipv6_addrs[0].addr_s, + ext_addrs->ipv6_addrs[0].sn_addr_s, + REG_INPORT_ETH_ADDR, NULL, false, 90, + &nat->header_, lflows); + } else { + build_lrouter_arp_flow(od, NULL, + ext_addrs->ipv4_addrs[0].addr_s, + REG_INPORT_ETH_ADDR, NULL, false, 90, + &nat->header_, lflows); + } +} + +static void +build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, + struct ovn_nat *nat_entry, + struct hmap *lflows) +{ + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; + const struct nbrec_nat *nat = nat_entry->nb; + struct ds match = DS_EMPTY_INITIALIZER; + + /* Mac address to use when replying to ARP/NS. */ + const char *mac_s = REG_INPORT_ETH_ADDR; + struct eth_addr mac; + + if (nat->external_mac && + eth_addr_from_string(nat->external_mac, &mac) + && nat->logical_port) { + /* distributed NAT case, use nat->external_mac */ + mac_s = nat->external_mac; + /* Traffic with eth.src = nat->external_mac should only be + * sent from the chassis where nat->logical_port is + * resident, so that upstream MAC learning points to the + * correct chassis. Also need to avoid generation of + * multiple ARP responses from different chassis. */ + ds_put_format(&match, "is_chassis_resident(\"%s\")", + nat->logical_port); + } else { + mac_s = REG_INPORT_ETH_ADDR; + /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s + * should only be sent from the "redirect-chassis", so that + * upstream MAC learning points to the "redirect-chassis". + * Also need to avoid generation of multiple ARP responses + * from different chassis. */ + if (op->od->l3redirect_port) { + ds_put_format(&match, "is_chassis_resident(%s)", + op->od->l3redirect_port->json_key); + } + } + + /* Respond to ARP/NS requests on the chassis that binds the gw + * port. Drop the ARP/NS requests on other chassis. + */ + if (nat_entry_is_v6(nat_entry)) { + build_lrouter_nd_flow(op->od, op, "nd_na", + ext_addrs->ipv6_addrs[0].addr_s, + ext_addrs->ipv6_addrs[0].sn_addr_s, + mac_s, &match, false, 92, + &nat->header_, lflows); + build_lrouter_nd_flow(op->od, op, "nd_na", + ext_addrs->ipv6_addrs[0].addr_s, + ext_addrs->ipv6_addrs[0].sn_addr_s, + mac_s, NULL, true, 91, + &nat->header_, lflows); + } else { + build_lrouter_arp_flow(op->od, op, + ext_addrs->ipv4_addrs[0].addr_s, + mac_s, &match, false, 92, + &nat->header_, lflows); + build_lrouter_arp_flow(op->od, op, + ext_addrs->ipv4_addrs[0].addr_s, + mac_s, NULL, true, 91, + &nat->header_, lflows); + } + + ds_destroy(&match); +} + +static void build_lrouter_force_snat_flows(struct hmap *lflows, struct ovn_datapath *od, const char *ip_version, const char *ip_addr, const char *context) @@ -8869,6 +8957,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* Priority-90-92 flows handle ARP requests and ND packets. Most are * per logical port but DNAT addresses can be handled per datapath * for non gateway router ports. + * + * 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 sset snat_ips = SSET_INITIALIZER(&snat_ips); for (int i = 0; i < od->nbr->n_nat; i++) { @@ -8890,23 +8982,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } } - - /* 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. - */ - if (nat_entry_is_v6(nat_entry)) { - build_lrouter_nd_flow(od, NULL, "nd_na", - ext_addrs->ipv6_addrs[0].addr_s, - ext_addrs->ipv6_addrs[0].sn_addr_s, - REG_INPORT_ETH_ADDR, NULL, false, 90, - &nat->header_, lflows); - } else { - build_lrouter_arp_flow(od, NULL, - ext_addrs->ipv4_addrs[0].addr_s, - REG_INPORT_ETH_ADDR, NULL, false, 90, - &nat->header_, lflows); - } + build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows); } sset_destroy(&snat_ips); @@ -9212,67 +9288,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } } - - /* Mac address to use when replying to ARP/NS. */ - const char *mac_s = REG_INPORT_ETH_ADDR; - - /* ARP / ND handling for external IP addresses. - * - * DNAT IP addresses are external IP addresses that need ARP - * handling. */ - - struct eth_addr mac; - - ds_clear(&match); - if (nat->external_mac && - eth_addr_from_string(nat->external_mac, &mac) - && nat->logical_port) { - /* distributed NAT case, use nat->external_mac */ - mac_s = nat->external_mac; - /* Traffic with eth.src = nat->external_mac should only be - * sent from the chassis where nat->logical_port is - * resident, so that upstream MAC learning points to the - * correct chassis. Also need to avoid generation of - * multiple ARP responses from different chassis. */ - ds_put_format(&match, "is_chassis_resident(\"%s\")", - nat->logical_port); - } else { - mac_s = REG_INPORT_ETH_ADDR; - /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s - * should only be sent from the "redirect-chassis", so that - * upstream MAC learning points to the "redirect-chassis". - * Also need to avoid generation of multiple ARP responses - * from different chassis. */ - if (op->od->l3redirect_port) { - ds_put_format(&match, "is_chassis_resident(%s)", - op->od->l3redirect_port->json_key); - } - } - - /* Respond to ARP/NS requests on the chassis that binds the gw - * port. Drop the ARP/NS requests on other chassis. - */ - if (nat_entry_is_v6(nat_entry)) { - build_lrouter_nd_flow(op->od, op, "nd_na", - ext_addrs->ipv6_addrs[0].addr_s, - ext_addrs->ipv6_addrs[0].sn_addr_s, - mac_s, &match, false, 92, - &nat->header_, lflows); - build_lrouter_nd_flow(op->od, op, "nd_na", - ext_addrs->ipv6_addrs[0].addr_s, - ext_addrs->ipv6_addrs[0].sn_addr_s, - mac_s, NULL, true, 91, - &nat->header_, lflows); - } else { - build_lrouter_arp_flow(op->od, op, - ext_addrs->ipv4_addrs[0].addr_s, - mac_s, &match, false, 92, - &nat->header_, lflows); - build_lrouter_arp_flow(op->od, op, - ext_addrs->ipv4_addrs[0].addr_s, - mac_s, NULL, true, 91, - &nat->header_, lflows); - } + build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows); } sset_destroy(&sset_snat_ips); } From patchwork Thu Sep 17 12:51:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dumitru Ceara X-Patchwork-Id: 1366106 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=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TSYOpQVx; dkim-atps=neutral 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 4BscMG6xvRz9sS8 for ; Thu, 17 Sep 2020 22:52:58 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 5D3E92E199; Thu, 17 Sep 2020 12:52:57 +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 jn+opWb1FbgO; Thu, 17 Sep 2020 12:52:42 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id BBCB92E1A2; Thu, 17 Sep 2020 12:51:49 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8F9D4C0864; Thu, 17 Sep 2020 12:51:49 +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 8A857C0051 for ; Thu, 17 Sep 2020 12:51:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7971A86E47 for ; Thu, 17 Sep 2020 12:51:47 +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 d_k0UWziecsK for ; Thu, 17 Sep 2020 12:51:46 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) by fraxinus.osuosl.org (Postfix) with ESMTPS id B72DF86D62 for ; Thu, 17 Sep 2020 12:51:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1600347105; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fkZUvnu+KaFZelHY+b1rYrsdY6raYl55sVwQMK1TWEc=; b=TSYOpQVxrHGj2FNrq6W4y2ieIOtxTfXcQho2YbCYu1hwgRQXOREssyTC2wfszt/NRuWwVR K5aC131mkK19Ow9jmgcNnAajDDiv6n/s97wpOH7wTU9NIaop35stml1x1wrWGtvetrUCxh JltjrPIF3z4K9x2IPUCoZe+flD/YWeE= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-199-WIQRQ_mdO_-xOaEHE5g_WQ-1; Thu, 17 Sep 2020 08:51:42 -0400 X-MC-Unique: WIQRQ_mdO_-xOaEHE5g_WQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 87F591091066 for ; Thu, 17 Sep 2020 12:51:40 +0000 (UTC) Received: from dceara.remote.csb (ovpn-113-244.ams2.redhat.com [10.36.113.244]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0CA6319D6C for ; Thu, 17 Sep 2020 12:51:39 +0000 (UTC) From: Dumitru Ceara To: dev@openvswitch.org Date: Thu, 17 Sep 2020 14:51:37 +0200 Message-Id: <20200917125121.19729.67492.stgit@dceara.remote.csb> In-Reply-To: <20200917125025.19729.19409.stgit@dceara.remote.csb> References: <20200917125025.19729.19409.stgit@dceara.remote.csb> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v3 ovn 3/4] ovn-northd: Refactor parsing of *_force_snat_ip. 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" Avoid reparsing the *_force_snat_ip addresses for every logical router port. These addresses are defined once for the whole router. Signed-off-by: Dumitru Ceara Acked-by: Han Zhou --- lib/ovn-util.c | 6 ++++ lib/ovn-util.h | 2 + northd/ovn-northd.c | 69 ++++++++++++++++++++++++--------------------------- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/lib/ovn-util.c b/lib/ovn-util.c index cdb5e18..a8cf6c9 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -320,6 +320,12 @@ extract_sbrec_binding_first_mac(const struct sbrec_port_binding *binding, return ret; } +bool +empty_lport_addresses(struct lport_addresses *laddrs) +{ + return !laddrs->n_ipv4_addrs && !laddrs->n_ipv6_addrs; +} + void destroy_lport_addresses(struct lport_addresses *laddrs) { diff --git a/lib/ovn-util.h b/lib/ovn-util.h index d9aadcb..3343f28 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -74,7 +74,7 @@ bool extract_lrp_networks(const struct nbrec_logical_router_port *, struct lport_addresses *); bool extract_sbrec_binding_first_mac(const struct sbrec_port_binding *binding, struct eth_addr *ea); - +bool empty_lport_addresses(struct lport_addresses *); void destroy_lport_addresses(struct lport_addresses *); char *alloc_nat_zone_key(const struct uuid *key, const char *type); diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index f79ed99..43bd7b5 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -625,6 +625,8 @@ struct ovn_datapath { /* SNAT IPs used by the router. */ struct sset snat_ips; + struct lport_addresses dnat_force_snat_addrs; + struct lport_addresses lb_force_snat_addrs; struct ovn_port **localnet_ports; size_t n_localnet_ports; @@ -670,32 +672,31 @@ nat_entry_is_v6(const struct ovn_nat *nat_entry) static void init_nat_entries(struct ovn_datapath *od) { - struct lport_addresses snat_addrs; - if (!od->nbr) { return; } sset_init(&od->snat_ips); - if (get_force_snat_ip(od, "dnat", &snat_addrs)) { - if (snat_addrs.n_ipv4_addrs) { - sset_add(&od->snat_ips, snat_addrs.ipv4_addrs[0].addr_s); + if (get_force_snat_ip(od, "dnat", &od->dnat_force_snat_addrs)) { + if (&od->dnat_force_snat_addrs.n_ipv4_addrs) { + sset_add(&od->snat_ips, + od->dnat_force_snat_addrs.ipv4_addrs[0].addr_s); } - if (snat_addrs.n_ipv6_addrs) { - sset_add(&od->snat_ips, snat_addrs.ipv6_addrs[0].addr_s); + if (&od->dnat_force_snat_addrs.n_ipv6_addrs) { + sset_add(&od->snat_ips, + od->dnat_force_snat_addrs.ipv6_addrs[0].addr_s); } - destroy_lport_addresses(&snat_addrs); } - memset(&snat_addrs, 0, sizeof(snat_addrs)); - if (get_force_snat_ip(od, "lb", &snat_addrs)) { - if (snat_addrs.n_ipv4_addrs) { - sset_add(&od->snat_ips, snat_addrs.ipv4_addrs[0].addr_s); + if (get_force_snat_ip(od, "lb", &od->lb_force_snat_addrs)) { + if (od->lb_force_snat_addrs.n_ipv4_addrs) { + sset_add(&od->snat_ips, + od->lb_force_snat_addrs.ipv4_addrs[0].addr_s); } - if (snat_addrs.n_ipv6_addrs) { - sset_add(&od->snat_ips, snat_addrs.ipv6_addrs[0].addr_s); + if (od->lb_force_snat_addrs.n_ipv6_addrs) { + sset_add(&od->snat_ips, + od->lb_force_snat_addrs.ipv6_addrs[0].addr_s); } - destroy_lport_addresses(&snat_addrs); } if (!od->nbr->n_nat) { @@ -736,6 +737,9 @@ destroy_nat_entries(struct ovn_datapath *od) } sset_destroy(&od->snat_ips); + destroy_lport_addresses(&od->dnat_force_snat_addrs); + destroy_lport_addresses(&od->lb_force_snat_addrs); + for (size_t i = 0; i < od->nbr->n_nat; i++) { destroy_lport_addresses(&od->nat_entries[i].ext_addrs); } @@ -9477,12 +9481,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, struct sset nat_entries = SSET_INITIALIZER(&nat_entries); - struct lport_addresses dnat_force_snat_addrs; - struct lport_addresses lb_force_snat_addrs; - bool dnat_force_snat_ip = get_force_snat_ip(od, "dnat", - &dnat_force_snat_addrs); - bool lb_force_snat_ip = get_force_snat_ip(od, "lb", - &lb_force_snat_addrs); + bool dnat_force_snat_ip = + !empty_lport_addresses(&od->dnat_force_snat_addrs); + bool lb_force_snat_ip = + !empty_lport_addresses(&od->lb_force_snat_addrs); for (int i = 0; i < od->nbr->n_nat; i++) { const struct nbrec_nat *nat; @@ -9982,23 +9984,25 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* Handle force SNAT options set in the gateway router. */ if (!od->l3dgw_port) { if (dnat_force_snat_ip) { - if (dnat_force_snat_addrs.n_ipv4_addrs) { + if (od->dnat_force_snat_addrs.n_ipv4_addrs) { build_lrouter_force_snat_flows(lflows, od, "4", - dnat_force_snat_addrs.ipv4_addrs[0].addr_s, "dnat"); + od->dnat_force_snat_addrs.ipv4_addrs[0].addr_s, + "dnat"); } - if (dnat_force_snat_addrs.n_ipv6_addrs) { + if (od->dnat_force_snat_addrs.n_ipv6_addrs) { build_lrouter_force_snat_flows(lflows, od, "6", - dnat_force_snat_addrs.ipv6_addrs[0].addr_s, "dnat"); + od->dnat_force_snat_addrs.ipv6_addrs[0].addr_s, + "dnat"); } } if (lb_force_snat_ip) { - if (lb_force_snat_addrs.n_ipv4_addrs) { + if (od->lb_force_snat_addrs.n_ipv4_addrs) { build_lrouter_force_snat_flows(lflows, od, "4", - lb_force_snat_addrs.ipv4_addrs[0].addr_s, "lb"); + od->lb_force_snat_addrs.ipv4_addrs[0].addr_s, "lb"); } - if (lb_force_snat_addrs.n_ipv6_addrs) { + if (od->lb_force_snat_addrs.n_ipv6_addrs) { build_lrouter_force_snat_flows(lflows, od, "6", - lb_force_snat_addrs.ipv6_addrs[0].addr_s, "lb"); + od->lb_force_snat_addrs.ipv6_addrs[0].addr_s, "lb"); } } @@ -10015,13 +10019,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "ip", "flags.loopback = 1; ct_dnat;"); } - if (dnat_force_snat_ip) { - destroy_lport_addresses(&dnat_force_snat_addrs); - } - if (lb_force_snat_ip) { - destroy_lport_addresses(&lb_force_snat_addrs); - } - /* Load balancing and packet defrag are only valid on * Gateway routers or router with gateway port. */ if (!smap_get(&od->nbr->options, "chassis") && !od->l3dgw_port) { From patchwork Thu Sep 17 12:51:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dumitru Ceara X-Patchwork-Id: 1366108 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=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Sl4dsLbO; dkim-atps=neutral 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 4BscN22y3mz9sSC for ; Thu, 17 Sep 2020 22:53:38 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id DA0092E1A0; Thu, 17 Sep 2020 12:53:36 +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 e+dhDipyqdVe; Thu, 17 Sep 2020 12:53:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 763052E1B6; Thu, 17 Sep 2020 12:52:03 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 66AC5C0864; Thu, 17 Sep 2020 12:52:03 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id ABA44C0051 for ; Thu, 17 Sep 2020 12:52:01 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id A8A0C878AE for ; Thu, 17 Sep 2020 12:52:01 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id COKaByrVpz19 for ; Thu, 17 Sep 2020 12:52:00 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by whitealder.osuosl.org (Postfix) with ESMTPS id 5E83A878A9 for ; Thu, 17 Sep 2020 12:52:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1600347119; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kmIwumqn6rJB1GZtqrlamE2gyGA8YHpviLeeiv/DuZs=; b=Sl4dsLbOlEOGOuH3c5QS1Q7a+Gqt0/Gkn24EC6MZGzkQe9+e42GhLvEPceEz4DBAy27DF5 xuNsPlfnOGYZHKxRn7g1gKSWdsYVz+yBY0amhnYlEaJbMBNJmfGUPX7zBkfJUoocJwgf1z /e5eo7XJHWpmi+9ezA8oVwLcQpadblI= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-218-7W6esefaOlClfP_sSXj2Ew-1; Thu, 17 Sep 2020 08:51:57 -0400 X-MC-Unique: 7W6esefaOlClfP_sSXj2Ew-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 47C401091068 for ; Thu, 17 Sep 2020 12:51:56 +0000 (UTC) Received: from dceara.remote.csb (ovpn-113-244.ams2.redhat.com [10.36.113.244]) by smtp.corp.redhat.com (Postfix) with ESMTP id A6A455DEBB for ; Thu, 17 Sep 2020 12:51:55 +0000 (UTC) From: Dumitru Ceara To: dev@openvswitch.org Date: Thu, 17 Sep 2020 14:51:53 +0200 Message-Id: <20200917125145.19729.68870.stgit@dceara.remote.csb> In-Reply-To: <20200917125025.19729.19409.stgit@dceara.remote.csb> References: <20200917125025.19729.19409.stgit@dceara.remote.csb> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v3 ovn 4/4] ovn-northd: Refactor processing of SNAT IPs. 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" Instead of building string sets every time we need to generate logical flows for unique SNAT IPs we now prebuild the set of unique SNAT IPs and store the list of NAT entries that refer it. Signed-off-by: Dumitru Ceara Acked-by: Han Zhou --- northd/ovn-northd.c | 326 ++++++++++++++++++++++++++++----------------------- 1 file changed, 176 insertions(+), 150 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 43bd7b5..1e88cb9 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -623,8 +623,9 @@ struct ovn_datapath { /* NAT entries configured on the router. */ struct ovn_nat *nat_entries; - /* SNAT IPs used by the router. */ - struct sset snat_ips; + /* SNAT IPs owned by the router (shash of 'struct ovn_snat_ip'). */ + struct shash snat_ips; + struct lport_addresses dnat_force_snat_addrs; struct lport_addresses lb_force_snat_addrs; @@ -644,6 +645,18 @@ struct ovn_datapath { struct ovn_nat { const struct nbrec_nat *nb; struct lport_addresses ext_addrs; + struct ovs_list ext_addr_list_node; /* Linkage in the per-external IP + * list of nat entries. Currently + * only used for SNAT. + */ +}; + +/* Stores the list of SNAT entries referencing a unique SNAT IP address. + * The 'snat_entries' list will be empty if the SNAT IP is used only for + * dnat_force_snat_ip or lb_force_snat_ip. + */ +struct ovn_snat_ip { + struct ovs_list snat_entries; }; static bool @@ -670,32 +683,49 @@ nat_entry_is_v6(const struct ovn_nat *nat_entry) } static void +snat_ip_add(struct ovn_datapath *od, const char *ip, struct ovn_nat *nat_entry) +{ + struct ovn_snat_ip *snat_ip = shash_find_data(&od->snat_ips, ip); + + if (!snat_ip) { + snat_ip = xzalloc(sizeof *snat_ip); + ovs_list_init(&snat_ip->snat_entries); + shash_add(&od->snat_ips, ip, snat_ip); + } + + if (nat_entry) { + ovs_list_push_back(&snat_ip->snat_entries, + &nat_entry->ext_addr_list_node); + } +} + +static void init_nat_entries(struct ovn_datapath *od) { if (!od->nbr) { return; } - sset_init(&od->snat_ips); + shash_init(&od->snat_ips); if (get_force_snat_ip(od, "dnat", &od->dnat_force_snat_addrs)) { - if (&od->dnat_force_snat_addrs.n_ipv4_addrs) { - sset_add(&od->snat_ips, - od->dnat_force_snat_addrs.ipv4_addrs[0].addr_s); + if (od->dnat_force_snat_addrs.n_ipv4_addrs) { + snat_ip_add(od, od->dnat_force_snat_addrs.ipv4_addrs[0].addr_s, + NULL); } - if (&od->dnat_force_snat_addrs.n_ipv6_addrs) { - sset_add(&od->snat_ips, - od->dnat_force_snat_addrs.ipv6_addrs[0].addr_s); + if (od->dnat_force_snat_addrs.n_ipv6_addrs) { + snat_ip_add(od, od->dnat_force_snat_addrs.ipv6_addrs[0].addr_s, + NULL); } } if (get_force_snat_ip(od, "lb", &od->lb_force_snat_addrs)) { if (od->lb_force_snat_addrs.n_ipv4_addrs) { - sset_add(&od->snat_ips, - od->lb_force_snat_addrs.ipv4_addrs[0].addr_s); + snat_ip_add(od, od->lb_force_snat_addrs.ipv4_addrs[0].addr_s, + NULL); } if (od->lb_force_snat_addrs.n_ipv6_addrs) { - sset_add(&od->snat_ips, - od->lb_force_snat_addrs.ipv6_addrs[0].addr_s); + snat_ip_add(od, od->lb_force_snat_addrs.ipv6_addrs[0].addr_s, + NULL); } } @@ -721,10 +751,15 @@ init_nat_entries(struct ovn_datapath *od) continue; } - if (!nat_entry_is_v6(nat_entry)) { - sset_add(&od->snat_ips, nat_entry->ext_addrs.ipv4_addrs[0].addr_s); - } else { - sset_add(&od->snat_ips, nat_entry->ext_addrs.ipv6_addrs[0].addr_s); + /* If this is a SNAT rule add the IP to the set of unique SNAT IPs. */ + if (!strcmp(nat->type, "snat")) { + if (!nat_entry_is_v6(nat_entry)) { + snat_ip_add(od, nat_entry->ext_addrs.ipv4_addrs[0].addr_s, + nat_entry); + } else { + snat_ip_add(od, nat_entry->ext_addrs.ipv6_addrs[0].addr_s, + nat_entry); + } } } } @@ -736,7 +771,7 @@ destroy_nat_entries(struct ovn_datapath *od) return; } - sset_destroy(&od->snat_ips); + shash_destroy_free_data(&od->snat_ips); destroy_lport_addresses(&od->dnat_force_snat_addrs); destroy_lport_addresses(&od->lb_force_snat_addrs); @@ -8728,6 +8763,65 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, } static void +build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage, + uint16_t priority, bool drop_snat, + struct hmap *lflows) +{ + struct ds match_ips = DS_EMPTY_INITIALIZER; + + if (op->lrp_networks.n_ipv4_addrs) { + for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + const char *ip = op->lrp_networks.ipv4_addrs[i].addr_s; + + if (drop_snat && !shash_find(&op->od->snat_ips, ip)) { + continue; + } else if (!drop_snat && shash_find(&op->od->snat_ips, ip)) { + continue; + } + ds_put_format(&match_ips, "%s, ", ip); + } + + if (ds_last(&match_ips) != EOF) { + ds_chomp(&match_ips, ' '); + ds_chomp(&match_ips, ','); + + char *match = xasprintf("ip4.dst == {%s}", ds_cstr(&match_ips)); + ovn_lflow_add_with_hint(lflows, op->od, stage, priority, + match, "drop;", + &op->nbrp->header_); + free(match); + } + } + + if (op->lrp_networks.n_ipv6_addrs) { + ds_clear(&match_ips); + + for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + const char *ip = op->lrp_networks.ipv6_addrs[i].addr_s; + + if (drop_snat && !shash_find(&op->od->snat_ips, ip)) { + continue; + } else if (!drop_snat && shash_find(&op->od->snat_ips, ip)) { + continue; + } + ds_put_format(&match_ips, "%s, ", ip); + } + + if (ds_last(&match_ips) != EOF) { + ds_chomp(&match_ips, ' '); + ds_chomp(&match_ips, ','); + + char *match = xasprintf("ip6.dst == {%s}", ds_cstr(&match_ips)); + ovn_lflow_add_with_hint(lflows, op->od, stage, priority, + match, "drop;", + &op->nbrp->header_); + free(match); + } + } + ds_destroy(&match_ips); +} + +static void build_lrouter_force_snat_flows(struct hmap *lflows, struct ovn_datapath *od, const char *ip_version, const char *ip_addr, const char *context) @@ -8879,68 +8973,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, op, lflows, &match, &actions); } - /* Drop IP traffic destined to router owned IPs. Part of it is dropped - * in stage "lr_in_ip_input" but traffic that could have been unSNATed - * but didn't match any existing session might still end up here. - */ - HMAP_FOR_EACH (op, key_node, ports) { - if (!op->nbrp) { - continue; - } - - if (op->lrp_networks.n_ipv4_addrs) { - ds_clear(&match); - for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - if (!sset_find(&op->od->snat_ips, - op->lrp_networks.ipv4_addrs[i].addr_s)) { - continue; - } - ds_put_format(&match, "%s, ", - op->lrp_networks.ipv4_addrs[i].addr_s); - } - - if (ds_last(&match) != EOF) { - ds_chomp(&match, ' '); - ds_chomp(&match, ','); - - char *drop_match = xasprintf("ip4.dst == {%s}", - ds_cstr(&match)); - /* Drop traffic with IP.dest == router-ip. */ - ovn_lflow_add_with_hint(lflows, op->od, - S_ROUTER_IN_ARP_RESOLVE, 1, - drop_match, "drop;", - &op->nbrp->header_); - free(drop_match); - } - } - - if (op->lrp_networks.n_ipv6_addrs) { - ds_clear(&match); - for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - if (!sset_find(&op->od->snat_ips, - op->lrp_networks.ipv6_addrs[i].addr_s)) { - continue; - } - ds_put_format(&match, "%s, ", - op->lrp_networks.ipv6_addrs[i].addr_s); - } - - if (ds_last(&match) != EOF) { - ds_chomp(&match, ' '); - ds_chomp(&match, ','); - - char *drop_match = xasprintf("ip6.dst == {%s}", - ds_cstr(&match)); - /* Drop traffic with IP.dest == router-ip. */ - ovn_lflow_add_with_hint(lflows, op->od, - S_ROUTER_IN_ARP_RESOLVE, 1, - drop_match, "drop;", - &op->nbrp->header_); - free(drop_match); - } - } - } - HMAP_FOR_EACH (od, key_node, datapaths) { if (!od->nbr) { continue; @@ -8966,29 +8998,37 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * 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 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; /* Skip entries we failed to parse. */ if (!nat_entry_is_valid(nat_entry)) { 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; + /* Skip SNAT entries for now, we handle unique SNAT IPs separately + * below. + */ + if (!strcmp(nat_entry->nb->type, "snat")) { + continue; + } + build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows); + } - if (!strcmp(nat->type, "snat")) { - if (!sset_add(&snat_ips, ext_addr)) { - continue; - } + /* Now handle SNAT entries too, one per unique SNAT IP. */ + struct shash_node *snat_snode; + SHASH_FOR_EACH (snat_snode, &od->snat_ips) { + struct ovn_snat_ip *snat_ip = snat_snode->data; + + if (ovs_list_is_empty(&snat_ip->snat_entries)) { + continue; } + + struct ovn_nat *nat_entry = + CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), + struct ovn_nat, ext_addr_list_node); build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows); } - sset_destroy(&snat_ips); /* Drop ARP packets (priority 85). ARP request packets for router's own * IPs are handled with priority-90 flows. @@ -9219,82 +9259,59 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } } - /* A gateway router can have 4 SNAT IP addresses to force DNATed and - * LBed traffic respectively to be SNATed. In addition, there can be - * a number of SNAT rules in the NAT table. - * Skip all of them for drop flows. */ - ds_clear(&match); - ds_put_cstr(&match, "ip4.dst == {"); - bool has_drop_ips = false; - for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - if (sset_find(&op->od->snat_ips, - op->lrp_networks.ipv4_addrs[i].addr_s)) { - continue; - } - ds_put_format(&match, "%s, ", - op->lrp_networks.ipv4_addrs[i].addr_s); - has_drop_ips = true; - } - if (has_drop_ips) { - ds_chomp(&match, ' '); - ds_chomp(&match, ','); - ds_put_cstr(&match, "} || ip6.dst == {"); - } else { - ds_clear(&match); - ds_put_cstr(&match, "ip6.dst == {"); - } - - for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - if (sset_find(&op->od->snat_ips, - op->lrp_networks.ipv6_addrs[i].addr_s)) { - continue; - } - ds_put_format(&match, "%s, ", - op->lrp_networks.ipv6_addrs[i].addr_s); - has_drop_ips = true; - } - - ds_chomp(&match, ' '); - ds_chomp(&match, ','); - ds_put_cstr(&match, "}"); - - if (has_drop_ips) { - /* Drop IP traffic to this router. */ - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, - ds_cstr(&match), "drop;", - &op->nbrp->header_); - } + /* Drop IP traffic destined to router owned IPs except if the IP is + * also a SNAT IP. Those are dropped later, in stage + * "lr_in_arp_resolve", if unSNAT was unsuccessful. + * + * Priority 60. + */ + build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false, + lflows); - /* ARP/NS packets are taken care of per router. The only exception - * is on the l3dgw_port where we might need to use a different - * ETH address. + /* ARP / ND handling for external IP addresses. + * + * DNAT and SNAT IP addresses are external IP addresses that need ARP + * handling. + * + * These are already taken care globally, per router. The only + * exception is on the l3dgw_port where we might need to use a + * different ETH address. */ if (op != op->od->l3dgw_port) { continue; } - struct sset sset_snat_ips = SSET_INITIALIZER(&sset_snat_ips); for (size_t i = 0; i < op->od->nbr->n_nat; i++) { struct ovn_nat *nat_entry = &op->od->nat_entries[i]; - const struct nbrec_nat *nat = nat_entry->nb; /* Skip entries we failed to parse. */ if (!nat_entry_is_valid(nat_entry)) { 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")) { - if (!sset_add(&sset_snat_ips, ext_addr)) { - continue; - } + /* Skip SNAT entries for now, we handle unique SNAT IPs separately + * below. + */ + if (!strcmp(nat_entry->nb->type, "snat")) { + continue; + } + build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows); + } + + /* Now handle SNAT entries too, one per unique SNAT IP. */ + struct shash_node *snat_snode; + SHASH_FOR_EACH (snat_snode, &op->od->snat_ips) { + struct ovn_snat_ip *snat_ip = snat_snode->data; + + if (ovs_list_is_empty(&snat_ip->snat_entries)) { + continue; } + + struct ovn_nat *nat_entry = + CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), + struct ovn_nat, ext_addr_list_node); build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows); } - sset_destroy(&sset_snat_ips); } /* DHCPv6 reply handling */ @@ -10813,6 +10830,15 @@ build_arp_resolve_flows_for_lrouter_port( &op->nbrp->header_); } } + + /* Drop IP traffic destined to router owned IPs. Part of it is dropped + * in stage "lr_in_ip_input" but traffic that could have been unSNATed + * but didn't match any existing session might still end up here. + * + * Priority 1. + */ + build_lrouter_drop_own_dest(op, S_ROUTER_IN_ARP_RESOLVE, 1, true, + lflows); } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router") && strcmp(op->nbsp->type, "virtual")) { /* This is a logical switch port that backs a VM or a container.