Signed-off-by: Justin Pettit <jpet...@nicira.com> --- ovn/utilities/ovn-nbctl.8.xml | 28 +++++ ovn/utilities/ovn-nbctl.c | 242 +++++++++++++++++++++++++++++++++++++++++ tests/ovn-nbctl.at | 49 ++++++++ 3 files changed, 319 insertions(+), 0 deletions(-)
diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index ba3cc82..1555b02 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -66,6 +66,34 @@ </dd> </dl> + <h1>ACL Commands</h1> + <dl> + <dt><code>acl-add</code> <var>lswitch</var> <var>direction</var> <var>priority</var> <var>match</var> <var>action</var> [<code>log</code>]</dt> + <dd> + Adds the specified ACL to <var>lswitch</var>. + <var>direction</var> must be either <code>from-lport</code> or + <code>to-lport</code>. <var>priority</var> must be between + <code>1</code> and <code>65534</code>, inclusive. If + <code>log</code> is supplied, packet logging is enabled for the + ACL. A full description of the fields are in <code>ovn-nb</code>(5). + </dd> + + <dt><code>acl-del</code> <var>lswitch</var> [<var>direction</var> [<var>priority</var> <var>match</var>]]</dt> + <dd> + Deletes ACLs from <var>lswitch</var>. If only + <var>lswitch</var> is supplied, all the ACLs from the logical + switch are deleted. If <var>direction</var> is also specified, + then all the flows in that direction will be deleted from the + logical switch. If all the fields are given, then a single flow + that matches all the fields will be deleted. + </dd> + + <dt><code>acl-list</code> <var>lswitch</var></dt> + <dd> + Lists the ACLs on <var>lswitch</var>. + </dd> + </dl> + <h1>Logical Port Commands</h1> <dl> <dt><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 d095df1..0b19521 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -63,6 +63,13 @@ Logical switch commands:\n\ lswitch-get-external-id LSWITCH [KEY]\n\ list one or all external-ids on LSWITCH\n\ \n\ +ACL commands:\n\ + acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\ + add an ACL to LSWITCH\n\ + acl-del LSWITCH [DIRECTION [PRIORITY MATCH]]\n\ + remove ACLs from LSWITCH\n\ + acl-list LSWITCH print ACLs for LSWITCH\n\ +\n\ Logical port commands:\n\ lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\ lport-add LSWITCH LPORT PARENT TAG\n\ @@ -747,6 +754,220 @@ do_lport_get_options(struct ovs_cmdl_context *ctx) printf("%s=%s\n", node->key, node->value); } } + +enum { + DIR_FROM_LPORT, + DIR_TO_LPORT +}; + +static int +dir_encode(const char *dir) +{ + if (!strcmp(dir, "from-lport")) { + return DIR_FROM_LPORT; + } else if (!strcmp(dir, "to-lport")) { + return DIR_TO_LPORT; + } + + OVS_NOT_REACHED(); +} + +static int +acl_cmp(const void *acl1_, const void *acl2_) +{ + const struct nbrec_acl *acl1, *acl2; + + acl1 = *((struct nbrec_acl **) acl1_); + acl2 = *((struct nbrec_acl **) acl2_); + + int dir1 = dir_encode(acl1->direction); + int dir2 = dir_encode(acl2->direction); + +#define CMP(expr) \ + do { \ + int res; \ + res = (expr); \ + if (res) { \ + return res; \ + } \ + } while (0) + + CMP(dir1 - dir2); + CMP(acl1->priority > acl2->priority ? -1 : + (acl1->priority < acl2->priority ? 1 : 0)); + CMP(strcmp(acl1->match, acl2->match)); + +#undef CMP + + return 0; +} + +static void +do_acl_list(struct ovs_cmdl_context *ctx) +{ + const struct nbrec_logical_switch *lswitch; + struct nbctl_context *nb_ctx = ctx->pvt; + const struct nbrec_acl **acls; + size_t i; + + lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); + if (!lswitch) { + return; + } + + acls = xmalloc(sizeof *acls * lswitch->n_acls); + for (i = 0; i < lswitch->n_acls; i++) { + acls[i] = lswitch->acls[i]; + } + + qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp); + + for (i = 0; i < lswitch->n_acls; i++) { + const struct nbrec_acl *acl = acls[i]; + printf("%10s %5ld (%s) %s%s\n", acl->direction, acl->priority, + acl->match, acl->action, acl->log ? " log" : ""); + } + + free(acls); +} + +static void +do_acl_add(struct ovs_cmdl_context *ctx) +{ + const struct nbrec_logical_switch *lswitch; + struct nbctl_context *nb_ctx = ctx->pvt; + const char *action = ctx->argv[5]; + const char *direction; + int64_t priority; + + lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); + if (!lswitch) { + return; + } + + /* Validate direction. Only require the first letter. */ + if (ctx->argv[2][0] == 't') { + direction = "to-lport"; + } else if (ctx->argv[2][0] == 'f') { + direction = "from-lport"; + } else { + VLOG_WARN("Invalid direction '%s'", ctx->argv[2]); + return; + } + + /* Validate priority. */ + if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1 + || priority > 65535) { + VLOG_WARN("Invalid priority '%s'", ctx->argv[3]); + return; + } + + /* Validate action. */ + if (strcmp(action, "allow") && strcmp(action, "allow-related") + && strcmp(action, "drop") && strcmp(action, "reject")) { + VLOG_WARN("Invalid action '%s'", action); + return; + } + + /* Create the acl. */ + struct nbrec_acl *acl = nbrec_acl_insert(nb_ctx->txn); + nbrec_acl_set_priority(acl, priority); + nbrec_acl_set_direction(acl, direction); + nbrec_acl_set_match(acl, ctx->argv[4]); + nbrec_acl_set_action(acl, action); + if (ctx->argc == 7 && ctx->argv[6][0] == 'l') { + nbrec_acl_set_log(acl, true); + } + + /* Insert the acl into the logical switch. */ + nbrec_logical_switch_verify_acls(lswitch); + struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * + (lswitch->n_acls + 1)); + memcpy(new_acls, lswitch->acls, sizeof *new_acls * lswitch->n_acls); + new_acls[lswitch->n_acls] = acl; + nbrec_logical_switch_set_acls(lswitch, new_acls, lswitch->n_acls + 1); + free(new_acls); +} + +static void +do_acl_del(struct ovs_cmdl_context *ctx) +{ + const struct nbrec_logical_switch *lswitch; + struct nbctl_context *nb_ctx = ctx->pvt; + const char *direction; + int64_t priority = 0; + + lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); + if (!lswitch) { + return; + } + + if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) { + VLOG_WARN("Invalid number of arguments"); + return; + } + + if (ctx->argc == 2) { + /* If direction, priority, and match are not specified, delete + * all ACLs. */ + nbrec_logical_switch_verify_acls(lswitch); + nbrec_logical_switch_set_acls(lswitch, NULL, 0); + return; + } + + /* Validate direction. Only require first letter. */ + if (ctx->argv[2][0] == 't') { + direction = "to-lport"; + } else if (ctx->argv[2][0] == 'f') { + direction = "from-lport"; + } else { + VLOG_WARN("Invalid direction '%s'", ctx->argv[2]); + return; + } + + /* If priority and match are not specified, delete all ACLs with the + * specified direction. */ + if (ctx->argc == 3) { + struct nbrec_acl **new_acls + = xmalloc(sizeof *new_acls * lswitch->n_acls); + + int n_acls = 0; + for (size_t i = 0; i < lswitch->n_acls; i++) { + if (strcmp(direction, lswitch->acls[i]->direction)) { + new_acls[n_acls++] = lswitch->acls[i]; + } + } + + nbrec_logical_switch_verify_acls(lswitch); + nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls); + free(new_acls); + return; + } + + /* Validate priority. */ + if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1 + || priority > 65535) { + VLOG_WARN("Invalid priority '%s'", ctx->argv[3]); + return; + } + + /* Remove the matching rule. */ + for (size_t i = 0; i < lswitch->n_acls; i++) { + struct nbrec_acl *acl = lswitch->acls[i]; + + if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) && + !strcmp(direction, acl->direction)) { + struct nbrec_acl **new_acls + = xmemdup(lswitch->acls, sizeof *new_acls * lswitch->n_acls); + new_acls[i] = lswitch->acls[lswitch->n_acls - 1]; + nbrec_logical_switch_verify_acls(lswitch); + nbrec_logical_switch_set_acls(lswitch, new_acls, + lswitch->n_acls - 1); + free(new_acls); + return; + } + } +} static void parse_options(int argc, char *argv[]) @@ -849,6 +1070,27 @@ static const struct ovs_cmdl_command all_commands[] = { .handler = do_lswitch_get_external_id, }, { + .name = "acl-add", + .usage = "LSWITCH DIRECTION PRIORITY MATCH ACTION [log]", + .min_args = 5, + .max_args = 6, + .handler = do_acl_add, + }, + { + .name = "acl-del", + .usage = "LSWITCH [DIRECTION [PRIORITY MATCH]]", + .min_args = 1, + .max_args = 4, + .handler = do_acl_del, + }, + { + .name = "acl-list", + .usage = "LSWITCH", + .min_args = 1, + .max_args = 1, + .handler = do_acl_list, + }, + { .name = "lport-add", .usage = "LSWITCH LPORT [PARENT] [TAG]", .min_args = 2, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 8729ec0..fd9fce8 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -117,3 +117,52 @@ AT_CHECK([ovn-nbctl lport-get-port-security lp0], [0], [dnl OVN_NBCTL_TEST_STOP AT_CLEANUP + +dnl --------------------------------------------------------------------- + +AT_SETUP([ovn-nbctl - ACLs]) +OVN_NBCTL_TEST_START + +AT_CHECK([ovn-nbctl lswitch-add ls0]) +AT_CHECK([ovn-nbctl acl-add ls0 from-lport 600 udp drop log]) +AT_CHECK([ovn-nbctl acl-add ls0 to-lport 500 udp drop log]) +AT_CHECK([ovn-nbctl acl-add ls0 from-lport 400 tcp drop]) +AT_CHECK([ovn-nbctl acl-add ls0 to-lport 300 tcp drop]) +AT_CHECK([ovn-nbctl acl-add ls0 from-lport 200 ip drop]) +AT_CHECK([ovn-nbctl acl-add ls0 to-lport 100 ip drop]) + +AT_CHECK([ovn-nbctl acl-list ls0], [0], [dnl +from-lport 600 (udp) drop log +from-lport 400 (tcp) drop +from-lport 200 (ip) drop + to-lport 500 (udp) drop log + to-lport 300 (tcp) drop + to-lport 100 (ip) drop +]) + +dnl Delete in one direction. +AT_CHECK([ovn-nbctl acl-del ls0 to-lport]) +AT_CHECK([ovn-nbctl acl-list ls0], [0], [dnl +from-lport 600 (udp) drop log +from-lport 400 (tcp) drop +from-lport 200 (ip) drop +]) + +dnl Delete all ACLs. +AT_CHECK([ovn-nbctl acl-del ls0]) +AT_CHECK([ovn-nbctl acl-list ls0], [0], [dnl +]) + +AT_CHECK([ovn-nbctl acl-add ls0 from-lport 600 udp drop]) +AT_CHECK([ovn-nbctl acl-add ls0 from-lport 400 tcp drop]) +AT_CHECK([ovn-nbctl acl-add ls0 from-lport 200 ip drop]) + +dnl Delete a single flow. +AT_CHECK([ovn-nbctl acl-del ls0 from-lport 400 tcp]) +AT_CHECK([ovn-nbctl acl-list ls0], [0], [dnl +from-lport 600 (udp) drop +from-lport 200 (ip) drop +]) + +OVN_NBCTL_TEST_STOP +AT_CLEANUP -- 1.7.5.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev