[ovs-dev] [PATCH V5] add lrouter and lrport related commands to ovn-nbctl

nghosh at us.ibm.com nghosh at us.ibm.com
Tue May 24 22:18:18 UTC 2016


ovn-nbctl provides a shortcut to perform commands related lswitch, lport
and such but it doesn't have similar commands related to logical routers
and logical router ports. Also, 'ovn-nbctl show' is supposed to show an
overview of database contents, which means it should show the routers
as well. "ovn-nbctl show LSWITCH" shows the switch details, similarly
"ovn-nbctl show LROUTER" should show the router details too. This patch
takes care of all of these.

Modifications;
1) ovn-nbctl show -- will now show lrouters as well
2) ovn-nbctl show <lrouter> -- will show the router now

New commands added:
3) ovn-nbctl lrouter-add [LROUTER]
4) ovn-nbctl lrouter-del LROUTER
5) ovn-nbctl lrouter-list
6) lrport-add LROUTER LRPORT
7) lrport-del LRPORT
8) lrport-list LROUTER
9) lrport-set-mac-address LRPORT [ADDRESS]
10) lrport-get-mac-address LRPORT
11) lrport-set-enabled LRPORT STATE
12) lrport-get-enabled LRPORT

Unit test cases have been added to test all of these modifications and
additions.

Signed-off-by: Nirapada Ghosh <nghosh at us.ibm.com>

---
diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml
index 8375ab7..edfb708 100644
--- a/ovn/utilities/ovn-nbctl.8.xml
+++ b/ovn/utilities/ovn-nbctl.8.xml
@@ -12,14 +12,36 @@
     <h1>General Commands</h1>
 
     <dl>
-      <dt><code>show [<var>lswitch</var>]</code></dt>
+      <dt><code>show [<var>lswitch</var> | <var>lrouter</var>]</code></dt>
       <dd>
         Prints a brief overview of the database contents.  If
         <var>lswitch</var> is provided, only records related to that
-        logical switch are shown.
+        logical switch are shown. If
+        <var>lrouter</var> is provided, only records related to that
+        logical router are shown.
       </dd>
     </dl>
 
+    <h1>Logical Router Commands</h1>
+
+    <dl>
+      <dt><code>lrouter-add</code> [<var>lrouter</var>]</dt> <dd>
+        Creates a new logical lrouter named <var>lrouter</var>.  If
+        <var>lrouter</var> is not provided, the lrouter will not have a
+        name so other commands must refer to this router by its UUID.
+        Initially the router will have no ports.
+      </dd>
+
+      <dt><code>lrouter-del</code> <var>lrouter</var></dt>
+      <dd>
+        Deletes <var>lrouter</var>.
+      </dd>
+
+      <dt><code>lrouter-list</code></dt>
+      <dd>
+        Lists all existing logical routers on standard output, one per line.
+      </dd>
+    </dl>
     <h1>Logical Switch Commands</h1>
 
     <dl>
@@ -91,7 +113,57 @@
         Lists the ACLs on <var>lswitch</var>.
       </dd>
     </dl>
+    <h1>Logical Router Port Commands</h1>
+    <dl>
+      <dt><code>lrport-add</code> <var>lrouter</var> <var>lrport</var></dt>
+      <dd>
+        Creates on <var>lrouter</var> a new logical router port named
+        <var>lrport</var>.
+      </dd>
 
