From patchwork Thu Sep 15 17:12:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gurucharan Shetty X-Patchwork-Id: 670519 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (archives.nicira.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 3sZlNP538qz9sDG for ; Fri, 16 Sep 2016 03:12:51 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id CDD9110869; Thu, 15 Sep 2016 10:12:48 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id F179610868 for ; Thu, 15 Sep 2016 10:12:47 -0700 (PDT) Received: from bar6.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id 5A4AE16124A for ; Thu, 15 Sep 2016 11:12:47 -0600 (MDT) X-ASG-Debug-ID: 1473959565-0b323722611bca00001-byXFYA Received: from mx3-pf1.cudamail.com ([192.168.14.2]) by bar6.cudamail.com with ESMTP id UJUCpEeQbeLBZ0Bl (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 15 Sep 2016 11:12:45 -0600 (MDT) X-Barracuda-Envelope-From: guru@ovn.org X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.2 Received: from unknown (HELO relay6-d.mail.gandi.net) (217.70.183.198) by mx3-pf1.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 15 Sep 2016 17:12:44 -0000 Received-SPF: pass (mx3-pf1.cudamail.com: SPF record at ovn.org designates 217.70.183.198 as permitted sender) X-Barracuda-Apparent-Source-IP: 217.70.183.198 X-Barracuda-RBL-IP: 217.70.183.198 Received: from mfilter17-d.gandi.net (mfilter17-d.gandi.net [217.70.178.145]) by relay6-d.mail.gandi.net (Postfix) with ESMTP id 30E5FFB8A9 for ; Thu, 15 Sep 2016 19:12:41 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at mfilter17-d.gandi.net Received: from relay6-d.mail.gandi.net ([IPv6:::ffff:217.70.183.198]) by mfilter17-d.gandi.net (mfilter17-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id 6rbyhaWGha7y for ; Thu, 15 Sep 2016 19:12:34 +0200 (CEST) X-Originating-IP: 209.85.215.48 Received: from mail-lf0-f48.google.com (mail-lf0-f48.google.com [209.85.215.48]) (Authenticated sender: guru@ovn.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 7208DFB8B3 for ; Thu, 15 Sep 2016 19:12:34 +0200 (CEST) Received: by mail-lf0-f48.google.com with SMTP id h127so47953681lfh.0 for ; Thu, 15 Sep 2016 10:12:34 -0700 (PDT) X-Gm-Message-State: AE9vXwOIi7R3KMxQgARe3zZEzxoY/0F2THbZEuhPRp1nHTSbuCw7nWPHsEBJBbdhsvaNCRC3Cna841YSKY/KQw== X-Received: by 10.25.143.137 with SMTP id r131mr4259825lfd.165.1473959553484; Thu, 15 Sep 2016 10:12:33 -0700 (PDT) MIME-Version: 1.0 Received: by 10.114.172.144 with HTTP; Thu, 15 Sep 2016 10:12:32 -0700 (PDT) In-Reply-To: <1473471021-73614-1-git-send-email-nickcooper-zhangtonghao@opencloud.tech> References: <1473471021-73614-1-git-send-email-nickcooper-zhangtonghao@opencloud.tech> X-CudaMail-Envelope-Sender: guru@ovn.org From: Guru Shetty Date: Thu, 15 Sep 2016 10:12:32 -0700 X-Gmail-Original-Message-ID: Message-ID: X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V1-914032426 X-CudaMail-DTE: 091516 X-CudaMail-Originating-IP: 217.70.183.198 To: nickcooper-zhangtonghao X-ASG-Orig-Subj: [##CM-V1-914032426##]Re: [ovs-dev] [PATCH v5] ovn-nbctl: Add LB commands. X-Barracuda-Connect: UNKNOWN[192.168.14.2] X-Barracuda-Start-Time: 1473959565 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at cudamail.com X-Content-Filtered-By: Mailman/MimeDel 2.1.16 Cc: ovs dev Subject: Re: [ovs-dev] [PATCH v5] ovn-nbctl: Add LB commands. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@openvswitch.org Sender: "dev" On 9 September 2016 at 18:30, nickcooper-zhangtonghao < nickcooper-zhangtonghao@opencloud.tech> wrote: > This patch provides the command line to create a load balancer. > You can create a load balancer independently and add it to multiple > switches or routers. A single load balancer can have multiple vips. > Add a name column for the load balancer. With --add-duplicate, > the command really creates a new load balancer with a duplicate name. > This name has no special meaning or purpose other than to provide > convenience for human interaction with the ovn-nb database. > This patch also provides the unit tests and the documentation. > > Signed-off-by: nickcooper-zhangtonghao opencloud.tech> > Thanks. This looks close. I feel the output of the "list" commands are a little awkward. For e.g.: ovn-nbctl lb-list UUID LB PROTO VIP IPs fc916e82-bace-4b86-9d1a-cee5fc796499 lb0 udp 192.168.1.2 10.0.0.10,10.0.0.20 fc916e82-bace-4b86-9d1a-cee5fc796499 lb0 udp 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80,192.168.10.30:80 What would be nice is to aggregate the vips of a load-balancer and list it without the first 2 columns. e.g: UUID LB PROTO VIP IPs fc916e82-bace-4b86-9d1a-cee5fc796499 lb0 udp 192.168.1.2 10.0.0.10,10.0.0.20 udp 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80, 192.168.10.30:80 The above style is used in many commands in the OVS repo, so it would be nice if we are consistent. Also, in the documentation please try to limit lines to less than 79 characters. I use vim and I have the following in my .vimrc to show the the transgressing lines: :syntax on :colorscheme zellner :match ErrorMsg '\%>79v.\+' Please add the following incremental for your next version (please do read it through once and fix any formatting or spelling issues). + 192.168.10.10:80,192.168.10.20:80,192.168.10.30:80 udp

[--if-exists] lb-del lb [vip]
Deletes lb or the vip from lb. - If vip is supplied, the vip will be deleted - only from the lb. If only lb is supplied, + If vip is supplied, only the vip will be deleted + from the lb. If only the lb is supplied, the lb will be deleted. It is an error if vip - does not be included in lb, unless --if-exists is specified. + does not already exist in lb, unless + --if-exists is specified.
lb-list [lb]
- Lists the LBs. If lb is also specified, then the lb will be listed. + Lists the LBs. If lb is also specified, then only the + specified lb will be listed.
[--may-exist] ls-lb-add switch lb
@@ -447,18 +467,19 @@
[--if-exists] ls-lb-del switch [lb]
- Deletes lb from switch. If only switch is supplied, - all the LBs from the logical switch are deleted. If lb is also specified, - then the lb will be deleted only from the logical switch. - It is an error if lb does not exist in the switch, - unless --if-exists is specified. + Removes lb from switch. If only + switch is supplied, all the LBs from the logical switch are + removed. If lb is also specified, then only the + lb will be removed from the logical switch. + It is an error if lb does not exist in the + switch, unless --if-exists is specified.
ls-lb-list switch [lb]
Lists the LBs. If switch is supplied, all the LBs from - the logical switch are listed. If lb is also specified, - then the lb will be listed only from the logical switch. + the logical switch are listed. If lb is also specified, + only the lb will be listed from the logical switch.
[--may-exist] lr-lb-add router lb
@@ -470,18 +491,19 @@
[--if-exists] lr-lb-del router [lb]
- Deletes lb from router. If only router is supplied, - all the LBs from the logical router are deleted. If lb is also specified, - then the lb will be deleted only from the logical router. - It is an error if lb does not exist in the router, - unless --if-exists is specified. + Removes lb from router. If only + router is supplied, all the LBs from the logical router are + removed. If lb is also specified, then only the + lb will be deleted from the logical router. + It is an error if lb does not exist in the + router, unless --if-exists is specified.
lr-lb-list router [lb]
Lists the LBs. If router is supplied, all the LBs from the logical router are listed. If lb is also specified, - then the lb will be listed only from the logical router. + then only the lb will be listed from the logical router.
> --- > ovn/ovn-nb.ovsschema | 3 +- > ovn/ovn-nb.xml | 6 + > ovn/utilities/ovn-nbctl.8.xml | 86 ++++++++ > ovn/utilities/ovn-nbctl.c | 471 ++++++++++++++++++++++++++++++ > +++++++++++- > tests/ovn-nbctl.at | 147 +++++++++++++ > 5 files changed, 711 insertions(+), 2 deletions(-) > > diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema > index b7e70aa..7772ad2 100644 > --- a/ovn/ovn-nb.ovsschema > +++ b/ovn/ovn-nb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Northbound", > "version": "5.3.3", > - "cksum": "2442952958 9945", > + "cksum": "1191768021 9975", > "tables": { > "NB_Global": { > "columns": { > @@ -97,6 +97,7 @@ > "isRoot": true}, > "Load_Balancer": { > "columns": { > + "name": {"type": "string"}, > "vips": { > "type": {"key": "string", "value": "string", > "min": 0, "max": "unlimited"}}, > diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml > index 9a8bdbd..2ebae29 100644 > --- a/ovn/ovn-nb.xml > +++ b/ovn/ovn-nb.xml > @@ -676,6 +676,12 @@ > Each row represents one load balancer. >

> > + > + A name for the load balancer. This name has no special meaning or > + purpose other than to provide convenience for human interaction with > + the ovn-nb database. > + > + > >

> A map of virtual IPv4 addresses (and an optional port number with > diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml > index 76cf97e..84a74ae 100644 > --- a/ovn/utilities/ovn-nbctl.8.xml > +++ b/ovn/utilities/ovn-nbctl.8.xml > @@ -400,6 +400,92 @@ > > > > +

Logical Switch/Router LB Commands

> +
> +
[--may-exist | --add-duplicate] > lb-add lb vip ips > [protocol]
> +
> + Creates a new load balancer named lb with the > vip or > + adds the vip to lb. A single load balancer > can > + have multiple vips. We should assign lb a virtual > IPv4 address > + (and an optional port number with : as a separator) and the > corresponding > + endpoint IPv4 addresses (and optional port numbers with : as > separators) > + separated by commas. The optional argument protocol > must be > + either tcp or udp. This argument is > useful when > + a port number is provided as part of the vip. If the > protocol > + is unspecified and a port number is provided as part of > vip, > + OVN assumes the protocol to be tcp. It > is an > + error if the vip has been included in the load > balancer named > + lb, unless --may-exist is specified. > + With --add-duplicate, the command really creates a > new load > + balancer with a duplicate name. The following example adds a > load balancer > + with protocol udp: > +

> + lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80 > ,192.168.10.30:80 udp > +

> +
> + > +
[--if-exists] lb-del lb > [vip]
> +
> + Deletes lb or the vip from lb. > + If vip is supplied, the vip will be deleted > + only from the lb. If only lb is supplied, > + the lb will be deleted. It is an error if > vip > + does not be included in lb, unless > --if-exists is specified. > +
> + > +
lb-list [lb]
> +
> + Lists the LBs. If lb is also specified, then the > lb will be listed. > +
> + > +
[--may-exist] ls-lb-add > switch lb
> +
> + Adds the specified lb to switch. > + It is an error if a load balancer named lb already > exists > + in the switch, unless --may-exist is > specified. > +
> + > +
[--if-exists] ls-lb-del > switch [lb]
> +
> + Deletes lb from switch. If only > switch is supplied, > + all the LBs from the logical switch are deleted. If > lb is also specified, > + then the lb will be deleted only from the logical > switch. > + It is an error if lb does not exist in the > switch, > + unless --if-exists is specified. > +
> + > +
ls-lb-list switch [lb]
> +
> + Lists the LBs. If switch is supplied, all the LBs from > + the logical switch are listed. If lb is also specified, > + then the lb will be listed only from the logical > switch. > +
> + > +
[--may-exist] lr-lb-add > router lb
> +
> + Adds the specified lb to router. > + It is an error if a load balancer named lb already > exists > + in the router, unless --may-exist is > specified. > +
> + > +
[--if-exists] lr-lb-del > router [lb]
> +
> + Deletes lb from router. If only > router is supplied, > + all the LBs from the logical router are deleted. If > lb is also specified, > + then the lb will be deleted only from the logical > router. > + It is an error if lb does not exist in the > router, > + unless --if-exists is specified. > +
> + > +
lr-lb-list router [lb]
> +
> + Lists the LBs. If router is supplied, all the LBs from > + the logical router are listed. If lb is also specified, > + then the lb will be listed only from the logical > router. > +
> +
> + > + >

DHCP Options commands

> >
> diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c > index 2148665..f82aa39 100644 > --- a/ovn/utilities/ovn-nbctl.c > +++ b/ovn/utilities/ovn-nbctl.c > @@ -384,6 +384,17 @@ Route commands:\n\ > remove routes from ROUTER\n\ > lr-route-list ROUTER print routes for ROUTER\n\ > \n\ > +LB commands:\n\ > + lb-add LB VIP[:PORT] IP[:PORT]... [PROTOCOL]\n\ > + add a load-balancer or VIP to load balancer\n\ > + lb-del LB [VIP] remove a load-balancer or VIP from load > balancer\n\ > + lb-list [LB] print load-balancers\n\ > + lr-lb-add ROUTER LB add a load-balancer to ROUTER\n\ > + lr-lb-del ROUTER [LB] remove load-balancers from ROUTER\n\ > + lr-lb-list ROUTER [LB] print load-balancers\n\ > + ls-lb-add SWITCH LB add a load-balancer to SWITCH\n\ > + ls-lb-del SWITCH [LB] remove load-balancers from SWITCH\n\ > + ls-lb-list SWITCH [LB] print load-balancers\n\ > \n\ > DHCP Options commands:\n\ > dhcp-options-create CIDR [EXTERNAL_IDS]\n\ > @@ -493,6 +504,39 @@ ls_by_name_or_uuid(struct ctl_context *ctx, const > char *id, bool must_exist) > return ls; > } > > +static const struct nbrec_load_balancer * > +lb_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool > must_exist) > +{ > + const struct nbrec_load_balancer *lb = NULL; > + > + struct uuid lb_uuid; > + bool is_uuid = uuid_from_string(&lb_uuid, id); > + if (is_uuid) { > + lb = nbrec_load_balancer_get_for_uuid(ctx->idl, &lb_uuid); > + } > + > + if (!lb) { > + const struct nbrec_load_balancer *iter; > + > + NBREC_LOAD_BALANCER_FOR_EACH(iter, ctx->idl) { > + if (strcmp(iter->name, id)) { > + continue; > + } > + if (lb) { > + ctl_fatal("Multiple load balancers named '%s'. " > + "Use a UUID.", id); > + } > + lb = iter; > + } > + } > + > + if (!lb && must_exist) { > + ctl_fatal("%s: load balancer %s not found", id, is_uuid ? "UUID" > : "name"); > + } > + > + return lb; > +} > + > /* Given pointer to logical router, this routine prints the router > * information. */ > static void > @@ -1316,7 +1360,420 @@ nbctl_acl_del(struct ctl_context *ctx) > } > } > } > - > + > +static void > +nbctl_lb_add(struct ctl_context *ctx) > +{ > + const char *lb_name = ctx->argv[1]; > + const char *lb_vip = ctx->argv[2]; > + const char *lb_ips = ctx->argv[3]; > + > + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; > + bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != > NULL; > + > + const char *lb_proto; > + bool is_update_proto = false; > + if (ctx->argc == 4) { > + /* Default protocol. */ > + lb_proto = "tcp"; > + } else { > + /* Validate protocol. */ > + lb_proto = ctx->argv[4]; > + is_update_proto = true; > + if (strcmp(lb_proto, "tcp") && strcmp(lb_proto, "udp")) { > + ctl_fatal("%s: protocol must be one of \"tcp\", \"udp\".", > lb_proto); > + } > + } > + > + const struct nbrec_load_balancer *lb = NULL; > + if (!add_duplicate) { > + lb = lb_by_name_or_uuid(ctx, lb_name, false); > + if (lb) { > + if (smap_get(&lb->vips, lb_vip)) { > + if (!may_exist) { > + ctl_fatal("%s: a load balancer with this vip (%s) > already exists", lb_name, lb_vip); > + } > + /* Update the vips. */ > + smap_replace(CONST_CAST(struct smap * ,&lb->vips), > lb_vip, lb_ips); > + } else { > + /* Add the new vips. */ > + smap_add(CONST_CAST(struct smap * ,&lb->vips), lb_vip, > lb_ips); > + } > + > + /* Update the load balancer. */ > + if (is_update_proto) { > + nbrec_load_balancer_verify_protocol(lb); > + nbrec_load_balancer_set_protocol(lb, lb_proto); > + } > + nbrec_load_balancer_verify_vips(lb); > + nbrec_load_balancer_set_vips(lb, &lb->vips); > + return; > + } > + } > + > + /* Create the load balancer. */ > + lb = nbrec_load_balancer_insert(ctx->txn); > + nbrec_load_balancer_set_name(lb, lb_name); > + nbrec_load_balancer_set_protocol(lb, lb_proto); > + smap_add(CONST_CAST(struct smap * ,&lb->vips), lb_vip, lb_ips); > + nbrec_load_balancer_set_vips(lb, &lb->vips); > +} > + > +static void > +nbctl_lb_del(struct ctl_context *ctx) > +{ > + const char *id = ctx->argv[1]; > + const struct nbrec_load_balancer *lb = NULL; > + bool must_exist = !shash_find(&ctx->options, "--if-exists"); > + > + lb = lb_by_name_or_uuid(ctx, id, false); > + if (!lb) { > + return; > + } > + > + if (ctx->argc == 3) { > + const char *lb_vip = ctx->argv[2]; > + if (smap_get(&lb->vips, lb_vip)) { > + smap_remove(CONST_CAST(struct smap * ,&lb->vips), lb_vip); > + if (smap_is_empty(&lb->vips)) { > + nbrec_load_balancer_delete(lb); > + return; > + } > + > + /* Delete the vip of the load balancer. */ > + nbrec_load_balancer_verify_vips(lb); > + nbrec_load_balancer_set_vips(lb, &lb->vips); > + return; > + } > + if (must_exist) { > + ctl_fatal("vip %s is not part of the load balancer.", > + lb_vip); > + } > + return; > + } > + nbrec_load_balancer_delete(lb); > +} > + > +static const struct smap_node ** > +nbctl_lb_list_router(struct ctl_context *ctx, struct smap *lbs, > + const char *lr_name, const char *lb_name, bool > lb_check) > +{ > + const struct nbrec_logical_router *lr; > + lr = lr_by_name_or_uuid(ctx, lr_name, true); > + > + for (int i = 0; i < lr->n_load_balancer; i++) { > + const struct nbrec_load_balancer *lb > + = lr->load_balancer[i]; > + if (lb_check && strcmp(lb->name, lb_name)) { > + continue; > + } > + > + const struct smap_node **nodes = smap_sort(&lb->vips); > + if (nodes) { > + struct ds key = DS_EMPTY_INITIALIZER; > + ds_put_format(&key, "%-10.8s" UUID_FMT, > + lb->name, UUID_ARGS(&lb->header_.uuid)); > + for (int i = 0; i < smap_count(&lb->vips); i++) { > + const struct smap_node *node = nodes[i]; > + smap_add_format(lbs, ds_cstr(&key), UUID_FMT " %-10.8s > %-8s %-20s %s", > + UUID_ARGS(&lb->header_.uuid), lb->name, > lb->protocol, node->key, node->value); > + } > + > + ds_destroy(&key); > + free(nodes); > + } > + } > + > + return smap_sort(lbs); > +} > + > +static const struct smap_node ** > +nbctl_lb_list_switch(struct ctl_context *ctx, struct smap *lbs, > + const char *ls_name, const char *lb_name, bool > lb_check) > +{ > + const struct nbrec_logical_switch *ls; > + ls = ls_by_name_or_uuid(ctx, ls_name, true); > + > + for (int i = 0; i < ls->n_load_balancer; i++) { > + const struct nbrec_load_balancer *lb > + = ls->load_balancer[i]; > + if (lb_check && strcmp(lb->name, lb_name)) { > + continue; > + } > + > + const struct smap_node **nodes = smap_sort(&lb->vips); > + if (nodes) { > + struct ds key = DS_EMPTY_INITIALIZER; > + ds_put_format(&key, "%-10.8s" UUID_FMT, > + lb->name, UUID_ARGS(&lb->header_.uuid)); > + for (int i = 0; i < smap_count(&lb->vips); i++) { > + const struct smap_node *node = nodes[i]; > + smap_add_format(lbs, ds_cstr(&key), UUID_FMT " %-10.8s > %-8s %-20s %s", > + UUID_ARGS(&lb->header_.uuid), lb->name, > lb->protocol, node->key, node->value); > + } > + > + ds_destroy(&key); > + free(nodes); > + } > + } > + > + return smap_sort(lbs); > +} > + > +static const struct smap_node ** > +nbctl_lb_list_all(struct ctl_context *ctx, struct smap *lbs, const char > *lb_name, bool lb_check) { > + > + const struct nbrec_load_balancer *lb; > + NBREC_LOAD_BALANCER_FOR_EACH(lb, ctx->idl) { > + > + if (lb_check && strcmp(lb->name, lb_name)) { > + continue; > + } > + > + const struct smap_node **nodes = smap_sort(&lb->vips); > + if (nodes) { > + struct ds key = DS_EMPTY_INITIALIZER; > + ds_put_format(&key, "%-10.8s" UUID_FMT, > + lb->name, UUID_ARGS(&lb->header_.uuid)); > + for (int i = 0; i < smap_count(&lb->vips); i++) { > + const struct smap_node *node = nodes[i]; > + smap_add_format(lbs, ds_cstr(&key), UUID_FMT " %-10.8s > %-8s %-20s %s", > + UUID_ARGS(&lb->header_.uuid), lb->name, > lb->protocol, node->key, node->value); > + } > + > + ds_destroy(&key); > + free(nodes); > + } > + } > + > + return smap_sort(lbs); > +} > + > +static void > +nbctl_lb_list(struct ctl_context *ctx) > +{ > + struct smap lbs = SMAP_INITIALIZER(&lbs); > + const struct smap_node **nodes = NULL; > + > + if (ctx->argc == 1) { > + nodes = nbctl_lb_list_all(ctx, &lbs, NULL, false); > + } else if (ctx->argc == 2) { > + nodes = nbctl_lb_list_all(ctx, &lbs, ctx->argv[1], true); > + } > + > + if (nodes) { > + ds_put_format(&ctx->output, "%-36s %-10.8s %-8s %-20s %s\n", > + "UUID", "LB", "PROTO", "VIP", "IPs"); > + for (size_t i = 0; i < smap_count(&lbs); i++) { > + const struct smap_node *node = nodes[i]; > + ds_put_format(&ctx->output, "%s\n", node->value); > + } > + > + smap_destroy(&lbs); > + free(nodes); > + } > +} > + > +static void > +nbctl_lr_lb_add(struct ctl_context *ctx) > +{ > + const struct nbrec_logical_router *lr; > + const struct nbrec_load_balancer *new_lb; > + > + lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true); > + new_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true); > + > + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; > + for (int i = 0; i < lr->n_load_balancer; i++) { > + const struct nbrec_load_balancer *lb > + = lr->load_balancer[i]; > + > + if (uuid_equals(&new_lb->header_.uuid, &lb->header_.uuid)) { > + if (may_exist) { > + return; > + } > + ctl_fatal(UUID_FMT " : a load balancer with this UUID already > exists", > + UUID_ARGS(&lb->header_.uuid)); > + } > + } > + > + /* Insert the load balancer into the logical router. */ > + nbrec_logical_router_verify_load_balancer(lr); > + struct nbrec_load_balancer **new_lbs > + = xmalloc(sizeof *new_lbs * (lr->n_load_balancer + 1)); > + > + memcpy(new_lbs, lr->load_balancer, sizeof *new_lbs * > lr->n_load_balancer); > + new_lbs[lr->n_load_balancer] = CONST_CAST(struct nbrec_load_balancer > *, new_lb); > + nbrec_logical_router_set_load_balancer(lr, new_lbs, > lr->n_load_balancer + 1); > + free(new_lbs); > +} > + > +static void > +nbctl_lr_lb_del(struct ctl_context *ctx) > +{ > + const struct nbrec_logical_router *lr; > + const struct nbrec_load_balancer *del_lb; > + lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true); > + > + if (ctx->argc == 2) { > + /* If load-balancer is not specified, remove > + * all load-balancers from the logical router. */ > + nbrec_logical_router_verify_load_balancer(lr); > + nbrec_logical_router_set_load_balancer(lr, NULL, 0); > + return; > + } > + > + del_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true); > + for (size_t i = 0; i < lr->n_load_balancer; i++) { > + const struct nbrec_load_balancer *lb > + = lr->load_balancer[i]; > + > + if (uuid_equals(&del_lb->header_.uuid, &lb->header_.uuid)) { > + /* Remove the matching rule. */ > + nbrec_logical_router_verify_load_balancer(lr); > + > + struct nbrec_load_balancer **new_lbs > + = xmemdup(lr->load_balancer, sizeof *new_lbs * > lr->n_load_balancer); > + new_lbs[i] = lr->load_balancer[lr->n_load_balancer - 1]; > + nbrec_logical_router_set_load_balancer(lr, new_lbs, > + lr->n_load_balancer - 1); > + free(new_lbs); > + return; > + } > + } > + > + bool must_exist = !shash_find(&ctx->options, "--if-exists"); > + if (must_exist) { > + ctl_fatal("load balancer %s is not part of any logical router.", > + del_lb->name); > + } > +} > + > +static void > +nbctl_lr_lb_list(struct ctl_context *ctx) > +{ > + struct smap lbs = SMAP_INITIALIZER(&lbs); > + const struct smap_node **nodes = NULL; > + > + if (ctx->argc == 2) { > + nodes = nbctl_lb_list_router(ctx, &lbs, ctx->argv[1], NULL, > false); > + } else { > + nodes = nbctl_lb_list_router(ctx, &lbs, ctx->argv[1], > ctx->argv[2], true); > + } > + > + if (nodes) { > + ds_put_format(&ctx->output, "%-36s %-10.8s %-8s %-20s %s\n", > + "UUID", "LB", "PROTO", "VIP", "IPs"); > + for (size_t i = 0; i < smap_count(&lbs); i++) { > + const struct smap_node *node = nodes[i]; > + ds_put_format(&ctx->output, "%s\n", node->value); > + } > + > + smap_destroy(&lbs); > + free(nodes); > + } > +} > + > +static void > +nbctl_ls_lb_add(struct ctl_context *ctx) > +{ > + const struct nbrec_logical_switch *ls; > + const struct nbrec_load_balancer *new_lb; > + > + ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true); > + new_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true); > + > + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; > + for (int i = 0; i < ls->n_load_balancer; i++) { > + const struct nbrec_load_balancer *lb > + = ls->load_balancer[i]; > + > + if (uuid_equals(&new_lb->header_.uuid, &lb->header_.uuid)) { > + if (may_exist) { > + return; > + } > + ctl_fatal(UUID_FMT " : a load balancer with this UUID already > exists", > + UUID_ARGS(&lb->header_.uuid)); > + } > + } > + > + /* Insert the load balancer into the logical switch. */ > + nbrec_logical_switch_verify_load_balancer(ls); > + struct nbrec_load_balancer **new_lbs > + = xmalloc(sizeof *new_lbs * (ls->n_load_balancer + 1)); > + > + memcpy(new_lbs, ls->load_balancer, sizeof *new_lbs * > ls->n_load_balancer); > + new_lbs[ls->n_load_balancer] = CONST_CAST(struct nbrec_load_balancer > *, new_lb); > + nbrec_logical_switch_set_load_balancer(ls, new_lbs, > ls->n_load_balancer + 1); > + free(new_lbs); > +} > + > +static void > +nbctl_ls_lb_del(struct ctl_context *ctx) > +{ > + const struct nbrec_logical_switch *ls; > + const struct nbrec_load_balancer *del_lb; > + ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true); > + > + if (ctx->argc == 2) { > + /* If load-balancer is not specified, remove > + * all load-balancers from the logical switch. */ > + nbrec_logical_switch_verify_load_balancer(ls); > + nbrec_logical_switch_set_load_balancer(ls, NULL, 0); > + return; > + } > + > + del_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true); > + for (size_t i = 0; i < ls->n_load_balancer; i++) { > + const struct nbrec_load_balancer *lb > + = ls->load_balancer[i]; > + > + if (uuid_equals(&del_lb->header_.uuid, &lb->header_.uuid)) { > + /* Remove the matching rule. */ > + nbrec_logical_switch_verify_load_balancer(ls); > + > + struct nbrec_load_balancer **new_lbs > + = xmemdup(ls->load_balancer, sizeof *new_lbs * > ls->n_load_balancer); > + new_lbs[i] = ls->load_balancer[ls->n_load_balancer - 1]; > + nbrec_logical_switch_set_load_balancer(ls, new_lbs, > + ls->n_load_balancer - 1); > + free(new_lbs); > + return; > + } > + } > + > + bool must_exist = !shash_find(&ctx->options, "--if-exists"); > + if (must_exist) { > + ctl_fatal("load balancer %s is not part of any logical switch.", > + del_lb->name); > + } > +} > + > +static void > +nbctl_ls_lb_list(struct ctl_context *ctx) > +{ > + struct smap lbs = SMAP_INITIALIZER(&lbs); > + const struct smap_node **nodes = NULL; > + > + if (ctx->argc == 2) { > + nodes = nbctl_lb_list_switch(ctx, &lbs, ctx->argv[1], NULL, > false); > + } else { > + nodes = nbctl_lb_list_switch(ctx, &lbs, ctx->argv[1], > ctx->argv[2], true); > + } > + > + if (nodes) { > + ds_put_format(&ctx->output, "%-36s %-10.8s %-8s %-20s %s\n", > + "UUID", "LB", "PROTO", "VIP", "IPs"); > + for (size_t i = 0; i < smap_count(&lbs); i++) { > + const struct smap_node *node = nodes[i]; > + ds_put_format(&ctx->output, "%s\n", node->value); > + } > + > + smap_destroy(&lbs); > + free(nodes); > + } > +} > + > static void > nbctl_lr_add(struct ctl_context *ctx) > { > @@ -2480,6 +2937,18 @@ static const struct ctl_command_syntax > nbctl_commands[] = { > { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL, > "", RO }, > > + /* load balancer commands. */ > + { "lb-add", 3, 4, "LB VIP[:PORT] IP[:PORT]... [PROTOCOL]", NULL, > + nbctl_lb_add, NULL, "--may-exist,--add-duplicate", RW }, > + { "lb-del", 1, 2, "LB [VIP]", NULL, nbctl_lb_del, NULL, > "--if-exists", RW }, > + { "lb-list", 0, 1, "[LB]", NULL, nbctl_lb_list, NULL, "", RO }, > + { "lr-lb-add", 2, 2, "ROUTER LB", NULL, nbctl_lr_lb_add, NULL, > "--may-exist", RW }, > + { "lr-lb-del", 1, 2, "ROUTER [LB]", NULL, nbctl_lr_lb_del, NULL, > "--if-exists", RW }, > + { "lr-lb-list", 1, 2, "ROUTER [LB]", NULL, nbctl_lr_lb_list, NULL, > "", RO }, > + { "ls-lb-add", 2, 2, "SWITCH LB", NULL, nbctl_ls_lb_add, NULL, > "--may-exist", RW }, > + { "ls-lb-del", 1, 2, "SWITCH [LB]", NULL, nbctl_ls_lb_del, NULL, > "--if-exists", RW }, > + { "ls-lb-list", 1, 2, "SWITCH [LB]", NULL, nbctl_ls_lb_list, NULL, > "", RO }, > + > /* DHCP_Options commands */ > {"dhcp-options-create", 1, INT_MAX, "CIDR [EXTERNAL:IDS]", NULL, > nbctl_dhcp_options_create, NULL, "", RW }, > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at > index 241e6d3..9508e70 100644 > --- a/tests/ovn-nbctl.at > +++ b/tests/ovn-nbctl.at > @@ -239,6 +239,153 @@ AT_CLEANUP > > dnl --------------------------------------------------------------------- > > +AT_SETUP([ovn-nbctl - LBs]) > +OVN_NBCTL_TEST_START > + > +dnl Add two LBs. > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10. > 20:80]) > +AT_CHECK([ovn-nbctl lb-add lb1 30.0.0.10:80 192.168.10.10:80,192.168.10. > 20:80 tcp]) > +AT_CHECK([ovn-nbctl lb-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb1 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +dnl Update the VIP of the lb1. > +AT_CHECK([ovn-nbctl --may-exist lb-add lb1 30.0.0.10:80 > 192.168.10.10:8080,192.168.10.20:8080]) > +AT_CHECK([ovn-nbctl lb-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb1 tcp 30.0.0.10:80 192.168.10.10:8080, > 192.168.10.20:8080 > +]) > + > +AT_CHECK([ovn-nbctl --may-exist lb-add lb1 30.0.0.10:80 > 192.168.10.10:8080,192.168.10.20:8080 udp]) > +AT_CHECK([ovn-nbctl lb-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb1 udp 30.0.0.10:80 192.168.10.10:8080, > 192.168.10.20:8080 > +]) > + > +dnl Config lb1 with another VIP. > +AT_CHECK([ovn-nbctl lb-add lb1 30.0.0.20:80 192.168.10.10:80,192.168.10. > 20:80 udp]) > +AT_CHECK([ovn-nbctl lb-del lb1 30.0.0.20:80]) > +AT_CHECK([ovn-nbctl lb-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb1 udp 30.0.0.10:80 192.168.10.10:8080, > 192.168.10.20:8080 > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb2 30.0.0.10:8080 192.168.10.10:80, > 192.168.10.20:80 tcp]) > +AT_CHECK([ovn-nbctl --add-duplicate lb-add lb2 30.0.0.10:8080 > 192.168.10.10:80,192.168.10.20:80 tcp]) > +AT_CHECK([ovn-nbctl lb-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb1 udp 30.0.0.10:80 192.168.10.10:8080, > 192.168.10.20:8080 > +<2> lb2 tcp 30.0.0.10:8080 192.168.10.10:80, > 192.168.10.20:80 > +<3> lb2 tcp 30.0.0.10:8080 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +dnl If there are multiple load balancers with the same name, use a UUID > to update/delete. > +AT_CHECK([ovn-nbctl lb-add lb2 30.0.0.10:8080 192.168.10.10:80, > 192.168.10.20:80 tcp], [1], [], > +[ovn-nbctl: Multiple load balancers named 'lb2'. Use a UUID. > +]) > + > +AT_CHECK([ovn-nbctl lb-del lb2], [1], [], > +[ovn-nbctl: Multiple load balancers named 'lb2'. Use a UUID. > +]) > + > +AT_CHECK([ovn-nbctl --may-exist lb-add lb1 30.0.0.10:80 > 192.168.10.10:8080,192.168.10.20:8080 udp]) > +AT_CHECK([ovn-nbctl --may-exist lb-add lb1 30.0.0.10:8080 > 192.168.10.10:8080,192.168.10.20:8080 udp]) > +AT_CHECK([ovn-nbctl --may-exist lb-add lb1 30.0.0.10:9090 > 192.168.10.10:8080,192.168.10.20:8080 udp]) > +AT_CHECK([ovn-nbctl lb-del lb0 30.0.0.10:80]) > +AT_CHECK([ovn-nbctl lb-del lb1]) > +AT_CHECK([ovn-nbctl lb-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb2 tcp 30.0.0.10:8080 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb2 tcp 30.0.0.10:8080 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +dnl Add load balancer to logical switch. > +AT_CHECK([ovn-nbctl ls-add ls0]) > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10. > 20:80]) > +AT_CHECK([ovn-nbctl lb-add lb1 30.0.0.10:80 192.168.10.10:80,192.168.10. > 20:80 udp]) > +AT_CHECK([ovn-nbctl ls-lb-add ls0 lb0]) > +AT_CHECK([ovn-nbctl ls-lb-add ls0 lb1]) > +AT_CHECK([ovn-nbctl --may-exist ls-lb-add ls0 lb1]) > +AT_CHECK([ovn-nbctl ls-lb-add ls0 lb2], [1], [], > +[ovn-nbctl: Multiple load balancers named 'lb2'. Use a UUID. > +]) > + > +AT_CHECK([ovn-nbctl ls-lb-list ls0 | ${PERL} $srcdir/uuidfilt.pl], [0], > [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb1 udp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +AT_CHECK([ovn-nbctl ls-lb-list ls0 lb0 | ${PERL} $srcdir/uuidfilt.pl], > [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb0 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +AT_CHECK([ovn-nbctl ls-lb-del ls0 lb0]) > +AT_CHECK([ovn-nbctl ls-lb-list ls0 | ${PERL} $srcdir/uuidfilt.pl], [0], > [dnl > +UUID LB PROTO VIP > IPs > +<0> lb1 udp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +AT_CHECK([ovn-nbctl ls-lb-del ls0 lb1]) > +AT_CHECK([ovn-nbctl ls-lb-list ls0 | ${PERL} $srcdir/uuidfilt.pl], [0], > []) > +AT_CHECK([ovn-nbctl --if-exists ls-lb-del ls0 lb1]) > + > +dnl Remove all load balancers from logical switch. > +AT_CHECK([ovn-nbctl ls-lb-add ls0 lb0]) > +AT_CHECK([ovn-nbctl ls-lb-add ls0 lb1]) > +AT_CHECK([ovn-nbctl ls-lb-del ls0]) > +AT_CHECK([ovn-nbctl ls-lb-list ls0 | ${PERL} $srcdir/uuidfilt.pl], [0], > []) > + > +dnl Add load balancer to logical router. > +AT_CHECK([ovn-nbctl lr-add lr0]) > +AT_CHECK([ovn-nbctl lb-add lb00 30.0.0.10:80 192.168.10.10:80,192.168.10. > 20:80]) > +AT_CHECK([ovn-nbctl lb-add lb01 30.0.0.10:80 192.168.10.10:80,192.168.10. > 20:80 udp]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb00]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb01]) > +AT_CHECK([ovn-nbctl --may-exist lr-lb-add lr0 lb01]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb2], [1], [], > +[ovn-nbctl: Multiple load balancers named 'lb2'. Use a UUID. > +]) > + > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], > [dnl > +UUID LB PROTO VIP > IPs > +<0> lb00 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +<1> lb01 udp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +AT_CHECK([ovn-nbctl lr-lb-list lr0 lb00 | ${PERL} $srcdir/uuidfilt.pl], > [0], [dnl > +UUID LB PROTO VIP > IPs > +<0> lb00 tcp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +AT_CHECK([ovn-nbctl lr-lb-del lr0 lb00]) > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], > [dnl > +UUID LB PROTO VIP > IPs > +<0> lb01 udp 30.0.0.10:80 192.168.10.10:80, > 192.168.10.20:80 > +]) > + > +AT_CHECK([ovn-nbctl lr-lb-del lr0 lb01]) > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], > []) > +AT_CHECK([ovn-nbctl --if-exists lr-lb-del lr0 lb01]) > + > +dnl Remove all load balancers from logical router. > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb00]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb01]) > +AT_CHECK([ovn-nbctl lr-lb-del lr0]) > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], > []) > + > +OVN_NBCTL_TEST_STOP > +AT_CLEANUP > + > +dnl --------------------------------------------------------------------- > + > AT_SETUP([ovn-nbctl - basic logical router commands]) > OVN_NBCTL_TEST_START > > -- > 1.8.3.1 > > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index 84a74ae..ada65fb 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -400,42 +400,62 @@
-

