diff mbox

[ovs-dev,5/8] ovn-nbctl: Add static route commands.

Message ID 1465456362-58140-6-git-send-email-jpettit@ovn.org
State Accepted
Headers show

Commit Message

Justin Pettit June 9, 2016, 7:12 a.m. UTC
Signed-off-by: Justin Pettit <jpettit@ovn.org>
---
 ovn/utilities/ovn-nbctl.8.xml |  26 +++++
 ovn/utilities/ovn-nbctl.c     | 214 +++++++++++++++++++++++++++++++++++++++++-
 tests/ovn-nbctl.at            |  78 +++++++++++++++
 tests/ovn.at                  |  41 ++------
 4 files changed, 325 insertions(+), 34 deletions(-)

Comments

Ryan Moats June 9, 2016, 3:37 p.m. UTC | #1
"dev" <dev-bounces@openvswitch.org> wrote on 06/09/2016 02:12:39 AM:

> From: Justin Pettit <jpettit@ovn.org>
> To: dev@openvswitch.org
> Date: 06/09/2016 02:14 AM
> Subject: [ovs-dev] [PATCH 5/8] ovn-nbctl: Add static route commands.
> Sent by: "dev" <dev-bounces@openvswitch.org>
>
> Signed-off-by: Justin Pettit <jpettit@ovn.org>
> ---

For some reason, parts 2-4 didn't make it through to my mail client.

I've looked at parts 2-5, made sure they apply cleanly and that make
check is happy, so this can be considered a bulk ack on parts 2, 3,
4, and 5 of this series.

Acked-by: Ryan Moats <rmoats@us.ibm.com>
diff mbox

Patch

diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml
index c085274..ba6a1ed 100644
--- a/ovn/utilities/ovn-nbctl.8.xml
+++ b/ovn/utilities/ovn-nbctl.8.xml
@@ -329,7 +329,33 @@ 
         Prints the administrative state of <var>port</var>, either
         <code>enabled</code> or <code>disabled</code>.
       </dd>
+    </dl>
+
+    <h1>Logical Route Commands</h1>
+
+    <dl>
+      <dt><code>lr-route-add</code> <var>router</var> <var>prefix</var> <var>nexthop</var> [<var>port</var>]</dt>
+      <dd>
+        Adds the specified route to <var>router</var>.  <var>prefix</var>
+        describes the IP prefix for this route.  <var>nexthop</var>
+        specifies the gateway to use for this route.  If <var>port</var>
+        is specified, packets that match this route will be sent out
+        that port.
+      </dd>
 
+      <dt><code>lr-route-del</code> <var>router</var> [<var>prefix</var>]</dt>
+      <dd>
+        Deletes routes from <var>router</var>.  If only
+        <var>router</var> is supplied, all the routes from the logical
+        router are deleted.  If <var>prefix</var> is also specified,
+        then all the routes that match the prefix will be deleted from
+        the logical router.
+      </dd>
+
+      <dt><code>lr-route-list</code> <var>router</var></dt>
+      <dd>
+        Lists the routes on <var>router</var>.
+      </dd>
     </dl>
 
     <h1>Database Commands</h1>
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
index 493f1e8..eeed70f 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -350,6 +350,13 @@  Logical router port commands:\n\
   lrp-get-enabled PORT      get administrative state PORT\n\
                             ('enabled' or 'disabled')\n\
 \n\
+Route commands:\n\
+  lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\
+                            add a route to ROUTER\n\
+  lr-route-del ROUTER [PREFIX]\n\
+                            remove routes from ROUTER\n\
+  lr-route-list ROUTER      print routes for ROUTER\n\
+\n\
 %s\
 \n\
 Options:\n\
@@ -1269,6 +1276,82 @@  nbctl_lr_list(struct ctl_context *ctx)
     free(nodes);
 }
 
