From patchwork Thu Jan 26 09:20:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mickey Spiegel X-Patchwork-Id: 720004 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3v8Gf26PNfz9tB1 for ; Thu, 26 Jan 2017 20:22:18 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="t+x1hIzh"; dkim-atps=neutral Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 026A1B4A; Thu, 26 Jan 2017 09:20:53 +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 5BA3A94B for ; Thu, 26 Jan 2017 09:20:51 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 2BED4137 for ; Thu, 26 Jan 2017 09:20:49 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id 19so16146361pfo.3 for ; Thu, 26 Jan 2017 01:20:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=DVPHdeSWIjK1wFsJjg5PqYTjqv7wasfXC00ujTusa3I=; b=t+x1hIzhrmbap8i7c7H3+jR/khI+qtpcvocOvXEu1BvL9QvcabWcFEC9j15AijdR4X zs3tZwBadoZuOjogMs9xY5DXmVW9kWPReqzLhhAUM9r/cPj4NZO4f5s7e54oL/kY7fpa K+qTxDHpdRgFwpBip9pBVevW0I/r6JXZFfCjAd6/WDZ29gMRoxHJQhgYWghD43BdbooC bxbVHljI2CfVOB0PtdhkSLCQRZBGY8TxwyJpZgVDl5FNhgTare9wsXD1RxxwX3rCTmXR /FsrSDmh3ifEm+e8fzzQO0M8dPu8G7d8lRXS/wM5PZ/f+7um5JrmlFv8B03EvsF7L3GU 3p3g== 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; bh=DVPHdeSWIjK1wFsJjg5PqYTjqv7wasfXC00ujTusa3I=; b=I93vEBMxlozsLKvFU87sR8AN9zddEpN+hJs5J/M0kWWOi8LWZUDuqe+MM2ezP/ZxnG MtxwjvL+Eq0TupQV/WGWSD8aRrUksvxEREnp5Or9Q2dRw+K+IKQPxLxcSae1vMl64rM3 2M/PnjohrmJ88/WY9/BW+vDQMrEoEawfR3NQydRSnA1WlJGi3UP8e15AnhcWFnDcw5yC GgMx6muxE4musDoAXpNqZ57ZrM3dBCPHBMKh7J1lJpEPhRrWIVJjzwoBO3zb1KIJflRf 8bRPdda+ykBjyHdqJJqYJwyWa72T6/EiZZISta2kc/cuWvU3/77qzCPxetZnkPr7RtlX lbxw== X-Gm-Message-State: AIkVDXKXFY7L8duVGNkZo6k7iLTv5t8tRt4SnqCjFa+cuo5IPDQpqsTECXri0bGPxvtiMw== X-Received: by 10.84.225.150 with SMTP id u22mr2706384plj.157.1485422448535; Thu, 26 Jan 2017 01:20:48 -0800 (PST) Received: from localhost.localdomain (c-73-202-53-195.hsd1.ca.comcast.net. [73.202.53.195]) by smtp.gmail.com with ESMTPSA id p25sm2345404pfd.0.2017.01.26.01.20.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 26 Jan 2017 01:20:47 -0800 (PST) From: Mickey Spiegel To: dev@openvswitch.org Date: Thu, 26 Jan 2017 01:20:28 -0800 Message-Id: <1485422430-3963-5-git-send-email-mickeys.dev@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1485422430-3963-1-git-send-email-mickeys.dev@gmail.com> References: <1485422430-3963-1-git-send-email-mickeys.dev@gmail.com> X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v12 4/6] ovn: ovn-nbctl commands for distributed NAT 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 This patch adds the new optional arguments "logical_port" and "external_mac" to lr-nat-add, and displays that information in lr-nat-list. Signed-off-by: Mickey Spiegel --- ovn/utilities/ovn-nbctl.8.xml | 27 +++++++++++++++++++--- ovn/utilities/ovn-nbctl.c | 54 +++++++++++++++++++++++++++++++++++++------ tests/ovn-nbctl.at | 47 +++++++++++++++++++++++++++++++++---- tests/system-ovn.at | 30 +++++------------------- 4 files changed, 119 insertions(+), 39 deletions(-) diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index f95b88d..d81e99f 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -444,7 +444,7 @@

