From patchwork Fri Jul 26 06:32:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dumitru Ceara X-Patchwork-Id: 1137258 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45vzn23S3mz9s8m for ; Fri, 26 Jul 2019 16:33:42 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 77BD57F6; Fri, 26 Jul 2019 06:33:39 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 30EDF3EE for ; Fri, 26 Jul 2019 06:33:38 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 888C5709 for ; Fri, 26 Jul 2019 06:33:37 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EA307C059B6F; Fri, 26 Jul 2019 06:33:36 +0000 (UTC) Received: from dceara.remote.csb (ovpn-116-111.ams2.redhat.com [10.36.116.111]) by smtp.corp.redhat.com (Postfix) with ESMTP id 69A4D1001B02; Fri, 26 Jul 2019 06:33:35 +0000 (UTC) From: Dumitru Ceara To: dev@openvswitch.org Date: Fri, 26 Jul 2019 08:32:37 +0200 Message-Id: <1564122757-24465-1-git-send-email-dceara@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 26 Jul 2019 06:33:36 +0000 (UTC) X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Guru Shetty Subject: [ovs-dev] [PATCH v2] OVN: Fix learning of neighbors from ARP/ND packets. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add a restriction on the target protocol addresses to match the configured subnets. All other ARP/ND packets are invalid in this context. One exception is for ARP replies that are received for route next-hops that are only reachable via a port but can't be directly resolved through route lookups. Such support was introduced by commit: 6b785fd8fe29 ("ovn-util: Allow /32 IP addresses for router ports.") Reported-at: https://bugzilla.redhat.com/1729846 Reported-by: Haidong Li CC: Han Zhou CC: Guru Shetty Fixes: b068454082f5 ("ovn-northd: Support learning neighbor from ARP request.") Signed-off-by: Dumitru Ceara --- v2: - Update commit message. - Implement the fix also for ARP replies and IPv6 ND. --- ovn/northd/ovn-northd.c | 95 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index eb6c47c..1e3ec68 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -5815,10 +5815,32 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, if (is_ipv4) { if (out_port->lrp_networks.n_ipv4_addrs) { lrp_addr_s = out_port->lrp_networks.ipv4_addrs[0].addr_s; + + /* Explicitly allow ARP replies for the next-hop. */ + struct ds match; + ds_init(&match); + ds_put_format(&match, "inport == %s && arp.op == 2 && " + "arp.spa == %s", out_port->json_key, + route->nexthop); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_arp(inport, arp.spa, arp.sha);"); + ds_destroy(&match); } } else { if (out_port->lrp_networks.n_ipv6_addrs) { lrp_addr_s = out_port->lrp_networks.ipv6_addrs[0].addr_s; + + /* Explicitly allow NA for the next-hop. */ + struct ds match; + ds_init(&match); + ds_put_format(&match, "inport == %s && nd_na && " + "ip6.src == %s", out_port->json_key, + route->nexthop); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_nd(inport, nd.target, nd.tll);"); + ds_destroy(&match); } } } @@ -6159,10 +6181,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "ip4.dst == 0.0.0.0/8", "drop;"); - /* ARP reply handling. Use ARP replies to populate the logical - * router's ARP table. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "arp.op == 2", - "put_arp(inport, arp.spa, arp.sha);"); /* Drop Ethernet local broadcast. By definition this traffic should * not be forwarded.*/ @@ -6175,16 +6193,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, ds_cstr(&match), "drop;"); - /* ND advertisement handling. Use advertisements to populate - * the logical router's ARP/ND table. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "nd_na", - "put_nd(inport, nd.target, nd.tll);"); - /* Lean from neighbor solicitations that were not directed at - * us. (A priority-90 flow will respond to requests to us and - * learn the sender's mac address. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 80, "nd_ns", - "put_nd(inport, ip6.src, nd.sll);"); /* Pass other traffic not already handled to the next table for * routing. */ @@ -6320,15 +6329,34 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_cstr(&match), ds_cstr(&actions)); } + /* ARP reply handling. Use ARP replies to populate the logical + * router's ARP table. */ + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + ds_clear(&match); + ds_put_format(&match, "inport == %s && arp.spa == %s/%u && " + "arp.tpa == %s/%u && arp.op == 2", + op->json_key, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_arp(inport, arp.spa, arp.sha);"); + } + /* Learn from ARP requests that were not directed at us. A typical * use case is GARP request handling. (A priority-90 flow will * respond to request to us and learn the sender's mac address.) */ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { ds_clear(&match); ds_put_format(&match, - "inport == %s && arp.spa == %s/%u && arp.op == 1", + "inport == %s && arp.spa == %s/%u && " + "arp.tpa == %s/%u && arp.op == 1", op->json_key, op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen, + op->lrp_networks.ipv4_addrs[i].network_s, op->lrp_networks.ipv4_addrs[i].plen); if (op->od->l3dgw_port && op == op->od->l3dgw_port && op->od->l3redirect_port) { @@ -6669,6 +6697,45 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_cstr(&match), ds_cstr(&actions)); } + /* NA reply handling. Use NA replies to populate the logical + * router's neighbor table. */ + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(&match); + ds_put_format(&match, "inport == %s && nd_na && " + "nd.target == %s/%u && ip6.src == %s/%u", + op->json_key, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_nd(inport, nd.target, nd.tll);"); + } + + /* Learn from ND requests that were not directed at us. + * (A priority-90 flow will respond to request to us and learn the + * sender's mac address.) */ + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(&match); + ds_put_format(&match, + "inport == %s && nd_ns && ip6.src == %s/%u && " + "ip6.dst == %s/%u", + op->json_key, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen); + if (op->od->l3dgw_port && op == op->od->l3dgw_port + && op->od->l3redirect_port) { + ds_put_format(&match, " && is_chassis_resident(%s)", + op->od->l3redirect_port->json_key); + } + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, + ds_cstr(&match), + "put_nd(inport, ip6.src, nd.sll);"); + } + /* UDP/TCP port unreachable */ if (!smap_get(&op->od->nbr->options, "chassis") && !op->od->l3dgw_port) {