+static void
+nbctl_lr_route_add(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_router *lr;
+    lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
+    unsigned int plen;
+    ovs_be32 ipv4;
+    char *error;
+
+    error = ip_parse_cidr(ctx->argv[2], &ipv4, &plen);
+    if (!error) {
+        if (!ip_parse(ctx->argv[3], &ipv4)) {
+            ctl_fatal("bad IPv4 nexthop argument: %s", ctx->argv[3]);
+        }
+    } else {
+        free(error);
+
+        struct in6_addr ipv6;
+        error = ipv6_parse_cidr(ctx->argv[2], &ipv6, &plen);
+        if (!error) {
+            if (!ipv6_parse(ctx->argv[3], &ipv6)) {
+                ctl_fatal("bad IPv6 nexthop argument: %s", ctx->argv[3]);
+            }
+        } else {
+            ctl_fatal("bad prefix argument: %s", error);
+        }
+    }
+
+    struct nbrec_logical_router_static_route *route;
+    route = nbrec_logical_router_static_route_insert(ctx->txn);
+    nbrec_logical_router_static_route_set_ip_prefix(route, ctx->argv[2]);
+    nbrec_logical_router_static_route_set_nexthop(route, ctx->argv[3]);
+    if (ctx->argc == 5) {
+        nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]);
+    }
+
+    nbrec_logical_router_verify_static_routes(lr);
+    struct nbrec_logical_router_static_route **new_routes
+        = xmalloc(sizeof *new_routes * (lr->n_static_routes + 1));
+    memcpy(new_routes, lr->static_routes,
+           sizeof *new_routes * lr->n_static_routes);
+    new_routes[lr->n_static_routes] = route;
+    nbrec_logical_router_set_static_routes(lr, new_routes,
+                                           lr->n_static_routes + 1);
+    free(new_routes);
+}
+
+static void
+nbctl_lr_route_del(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_router *lr;
+    lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+    if (ctx->argc == 2) {
+        /* If a prefix is not specified, delete all routes. */
+        nbrec_logical_router_verify_static_routes(lr);
+        nbrec_logical_router_set_static_routes(lr, NULL, 0);
+        return;
+    }
+
+    for (int i = 0; i < lr->n_static_routes; i++) {
+        if (!strcmp(lr->static_routes[i]->ip_prefix, ctx->argv[2])) {
+            struct nbrec_logical_router_static_route **new_routes
+                = xmemdup(lr->static_routes,
+                          sizeof *new_routes * lr->n_static_routes);
+
+            new_routes[i] = lr->static_routes[lr->n_static_routes - 1];
+            nbrec_logical_router_verify_static_routes(lr);
+            nbrec_logical_router_set_static_routes(lr, new_routes,
+                                                 lr->n_static_routes - 1);
+            free(new_routes);
+            return;
+        }
+    }
+}
+
 static const struct nbrec_logical_router_port *
 lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
 {
@@ -1358,9 +1441,9 @@  nbctl_lrp_add(struct ctl_context *ctx)
         ctl_fatal("%s: invalid mac address.", ctx->argv[3]);
     }
 
-    ovs_be32 ip;
+    ovs_be32 ipv4;
     unsigned int plen;
-    char *error = ip_parse_cidr(ctx->argv[4], &ip, &plen);
+    char *error = ip_parse_cidr(ctx->argv[4], &ipv4, &plen);
     if (error) {
         free(error);
         struct in6_addr ipv6;
@@ -1501,6 +1584,125 @@  nbctl_lrp_get_enabled(struct ctl_context *ctx)
                   *lrp->enabled ? "enabled" : "disabled");
 }
 
