From patchwork Sun Jun 28 22:02:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ankur Sharma X-Patchwork-Id: 1318680 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=nutanix.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=nutanix.com header.i=@nutanix.com header.a=rsa-sha256 header.s=proofpoint20171006 header.b=ZZWv6SxH; 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 49w4PK1lYxz9sQx for ; Mon, 29 Jun 2020 08:03:01 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id B2416881EC; Sun, 28 Jun 2020 22:02:59 +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 eN3oT4OAOm1p; Sun, 28 Jun 2020 22:02:55 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id 84A8788089; Sun, 28 Jun 2020 22:02:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 69A00C0892; Sun, 28 Jun 2020 22:02:55 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 53F9FC08A6 for ; Sun, 28 Jun 2020 22:02:52 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 5024C88049 for ; Sun, 28 Jun 2020 22:02:52 +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 YK-Vxv5l2Q8v for ; Sun, 28 Jun 2020 22:02:51 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx0b-002c1b01.pphosted.com (mx0b-002c1b01.pphosted.com [148.163.155.12]) by hemlock.osuosl.org (Postfix) with ESMTPS id 31E7187F3F for ; Sun, 28 Jun 2020 22:02:51 +0000 (UTC) Received: from pps.filterd (m0127841.ppops.net [127.0.0.1]) by mx0b-002c1b01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 05SM0wxw025251 for ; Sun, 28 Jun 2020 15:02:50 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nutanix.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : content-type : mime-version; s=proofpoint20171006; bh=KnR4eoeXvrs4iDye3KFJ1fqU5FjIxQScnbdEryuaywA=; b=ZZWv6SxHRHpEz0GrOcot2c4twVPp9Xi8iyl6x3gif0cz24NuXJ8IOIO5qPGktzetRz31 7ZHWQ1M3uwbYUN8e4eaexwQiee+UfJHRxordNyL0WgrFNbC8YJSk1SaV9enHpFiGFtA4 VSBxKpGTCI0WNL4ieLME+2aHfqTidxEZVEqqcCIuMAi4TlMhZljEU8lRbRR6sD8TxUWs /LMc3tNPwKZmAhU2rSZAuB+IzLou6QdRQdli7jnNLz2P/Zou5g4XfSr7Uhn93Sb1ZVzP ETfAypHM/n8oyLjjyF5rqVccE8VCTbHYBv7aLBkwmEjOCcRjNVi5neGp6cR2S/CogDRd aw== Received: from nam02-bl2-obe.outbound.protection.outlook.com (mail-bl2nam02lp2052.outbound.protection.outlook.com [104.47.38.52]) by mx0b-002c1b01.pphosted.com with ESMTP id 31x3naa5yh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sun, 28 Jun 2020 15:02:50 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=NtXUWQBz/GCBq5AKVYEL34GoQpHQtbR26UoVp9p6vr+hw34dUqXYsGXr1ONTGjg2YeMJuehU4O5wbrQLjfGwhwyEmZ7dIKLvjKcOYzksTcwo+qlNi9PaaLh+GULaJjGKRDGMjmwQM2m6dsVsO/YAyIDkMW6NTPmqjR0k4myIXHiQclD4zpPvGqo7A+bDGhgmOUuacWCBsvT3bj4CtgEnr6t4ZOcGxI3lL32BJSZZNyD2dP+vRvtrnEbmQf4PjT7ZBOV03JVp+o18kSHCWRx5GKAaDgyxijbHXhFIljxKF6MgPYJ2zyV+nEFT2xUQxmY7XKfq0TT4luID9KwhOXdWuQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=KnR4eoeXvrs4iDye3KFJ1fqU5FjIxQScnbdEryuaywA=; b=RbpA/IbeGuYxy5eO/BT1uO61PVDJ7XiBGbo7yExslmg2DCJbXhB378N18A/8QcGUXlpCUmNK0FShY9h6NSAKACnnbnsy1GJIdCbWr35/UdX7a9lXrGNHk6pT7pgLS8owh/iJqbFO1rygq3VwnGDuNdPXFAazviM/JQahywT+JTEsfcdhtrM8DdhzxMPJmnaVOm5+DSTNn1N4VfhQiYoXhSlAGCoyDpltGiQcn0/hZV6qTCyUcu8IAXYxYtM1S+ZUp42V+pcAO35Lg6ozW4HQnEJsq+eWb5YNaqfE5oM94mJOb9tUQOXelxvLfz27PKOPefaI9wVFD4CYYt/qN1b92Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nutanix.com; dmarc=pass action=none header.from=nutanix.com; dkim=pass header.d=nutanix.com; arc=none Authentication-Results: openvswitch.org; dkim=none (message not signed) header.d=none;openvswitch.org; dmarc=none action=none header.from=nutanix.com; Received: from BL0PR02MB3714.namprd02.prod.outlook.com (2603:10b6:207:44::16) by BL0PR02MB4961.namprd02.prod.outlook.com (2603:10b6:208:57::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3131.26; Sun, 28 Jun 2020 22:02:48 +0000 Received: from BL0PR02MB3714.namprd02.prod.outlook.com ([fe80::445e:7f74:952e:2ccb]) by BL0PR02MB3714.namprd02.prod.outlook.com ([fe80::445e:7f74:952e:2ccb%5]) with mapi id 15.20.3131.026; Sun, 28 Jun 2020 22:02:48 +0000 From: Ankur Sharma To: ovs-dev@openvswitch.org Date: Sun, 28 Jun 2020 15:02:36 -0700 Message-Id: <1593381757-40032-2-git-send-email-svc.mail.git@nutanix.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1593381757-40032-1-git-send-email-svc.mail.git@nutanix.com> References: <1593381757-40032-1-git-send-email-svc.mail.git@nutanix.com> X-ClientProxiedBy: BYAPR07CA0008.namprd07.prod.outlook.com (2603:10b6:a02:bc::21) To BL0PR02MB3714.namprd02.prod.outlook.com (2603:10b6:207:44::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from northd.localdomain (192.146.154.98) by BYAPR07CA0008.namprd07.prod.outlook.com (2603:10b6:a02:bc::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3131.20 via Frontend Transport; Sun, 28 Jun 2020 22:02:48 +0000 X-Mailer: git-send-email 1.8.3.1 X-Originating-IP: [192.146.154.98] X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: b52f3425-f12e-4e88-177a-08d81baefec0 X-MS-TrafficTypeDiagnostic: BL0PR02MB4961: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: x-proofpoint-crosstenant: true X-MS-Oob-TLC-OOBClassifiers: OLM:376; X-Forefront-PRVS: 0448A97BF2 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: npO79chY9m92TO28ZHRWipaR91Pm5M2YznbOoc6z8tQRE2u3Yi4xq73Wh5RhBVUaqJUXytsniQVRVNBh9wJTveS4Dleym1ajbK5LhEnXr8l+7hUW+3O5IBefkLKhO7ApTF0NCuHHQG/0+wwaBNr1uiBD7pPjpq8qkWHRti7RM1zxseQnTIERMnpjgIwfJIIzlQz22Jg/jnwvqiWk0pqpFNPM27XpdnqEzB63x6a7Owzq3FhyBC6YbQNX/yL4HL6GtJWyCS8xNT1UpH3VJqJlNLeJSbSDopGUGcozFdxSWh0FXHtCtn2ZkBkO5RgjfsGJr+leKfqLEHpbJn35DnzpNg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:BL0PR02MB3714.namprd02.prod.outlook.com; PTR:; CAT:NONE; SFTY:; SFS:(396003)(39850400004)(366004)(136003)(376002)(346002)(66556008)(66946007)(8676002)(66476007)(83380400001)(36756003)(8936002)(956004)(478600001)(2616005)(6486002)(186003)(86362001)(107886003)(6666004)(26005)(16526019)(66574015)(52116002)(6916009)(6512007)(2906002)(6506007)(316002)(5660300002)(4326008)(54906003); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData: qxHOAjFeF+2iYPRujjndK5CyjKXnar9TLqqpg9OIwEUmg4/SeFX8EGEC6vd+yc4CyVUeYVTIR6pnUFjc8zj+6NOIZYu9tIf7JYgY8m7Fv6Z7VAa5aas4lgAjdvtkXK4keRomsfB7XrUyEXAf7p+aTIIgbdynJzCJdzX08115uBBqwTdIdY7QNjxfXHeTKRNbJUCfUby4YikMeDmwN28J/JxHSKSmt4QMIXqPEy0cnB85gL/d92SQnfxfdjnQs3fqiirXzVBc4dQYBj+S8o6smN/zkvPjNdI+qM1N3WwxfJIO7w6m1OiDv1TGDljQbrDGgzr8LcHcaz0ptuMstIDcN3wGXGi7Mth+enZmO/jGbdNTdZ4pbu4r+MuXUw0nWdVSTnqi+vpYtOCg1B06t0ZDyz3O+MbIWqmpc4eJT6U5xhZ20z1+xVEV+eVHkJ8G/0cmOVwAXXigDLDMbudUkzfsU+wznjSL45UVuSAeQlkBvdo= X-OriginatorOrg: nutanix.com X-MS-Exchange-CrossTenant-Network-Message-Id: b52f3425-f12e-4e88-177a-08d81baefec0 X-MS-Exchange-CrossTenant-AuthSource: BL0PR02MB3714.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Jun 2020 22:02:48.6885 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bb047546-786f-4de1-bd75-24e5b6f79043 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: SoGZHFgqCojtqxuM3Y0135jJLJI7n2assoaVSb3EOFrzfoZQoqxSvsCDo69Wk8itbtA0ppBeHRJDGJBUgwb5hIJdvq1qaByuf1T49Z1dgvs= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL0PR02MB4961 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.216, 18.0.687 definitions=2020-06-28_11:2020-06-26, 2020-06-28 signatures=0 X-Proofpoint-Spam-Reason: safe Subject: [ovs-dev] [PATCH v1 1/2 ovn] External IP based NAT: Add Columns and CLI 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" This patch adds following columns to NAT table. a. allowed_external_ip: Represents Address Set of External IPs for which a NAT rule is applicable. b. disallowed_external_ip Represents Address Set of External IPs for which a NAT rule is NOT applicable. Additionally, patch adds nbctl cli to set these column values. ovn-nbctl [--is-allowed] lr-nat-update-ext-ip Signed-off-by: Ankur Sharma --- ovn-nb.ovsschema | 14 ++++++- ovn-nb.xml | 24 ++++++++++++ tests/ovn-nbctl.at | 37 +++++++++++++++++- utilities/ovn-nbctl.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 173 insertions(+), 4 deletions(-) diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index da9af71..a0920dd 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.24.0", - "cksum": "1092394564 25961", + "version": "5.24.1", + "cksum": "2908501684 26686", "tables": { "NB_Global": { "columns": { @@ -400,6 +400,16 @@ "snat", "dnat_and_snat" ]]}}}, + "allowed_external_ip": {"type": {"key": {"type": "uuid", + "refTable": "Address_Set", + "refType": "strong"}, + "min": 0, + "max": 1}}, + "disallowed_external_ip": {"type": {"key": {"type": "uuid", + "refTable": "Address_Set", + "refType": "strong"}, + "min": 0, + "max": 1}}, "options": {"type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}, "external_ids": { diff --git a/ovn-nb.xml b/ovn-nb.xml index 6ac178b..d2d0b25 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2658,6 +2658,30 @@

+ + It represents Address Set of external ips that NAT rule is applicable to. + +

+ This configuration overrides the default NAT behavior of applying a + rule solely based on internal IP. +

+
+ + + It represents Address Set of external ips that NAT rule is NOT + applicable to. +

+ This configuration overrides the default NAT behavior of applying a + rule solely based on internal IP. +

+ +

+ "allowed_external_ip" and "disallowed_external_ip" are mutually + exclusive to each other. If both Address Sets are set for a rule, + then the NAT rule is not applied. +

+
+ Indicates if a dnat_and_snat rule should lead to connection tracking state or not. diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 6d66087..613d297 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -685,7 +685,42 @@ snat 40.0.0.3 21-65535 192.168.1.6 AT_CHECK([ovn-nbctl lr-nat-del lr0]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], []) AT_CHECK([ovn-nbctl lr-nat-del lr0]) -AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat])]) +AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat]) + +AT_CHECK([ovn-nbctl lr-nat-del lr0]) + +ovn-nbctl create Address_Set name=allowed_range addresses=\"1.1.1.1\" +ovn-nbctl create Address_Set name=disallowed_range addresses=\"2.2.2.2\" +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 40.0.0.3 192.168.1.6]) +AT_CHECK([ovn-nbctl lr-nat-update-ext-ip lr0 snat 192.168.1.6 disallowed_range]) +AT_CHECK([ovn-nbctl --is-allowed lr-nat-update-ext-ip lr0 snat 192.168.1.6 allowed_range]) +AT_CHECK([ovn-nbctl lr-nat-update-ext-ip lr0 snat 192.168.1.6 disallowed_range_tmp], [1], [], +[ovn-nbctl: disallowed_range_tmp: Address Set name not found +]) +AT_CHECK([ovn-nbctl --is-allowed lr-nat-update-ext-ip lr0 snat 192.168.1.6 allowed_range_tmp], [1], [], +[ovn-nbctl: allowed_range_tmp: Address Set name not found +]) + +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 40.0.0.4 192.168.1.7]) +AT_CHECK([ovn-nbctl lr-nat-update-ext-ip lr0 dnat 40.0.0.4 disallowed_range]) +AT_CHECK([ovn-nbctl --is-allowed lr-nat-update-ext-ip lr0 dnat 40.0.0.4 allowed_range]) +AT_CHECK([ovn-nbctl lr-nat-update-ext-ip lr0 dnat 40.0.0.4 disallowed_range_tmp], [1], [], +[ovn-nbctl: disallowed_range_tmp: Address Set name not found +]) +AT_CHECK([ovn-nbctl --is-allowed lr-nat-update-ext-ip lr0 dnat 40.0.0.4 allowed_range_tmp], [1], [], +[ovn-nbctl: allowed_range_tmp: Address Set name not found +]) + +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 40.0.0.5 192.168.1.8]) +AT_CHECK([ovn-nbctl lr-nat-update-ext-ip lr0 dnat_and_snat 40.0.0.5 disallowed_range]) +AT_CHECK([ovn-nbctl --is-allowed lr-nat-update-ext-ip lr0 dnat 40.0.0.4 allowed_range]) +AT_CHECK([ovn-nbctl lr-nat-update-ext-ip lr0 dnat 40.0.0.4 disallowed_range_tmp], [1], [], +[ovn-nbctl: disallowed_range_tmp: Address Set name not found +]) +AT_CHECK([ovn-nbctl --is-allowed lr-nat-update-ext-ip lr0 dnat 40.0.0.4 allowed_range_tmp], [1], [], +[ovn-nbctl: allowed_range_tmp: Address Set name not found +]) +AT_CHECK([ovn-nbctl lr-nat-del lr0])]) dnl --------------------------------------------------------------------- diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 7578b99..868cfb1 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -838,6 +838,46 @@ lr_by_name_or_uuid(struct ctl_context *ctx, const char *id, return NULL; } +/* Find an Address Set given its id. */ +static char * OVS_WARN_UNUSED_RESULT +address_set_by_name_or_uuid(struct ctl_context *ctx, + const char *id, bool must_exist, + const struct nbrec_address_set **addr_set_p) +{ + const struct nbrec_address_set *addr_set = NULL; + bool is_uuid = false; + struct uuid addr_set_uuid; + + *addr_set_p = NULL; + if (uuid_from_string(&addr_set_uuid, id)) { + is_uuid = true; + addr_set = nbrec_address_set_get_for_uuid(ctx->idl, &addr_set_uuid); + } + + if (!addr_set) { + const struct nbrec_address_set *iter; + + NBREC_ADDRESS_SET_FOR_EACH(iter, ctx->idl) { + if (strcmp(iter->name, id)) { + continue; + } + if (addr_set) { + return xasprintf("Multiple Address Sets named '%s'. " + "Use a UUID.", id); + } + addr_set = iter; + } + } + + if (!addr_set && must_exist) { + return xasprintf("%s: Address Set %s not found", + id, is_uuid ? "UUID" : "name"); + } + + *addr_set_p = addr_set; + return NULL; +} + static char * OVS_WARN_UNUSED_RESULT ls_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist, const struct nbrec_logical_switch **ls_p) @@ -4503,6 +4543,65 @@ nbctl_lr_nat_list(struct ctl_context *ctx) smap_destroy(&lr_nats); } +static void +nbctl_lr_nat_set_ext_ips(struct ctl_context *ctx) +{ + const struct nbrec_logical_router *lr = NULL; + const struct nbrec_address_set *addr_set = NULL; + bool is_allowed = shash_find(&ctx->options, "--is-allowed"); + bool nat_found = false; + + if (ctx->argc < 5) { + ctl_error(ctx, "Incomplete input"); + return; + } + + char *error = lr_by_name_or_uuid(ctx, ctx->argv[1], true, &lr); + if (error) { + ctx->error = error; + return; + } + + const char *nat_type = ctx->argv[2]; + if (strcmp(nat_type, "dnat") && strcmp(nat_type, "snat") + && strcmp(nat_type, "dnat_and_snat")) { + ctl_error(ctx, "%s: type must be one of \"dnat\", \"snat\" and " + "\"dnat_and_snat\".", nat_type); + return; + } + + error = address_set_by_name_or_uuid(ctx, ctx->argv[4], true, &addr_set); + if (error) { + ctx->error = error; + return; + } + + const char *nat_ip = ctx->argv[3]; + int is_snat = !strcmp("snat", nat_type); + + /* Update the matching NAT. */ + for (size_t i = 0; i < lr->n_nat; i++) { + struct nbrec_nat *nat = lr->nat[i]; + if (!strcmp(nat_type, nat->type) && + !strcmp(nat_ip, is_snat ? nat->logical_ip : nat->external_ip)) { + nat_found = true; + nbrec_logical_router_verify_nat(lr); + if (is_allowed) { + nbrec_nat_set_allowed_external_ip(nat, addr_set); + } else { + nbrec_nat_set_disallowed_external_ip(nat, addr_set); + } + return; + } + } + + if (!nat_found) { + ctl_error(ctx, "%s: Could not locate nat rule for: %s.", + nat_type, nat_ip); + return; + } +} + static char * OVS_WARN_UNUSED_RESULT lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist, @@ -6413,7 +6512,8 @@ static const struct ctl_command_syntax nbctl_commands[] = { { "lr-nat-del", 1, 3, "ROUTER [TYPE [IP]]", NULL, nbctl_lr_nat_del, NULL, "--if-exists", RW }, { "lr-nat-list", 1, 1, "ROUTER", NULL, nbctl_lr_nat_list, NULL, "", RO }, - + { "lr-nat-update-ext-ip", 4, 4, "ROUTER TYPE IP ADDRESS_SET", NULL, + nbctl_lr_nat_set_ext_ips, NULL, "--is-allowed", RW}, /* load balancer commands. */ { "lb-add", 3, 4, "LB VIP[:PORT] IP[:PORT]... [PROTOCOL]", NULL, nbctl_lb_add, NULL, "--may-exist,--add-duplicate", RW },