NAT Commands

-
[--may-exist] lr-nat-add router type external_ip logical_ip
+
[--may-exist] lr-nat-add router type external_ip logical_ip [logical_port external_mac]

Adds the specified NAT to router. @@ -453,6 +453,13 @@ The external_ip is an IPv4 address. The logical_ip is an IPv4 network (e.g 192.168.1.0/24) or an IPv4 address. + The logical_port and external_mac are only + accepted when router is a distributed router (rather + than a gateway router) and type is + dnat_and_snat. + The logical_port is the name of an existing logical + switch port where the logical_ip resides. + The external_mac is an Ethernet address.

When type is dnat, the externally @@ -475,8 +482,22 @@ the IP address in external_ip.

- It is an error if a NAT already exists, - unless --may-exist is specified. + When the logical_port and external_mac + are specified, the NAT rule will be programmed on the chassis + where the logical_port resides. This includes + ARP replies for the external_ip, which return the + value of external_mac. All packets transmitted + with source IP address equal to external_ip will + be sent using the external_mac. +

+

+ It is an error if a NAT already exists with the same values + of router, type, external_ip, + and logical_ip, unless --may-exist is + specified. When --may-exist, + logical_port, and external_mac are all + specified, the existing values of logical_port and + external_mac are overwritten.

diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index f0ff27a..3dac434 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -390,7 +390,7 @@ Route commands:\n\ lr-route-list ROUTER print routes for ROUTER\n\ \n\ NAT commands:\n\ - lr-nat-add ROUTER TYPE EXTERNAL_IP LOGICAL_IP\n\ + lr-nat-add ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]\n\ add a NAT to ROUTER\n\ lr-nat-del ROUTER [TYPE [IP]]\n\ remove NATs from ROUTER\n\ @@ -2239,6 +2239,30 @@ nbctl_lr_nat_add(struct ctl_context *ctx) new_logical_ip = normalize_ipv4_prefix(ipv4, plen); } + const char *logical_port; + const char *external_mac; + if (ctx->argc == 6) { + ctl_fatal("lr-nat-add with logical_port " + "must also specify external_mac."); + } else if (ctx->argc == 7) { + if (strcmp(nat_type, "dnat_and_snat")) { + ctl_fatal("logical_port and external_mac are only valid when " + "type is \"dnat_and_snat\"."); + } + + logical_port = ctx->argv[5]; + lsp_by_name_or_uuid(ctx, logical_port, true); + + external_mac = ctx->argv[6]; + struct eth_addr ea; + if (!eth_addr_from_string(external_mac, &ea)) { + ctl_fatal("invalid mac address %s.", external_mac); + } + } else { + logical_port = NULL; + external_mac = NULL; + } + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; int is_snat = !strcmp("snat", nat_type); for (size_t i = 0; i < lr->n_nat; i++) { @@ -2249,6 +2273,10 @@ nbctl_lr_nat_add(struct ctl_context *ctx) if (!strcmp(is_snat ? external_ip : new_logical_ip, is_snat ? nat->external_ip : nat->logical_ip)) { if (may_exist) { + nbrec_nat_verify_logical_port(nat); + nbrec_nat_verify_external_mac(nat); + nbrec_nat_set_logical_port(nat, logical_port); + nbrec_nat_set_external_mac(nat, external_mac); free(new_logical_ip); return; } @@ -2271,6 +2299,10 @@ nbctl_lr_nat_add(struct ctl_context *ctx) nbrec_nat_set_type(nat, nat_type); nbrec_nat_set_external_ip(nat, external_ip); nbrec_nat_set_logical_ip(nat, new_logical_ip); + if (logical_port && external_mac) { + nbrec_nat_set_logical_port(nat, logical_port); + nbrec_nat_set_external_mac(nat, external_mac); + } free(new_logical_ip); /* Insert the NAT into the logical router. */ @@ -2353,17 +2385,24 @@ nbctl_lr_nat_list(struct ctl_context *ctx) struct smap lr_nats = SMAP_INITIALIZER(&lr_nats); for (size_t i = 0; i < lr->n_nat; i++) { const struct nbrec_nat *nat = lr->nat[i]; - smap_add_format(&lr_nats, nat->type, "%-19.15s%s", - nat->external_ip, nat->logical_ip); + const char *key = xasprintf("%-17.13s%s", nat->type, nat->external_ip); + if (nat->external_mac && nat->logical_port) { + smap_add_format(&lr_nats, key, "%-22.18s%-21.17s%s", + nat->logical_ip, nat->external_mac, + nat->logical_port); + } else { + smap_add_format(&lr_nats, key, "%s", nat->logical_ip); + } } const struct smap_node **nodes = smap_sort(&lr_nats); if (nodes) { - ds_put_format(&ctx->output, "%-17.13s%-19.15s%s\n", - "TYPE", "EXTERNAL_IP", "LOGICAL_IP"); + ds_put_format(&ctx->output, "%-17.13s%-19.15s%-22.18s%-21.17s%s\n", + "TYPE", "EXTERNAL_IP", "LOGICAL_IP", "EXTERNAL_MAC", + "LOGICAL_PORT"); for (size_t i = 0; i < smap_count(&lr_nats); i++) { const struct smap_node *node = nodes[i]; - ds_put_format(&ctx->output, "%-17.13s%s\n", + ds_put_format(&ctx->output, "%-36.32s%s\n", node->key, node->value); } free(nodes); @@ -3314,7 +3353,8 @@ static const struct ctl_command_syntax nbctl_commands[] = { "", RO }, /* NAT commands. */ - { "lr-nat-add", 4, 4, "ROUTER TYPE EXTERNAL_IP LOGICAL_IP", NULL, + { "lr-nat-add", 4, 6, + "ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]", NULL, nbctl_lr_nat_add, NULL, "--may-exist", RW }, { "lr-nat-del", 1, 3, "ROUTER [TYPE [IP]]", NULL, nbctl_lr_nat_del, NULL, "--if-exists", RW }, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 164c81a..cec516f 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -283,15 +283,34 @@ AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.2 192.168.1.2/24], [1], [], AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2/24], [1], [], [ovn-nbctl: 192.168.1.2/24: should be an IPv4 address. ]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2 lp0], [1], [], +[ovn-nbctl: lr-nat-add with logical_port must also specify external_mac. +]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.2 192.168.1.2 lp0 00:00:00:01:02:03], [1], [], +[ovn-nbctl: logical_port and external_mac are only valid when type is "dnat_and_snat". +]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.2 192.168.1.2 lp0 00:00:00:01:02:03], [1], [], +[ovn-nbctl: logical_port and external_mac are only valid when type is "dnat_and_snat". +]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2 lp0 00:00:00:01:02:03], [1], [], +[ovn-nbctl: lp0: port name not found +]) +AT_CHECK([ovn-nbctl ls-add ls0]) +AT_CHECK([ovn-nbctl lsp-add ls0 lp0]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2 lp0 00:00:00:01:02], [1], [], +[ovn-nbctl: invalid mac address 00:00:00:01:02. +]) dnl Add snat and dnat AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.1 192.168.1.0/24]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.1 192.168.1.2]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.1 192.168.1.2]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.3 lp0 00:00:00:01:02:03]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE EXTERNAL_IP LOGICAL_IP +TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT dnat 30.0.0.1 192.168.1.2 dnat_and_snat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 00:00:00:01:02:03 lp0 snat 30.0.0.1 192.168.1.0/24 ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.1 192.168.1.0/24], [1], [], @@ -318,10 +337,26 @@ AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat 30.0.0.1 192.168.1. AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.1 192.168.1.3], [1], [], [ovn-nbctl: a NAT with this type (dnat_and_snat) and external_ip (30.0.0.1) already exists ]) +AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.3 lp0 00:00:00:04:05:06]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 00:00:00:04:05:06 lp0 +snat 30.0.0.1 192.168.1.0/24 +]) +AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.3]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 +snat 30.0.0.1 192.168.1.0/24 +]) dnl Deletes the NATs -AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.2], [1], [], -[ovn-nbctl: no matching NAT with the type (dnat_and_snat) and external_ip (30.0.0.2) +AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.3], [1], [], +[ovn-nbctl: no matching NAT with the type (dnat_and_snat) and external_ip (30.0.0.3) ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat 30.0.0.2], [1], [], [ovn-nbctl: no matching NAT with the type (dnat) and external_ip (30.0.0.2) @@ -333,14 +368,16 @@ AT_CHECK([ovn-nbctl --if-exists lr-nat-del lr0 snat 192.168.10.0/24]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.1]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE EXTERNAL_IP LOGICAL_IP +TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT dnat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 snat 30.0.0.1 192.168.1.0/24 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE EXTERNAL_IP LOGICAL_IP +TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat_and_snat 30.0.0.2 192.168.1.3 snat 30.0.0.1 192.168.1.0/24 ]) diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 307cbb3..638ac56 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -1145,20 +1145,11 @@ ovn-nbctl lsp-add alice alice1 \ -- lsp-set-addresses alice1 "f0:00:00:01:02:05 172.16.1.2" # Add DNAT rules -ovn-nbctl -- --id=@nat create nat type="dnat_and_snat" \ - logical_ip=192.168.1.2 external_ip=172.16.1.3 \ - external_mac=\"00:00:02:02:03:04\" logical_port=foo1 \ - -- add logical_router R1 nat @nat - -ovn-nbctl -- --id=@nat create nat type="dnat_and_snat" \ - logical_ip=192.168.1.3 external_ip=172.16.1.4 \ - external_mac=\"00:00:02:02:03:05\" logical_port=foo2 \ - -- add logical_router R1 nat @nat +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 00:00:02:02:03:04]) +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.4 192.168.1.3 foo2 00:00:02:02:03:05]) # Add a SNAT rule -ovn-nbctl -- --id=@nat create nat type="snat" \ - logical_ip=192.168.0.0/16 external_ip=172.16.1.1 \ - -- add logical_router R1 nat @nat +AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.0.0/16]) OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep ct\( | grep nat]) @@ -1300,20 +1291,11 @@ ovn-nbctl lsp-add alice alice1 \ -- lsp-set-addresses alice1 "f0:00:00:01:02:05 172.16.1.2" # Add DNAT rules -ovn-nbctl -- --id=@nat create nat type="dnat_and_snat" \ - logical_ip=192.168.1.2 external_ip=172.16.1.3 \ - external_mac=\"00:00:02:02:03:04\" logical_port=foo1 \ - -- add logical_router R1 nat @nat - -ovn-nbctl -- --id=@nat create nat type="dnat_and_snat" \ - logical_ip=192.168.2.2 external_ip=172.16.1.4 \ - external_mac=\"00:00:02:02:03:05\" logical_port=bar1 \ - -- add logical_router R1 nat @nat +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 00:00:02:02:03:04]) +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.4 192.168.2.2 bar1 00:00:02:02:03:05]) # Add a SNAT rule -ovn-nbctl -- --id=@nat create nat type="snat" \ - logical_ip=192.168.0.0/16 external_ip=172.16.1.1 \ - -- add logical_router R1 nat @nat +AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.0.0/16]) OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep ct\( | grep nat])