From patchwork Thu Mar 28 15:31:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1068320 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 44VTPR1ccbz9sRj for ; Fri, 29 Mar 2019 02:31:54 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id EB428E70; Thu, 28 Mar 2019 15:31:49 +0000 (UTC) X-Original-To: ovs-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 5CDF1E5B for ; Thu, 28 Mar 2019 15:31:48 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5CBED75B for ; Thu, 28 Mar 2019 15:31:47 +0000 (UTC) Received: by mail-wr1-f41.google.com with SMTP id y13so5748966wrd.3 for ; Thu, 28 Mar 2019 08:31:47 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=w5yEcGvAYfvaKraRK6CqBDWs0T3eni/z9+y2uj/YwqE=; b=SqqO0L1WZWSYcGaTDWGosaW+VxhFxzJNtm0w+JmHs0NIF7MYATH3gnwnbqcpgW8FZY FAcaI6vAjXM3g0bdVsIkEoWCwVEUn6tymNceBb/FBpvMIK6+J98UMjhWTt+MREi163JZ Ngo99uzG/6wO9KNOKCMktkmoZMt0gkGp+KjUVMgXv4de+w5QSfdN0QaX3YOeYc+kc1Aw sfDqQDkOsMEJ9f8hHx/+GCP5mI1t6lIOFTu3fS5TLazjJrkqtGy5Cmno9dk74TSFvHP2 4GVz/1Sc2mmsyM2H3o76YC7NXUNGZbRxZ1GbgeNp/GDw70qnlPP0LIIhtvuHPMcqGQOP 7WXA== X-Gm-Message-State: APjAAAXRQNl0+NYGCPBpK5Jd1JYkKiXlN0THazUoFFsr262tW5ncwOPV lwIN9cV9RTyXpRvhfLCxSvpQ5MHywzI= X-Google-Smtp-Source: APXvYqxL2huIuYLMyILLxe1LT+ABO0k+HlJZn6ixEVhdrKacr37ysLVOuu+dGqGwr+p9KG+JGVaUZQ== X-Received: by 2002:adf:ce87:: with SMTP id r7mr26678693wrn.324.1553787105571; Thu, 28 Mar 2019 08:31:45 -0700 (PDT) Received: from localhost.localdomain.com (nat-pool-mxp-t.redhat.com. [149.6.153.186]) by smtp.gmail.com with ESMTPSA id 13sm3389294wmj.33.2019.03.28.08.31.44 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 28 Mar 2019 08:31:44 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 28 Mar 2019 16:31:35 +0100 Message-Id: <9f507e842c39d9749023bf8f5f061c8ac9c0a58a.1553786655.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [RFC] OVN: fix DVR Floating IP support 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: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org When DVR is enabled FIP traffic need to be forwarded directly using external connection to the underlay network and not be distributed through geneve tunnels. Fix this adding new logical flows to take care of distributed DNAT/SNAT Signed-off-by: Lorenzo Bianconi --- ovn/northd/ovn-northd.8.xml | 51 ++++++++++++++++++ ovn/northd/ovn-northd.c | 105 ++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml index 392a5efc9..1cec0a69d 100644 --- a/ovn/northd/ovn-northd.8.xml +++ b/ovn/northd/ovn-northd.8.xml @@ -1828,6 +1828,37 @@ output;

    +
  • +

    + For distributed logical routers where one of the logical router + ports specifies a redirect-chassis, a priority-400 + logical flow for each ip source/destination couple that matches the + dnat_and_snat NAT rules configured. These flows will + allow to properly forward traffic to the external connections if + available and avoid sending it through the tunnel. + Assuming the two following NAT rules have been configured: +

    + +
    +external_ip{0,1} = EIP{0,1};
    +external_mac{0,1} = MAC{0,1};
    +logical_ip{0,1} = LIP{0,1};
    +        
    + +

    + the following action will be applied: +

    + +
    +eth.dst = MAC0;
    +eth.src = MAC1;
    +reg0 = ip4.dst;
    +reg1 = EIP1;
    +outport = redirect-chassis-port;
    +REGBIT_DISTRIBUTED_NAT = 1; next;.
    +        
    +
  • +
  • For distributed logical routers where one of the logical router @@ -1924,6 +1955,12 @@ next;

    • +

      + For distributed logical routers where one of the logical router + ports specifies a redirect-chassis, a priority-400 + logical flow with match REGBIT_DISTRIBUTED_NAT == 1 + has action next; +

      For distributed logical routers where one of the logical router ports specifies a redirect-chassis, a priority-200 @@ -2012,6 +2049,11 @@ next;

        +
      • + A priority-300 logical flow with match + REGBIT_DISTRIBUTED_NAT == 1 has action + next; +
      • A priority-200 logical flow with match REGBIT_NAT_REDIRECT == 1 has actions @@ -2321,6 +2363,15 @@ nd_ns {
        • +

          + For each dnat_and_snat NAT rule couple in the + OVN Northbound database on a distributed router, + a priority-200 logical with match + ip4.dst == external_ip0 && + ip4.src == external_ip1, has action + next; +

          +

          For each NAT rule in the OVN Northbound database on a distributed router, a priority-100 logical flow with match diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 05b8aad4f..0f42b2ba5 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -179,6 +179,7 @@ enum ovn_stage { * logical router dropping packets with source IP address equals * one of the logical router's own IP addresses. */ #define REGBIT_EGRESS_LOOPBACK "reg9[1]" +#define REGBIT_DISTRIBUTED_NAT "reg9[2]" /* Returns an "enum ovn_stage" built from the arguments. */ static enum ovn_stage @@ -4678,6 +4679,66 @@ find_lrp_member_ip(const struct ovn_port *op, const char *ip_s) return NULL; } +static void +add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) +{ + struct ds actions = DS_EMPTY_INITIALIZER; + struct ds match = DS_EMPTY_INITIALIZER; + + if (!op->od->l3dgw_port) { + return; + } + + for (size_t i = 0; i < op->od->nbr->n_nat; i++) { + const struct nbrec_nat *nat = op->od->nbr->nat[i]; + bool found = false; + + if (strcmp(nat->type, "dnat_and_snat") || + !nat->external_mac || !nat->external_ip) { + continue; + } + + if (!op->peer || !op->peer->od->nbs) { + continue; + } + + const struct ovn_datapath *peer_dp = op->peer->od; + for (size_t j = 0; j < peer_dp->nbs->n_ports; j++) { + if (!strcmp(peer_dp->nbs->ports[j]->name, nat->logical_port)) { + found = true; + break; + } + } + if (!found) { + continue; + } + + for (size_t j = 0; j < op->od->nbr->n_nat; j++) { + const struct nbrec_nat *nat2 = op->od->nbr->nat[j]; + + if (nat == nat2 || strcmp(nat2->type, "dnat_and_snat") || + !nat2->external_mac || !nat2->external_ip) + continue; + + ds_put_format(&match, "inport == %s && " + "ip4.src == %s && ip4.dst == %s", + op->json_key, nat->logical_ip, nat2->external_ip); + ds_put_format(&actions, "outport = %s; " + "eth.src = %s; eth.dst = %s; " + "reg0 = ip4.dst; reg1 = %s; " + REGBIT_DISTRIBUTED_NAT" = 1; " + REGBIT_NAT_REDIRECT" = 0; next;", + op->od->l3dgw_port->json_key, + op->od->l3dgw_port->lrp_networks.ea_s, + nat2->external_mac, nat->external_ip); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, + ds_cstr(&match), ds_cstr(&actions)); + ds_clear(&match); + ds_clear(&actions); + } + } +} + static void add_route(struct hmap *lflows, const struct ovn_port *op, const char *lrp_addr_s, const char *network_s, int plen, @@ -6061,6 +6122,41 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * ingress pipeline with inport = outport. */ if (od->l3dgw_port) { /* Distributed router. */ + if (!strcmp(nat->type, "dnat_and_snat") && + nat->external_mac && nat->external_ip) { + for (int j = 0; j < od->nbr->n_nat; j++) { + const struct nbrec_nat *nat2 = od->nbr->nat[j]; + + if (nat2 == nat || + strcmp(nat2->type, "dnat_and_snat") || + !nat2->external_mac || !nat2->external_ip) { + continue; + } + + ds_clear(&match); + ds_put_format(&match, "is_chassis_resident(\"%s\") && " + "ip4.src == %s && ip4.dst == %s", + nat->logical_port, nat2->external_ip, + nat->external_ip); + ds_clear(&actions); + ds_put_format(&actions, + "inport = outport; outport = \"\"; " + "flags = 0; flags.loopback = 1; " + REGBIT_EGRESS_LOOPBACK" = 1; " + "next(pipeline=ingress, table=0); "); + ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 300, + ds_cstr(&match), ds_cstr(&actions)); + + ds_clear(&match); + ds_put_format(&match, + "ip4.src == %s && ip4.dst == %s", + nat2->external_ip, nat->external_ip); + ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 200, + ds_cstr(&match), "next;"); + ds_clear(&match); + } + } + ds_clear(&match); ds_put_format(&match, "ip4.dst == %s && outport == %s", nat->external_ip, @@ -6132,6 +6228,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, "ip", "flags.loopback = 1; ct_dnat;"); } else { + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 400, + REGBIT_DISTRIBUTED_NAT" == 1", "next;"); + /* For NAT on a distributed router, add flows to Ingress * IP Routing table, Ingress ARP Resolution table, and * Ingress Gateway Redirect Table that are not specific to a @@ -6367,6 +6466,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } + /* create logical flows for DVR floating IPs */ + add_distributed_nat_routes(lflows, op); + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s, op->lrp_networks.ipv4_addrs[i].network_s, @@ -6607,6 +6709,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } if (od->l3dgw_port && od->l3redirect_port) { + ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300, + REGBIT_DISTRIBUTED_NAT" == 1", "next;"); + /* For traffic with outport == l3dgw_port, if the * packet did not match any higher priority redirect * rule, then the traffic is redirected to the central