Logical Switch/Router LB Commands

+

Load Balancer Commands

[--may-exist | --add-duplicate] lb-add lb vip ips [protocol]
- Creates a new load balancer named lb with the vip or - adds the vip to lb. A single load balancer can - have multiple vips. We should assign lb a virtual IPv4 address - (and an optional port number with : as a separator) and the corresponding - endpoint IPv4 addresses (and optional port numbers with : as separators) - separated by commas. The optional argument protocol must be - either tcp or udp. This argument is useful when - a port number is provided as part of the vip. If the protocol - is unspecified and a port number is provided as part of vip, - OVN assumes the protocol to be tcp. It is an - error if the vip has been included in the load balancer named - lb, unless --may-exist is specified. - With --add-duplicate, the command really creates a new load - balancer with a duplicate name. The following example adds a load balancer - with protocol udp:

- lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80, 192.168.10.30:80 udp + Creates a new load balancer named lb with the provided + vip and ips or adds the vip to + an existing lb. vip should be a + virtual IPv4 address (or an IPv4 address and a port number with + : as a separator). Examples for vip are + 192.168.1.4 and 192.168.1.5:8080. + ips should be comma separated IPv4 endpoints (or comma + separated IPv4 addresses and port numbers with : as a + separator). Examples for ips are 10.0.0.1,10.0.0.2 + or 20.0.0.10:8800,20.0.0.11:8800. +

+ +

+ The optional argument protocol must be either + tcp or udp. This argument is useful when + a port number is provided as part of the vip. If the + protocol is unspecified and a port number is provided as + part of the vip, OVN assumes the protocol to + be tcp. +

+ +

+ It is an error if the vip already exists in the load + balancer named lb, unless --may-exist is + specified. With --add-duplicate, the command really + creates a new load balancer with a duplicate name. +

+ +

+ The following example adds a load balancer. +

+

+ lb-add lb0 30.0.0.10:80