+      <dt><code>lrport-del</code> <var>lrport</var></dt>
+      <dd>
+        Deletes <var>lrport</var>.
+      </dd>
+
+      <dt><code>lrport-list</code> <var>lrouter</var></dt>
+      <dd>
+        Lists all the logical router ports within <var>lrouter</var> on
+        standard output, one per line.
+      </dd>
+
+      <dt><code>lrport-set-mac-address</code> <var>lrport</var>
+                <var>address</var>...</dt>
+      <dd>
+        Sets the address associated with <var>lrport</var> to
+        <var>address</var>.  <var>address</var> should be either an
+        Ethernet address or an Ethernet address followed by an IP address
+        (separated by a space and quoted to form a single command-line
+        argument).  The special form <code>unknown</code> is also valid.
+      </dd>
+
+      <dt><code>lrport-get-mac-address</code> <var>lrport</var></dt>
+      <dd>
+        Lists the mac address associated with <var>lrport</var> on standard
+        output.
+      </dd>
+
+      <dt><code>lrport-set-enabled</code> <var>lrport</var>
+                                          <var>state</var></dt>
+      <dd>
+        Set the administrative state of <var>lrport</var>,
+        either <code>enabled</code> or <code>disabled</code>.
+        When a port is disabled, no traffic is allowed into
+        or out of the port.
+      </dd>
+
+      <dt><code>lrport-get-enabled</code> <var>lrport</var></dt>
+      <dd>
+        Prints the administrative state of <var>lrport</var>,
+        either <code>enabled</code> or <code>disabled</code>.
+      </dd>
+
+    </dl>
     <h1>Logical Port Commands</h1>
     <dl>
       <dt>[<code>--may-exist</code>] <code>lport-add</code> <var>lswitch</var> <var>lport</var></dt>
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
index d267829..f9783da 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -293,12 +293,18 @@ usage: %s [OPTIONS] COMMAND [ARG...]\n\
 General commands:\n\
   show                      print overview of database contents\n\
   show LSWITCH              print overview of database contents for LSWITCH\n\
+  show LROUTER              print overview of database contents for LROUTER\n\
 \n\
 Logical switch commands:\n\
   lswitch-add [LSWITCH]     create a logical switch named LSWITCH\n\
   lswitch-del LSWITCH       delete LSWITCH and all its ports\n\
   lswitch-list              print the names of all logical switches\n\
 \n\
+Logical router commands:\n\
+  lrouter-add [LROUTER]     create a logical router named LROUTER\n\
+  lrouter-del LROUTER       delete LROUTER and all its ports\n\
+  lrouter-list              print the names of all logical routers\n\
+\n\
 ACL commands:\n\
   acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
                             add an ACL to LSWITCH\n\
@@ -306,6 +312,19 @@ ACL commands:\n\
                             remove ACLs from LSWITCH\n\
   acl-list LSWITCH          print ACLs for LSWITCH\n\
 \n\
+Logical router port commands:\n\
+  lrport-add LROUTER LRPORT   add logical router port LRPORT to LROUTER\n\
+  lrport-del LRPORT           delete LRPORT from its attached router\n\
+  lrport-list LROUTER        print the names of all logical ports on LROUTER\n\
+  lrport-set-mac-address LRPORT [ADDRESS]\n\
+                            set MAC address for LRPORT.\n\
+  lrport-get-mac-address LRPORT      get MAC addresses on LRPORT\n\
+  lrport-set-enabled LRPORT STATE\n\
+                            set administrative state LRPORT\n\
+                            ('enabled' or 'disabled')\n\
+  lrport-get-enabled LRPORT   get administrative state LRPORT\n\
+                            ('enabled' or 'disabled')\n\
+\n\
 Logical port commands:\n\
   lport-add LSWITCH LPORT   add logical port LPORT on LSWITCH\n\
   lport-add LSWITCH LPORT PARENT TAG\n\
@@ -352,9 +371,50 @@ Other options:\n\
     exit(EXIT_SUCCESS);
 }
 
+
+/* Following function finds out the lrouter given it's id. */
+static const struct nbrec_logical_router *
+lrouter_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool silent)
+{
+    const struct nbrec_logical_router *lrouter = NULL;
+    bool is_uuid = false;
+    bool duplicate = false;
+    struct uuid lrouter_uuid;
+
+    if (uuid_from_string(&lrouter_uuid, id)) {
+        is_uuid = true;
+        lrouter = nbrec_logical_router_get_for_uuid(ctx->idl,
+                                                    &lrouter_uuid);
+    }
+
+    if (!lrouter) {
+        const struct nbrec_logical_router *iter;
+
+        NBREC_LOGICAL_ROUTER_FOR_EACH(iter, ctx->idl) {
+            if (strcmp(iter->name, id)) {
+                continue;
+            }
+            if (lrouter) {
+                ctl_fatal("There is more than one logical router named '%s'. "
+                        "Use a UUID.", id);
+                lrouter = NULL;
+                duplicate = true;
+                break;
+            }
+            lrouter = iter;
+        }
+    }
+
+    if (!lrouter && !duplicate && !silent) {
+        ctl_fatal("lrouter not found for %s: '%s'",
+                is_uuid ? "UUID" : "name", id);
+    }
+
+    return lrouter;
+}
 static const struct nbrec_logical_switch *
 lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id,
