Network function: network-function-add <nf-name> <inport> <outport> - Add a new NF network-function-del <nf-name-or-uuid> - Delete a NF network-function-list - List all NFs
Network function group: network-function-group-add <nfg-name> [<nf1> <nf2> ...] - Add a new NFG network-function-group-del <nfg-name-or-uuid> - Delete a NFG network-function-group-list [<nfg-name-or-uuid>] - List all NFGs network-function-group-add-network-function <nfg-name-or-uuid> <nf-name-or-uuid> - Add a NF to a NFG network-function-group-del-network-function <nfg-name-or-uuid> <nf-name-or-uuid> - Remove a NF from a NFG ACL (new optional parameter added for NFG): acl-add <ls>|<pg> <direction> <priority> <match> <action> [<nfg-name-or-uuid>] Acked-by: Naveen Yerramneni <naveen.yerramn...@nutanix.com> Signed-off-by: Sragdhara Datta Chaudhuri <sragdha.chau...@nutanix.com> --- utilities/ovn-nbctl.c | 533 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 530 insertions(+), 3 deletions(-) diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index e94658371..d6213ad25 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -281,7 +281,7 @@ Logical switch commands:\n\ \n\ ACL commands:\n\ [--type={switch | port-group}] [--log] [--severity=SEVERITY] [--name=NAME] [--may-exist]\n\ - acl-add {SWITCH | PORTGROUP} DIRECTION PRIORITY MATCH ACTION\n\ + acl-add {SWITCH | PORTGROUP} DIRECTION PRIORITY MATCH ACTION [NETWORK-FUNCTION-GROUP]\n\ add an ACL to SWITCH/PORTGROUP\n\ [--type={switch | port-group}]\n\ acl-del {SWITCH | PORTGROUP} [DIRECTION [PRIORITY MATCH]]\n\ @@ -362,6 +362,26 @@ Forwarding group commands:\n\ fwd-group-del GROUP delete a forwarding group\n\ fwd-group-list [SWITCH] print forwarding groups\n\ \n\ +Network function group commands:\n\ + network-function-group-add NETWORK-FUNCTION-GROUP [NETWORK-FUNCTION]...\n\ + create a network-functionr-group\n\ + network-function-group-del NETWORK-FUNCTION-GROUP\n\ + delete a network-function-group\n\ + network-function-group-list print all network-function-groups\n\ + network-function-group-add-network-function NETWORK-FUNCTION-GROUP NETWORK-FUNCTION\n\ + add a network-function to a\n\ + network-function-group\n\ + network-function-group-del-network-function NETWORK-FUNCTION-GROUP NETWORK-FUNCTION\n\ + delete a network-function from a\n\ + network-function-group\n\ +\n\ +Network function commands:\n\ + network-function-add NETWORK-FUNCTION PORT-IN PORT-OUT\n\ + create a network-function\n\ + network-function-del NETWORK-FUNCTION delete a network-function\n\ + network-function-list print all network-functions\n\ +\n\n",program_name, program_name); + printf("\ Logical router commands:\n\ lr-add [ROUTER] create a logical router named ROUTER\n\ lr-del ROUTER delete ROUTER and all its ports\n\ @@ -418,7 +438,7 @@ Policy commands:\n\ lr-policy-del ROUTER [{PRIORITY | UUID} [MATCH]]\n\ remove policies from ROUTER\n\ lr-policy-list ROUTER print policies for ROUTER\n\ -\n\n",program_name, program_name); +\n\n"); printf("\ NAT commands:\n\ [--stateless]\n\ @@ -2123,6 +2143,462 @@ nbctl_lsp_get_ls(struct ctl_context *ctx) } } + +static char * OVS_WARN_UNUSED_RESULT +nf_group_by_name_or_uuid( + struct ctl_context *ctx, const char *id, + const bool must_exist, + const struct nbrec_network_function_group **nf_group_p) +{ + const struct nbrec_network_function_group *nf_group = NULL; + struct uuid nf_group_uuid; + bool is_uuid = uuid_from_string(&nf_group_uuid, id); + + *nf_group_p = NULL; + if (is_uuid) { + nf_group = nbrec_network_function_group_get_for_uuid(ctx->idl, + &nf_group_uuid); + } + + if (!nf_group) { + const struct nbrec_network_function_group *iter; + NBREC_NETWORK_FUNCTION_GROUP_FOR_EACH (iter, ctx->idl) { + if (strcmp(iter->name, id)) { + continue; + } + if (nf_group) { + return xasprintf("Multiple network function group named '%s'. " + "Use a UUID.", id); + } + nf_group = iter; + } + } + if (!nf_group && must_exist) { + return xasprintf("%s: network function group %s not found", id, + is_uuid ? "UUID" : "name"); + } + + *nf_group_p = nf_group; + return NULL; +} + +static char * OVS_WARN_UNUSED_RESULT +nf_by_name_or_uuid( + struct ctl_context *ctx, const char *id, + bool must_exist, const struct nbrec_network_function **nf_p) +{ + const struct nbrec_network_function *nf = NULL; + struct uuid nf_uuid; + bool is_uuid = uuid_from_string(&nf_uuid, id); + + *nf_p = NULL; + if (is_uuid) { + nf = nbrec_network_function_get_for_uuid(ctx->idl, &nf_uuid); + } + + if (!nf) { + const struct nbrec_network_function *iter; + NBREC_NETWORK_FUNCTION_FOR_EACH (iter, ctx->idl) { + if (strcmp(iter->name, id)) { + continue; + } + if (nf) { + return xasprintf("Multiple network functions named '%s'. " + "Use a UUID.", id); + } + nf = iter; + } + } + if (!nf && must_exist) { + return xasprintf("%s: network function %s not found", id, + is_uuid ? "UUID" : "name"); + } + + *nf_p = nf; + return NULL; +} + +/* + * Network Function Groups CLI Functions + */ +static void +nbctl_pre_nf_group_add(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_group_col_name); + ovsdb_idl_add_column( + ctx->idl, &nbrec_network_function_group_col_network_function); +} + +static char * +set_network_function_in_network_function_group( + struct ctl_context *ctx, + const struct nbrec_network_function_group *nf_group, + char **new_network_function, size_t num_new_network_function) +{ + struct nbrec_network_function **nfs; + nfs = xmalloc(sizeof *nfs * num_new_network_function); + + size_t i; + char *error = NULL; + for (i = 0; i < num_new_network_function; i++) { + const struct nbrec_network_function *nf; + error = nf_by_name_or_uuid(ctx, new_network_function[i], true, &nf); + if (error) { + free(nfs); + return error; + } + nfs[i] = (struct nbrec_network_function *) nf; + } + nbrec_network_function_group_set_network_function( + nf_group, nfs, num_new_network_function); + free(nfs); + return error; +} + +static void +nbctl_nf_group_add(struct ctl_context *ctx) +{ + const struct nbrec_network_function_group *nf_group; + const char *nfg_name = ctx->argv[1]; + + const bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + const bool add_duplicate = shash_find(&ctx->options, + "--add-duplicate") != NULL; + + if (!add_duplicate) { + NBREC_NETWORK_FUNCTION_GROUP_FOR_EACH (nf_group, ctx->idl) { + if (!strcmp(nf_group->name, nfg_name)) { + if (may_exist) { + return; + } + ctl_error(ctx, "%s: a network-function-group with this name " + "already exists", nfg_name); + return; + } + } + } + + nf_group = nbrec_network_function_group_insert(ctx->txn); + nbrec_network_function_group_set_name(nf_group, nfg_name); + nbrec_network_function_group_set_mode(nf_group, "inline"); + + if (ctx->argc > 2) { + ctx->error = set_network_function_in_network_function_group( + ctx, nf_group, ctx->argv + 2, ctx->argc - 2); + } +} + +static void +nbctl_pre_nf_group_del(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_group_col_name); +} + +static void +nbctl_nf_group_del(struct ctl_context *ctx) +{ + const struct nbrec_network_function_group *nf_group; + const bool must_exist = !shash_find(&ctx->options, "--if-exists"); + + char *error = nf_group_by_name_or_uuid( + ctx, ctx->argv[1], must_exist, &nf_group); + if (error) { + ctx->error = error; + return; + } + if (!nf_group) { + return; + } + + nbrec_network_function_group_delete(nf_group); +} + +static void +nbctl_pre_nf_group_list(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, + &nbrec_network_function_group_col_network_function); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_group_col_name); +} + +static void +nbctl_nf_group_list(struct ctl_context *ctx) +{ + const struct nbrec_network_function_group *nf_group; + struct smap nf_groups; + size_t i; + + smap_init(&nf_groups); + + NBREC_NETWORK_FUNCTION_GROUP_FOR_EACH (nf_group, ctx->idl) { + smap_add_format(&nf_groups, nf_group->name, + UUID_FMT " (%s)", + UUID_ARGS(&nf_group->header_.uuid), + nf_group->name); + } + const struct smap_node **nodes = smap_sort(&nf_groups); + for (i = 0; i < smap_count(&nf_groups); i++) { + const struct smap_node *node = nodes[i]; + ds_put_format(&ctx->output, "%s\n", node->value); + } + smap_destroy(&nf_groups); + free(nodes); +} + +static void +nbctl_pre_nf_group_add_network_function(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, + &nbrec_network_function_group_col_network_function); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_group_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name); +} + +static void +nbctl_nf_group_add_network_function(struct ctl_context *ctx) +{ + const struct nbrec_network_function_group *nf_group; + const struct nbrec_network_function *nf; + const bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + + char * error = nf_group_by_name_or_uuid(ctx, ctx->argv[1], true, + &nf_group); + if (error) { + ctx->error = error; + return; + } + if (!nf_group) { + return; + } + + /* Check that network-function exists */ + error = nf_by_name_or_uuid(ctx, ctx->argv[2], true, &nf); + if (error) { + ctx->error = error; + return; + } + + /* Do not add network_function more than once in a given + * network-function-group */ + for (size_t i = 0; i < nf_group->n_network_function; i++) { + if (nf_group->network_function[i] == nf) { + if (!may_exist) { + ctl_error(ctx, "network-function %s is already added to " + "network-function-group %s", + ctx->argv[2], ctx->argv[1]); + return; + } + return; + } + } + + /* Insert the logical network-function into the logical + * network-function-group. */ + nbrec_network_function_group_verify_network_function(nf_group); + struct nbrec_network_function **new_network_function = + xmalloc(sizeof *new_network_function + * (nf_group->n_network_function + 1)); + memcpy(new_network_function, nf_group->network_function, + sizeof *new_network_function * nf_group->n_network_function); + new_network_function[nf_group->n_network_function] = + CONST_CAST(struct nbrec_network_function *, nf); + nbrec_network_function_group_set_network_function(nf_group, + new_network_function, nf_group->n_network_function + 1); + free(new_network_function); +} + +static void +remove_nf_from_network_function_group( + const struct nbrec_network_function_group *nf_group, size_t idx) +{ + + struct nbrec_network_function **new_network_function + = xmemdup(nf_group->network_function, sizeof *new_network_function * + nf_group->n_network_function); + new_network_function[idx] + = new_network_function[nf_group->n_network_function - 1]; + nbrec_network_function_group_verify_network_function(nf_group); + nbrec_network_function_group_set_network_function( + nf_group, new_network_function, + nf_group->n_network_function - 1); + free(new_network_function); +} + +static void +nbctl_pre_nf_group_del_network_function(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, + &nbrec_network_function_group_col_network_function); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_group_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name); +} + +static void +nbctl_nf_group_del_network_function(struct ctl_context *ctx) +{ + const struct nbrec_network_function *nf; + const struct nbrec_network_function_group *nf_group; + const bool must_exist = !shash_find(&ctx->options, "--if-exists"); + + + char * error = nf_group_by_name_or_uuid(ctx, ctx->argv[1], must_exist, + &nf_group); + if (error) { + ctx->error = error; + return; + } + if (!nf_group) { + return; + } + + error = nf_by_name_or_uuid(ctx, ctx->argv[2], must_exist, &nf); + if (error) { + ctx->error = error; + return; + } + /* Find the network-function_group that contains 'network-function', + * then delete it. */ + + for (size_t i = 0; i < nf_group->n_network_function; i++) { + if (nf_group->network_function[i] == nf) { + remove_nf_from_network_function_group(nf_group,i); + return; + } + } + if (must_exist) { + ctl_error(ctx, "network-function %s is not part of any logical switch", + ctx->argv[1]); + return; + } +} +/* End of network-function-group operations */ + +/* + * network-function operations + */ +static void +nbctl_pre_nf_add(struct ctl_context *ctx) +{ + nbctl_pre_context(ctx); + + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_inport); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_outport); +} + +static void +nbctl_nf_add(struct ctl_context *ctx) +{ + const struct nbrec_logical_switch_port *lsp_in, *lsp_out; + const struct nbrec_network_function *nf; + + const bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + const bool add_duplicate = shash_find(&ctx->options, + "--add-duplicate") != NULL; + if (may_exist && add_duplicate) { + ctl_error(ctx, + "--may-exist and --add-duplicate may not be used together"); + return; + } + + char * error = lsp_by_name_or_uuid(ctx, ctx->argv[2], true, &lsp_in); + if (error) { + ctx->error = error; + return; + } + error = lsp_by_name_or_uuid(ctx, ctx->argv[3], true, &lsp_out); + if (error) { + ctx->error = error; + return; + } + + const char *nf_name = ctx->argv[1]; + + if (!add_duplicate) { + NBREC_NETWORK_FUNCTION_FOR_EACH (nf, ctx->idl) { + if (!strcmp(nf->name, nf_name)) { + if (may_exist) { + return; + } + ctl_error(ctx, "%s: same name network-function already exists", + nf_name); + return; + } + } + } + + /* create the logical network-function. */ + nf = nbrec_network_function_insert(ctx->txn); + nbrec_network_function_set_inport(nf, lsp_in); + nbrec_network_function_set_outport(nf, lsp_out); + nbrec_network_function_set_name(nf, nf_name); +} + +static void +nbctl_pre_nf_del(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name); +} + +static void +nbctl_nf_del(struct ctl_context *ctx) +{ + const struct nbrec_network_function *nf; + const bool must_exist = !shash_find(&ctx->options, "--if-exists"); + + char *error = nf_by_name_or_uuid(ctx, ctx->argv[1], must_exist, &nf); + if (error) { + ctx->error = error; + return; + } + if (!nf) { + return; + } + nbrec_network_function_delete(nf); +} + +static void +nbctl_pre_nf_list(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_inport); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_outport); + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name); +} + +static void +nbctl_nf_list(struct ctl_context *ctx) +{ + const struct nbrec_network_function *nf; + struct smap nfs; + size_t i; + + smap_init(&nfs); + + NBREC_NETWORK_FUNCTION_FOR_EACH (nf, ctx->idl) { + const struct nbrec_logical_switch_port *linport = nf->inport; + const struct nbrec_logical_switch_port *loutport = nf->outport; + const char *linport_name = linport ? linport->name : "<not_set>"; + const char *loutport_name = loutport ? loutport->name : "<not_set>"; + smap_add_format(&nfs, nf->name, + UUID_FMT " (%s) in:%s out:%s", + UUID_ARGS(&nf->header_.uuid), + nf->name, linport_name, loutport_name); + } + const struct smap_node **nodes = smap_sort(&nfs); + for (i = 0; i < smap_count(&nfs); i++) { + const struct smap_node *node = nodes[i]; + ds_put_format(&ctx->output, "%s\n", node->value); + } + smap_destroy(&nfs); + free(nodes); +} + +/* End of network-function operations */ + + enum { DIR_FROM_LPORT, DIR_TO_LPORT @@ -2240,6 +2716,10 @@ nbctl_acl_list(struct ctl_context *ctx) ds_put_format(&ctx->output, "%10s %5"PRId64" (%s) %s", acl->direction, acl->priority, acl->match, acl->action); + if (acl->network_function_group) { + ds_put_format(&ctx->output, " network-function-group=%s", + acl->network_function_group->name); + } if (acl->log) { ds_put_cstr(&ctx->output, " log("); if (acl->name) { @@ -2350,6 +2830,8 @@ nbctl_pre_acl(struct ctl_context *ctx) ovsdb_idl_add_table(ctx->idl, &nbrec_table_sample_collector); ovsdb_idl_add_table(ctx->idl, &nbrec_table_sample); + ovsdb_idl_add_column(ctx->idl, &nbrec_acl_col_network_function_group); + ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_group_col_name); } static void @@ -2406,10 +2888,21 @@ nbctl_acl_add(struct ctl_context *ctx) /* Create the acl. */ struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn); + const struct nbrec_network_function_group *network_function_group = NULL; 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->argv[6]) && strcmp(ctx->argv[6], "--")) { + error = nf_group_by_name_or_uuid(ctx, ctx->argv[6], true, + &network_function_group); + if (error) { + ctx->error = error; + return; + } + + nbrec_acl_set_network_function_group(acl, network_function_group); + } /* Logging options. */ bool log = shash_find(&ctx->options, "--log") != NULL; @@ -8024,7 +8517,8 @@ static const struct ctl_command_syntax nbctl_commands[] = { { "ls-list", 0, 0, "", nbctl_pre_ls_list, nbctl_ls_list, NULL, "", RO }, /* acl commands. */ - { "acl-add", 5, 6, "{SWITCH | PORTGROUP} DIRECTION PRIORITY MATCH ACTION", + { "acl-add", 5, 7, + "{SWITCH | PORTGROUP} DIRECTION PRIORITY MATCH ACTION [NETWORK-FUNCTION-GROUP]", nbctl_pre_acl, nbctl_acl_add, NULL, "--log,--may-exist,--type=,--name=,--severity=,--meter=,--label=," "--apply-after-lb,--tier=,--sample-new=,--sample-est=", RW }, @@ -8110,6 +8604,39 @@ static const struct ctl_command_syntax nbctl_commands[] = { { "lsp-detach-mirror", 2, 2, "PORT MIRROR", nbctl_pre_lsp_mirror, nbctl_lsp_detach_mirror, NULL, "", RW }, + /* network-function-group commands. */ + { "network-function-group-add", 1, INT_MAX, + "NETWORK-FUNCTION-GROUP [NETWORK-FUNCTION]", + nbctl_pre_nf_group_add, + nbctl_nf_group_add, NULL, "--may-exist,--add-duplicate", RW }, + { "network-function-group-del", 1, 1, "NETWORK-FUNCTION-GROUP", + nbctl_pre_nf_group_del, + nbctl_nf_group_del, + NULL, "--if-exists", RW }, + { "network-function-group-list", 0, 1, "[NETWORK-FUNCTION-GROUP]", + nbctl_pre_nf_group_list, + nbctl_nf_group_list, + NULL, "", RO }, + { "network-function-group-add-network-function", 2, 2, + "NETWORK-FUNCTION-GROUP NETWORK-FUNCTION", + nbctl_pre_nf_group_add_network_function, + nbctl_nf_group_add_network_function, NULL, "--may-exist", RW }, + { "network-function-group-del-network-function", 2, 2, + "NETWORK-FUNCTION-GROUP NETWORK-FUNCTION", + nbctl_pre_nf_group_del_network_function, + nbctl_nf_group_del_network_function, NULL, "--if-exists", RW }, + + /* network-function commands. */ + { "network-function-add", 3, 3, "NETWORK-FUNCTION, PORT-IN, PORT-OUT", + nbctl_pre_nf_add, + nbctl_nf_add, + NULL, "--may-exist,--add-duplicate", RW }, + { "network-function-del", 1, 1, "NETWORK-FUNCTION", nbctl_pre_nf_del, + nbctl_nf_del, + NULL, "--if-exists", RW }, + { "network-function-list", 0, 0, "", nbctl_pre_nf_list, + nbctl_nf_list, NULL, "", RO }, + /* forwarding group commands. */ { "fwd-group-add", 4, INT_MAX, "SWITCH GROUP VIP VMAC PORT...", nbctl_pre_fwd_group_add, nbctl_fwd_group_add, NULL, "--liveness", RW }, -- 2.39.3 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev