Message ID | 1472798854-23488-1-git-send-email-nickcooper-zhangtonghao@opencloud.tech |
---|---|
State | Changes Requested |
Headers | show |
On 1 September 2016 at 23:47, 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. 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 <nickcooper-zhangtonghao@ > opencloud.tech> > Sorry for the delay on this. I was waiting for the load balancer addition to gateway routers. Now that has been merged, would you please mind re-spinning this with the feature to add it to a router too? > --- > ovn/ovn-nb.ovsschema | 3 +- > ovn/ovn-nb.xml | 6 + > ovn/utilities/ovn-nbctl.8.xml | 57 ++++++++ > ovn/utilities/ovn-nbctl.c | 307 ++++++++++++++++++++++++++++++ > +++++++++++- > tests/ovn-nbctl.at | 97 +++++++++++++ > 5 files changed, 468 insertions(+), 2 deletions(-) > > diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema > index 456ae98..d935475 100644 > --- a/ovn/ovn-nb.ovsschema > +++ b/ovn/ovn-nb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Northbound", > "version": "5.3.1", > - "cksum": "1921908091 9353", > + "cksum": "440042936 9397", > "tables": { > "NB_Global": { > "columns": { > @@ -92,6 +92,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 5719e74..186abf8 100644 > --- a/ovn/ovn-nb.xml > +++ b/ovn/ovn-nb.xml > @@ -660,6 +660,12 @@ > Each row represents one load balancer. > </p> > > + <column name="name"> > + 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. > + </column> > + > <column name="vips"> > <p> > 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 d44f039..cf685a5 100644 > --- a/ovn/utilities/ovn-nbctl.8.xml > +++ b/ovn/utilities/ovn-nbctl.8.xml > @@ -102,6 +102,63 @@ > </dd> > </dl> > > + <h1>Logical Switch LB Commands</h1> > + <dl> > + <dt>[<code>--may-exist</code> | <code>--add-duplicate</code>] > <code>lb-add</code> <var>lb</var> <var>vip</var> <var>ips</var> > [<var>protocol</var>]</dt> > + <dd> > + Creates a new load balancer named <var>lb</var> with the > <var>vip</var> or > + adds the <var>vip</var> to <var>lb</var>. A single load balancer > can > + have multiple vips. We should assign <var>lb</var> 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 <var>protocol</var> > must be > + either <code>tcp</code> or <code>udp</code>. This argument is > useful when > + a port number is provided as part of the <var>vip</var>. If the > <var>protocol</var> > + is unspecified and a port number is provided as part of > <var>vip</var>, > + OVN assumes the <var>protocol</var> to be <code>tcp</code>. It > is an > + error if the <var>vip</var> has been included in the load > balancer named > + <var>lb</var>, unless <code>--may-exist</code> is specified. > + With <code>--add-duplicate</code>, the command really creates a > new load > + balancer with a duplicate name. The following example adds a > load balancer > + with <var>protocol</var> <code>udp</code>: > + <p> > + <code>lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80 > ,192.168.10.30:80 udp</code> > + </p> > + </dd> > + > + <dt>[<code>--if-exists</code>] <code>lb-del</code> <var>lb</var> > [<var>vip</var>]</dt> > + <dd> > + Deletes <var>lb</var> or the <var>vip</var> from <var>lb</var>. > + If <var>vip</var> is supplied, the <var>vip</var> will be deleted > + only from the <var>lb</var>. If only <var>lb</var> is supplied, > + the <var>lb</var> will be deleted. It is an error if > <var>vip</var> > + does not be included in <var>lb</var>, unless > <code>--if-exists</code> is specified. > + </dd> > + > + <dt><code>lb-list</code> [<var>switch</var>] [<var>lb</var>]</dt> > + <dd> > + Lists the LBs. If <var>switch</var> is supplied, all the LBs from > + the logical switch are listed. If <var>lb</var> is also specified, > + then the <var>lb</var> will be listed only from the logical > switch. > + </dd> > + > + <dt>[<code>--may-exist</code>] <code>lb-append-to</code> > <var>switch</var> <var>lb</var></dt> > + <dd> > + Adds the specified <var>lb</var> to <var>switch</var>. > + It is an error if a load balancer named <var>lb</var> already > exists > + in the <var>switch</var>, unless <code>--may-exist</code> is > specified. > + </dd> > + > + <dt>[<code>--if-exists</code>] <code>lb-remove-from</code> > <var>switch</var> [<var>lb</var>]</dt> > + <dd> > + Deletes <var>lb</var> from <var>switch</var>. If only > <var>switch</var> is supplied, > + all the LBs from the logical switch are deleted. If > <var>lb</var> is also specified, > + then the <var>lb</var> will be deleted only from the logical > switch. > + It is an error if <var>lb</var> does not exist in the > <var>switch</var>, > + unless <code>--if-exists</code> is specified. > + </dd> > + </dl> > + > <h1>Logical Switch Port Commands</h1> > <dl> > <dt>[<code>--may-exist</code>] <code>lsp-add</code> > <var>switch</var> <var>port</var></dt> > diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c > index d6d64ea..d90080f 100644 > --- a/ovn/utilities/ovn-nbctl.c > +++ b/ovn/utilities/ovn-nbctl.c > @@ -331,6 +331,18 @@ ACL commands:\n\ > remove ACLs from SWITCH\n\ > acl-list SWITCH print ACLs for SWITCH\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]\n\ > + remove a load-balancer or VIP from load > balancer\n\ > + lb-list [SWITCH] [LB]\n\ > + print load-balancers\n\ > + lb-append-to SWITCH LB\n\ > + add a load-balancer to SWITCH\n\ > + lb-remove-from SWITCH [LB]\n\ > + remove load-balancers from SWITCH\n\ > +\n\ > Logical switch port commands:\n\ > lsp-add SWITCH PORT add logical port PORT on SWITCH\n\ > lsp-add SWITCH PORT PARENT TAG\n\ > @@ -493,6 +505,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 > @@ -1315,7 +1360,259 @@ 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_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 struct nbrec_load_balancer *lb; > + NBREC_LOAD_BALANCER_FOR_EACH(lb, ctx->idl) { > + 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); > + } else 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_lb_append_to(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_lb_remove_from(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_lr_add(struct ctl_context *ctx) > { > @@ -2420,6 +2717,14 @@ static const struct ctl_command_syntax > nbctl_commands[] = { > nbctl_acl_del, NULL, "", RW }, > { "acl-list", 1, 1, "SWITCH", NULL, nbctl_acl_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, 2, "[SWITCH] [LB]", NULL, nbctl_lb_list, NULL, "", RO > }, > + { "lb-append-to", 2, 2, "SWITCH LB", NULL, nbctl_lb_append_to, NULL, > "--may-exist", RW }, > + { "lb-remove-from", 1, 2, "SWITCH [LB]", NULL, nbctl_lb_remove_from, > NULL, "--if-exists", RW }, > + > /* logical switch port commands. */ > { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add, > NULL, "--may-exist", RW }, > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at > index 5357ced..6cbcf16 100644 > --- a/tests/ovn-nbctl.at > +++ b/tests/ovn-nbctl.at > @@ -239,6 +239,103 @@ 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 > +]) > + > +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-append-to ls0 lb0]) > +AT_CHECK([ovn-nbctl lb-append-to ls0 lb1]) > +AT_CHECK([ovn-nbctl --may-exist lb-append-to ls0 lb1]) > +AT_CHECK([ovn-nbctl lb-append-to ls0 lb2], [1], [], > +[ovn-nbctl: Multiple load balancers named 'lb2'. Use a UUID. > +]) > + > +AT_CHECK([ovn-nbctl 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 lb-remove-from ls0 lb0]) > +AT_CHECK([ovn-nbctl 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 lb-remove-from ls0 lb1]) > +AT_CHECK([ovn-nbctl lb-list ls0 | ${PERL} $srcdir/uuidfilt.pl], [0], []) > +AT_CHECK([ovn-nbctl --if-exists lb-remove-from ls0 lb1]) > + > +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 >
Yes, I have submitted the v5 patch which support for gateway router. Thank you so much for your reviews. > On Sep 10, 2016, at 5:54 AM, Guru Shetty <guru@ovn.org> wrote: > > On 1 September 2016 at 23:47, nickcooper-zhangtonghao <nickcooper-zhangtonghao@opencloud.tech <mailto: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. 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 <nickcooper-zhangtonghao@opencloud.tech> > > Sorry for the delay on this. I was waiting for the load balancer addition to gateway routers. Now that has been merged, would you please mind re-spinning this with the feature to add it to a router too?
diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 456ae98..d935475 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", "version": "5.3.1", - "cksum": "1921908091 9353", + "cksum": "440042936 9397", "tables": { "NB_Global": { "columns": { @@ -92,6 +92,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 5719e74..186abf8 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -660,6 +660,12 @@ Each row represents one load balancer. </p> + <column name="name"> + 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. + </column> + <column name="vips"> <p> 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 d44f039..cf685a5 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -102,6 +102,63 @@ </dd> </dl> + <h1>Logical Switch LB Commands</h1> + <dl> + <dt>[<code>--may-exist</code> | <code>--add-duplicate</code>] <code>lb-add</code> <var>lb</var> <var>vip</var> <var>ips</var> [<var>protocol</var>]</dt> + <dd> + Creates a new load balancer named <var>lb</var> with the <var>vip</var> or + adds the <var>vip</var> to <var>lb</var>. A single load balancer can + have multiple vips. We should assign <var>lb</var> 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 <var>protocol</var> must be + either <code>tcp</code> or <code>udp</code>. This argument is useful when + a port number is provided as part of the <var>vip</var>. If the <var>protocol</var> + is unspecified and a port number is provided as part of <var>vip</var>, + OVN assumes the <var>protocol</var> to be <code>tcp</code>. It is an + error if the <var>vip</var> has been included in the load balancer named + <var>lb</var>, unless <code>--may-exist</code> is specified. + With <code>--add-duplicate</code>, the command really creates a new load + balancer with a duplicate name. The following example adds a load balancer + with <var>protocol</var> <code>udp</code>: + <p> + <code>lb-add lb0 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80,192.168.10.30:80 udp</code> + </p> + </dd> + + <dt>[<code>--if-exists</code>] <code>lb-del</code> <var>lb</var> [<var>vip</var>]</dt> + <dd> + Deletes <var>lb</var> or the <var>vip</var> from <var>lb</var>. + If <var>vip</var> is supplied, the <var>vip</var> will be deleted + only from the <var>lb</var>. If only <var>lb</var> is supplied, + the <var>lb</var> will be deleted. It is an error if <var>vip</var> + does not be included in <var>lb</var>, unless <code>--if-exists</code> is specified. + </dd> + + <dt><code>lb-list</code> [<var>switch</var>] [<var>lb</var>]</dt> + <dd> + Lists the LBs. If <var>switch</var> is supplied, all the LBs from + the logical switch are listed. If <var>lb</var> is also specified, + then the <var>lb</var> will be listed only from the logical switch. + </dd> + + <dt>[<code>--may-exist</code>] <code>lb-append-to</code> <var>switch</var> <var>lb</var></dt> + <dd> + Adds the specified <var>lb</var> to <var>switch</var>. + It is an error if a load balancer named <var>lb</var> already exists + in the <var>switch</var>, unless <code>--may-exist</code> is specified. + </dd> + + <dt>[<code>--if-exists</code>] <code>lb-remove-from</code> <var>switch</var> [<var>lb</var>]</dt> + <dd> + Deletes <var>lb</var> from <var>switch</var>. If only <var>switch</var> is supplied, + all the LBs from the logical switch are deleted. If <var>lb</var> is also specified, + then the <var>lb</var> will be deleted only from the logical switch. + It is an error if <var>lb</var> does not exist in the <var>switch</var>, + unless <code>--if-exists</code> is specified. + </dd> + </dl> + <h1>Logical Switch Port Commands</h1> <dl> <dt>[<code>--may-exist</code>] <code>lsp-add</code> <var>switch</var> <var>port</var></dt> diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index d6d64ea..d90080f 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -331,6 +331,18 @@ ACL commands:\n\ remove ACLs from SWITCH\n\ acl-list SWITCH print ACLs for SWITCH\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]\n\ + remove a load-balancer or VIP from load balancer\n\ + lb-list [SWITCH] [LB]\n\ + print load-balancers\n\ + lb-append-to SWITCH LB\n\ + add a load-balancer to SWITCH\n\ + lb-remove-from SWITCH [LB]\n\ + remove load-balancers from SWITCH\n\ +\n\ Logical switch port commands:\n\ lsp-add SWITCH PORT add logical port PORT on SWITCH\n\ lsp-add SWITCH PORT PARENT TAG\n\ @@ -493,6 +505,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 @@ -1315,7 +1360,259 @@ 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_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 struct nbrec_load_balancer *lb; + NBREC_LOAD_BALANCER_FOR_EACH(lb, ctx->idl) { + 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); + } else 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_lb_append_to(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_lb_remove_from(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_lr_add(struct ctl_context *ctx) { @@ -2420,6 +2717,14 @@ static const struct ctl_command_syntax nbctl_commands[] = { nbctl_acl_del, NULL, "", RW }, { "acl-list", 1, 1, "SWITCH", NULL, nbctl_acl_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, 2, "[SWITCH] [LB]", NULL, nbctl_lb_list, NULL, "", RO }, + { "lb-append-to", 2, 2, "SWITCH LB", NULL, nbctl_lb_append_to, NULL, "--may-exist", RW }, + { "lb-remove-from", 1, 2, "SWITCH [LB]", NULL, nbctl_lb_remove_from, NULL, "--if-exists", RW }, + /* logical switch port commands. */ { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add, NULL, "--may-exist", RW }, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 5357ced..6cbcf16 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -239,6 +239,103 @@ 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 +]) + +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-append-to ls0 lb0]) +AT_CHECK([ovn-nbctl lb-append-to ls0 lb1]) +AT_CHECK([ovn-nbctl --may-exist lb-append-to ls0 lb1]) +AT_CHECK([ovn-nbctl lb-append-to ls0 lb2], [1], [], +[ovn-nbctl: Multiple load balancers named 'lb2'. Use a UUID. +]) + +AT_CHECK([ovn-nbctl 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 lb-remove-from ls0 lb0]) +AT_CHECK([ovn-nbctl 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 lb-remove-from ls0 lb1]) +AT_CHECK([ovn-nbctl lb-list ls0 | ${PERL} $srcdir/uuidfilt.pl], [0], []) +AT_CHECK([ovn-nbctl --if-exists lb-remove-from ls0 lb1]) + +OVN_NBCTL_TEST_STOP +AT_CLEANUP + +dnl --------------------------------------------------------------------- + AT_SETUP([ovn-nbctl - basic logical router commands]) OVN_NBCTL_TEST_START
This patch provides the command line to create a load balancer. You can create a load balancer independently and add it to multiple switches. 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 <nickcooper-zhangtonghao@opencloud.tech> --- ovn/ovn-nb.ovsschema | 3 +- ovn/ovn-nb.xml | 6 + ovn/utilities/ovn-nbctl.8.xml | 57 ++++++++ ovn/utilities/ovn-nbctl.c | 307 +++++++++++++++++++++++++++++++++++++++++- tests/ovn-nbctl.at | 97 +++++++++++++ 5 files changed, 468 insertions(+), 2 deletions(-)