-                        bool must_exist)
+                        bool must_exist, bool silent)
 {
     const struct nbrec_logical_switch *lswitch = NULL;
 
@@ -379,13 +439,31 @@ lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id,
         }
     }
 
-    if (!lswitch && must_exist) {
+    if (!lswitch && must_exist && !silent) {
         ctl_fatal("%s: lswitch %s not found", id, is_uuid ? "UUID" : "name");
     }
 
     return lswitch;
 }
 
+/* Given pointer to lrouter, this routine prints the lrouter information.  */
+static void
+print_lrouter(const struct nbrec_logical_router *lrouter, struct ds *s)
+{
+    ds_put_format(s, "    lrouter "UUID_FMT" (%s)\n",
+                  UUID_ARGS(&lrouter->header_.uuid), lrouter->name);
+
+    for (size_t i = 0; i < lrouter->n_ports; i++) {
+        const struct nbrec_logical_router_port *lrport = lrouter->ports[i];
+        ds_put_format(s, "        lrport %s\n", lrport->name);
+        if (lrport->mac) {
+            ds_put_cstr(s, "            mac: ");
+            ds_put_format(s, "\"%s\"", lrport->mac);
+        }
+        ds_put_format(s, "\n");
+    }
+}
+
 static void
 print_lswitch(const struct nbrec_logical_switch *lswitch, struct ds *s)
 {
@@ -420,7 +498,7 @@ nbctl_show(struct ctl_context *ctx)
     const struct nbrec_logical_switch *lswitch;
 
     if (ctx->argc == 2) {
-        lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], false);
+        lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], false, true);
         if (lswitch) {
             print_lswitch(lswitch, &ctx->output);
         }
@@ -429,6 +507,66 @@ nbctl_show(struct ctl_context *ctx)
             print_lswitch(lswitch, &ctx->output);
         }
     }
+    const struct nbrec_logical_router *lrouter;
+
+    if (ctx->argc == 2) {
+        lrouter = lrouter_by_name_or_uuid(ctx, ctx->argv[1], true);
+        if (lrouter) {
+            print_lrouter(lrouter, &ctx->output);
+        }
+    } else {
+        NBREC_LOGICAL_ROUTER_FOR_EACH(lrouter, ctx->idl) {
+            print_lrouter(lrouter, &ctx->output);
+        }
+    }
+}
+
+/* Following function adds a lrouter to NB */
+static void
+nbctl_lrouter_add(struct ctl_context *ctx)
+{
+    struct nbrec_logical_router *lrouter;
+
+    lrouter = nbrec_logical_router_insert(ctx->txn);
+    if (ctx->argc == 2) {
+        nbrec_logical_router_set_name(lrouter, ctx->argv[1]);
+    }
+}
+
+/* Following function deletes a lrouter from NB */
+static void
+nbctl_lrouter_del(struct ctl_context *ctx)
+{
+    const char *id = ctx->argv[1];
+    const struct nbrec_logical_router *lrouter;
+
+    lrouter = lrouter_by_name_or_uuid(ctx, id, false);
+    if (!lrouter) {
+        return;
+    }
+
+    nbrec_logical_router_delete(lrouter);
+}
+
+/* Following function prints list of lrouters in NB */
+static void
+nbctl_lrouter_list(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_router *lrouter;
+    struct smap lrouters;
+
+    smap_init(&lrouters);
+    NBREC_LOGICAL_ROUTER_FOR_EACH(lrouter, ctx->idl) {
+        smap_add_format(&lrouters, lrouter->name, UUID_FMT " (%s)",
+                        UUID_ARGS(&lrouter->header_.uuid), lrouter->name);
+    }
+    const struct smap_node **nodes = smap_sort(&lrouters);
+    for (size_t i = 0; i < smap_count(&lrouters); i++) {
+        const struct smap_node *node = nodes[i];
+        ds_put_format(&ctx->output, "%s\n", node->value);
+    }
+    smap_destroy(&lrouters);
+    free(nodes);
 }
 
 static void
