[ovs-dev] [RFC PATCH 5/5] added code and documentation to extend ovn-nbctl for port-chain, port-pair-groups, port-pairs and ACL SFC action
John McDowall
jmcdowall at paloaltonetworks.com
Tue Dec 27 22:11:46 UTC 2016
These changes provide the necessary CLI support in ovn-nbctl to control the SFC.
There are new commands for port-chain, port-pair-groups, port-pairs and extensions
to ACLs to added a new action 'sfc'.
Co-authored-by: Flavio Fernandes <flavio at flaviof.com>
Reported at: https://mail.openvswitch.org/pipermail/ovs-discuss/2016-March/040381.html
Reported at: https://mail.openvswitch.org/pipermail/ovs-discuss/2016-May/041359.html
Signed-off-by: John McDowall <jmcdowall at paloaltonetworks.com>
---
ovn/ovn-nb.xml | 150 +++-
ovn/utilities/ovn-nbctl.c | 1935 +++++++++++++++++++++++++++++++++++++++++----
2 files changed, 1943 insertions(+), 142 deletions(-)
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index a3dc916a5..5a85e4ea7 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -120,7 +120,23 @@
logical port.
</p>
</column>
-
+ <column name="port_chains">
+ <p>
+ The logical port-chains connected to the logical switch.
+ </p>
+ <p>
+ It is an error for multiple logical switches to include the same
+ logical port.
+ </p>
+ </column>
+ <column name="port_pairs">
+ <p>
+ The logical chains that define the service path.
+ </p>
+ <p>
+ Logical chains cannot currently cross logical switch boundaries.
+ </p>
+ </column>
<column name="load_balancer">
Load balance a virtual ipv4 address to a set of logical port endpoint
ipv4 addresses.
@@ -155,7 +171,98 @@
</column>
</group>
</table>
+ <table name="Logical_Port_Chain" title="Logical port chain">
+ <p>
+ Each row represents one logical port chain
+ </p>
+
+ <column name="name">
+ <p>
+ A name for the logical chain. This name has no special meaning or purpose
+ other than to provide convenience for human interaction with the ovn-nb
+ database. There is no requirement for the name to be unique. The
+ logical chains's UUID should be used as the unique identifier.
+ </p>
+ </column>
+
+ <column name="port_pair_groups">
+ <p>
+ The logical list of port pairs that the flow goes through.
+ </p>
+
+ <p>
+ It is an error for a port pair group to be empty.
+ </p>
+ </column>
+ <column name="last_hop_port">
+ The <ref table="Logical_Switch_Port"/> to be used once packet reaches the end
+ of the chain.
+ </column>
+ <group title="Common Columns">
+ <column name="external_ids">
+ See <em>External IDs</em> at the beginning of this document.
+ </column>
+ </group>
+ </table>
+ <table name="Logical_Port_Pair_Group" title="logical port pair groups">
+ <p>
+ An ordered port pair list
+ </p>
+
+ <column name="name">
+ <p>
+ Logical port pair group name
+ </p>
+ </column>
+
+ <column name="port_pairs">
+ <p>
+ port pair for this group
+ </p>
+ </column>
+
+ <column name="sortkey">
+ <p>
+ An integer used for ordering instances of <ref table="Logical_Port_Pair_Group"/>
+ in the <ref column="port_pairs" table="Logical_Port_Chain"/> column
+ of <ref table="Logical_Port_Chain"/>.
+ </p>
+ </column>
+ <group title="Common Columns">
+ <column name="external_ids">
+ See <em>External IDs</em> at the beginning of this document.
+ </column>
+ </group>
+ </table>
+
+ <table name="Logical_Port_Pair" title="logical port pairs">
+ <p>
+ Ports pairs defining the service
+ </p>
+ <column name="name">
+ <p>
+ Logical port pair
+ </p>
+ </column>
+
+ <column name="outport">
+ <p>
+ Out logical port for this port pair. Can be the same value as inport.
+ </p>
+ </column>
+
+ <column name="inport">
+ <p>
+ In logical port for this port pair.
+ </p>
+ </column>
+ <group title="Common Columns">
+ <column name="external_ids">
+ See <em>External IDs</em> at the beginning of this document.
+ </column>
+ </group>
+ </table>
<table name="Logical_Switch_Port" title="L2 logical switch port">
<p>
A port within an L2 logical switch.
@@ -853,6 +960,13 @@
ICMP unreachable message for other IP-based protocols.
<code>Not implemented--currently treated as drop</code>
</li>
+
+ <li>
+ <code>sfc</code>: Forward the packet into a logical port chain.
+ The chain to be used -- as well as any other attributes that determine
+ the behavior of the packet while in the chain -- are provided
+ via <ref column="options"/>.
+ </li>
</ul>
</column>
@@ -868,6 +982,40 @@
</p>
</column>
+ <group title="Options">
+ <column name = "options">
+ This column provides key/value settings specific to the ACL
+ <ref column="action"/>. The type-specific options are described
+ individually below.
+ </column>
+
+ <group title="Options for action sfc">
+ <p>
+ These options apply when <ref column="action"/> is <code>sfc</code>.
+ </p>
+
+ <column name="options" key="sfc-port-chain">
+ Required when <ref column="action"/> is <code>sfc</code>.
+ The uuid (or name) of the <ref table="Logical_Port_Chain"/> to be used.
+ </column>
+
+ <column name="options" key="sfc-bidirectional">
+ Optional and only applicable when <ref column="action"/> is <code>sfc</code>.
+ When set with value <code>true</code>, the implementation will also add rules to make packets
+ go through the chain in reverse direction. A restriction on making bidirectional chains is
+ that the inport parameter must be present in <ref column="match"/>, as it will be used as the
+ <ref table="Logical_Port_Chain" column="last_hop_port"/>. As expected, all <code>src*</code>
+ fields in <ref column="match"/> will be converted to <code>dst*</code> in order to derive the
+ reverse ACL.
+
+ <p>
+ sfc-bidirectional option is not yet implemented.
+ </p>
+ </column>
+ </group>
+
+ </group>
+
<group title="Common Columns">
<column name="external_ids">
See <em>External IDs</em> at the beginning of this document.
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
index af1eeab7f..dc3d45eea 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -323,8 +323,73 @@ Logical switch commands:\n\
ls-del SWITCH delete SWITCH and all its ports\n\
ls-list print the names of all logical switches\n\
\n\
+Logical port-chain commands:\n\
+ lport-chain-add LSWITCH [LPORT-CHAIN] create a logical port-chain named LPORT-CHAIN\n\
+ lport-chain-del LPORT-CHAIN delete LPORT-CHAIN but not FLOW-CLASSIFIER\n \
+ lport-chain-list LSWITCH print the names of all logical port-chains on LSWITCH\n\
+\n\
+Logical port-pair-groups commands:\n\
+ lport-pair-group-add LPORT-CHAIN LPORT-PAIR-GROUP-NAME\n\
+ create a logical port-pair-group \n\
+ lport-pair-group-del LPORT-PAIR-GROUP-NAME delete a port-pair-group, does not delete port-pairs\n\
+ or flow-classifier\n\
+ lport-pair-group-list LPORT-CHAIN print the names of all logical port-pair-groups\n\
+ lport-pair-group-add-port-pair LPORT-PAIR-GROUP LPORT-PAIR add a port pair to a port-group\n\
+ lport-pair-group-del-port-pair LPORT-PAIR-GROUP LPORT-PAIR del a port pair from a port-group\n\
+\n\
+Logical port-pair commands:\n\
+ lport-pair-add LSWITCH LIN-PORT LOUT-PORT [LPORT-PAIR-NAME]\n\
+ create a logical port-pair \n\
+ lport-pair-del LPORT-PAIR-NAME delete a port-pair, does not delete ports\n\
+ lport-pair-list print the names of all logical port-pairs\n\
+\n\
+Logical flow-classifier commands:\n\
+ lflow-classifier-add LPORT-CHAIN LIN-PORT [LFLOW-CLASSIFIER-NAME]\n\
+ create a logical flow-classifer \n\
+ lflow-classifier-del LFLOW-CLASSIFIER-NAME delete a flow-classifier, does not delete ports\n\
+ lflow-classifier-list LPORT-CHAIN print the names of all logical flow-classifiers on a switch\n\
+ lflow-classifier-set-logical-destination-port LFLOW_CLASSIFIER [LDEST_PORT]\n\
+ set the name of ldest port \n\
+ lflow-classifier-get-logical-destination-port LFLOW_CLASSIFIER\n\
+ get the name of ldest port \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\
+Logical port-chain commands:\n\
+ lsp-chain-add LSWITCH [LSP-CHAIN] create a logical port-chain named LSP-CHAIN\n\
+ lsp-chain-del LSP-CHAIN delete LSP-CHAIN but not FLOW-CLASSIFIER\n \
+ lsp-chain-list LSWITCH print the names of all logical port-chains on LSWITCH\n\
+\n\
+Logical port-pair-groups commands:\n\
+ lsp-pair-group-add LSP-CHAIN LSP-PAIR-GROUP-NAME\n\
+ create a logical port-pair-group \n\
+ lsp-pair-group-del LSP-PAIR-GROUP-NAME delete a port-pair-group, does not delete port-pairs\n\
+ or flow-classifier\n\
+ lsp-pair-group-list LSP-CHAIN print the names of all logical port-pair-groups\n\
+ lsp-pair-group-add-port-pair LSP-PAIR-GROUP LSP-PAIR add a port pair to a port-group\n\
+ lsp-pair-group-del-port-pair LSP-PAIR-GROUP LSP-PAIR del a port pair from a port-group\n\
+\n\
+Logical port-pair commands:\n\
+ lsp-pair-add LSWITCH LIN-PORT LOUT-PORT [LSP-PAIR-NAME]\n\
+ create a logical port-pair \n\
+ lsp-pair-del LSP-PAIR-NAME delete a port-pair, does not delete ports\n\
+ lsp-pair-list print the names of all logical port-pairs\n\
+\n\
+Logical flow-classifier commands:\n\
+ lflow-classifier-add LSP-CHAIN LIN-PORT [LFLOW-CLASSIFIER-NAME]\n\
+ create a logical flow-classifer \n\
+ lflow-classifier-del LFLOW-CLASSIFIER-NAME delete a flow-classifier, does not delete ports\n\
+ lflow-classifier-list LSP-CHAIN print the names of all logical flow-classifiers on a switch\n\
+ lflow-classifier-set-logical-destination-port LFLOW_CLASSIFIER [LDEST_PORT]\n\
+ set the name of ldest port \n\
+ lflow-classifier-get-logical-destination-port LFLOW_CLASSIFIER\n\
+ get the name of ldest port \n\
+\n\
ACL commands:\n\
- acl-add SWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
+ acl-add SWITCH DIRECTION PRIORITY MATCH ACTION [ACL-OPTIONS] [log]\n\
add an ACL to SWITCH\n\
acl-del SWITCH [DIRECTION [PRIORITY MATCH]]\n\
remove ACLs from SWITCH\n\
@@ -360,6 +425,28 @@ Logical switch port commands:\n\
set dhcpv4 options for PORT\n\
lsp-get-dhcpv4-options PORT get the dhcpv4 options for PORT\n\
\n\
+Logical port-chain commands:\n\
+ lsp-chain-add SWITCH [CHAIN] LAST_PORT create a logical port-chain [named LSP-CHAIN]\n\
+ that has LAST_PORT as last hop at the end of chain\n\
+ lsp-chain-del CHAIN delete LSP-CHAIN\n\
+ lsp-chain-list [SWITCH] print the names of all logical port-chains [on SWITCH]\n\
+ lsp-chain-show SWITCH [CHAIN] print details on port-chains on SWITCH\n\
+\n\
+Logical port-pair-groups commands:\n\
+ lsp-pair-group-add CHAIN [PAIR-GROUP [OFFSET]]\n\
+ create a logical port-pair-group. Optionally, indicate the order it\n\
+ should be in chain.\n\
+ lsp-pair-group-del PAIR-GROUP delete a port-pair-group, does not delete port-pairs\n\
+ lsp-pair-group-list CHAIN print port-pair-groups for a givan chain\n\
+ lsp-pair-group-add-port-pair PAIR-GROUP LSP-PAIR add a port pair to a port-pair-group\n\
+ lsp-pair-group-del-port-pair PAIR-GROUP LSP-PAIR del a port pair from a port-pair-group\n\
+\n\
+Logical port-pair commands:\n\
+ lsp-pair-add SWITCH PORT-IN PORT-OUT [LSP-PAIR]\n\
+ create a logical port-pair\n\
+ lsp-pair-del LSP-PAIR delete a port-pair, does not delete ports\n\
+ lsp-pair-list [SWITCH [LSP-PAIR]] print the names of all logical port-pairs\n\
+\n\
Logical router commands:\n\
lr-add [ROUTER] create a logical router named ROUTER\n\
lr-del ROUTER delete ROUTER and all its ports\n\
@@ -522,6 +609,119 @@ ls_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
return ls;
}
+static const struct nbrec_logical_port_chain *
+lsp_chain_by_name_or_uuid(struct ctl_context *ctx, const char *id)
+{
+ const struct nbrec_logical_port_chain *lsp_chain = NULL;
+ bool is_uuid = false;
+ struct uuid lsp_chain_uuid;
+
+ if (uuid_from_string(&lsp_chain_uuid, id)) {
+ is_uuid = true;
+ lsp_chain = nbrec_logical_port_chain_get_for_uuid(ctx->idl,
+ &lsp_chain_uuid);
+ printf("found lsp_chain %s\n",id); // FIXME(ff): debug, remove this
+ }
+
+ if (!lsp_chain) {
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH(lsp_chain, ctx->idl) {
+ if (!strcmp(lsp_chain->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lsp_chain) {
+ ctl_fatal("lsp_chain not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lsp_chain;
+}
+static const struct nbrec_logical_port_pair_group *
+lsp_pair_group_by_name_or_uuid(struct ctl_context *ctx, const char *id)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group = NULL;
+ bool is_uuid = false;
+ struct uuid lsp_pair_group_uuid;
+
+ if (uuid_from_string(&lsp_pair_group_uuid, id)) {
+ is_uuid = true;
+ lsp_pair_group = nbrec_logical_port_pair_group_get_for_uuid(ctx->idl,
+ &lsp_pair_group_uuid);
+ printf("Found lsp_pair_group %s\n",id); // FIXME(ff): debug, remove this
+ }
+
+ if (!lsp_pair_group) {
+ NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH(lsp_pair_group, ctx->idl) {
+ if (!strcmp(lsp_pair_group->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lsp_pair_group) {
+ ctl_fatal("lsp_pair_group not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lsp_pair_group;
+}
+static const struct nbrec_logical_port_pair *
+lsp_pair_by_name_or_uuid(struct ctl_context *ctx, const char *id)
+{
+ const struct nbrec_logical_port_pair *lsp_pair = NULL;
+ bool is_uuid = false;
+ struct uuid lsp_pair_uuid;
+
+ if (uuid_from_string(&lsp_pair_uuid, id)) {
+ is_uuid = true;
+ lsp_pair = nbrec_logical_port_pair_get_for_uuid(ctx->idl,
+ &lsp_pair_uuid);
+ printf("found lsp_pair %s\n",id); // FIXME(ff): debug, remove this
+ }
+
+ if (!lsp_pair) {
+ NBREC_LOGICAL_PORT_PAIR_FOR_EACH(lsp_pair, ctx->idl) {
+ if (!strcmp(lsp_pair->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lsp_pair) {
+ ctl_fatal("lsp_pair not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lsp_pair;
+}
+static const struct nbrec_logical_flow_classifier *
+lflow_classifier_by_name_or_uuid(struct ctl_context *ctx, const char *id)
+{
+ const struct nbrec_logical_flow_classifier *lflow_classifier = NULL;
+ bool is_uuid = false;
+ struct uuid lflow_classifier_uuid;
+
+ if (uuid_from_string(&lflow_classifier_uuid, id)) {
+ is_uuid = true;
+ lflow_classifier = nbrec_logical_flow_classifier_get_for_uuid(ctx->idl,
+ &lflow_classifier_uuid);
+ printf("found lflow_classifier %s\n",id); // FIXME(ff): debug, remove this
+ }
+
+ if (!lflow_classifier) {
+ NBREC_LOGICAL_FLOW_CLASSIFIER_FOR_EACH(lflow_classifier, ctx->idl) {
+ if (!strcmp(lflow_classifier->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lflow_classifier) {
+ ctl_fatal("lflow_classifier not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lflow_classifier;
+ }
+
static const struct nbrec_load_balancer *
lb_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
{
@@ -548,217 +748,1560 @@ lb_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
}
}
- if (!lb && must_exist) {
- ctl_fatal("%s: load balancer %s not found", id,
- is_uuid ? "UUID" : "name");
+ if (!lb && must_exist) {
+ ctl_fatal("%s: load balancer %s not found", id,
+ is_uuid ? "UUID" : "name");
+ }
+
+ return lb;
+}
+
+/* Given pointer to logical router, this routine prints the router
+ * information. */
+static void
+print_lr(const struct nbrec_logical_router *lr, struct ds *s)
+{
+ ds_put_format(s, " router "UUID_FMT" (%s)\n",
+ UUID_ARGS(&lr->header_.uuid), lr->name);
+
+ for (size_t i = 0; i < lr->n_ports; i++) {
+ const struct nbrec_logical_router_port *lrp = lr->ports[i];
+ ds_put_format(s, " port %s\n", lrp->name);
+ if (lrp->mac) {
+ ds_put_cstr(s, " mac: ");
+ ds_put_format(s, "\"%s\"\n", lrp->mac);
+ }
+ if (lrp->n_networks) {
+ ds_put_cstr(s, " networks: [");
+ for (size_t j = 0; j < lrp->n_networks; j++) {
+ ds_put_format(s, "%s\"%s\"",
+ j == 0 ? "" : ", ",
+ lrp->networks[j]);
+ }
+ ds_put_cstr(s, "]\n");
+ }
+ }
+}
+
+static void
+print_ls(const struct nbrec_logical_switch *ls, struct ds *s)
+{
+ ds_put_format(s, " switch "UUID_FMT" (%s)\n",
+ UUID_ARGS(&ls->header_.uuid), ls->name);
+
+ for (size_t i = 0; i < ls->n_ports; i++) {
+ const struct nbrec_logical_switch_port *lsp = ls->ports[i];
+
+ ds_put_format(s, " port %s\n", lsp->name);
+ if (lsp->parent_name) {
+ ds_put_format(s, " parent: %s\n", lsp->parent_name);
+ }
+ if (lsp->n_tag) {
+ ds_put_format(s, " tag: %"PRIu64"\n", lsp->tag[0]);
+ }
+ if (lsp->n_addresses) {
+ ds_put_cstr(s, " addresses: [");
+ for (size_t j = 0; j < lsp->n_addresses; j++) {
+ ds_put_format(s, "%s\"%s\"",
+ j == 0 ? "" : ", ",
+ lsp->addresses[j]);
+ }
+ ds_put_cstr(s, "]\n");
+ }
+ }
+}
+
+static void
+nbctl_init(struct ctl_context *ctx OVS_UNUSED)
+{
+}
+
+static void
+nbctl_pre_sync(struct ctl_context *ctx OVS_UNUSED)
+{
+ if (wait_type != NBCTL_WAIT_NONE) {
+ force_wait = true;
+ } else {
+ VLOG_INFO("\"sync\" command has no effect without --wait");
+ }
+}
+
+static void
+nbctl_sync(struct ctl_context *ctx OVS_UNUSED)
+{
+}
+
+static void
+nbctl_show(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_switch *ls;
+
+ if (ctx->argc == 2) {
+ ls = ls_by_name_or_uuid(ctx, ctx->argv[1], false);
+ if (ls) {
+ print_ls(ls, &ctx->output);
+ }
+ } else {
+ NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
+ print_ls(ls, &ctx->output);
+ }
+ }
+ const struct nbrec_logical_router *lr;
+
+ if (ctx->argc == 2) {
+ lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
+ if (lr) {
+ print_lr(lr, &ctx->output);
+ }
+ } else {
+ NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
+ print_lr(lr, &ctx->output);
+ }
+ }
+}
+
+static void
+nbctl_ls_add(struct ctl_context *ctx)
+{
+ const char *ls_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
+
+ bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
+ bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
+ if (may_exist && add_duplicate) {
+ ctl_fatal("--may-exist and --add-duplicate may not be used together");
+ }
+
+ if (ls_name) {
+ if (!add_duplicate) {
+ const struct nbrec_logical_switch *ls;
+ NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
+ if (!strcmp(ls->name, ls_name)) {
+ if (may_exist) {
+ return;
+ }
+ ctl_fatal("%s: a switch with this name already exists",
+ ls_name);
+ }
+ }
+ }
+ } else if (may_exist) {
+ ctl_fatal("--may-exist requires specifying a name");
+ } else if (add_duplicate) {
+ ctl_fatal("--add-duplicate requires specifying a name");
+ }
+
+ struct nbrec_logical_switch *ls;
+ ls = nbrec_logical_switch_insert(ctx->txn);
+ if (ls_name) {
+ nbrec_logical_switch_set_name(ls, ls_name);
+ }
+}
+
+static void
+nbctl_ls_del(struct ctl_context *ctx)
+{
+ bool must_exist = !shash_find(&ctx->options, "--if-exists");
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_switch *ls;
+
+ ls = ls_by_name_or_uuid(ctx, id, must_exist);
+ if (!ls) {
+ return;
+ }
+
+ nbrec_logical_switch_delete(ls);
+}
+
+static void
+nbctl_ls_list(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_switch *ls;
+ struct smap lswitches;
+
+ smap_init(&lswitches);
+ NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
+ smap_add_format(&lswitches, ls->name, UUID_FMT " (%s)",
+ UUID_ARGS(&ls->header_.uuid), ls->name);
+ }
+ const struct smap_node **nodes = smap_sort(&lswitches);
+ for (size_t i = 0; i < smap_count(&lswitches); i++) {
+ const struct smap_node *node = nodes[i];
+ ds_put_format(&ctx->output, "%s\n", node->value);
+ }
+ smap_destroy(&lswitches);
+ free(nodes);
+}
+
+/*
+ * Port chain CLI Functions
+ */
+static void
+nbctl_lsp_chain_add(struct ctl_context *ctx)
+{
+
+ const struct nbrec_logical_switch *lswitch;
+
+ if (ctx->argc < 2) {
+ /* ensure all arguments are present */
+ ctl_fatal("Invalid number of arguments: (%d), to lsp-chain-add.",ctx->argc);
+ }
+
+ const char *lsp_chain_name = ctx->argc == 3 ? ctx->argv[2] : NULL;
+ lswitch = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+ if (lsp_chain_name) {
+ const struct nbrec_logical_port_chain *lsp_chain;
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH(lsp_chain, ctx->idl) {
+ if (strcmp(lsp_chain->name, lsp_chain_name))
+ ctl_fatal("%s: an lsp_chain with this name already exists",
+ lsp_chain_name);
+ }
+ }
+ struct nbrec_logical_port_chain *lsp_chain;
+ lsp_chain = nbrec_logical_port_chain_insert(ctx->txn);
+ if (lsp_chain_name) {
+ nbrec_logical_port_chain_set_name(lsp_chain, lsp_chain_name);
+ }
+
+ /* Insert the logical port-chain into the logical switch. */
+
+ nbrec_logical_switch_verify_port_chains(lswitch);
+ struct nbrec_logical_port_chain **new_port_chain = xmalloc(sizeof *new_port_chain *
+ (lswitch->n_port_chains + 1));
+ memcpy(new_port_chain, lswitch->port_chains, sizeof *new_port_chain * lswitch->n_port_chains);
+ new_port_chain[lswitch->n_port_chains] = CONST_CAST(struct nbrec_logical_port_chain *, lsp_chain);
+ nbrec_logical_switch_set_port_chains(lswitch, new_port_chain, lswitch->n_port_chains + 1);
+ free(new_port_chain);
+}
+
+/* Removes lswitch->pair_chain[idx]'. */
+static void
+remove_lsp_chain(const struct nbrec_logical_switch *lswitch, size_t idx)
+{
+ const struct nbrec_logical_port_chain *lsp_chain = lswitch->port_chains[idx];
+
+ /* First remove 'lsp-chain' from the array of port-chains. This is what will
+ * actually cause the logical port-chain to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_chain **new_port_chain
+ = xmemdup(lswitch->port_chains, sizeof *new_port_chain * lswitch->n_port_chains);
+ new_port_chain[idx] = new_port_chain[lswitch->n_port_chains - 1];
+ nbrec_logical_switch_verify_port_chains(lswitch);
+ nbrec_logical_switch_set_port_chains(lswitch, new_port_chain, lswitch->n_port_chains - 1);
+ free(new_port_chain);
+
+ /* Delete 'lsp-chain' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_CHAIN_FOR_EACH later. */
+ nbrec_logical_port_chain_delete(lsp_chain);
+}
+
+static void
+nbctl_lsp_chain_del(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_chain *lsp_chain;
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lsp_chain) {
+ ctl_fatal("Cannot find lsp_chain: %s\n", ctx->argv[1]);
+ }
+
+ /* Find the lswitch that contains 'port-chain', then delete it. */
+ const struct nbrec_logical_switch *lswitch;
+ NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
+ for (size_t i = 0; i < lswitch->n_port_chains; i++) {
+ if (lswitch->port_chains[i] == lsp_chain) {
+ remove_lsp_chain(lswitch,i);
+ printf("Deleted lsp-chain: %s\n", ctx->argv[1]); // FIXME(ff): debug, remove this
+ return;
+ }
+ }
+ }
+}
+
+static const struct nbrec_logical_switch_port *
+lsp_by_name_or_uuid(struct ctl_context *ctx, const char *id,
+ bool must_exist)
+{
+ const struct nbrec_logical_switch_port *lsp = NULL;
+
+ struct uuid lsp_uuid;
+ bool is_uuid = uuid_from_string(&lsp_uuid, id);
+ if (is_uuid) {
+ lsp = nbrec_logical_switch_port_get_for_uuid(ctx->idl, &lsp_uuid);
+ }
+
+ if (!lsp) {
+ NBREC_LOGICAL_SWITCH_PORT_FOR_EACH(lsp, ctx->idl) {
+ if (!strcmp(lsp->name, id)) {
+ break;
+ }
+ }
+ }
+
+ if (!lsp && must_exist) {
+ ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
+ }
+
+ return lsp;
+
+}
+
+/*
+ * Port chain CLI Functions
+ */
+static const struct nbrec_logical_port_chain *
+lsp_chain_by_name_or_uuid(struct ctl_context *ctx, const char *id, const bool must_exist)
+{
+ const struct nbrec_logical_port_chain *lsp_chain = NULL;
+ bool is_uuid = false;
+ struct uuid lsp_chain_uuid;
+
+ if (uuid_from_string(&lsp_chain_uuid, id)) {
+ is_uuid = true;
+ lsp_chain = nbrec_logical_port_chain_get_for_uuid(ctx->idl,
+ &lsp_chain_uuid);
+ }
+
+ if (!lsp_chain) {
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH(lsp_chain, ctx->idl) {
+ if (!strcmp(lsp_chain->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lsp_chain && must_exist) {
+ ctl_fatal("lsp_chain not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lsp_chain;
+}
+static const struct nbrec_logical_port_pair_group *
+lsp_pair_group_by_name_or_uuid(struct ctl_context *ctx, const char *id, const bool must_exist)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group = NULL;
+ bool is_uuid = false;
+ struct uuid lsp_pair_group_uuid;
+
+ if (uuid_from_string(&lsp_pair_group_uuid, id)) {
+ is_uuid = true;
+ lsp_pair_group = nbrec_logical_port_pair_group_get_for_uuid(ctx->idl,
+ &lsp_pair_group_uuid);
+ }
+
+ if (!lsp_pair_group) {
+ NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH(lsp_pair_group, ctx->idl) {
+ if (!strcmp(lsp_pair_group->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lsp_pair_group && must_exist) {
+ ctl_fatal("lsp_pair_group not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lsp_pair_group;
+}
+
+static const struct nbrec_logical_port_pair *
+lsp_pair_by_name_or_uuid(struct ctl_context *ctx, const char *id, const bool must_exist)
+{
+ const struct nbrec_logical_port_pair *lsp_pair = NULL;
+ bool is_uuid = false;
+ struct uuid lsp_pair_uuid;
+
+ if (uuid_from_string(&lsp_pair_uuid, id)) {
+ is_uuid = true;
+ lsp_pair = nbrec_logical_port_pair_get_for_uuid(ctx->idl,
+ &lsp_pair_uuid);
+ }
+
+ if (!lsp_pair) {
+ NBREC_LOGICAL_PORT_PAIR_FOR_EACH(lsp_pair, ctx->idl) {
+ if (!strcmp(lsp_pair->name, id)) {
+ break;
+ }
+ }
+ }
+ if (!lsp_pair && must_exist) {
+ ctl_fatal("lsp_pair not found for %s: '%s'",
+ is_uuid ? "UUID" : "name", id);
+ }
+
+ return lsp_pair;
+}
+
+
+static void
+nbctl_lsp_chain_add(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_switch *lswitch;
+ const struct nbrec_logical_switch_port *last_hop_lsp;
+
+ lswitch = ls_by_name_or_uuid(ctx, ctx->argv[1], true /*must_exist*/);
+ const char *lsp_chain_name = ctx->argc > 3 ? ctx->argv[2] : NULL;
+ const char *last_hop_lsp_name = lsp_chain_name ? ctx->argv[3] : ctx->argv[2];
+
+ 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_fatal("--may-exist and --add-duplicate may not be used together");
+ }
+
+ last_hop_lsp = lsp_by_name_or_uuid(ctx, last_hop_lsp_name, true);
+
+ if (lsp_chain_name) {
+ if (!add_duplicate) {
+ const struct nbrec_logical_port_chain *lsp_chain;
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH(lsp_chain, ctx->idl) {
+ if (!strcmp(lsp_chain->name, lsp_chain_name)) {
+ if (may_exist) {
+ return;
+ }
+ ctl_fatal("%s: an lsp_chain with this name already exists",
+ lsp_chain_name);
+ }
+ }
+ }
+ } else if (may_exist) {
+ ctl_fatal("--may-exist requires specifying a name");
+ } else if (add_duplicate) {
+ ctl_fatal("--add-duplicate requires specifying a name");
+ }
+
+ struct nbrec_logical_port_chain *lsp_chain;
+ lsp_chain = nbrec_logical_port_chain_insert(ctx->txn);
+ if (lsp_chain_name) {
+ nbrec_logical_port_chain_set_name(lsp_chain, lsp_chain_name);
+ }
+ nbrec_logical_port_chain_set_last_hop_port(lsp_chain, last_hop_lsp);
+
+ /* Insert the logical port-chain into the logical switch. */
+
+ nbrec_logical_switch_verify_port_chains(lswitch);
+ struct nbrec_logical_port_chain **new_port_chain = xmalloc(sizeof *new_port_chain *
+ (lswitch->n_port_chains + 1));
+ memcpy(new_port_chain, lswitch->port_chains, sizeof *new_port_chain * lswitch->n_port_chains);
+ new_port_chain[lswitch->n_port_chains] = CONST_CAST(struct nbrec_logical_port_chain *, lsp_chain);
+ nbrec_logical_switch_set_port_chains(lswitch, new_port_chain, lswitch->n_port_chains + 1);
+ free(new_port_chain);
+}
+
+/* Removes lswitch->pair_chain[idx]'. */
+static void
+remove_lsp_chain(const struct nbrec_logical_switch *lswitch, size_t idx)
+{
+ const struct nbrec_logical_port_chain *lsp_chain = lswitch->port_chains[idx];
+
+ /* First remove 'lsp-chain' from the array of port-chains. This is what will
+ * actually cause the logical port-chain to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_chain **new_port_chain
+ = xmemdup(lswitch->port_chains, sizeof *new_port_chain * lswitch->n_port_chains);
+ new_port_chain[idx] = new_port_chain[lswitch->n_port_chains - 1];
+ nbrec_logical_switch_verify_port_chains(lswitch);
+ nbrec_logical_switch_set_port_chains(lswitch, new_port_chain, lswitch->n_port_chains - 1);
+ free(new_port_chain);
+
+ /* Delete 'lsp-chain' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_CHAIN_FOR_EACH later. */
+ nbrec_logical_port_chain_delete(lsp_chain);
+}
+
+static void
+nbctl_lsp_chain_del(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_chain *lsp_chain;
+ const bool must_exist = !shash_find(&ctx->options, "--if-exists");
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
+ if (!lsp_chain) {
+ return;
+ }
+
+ /* Find the lswitch that contains 'port-chain', then delete it. */
+ const struct nbrec_logical_switch *lswitch;
+ NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
+ for (size_t i = 0; i < lswitch->n_port_chains; i++) {
+ if (lswitch->port_chains[i] == lsp_chain) {
+ remove_lsp_chain(lswitch,i);
+ return;
+ }
+ }
+ }
+}
+
+static void
+print_lsp_chain_entry(struct ctl_context *ctx,
+ const struct nbrec_logical_switch *lswitch,
+ const char *chain_name_filter,
+ const bool show_switch_name)
+{
+ struct smap lsp_chains;
+ size_t i;
+
+ smap_init(&lsp_chains);
+ for (i = 0; i < lswitch->n_port_chains; i++) {
+ const struct nbrec_logical_port_chain *lsp_chain = lswitch->port_chains[i];
+ if (chain_name_filter && strcmp(chain_name_filter, lsp_chain->name)) {
+ continue;
+ }
+ if (show_switch_name) {
+ smap_add_format(&lsp_chains, lsp_chain->name, UUID_FMT " (%s:%s)",
+ UUID_ARGS(&lsp_chain->header_.uuid),
+ lswitch->name, lsp_chain->name);
+ } else {
+ smap_add_format(&lsp_chains, lsp_chain->name, UUID_FMT " (%s)",
+ UUID_ARGS(&lsp_chain->header_.uuid), lsp_chain->name);
+ }
+ }
+
+ const struct smap_node **nodes = smap_sort(&lsp_chains);
+ for (i = 0; i < smap_count(&lsp_chains); i++) {
+ const struct smap_node *node = nodes[i];
+ ds_put_format(&ctx->output, "%s\n", node->value);
+ }
+ smap_destroy(&lsp_chains);
+ free(nodes);
+}
+
+static void
+nbctl_lsp_chain_list(struct ctl_context *ctx)
+{
+ const char *id = ctx->argc > 1 ? ctx->argv[1] : NULL;
+ const char *chain_name_filter = ctx->argc > 2 ? ctx->argv[2] : NULL;
+ const struct nbrec_logical_switch *lswitch;
+
+ if (id) {
+ lswitch = ls_by_name_or_uuid(ctx, id, true);
+ print_lsp_chain_entry(ctx, lswitch, chain_name_filter, false);
+ } else {
+ NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
+ if (lswitch->n_port_chains == 0) {
+ continue;
+ }
+ print_lsp_chain_entry(ctx, lswitch, chain_name_filter, true);
+ }
+ }
+}
+
+static void
+print_lsp_chain(const struct nbrec_logical_port_chain *lsp_chain,
+ struct ctl_context *ctx)
+{
+ ds_put_format(&ctx->output, "lsp-chain "UUID_FMT" (%s)\n",
+ UUID_ARGS(&lsp_chain->header_.uuid), lsp_chain->name);
+
+ for (size_t i = 0; i < lsp_chain->n_port_pair_groups; i++) {
+ const struct nbrec_logical_port_pair_group *lsp_pair_group
+ = lsp_chain->port_pair_groups[i];
+ ds_put_format(&ctx->output, " lsp-pair-group %s\n", lsp_pair_group->name);
+ for (size_t j = 0; j < lsp_pair_group->n_port_pairs; j++){
+ const struct nbrec_logical_port_pair *lsp_pair = lsp_pair_group->port_pairs[j];
+ ds_put_format(&ctx->output, " lsp-pair %s\n", lsp_pair->name);
+
+ const struct nbrec_logical_switch_port *linport = lsp_pair->inport;
+ if (linport) {
+ ds_put_format(&ctx->output, " lsp-pair inport "UUID_FMT" (%s)\n",
+ UUID_ARGS(&linport->header_.uuid), linport->name);
+ }
+
+ const struct nbrec_logical_switch_port *loutport = lsp_pair->outport;
+ if (loutport) {
+ ds_put_format(&ctx->output, " lsp-pair outport "UUID_FMT" (%s)\n",
+ UUID_ARGS(&loutport->header_.uuid), loutport->name);
+ }
+ }
+ }
+
+ // TODO: iterate ACLs and display the ones that have action 'sfc' and use this lsp_chain
+}
+
+static void
+nbctl_lsp_chain_show(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_chain *lsp_chain;
+
+ if (ctx->argc == 2) {
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1], false);
+ if (lsp_chain) {
+ print_lsp_chain(lsp_chain, ctx);
+ }
+ } else {
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH(lsp_chain, ctx->idl) {
+ print_lsp_chain(lsp_chain, ctx);
+ }
+ }
+}
+/* End of port-chain operations */
+
+/*
+ * Port Pair Groups CLI Functions
+ */
+static void
+nbctl_lsp_pair_group_add(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ const char *ppg_name = ctx->argc >= 3 ? ctx->argv[2] : NULL;
+
+ 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_fatal("--may-exist and --add-duplicate may not be used together");
+ }
+
+ if (ppg_name) {
+ if (!add_duplicate) {
+ NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH(lsp_pair_group, ctx->idl) {
+ if (!strcmp(lsp_pair_group->name, ppg_name)) {
+ if (may_exist) {
+ return;
+ }
+ ctl_fatal("%s: an lsp_port_pair_group with this name already exists",
+ ppg_name);
+ }
+ }
+ }
+ } else if (may_exist) {
+ ctl_fatal("--may-exist requires specifying a name");
+ } else if (add_duplicate) {
+ ctl_fatal("--add-duplicate requires specifying a name");
+ }
+
+ /* check lsp_chain exists */
+ const struct nbrec_logical_port_chain *lsp_chain;
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1], true);
+ if (!lsp_chain) {
+ return;
+ }
+
+ /* create the logical port-pair-group. */
+ lsp_pair_group = nbrec_logical_port_pair_group_insert(ctx->txn);
+ if (ppg_name) {
+ nbrec_logical_port_pair_group_set_name(lsp_pair_group, ctx->argv[2]);
+ }
+
+ int64_t sortkey = (int64_t) lsp_chain->n_port_pair_groups + 1;
+ if (ctx->argc >= 4) {
+ sortkey = (int64_t) atoi(ctx->argv[3]);
+ }
+ nbrec_logical_port_pair_group_set_sortkey(lsp_pair_group, &sortkey, 1);
+
+ /* Insert the logical port-pair-group into the logical switch. */
+ nbrec_logical_port_chain_verify_port_pair_groups(lsp_chain);
+ struct nbrec_logical_port_pair_group **new_port_pair_group = xmalloc(sizeof *new_port_pair_group *
+ (lsp_chain->n_port_pair_groups + 1));
+ memcpy(new_port_pair_group, lsp_chain->port_pair_groups, sizeof *new_port_pair_group * lsp_chain->n_port_pair_groups);
+ new_port_pair_group[lsp_chain->n_port_pair_groups] =
+ CONST_CAST(struct nbrec_logical_port_pair_group *,lsp_pair_group);
+ nbrec_logical_port_chain_set_port_pair_groups(lsp_chain, new_port_pair_group, lsp_chain->n_port_pair_groups + 1);
+ free(new_port_pair_group);
+}
+
+/* Removes lsp-pair-group 'lsp_chain->port_pair_group[idx]'. */
+static void
+remove_lsp_pair_group(const struct nbrec_logical_port_chain *lsp_chain, size_t idx)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group = lsp_chain->port_pair_groups[idx];
+
+ /* First remove 'lsp-pair-group' from the array of port-pair-groups. This is what will
+ * actually cause the logical port-pair-group to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_pair_group **new_port_pair_group
+ = xmemdup(lsp_chain->port_pair_groups, sizeof *new_port_pair_group * lsp_chain->n_port_pair_groups);
+ new_port_pair_group[idx] = new_port_pair_group[lsp_chain->n_port_pair_groups - 1];
+ nbrec_logical_port_chain_verify_port_pair_groups(lsp_chain);
+ nbrec_logical_port_chain_set_port_pair_groups(lsp_chain, new_port_pair_group, lsp_chain->n_port_pair_groups - 1);
+ free(new_port_pair_group);
+
+ /* Delete 'lsp-pair-group' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH later. */
+ nbrec_logical_port_pair_group_delete(lsp_pair_group);
+}
+
+static void
+nbctl_lsp_pair_group_del(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ const bool must_exist = !shash_find(&ctx->options, "--if-exists");
+
+ lsp_pair_group = lsp_pair_group_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
+ if (!lsp_pair_group) {
+ return;
+ }
+
+ /* Find the port-chain that contains 'port-pair-group', then delete it. */
+ const struct nbrec_logical_port_chain *lsp_chain;
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH (lsp_chain, ctx->idl) {
+ for (size_t i = 0; i < lsp_chain->n_port_pair_groups; i++) {
+ if (lsp_chain->port_pair_groups[i] == lsp_pair_group) {
+ remove_lsp_pair_group(lsp_chain,i);
+ return;
+ }
+ }
+ }
+ if (must_exist) {
+ ctl_fatal("logical port-pair-group %s is not part of any logical port-chain",
+ ctx->argv[1]);
+ }
+}
+
+static void
+nbctl_lsp_pair_group_list(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_port_chain *lsp_chain;
+ struct smap lsp_pair_groups;
+ size_t i;
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, id, true);
+ if (!lsp_chain) {
+ return;
+ }
+
+ smap_init(&lsp_pair_groups);
+ for (i = 0; i < lsp_chain->n_port_pair_groups; i++) {
+ const struct nbrec_logical_port_pair_group *lsp_pair_group = lsp_chain->port_pair_groups[i];
+ smap_add_format(&lsp_pair_groups, lsp_pair_group->name, UUID_FMT " (%s)",
+ UUID_ARGS(&lsp_pair_group->header_.uuid), lsp_pair_group->name);
+ }
+ const struct smap_node **nodes = smap_sort(&lsp_pair_groups);
+ for (i = 0; i < smap_count(&lsp_pair_groups); i++) {
+ const struct smap_node *node = nodes[i];
+ ds_put_format(&ctx->output, "%s\n", node->value);
+ }
+ smap_destroy(&lsp_pair_groups);
+ free(nodes);
+}
+
+static void
+nbctl_lsp_pair_group_add_port_pair(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ const struct nbrec_logical_port_pair *lsp_pair;
+ const bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
+
+ lsp_pair_group = lsp_pair_group_by_name_or_uuid(ctx, ctx->argv[1], true);
+ if (!lsp_pair_group) {
+ return;
+ }
+
+ /* Check that port-pair exists */
+ lsp_pair = lsp_pair_by_name_or_uuid(ctx, ctx->argv[2], true);
+ if (!lsp_pair){
+ return;
+ }
+
+ /* Do not add port pair more than once in a given port-pair-group */
+ for (size_t i = 0; i < lsp_pair_group->n_port_pairs; i++) {
+ if (lsp_pair_group->port_pairs[i] == lsp_pair) {
+ if (!may_exist) {
+ ctl_fatal("lsp_pair: %s is already added to port-pair-group %s\n", ctx->argv[2], ctx->argv[1]);
+ }
+ return;
+ }
+ }
+
+ /* Insert the logical port-pair into the logical port-pair-group. */
+ nbrec_logical_port_pair_group_verify_port_pairs(lsp_pair_group);
+ struct nbrec_logical_port_pair **new_port_pair = xmalloc(sizeof *new_port_pair *
+ (lsp_pair_group->n_port_pairs + 1));
+ memcpy(new_port_pair, lsp_pair_group->port_pairs, sizeof *new_port_pair * lsp_pair_group->n_port_pairs);
+ new_port_pair[lsp_pair_group->n_port_pairs] = CONST_CAST(struct nbrec_logical_port_pair *, lsp_pair);
+ nbrec_logical_port_pair_group_set_port_pairs(lsp_pair_group, new_port_pair, lsp_pair_group->n_port_pairs + 1);
+ free(new_port_pair);
+}
+
+/* Removes port-pair from port-pair-groiup but does not delete it'. */
+static void
+remove_lsp_pair_from_port_pair_group(const struct nbrec_logical_port_pair_group *lsp_pair_group, size_t idx)
+{
+ //TODO Check const struct nbrec_logical_port_pair *lsp_pair = lsp_pair_group->port_pairs[idx];
+
+ /* First remove 'lsp-pair' from the array of port-pairs. This is what will
+ * actually cause the logical port-pair to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_pair **new_port_pair
+ = xmemdup(lsp_pair_group->port_pairs, sizeof *new_port_pair * lsp_pair_group->n_port_pairs);
+ new_port_pair[idx] = new_port_pair[lsp_pair_group->n_port_pairs - 1];
+ nbrec_logical_port_pair_group_verify_port_pairs(lsp_pair_group);
+ nbrec_logical_port_pair_group_set_port_pairs(lsp_pair_group, new_port_pair, lsp_pair_group->n_port_pairs - 1);
+ free(new_port_pair);
+
+ /* Do not delete actual port-pair as they are owned by a lswitch and can be reused. */
+ //nbrec_logical_port_pair_delete(lsp_pair);
+}
+
+static void
+nbctl_lsp_pair_group_del_port_pair(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_pair *lsp_pair;
+ const bool must_exist = !shash_find(&ctx->options, "--if-exists");
+
+ lsp_pair = lsp_pair_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
+ if (!lsp_pair) {
+ return;
+ }
+
+ /* Find the port-pair_group that contains 'port-pair', then delete it. */
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH (lsp_pair_group, ctx->idl) {
+ for (size_t i = 0; i < lsp_pair_group->n_port_pairs; i++) {
+ if (lsp_pair_group->port_pairs[i] == lsp_pair) {
+ remove_lsp_pair_from_port_pair_group(lsp_pair_group,i);
+ return;
+ }
+ }
+ }
+ if (must_exist) {
+ ctl_fatal("logical port-pair %s is not part of any logical switch",
+ ctx->argv[1]);
+ }
+}
+/* End of port-pair-group operations */
+
+/*
+ * port-pair operations
+ */
+static void
+nbctl_lsp_pair_add(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_switch *lswitch;
+ const struct nbrec_logical_switch_port *lsp_in,*lsp_out;
+ const struct nbrec_logical_port_pair *lsp_pair;
+
+ const bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
+ const bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
+
+ lswitch = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+ lsp_in = lsp_by_name_or_uuid(ctx, ctx->argv[2], true);
+ lsp_out = lsp_by_name_or_uuid(ctx, ctx->argv[3], true);
+
+ const char *lsp_pair_name = ctx->argc >= 5 ? ctx->argv[4] : NULL;
+ if (may_exist && add_duplicate) {
+ ctl_fatal("--may-exist and --add-duplicate may not be used together");
+ }
+
+ if (lsp_pair_name) {
+ if (!add_duplicate) {
+ NBREC_LOGICAL_PORT_PAIR_FOR_EACH(lsp_pair, ctx->idl) {
+ if (!strcmp(lsp_pair->name, lsp_pair_name)) {
+ if (may_exist) {
+ return;
+ }
+ ctl_fatal("%s: an lsp_pair with this name already exists",
+ lsp_pair_name);
+ }
+ }
+ }
+ } else if (may_exist) {
+ ctl_fatal("--may-exist requires specifying a name");
+ } else if (add_duplicate) {
+ ctl_fatal("--add-duplicate requires specifying a name");
+ }
+
+ /* create the logical port-pair. */
+ lsp_pair = nbrec_logical_port_pair_insert(ctx->txn);
+ nbrec_logical_port_pair_set_inport(lsp_pair, lsp_in);
+ nbrec_logical_port_pair_set_outport(lsp_pair, lsp_out);
+ if (lsp_pair_name) {
+ nbrec_logical_port_pair_set_name(lsp_pair, lsp_pair_name);
+ }
+
+ /* Insert the logical port-pair into the logical port-pair-group. */
+ nbrec_logical_switch_verify_port_pairs(lswitch);
+ struct nbrec_logical_port_pair **new_port_pair = xmalloc(sizeof *new_port_pair *
+ (lswitch->n_port_pairs + 1));
+ memcpy(new_port_pair, lswitch->port_pairs, sizeof *new_port_pair * lswitch->n_port_pairs);
+ new_port_pair[lswitch->n_port_pairs] = CONST_CAST(struct nbrec_logical_port_pair *, lsp_pair);
+ nbrec_logical_switch_set_port_pairs(lswitch, new_port_pair, lswitch->n_port_pairs + 1);
+ free(new_port_pair);
+}
+/* Removes lswitch->pair_pair[idx]'. */
+static void
+remove_lsp_pair(const struct nbrec_logical_switch *lswitch, size_t idx)
+{
+ const struct nbrec_logical_port_pair *lsp_pair = lswitch->port_pairs[idx];
+
+ /* First remove 'lsp-pair' from the array of port-pairs. This is what will
+ * actually cause the logical port-pair to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_pair **new_port_pair
+ = xmemdup(lswitch->port_pairs, sizeof *new_port_pair * lswitch->n_port_pairs);
+ new_port_pair[idx] = new_port_pair[lswitch->n_port_pairs - 1];
+ nbrec_logical_switch_verify_port_pairs(lswitch);
+ nbrec_logical_switch_set_port_pairs(lswitch, new_port_pair, lswitch->n_port_pairs - 1);
+ free(new_port_pair);
+
+ /* Delete 'lsp-pair' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_PAIR_FOR_EACH later. */
+ nbrec_logical_port_pair_delete(lsp_pair);
+}
+
+static void
+nbctl_lsp_pair_del(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_pair *lsp_pair;
+ const bool must_exist = !shash_find(&ctx->options, "--if-exists");
+
+ lsp_pair = lsp_pair_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
+ if (!lsp_pair) {
+ if (must_exist) {
+ ctl_fatal("Cannot find lsp_pair: %s\n", ctx->argv[1]);
+ }
+ }
+
+ /* Find the port-pair_group that contains 'port-pair', then delete it. */
+ const struct nbrec_logical_switch *lswitch;
+ NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
+ for (size_t i = 0; i < lswitch->n_port_pairs; i++) {
+ if (lswitch->port_pairs[i] == lsp_pair) {
+ remove_lsp_pair(lswitch,i);
+ return;
+ }
+ }
+ }
+ if (must_exist) {
+ ctl_fatal("logical port-pair %s is not part of any logical switch",
+ ctx->argv[1]);
+ }
+}
+
+static void
+print_lsp_pairs_for_switch(struct ctl_context *ctx,
+ const struct nbrec_logical_switch *lswitch,
+ const char *ppair_name_filter,
+ const bool show_switch_name)
+{
+ struct smap lsp_pairs;
+ size_t i;
+
+ smap_init(&lsp_pairs);
+ for (i = 0; i < lswitch->n_port_pairs; i++) {
+ const struct nbrec_logical_port_pair *lsp_pair = lswitch->port_pairs[i];
+ if (ppair_name_filter && strcmp(ppair_name_filter, lsp_pair->name)) {
+ continue;
+ }
+ const struct nbrec_logical_switch_port *linport = lsp_pair->inport;
+ const struct nbrec_logical_switch_port *loutport = lsp_pair->outport;
+ const char *linport_name = linport ? linport->name : "<not_set>";
+ const char *loutport_name = loutport ? loutport->name : "<not_set>";
+
+ if (show_switch_name) {
+ smap_add_format(&lsp_pairs, lsp_pair->name, UUID_FMT " (%s:%s) in:%s out:%s",
+ UUID_ARGS(&lsp_pair->header_.uuid), lswitch->name,
+ lsp_pair->name, linport_name, loutport_name);
+ } else {
+ smap_add_format(&lsp_pairs, lsp_pair->name, UUID_FMT " (%s) in:%s out:%s",
+ UUID_ARGS(&lsp_pair->header_.uuid),
+ lsp_pair->name, linport_name, loutport_name);
+ }
+ }
+ const struct smap_node **nodes = smap_sort(&lsp_pairs);
+ for (i = 0; i < smap_count(&lsp_pairs); i++) {
+ const struct smap_node *node = nodes[i];
+ ds_put_format(&ctx->output, "%s\n", node->value);
+ }
+ smap_destroy(&lsp_pairs);
+ free(nodes);
+}
+
+static void
+nbctl_lsp_pair_list(struct ctl_context *ctx)
+{
+ const char *id = ctx->argc > 1 ? ctx->argv[1] : NULL;
+ const char *pair_name_filter = ctx->argc > 2 ? ctx->argv[2] : NULL;
+ const struct nbrec_logical_switch *lswitch;
+
+ if (id) {
+ lswitch = ls_by_name_or_uuid(ctx, id, true);
+ print_lsp_pairs_for_switch(ctx, lswitch, pair_name_filter, false);
+ } else {
+ NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
+ if (lswitch->n_port_pairs == 0) {
+ continue;
+ }
+ print_lsp_pairs_for_switch(ctx, lswitch, pair_name_filter, true);
+ }
+ }
+}
+/* End of port-pair operations */
+
+static void
+nbctl_lsp_chain_list(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_switch *lswitch;
+ struct smap lsp_chains;
+ size_t i;
+
+ lswitch = ls_by_name_or_uuid(ctx, id, true);
+ if (!lswitch) {
+ return;
+ }
+
+ smap_init(&lsp_chains);
+ for (i = 0; i < lswitch->n_port_chains; i++) {
+ const struct nbrec_logical_port_chain *lsp_chain = lswitch->port_chains[i];
+ smap_add_format(&lsp_chains, lsp_chain->name, UUID_FMT " (%s)",
+ UUID_ARGS(&lsp_chain->header_.uuid), lsp_chain->name);
+ }
+ const struct smap_node **nodes = smap_sort(&lsp_chains);
+ for (i = 0; i < smap_count(&lsp_chains); i++) {
+ const struct smap_node *node = nodes[i];
+ ds_put_format(&ctx->output, "%s\n", node->value);
+ }
+ smap_destroy(&lsp_chains);
+ free(nodes);
+}
+
+static void
+print_lsp_chain(const struct nbrec_logical_port_chain *lsp_chain,
+ struct ctl_context *ctx)
+{
+ const char *port_not_set="Not Set";
+ ds_put_format(&ctx->output, " lsp-chain "UUID_FMT" (%s)\n",
+ UUID_ARGS(&lsp_chain->header_.uuid), lsp_chain->name);
+ for (size_t i = 0; i < lsp_chain->n_port_pair_groups; i++) {
+ const struct nbrec_logical_port_pair_group *lsp_pair_group
+ = lsp_chain->port_pair_groups[i];
+ ds_put_format(&ctx->output, " lsp-pair-group %s\n", lsp_pair_group->name);
+ for (size_t j = 0; j < lsp_pair_group->n_port_pairs; j++){
+ const struct nbrec_logical_switch_port *linport;
+ const struct nbrec_logical_switch_port *loutport;
+ const struct nbrec_logical_port_pair *lsp_pair
+ = lsp_pair_group->port_pairs[j];
+ ds_put_format(&ctx->output, " lsp-pair %s\n", lsp_pair->name);
+ linport = lsp_pair->inport;
+ ds_put_format(&ctx->output, " lsp-pair inport "UUID_FMT" (%s)\n",
+ UUID_ARGS(&linport->header_.uuid), linport->name);
+ loutport = lsp_pair->outport;
+ ds_put_format(&ctx->output, " lsp-pair outport "UUID_FMT" (%s)\n",
+ UUID_ARGS(&loutport->header_.uuid), loutport->name);
+ }
+ }
+ printf("finished port pairs\n"); // FIXME(ff): debug, remove this
+
+ const struct nbrec_logical_flow_classifier *lflow_classifier = lsp_chain->flow_classifier;
+ printf("Getting flow classifier: %s\n", lflow_classifier->name); // FIXME(ff): debug, remove this
+ ds_put_format(&ctx->output, " lflow_classifier %s\n", lflow_classifier->name);
+ if (lflow_classifier->logical_source_port == NULL){
+ ds_put_format(&ctx->output, " logical-source-port %s\n", port_not_set);
+ } else {
+ ds_put_format(&ctx->output, " logical-source-port %s\n", lflow_classifier->logical_source_port->name);
+ }
+ if (lflow_classifier->logical_destination_port == NULL){
+ ds_put_format(&ctx->output, " logical-destination-port %s\n", port_not_set);
+ } else {
+ ds_put_format(&ctx->output, " logical-destination-port %s\n", lflow_classifier->logical_destination_port->name);
+ }
+ ds_put_format(&ctx->output, " ethertype: %s\n", lflow_classifier->ethertype);
+ ds_put_format(&ctx->output, " protocol: %s\n", lflow_classifier->protocol);
+ ds_put_format(&ctx->output, " source_port_range_min: %ld\n", lflow_classifier->source_port_range_min);
+ ds_put_format(&ctx->output, " source_port_range_max: %ld\n", lflow_classifier->source_port_range_max);
+ ds_put_format(&ctx->output, " destination_port_range_min: %ld\n", lflow_classifier->destination_port_range_min);
+ ds_put_format(&ctx->output, " destination_port_range_max: %ld\n", lflow_classifier->destination_port_range_max);
+ ds_put_format(&ctx->output, " source_ip_prefix: %ld\n", lflow_classifier->source_ip_prefix);
+ ds_put_format(&ctx->output, " destination_ip_prefix: %ld\n", lflow_classifier->destination_ip_prefix);
+}
+
+static void
+nbctl_lsp_chain_show(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_switch *lswitch;
+ const struct nbrec_logical_port_chain *lsp_chain;
+ printf("\nIn lsp-chain-show\n"); // FIXME(ff): debug, remove this
+ if (ctx->argc < 2) {
+ /* ensure all arguments are present */
+ ctl_fatal("Invalid number of arguments: (%d), to lsp-chain-show.",ctx->argc);
+ }
+ lswitch = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+ ds_put_format(&ctx->output, " lswitch "UUID_FMT" (%s)\n",
+ UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
+ if (ctx->argc == 3) {
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[2]);
+ if (lsp_chain) {
+ print_lsp_chain(lsp_chain, ctx);
+ }
+ } else {
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH(lsp_chain, ctx->idl) {
+ print_lsp_chain(lsp_chain, ctx);
+ }
+ }
+}
+
+
+static void
+nbctl_lsp_chain_set_flow_classifier(struct ctl_context *ctx)
+{
+
+ const struct nbrec_logical_port_chain *lsp_chain;
+ const struct nbrec_logical_flow_classifier *lflow_classifier = NULL;
+
+ if (ctx->argc < 3){
+ /* ensure all arguments are present */
+ ctl_fatal("Invalid number of arguments: (%d), to lsp-chain-set-flow-classifier.",ctx->argc);
+ }
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lsp_chain){
+ ctl_fatal("Invalid port_chain %s ", ctx->argv[1]);
+ }
+ /* Check flow classifier exists*/
+ lflow_classifier = lflow_classifier_by_name_or_uuid(ctx, ctx->argv[2]);
+ if (!lflow_classifier){
+ ctl_fatal("Invalid flow_classifier %s ", ctx->argv[2]);
+ }
+
+ /* Insert the logical flow-classifier into the logical port-chain. */
+ nbrec_logical_port_chain_verify_flow_classifier(lsp_chain);
+ //struct nbrec_logical_flow_classifier **new_flow_classifier= xmalloc(sizeof *new_flow_classifier);
+ //memcpy(new_flow_classifier, lsp_chain->flow_classifier, sizeof *new_flow_classifier);
+ //new_flow_classifier = CONST_CAST(struct nbrec_logical_flow_classifier *, lflow_classifier);
+ //nbrec_logical_port_chain_set_flow_classifier(lsp_chain, new_flow_classifier);
+ nbrec_logical_port_chain_set_flow_classifier(lsp_chain, lflow_classifier); // FIXME (ff): should allow multiple classifiers to same port_chain
+ //free(new_flow_classifier);
+}
+
+static void nbctl_lsp_chain_get_flow_classifier(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_port_chain *lsp_chain;
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, id);
+ ds_put_format(&ctx->output, "%s\n", lsp_chain->flow_classifier->name);
+}
+/* End of port-chain operations */
+
+/*
+ * Port Pair Groups CLI Functions
+ */
+static void
+nbctl_lsp_pair_group_add(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ const struct nbrec_logical_port_chain *lsp_chain;
+
+ /* check lsp_chain exists */
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lsp_chain) {
+ return;
+ }
+
+ if (ctx->argc < 2) {
+ /* ensure all arguments are present */
+ ctl_fatal("invalid number of arguments: %d to lsp-pair-groups-add.", ctx->argc);
}
- return lb;
-}
+ /* create the logical port-pair-group. */
+ lsp_pair_group = nbrec_logical_port_pair_group_insert(ctx->txn);
+ if (ctx->argc == 3){
+ nbrec_logical_port_pair_group_set_name(lsp_pair_group, ctx->argv[2]);
+ }
-/* Given pointer to logical router, this routine prints the router
- * information. */
+ /* Insert the logical port into the logical switch. */
+ nbrec_logical_port_chain_verify_port_pair_groups(lsp_chain);
+ struct nbrec_logical_port_pair_group **new_port_pair_group = xmalloc(sizeof *new_port_pair_group *
+ (lsp_chain->n_port_pair_groups + 1));
+ memcpy(new_port_pair_group, lsp_chain->port_pair_groups, sizeof *new_port_pair_group * lsp_chain->n_port_pair_groups);
+ new_port_pair_group[lsp_chain->n_port_pair_groups] =
+ CONST_CAST(struct nbrec_logical_port_pair_group *,lsp_pair_group);
+ nbrec_logical_port_chain_set_port_pair_groups(lsp_chain, new_port_pair_group, lsp_chain->n_port_pair_groups + 1);
+ free(new_port_pair_group);
+}
+/* Removes lsp-pair-group 'lsp_chain->port_pair_group[idx]'. */
static void
-print_lr(const struct nbrec_logical_router *lr, struct ds *s)
+remove_lsp_pair_group(const struct nbrec_logical_port_chain *lsp_chain, size_t idx)
{
- ds_put_format(s, " router "UUID_FMT" (%s)\n",
- UUID_ARGS(&lr->header_.uuid), lr->name);
+ const struct nbrec_logical_port_pair_group *lsp_pair_group = lsp_chain->port_pair_groups[idx];
- for (size_t i = 0; i < lr->n_ports; i++) {
- const struct nbrec_logical_router_port *lrp = lr->ports[i];
- ds_put_format(s, " port %s\n", lrp->name);
- if (lrp->mac) {
- ds_put_cstr(s, " mac: ");
- ds_put_format(s, "\"%s\"\n", lrp->mac);
- }
- if (lrp->n_networks) {
- ds_put_cstr(s, " networks: [");
- for (size_t j = 0; j < lrp->n_networks; j++) {
- ds_put_format(s, "%s\"%s\"",
- j == 0 ? "" : ", ",
- lrp->networks[j]);
- }
- ds_put_cstr(s, "]\n");
- }
- }
+ /* First remove 'lsp-pair-group' from the array of port-pair-groups. This is what will
+ * actually cause the logical port-pair-group to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_pair_group **new_port_pair_group
+ = xmemdup(lsp_chain->port_pair_groups, sizeof *new_port_pair_group * lsp_chain->n_port_pair_groups);
+ new_port_pair_group[idx] = new_port_pair_group[lsp_chain->n_port_pair_groups - 1];
+ nbrec_logical_port_chain_verify_port_pair_groups(lsp_chain);
+ nbrec_logical_port_chain_set_port_pair_groups(lsp_chain, new_port_pair_group, lsp_chain->n_port_pair_groups - 1);
+ free(new_port_pair_group);
+
+ /* Delete 'lsp-pair-group' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH later. */
+ nbrec_logical_port_pair_group_delete(lsp_pair_group);
}
static void
-print_ls(const struct nbrec_logical_switch *ls, struct ds *s)
+nbctl_lsp_pair_group_del(struct ctl_context *ctx)
{
- ds_put_format(s, " switch "UUID_FMT" (%s)\n",
- UUID_ARGS(&ls->header_.uuid), ls->name);
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
- for (size_t i = 0; i < ls->n_ports; i++) {
- const struct nbrec_logical_switch_port *lsp = ls->ports[i];
+ lsp_pair_group = lsp_pair_group_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lsp_pair_group) {
+ ctl_fatal("Cannot find lsp_pair_group: %s\n", ctx->argv[1]);
+ }
- ds_put_format(s, " port %s\n", lsp->name);
- if (lsp->parent_name) {
- ds_put_format(s, " parent: %s\n", lsp->parent_name);
- }
- if (lsp->n_tag) {
- ds_put_format(s, " tag: %"PRIu64"\n", lsp->tag[0]);
- }
- if (lsp->n_addresses) {
- ds_put_cstr(s, " addresses: [");
- for (size_t j = 0; j < lsp->n_addresses; j++) {
- ds_put_format(s, "%s\"%s\"",
- j == 0 ? "" : ", ",
- lsp->addresses[j]);
+ /* Find the port-chain that contains 'port-pair-group', then delete it. */
+ const struct nbrec_logical_port_chain *lsp_chain;
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH (lsp_chain, ctx->idl) {
+ for (size_t i = 0; i < lsp_chain->n_port_pair_groups; i++) {
+ if (lsp_chain->port_pair_groups[i] == lsp_pair_group) {
+ remove_lsp_pair_group(lsp_chain,i);
+ printf("Deleted lsp-pair-group: %s\n", ctx->argv[1]); // FIXME(ff): debug, remove this
+ return;
}
- ds_put_cstr(s, "]\n");
}
}
+ ctl_fatal("logical port-pair-group %s is not part of any logical port-chain",
+ ctx->argv[1]);
}
static void
-nbctl_init(struct ctl_context *ctx OVS_UNUSED)
+nbctl_lsp_pair_group_list(struct ctl_context *ctx)
{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_port_chain *lsp_chain;
+ struct smap lsp_pair_groups;
+ size_t i;
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, id);
+ if (!lsp_chain) {
+ return;
+ }
+
+ smap_init(&lsp_pair_groups);
+ for (i = 0; i < lsp_chain->n_port_pair_groups; i++) {
+ const struct nbrec_logical_port_pair_group *lsp_pair_group = lsp_chain->port_pair_groups[i];
+ smap_add_format(&lsp_pair_groups, lsp_pair_group->name, UUID_FMT " (%s)",
+ UUID_ARGS(&lsp_pair_group->header_.uuid), lsp_pair_group->name);
+ }
+ const struct smap_node **nodes = smap_sort(&lsp_pair_groups);
+ for (i = 0; i < smap_count(&lsp_pair_groups); i++) {
+ const struct smap_node *node = nodes[i];
+ ds_put_format(&ctx->output, "%s\n", node->value);
+ }
+ smap_destroy(&lsp_pair_groups);
+ free(nodes);
}
static void
-nbctl_pre_sync(struct ctl_context *ctx OVS_UNUSED)
+nbctl_lsp_pair_group_add_port_pair(struct ctl_context *ctx)
{
- if (wait_type != NBCTL_WAIT_NONE) {
- force_wait = true;
- } else {
- VLOG_INFO("\"sync\" command has no effect without --wait");
- }
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ const struct nbrec_logical_port_pair *lsp_pair;
+ const char *lsp_pair_name;
+
+ lsp_pair_group = lsp_pair_group_by_name_or_uuid(ctx, ctx->argv[1]);
+
+ if (ctx->argc < 3) {
+ /* ensure all arguments are present */
+ ctl_fatal("Invalid number of arguments: (%d), to lsp-pair-group-add-port-pair.",ctx->argc);
+ }
+ /* Check that port-pair exists */
+ lsp_pair_name = ctx->argv[2];
+ lsp_pair = lsp_pair_by_name_or_uuid(ctx, lsp_pair_name);
+ if (!lsp_pair){
+ ctl_fatal("%s: an lsp-pair with this name does not exist",lsp_pair_name);
+ }
+
+ /* Insert the logical port-pair into the logical port-pair-group. */
+ nbrec_logical_port_pair_group_verify_port_pairs(lsp_pair_group);
+ struct nbrec_logical_port_pair **new_port_pair = xmalloc(sizeof *new_port_pair *
+ (lsp_pair_group->n_port_pairs + 1));
+ memcpy(new_port_pair, lsp_pair_group->port_pairs, sizeof *new_port_pair * lsp_pair_group->n_port_pairs);
+ new_port_pair[lsp_pair_group->n_port_pairs] = CONST_CAST(struct nbrec_logical_port_pair *, lsp_pair);
+ nbrec_logical_port_pair_group_set_port_pairs(lsp_pair_group, new_port_pair, lsp_pair_group->n_port_pairs + 1);
+ free(new_port_pair);
}
+/* Removes port-pair from port-pair-groiup but does not delete it'. */
static void
-nbctl_sync(struct ctl_context *ctx OVS_UNUSED)
+remove_lsp_pair_from_port_pair_group(const struct nbrec_logical_port_pair_group *lsp_pair_group, size_t idx)
{
+ //TODO Check const struct nbrec_logical_port_pair *lsp_pair = lsp_pair_group->port_pairs[idx];
+
+ /* First remove 'lsp-pair' from the array of port-pairs. This is what will
+ * actually cause the logical port-pair to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_pair **new_port_pair
+ = xmemdup(lsp_pair_group->port_pairs, sizeof *new_port_pair * lsp_pair_group->n_port_pairs);
+ new_port_pair[idx] = new_port_pair[lsp_pair_group->n_port_pairs - 1];
+ nbrec_logical_port_pair_group_verify_port_pairs(lsp_pair_group);
+ nbrec_logical_port_pair_group_set_port_pairs(lsp_pair_group, new_port_pair, lsp_pair_group->n_port_pairs - 1);
+ free(new_port_pair);
+
+ /* Do not delete actual port-pair as they are owned by a lswitch and can be reused. */
+ //nbrec_logical_port_pair_delete(lsp_pair);
}
static void
-nbctl_show(struct ctl_context *ctx)
+nbctl_lsp_pair_group_del_port_pair(struct ctl_context *ctx)
{
- const struct nbrec_logical_switch *ls;
+ const struct nbrec_logical_port_pair *lsp_pair;
- if (ctx->argc == 2) {
- ls = ls_by_name_or_uuid(ctx, ctx->argv[1], false);
- if (ls) {
- print_ls(ls, &ctx->output);
- }
- } else {
- NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
- print_ls(ls, &ctx->output);
- }
+ lsp_pair = lsp_pair_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lsp_pair) {
+ ctl_fatal("Cannot find lsp_pair: %s\n", ctx->argv[1]);
}
- const struct nbrec_logical_router *lr;
- if (ctx->argc == 2) {
- lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
- if (lr) {
- print_lr(lr, &ctx->output);
- }
- } else {
- NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
- print_lr(lr, &ctx->output);
+ /* Find the port-pair_group that contains 'port-pair', then delete it. */
+ const struct nbrec_logical_port_pair_group *lsp_pair_group;
+ NBREC_LOGICAL_PORT_PAIR_GROUP_FOR_EACH (lsp_pair_group, ctx->idl) {
+ for (size_t i = 0; i < lsp_pair_group->n_port_pairs; i++) {
+ if (lsp_pair_group->port_pairs[i] == lsp_pair) {
+ remove_lsp_pair_from_port_pair_group(lsp_pair_group,i);
+ printf("Deleted lsp-pair: %s from lsp-group-pair \n", ctx->argv[1]); // FIXME(ff): debug, remove this
+ return;
+ }
}
}
+ ctl_fatal("logical port-pair %s is not part of any logical switch",
+ ctx->argv[1]);
}
+/* End of port-pair-group operations */
+/*
+ * port-pair operations
+ */
static void
-nbctl_ls_add(struct ctl_context *ctx)
+nbctl_lsp_pair_add(struct ctl_context *ctx)
{
- const char *ls_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
+ const char *port_id_in = ctx->argv[2];
+ const char *port_id_out = ctx->argv[3];
- bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
- bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
- if (may_exist && add_duplicate) {
- ctl_fatal("--may-exist and --add-duplicate may not be used together");
- }
+ const struct nbrec_logical_switch *lswitch;
+ const struct nbrec_logical_port_pair *lsp_pair;
+ const struct nbrec_logical_switch_port *lsp_in,*lsp_out;
- if (ls_name) {
- if (!add_duplicate) {
- const struct nbrec_logical_switch *ls;
- NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
- if (!strcmp(ls->name, ls_name)) {
- if (may_exist) {
- return;
- }
- ctl_fatal("%s: a switch with this name already exists",
- ls_name);
- }
- }
- }
- } else if (may_exist) {
- ctl_fatal("--may-exist requires specifying a name");
- } else if (add_duplicate) {
- ctl_fatal("--add-duplicate requires specifying a name");
+ lswitch = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+ if (ctx->argc < 4) {
+ /* ensure all arguments are present */
+ ctl_fatal("Invalid number of arguments: (%d), to lsp-pair-add.",ctx->argc);
+ }
+ /* Check that ports exist in this switch */
+ lsp_in = lsp_by_name_or_uuid(ctx, port_id_in, false);
+ if (!lsp_in){
+ ctl_fatal("%s: an lsp with this name does not exist",ctx->argv[2]);
+ }
+ lsp_out = lsp_by_name_or_uuid(ctx, port_id_out, false);
+ if (!lsp_out){
+ ctl_fatal("%s: an lsp with this name does not exist",ctx->argv[3]);
}
- struct nbrec_logical_switch *ls;
- ls = nbrec_logical_switch_insert(ctx->txn);
- if (ls_name) {
- nbrec_logical_switch_set_name(ls, ls_name);
+ /* create the logical port-pair. */
+ lsp_pair = nbrec_logical_port_pair_insert(ctx->txn);
+ nbrec_logical_port_pair_set_inport(lsp_pair, lsp_in);
+ nbrec_logical_port_pair_set_outport(lsp_pair, lsp_out);
+ if (ctx->argc == 5){
+ nbrec_logical_port_pair_set_name(lsp_pair, ctx->argv[4]);
}
+
+ /* Insert the logical port-pair into the logical port-pair-group. */
+ nbrec_logical_switch_verify_port_pairs(lswitch);
+ struct nbrec_logical_port_pair **new_port_pair = xmalloc(sizeof *new_port_pair *
+ (lswitch->n_port_pairs + 1));
+ memcpy(new_port_pair, lswitch->port_pairs, sizeof *new_port_pair * lswitch->n_port_pairs);
+ new_port_pair[lswitch->n_port_pairs] = CONST_CAST(struct nbrec_logical_port_pair *, lsp_pair);
+ nbrec_logical_switch_set_port_pairs(lswitch, new_port_pair, lswitch->n_port_pairs + 1);
+ free(new_port_pair);
+}
+/* Removes lswitch->pair_pair[idx]'. */
+static void
+remove_lsp_pair(const struct nbrec_logical_switch *lswitch, size_t idx)
+{
+ const struct nbrec_logical_port_pair *lsp_pair = lswitch->port_pairs[idx];
+
+ /* First remove 'lsp-pair' from the array of port-pairs. This is what will
+ * actually cause the logical port-pair to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port_pair **new_port_pair
+ = xmemdup(lswitch->port_pairs, sizeof *new_port_pair * lswitch->n_port_pairs);
+ new_port_pair[idx] = new_port_pair[lswitch->n_port_pairs - 1];
+ nbrec_logical_switch_verify_port_pairs(lswitch);
+ nbrec_logical_switch_set_port_pairs(lswitch, new_port_pair, lswitch->n_port_pairs - 1);
+ free(new_port_pair);
+
+ /* Delete 'lsp-pair' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_PAIR_FOR_EACH later. */
+ nbrec_logical_port_pair_delete(lsp_pair);
}
static void
-nbctl_ls_del(struct ctl_context *ctx)
+nbctl_lsp_pair_del(struct ctl_context *ctx)
{
- bool must_exist = !shash_find(&ctx->options, "--if-exists");
- const char *id = ctx->argv[1];
- const struct nbrec_logical_switch *ls;
+ const struct nbrec_logical_port_pair *lsp_pair;
- ls = ls_by_name_or_uuid(ctx, id, must_exist);
- if (!ls) {
- return;
+ lsp_pair = lsp_pair_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lsp_pair) {
+ ctl_fatal("Cannot find lsp_pair: %s\n", ctx->argv[1]);
}
- nbrec_logical_switch_delete(ls);
+ /* Find the port-pair_group that contains 'port-pair', then delete it. */
+ const struct nbrec_logical_switch *lswitch;
+ NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
+ for (size_t i = 0; i < lswitch->n_port_pairs; i++) {
+ if (lswitch->port_pairs[i] == lsp_pair) {
+ remove_lsp_pair(lswitch,i);
+ printf("Deleted lsp-pair: %s\n", ctx->argv[1]); // FIXME(ff): debug, remove this
+ return;
+ }
+ }
+ }
+ ctl_fatal("logical port-pair %s is not part of any logical switch",
+ ctx->argv[1]);
}
static void
-nbctl_ls_list(struct ctl_context *ctx)
+nbctl_lsp_pair_list(struct ctl_context *ctx)
{
- const struct nbrec_logical_switch *ls;
- struct smap lswitches;
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_switch *lswitch;
+ struct smap lsp_pairs;
+ size_t i;
- smap_init(&lswitches);
- NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
- smap_add_format(&lswitches, ls->name, UUID_FMT " (%s)",
- UUID_ARGS(&ls->header_.uuid), ls->name);
+ lswitch = ls_by_name_or_uuid(ctx, id, true);
+ if (!lswitch) {
+ return;
}
- const struct smap_node **nodes = smap_sort(&lswitches);
- for (size_t i = 0; i < smap_count(&lswitches); i++) {
+
+ smap_init(&lsp_pairs);
+ for (i = 0; i < lswitch->n_port_pairs; i++) {
+ const struct nbrec_logical_port_pair *lsp_pair = lswitch->port_pairs[i];
+ smap_add_format(&lsp_pairs, lsp_pair->name, UUID_FMT " (%s)",
+ UUID_ARGS(&lsp_pair->header_.uuid), lsp_pair->name);
+ }
+ const struct smap_node **nodes = smap_sort(&lsp_pairs);
+ for (i = 0; i < smap_count(&lsp_pairs); i++) {
const struct smap_node *node = nodes[i];
ds_put_format(&ctx->output, "%s\n", node->value);
}
- smap_destroy(&lswitches);
+ smap_destroy(&lsp_pairs);
free(nodes);
}
-
-static const struct nbrec_logical_switch_port *
-lsp_by_name_or_uuid(struct ctl_context *ctx, const char *id,
- bool must_exist)
+/* End of port-pair operations */
+/*
+ * flow_classifier operations
+ */
+static void
+nbctl_lflow_classifier_add(struct ctl_context *ctx)
{
- const struct nbrec_logical_switch_port *lsp = NULL;
+ const struct nbrec_logical_port_chain *lsp_chain;
+ const struct nbrec_logical_switch_port *lsp;
+ const char *lsp_name;
+ const struct nbrec_logical_flow_classifier *lflow_classifier;
- struct uuid lsp_uuid;
- bool is_uuid = uuid_from_string(&lsp_uuid, id);
- if (is_uuid) {
- lsp = nbrec_logical_switch_port_get_for_uuid(ctx->idl, &lsp_uuid);
+
+ if (ctx->argc < 3) {
+ /* ensure all arguments are present */
+ ctl_fatal("Invalid number of arguments: (%d), to lflow_classifier-add",ctx->argc);
+ }
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, ctx->argv[1]);
+ /* Check that logical source port exist in this switch */
+ lsp_name = ctx->argv[2];
+ lsp = lsp_by_name_or_uuid(ctx, lsp_name, false);
+ if (!lsp){
+ ctl_fatal("%s: a lsp with this name does not exist",lsp_name);
}
- if (!lsp) {
- NBREC_LOGICAL_SWITCH_PORT_FOR_EACH(lsp, ctx->idl) {
- if (!strcmp(lsp->name, id)) {
- break;
- }
+ /* create the logical flow_classifier. */
+ lflow_classifier = nbrec_logical_flow_classifier_insert(ctx->txn);
+ nbrec_logical_flow_classifier_set_logical_source_port(lflow_classifier, lsp);
+ if (ctx->argc == 4){
+ nbrec_logical_flow_classifier_set_name(lflow_classifier, ctx->argv[3]);
+ }
+
+ /* Insert the logical flow_classifier into the logical switch. */
+ nbrec_logical_port_chain_verify_flow_classifier(lsp_chain);
+ //struct nbrec_logical_flow_classifier **new_flow_classifier = xmalloc(sizeof *new_flow_classifier);
+ //memcpy(new_flow_classifier, lswitch->flow_classifiers, sizeof *new_flow_classifier * lswitch->n_flow_classifiers);
+ //new_flow_classifier[lswitch->n_flow_classifiers] = CONST_CAST(struct nbrec_logical_flow_classifier *, lflow_classifier);
+ nbrec_logical_port_chain_set_flow_classifier(lsp_chain, lflow_classifier); // FIXME (ff): should allow multiple classifiers to same port_chain
+ //free(new_flow_classifier);
+}
+static void
+nbctl_lflow_classifier_del(struct ctl_context *ctx)
+{
+ const struct nbrec_logical_flow_classifier *lflow_classifier;
+
+ lflow_classifier = lflow_classifier_by_name_or_uuid(ctx, ctx->argv[1]);
+ if (!lflow_classifier) {
+ printf("Cannot find lflow_classifier: %s\n", ctx->argv[1]); // FIXME(ff): debug, remove this
+ return;
+ }
+
+ /* Find the switch that contains 'flow-classifier', then delete it. */
+ const struct nbrec_logical_port_chain *lsp_chain;
+ NBREC_LOGICAL_PORT_CHAIN_FOR_EACH (lsp_chain, ctx->idl) {
+ if (lsp_chain->flow_classifier == lflow_classifier) {
+ nbrec_logical_flow_classifier_delete(lflow_classifier);
+ printf("Deleted lflow-classifier: %s\n", ctx->argv[1]); // FIXME(ff): debug, remove this
+ return;
}
}
+ ctl_fatal("logical flow-classifier %s is not part of any logical switch",
+ ctx->argv[1]);
+}
- if (!lsp && must_exist) {
- ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
+static void
+nbctl_lflow_classifier_list(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_port_chain *lsp_chain;
+
+
+ lsp_chain = lsp_chain_by_name_or_uuid(ctx, id);
+ if (!lsp_chain) {
+ return;
}
+ const struct nbrec_logical_flow_classifier *lflow_classifier = lsp_chain->flow_classifier;
+ printf("Getting flow classifier: %s\n", lflow_classifier->name); // FIXME(ff): debug, remove this
+ ds_put_format(&ctx->output, " lflow_classifier %s\n", lflow_classifier->name);
+ ds_put_format(&ctx->output, " logical-source-port %s\n", lflow_classifier->logical_source_port->name);
+ ds_put_format(&ctx->output, " ethertype: %s\n", lflow_classifier->ethertype);
+ ds_put_format(&ctx->output, " protocol: %s\n", lflow_classifier->protocol);
- return lsp;
}
+static void
+nbctl_lflow_classifier_set_logical_destination_port(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_switch_port *lsp = NULL;
+ const struct nbrec_logical_flow_classifier *lflow_classifier;
+
+ lflow_classifier = lflow_classifier_by_name_or_uuid(ctx, id);
+
+ /* Check port exists if given*/
+ if (!strcmp(ctx->argv[2],"") ){
+ lsp = lsp_by_name_or_uuid(ctx, ctx->argv[2], true);
+ if (!lsp){
+ ctl_fatal("Invalid port %s ", ctx->argv[2]);
+ }
+ }
+ nbrec_logical_flow_classifier_set_logical_destination_port(lflow_classifier,lsp);
+}
+
+static void
+nbctl_lflow_classifier_get_logical_destination_port(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_flow_classifier *lflow_classifier;
+
+ lflow_classifier = lflow_classifier_by_name_or_uuid(ctx, id);
+ ds_put_format(&ctx->output, "%s\n", (lflow_classifier->logical_destination_port)->name);
+}
+/* End of flow-classifier operations */
+
+
+
+
/* Returns the logical switch that contains 'lsp'. */
static const struct nbrec_logical_switch *
lsp_to_ls(const struct ovsdb_idl *idl,
@@ -1296,12 +2839,33 @@ nbctl_acl_add(struct ctl_context *ctx)
/* Validate action. */
if (strcmp(action, "allow") && strcmp(action, "allow-related")
- && strcmp(action, "drop") && strcmp(action, "reject")) {
+ && strcmp(action, "drop") && strcmp(action, "reject")
+ && strcmp(action, "sfc")) {
ctl_fatal("%s: action must be one of \"allow\", \"allow-related\", "
- "\"drop\", and \"reject\"", action);
+ "\"drop\", \"reject\" and \"sfc\"", action);
return;
}
+ /* Validate ACL Options, if there were any provided. */
+ struct smap acl_options = SMAP_INITIALIZER(&acl_options);
+ if (ctx->argc >= 7) {
+ struct sset acl_options_set;
+ sset_from_delimited_string(&acl_options_set, ctx->argv[6], " ");
+
+ const char *acl_option_tuple;
+ SSET_FOR_EACH (acl_option_tuple, &acl_options_set) {
+ char *key, *value;
+ value = xstrdup(acl_option_tuple);
+ key = strsep(&value, "=");
+ if (value) {
+ smap_add(&acl_options, key, value);
+ }
+ free(key);
+ }
+
+ sset_destroy(&acl_options_set);
+ }
+
/* Create the acl. */
struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
nbrec_acl_set_priority(acl, priority);
@@ -1311,6 +2875,9 @@ nbctl_acl_add(struct ctl_context *ctx)
if (shash_find(&ctx->options, "--log") != NULL) {
nbrec_acl_set_log(acl, true);
}
+ if (! smap_is_empty(&acl_options)) {
+ nbrec_acl_set_options(acl, &acl_options);
+ }
/* Insert the acl into the logical switch. */
nbrec_logical_switch_verify_acls(ls);
@@ -1319,6 +2886,8 @@ nbctl_acl_add(struct ctl_context *ctx)
new_acls[ls->n_acls] = acl;
nbrec_logical_switch_set_acls(ls, new_acls, ls->n_acls + 1);
free(new_acls);
+
+ smap_destroy(&acl_options);
}
static void
@@ -2978,6 +4547,22 @@ static const struct ctl_table_class tables[] = {
{{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
{NULL, NULL, NULL}}},
+ {&nbrec_table_logical_port_chain,
+ {{&nbrec_table_logical_port_chain, &nbrec_logical_port_chain_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&nbrec_table_logical_port_pair_group,
+ {{&nbrec_table_logical_port_pair_group, &nbrec_logical_port_pair_group_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&nbrec_table_logical_port_pair,
+ {{&nbrec_table_logical_port_pair, &nbrec_logical_port_pair_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&nbrec_table_logical_flow_classifier,
+ {{&nbrec_table_logical_flow_classifier, &nbrec_logical_flow_classifier_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
{&nbrec_table_logical_switch_port,
{{&nbrec_table_logical_switch_port, &nbrec_logical_switch_port_col_name,
NULL},
@@ -3276,6 +4861,74 @@ static const struct ctl_command_syntax nbctl_commands[] = {
{ "init", 0, 0, "", NULL, nbctl_init, NULL, "", RW },
{ "sync", 0, 0, "", nbctl_pre_sync, nbctl_sync, NULL, "", RO },
{ "show", 0, 1, "[SWITCH]", NULL, nbctl_show, NULL, "", RO },
+ /* lsp-chain commands. */
+ { "lsp-chain-add", 1, 2, "LSWITCH,[LSP-CHAIN]", NULL, nbctl_lsp_chain_add,
+ NULL, "", RW },
+ { "lsp-chain-del", 1, 1, "LSP-CHAIN", NULL, nbctl_lsp_chain_del,
+ NULL, "--if-exists", RW },
+ { "lsp-chain-list", 1, 1, "LSWITCH", NULL, nbctl_lsp_chain_list, NULL, "", RO },
+ { "lsp-chain-show", 1, 2, "LSWITCH [LSP-CHAIN]", NULL, nbctl_lsp_chain_show, NULL, "", RO },
+ { "lsp-chain-get-flow-classifier", 1, 1, "LSP-CHAIN", NULL,
+ nbctl_lsp_chain_get_flow_classifier, NULL, "", RO },
+ { "lsp-chain-set-flow-classifier", 2, 2, "LSP-CHAIN LFLOW-CLASSIFIER", NULL,
+ nbctl_lsp_chain_set_flow_classifier, NULL, "", RW },
+
+ /* lsp-pair-group commands. */
+ { "lsp-pair-group-add", 1, 2, "LSP-CHAIN [LSP-PAIR-GROUP]",
+ NULL, nbctl_lsp_pair_group_add, NULL, "", RW },
+ { "lsp-pair-group-del", 2, 2, "LSP-CHAIN, LSP-PAIR-GROUP", NULL, nbctl_lsp_pair_group_del,
+ NULL, "", RW },
+ { "lsp-pair-group-list", 1, 1, "LSP_CHAIN", NULL, nbctl_lsp_pair_group_list, NULL, "", RO },
+ { "lsp-pair-group-add-port-pair", 2, 2, "LSP-PAIR-GROUP LSP-PAIR",
+ NULL, nbctl_lsp_pair_group_add_port_pair, NULL, "", RW },
+ { "lsp-pair-group-del-port-pair", 2, 2, "LSP-PAIR-GROUP LSP-PAIR",
+ NULL, nbctl_lsp_pair_group_del_port_pair, NULL, "", RW },
+
+ /* lsp-pair commands. */
+ { "lsp-pair-add", 3, 4, "LSWITCH, LSP, LSP [LSP_PAIR_NAME]", NULL, nbctl_lsp_pair_add,
+ NULL, "", RW },
+ { "lsp-pair-del", 1, 1, "LSP-PAIR", NULL, nbctl_lsp_pair_del,
+ NULL, "", RW },
+ { "lsp-pair-list", 1, 1, "LSWITCH", NULL, nbctl_lsp_pair_list, NULL, "", RO },
+
+ /* lflow-classifier commands. */
+ { "lflow-classifier-add", 2, 3, "LSP-CHAIN LSOURCE_PORT [LFLOW-CLASSIFIER-NAME]", NULL,
+ nbctl_lflow_classifier_add, NULL, "", RW },
+ { "lflow-classifier-del", 1, 1, "LFLOW-CLASSIFIER", NULL,
+ nbctl_lflow_classifier_del, NULL, "", RW },
+ { "lflow-classifier-list", 1, 1, "LSP-CHAIN", NULL, nbctl_lflow_classifier_list,
+ NULL, "", RO },
+ { "lflow-classifier-get-logical-destination-port", 1, 1, "LFLOW-CLASSIFIER", NULL,
+ nbctl_lflow_classifier_get_logical_destination_port, NULL, "", RO },
+ { "lflow-classifier-set-logical-destination-port", 2, 2, "LFLOW-CLASSIFIER LDESTINATION_PORT", NULL,
+ nbctl_lflow_classifier_set_logical_destination_port, NULL, "", RO },
+ /* TODO ADD OTHER FLOW-CLASSIFIER PARAMETERS */
+
+ /* lsp-chain commands. */
+ { "lsp-chain-add", 2, 3, "SWITCH [CHAIN] LAST_PORT", NULL, nbctl_lsp_chain_add,
+ NULL, "--may-exist,--add-duplicate", RW },
+ { "lsp-chain-del", 1, 1, "CHAIN", NULL, nbctl_lsp_chain_del,
+ NULL, "--if-exists", RW },
+ { "lsp-chain-list", 0, 2, "[SWITCH [CHAIN]]", NULL, nbctl_lsp_chain_list, NULL, "", RO },
+ { "lsp-chain-show", 0, 1, "[CHAIN]", NULL, nbctl_lsp_chain_show, NULL, "", RO },
+
+ /* lsp-pair-group commands. */
+ { "lsp-pair-group-add", 1, 3, "CHAIN [PAIR-GROUP [OFFSET]]",
+ NULL, nbctl_lsp_pair_group_add, NULL, "--may-exist,--add-duplicate", RW },
+ { "lsp-pair-group-del", 1, 1, "PAIR-GROUP", NULL, nbctl_lsp_pair_group_del,
+ NULL, "--if-exists", RW },
+ { "lsp-pair-group-list", 1, 1, "CHAIN", NULL, nbctl_lsp_pair_group_list, NULL, "", RO },
+ { "lsp-pair-group-add-port-pair", 2, 2, "PAIR-GROUP LSP-PAIR",
+ NULL, nbctl_lsp_pair_group_add_port_pair, NULL, "--may-exist", RW },
+ { "lsp-pair-group-del-port-pair", 2, 2, "PAIR-GROUP LSP-PAIR",
+ NULL, nbctl_lsp_pair_group_del_port_pair, NULL, "--if-exists", RW },
+
+ /* lsp-pair commands. */
+ { "lsp-pair-add", 3, 4, "SWITCH, PORT-IN, PORT-OUT [LSP-PAIR]", NULL, nbctl_lsp_pair_add,
+ NULL, "--may-exist,--add-duplicate", RW },
+ { "lsp-pair-del", 1, 1, "LSP-PAIR", NULL, nbctl_lsp_pair_del,
+ NULL, "--if-exists", RW },
+ { "lsp-pair-list", 0, 2, "[SWITCH [LSP-PAIR]]", NULL, nbctl_lsp_pair_list, NULL, "", RO },
/* logical switch commands. */
{ "ls-add", 0, 1, "[SWITCH]", NULL, nbctl_ls_add, NULL,
@@ -3284,7 +4937,7 @@ static const struct ctl_command_syntax nbctl_commands[] = {
{ "ls-list", 0, 0, "", NULL, nbctl_ls_list, NULL, "", RO },
/* acl commands. */
- { "acl-add", 5, 5, "SWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
+ { "acl-add", 5, 6, "SWITCH DIRECTION PRIORITY MATCH ACTION [ACL-OPTIONS]", NULL,
nbctl_acl_add, NULL, "--log", RW },
{ "acl-del", 1, 4, "SWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
nbctl_acl_del, NULL, "", RW },
--
2.11.0
More information about the dev
mailing list