+struct ipv4_route {
+    int plen;
+    ovs_be32 addr;
+    const struct nbrec_logical_router_static_route *route;
+};
+
+static int
+ipv4_route_cmp(const void *route1_, const void *route2_)
+{
+    const struct ipv4_route *route1p = route1_;
+    const struct ipv4_route *route2p = route2_;
+
+    if (route1p->plen != route2p->plen) {
+        return route1p->plen > route2p->plen ? -1 : 1;
+    } else if (route1p->addr != route2p->addr) {
+        return route1p->addr < route2p->addr ? -1 : 1;
+    } else {
+        return 0;
+    }
+}
+
+struct ipv6_route {
+    int plen;
+    struct in6_addr addr;
+    const struct nbrec_logical_router_static_route *route;
+};
+
+static int
+ipv6_route_cmp(const void *route1_, const void *route2_)
+{
+    const struct ipv6_route *route1p = route1_;
+    const struct ipv6_route *route2p = route2_;
+
+    if (route1p->plen != route2p->plen) {
+        return route1p->plen > route2p->plen ? -1 : 1;
+    }
+    return memcmp(&route1p->addr, &route2p->addr, sizeof(route1p->addr));
+}
+
+static void
+nbctl_lr_route_list(struct ctl_context *ctx)
+{
+    const struct nbrec_logical_router *lr;
+    struct ipv4_route *ipv4_routes;
+    struct ipv6_route *ipv6_routes;
+    size_t n_ipv4_routes = 0;
+    size_t n_ipv6_routes = 0;
+
+    lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+    ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes);
+    ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes);
+
+    for (int i = 0; i < lr->n_static_routes; i++) {
+        const struct nbrec_logical_router_static_route *route
+            = lr->static_routes[i];
+        unsigned int plen;
+        ovs_be32 ipv4;
+        char *error;
+
+        error = ip_parse_cidr(route->ip_prefix, &ipv4, &plen);
+        if (!error) {
+            ipv4_routes[n_ipv4_routes].plen = plen;
+            ipv4_routes[n_ipv4_routes].addr = ipv4;
+            ipv4_routes[n_ipv4_routes].route = route;
+            n_ipv4_routes++;
+        } else {
+            free(error);
+
+            struct in6_addr ipv6;
+            if (!ipv6_parse_cidr(route->ip_prefix, &ipv6, &plen)) {
+                ipv6_routes[n_ipv6_routes].plen = plen;
+                ipv6_routes[n_ipv6_routes].addr = ipv6;
+                ipv6_routes[n_ipv6_routes].route = route;
+                n_ipv6_routes++;
+            } else {
+                /* Invalid prefix. */
+                free(error);
+                continue;
+            }
+        }
+    }
+
+    qsort(ipv4_routes, n_ipv4_routes, sizeof *ipv4_routes, ipv4_route_cmp);
+    qsort(ipv6_routes, n_ipv6_routes, sizeof *ipv6_routes, ipv6_route_cmp);
+
+    if (n_ipv4_routes) {
+        ds_put_cstr(&ctx->output, "IPv4 Routes\n");
+    }
+    for (int i = 0; i < n_ipv4_routes; i++) {
+        const struct nbrec_logical_router_static_route *route
+            = ipv4_routes[i].route;
+        ds_put_format(&ctx->output, "%25s %25s", route->ip_prefix,
+                      route->nexthop);
+        if (route->output_port) {
+            ds_put_format(&ctx->output, " %s", route->output_port);
+        }
+        ds_put_char(&ctx->output, '\n');
+    }
+
+    if (n_ipv6_routes) {
+        ds_put_format(&ctx->output, "%sIPv6 Routes\n",
+                      n_ipv4_routes ?  "\n" : "");
+    }
+    for (int i = 0; i < n_ipv6_routes; i++) {
+        const struct nbrec_logical_router_static_route *route
+            = ipv6_routes[i].route;
+        ds_put_format(&ctx->output, "%25s %25s", route->ip_prefix,
+                      route->nexthop);
+        if (route->output_port) {
+            ds_put_format(&ctx->output, " %s", route->output_port);
+        }
+        ds_put_char(&ctx->output, '\n');
+    }
+
+    free(ipv4_routes);
+    free(ipv6_routes);
+}
+
 static const struct ctl_table_class tables[] = {
     {&nbrec_table_logical_switch,
      {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
@@ -1796,6 +1998,14 @@  static const struct ctl_command_syntax nbctl_commands[] = {
     { "lrp-get-enabled", 1, 1, "PORT", NULL, nbctl_lrp_get_enabled,
       NULL, "", RO },
 
+    /* logical router route commands. */
+    { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", NULL,
+      nbctl_lr_route_add, NULL, "", RW },
+    { "lr-route-del", 1, 2, "ROUTER [PREFIX]", NULL, nbctl_lr_route_del,
+      NULL, "", RW },
+    { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL,
+      "", RO },
+
     {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
 };
 
diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
index 2e8fc17..73792b3 100644
--- a/tests/ovn-nbctl.at
+++ b/tests/ovn-nbctl.at
@@ -351,3 +351,81 @@  AT_CHECK([ovn-nbctl lrp-set-enabled lrp0 xyzzy], [1], [],
 
 OVN_NBCTL_TEST_STOP
 AT_CLEANUP
+
+dnl ---------------------------------------------------------------------
+
+AT_SETUP([ovn-nbctl - routes])
+OVN_NBCTL_TEST_START
+
+AT_CHECK([ovn-nbctl lr-add lr0])
+
+dnl Check IPv4 routes
+AT_CHECK([ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.1])
+AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0])
+AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.1])
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+              10.0.0.1/24                  11.0.0.1
+              10.0.1.1/24                  11.0.1.1 lp0
+                0.0.0.0/0               192.168.0.1
+])
+
+AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.1.1/24])
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+              10.0.0.1/24                  11.0.0.1
+                0.0.0.0/0               192.168.0.1
+])
+
+AT_CHECK([ovn-nbctl lr-route-del lr0])
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+])
+
+dnl Check IPv6 routes
+AT_CHECK([ovn-nbctl lr-route-add lr0 ::/0 2001:0db8:0:f101::1])
+AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 2001:0db8:0:f102::1 lp0])
+AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1])
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv6 Routes
+         2001:0db8:0::/64       2001:0db8:0:f102::1 lp0
+         2001:0db8:1::/64       2001:0db8:0:f103::1
+                     ::/0       2001:0db8:0:f101::1
+])
+
+AT_CHECK([ovn-nbctl lr-route-del lr0 2001:0db8:0::/64])
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv6 Routes
+         2001:0db8:1::/64       2001:0db8:0:f103::1
+                     ::/0       2001:0db8:0:f101::1
+])
+
+AT_CHECK([ovn-nbctl lr-route-del lr0])
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+])
+
+dnl Check IPv4 and IPv6 routes
+AT_CHECK([ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.1])
+AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0])
+AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.1])
+AT_CHECK([ovn-nbctl lr-route-add lr0 ::/0 2001:0db8:0:f101::1])
+AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 2001:0db8:0:f102::1 lp0])
+AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1])
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+              10.0.0.1/24                  11.0.0.1
+              10.0.1.1/24                  11.0.1.1 lp0
+                0.0.0.0/0               192.168.0.1
+
+IPv6 Routes
+         2001:0db8:0::/64       2001:0db8:0:f102::1 lp0
+         2001:0db8:1::/64       2001:0db8:0:f103::1
+                     ::/0       2001:0db8:0:f101::1
+])
+
+OVN_NBCTL_TEST_STOP
+AT_CLEANUP
diff --git a/tests/ovn.at b/tests/ovn.at
index 0b9d3d1..652f0a6 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -2384,17 +2384,9 @@  ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 20.0.0.1/24 R2_R1
 ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 20.0.0.2/24 R1_R2
 
 #install static routes
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=172.16.1.0/24 nexthop=20.0.0.2 -- add Logical_Router \
-R1 static_routes @lrt
-
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=172.16.2.0/24 nexthop=20.0.0.2 output_port=R1_R2 -- add Logical_Router \
-R1 static_routes @lrt
-
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=192.168.1.0/24 nexthop=20.0.0.1 -- add Logical_Router \
-R2 static_routes @lrt
+ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
+ovn-nbctl lr-route-add R2 172.16.2.0/24 20.0.0.2 R1_R2
+ovn-nbctl lr-route-add R2 192.168.1.0/24 20.0.0.1
 
 # Create logical port foo1 in foo
 ovn-nbctl lport-add foo foo1 \