@@ -475,7 +613,7 @@ nbctl_lswitch_del(struct ctl_context *ctx)
     const char *id = ctx->argv[1];
     const struct nbrec_logical_switch *lswitch;
 
-    lswitch = lswitch_by_name_or_uuid(ctx, id, must_exist);
+    lswitch = lswitch_by_name_or_uuid(ctx, id, must_exist, false);
     if (!lswitch) {
         return;
     }
@@ -503,6 +641,37 @@ nbctl_lswitch_list(struct ctl_context *ctx)
     free(nodes);
 }
 
+
+/* Following function finds out the lrport given it's id. */
+static const struct nbrec_logical_router_port *
+lrport_by_name_or_uuid(struct ctl_context *ctx, const char *id)
+{
+    const struct nbrec_logical_router_port *lrport = NULL;
+    bool is_uuid = false;
+    struct uuid lrport_uuid;
+
+    if (uuid_from_string(&lrport_uuid, id)) {
+        is_uuid = true;
+        lrport = nbrec_logical_router_port_get_for_uuid(ctx->idl,
+                                                        &lrport_uuid);
+    }
+
+    if (!lrport) {
+        NBREC_LOGICAL_ROUTER_PORT_FOR_EACH(lrport, ctx->idl) {
+            if (!strcmp(lrport->name, id)) {
+                break;
+            }
+        }
+    }
+
+    if (!lrport) {
+        ctl_fatal("lrport not found for %s: '%s'",
+                is_uuid ? "UUID" : "name", id);
+    }
+
+    return lrport;
+}
+
 static const struct nbrec_logical_port *
 lport_by_name_or_uuid(struct ctl_context *ctx, const char *id,
                       bool must_exist)
@@ -566,7 +735,7 @@ nbctl_lport_add(struct ctl_context *ctx)
     bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
 
     const struct nbrec_logical_switch *lswitch;
-    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
+    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true, false);
 
     const char *parent_name;
     int64_t tag;
@@ -646,6 +815,26 @@ nbctl_lport_add(struct ctl_context *ctx)
     free(new_ports);
 }
 
+/* Removes lrport 'lrouter->ports[idx]' from lrouter. */
+static void
+remove_lrport(const struct nbrec_logical_router *lrouter, size_t idx)
+{
+    const struct nbrec_logical_router_port *lrport = lrouter->ports[idx];
+
+    /* First remove 'lrport' from the array of ports.  This is what will
+     * actually cause the logical port to be deleted when the transaction is
+     * sent to the database server (due to garbage collection). */
+    struct nbrec_logical_router_port **new_ports
+        = xmemdup(lrouter->ports, sizeof *new_ports * lrouter->n_ports);
+    new_ports[idx] = new_ports[lrouter->n_ports - 1];
+    nbrec_logical_router_verify_ports(lrouter);
+    nbrec_logical_router_set_ports(lrouter, new_ports, lrouter->n_ports - 1);
+    free(new_ports);
+
+    /* Delete 'lrport' from the IDL. */
+    nbrec_logical_router_port_delete(lrport);
+}
+
 /* Removes lport 'lswitch->ports[idx]'. */
 static void
 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
@@ -703,7 +892,7 @@ nbctl_lport_list(struct ctl_context *ctx)
     struct smap lports;
     size_t i;
 
-    lswitch = lswitch_by_name_or_uuid(ctx, id, true);
+    lswitch = lswitch_by_name_or_uuid(ctx, id, true, false);
 
     smap_init(&lports);
     for (i = 0; i < lswitch->n_ports; i++) {
@@ -742,6 +931,32 @@ nbctl_lport_get_tag(struct ctl_context *ctx)
     }
 }
 
+/* Following function sets the mac address of lrport. */
+static void
+nbctl_lrport_set_mac(struct ctl_context *ctx)
+{
+    struct eth_addr ea;
+    const char *id = ctx->argv[1];
+    const struct nbrec_logical_router_port *lrport;
+
+    lrport = lrport_by_name_or_uuid(ctx, id);
+    if (!lrport) {
+        return;
+    }
+    if (ctx->argc != 3) {
+        ctl_fatal("Invalid usage");
+        return;
+    }
+
+    if (strcmp(ctx->argv[2], "unknown")
+        && !ovs_scan(ctx->argv[2], ETH_ADDR_SCAN_FMT,
+                     ETH_ADDR_SCAN_ARGS(ea))) {
+        ctl_fatal("Invalid MAC address format, See ovn-nb(5)");
+        return;
+    }
+
+    nbrec_logical_router_port_set_mac(lrport, ctx->argv[2]);
+}
 static void
 nbctl_lport_set_addresses(struct ctl_context *ctx)
 {
@@ -768,6 +983,20 @@ nbctl_lport_set_addresses(struct ctl_context *ctx)
             (const char **) ctx->argv + 2, ctx->argc - 2);
 }
 
