mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
db-ctl-base: Added filter option in show command.
The --filter option allows filtering output in two ways: 1. Basic filtering (comma-separated list, e.g., 'filter1,filter2'). 2. Recursive filtering by table (e.g., 'interface(geneve)'). Signed-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
parent
943f9096e2
commit
6f2ca3fb26
1
NEWS
1
NEWS
@ -26,6 +26,7 @@ Post-v3.5.0
|
||||
ovs-vswitchd to finish reconfiguring itself after a successful
|
||||
database transaction. E.g., when ovs-vswitchd fails to add a new
|
||||
port or a bridge.
|
||||
* Added '--filter' option to the 'show' command.
|
||||
- SSL/TLS:
|
||||
* Support for deprecated TLSv1 and TLSv1.1 protocols on OpenFlow and
|
||||
database connections is now removed.
|
||||
|
@ -2143,14 +2143,40 @@ cmd_show_weak_ref(struct ctl_context *ctx, const struct cmd_show_table *show,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
table_filter(struct ctl_context *ctx,
|
||||
const struct cmd_show_table *show,
|
||||
const struct shash *filters, size_t base_length)
|
||||
{
|
||||
if (!show || !show->table || shash_is_empty(filters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *table_name = show->table->name;
|
||||
struct sset *table_filter = shash_find_data(filters, table_name);
|
||||
|
||||
if (table_filter) {
|
||||
const char *output = &ctx->output.string[base_length];
|
||||
const char *value;
|
||||
|
||||
SSET_FOR_EACH (value, table_filter) {
|
||||
if (strcasestr(output, value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ds_truncate(&ctx->output, base_length);
|
||||
}
|
||||
}
|
||||
|
||||
/* 'shown' records the tables that has been displayed by the current
|
||||
* command to avoid duplicated prints.
|
||||
*/
|
||||
static void
|
||||
cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
|
||||
int level, struct sset *shown)
|
||||
int level, struct sset *shown, const struct shash *filters)
|
||||
{
|
||||
const struct cmd_show_table *show = cmd_show_find_table_by_row(row);
|
||||
size_t start_pos = ctx->output.length;
|
||||
size_t i;
|
||||
|
||||
ds_put_char_multiple(&ctx->output, ' ', level * 4);
|
||||
@ -2194,7 +2220,7 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
|
||||
ref_show->table,
|
||||
&datum->keys[j].uuid);
|
||||
if (ref_row) {
|
||||
cmd_show_row(ctx, ref_row, level + 1, shown);
|
||||
cmd_show_row(ctx, ref_row, level + 1, shown, filters);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@ -2249,6 +2275,85 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
|
||||
}
|
||||
cmd_show_weak_ref(ctx, show, row, level);
|
||||
sset_find_and_delete_assert(shown, show->table->name);
|
||||
|
||||
table_filter(ctx, show, filters, start_pos);
|
||||
}
|
||||
|
||||
static char * OVS_WARN_UNUSED_RESULT
|
||||
init_filters(const char *filter_str,
|
||||
const struct ovsdb_idl_table_class *top_table,
|
||||
struct shash *filters)
|
||||
{
|
||||
struct sset initialized_filters;
|
||||
char *error = NULL;
|
||||
const char *item;
|
||||
|
||||
sset_init(&initialized_filters);
|
||||
sset_from_delimited_string(&initialized_filters, filter_str, ",");
|
||||
|
||||
SSET_FOR_EACH (item, &initialized_filters) {
|
||||
const struct ovsdb_idl_table_class *table;
|
||||
const char *ptr = strchr(item, '(');
|
||||
size_t len = strlen(item);
|
||||
char *table_name = NULL;
|
||||
char *values = NULL;
|
||||
|
||||
struct sset parsed_values;
|
||||
sset_init(&parsed_values);
|
||||
|
||||
if (ptr && item[len - 1] == ')') {
|
||||
table_name = xmemdup0(item, ptr - item);
|
||||
error = get_table(table_name, &table);
|
||||
if (error) {
|
||||
goto cleanup_item;
|
||||
}
|
||||
values = xmemdup0(ptr + 1, len - (ptr - item + 2));
|
||||
} else if (!ptr) {
|
||||
table = top_table;
|
||||
values = xstrdup(item);
|
||||
} else {
|
||||
error = xasprintf("Malformed filter: missing closing ')'");
|
||||
goto cleanup_item;
|
||||
}
|
||||
|
||||
sset_from_delimited_string(&parsed_values, values, "|");
|
||||
|
||||
struct sset *value_set = shash_find_data(filters, table->name);
|
||||
if (!value_set) {
|
||||
value_set = xzalloc(sizeof *value_set);
|
||||
sset_init(value_set);
|
||||
shash_add(filters, table->name, value_set);
|
||||
}
|
||||
|
||||
const char *v;
|
||||
SSET_FOR_EACH (v, &parsed_values) {
|
||||
sset_add(value_set, v);
|
||||
}
|
||||
|
||||
cleanup_item:
|
||||
sset_destroy(&parsed_values);
|
||||
free(table_name);
|
||||
free(values);
|
||||
if (error) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
sset_destroy(&initialized_filters);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_filters(struct shash *filters)
|
||||
{
|
||||
struct shash_node *node;
|
||||
SHASH_FOR_EACH (node, filters) {
|
||||
struct sset *value_set = node->data;
|
||||
sset_destroy(value_set);
|
||||
free(value_set);
|
||||
}
|
||||
shash_destroy(filters);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2256,12 +2361,25 @@ cmd_show(struct ctl_context *ctx)
|
||||
{
|
||||
const struct ovsdb_idl_row *row;
|
||||
struct sset shown = SSET_INITIALIZER(&shown);
|
||||
struct shash filters = SHASH_INITIALIZER(&filters);
|
||||
|
||||
char *filter_str = shash_find_data(&ctx->options, "--filter");
|
||||
if (filter_str && *filter_str) {
|
||||
char *error = init_filters(filter_str,
|
||||
cmd_show_tables[0].table, &filters);
|
||||
if (error) {
|
||||
destroy_filters(&filters);
|
||||
ctx->error = error;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (row = ovsdb_idl_first_row(ctx->idl, cmd_show_tables[0].table);
|
||||
row; row = ovsdb_idl_next_row(row)) {
|
||||
cmd_show_row(ctx, row, 0, &shown);
|
||||
cmd_show_row(ctx, row, 0, &shown, &filters);
|
||||
}
|
||||
|
||||
destroy_filters(&filters);
|
||||
ovs_assert(sset_is_empty(&shown));
|
||||
sset_destroy(&shown);
|
||||
}
|
||||
@ -2556,7 +2674,7 @@ ctl_init__(const struct ovsdb_idl_class *idl_class_,
|
||||
cmd_show_tables = cmd_show_tables_;
|
||||
if (cmd_show_tables) {
|
||||
static const struct ctl_command_syntax show =
|
||||
{"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO};
|
||||
{"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "--filter=", RO};
|
||||
ctl_register_command(&show);
|
||||
}
|
||||
}
|
||||
|
@ -1859,3 +1859,92 @@ OVS_VSWITCHD_STOP(["/is not a valid IP address/d
|
||||
/netdev_vport|WARN|gre0: bad ip6gre 'remote_ip'/d
|
||||
/netdev|WARN|gre0: could not set configuration/d"])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ovs-vsctl filter option usage])
|
||||
AT_KEYWORDS([ovs-vsctl filter option])
|
||||
|
||||
OVS_VSWITCHD_START([dnl
|
||||
add-port br0 p1 -- set Interface p1 type=internal ofport_request=1 -- \
|
||||
add-port br0 tunnel_port \
|
||||
-- set Interface tunnel_port type=geneve \
|
||||
options:remote_ip=1.2.3.4 options:key=123 -- \
|
||||
add-port br0 tunnel_port2 \
|
||||
-- set Interface tunnel_port2 type=geneve \
|
||||
options:remote_ip=1.2.3.5 options:key=125
|
||||
])
|
||||
|
||||
m4_define([FILTER], [grep -E '(Port|Interface)' | sort])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='geneve,interface(1.2.3.5)' show | FILTER], [0], [dnl
|
||||
Interface tunnel_port2
|
||||
Port br0
|
||||
Port p1
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='interface(1.2.3.5),geneve' show | FILTER], [0], [dnl
|
||||
Interface tunnel_port2
|
||||
Port br0
|
||||
Port p1
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='interface(1.2.3.5)' show | FILTER], [0], [dnl
|
||||
Interface tunnel_port2
|
||||
Port br0
|
||||
Port p1
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='geneve' show | FILTER], [0], [dnl
|
||||
Interface br0
|
||||
Interface p1
|
||||
Interface tunnel_port
|
||||
Interface tunnel_port2
|
||||
Port br0
|
||||
Port p1
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='port(geneve),interface(1.2.3.5)' show | FILTER], [0], [dnl
|
||||
Interface tunnel_port2
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='port(geneve),interface(123|125)' show | FILTER], [0], [dnl
|
||||
Interface tunnel_port
|
||||
Interface tunnel_port2
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='interface(geneve)' show | FILTER], [0], [dnl
|
||||
Interface tunnel_port
|
||||
Interface tunnel_port2
|
||||
Port br0
|
||||
Port p1
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='interface(p1),interface(p2)' show | FILTER], [0], [dnl
|
||||
Interface p1
|
||||
Port br0
|
||||
Port p1
|
||||
Port tunnel_port
|
||||
Port tunnel_port2
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter='interface1(p1)' show], [1], [stdout], [dnl
|
||||
ovs-vsctl: unknown table "interface1"
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl --filter=$'interface\x28p1' show], [1], [stdout], [dnl
|
||||
ovs-vsctl: Malformed filter: missing closing ')'
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
|
@ -150,8 +150,12 @@ Any successful \fBovs\-vsctl\fR command automatically initializes the
|
||||
Open vSwitch database if it is empty. This command is provided to
|
||||
initialize the database without executing any other command.
|
||||
.
|
||||
.IP "\fBshow\fR"
|
||||
Prints a brief overview of the database contents.
|
||||
.IP "[\fB\-\-filter\fR=\fIfilter\-rule\fR[,\fIfilter\-rule\fR]...] \fBshow\fR"
|
||||
Prints a brief overview of the database contents. If \fB\-\-filter\fR is
|
||||
specified, output is filtered according to the rules. Each \fIfilter\-rule\fR
|
||||
has the form \fBtable\-name\fR(\fIfilter\fR[|\fIfilter\fR]...). The row in
|
||||
this table is shown only if the printed version of it, including all the rows
|
||||
referenced from this one, contains one of the \fIfilter\fRs as a sub-string.
|
||||
.
|
||||
.IP "\fBemer\-reset\fR"
|
||||
Reset the configuration into a clean state. It deconfigures OpenFlow
|
||||
|
Loading…
x
Reference in New Issue
Block a user