2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

Support accepting and displaying port names in OVS tools.

Until now, most ovs-ofctl commands have not accepted names for ports, only
numbers, and have not been able to display port names either.  It's a lot
easier for users if they can use and see meaningful names instead of
arbitrary numbers.  This commit adds that support.

For backward compatibility, only interactive ovs-ofctl commands by default
display port names; to display them in scripts, use the new --names
option.

Signed-off-by: Ben Pfaff <blp@ovn.org>
Tested-by: Aaron Conole <aconole@redhat.com>
This commit is contained in:
Ben Pfaff
2017-05-31 16:06:12 -07:00
parent 52182c5f50
commit 50f96b10e1
45 changed files with 1383 additions and 617 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
* Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -235,7 +235,8 @@ parse_protocol(const char *name, const struct protocol **p_out)
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
static char * OVS_WARN_UNUSED_RESULT
parse_field(const struct mf_field *mf, const char *s, struct match *match,
parse_field(const struct mf_field *mf, const char *s,
const struct ofputil_port_map *port_map, struct match *match,
enum ofputil_protocol *usable_protocols)
{
union mf_value value, mask;
@@ -247,7 +248,7 @@ parse_field(const struct mf_field *mf, const char *s, struct match *match,
s = "0/0";
}
error = mf_parse(mf, s, &value, &mask);
error = mf_parse(mf, s, port_map, &value, &mask);
if (!error) {
*usable_protocols &= mf_set(mf, &value, &mask, match, &error);
}
@@ -281,7 +282,7 @@ parse_subfield(const char *name, const char *str_value, struct match *match,
struct ds ds;
ds_init(&ds);
mf_format(sf.field, &val, NULL, &ds);
mf_format(sf.field, &val, NULL, NULL, &ds);
error = xasprintf("%s: value %s does not fit into %d bits",
name, ds_cstr(&ds), sf.n_bits);
ds_destroy(&ds);
@@ -316,6 +317,7 @@ extract_actions(char *s)
static char * OVS_WARN_UNUSED_RESULT
parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
enum {
@@ -431,7 +433,8 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
|| !strcmp(name, "allow_hidden_fields")) {
/* ignore these fields. */
} else if ((mf = mf_from_name(name)) != NULL) {
error = parse_field(mf, value, &fm->match, usable_protocols);
error = parse_field(mf, value, port_map,
&fm->match, usable_protocols);
} else if (strchr(name, '[')) {
error = parse_subfield(name, value, &fm->match, usable_protocols);
} else {
@@ -445,7 +448,8 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
*usable_protocols &= OFPUTIL_P_TID;
}
} else if (fields & F_OUT_PORT && !strcmp(name, "out_port")) {
if (!ofputil_port_from_string(value, &fm->out_port)) {
if (!ofputil_port_from_string(value, port_map,
&fm->out_port)) {
error = xasprintf("%s is not a valid OpenFlow port",
value);
}
@@ -540,7 +544,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
char *error;
ofpbuf_init(&ofpacts, 32);
error = ofpacts_parse_instructions(act_str, &ofpacts,
error = ofpacts_parse_instructions(act_str, port_map, &ofpacts,
&action_usable_protocols);
*usable_protocols &= action_usable_protocols;
if (!error) {
@@ -588,12 +592,13 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
* error. The caller is responsible for freeing the returned string. */
char * OVS_WARN_UNUSED_RESULT
parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
char *string = xstrdup(str_);
char *error;
error = parse_ofp_str__(fm, command, string, usable_protocols);
error = parse_ofp_str__(fm, command, string, port_map, usable_protocols);
if (error) {
fm->ofpacts = NULL;
fm->ofpacts_len = 0;
@@ -607,6 +612,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
* both 'po->ofpacts' and 'po->packet' must be free()d by the caller. */
static char * OVS_WARN_UNUSED_RESULT
parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
enum ofputil_protocol action_usable_protocols;
@@ -635,7 +641,7 @@ parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string,
if (!strcmp(name, "in_port")) {
ofp_port_t in_port;
if (!ofputil_port_from_string(value, &in_port)) {
if (!ofputil_port_from_string(value, port_map, &in_port)) {
error = xasprintf("%s is not a valid OpenFlow port", value);
goto out;
}
@@ -662,7 +668,7 @@ parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string,
goto out;
}
error = parse_field(mf, value, &po->flow_metadata,
error = parse_field(mf, value, port_map, &po->flow_metadata,
usable_protocols);
if (error) {
goto out;
@@ -681,7 +687,7 @@ parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string,
}
if (act_str) {
error = ofpacts_parse_actions(act_str, &ofpacts,
error = ofpacts_parse_actions(act_str, port_map, &ofpacts,
&action_usable_protocols);
*usable_protocols &= action_usable_protocols;
if (error) {
@@ -707,12 +713,13 @@ out:
* error. The caller is responsible for freeing the returned string. */
char * OVS_WARN_UNUSED_RESULT
parse_ofp_packet_out_str(struct ofputil_packet_out *po, const char *str_,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
char *string = xstrdup(str_);
char *error;
error = parse_ofp_packet_out_str__(po, string, usable_protocols);
error = parse_ofp_packet_out_str__(po, string, port_map, usable_protocols);
if (error) {
po->ofpacts = NULL;
po->ofpacts_len = 0;
@@ -948,7 +955,9 @@ parse_ofp_meter_mod_str(struct ofputil_meter_mod *mm, const char *str_,
static char * OVS_WARN_UNUSED_RESULT
parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
const char *str_, char *string,
const char *str_,
const struct ofputil_port_map *port_map,
char *string,
enum ofputil_protocol *usable_protocols)
{
static atomic_count id = ATOMIC_COUNT_INIT(0);
@@ -984,8 +993,8 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
match_set_nw_proto(&fmr->match, p->nw_proto);
}
} else if (mf_from_name(name)) {
error = parse_field(mf_from_name(name), value, &fmr->match,
usable_protocols);
error = parse_field(mf_from_name(name), value, port_map,
&fmr->match, usable_protocols);
} else {
if (!*value) {
return xasprintf("%s: field %s missing value", str_, name);
@@ -1015,10 +1024,11 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
char * OVS_WARN_UNUSED_RESULT
parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr,
const char *str_,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
char *string = xstrdup(str_);
char *error = parse_flow_monitor_request__(fmr, str_, string,
char *error = parse_flow_monitor_request__(fmr, str_, port_map, string,
usable_protocols);
free(string);
return error;
@@ -1035,10 +1045,11 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr,
* error. The caller is responsible for freeing the returned string. */
char * OVS_WARN_UNUSED_RESULT
parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
int command,
const struct ofputil_port_map *port_map, int command,
enum ofputil_protocol *usable_protocols)
{
char *error = parse_ofp_str(fm, command, string, usable_protocols);
char *error = parse_ofp_str(fm, command, string, port_map,
usable_protocols);
if (!error) {
/* Normalize a copy of the match. This ensures that non-normalized
@@ -1189,7 +1200,8 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
char * OVS_WARN_UNUSED_RESULT
parse_ofp_flow_mod_file(const char *file_name, int command,
parse_ofp_flow_mod_file(const char *file_name,
const struct ofputil_port_map *port_map, int command,
struct ofputil_flow_mod **fms, size_t *n_fms,
enum ofputil_protocol *usable_protocols)
{
@@ -1219,8 +1231,8 @@ parse_ofp_flow_mod_file(const char *file_name, int command,
if (*n_fms >= allocated_fms) {
*fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms);
}
error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command,
&usable);
error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), port_map,
command, &usable);
if (error) {
char *err_msg;
size_t i;
@@ -1255,12 +1267,13 @@ parse_ofp_flow_mod_file(const char *file_name, int command,
char * OVS_WARN_UNUSED_RESULT
parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
bool aggregate, const char *string,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
struct ofputil_flow_mod fm;
char *error;
error = parse_ofp_str(&fm, -1, string, usable_protocols);
error = parse_ofp_str(&fm, -1, string, port_map, usable_protocols);
if (error) {
return error;
}
@@ -1295,7 +1308,7 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
char *
parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
const struct tun_table *tun_table, const char *s,
const struct simap *portno_names)
const struct ofputil_port_map *port_map)
{
char *pos, *key, *value_s;
char *error = NULL;
@@ -1353,28 +1366,17 @@ parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
goto exit;
}
if (!strcmp(key, "in_port")
&& portno_names
&& simap_contains(portno_names, value_s)) {
flow->in_port.ofp_port = u16_to_ofp(
simap_get(portno_names, value_s));
if (wc) {
wc->masks.in_port.ofp_port
= u16_to_ofp(ntohs(OVS_BE16_MAX));
}
} else {
field_error = mf_parse_value(mf, value_s, &value);
if (field_error) {
error = xasprintf("%s: bad value for %s (%s)",
s, key, field_error);
free(field_error);
goto exit;
}
field_error = mf_parse_value(mf, value_s, port_map, &value);
if (field_error) {
error = xasprintf("%s: bad value for %s (%s)",
s, key, field_error);
free(field_error);
goto exit;
}
mf_set_flow_value(mf, &value, flow);
if (wc) {
mf_mask_field(mf, wc);
}
mf_set_flow_value(mf, &value, flow);
if (wc) {
mf_mask_field(mf, wc);
}
}
}
@@ -1396,8 +1398,9 @@ exit:
}
static char * OVS_WARN_UNUSED_RESULT
parse_bucket_str(struct ofputil_bucket *bucket, char *str_, uint8_t group_type,
enum ofputil_protocol *usable_protocols)
parse_bucket_str(struct ofputil_bucket *bucket, char *str_,
const struct ofputil_port_map *port_map, uint8_t group_type,
enum ofputil_protocol *usable_protocols)
{
char *pos, *key, *value;
struct ofpbuf ofpacts;
@@ -1417,7 +1420,7 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_, uint8_t group_type,
if (!strcasecmp(key, "weight")) {
error = str_to_u16(value, "weight", &bucket->weight);
} else if (!strcasecmp(key, "watch_port")) {
if (!ofputil_port_from_string(value, &bucket->watch_port)
if (!ofputil_port_from_string(value, port_map, &bucket->watch_port)
|| (ofp_to_u16(bucket->watch_port) >= ofp_to_u16(OFPP_MAX)
&& bucket->watch_port != OFPP_ANY)) {
error = xasprintf("%s: invalid watch_port", value);
@@ -1453,7 +1456,7 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_, uint8_t group_type,
ds_chomp(&actions, ',');
ofpbuf_init(&ofpacts, 0);
error = ofpacts_parse_actions(ds_cstr(&actions), &ofpacts,
error = ofpacts_parse_actions(ds_cstr(&actions), port_map, &ofpacts,
usable_protocols);
ds_destroy(&actions);
if (error) {
@@ -1467,7 +1470,8 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_, uint8_t group_type,
}
static char * OVS_WARN_UNUSED_RESULT
parse_select_group_field(char *s, struct field_array *fa,
parse_select_group_field(char *s, const struct ofputil_port_map *port_map,
struct field_array *fa,
enum ofputil_protocol *usable_protocols)
{
char *name, *value_str;
@@ -1484,7 +1488,7 @@ parse_select_group_field(char *s, struct field_array *fa,
}
if (*value_str) {
error = mf_parse_value(mf, value_str, &value);
error = mf_parse_value(mf, value_str, port_map, &value);
if (error) {
return error;
}
@@ -1527,6 +1531,7 @@ parse_select_group_field(char *s, struct field_array *fa,
static char * OVS_WARN_UNUSED_RESULT
parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command,
char *string,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
enum {
@@ -1720,7 +1725,8 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command,
error = xstrdup("fields are not needed");
goto out;
}
error = parse_select_group_field(value, &gm->props.fields,
error = parse_select_group_field(value, port_map,
&gm->props.fields,
usable_protocols);
if (error) {
goto out;
@@ -1779,7 +1785,8 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command,
}
bucket = xzalloc(sizeof(struct ofputil_bucket));
error = parse_bucket_str(bucket, bkt_str, gm->type, usable_protocols);
error = parse_bucket_str(bucket, bkt_str, port_map,
gm->type, usable_protocols);
if (error) {
free(bucket);
goto out;
@@ -1811,11 +1818,12 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command,
char * OVS_WARN_UNUSED_RESULT
parse_ofp_group_mod_str(struct ofputil_group_mod *gm, int command,
const char *str_,
const struct ofputil_port_map *port_map,
enum ofputil_protocol *usable_protocols)
{
char *string = xstrdup(str_);
char *error = parse_ofp_group_mod_str__(gm, command, string,
usable_protocols);
port_map, usable_protocols);
free(string);
return error;
}
@@ -1825,7 +1833,9 @@ parse_ofp_group_mod_str(struct ofputil_group_mod *gm, int command,
* missing command name is treated as "add".
*/
char * OVS_WARN_UNUSED_RESULT
parse_ofp_group_mod_file(const char *file_name, int command,
parse_ofp_group_mod_file(const char *file_name,
const struct ofputil_port_map *port_map,
int command,
struct ofputil_group_mod **gms, size_t *n_gms,
enum ofputil_protocol *usable_protocols)
{
@@ -1862,7 +1872,7 @@ parse_ofp_group_mod_file(const char *file_name, int command,
*gms = new_gms;
}
error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, ds_cstr(&s),
&usable);
port_map, &usable);
if (error) {
size_t i;
@@ -1900,6 +1910,7 @@ parse_ofp_group_mod_file(const char *file_name, int command,
* error. The caller is responsible for freeing the returned string. */
char * OVS_WARN_UNUSED_RESULT
parse_ofp_bundle_file(const char *file_name,
const struct ofputil_port_map *port_map,
struct ofputil_bundle_msg **bms, size_t *n_bms,
enum ofputil_protocol *usable_protocols)
{
@@ -1946,7 +1957,8 @@ parse_ofp_bundle_file(const char *file_name,
if (!strncmp(s, "flow", len)) {
s += len;
error = parse_ofp_flow_mod_str(&(*bms)[*n_bms].fm, s, -2, &usable);
error = parse_ofp_flow_mod_str(&(*bms)[*n_bms].fm, s, port_map,
-2, &usable);
if (error) {
break;
}
@@ -1954,14 +1966,15 @@ parse_ofp_bundle_file(const char *file_name,
} else if (!strncmp(s, "group", len)) {
s += len;
error = parse_ofp_group_mod_str(&(*bms)[*n_bms].gm, -2, s,
&usable);
port_map, &usable);
if (error) {
break;
}
(*bms)[*n_bms].type = OFPTYPE_GROUP_MOD;
} else if (!strncmp(s, "packet-out", len)) {
s += len;
error = parse_ofp_packet_out_str(&(*bms)[*n_bms].po, s, &usable);
error = parse_ofp_packet_out_str(&(*bms)[*n_bms].po, s, port_map,
&usable);
if (error) {
break;
}