+/* Following function prints the mac address of the lrport. */
+static void
+nbctl_lrport_get_mac(struct ctl_context *ctx)
+{
+    const char *id = ctx->argv[1];
+    const struct nbrec_logical_router_port *lrport;
+
+    lrport = lrport_by_name_or_uuid(ctx, id);
+    if (!lrport) {
+        return;
+    }
+    ds_put_format(&ctx->output, "%s\n", lrport->mac);
+}
+
 static void
 nbctl_lport_get_addresses(struct ctl_context *ctx)
 {
@@ -833,6 +1062,29 @@ nbctl_lport_get_up(struct ctl_context *ctx)
                   "%s\n", (lport->up && *lport->up) ? "up" : "down");
 }
 
+/* Following function sets the lrport to admin-enabled. */
+static void
+nbctl_lrport_set_enabled(struct ctl_context *ctx)
+{
+    const char *id = ctx->argv[1];
+    const char *state = ctx->argv[2];
+    const struct nbrec_logical_router_port *lrport;
+
+    lrport = lrport_by_name_or_uuid(ctx, id);
+    if (!lrport) {
+        return;
+    }
+
+    if (!strcasecmp(state, "enabled")) {
+        bool enabled = true;
+        nbrec_logical_router_port_set_enabled(lrport, &enabled, 1);
+    } else if (!strcasecmp(state, "disabled")) {
+        bool enabled = false;
+        nbrec_logical_router_port_set_enabled(lrport, &enabled, 1);
+    } else {
+        ctl_fatal("Invalid state '%s' provided to lrport-set-enabled", state);
+    }
+}
 static void
 nbctl_lport_set_enabled(struct ctl_context *ctx)
 {
@@ -853,6 +1105,22 @@ nbctl_lport_set_enabled(struct ctl_context *ctx)
     }
 }
 
+/* Following function prints admin-enabled state. */
+static void
+nbctl_lrport_get_enabled(struct ctl_context *ctx)
+{
+    const char *id = ctx->argv[1];
+    const struct nbrec_logical_router_port *lrport;
+
+    lrport = lrport_by_name_or_uuid(ctx, id);
+    if (!lrport) {
+        return;
+    }
+
+    ds_put_format(&ctx->output, "%s\n",
+                  !lrport->enabled ||
+                  *lrport->enabled ? "enabled" : "disabled");
+}
 static void
 nbctl_lport_get_enabled(struct ctl_context *ctx)
 {
@@ -966,7 +1234,7 @@ nbctl_acl_list(struct ctl_context *ctx)
     const struct nbrec_acl **acls;
     size_t i;
 
-    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
+    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true, false);
 
     acls = xmalloc(sizeof *acls * lswitch->n_acls);
     for (i = 0; i < lswitch->n_acls; i++) {
@@ -1015,7 +1283,7 @@ nbctl_acl_add(struct ctl_context *ctx)
     const struct nbrec_logical_switch *lswitch;
     const char *action = ctx->argv[5];
 
-    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
+    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true, false);
 
     const char *direction = parse_direction(ctx->argv[2]);
     int64_t priority = parse_priority(ctx->argv[3]);
@@ -1052,7 +1320,7 @@ static void
 nbctl_acl_del(struct ctl_context *ctx)
 {
     const struct nbrec_logical_switch *lswitch;
-    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
+    lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true, false);
 
     if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
         ctl_fatal("cannot specify priority without match");
@@ -1336,6 +1604,92 @@ nbctl_exit(int status)
     exit(status);
 }
 
