From patchwork Wed Sep 28 17:13:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gurucharan Shetty X-Patchwork-Id: 676318 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 3skkn96CDVz9s5w for ; Thu, 29 Sep 2016 03:13:33 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id C6FA81062D; Wed, 28 Sep 2016 10:13:30 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx1e4.cudamail.com (mx1.cudamail.com [69.90.118.67]) by archives.nicira.com (Postfix) with ESMTPS id C848810203 for ; Wed, 28 Sep 2016 10:13:29 -0700 (PDT) Received: from bar5.cudamail.com (unknown [192.168.21.12]) by mx1e4.cudamail.com (Postfix) with ESMTPS id 1170E1E02B5 for ; Wed, 28 Sep 2016 11:13:29 -0600 (MDT) X-ASG-Debug-ID: 1475082807-09eadd519f12b360001-byXFYA Received: from mx1-pf1.cudamail.com ([192.168.24.1]) by bar5.cudamail.com with ESMTP id Pu4E1pslqjKNvH9s (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Wed, 28 Sep 2016 11:13:28 -0600 (MDT) X-Barracuda-Envelope-From: guru@ovn.org X-Barracuda-RBL-Trusted-Forwarder: 192.168.24.1 Received: from unknown (HELO relay8-d.mail.gandi.net) (217.70.183.201) by mx1-pf1.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 28 Sep 2016 17:13:27 -0000 Received-SPF: pass (mx1-pf1.cudamail.com: SPF record at ovn.org designates 217.70.183.201 as permitted sender) X-Barracuda-Apparent-Source-IP: 217.70.183.201 X-Barracuda-RBL-IP: 217.70.183.201 Received: from mfilter6-d.gandi.net (mfilter6-d.gandi.net [217.70.178.135]) by relay8-d.mail.gandi.net (Postfix) with ESMTP id AE09F405A2 for ; Wed, 28 Sep 2016 19:13:24 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at mfilter6-d.gandi.net Received: from relay8-d.mail.gandi.net ([IPv6:::ffff:217.70.183.201]) by mfilter6-d.gandi.net (mfilter6-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id Wrk4S5eKdMh3 for ; Wed, 28 Sep 2016 19:13:17 +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 relay8-d.mail.gandi.net (Postfix) with ESMTPSA id F21F1405A1 for ; Wed, 28 Sep 2016 19:13:16 +0200 (CEST) Received: by mail-lf0-f48.google.com with SMTP id g62so59654526lfe.3 for ; Wed, 28 Sep 2016 10:13:16 -0700 (PDT) X-Gm-Message-State: AE9vXwOxq8EkokiEJM8dEzwxyjOvo/D20fr7xthE5b0EraF+hPxQerPLZ67UyNQGv3pZL0UdLaVukE10x67QeA== X-Received: by 10.25.18.157 with SMTP id 29mr10926030lfs.10.1475082795460; Wed, 28 Sep 2016 10:13:15 -0700 (PDT) MIME-Version: 1.0 Received: by 10.114.200.5 with HTTP; Wed, 28 Sep 2016 10:13:14 -0700 (PDT) In-Reply-To: <1474463641-75314-1-git-send-email-nickcooper-zhangtonghao@opencloud.tech> References: <1474463641-75314-1-git-send-email-nickcooper-zhangtonghao@opencloud.tech> X-CudaMail-Envelope-Sender: guru@ovn.org From: Guru Shetty Date: Wed, 28 Sep 2016 10:13:14 -0700 X-Gmail-Original-Message-ID: Message-ID: X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-E1-927048193 X-CudaMail-DTE: 092816 X-CudaMail-Originating-IP: 217.70.183.201 To: nickcooper-zhangtonghao X-ASG-Orig-Subj: [##CM-E1-927048193##]Re: [PATCH v8] ovn-nbctl: Add LB commands. X-Barracuda-Connect: UNKNOWN[192.168.24.1] X-Barracuda-Start-Time: 1475082808 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 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 v8] 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 21 September 2016 at 06:14, 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> > Thank you for the extensive unit tests. This looks good to me. I think there is a bit of duplicate code in nbctl_lb_list_router, nbctl_lb_list_switch and nbctl_lb_list_all that could use a helper function. Would you mind looking at it? On that lines, do you think the following command extensions are useful: ls-lb-list switch lb lr-lb-list router lb We are filtering the load-balancers in a switch and a router by 'lb'. Potentially, one could just call lb-list lb instead? I don't have strong feelings either way. There were a few lines with more than 78 characters and some alignment issues. Please add the following incremental. node->key, node->value); } @@ -1581,11 +1582,12 @@ nbctl_lb_list_switch(struct ctl_context *ctx, struct smap *lbs, protocol = "tcp/udp"; } - i == 0 ? ds_put_format(&val, UUID_FMT " %-20.16s%-11.7s%-25.21s%s", + i == 0 ? ds_put_format(&val, + UUID_FMT " %-20.16s%-11.7s%-25.21s%s", UUID_ARGS(&lb->header_.uuid), lb->name, protocol, node->key, node->value) - : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", + : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", "", protocol, node->key, node->value); } @@ -1630,11 +1632,12 @@ nbctl_lb_list_all(struct ctl_context *ctx, struct smap *lbs, protocol = "tcp/udp"; } - i == 0 ? ds_put_format(&val, UUID_FMT " %-20.16s%-11.7s%-25.21s%s", + i == 0 ? ds_put_format(&val, + UUID_FMT " %-20.16s%-11.7s%-25.21s%s", UUID_ARGS(&lb->header_.uuid), lb->name, protocol, node->key, node->value) - : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", + : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", "", protocol, node->key, node->value); > --- > lib/packets.c | 17 ++ > lib/packets.h | 10 + > ovn/ovn-nb.ovsschema | 5 +- > ovn/ovn-nb.xml | 6 + > ovn/utilities/ovn-nbctl.8.xml | 109 ++++++++ > ovn/utilities/ovn-nbctl.c | 588 ++++++++++++++++++++++++++++++ > +++++++++++- > tests/ovn-nbctl.at | 228 ++++++++++++++++ > 7 files changed, 960 insertions(+), 3 deletions(-) > > diff --git a/lib/packets.c b/lib/packets.c > index e4c29d5..a8b1654 100644 > --- a/lib/packets.c > +++ b/lib/packets.c > @@ -427,6 +427,23 @@ ip_parse(const char *s, ovs_be32 *ip) > return inet_pton(AF_INET, s, ip) == 1; > } > > +/* Parses string 's', which must be an IP address with a port number. > + * Stores the IP address into '*ip' and port number to '*port'. */ > +char * OVS_WARN_UNUSED_RESULT > +ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) > +{ > + int n = 0; > + if (!ovs_scan_len(s, &n, IP_PORT_SCAN_FMT, > + IP_PORT_SCAN_ARGS(ip, port))) { > + return xasprintf("%s: invalid IP address or port number", s); > + } > + > + if (s[n]) { > + return xasprintf("%s: invalid IP address or port number", s); > + } > + return NULL; > +} > + > /* Parses string 's', which must be an IP address with an optional > netmask or > * CIDR prefix length. Stores the IP address into '*ip', netmask into > '*mask', > * (255.255.255.255, if 's' lacks a netmask), and number of scanned > characters > diff --git a/lib/packets.h b/lib/packets.h > index dcfcd04..21bd35c 100644 > --- a/lib/packets.h > +++ b/lib/packets.h > @@ -537,6 +537,14 @@ mpls_lse_to_bos(ovs_be32 mpls_lse) > &((uint8_t *) ip)[2], \ > &((uint8_t *) ip)[3] > > +#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16 > +#define IP_PORT_SCAN_ARGS(ip, port) \ > + ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ > + &((uint8_t *) ip)[1], \ > + &((uint8_t *) ip)[2], \ > + &((uint8_t *) ip)[3], \ > + ((void) (ovs_be16) *(port), (uint16_t *) port) > + > /* Returns true if 'netmask' is a CIDR netmask, that is, if it consists > of N > * high-order 1-bits and 32-N low-order 0-bits. */ > static inline bool > @@ -558,6 +566,8 @@ ip_is_local_multicast(ovs_be32 ip) > int ip_count_cidr_bits(ovs_be32 netmask); > void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *); > bool ip_parse(const char *s, ovs_be32 *ip); > +char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) > + OVS_WARN_UNUSED_RESULT; > char *ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) > OVS_WARN_UNUSED_RESULT; > char *ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) > diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema > index b7e70aa..5f2f2bf 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", > + "version": "5.3.4", > + "cksum": "1155817817 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 c45a444..b7690d0 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..991ecea 100644 > --- a/ovn/utilities/ovn-nbctl.8.xml > +++ b/ovn/utilities/ovn-nbctl.8.xml > @@ -400,6 +400,115 @@ > > > > +

Load Balancer Commands

> +
> +
[--may-exist | --add-duplicate] > lb-add lb vip ips > [protocol]
> +
> +

> + 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 > + 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, 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 already exist in lb, unless > + --if-exists is specified. > +
> + > +
lb-list [lb]
> +
> + Lists the LBs. If lb is also specified, then only the > + specified 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]
> +
> + 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 for the given switch. If lb > is > + also specified, only the lb will be listed 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]
> +
> + 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 removed 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 for the given router. If lb > is > + also specified, then only the lb will be listed from > the > + logical router. > +
> +
> + > + >

DHCP Options commands

> >
> diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c > index 2148665..a252902 100644 > --- a/ovn/utilities/ovn-nbctl.c > +++ b/ovn/utilities/ovn-nbctl.c > @@ -384,6 +384,19 @@ 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\ > + create a load-balancer or add a VIP to an\n\ > + existing load balancer\n\ > + lb-del LB [VIP] remove a load-balancer or just the VIP from\n\ > + the 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 +506,40 @@ 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 +1363,527 @@ 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; > + bool is_vip_with_port = true; > + > + 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); > + } > + } > + > + ovs_be32 ipv4 = 0; > + ovs_be16 port = 0; > + char *error = ip_parse_port(lb_vip, &ipv4, &port); > + if (error) { > + free(error); > + if (!ip_parse(lb_vip, &ipv4)) { > + ctl_fatal("%s: should be an IPv4 address (or an IPv4 address " > + "and a port number with : as a separator).", lb_vip); > + } > + > + if (is_update_proto) { > + ctl_fatal("Protocol is unnecessary when no port of vip is > given."); > + } > + is_vip_with_port = false; > + } > + > + char *token = NULL, *save_ptr = NULL; > + char *ips = xstrdup(lb_ips); > + for (token = strtok_r(ips, ",", &save_ptr); > + token != NULL; token = strtok_r(NULL, ",", &save_ptr)) { > + if (is_vip_with_port) { > + error = ip_parse_port(token, &ipv4, &port); > + if (error) { > + free(error); > + ctl_fatal("%s: should be an IPv4 address and a port " > + "number with : as a separator.", token); > + } > + } else { > + if (!ip_parse(token, &ipv4)) { > + ctl_fatal("%s: should be an IPv4 address.", token); > + } > + } > + } > + > + free(ips); > + > + 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; > + ovs_be32 ipv4 = 0; > + ovs_be16 port = 0; > + char *error, *protocol; > + > + 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; > + struct ds val = DS_EMPTY_INITIALIZER; > + for (int i = 0; i < smap_count(&lb->vips); i++) { > + const struct smap_node *node = nodes[i]; > + protocol = lb->protocol; > + error = ip_parse_port(node->key, &ipv4, &port); > + if (error) { > + free(error); > + protocol = "tcp/udp"; > + } > + > + i == 0 ? ds_put_format(&val, UUID_FMT " > %-20.16s%-11.7s%-25.21s%s", > + UUID_ARGS(&lb->header_.uuid), > + lb->name, protocol, > + node->key, node->value) > + : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", > + "", protocol, > + node->key, node->value); > + } > + > + ds_put_format(&key, "%-20.16s", lb->name); > + smap_add(lbs, ds_cstr(&key), ds_cstr(&val)); > + > + ds_destroy(&key); > + ds_destroy(&val); > + 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; > + ovs_be32 ipv4 = 0; > + ovs_be16 port = 0; > + char *error, *protocol; > + > + 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; > + struct ds val = DS_EMPTY_INITIALIZER; > + for (int i = 0; i < smap_count(&lb->vips); i++) { > + const struct smap_node *node = nodes[i]; > + protocol = lb->protocol; > + error = ip_parse_port(node->key, &ipv4, &port); > + if (error) { > + free(error); > + protocol = "tcp/udp"; > + } > + > + i == 0 ? ds_put_format(&val, UUID_FMT " > %-20.16s%-11.7s%-25.21s%s", > + UUID_ARGS(&lb->header_.uuid), > + lb->name, protocol, > + node->key, node->value) > + : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", > + "", protocol, > + node->key, node->value); > + } > + > + ds_put_format(&key, "%-20.16s", lb->name); > + smap_add(lbs, ds_cstr(&key), ds_cstr(&val)); > + > + ds_destroy(&key); > + ds_destroy(&val); > + 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; > + ovs_be32 ipv4 = 0; > + ovs_be16 port = 0; > + char *error, *protocol; > + > + 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; > + struct ds val = DS_EMPTY_INITIALIZER; > + for (int i = 0; i < smap_count(&lb->vips); i++) { > + const struct smap_node *node = nodes[i]; > + protocol = lb->protocol; > + error = ip_parse_port(node->key, &ipv4, &port); > + if (error) { > + free(error); > + protocol = "tcp/udp"; > + } > + > + i == 0 ? ds_put_format(&val, UUID_FMT " > %-20.16s%-11.7s%-25.21s%s", > + UUID_ARGS(&lb->header_.uuid), > + lb->name, protocol, > + node->key, node->value) > + : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", > + "", protocol, > + node->key, node->value); > + } > + > + ds_put_format(&key, "%-20.16s", lb->name); > + smap_add(lbs, ds_cstr(&key), ds_cstr(&val)); > + > + ds_destroy(&key); > + ds_destroy(&val); > + 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, "%-40.36s%-20.16s%-11.7s%-25. > 21s%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, "%-40.36s%-20.16s%-11.7s%-25. > 21s%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, "%-40.36s%-20.16s%-11.7s%-25. > 21s%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 +3047,25 @@ 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..6bd4aaf 100644 > --- a/tests/ovn-nbctl.at > +++ b/tests/ovn-nbctl.at > @@ -239,6 +239,234 @@ 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:80a 192.168.10.10:80,192.168.10. > 20:80 tcp], [1], [], > +[ovn-nbctl: 30.0.0.10:80a: should be an IPv4 address (or an IPv4 address > and a port number with : as a separator). > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10:a80 192.168.10.10:80,192.168.10. > 20:80 tcp], [1], [], > +[ovn-nbctl: 30.0.0.10:a80: should be an IPv4 address (or an IPv4 address > and a port number with : as a separator). > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10: 192.168.10.10:80,192.168.10. > 20:80 tcp], [1], [], > +[ovn-nbctl: 30.0.0.10:: should be an IPv4 address (or an IPv4 address > and a port number with : as a separator). > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10.20 > tcp], [1], [], > +[ovn-nbctl: 192.168.10.20: should be an IPv4 address and a port number > with : as a separator. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.1a 192.168.10.10:80,192.168.10. > 20:80], [1], [], > +[ovn-nbctl: 30.0.0.1a: should be an IPv4 address (or an IPv4 address and > a port number with : as a separator). > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0 192.168.10.10:80,192.168.10.20:80], > [1], [], > +[ovn-nbctl: 30.0.0: should be an IPv4 address (or an IPv4 address and a > port number with : as a separator). > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10.10,192.168.10.20:80], > [1], [], > +[ovn-nbctl: 192.168.10.20:80: should be an IPv4 address. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10.10:a80], [1], [], > +[ovn-nbctl: 192.168.10.10:a80: should be an IPv4 address. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10.10:], [1], [], > +[ovn-nbctl: 192.168.10.10:: should be an IPv4 address. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10.1a], [1], [], > +[ovn-nbctl: 192.168.10.1a: should be an IPv4 address. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10], [1], [], > +[ovn-nbctl: 192.168.10: should be an IPv4 address. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10.10 tcp], [1], [], > +[ovn-nbctl: Protocol is unnecessary when no port of vip is given. > +]) > + > +AT_CHECK([ovn-nbctl lb-add lb0 30.0.0.10 192.168.10.10:900 tcp], [1], [], > +[ovn-nbctl: Protocol is unnecessary when no port of vip is given. > +]) > + > +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:80, > 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:80,192.168.10.20:8080 > +]) > + > +AT_CHECK([ovn-nbctl --may-exist lb-add lb1 30.0.0.10:80 192.168.10.10:80, > 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:80,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 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:80,192.168.10.20:8080 > + udp > 30.0.0.20:80 192.168.10.10:80 > +]) > + > +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:80,192.168.10.20:8080 > +]) > + > +dnl Add LBs whose vip is just an IP address. > +AT_CHECK([ovn-nbctl lb-add lb2 30.0.0.30 192.168.10.10]) > +AT_CHECK([ovn-nbctl lb-add lb3 30.0.0.30 192.168.10.10]) > +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:80,192.168.10.20:8080 > +<2> lb2 tcp/udp 30.0.0.30 > 192.168.10.10 > +<3> lb3 tcp/udp 30.0.0.30 > 192.168.10.10 > +]) > +AT_CHECK([ovn-nbctl lb-del lb2 30.0.0.30]) > +AT_CHECK([ovn-nbctl lb-del lb3 30.0.0.30]) > + > +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:80,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 lb-add lb3 30.0.0.10 192.168.10.10,192.168.10.20]) > +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-add ls0 lb3]) > + > +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 > +<2> lb3 tcp/udp 30.0.0.10 > 192.168.10.10,192.168.10.20 > +]) > + > +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 > +<1> lb3 tcp/udp 30.0.0.10 > 192.168.10.10,192.168.10.20 > +]) > + > +AT_CHECK([ovn-nbctl ls-lb-del ls0 lb1]) > +AT_CHECK([ovn-nbctl ls-lb-del ls0 lb3]) > +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-add ls0 lb3]) > +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 lr-lb-add lr0 lb0]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb1]) > +AT_CHECK([ovn-nbctl --may-exist lr-lb-add lr0 lb1]) > +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-add lr0 lb3]) > + > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${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 > +<2> lb3 tcp/udp 30.0.0.10 > 192.168.10.10,192.168.10.20 > +]) > + > +AT_CHECK([ovn-nbctl lr-lb-list lr0 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 lr-lb-del lr0 lb0]) > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${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 > +<1> lb3 tcp/udp 30.0.0.10 > 192.168.10.10,192.168.10.20 > +]) > + > +AT_CHECK([ovn-nbctl lr-lb-del lr0 lb1]) > +AT_CHECK([ovn-nbctl lr-lb-del lr0 lb3]) > +AT_CHECK([ovn-nbctl lr-lb-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], > []) > +AT_CHECK([ovn-nbctl --if-exists lr-lb-del lr0 lb1]) > + > +dnl Remove all load balancers from logical router. > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb0]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb1]) > +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb3]) > +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 > > > > > diff --git a/lib/packets.c b/lib/packets.c index a8b1654..11bb587 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -427,7 +427,8 @@ ip_parse(const char *s, ovs_be32 *ip) return inet_pton(AF_INET, s, ip) == 1; } -/* Parses string 's', which must be an IP address with a port number. +/* Parses string 's', which must be an IP address with a port number + * with ":" as a separator (e.g.: 192.168.1.2:80). * Stores the IP address into '*ip' and port number to '*port'. */ char * OVS_WARN_UNUSED_RESULT ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index a252902..26c32c5 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -1478,7 +1478,7 @@ nbctl_lb_del(struct ctl_context *ctx) 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); + smap_remove(CONST_CAST(struct smap *, &lb->vips), lb_vip); if (smap_is_empty(&lb->vips)) { nbrec_load_balancer_delete(lb); return; @@ -1529,11 +1529,12 @@ nbctl_lb_list_router(struct ctl_context *ctx, struct smap *lbs, protocol = "tcp/udp"; } - i == 0 ? ds_put_format(&val, UUID_FMT " %-20.16s%-11.7s%-25.21s%s", + i == 0 ? ds_put_format(&val, + UUID_FMT " %-20.16s%-11.7s%-25.21s%s", UUID_ARGS(&lb->header_.uuid), lb->name, protocol, node->key, node->value) - : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", + : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s", "", protocol,