@@ -2649,29 +2641,14 @@  ovn-nbctl lport-add join r3-join -- set Logical_port r3-join type=router \
     options:router-port=R3_join addresses='"00:00:04:01:02:05"'
 
 #install static routes
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=172.16.1.0/24 nexthop=20.0.0.2 -- add Logical_Router \
-R1 static_routes @lrt
+ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2
+ovn-nbctl lr-route-add R1 10.32.1.0/24 20.0.0.3
 
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=10.32.1.0/24 nexthop=20.0.0.3 -- add Logical_Router \
-R1 static_routes @lrt
+ovn-nbctl lr-route-add R2 192.168.1.0/24 20.0.0.1
+ovn-nbctl lr-route-add R2 10.32.1.0/24 20.0.0.3
 
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=192.168.1.0/24 nexthop=20.0.0.1 -- add Logical_Router \
-R2 static_routes @lrt
-
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=10.32.1.0/24 nexthop=20.0.0.3 -- add Logical_Router \
-R2 static_routes @lrt
-
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=192.168.1.0/24 nexthop=20.0.0.1 -- add Logical_Router \
-R3 static_routes @lrt
-
-ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
-ip_prefix=172.16.1.0/24 nexthop=20.0.0.2 -- add Logical_Router \
-R3 static_routes @lrt
+ovn-nbctl lr-route-add R3 192.168.1.0/24 20.0.0.1
+ovn-nbctl lr-route-add R3 172.16.1.0/24 20.0.0.2
 
 # Create logical port foo1 in foo
 ovn-nbctl lport-add foo foo1 \