+/* Following function prints the list of lrports. */
+static void
+nbctl_lrport_list(struct ctl_context *ctx)
+{
+    const char *id = ctx->argv[1];
+    const struct nbrec_logical_router *lrouter;
+    struct smap lports;
+    size_t i;
+
+    lrouter = lrouter_by_name_or_uuid(ctx, id, false);
+    if (!lrouter) {
+        return;
+    }
+
+    smap_init(&lports);
+    for (i = 0; i < lrouter->n_ports; i++) {
+        const struct nbrec_logical_router_port *lport = lrouter->ports[i];
+        smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
+                        UUID_ARGS(&lport->header_.uuid), lport->name);
+    }
+    const struct smap_node **nodes = smap_sort(&lports);
+    for (i = 0; i < smap_count(&lports); i++) {
+        const struct smap_node *node = nodes[i];
+        ds_put_format(&ctx->output, "%s\n", node->value);
+    }
+    smap_destroy(&lports);
+    free(nodes);
+}
+
+/* Following function adds an lrport to the lrouter. */
+static void
+nbctl_lrport_add(struct ctl_context *ctx)
+{
+    struct nbrec_logical_router_port *lport;
+    const struct nbrec_logical_router *lrouter;
+
+    lrouter = lrouter_by_name_or_uuid(ctx, ctx->argv[1], false);
+    if (!lrouter) {
+        return;
+    }
+
+    if (ctx->argc != 3) {
+        ctl_fatal("Invalid arguments to lrport-add.");
+        return;
+    }
+
+    /* Create the logical router port. */
+    lport = nbrec_logical_router_port_insert(ctx->txn);
+    nbrec_logical_router_port_set_name(lport, ctx->argv[2]);
+
+    /* Insert the logical port into the logical router. */
+    nbrec_logical_router_verify_ports(lrouter);
+    struct nbrec_logical_router_port **new_ports = xmalloc(sizeof *new_ports *
+                                                    (lrouter->n_ports + 1));
+    memcpy(new_ports, lrouter->ports, sizeof *new_ports * lrouter->n_ports);
+    new_ports[lrouter->n_ports] = lport;
+    nbrec_logical_router_set_ports(lrouter, new_ports, lrouter->n_ports + 1);
+    free(new_ports);
+}
+
+/* Following function deletes the lrport from lrouter. */
+static void
+nbctl_lrport_del(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_router_port *lrport;
+
+    lrport = lrport_by_name_or_uuid(ctx, ctx->argv[1]);
+    if (!lrport) {
+        return;
+    }
+
+    /* Find the router that contains 'lport', then delete it. */
+    const struct nbrec_logical_router *lrouter;
+    NBREC_LOGICAL_ROUTER_FOR_EACH (lrouter, ctx->idl) {
+        for (size_t i = 0; i < lrouter->n_ports; i++) {
+            if (lrouter->ports[i] == lrport) {
+                remove_lrport(lrouter, i);
+                return;
+            }
+        }
+    }
+
+    ctl_fatal("logical router port %s is not part of any logical router",
+              ctx->argv[1]);
+}
+
 static const struct ctl_command_syntax nbctl_commands[] = {
     { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO },
 
@@ -1346,6 +1700,13 @@ static const struct ctl_command_syntax nbctl_commands[] = {
       NULL, "--if-exists", RW },
     { "lswitch-list", 0, 0, "", NULL, nbctl_lswitch_list, NULL, "", RO },
 
+    /* lrouter commands. */
+    { "lrouter-add", 0, 1, "[LROUTER]", NULL, nbctl_lrouter_add,
+      NULL, "", RW },
+    { "lrouter-del", 1, 1, "LROUTER", NULL, nbctl_lrouter_del,
+      NULL, "", RW },
+    { "lrouter-list", 0, 0, "", NULL, nbctl_lrouter_list, NULL, "", RO },
+
     /* acl commands. */
     { "acl-add", 5, 5, "LSWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
       nbctl_acl_add, NULL, "--log", RW },
@@ -1353,6 +1714,20 @@ static const struct ctl_command_syntax nbctl_commands[] = {
       nbctl_acl_del, NULL, "", RW },
     { "acl-list", 1, 1, "LSWITCH", NULL, nbctl_acl_list, NULL, "", RO },
 
+    /* lrport commands. */
+    { "lrport-add", 2, 4, "LROUTER LRPORT ", NULL, nbctl_lrport_add,
+      NULL, "", RW },
+    { "lrport-del", 1, 1, "LRPORT", NULL, nbctl_lrport_del, NULL, "", RO },
+    { "lrport-list", 1, 1, "LROUTER", NULL, nbctl_lrport_list, NULL, "", RO },
+    { "lrport-set-mac-address", 1, INT_MAX, "LRPORT [ADDRESS]", NULL,
+      nbctl_lrport_set_mac, NULL, "", RW },
+    { "lrport-get-mac-address", 1, 1, "LRPORT", NULL,
+      nbctl_lrport_get_mac, NULL,
+      "", RO },
+    { "lrport-set-enabled", 2, 2, "LRPORT STATE", NULL,
+      nbctl_lrport_set_enabled, NULL, "", RW },
+    { "lrport-get-enabled", 1, 1, "LRPORT", NULL,
+      nbctl_lrport_get_enabled, NULL, "", RO },
     /* lport commands. */
     { "lport-add", 2, 4, "LSWITCH LPORT [PARENT] [TAG]", NULL, nbctl_lport_add,
       NULL, "--may-exist", RW },
diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
index 47ec1ef..15fd90c 100644
--- a/tests/ovn-nbctl.at
+++ b/tests/ovn-nbctl.at
@@ -231,3 +231,72 @@ from-lport   200 (ip) drop
 
 OVN_NBCTL_TEST_STOP
 AT_CLEANUP
+
+dnl ---------------------------------------------------------------------
+
+AT_SETUP([ovn-nbctl - new commands ])
+OVN_NBCTL_TEST_START
+dnl create a lswitch
+AT_CHECK([ovn-nbctl lswitch-add ls0])
+dnl create a lrouter
+AT_CHECK([ovn-nbctl lrouter-add lr0])
+dnl show command shows both lswitch and lrouter
+AT_CHECK([ovn-nbctl show | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+    lswitch <0> (ls0)
+    lrouter <1> (lr0)
+])
+dnl add another lrouter
+AT_CHECK([ovn-nbctl lrouter-add lr1])
+dnl show <lrouter> to show a specific lrouter
+AT_CHECK([ovn-nbctl show lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+    lrouter <0> (lr0)
+])
+dnl lrouter-list shows all lrouters
+AT_CHECK([ovn-nbctl lrouter-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+<0> (lr0)
+<1> (lr1)
+])
+dnl delete lrouter and check the list is correct
+AT_CHECK([ovn-nbctl lrouter-del lr1])
+AT_CHECK([ovn-nbctl lrouter-list | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+<0> (lr0)
+])
+dnl add two lrport
+AT_CHECK([ovn-nbctl lrport-add lr0 lrport0])
+AT_CHECK([ovn-nbctl lrport-add lr0 lrport1])
+dnl check lrport-list is correct
+AT_CHECK([ovn-nbctl lrport-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+<0> (lrport0)
+<1> (lrport1)
+])
+dnl delete lrport
+AT_CHECK([ovn-nbctl lrport-del lrport1])
+dnl verify deletion
+AT_CHECK([ovn-nbctl lrport-list lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+<0> (lrport0)
+])
+dnl check lrport mac is uninitialzed
+AT_CHECK([ovn-nbctl show lr0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+    lrouter <0> (lr0)
+        lrport lrport0
+            mac: ""
+])
+dnl set lrport mac
+AT_CHECK([ovn-nbctl lrport-set-mac-address lrport0 "aa:bb:cc:dd:ee:ff"])
+dnl get lrport mac
+AT_CHECK([ovn-nbctl lrport-get-mac-address lrport0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+aa:bb:cc:dd:ee:ff
+])
+dnl get lrport enabled state (default:true)
+AT_CHECK([ovn-nbctl lrport-get-enabled lrport0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+enabled
+])
+dnl disable admin state of lrport
+AT_CHECK([ovn-nbctl lrport-set-enabled lrport0 disabled])
+dnl verify lrport state
+AT_CHECK([ovn-nbctl lrport-get-enabled lrport0 | ${PERL} $srcdir/uuidfilt.pl], [0], [dnl
+disabled
+])
+
+OVN_NBCTL_TEST_STOP
+AT_CLEANUP
-- 
1.8.3.1




More information about the dev mailing list