[ovs-dev] [PATCH] ovn: Add lflow-list to ovn-sbctl.
Alex Wang
alexw at nicira.com
Tue Aug 11 17:48:30 UTC 2015
Thx, this is really really useful!!!
Just few minor suggestions below,
On Mon, Aug 10, 2015 at 8:33 PM, Russell Bryant <rbryant at redhat.com> wrote:
> I frequently view the contents of the Logical_Flow table while working
> on OVN. Add a patch that can output the contents of this table in a
> sorted way that makes it easier to read through. It's sorted by
> logical datapath, pipeline, table id, priority, and match.
>
> Signed-off-by: Russell Bryant <rbryant at redhat.com>
> ---
> ovn/utilities/ovn-sbctl.8.in | 6 +++
> ovn/utilities/ovn-sbctl.c | 94
> ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 100 insertions(+)
>
> Example output:
>
> $ ./ovn-2port-setup.sh
> + ovn-nbctl lswitch-add sw0
> + ovn-nbctl lport-add sw0 sw0-port1
> + ovn-nbctl lport-add sw0 sw0-port2
> + ovn-nbctl lport-set-macs sw0-port1 00:00:00:00:00:01
> + ovn-nbctl lport-set-macs sw0-port2 00:00:00:00:00:02
> + ovn-nbctl lport-set-port-security sw0-port1 00:00:00:00:00:01
> + ovn-nbctl lport-set-port-security sw0-port2 00:00:00:00:00:02
> + ovs-vsctl add-port br-int lport1 -- set Interface lport1
> external_ids:iface-id=sw0-port1
> + ovs-vsctl add-port br-int lport2 -- set Interface lport2
> external_ids:iface-id=sw0-port2
>
> $ ovn-sbctl lflow-list
> Datapath: 03f8a791-b5bb-47b6-b373-09b75b8e26f3 Pipeline: ingress
> table_id=0, priority=100, match=(eth.src[40]), action=(drop;)
> table_id=0, priority=100, match=(vlan.present), action=(drop;)
> table_id=0, priority= 50, match=(inport == "sw0-port1" && eth.src ==
> {00:00:00:00:00:01}), action=(next;)
> table_id=0, priority= 50, match=(inport == "sw0-port2" && eth.src ==
> {00:00:00:00:00:02}), action=(next;)
> table_id=0, priority= 0, match=(1), action=(drop;)
> table_id=1, priority=100, match=(eth.dst[40]), action=(outport =
> "_MC_flood"; output;)
> table_id=1, priority= 50, match=(eth.dst == 00:00:00:00:00:01),
> action=(outport = "sw0-port1"; output;)
> table_id=1, priority= 50, match=(eth.dst == 00:00:00:00:00:02),
> action=(outport = "sw0-port2"; output;)
> Datapath: 03f8a791-b5bb-47b6-b373-09b75b8e26f3 Pipeline: egress
> table_id=0, priority= 0, match=(1), action=(next;)
> table_id=1, priority=100, match=(eth.dst[40]), action=(output;)
> table_id=1, priority= 50, match=(outport == "sw0-port1" && eth.dst ==
> {00:00:00:00:00:01}), action=(output;)
> table_id=1, priority= 50, match=(outport == "sw0-port2" && eth.dst ==
> {00:00:00:00:00:02}), action=(output;)
>
>
> diff --git a/ovn/utilities/ovn-sbctl.8.in b/ovn/utilities/ovn-sbctl.8.in
> index b5c796e..9f9168e 100644
> --- a/ovn/utilities/ovn-sbctl.8.in
> +++ b/ovn/utilities/ovn-sbctl.8.in
> @@ -146,6 +146,12 @@ Without \fB\-\-if\-exists\fR, attempting to unbind a
> logical port
> that is not bound is an error. With \fB\-\-if\-exists\fR, attempting
> to unbind logical port that is not bound has no effect.
> .
> +.SS "Logical Flow Commands"
> +.
> +.IP "\fBlflow\-list\fR [\fIlogical\-datapath\fR]"
> +List logical flows. If \fIlogical\-datapath\fR is specified, only list
> flows for
> +that logical datapath.
> +.
> .so lib/db-ctl-base.man
> .SH "EXIT STATUS"
> .IP "0"
> diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c
> index cbde60a..0bcb795 100644
> --- a/ovn/utilities/ovn-sbctl.c
> +++ b/ovn/utilities/ovn-sbctl.c
> @@ -300,6 +300,9 @@ Port binding commands:\n\
> lport-bind LPORT CHASSIS bind logical port LPORT to CHASSIS\n\
> lport-unbind LPORT reset the port binding of logical port
> LPORT\n\
> \n\
> +Logical flow commands:\n\
> + lflow-list [DATAPATH] List logical flows for all or a single
> datapath\n\
> +\n\
> %s\
> \n\
> Options:\n\
> @@ -470,6 +473,13 @@ pre_get_info(struct ctl_context *ctx)
>
> ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_logical_port);
> ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_chassis);
> +
> + ovsdb_idl_add_column(ctx->idl,
> &sbrec_logical_flow_col_logical_datapath);
> + ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_pipeline);
> + ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_actions);
> + ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_priority);
> + ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_table_id);
> + ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_match);
> }
>
> static struct cmd_show_table cmd_show_tables[] = {
> @@ -584,6 +594,86 @@ cmd_lport_unbind(struct ctl_context *ctx)
> }
> }
>
> +static int
> +lflow_cmp(const void *lf1_, const void *lf2_)
> +{
> + const struct sbrec_logical_flow *lf1, *lf2;
> +
> + lf1 = *((struct sbrec_logical_flow **) lf1_);
> + lf2 = *((struct sbrec_logical_flow **) lf2_);
> +
> +#define CMP(expr) \
> + do { \
> + int res; \
> + res = (expr); \
> + if (res) { \
> + return res; \
> + } \
> + } while (0)
> +
> + CMP(memcmp(&lf1->logical_datapath->header_.uuid,
> + &lf2->logical_datapath->header_.uuid,
> + sizeof(lf1->logical_datapath->header_.uuid)));
>
We have a uuid_compare_3way() function defined in lib/uuid.c, should
we use that?
> + CMP(strcmp(lf1->pipeline, lf2->pipeline) * -1);
>
Could we add an encode function that associate each type with an
enum'ed number?
enum pipeline_type {
PL_INGRESS,
PL_EGRESS,
};
and in the encode function, call OVS_NOT_REACHED() if the pipeline is
neither "ingress" or "egress"... so we can catch future changes,
> + CMP(lf1->table_id > lf2->table_id ? 1 :
> + (lf1->table_id < lf2->table_id ? -1 : 0));
> + CMP(lf1->priority > lf2->priority ? -1 :
> + (lf1->priority < lf2->priority ? 1 : 0));
> + CMP(strcmp(lf1->match, lf2->match));
> +
> +#undef CMP
> +
> + return 0;
> +}
> +
> +static void
> +cmd_lflow_list(struct ctl_context *ctx)
> +{
> + const char *datapath = ctx->argc == 2 ? ctx->argv[1] : NULL;
> + struct uuid datapath_uuid = { .parts = { 0, }};
> + const struct sbrec_logical_flow **lflows;
> + const struct sbrec_logical_flow *lflow;
> + size_t n_flows = 0, n_capacity = 64;
> +
> + if (datapath && !uuid_from_string(&datapath_uuid, datapath)) {
> + VLOG_ERR("Invalid format of datapath UUID");
> + return;
> + }
> +
> + lflows = xmalloc(sizeof *lflows * n_capacity);
> + SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->idl) {
> + if (n_flows == n_capacity) {
> + n_capacity *= 2;
> + lflows = xrealloc(lflows, sizeof *lflows * n_capacity);
> + }
> + lflows[n_flows] = lflow;
> + n_flows++;
> + }
> +
>
We also have x2nrealloc() defined in lib/util.c,~
> + qsort(lflows, n_flows, sizeof *lflows, lflow_cmp);
> +
> + const char *cur_pipeline = "";
> + size_t i;
> + for (i = 0; i < n_flows; i++) {
> + lflow = lflows[i];
> + if (datapath && !uuid_equals(&datapath_uuid,
> +
> &lflow->logical_datapath->header_.uuid)) {
> + continue;
> + }
> + if (strcmp(cur_pipeline, lflow->pipeline)) {
> + printf("Datapath: " UUID_FMT " Pipeline: %s\n",
> + UUID_ARGS(&lflow->logical_datapath->header_.uuid),
> + lflow->pipeline);
> + cur_pipeline = lflow->pipeline;
> + }
> + printf(" table_id=%" PRId64 ", priority=%3" PRId64 ", "
> + "match=(%s), action=(%s)\n",
> + lflow->table_id, lflow->priority,
> + lflow->match, lflow->actions);
> + }
> +
> + free(lflows);
> +}
>
> static const struct ctl_table_class tables[] = {
> {&sbrec_table_chassis,
> @@ -858,6 +948,10 @@ static const struct ctl_command_syntax
> sbctl_commands[] = {
> {"lport-unbind", 1, 1, "LPORT", pre_get_info, cmd_lport_unbind, NULL,
> "--if-exists", RW},
>
> + /* Logical flow commands */
> + {"lflow-list", 0, 1, "[DATAPATH]", pre_get_info, cmd_lflow_list, NULL,
> + "", RO},
> +
> /* SSL commands (To Be Added). */
>
> {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
> --
> 2.4.3
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
More information about the dev
mailing list