[ovs-dev] [PATCH v2] ovn-nbctl: Add LB commands.

nickcooper-zhangtonghao nickcooper-zhangtonghao at opencloud.tech
Tue Aug 30 03:12:48 UTC 2016


Add a name column for the load balancer.  This must be unique among
all load balancers.  This name has no special meaning or purpose
other than to provide convenience for human interaction with the
ovn-nb database.  This patch provides the command line to
create load-balancer and add the unit tests.

Signed-off-by: nickcooper-zhangtonghao <nickcooper-zhangtonghao at opencloud.tech>
---
 ovn/ovn-nb.ovsschema          |   5 +-
 ovn/ovn-nb.xml                |   6 ++
 ovn/utilities/ovn-nbctl.8.xml |  35 +++++++++
 ovn/utilities/ovn-nbctl.c     | 163 +++++++++++++++++++++++++++++++++++++++++-
 tests/ovn-nbctl.at            |  44 ++++++++++++
 tests/system-ovn.at           |  13 ++--
 6 files changed, 255 insertions(+), 11 deletions(-)

diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
index 456ae98..87ce15f 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": "360001470 9398",
     "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"}},
@@ -102,7 +103,7 @@
                 "external_ids": {
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}}},
-            "isRoot": true},
+            "isRoot": false},
         "ACL": {
             "columns": {
                 "priority": {"type": {"key": {"type": "integer",
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 5719e74..c3666f5 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 must be unique among all load balancers.
+      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..fa908b7 100644
--- a/ovn/utilities/ovn-nbctl.8.xml
+++ b/ovn/utilities/ovn-nbctl.8.xml
@@ -102,6 +102,41 @@
       </dd>
     </dl>
 
+    <h1>Logical Switch LB Commands</h1>
+    <dl>
+      <dt>[<code>--may-exist</code>] <code>lb-add</code> <var>switch</var> <var>lb</var> <var>vip</var> <var>ips</var> [<var>protocol</var>]</dt>
+      <dd>
+        Adds the specified LB to <var>switch</var>.  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 a load-balancer
+        named <var>lb</var> already exists, unless <code>--may-exist</code> is specified.
+        The following example adds a load-balancer with <var>protocol</var> <code>udp</code>:
+        <p>
+          <code>lb-add ls0 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>switch</var> [<var>lb</var>]</dt>
+      <dd>
+        Deletes LBs 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, unless <code>--if-exists</code>
+        is specified.
+      </dd>
+
+      <dt><code>lb-list</code> <var>switch</var></dt>
+      <dd>
+        Lists the LBs on <var>switch</var>.
+      </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..fc02918 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -331,6 +331,13 @@ ACL commands:\n\
                             remove ACLs from SWITCH\n\
   acl-list SWITCH           print ACLs for SWITCH\n\
 \n\
+LB commands:\n\
+  lb-add SWITCH LB VIP[:PORT] IP[:PORT]... [PROTOCOL]\n\
+                            add a load-balancer to SWITCH\n\
+  lb-del SWITCH [LB]\n\
+                            remove load-balancers from SWITCH\n\
+  lb-list SWITCH [LB]       print load-balancers for 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\
@@ -1315,7 +1322,154 @@ nbctl_acl_del(struct ctl_context *ctx)
         }
     }
 }
-
+
+static void
+nbctl_lb_add(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_switch *ls;
+    const char *lb_name = ctx->argv[2];
+    const char *lb_vip = ctx->argv[3];
+    const char *lb_ips = ctx->argv[4];
+
+    ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+    const char *lb_proto;
+    if (ctx->argc == 5) {
+        /* default protocol.*/
+        lb_proto = "tcp";
+    } else {
+        lb_proto = ctx->argv[5];
+        /* Validate protocol. */
+        if (strcmp(lb_proto, "tcp") && strcmp(lb_proto, "udp")) {
+            ctl_fatal("%s: protocol must be one of \"tcp\", \"udp\".", lb_proto);
+        }
+    }
+
+    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 (strcmp(lb->name, lb_name)) {
+            continue;
+        }
+
+        if (!may_exist) {
+            ctl_fatal("%s: a load balancer with this name already exists", lb_name);
+        }
+
+        nbrec_logical_switch_verify_load_balancer(ls);
+        nbrec_load_balancer_verify_protocol(lb);
+        nbrec_load_balancer_verify_vips(lb);
+        nbrec_load_balancer_set_protocol(lb, lb_proto);
+
+        struct smap vips = SMAP_INITIALIZER(&vips);
+        smap_add(&vips, lb_vip, lb_ips);
+        nbrec_load_balancer_set_vips(lb, &vips);
+        smap_destroy(&vips);
+
+        return;
+    }
+
+    /* Create the load balancer. */
+    struct nbrec_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);
+
+    struct smap vips = SMAP_INITIALIZER(&vips);
+    smap_add(&vips, lb_vip, lb_ips);
+    nbrec_load_balancer_set_vips(lb, &vips);
+    smap_destroy(&vips);
+
+    /* Insert the load balancer into the logical switch. */
+    nbrec_logical_switch_verify_acls(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] = lb;
+    nbrec_logical_switch_set_load_balancer(ls, new_lbs, ls->n_load_balancer + 1);
+    free(new_lbs);
+}
+
+static void
+nbctl_lb_del(struct ctl_context *ctx)
+{
+    const char *lb_name = ctx->argv[2];
+    const struct nbrec_logical_switch *ls;
+    ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+    if (ctx->argc == 2) {
+        /* If load-balancer is not specified, delete
+         * all load-balancers. */
+        nbrec_logical_switch_verify_load_balancer(ls);
+        nbrec_logical_switch_set_load_balancer(ls, NULL, 0);
+        return;
+    }
+
+    for (size_t i = 0; i < ls->n_load_balancer; i++) {
+        const struct nbrec_load_balancer *lb
+            = ls->load_balancer[i];
+
+        if (strcmp(lb->name, lb_name)) {
+            continue;
+        }
+
+        /* Remove the matching rule. */
+        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_verify_load_balancer(ls);
+        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.",
+                lb_name);
+    }
+}
+
+static void
+nbctl_lb_list(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_switch *ls;
+
+    ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+    struct smap lbs = SMAP_INITIALIZER(&lbs);
+    for (int i = 0; i < ls->n_load_balancer; i++) {
+        const struct nbrec_load_balancer *lb
+            = ls->load_balancer[i];
+        if (ctx->argc == 3 && strcmp(lb->name, ctx->argv[2])) {
+            continue;
+        }
+
+        const struct smap_node **nodes = smap_sort(&lb->vips);
+        if (nodes) {
+            const struct smap_node *node = nodes[0];
+            smap_add_format(&lbs, lb->name, "%-10.8s %-5s %-20s %s",
+                        lb->name, lb->protocol, node->key, node->value);
+            free(nodes);
+        }
+    }
+
+    const struct smap_node **nodes = smap_sort(&lbs);
+    ds_put_format(&ctx->output,
+            "Logical Switch: %s\n"
+            "%-10.8s %-5s %-20s IPs\n",
+            ls->name, "LB", "PROTO", "VIP");
+    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)
 {
@@ -2420,6 +2574,13 @@ 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", 4, 5, "SWITCH LB VIP[:PORT] IP[:PORT]... [PROTOCOL]", NULL,
+      nbctl_lb_add, NULL, "--may-exist", RW },
+    { "lb-del", 1, 2, "SWITCH [LB]", NULL,
+      nbctl_lb_del, NULL, "--if-exists", RW },
+    { "lb-list", 1, 2, "SWITCH [LB]", NULL, nbctl_lb_list, NULL, "", RO },
+
     /* 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..3ea246e 100644
--- a/tests/ovn-nbctl.at
+++ b/tests/ovn-nbctl.at
@@ -239,6 +239,50 @@ AT_CLEANUP
 
 dnl ---------------------------------------------------------------------
 
+AT_SETUP([ovn-nbctl - LBs])
+OVN_NBCTL_TEST_START
+
+AT_CHECK([ovn-nbctl ls-add ls0])
+AT_CHECK([ovn-nbctl lb-add ls0 lb0 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80])
+AT_CHECK([ovn-nbctl lb-add ls0 lb1 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80 tcp])
+AT_CHECK([ovn-nbctl lb-add ls0 lb2 30.0.0.10:80 192.168.10.10:80,192.168.10.20:80 udp])
+
+AT_CHECK([ovn-nbctl lb-list ls0], [0], [dnl
+Logical Switch: ls0
+LB         PROTO VIP                  IPs
+lb0        tcp   30.0.0.10:80         192.168.10.10:80,192.168.10.20:80
+lb1        tcp   30.0.0.10:80         192.168.10.10:80,192.168.10.20:80
+lb2        udp   30.0.0.10:80         192.168.10.10:80,192.168.10.20:80
+])
+
+dnl List a load-balancer.
+AT_CHECK([ovn-nbctl lb-list ls0 lb0], [0], [dnl
+Logical Switch: ls0
+LB         PROTO VIP                  IPs
+lb0        tcp   30.0.0.10:80         192.168.10.10:80,192.168.10.20:80
+])
+
+dnl Delete a load-balancer.
+AT_CHECK([ovn-nbctl lb-del ls0 lb0])
+AT_CHECK([ovn-nbctl lb-list ls0], [0], [dnl
+Logical Switch: ls0
+LB         PROTO VIP                  IPs
+lb1        tcp   30.0.0.10:80         192.168.10.10:80,192.168.10.20:80
+lb2        udp   30.0.0.10:80         192.168.10.10:80,192.168.10.20:80
+])
+
+dnl Delete all load-balancers.
+AT_CHECK([ovn-nbctl lb-del ls0])
+AT_CHECK([ovn-nbctl lb-list ls0], [0], [dnl
+Logical Switch: ls0
+LB         PROTO VIP                  IPs
+])
+
+OVN_NBCTL_TEST_STOP
+AT_CLEANUP
+
+dnl ---------------------------------------------------------------------
+
 AT_SETUP([ovn-nbctl - basic logical router commands])
 OVN_NBCTL_TEST_START
 
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index e267384..109be85 100755
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -348,15 +348,13 @@ ovn-nbctl lsp-add bar bar3 \
 -- lsp-set-addresses bar3 "f0:00:0f:01:02:05 172.16.1.4"
 
 # Config OVN load-balancer with a VIP.
-uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="172.16.1.2,172.16.1.3,172.16.1.4"`
-ovn-nbctl set logical_switch foo load_balancer=$uuid
+ovn-nbctl lb-add foo lb0 30.0.0.1 172.16.1.2,172.16.1.3,172.16.1.4
 
 # Create another load-balancer with another VIP.
-uuid=`ovn-nbctl create load_balancer vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"`
-ovn-nbctl add logical_switch foo load_balancer $uuid
+ovn-nbctl lb-add foo lb1 30.0.0.3 172.16.1.2,172.16.1.3,172.16.1.4
 
 # Config OVN load-balancer with another VIP (this time with ports).
-ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"172.16.1.2:80,172.16.1.3:80,172.16.1.4:80"'
+ovn-nbctl lb-add foo lb2 30.0.0.2:8000 172.16.1.2:80,172.16.1.3:80,172.16.1.4:80
 
 # Wait for ovn-controller to catch up.
 OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | grep ct\(])
@@ -468,11 +466,10 @@ for i in `seq 1 4`; do
 done
 
 # Config OVN load-balancer with a VIP.
-uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.3,192.168.1.4,192.168.1.5"`
-ovn-nbctl set logical_switch foo load_balancer=$uuid
+ovn-nbctl lb-add foo lb0 30.0.0.1 192.168.1.3,192.168.1.4,192.168.1.5
 
 # Config OVN load-balancer with another VIP (this time with ports).
-ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.3:80,192.168.1.4:80,192.168.1.5:80"'
+ovn-nbctl lb-add foo lb1 30.0.0.2:8000 192.168.1.3:80,192.168.1.4:80,192.168.1.5:80
 
 # Wait for ovn-controller to catch up.
 OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | grep ct\(])
-- 
1.8.3.1






More information about the dev mailing list