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

ofp-util: Support for OpenFlow 1.3 meters.

Signed-off-by: Jarno Rajahalme <jarno.rajahalme@nsn.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jarno Rajahalme
2013-06-20 17:26:18 +03:00
committed by Ben Pfaff
parent b4af6ceeea
commit 638a19b045
12 changed files with 1059 additions and 21 deletions

View File

@@ -402,7 +402,7 @@ struct ofp13_meter_stats {
ovs_be32 duration_sec; /* Time meter has been alive in seconds. */ ovs_be32 duration_sec; /* Time meter has been alive in seconds. */
ovs_be32 duration_nsec; /* Time meter has been alive in nanoseconds ovs_be32 duration_nsec; /* Time meter has been alive in nanoseconds
beyond duration_sec. */ beyond duration_sec. */
/* struct ofp13_meter_band_stats band_stats[0]; The band_stats length is struct ofp13_meter_band_stats band_stats[0]; /* The band_stats length is
inferred from the length field. */ inferred from the length field. */
}; };
OFP_ASSERT(sizeof(struct ofp13_meter_stats) == 40); OFP_ASSERT(sizeof(struct ofp13_meter_stats) == 40);

View File

@@ -352,6 +352,7 @@ enum ofp_flow_removed_reason {
OFPRR_DELETE, /* Evicted by a DELETE flow mod. */ OFPRR_DELETE, /* Evicted by a DELETE flow mod. */
OFPRR_GROUP_DELETE, /* Group was removed. */ OFPRR_GROUP_DELETE, /* Group was removed. */
OFPRR_EVICTION, /* Switch eviction to free resources. */ OFPRR_EVICTION, /* Switch eviction to free resources. */
OFPRR_METER_DELETE, /* Meter was removed. */
}; };
/* What changed about the physical port */ /* What changed about the physical port */

View File

@@ -1087,6 +1087,16 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
goto exit; goto exit;
} }
if (insts[OVSINST_OFPIT13_METER]) {
const struct ofp13_instruction_meter *oim;
struct ofpact_meter *om;
oim = (const struct ofp13_instruction_meter *)
insts[OVSINST_OFPIT13_METER];
om = ofpact_put_METER(ofpacts);
om->meter_id = ntohl(oim->meter_id);
}
if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) { if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
const union ofp_action *actions; const union ofp_action *actions;
size_t n_actions; size_t n_actions;
@@ -1229,6 +1239,7 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports)
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_METADATA: case OFPACT_WRITE_METADATA:
case OFPACT_METER:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
return 0; return 0;
@@ -1272,7 +1283,9 @@ ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len)
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
enum ovs_instruction_type next; enum ovs_instruction_type next;
if (a->type == OFPACT_CLEAR_ACTIONS) { if (a->type == OFPACT_METER) {
next = OVSINST_OFPIT13_METER;
} else if (a->type == OFPACT_CLEAR_ACTIONS) {
next = OVSINST_OFPIT11_CLEAR_ACTIONS; next = OVSINST_OFPIT11_CLEAR_ACTIONS;
} else if (a->type == OFPACT_WRITE_METADATA) { } else if (a->type == OFPACT_WRITE_METADATA) {
next = OVSINST_OFPIT11_WRITE_METADATA; next = OVSINST_OFPIT11_WRITE_METADATA;
@@ -1552,6 +1565,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
case OFPACT_SET_L4_DST_PORT: case OFPACT_SET_L4_DST_PORT:
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
case OFPACT_METER:
NOT_REACHED(); NOT_REACHED();
} }
} }
@@ -1644,6 +1658,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
case OFPACT_PUSH_VLAN: case OFPACT_PUSH_VLAN:
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
case OFPACT_METER:
/* XXX */ /* XXX */
break; break;
@@ -1816,6 +1831,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
case OFPACT_METER:
NOT_REACHED(); NOT_REACHED();
case OFPACT_CONTROLLER: case OFPACT_CONTROLLER:
@@ -1896,6 +1912,13 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow); oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
oiwm->metadata = om->metadata; oiwm->metadata = om->metadata;
oiwm->metadata_mask = om->mask; oiwm->metadata_mask = om->mask;
} else if (a->type == OFPACT_METER) {
const struct ofpact_meter *om;
struct ofp13_instruction_meter *oim;
om = ofpact_get_METER(a);
oim = instruction_put_OFPIT13_METER(openflow);
oim->meter_id = htonl(om->meter_id);
} else if (!ofpact_is_instruction(a)) { } else if (!ofpact_is_instruction(a)) {
/* Apply-actions */ /* Apply-actions */
const size_t ofs = openflow->size; const size_t ofs = openflow->size;
@@ -1965,6 +1988,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
case OFPACT_SAMPLE: case OFPACT_SAMPLE:
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
case OFPACT_METER:
default: default:
return false; return false;
} }
@@ -2291,6 +2315,12 @@ ofpact_format(const struct ofpact *a, struct ds *s)
OVSINST_OFPIT11_GOTO_TABLE), OVSINST_OFPIT11_GOTO_TABLE),
ofpact_get_GOTO_TABLE(a)->table_id); ofpact_get_GOTO_TABLE(a)->table_id);
break; break;
case OFPACT_METER:
ds_put_format(s, "%s:%"PRIu32,
ofpact_instruction_name_from_type(OVSINST_OFPIT13_METER),
ofpact_get_METER(a)->meter_id);
break;
} }
} }

View File

@@ -97,9 +97,10 @@
DEFINE_OFPACT(SAMPLE, ofpact_sample, ofpact) \ DEFINE_OFPACT(SAMPLE, ofpact_sample, ofpact) \
\ \
/* Instructions */ \ /* Instructions */ \
DEFINE_OFPACT(METER, ofpact_meter, ofpact) \
/* XXX Write-Actions */ \ /* XXX Write-Actions */ \
DEFINE_OFPACT(WRITE_METADATA, ofpact_metadata, ofpact) \
DEFINE_OFPACT(CLEAR_ACTIONS, ofpact_null, ofpact) \ DEFINE_OFPACT(CLEAR_ACTIONS, ofpact_null, ofpact) \
DEFINE_OFPACT(WRITE_METADATA, ofpact_metadata, ofpact) \
DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact) DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact)
/* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */ /* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */
@@ -374,6 +375,14 @@ struct ofpact_metadata {
ovs_be64 mask; ovs_be64 mask;
}; };
/* OFPACT_METER.
*
* Used for OFPIT13_METER. */
struct ofpact_meter {
struct ofpact ofpact;
uint32_t meter_id;
};
/* OFPACT_RESUBMIT. /* OFPACT_RESUBMIT.
* *
* Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */ * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
@@ -601,6 +610,10 @@ void ofpact_pad(struct ofpbuf *);
* It is enforced on parser from text string. * It is enforced on parser from text string.
*/ */
#define OVS_INSTRUCTIONS \ #define OVS_INSTRUCTIONS \
DEFINE_INST(OFPIT13_METER, \
ofp13_instruction_meter, false, \
"meter") \
\
DEFINE_INST(OFPIT11_APPLY_ACTIONS, \ DEFINE_INST(OFPIT11_APPLY_ACTIONS, \
ofp11_instruction_actions, true, \ ofp11_instruction_actions, true, \
"apply_actions") \ "apply_actions") \
@@ -639,6 +652,7 @@ ofpact_is_instruction(const struct ofpact *a)
{ {
/* XXX Write-Actions */ /* XXX Write-Actions */
return a->type == OFPACT_CLEAR_ACTIONS return a->type == OFPACT_CLEAR_ACTIONS
|| a->type == OFPACT_METER
|| a->type == OFPACT_WRITE_METADATA || a->type == OFPACT_WRITE_METADATA
|| a->type == OFPACT_GOTO_TABLE; || a->type == OFPACT_GOTO_TABLE;
} }

View File

@@ -217,7 +217,7 @@ enum ofpraw {
/* NXT 1.0+ (19): struct nx_async_config. */ /* NXT 1.0+ (19): struct nx_async_config. */
OFPRAW_NXT_SET_ASYNC_CONFIG, OFPRAW_NXT_SET_ASYNC_CONFIG,
/* OFPT 1.3+ (29): struct ofp13_meter_mod. */ /* OFPT 1.3+ (29): struct ofp13_meter_mod, uint8_t[8][]. */
OFPRAW_OFPT13_METER_MOD, OFPRAW_OFPT13_METER_MOD,
/* Standard statistics. */ /* Standard statistics. */
@@ -315,13 +315,13 @@ enum ofpraw {
/* OFPST 1.3+ (9): struct ofp13_meter_multipart_request. */ /* OFPST 1.3+ (9): struct ofp13_meter_multipart_request. */
OFPRAW_OFPST13_METER_REQUEST, OFPRAW_OFPST13_METER_REQUEST,
/* OFPST 1.3+ (9): struct ofp13_meter_stats[]. */ /* OFPST 1.3+ (9): uint8_t[8][]. */
OFPRAW_OFPST13_METER_REPLY, OFPRAW_OFPST13_METER_REPLY,
/* OFPST 1.3+ (10): struct ofp13_meter_multipart_request. */ /* OFPST 1.3+ (10): struct ofp13_meter_multipart_request. */
OFPRAW_OFPST13_METER_CONFIG_REQUEST, OFPRAW_OFPST13_METER_CONFIG_REQUEST,
/* OFPST 1.3+ (10): struct ofp13_meter_config[]. */ /* OFPST 1.3+ (10): uint8_t[8][]. */
OFPRAW_OFPST13_METER_CONFIG_REPLY, OFPRAW_OFPST13_METER_CONFIG_REPLY,
/* OFPST 1.3+ (11): void. */ /* OFPST 1.3+ (11): void. */

View File

@@ -45,14 +45,14 @@ static void ofp_fatal(const char *flow, bool verbose, const char *format, ...)
NO_RETURN; NO_RETURN;
static uint8_t static uint8_t
str_to_table_id(const char *str) str_to_u8(const char *str, const char *name)
{ {
int table_id; int value;
if (!str_to_int(str, 10, &table_id) || table_id < 0 || table_id > 255) { if (!str_to_int(str, 10, &value) || value < 0 || value > 255) {
ovs_fatal(0, "invalid table \"%s\"", str); ovs_fatal(0, "invalid %s \"%s\"", name, str);
} }
return table_id; return value;
} }
static uint16_t static uint16_t
@@ -705,6 +705,10 @@ parse_named_instruction(enum ovs_instruction_type type,
ofpact_put_CLEAR_ACTIONS(ofpacts); ofpact_put_CLEAR_ACTIONS(ofpacts);
break; break;
case OVSINST_OFPIT13_METER:
ofpact_put_METER(ofpacts)->meter_id = str_to_u32(arg);
break;
case OVSINST_OFPIT11_WRITE_METADATA: case OVSINST_OFPIT11_WRITE_METADATA:
parse_metadata(ofpacts, arg); parse_metadata(ofpacts, arg);
break; break;
@@ -715,7 +719,7 @@ parse_named_instruction(enum ovs_instruction_type type,
if (!table_s || !table_s[0]) { if (!table_s || !table_s[0]) {
ovs_fatal(0, "instruction goto-table needs table id"); ovs_fatal(0, "instruction goto-table needs table id");
} }
ogt->table_id = str_to_table_id(table_s); ogt->table_id = str_to_u8(table_s, "table");
break; break;
} }
} }
@@ -948,7 +952,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
} }
if (!strcmp(name, "table")) { if (!strcmp(name, "table")) {
fm->table_id = str_to_table_id(value); fm->table_id = str_to_u8(value, name);
} else if (!strcmp(name, "out_port")) { } else if (!strcmp(name, "out_port")) {
if (!ofputil_port_from_string(name, &fm->out_port)) { if (!ofputil_port_from_string(name, &fm->out_port)) {
ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port",
@@ -1025,6 +1029,198 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
free(string); free(string);
} }
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
* page) into 'mm' for sending the specified meter_mod 'command' to a switch.
*/
void
parse_ofp_meter_mod_str(struct ofputil_meter_mod *mm, const char *str_,
int command, bool verbose)
{
enum {
F_METER = 1 << 0,
F_FLAGS = 1 << 1,
F_BANDS = 1 << 2,
} fields;
char *string = xstrdup(str_);
char *save_ptr = NULL;
char *band_str = NULL;
char *name;
switch (command) {
case -1:
fields = F_METER;
break;
case OFPMC13_ADD:
fields = F_METER | F_FLAGS | F_BANDS;
break;
case OFPMC13_DELETE:
fields = F_METER;
break;
case OFPMC13_MODIFY:
fields = F_METER | F_FLAGS | F_BANDS;
break;
default:
NOT_REACHED();
}
mm->command = command;
mm->meter.meter_id = 0;
mm->meter.flags = 0;
if (fields & F_BANDS) {
band_str = strstr(string, "band");
if (!band_str) {
ofp_fatal(str_, verbose, "must specify bands");
}
*band_str = '\0';
band_str = strchr(band_str + 1, '=');
if (!band_str) {
ofp_fatal(str_, verbose, "must specify bands");
}
band_str++;
}
for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
if (fields & F_FLAGS && !strcmp(name, "kbps")) {
mm->meter.flags |= OFPMF13_KBPS;
} else if (fields & F_FLAGS && !strcmp(name, "pktps")) {
mm->meter.flags |= OFPMF13_PKTPS;
} else if (fields & F_FLAGS && !strcmp(name, "burst")) {
mm->meter.flags |= OFPMF13_BURST;
} else if (fields & F_FLAGS && !strcmp(name, "stats")) {
mm->meter.flags |= OFPMF13_STATS;
} else {
char *value;
value = strtok_r(NULL, ", \t\r\n", &save_ptr);
if (!value) {
ofp_fatal(str_, verbose, "field %s missing value", name);
}
if (!strcmp(name, "meter")) {
if (!strcmp(value, "all")) {
mm->meter.meter_id = OFPM13_ALL;
} else if (!strcmp(value, "controller")) {
mm->meter.meter_id = OFPM13_CONTROLLER;
} else if (!strcmp(value, "slowpath")) {
mm->meter.meter_id = OFPM13_SLOWPATH;
} else {
mm->meter.meter_id = str_to_u32(value);
if (mm->meter.meter_id > OFPM13_MAX) {
ofp_fatal(str_, verbose, "invalid value for %s", name);
}
}
} else {
ofp_fatal(str_, verbose, "unknown keyword %s", name);
}
}
}
if (fields & F_METER && !mm->meter.meter_id) {
ofp_fatal(str_, verbose, "must specify 'meter'");
}
if (fields & F_FLAGS && !mm->meter.flags) {
ofp_fatal(str_, verbose,
"meter must specify either 'kbps' or 'pktps'");
}
if (fields & F_BANDS) {
struct ofpbuf bands;
uint16_t n_bands = 0;
struct ofputil_meter_band *band = NULL;
int i;
ofpbuf_init(&bands, 64);
for (name = strtok_r(band_str, "=, \t\r\n", &save_ptr); name;
name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
char *value;
value = strtok_r(NULL, ", \t\r\n", &save_ptr);
if (!value) {
ofp_fatal(str_, verbose, "field %s missing value", name);
}
if (!strcmp(name, "type")) {
/* Start a new band */
band = ofpbuf_put_zeros(&bands, sizeof *band);
n_bands++;
if (!strcmp(value, "drop")) {
band->type = OFPMBT13_DROP;
} else if (!strcmp(value, "dscp_remark")) {
band->type = OFPMBT13_DSCP_REMARK;
} else {
ofp_fatal(str_, verbose, "field %s unknown value %s", name,
value);
}
} else if (!band || !band->type) {
ofp_fatal(str_, verbose,
"band must start with the 'type' keyword");
} else if (!strcmp(name, "rate")) {
band->rate = str_to_u32(value);
} else if (!strcmp(name, "burst_size")) {
band->burst_size = str_to_u32(value);
} else if (!strcmp(name, "prec_level")) {
band->prec_level = str_to_u8(value, name);
} else {
ofp_fatal(str_, verbose, "unknown keyword %s", name);
}
}
/* validate bands */
if (!n_bands) {
ofp_fatal(str_, verbose, "meter must have bands");
}
mm->meter.n_bands = n_bands;
mm->meter.bands = ofpbuf_steal_data(&bands);
for (i = 0; i < n_bands; ++i) {
band = &mm->meter.bands[i];
if (!band->type) {
ofp_fatal(str_, verbose, "band must have 'type'");
}
if (band->type == OFPMBT13_DSCP_REMARK) {
if (!band->prec_level) {
ofp_fatal(str_, verbose, "'dscp_remark' band must have"
" 'prec_level'");
}
} else {
if (band->prec_level) {
ofp_fatal(str_, verbose, "Only 'dscp_remark' band may have"
" 'prec_level'");
}
}
if (!band->rate) {
ofp_fatal(str_, verbose, "band must have 'rate'");
}
if (mm->meter.flags & OFPMF13_BURST) {
if (!band->burst_size) {
ofp_fatal(str_, verbose, "band must have 'burst_size' "
"when 'burst' flag is set");
}
} else {
if (band->burst_size) {
ofp_fatal(str_, verbose, "band may have 'burst_size' only "
"when 'burst' flag is set");
}
}
}
} else {
mm->meter.n_bands = 0;
mm->meter.bands = NULL;
}
free(string);
}
/* Convert 'str_' (as described in the documentation for the "monitor" command /* Convert 'str_' (as described in the documentation for the "monitor" command
* in the ovs-ofctl man page) into 'fmr'. */ * in the ovs-ofctl man page) into 'fmr'. */
void void
@@ -1074,7 +1270,7 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr,
} }
if (!strcmp(name, "table")) { if (!strcmp(name, "table")) {
fmr->table_id = str_to_table_id(value); fmr->table_id = str_to_u8(value, name);
} else if (!strcmp(name, "out_port")) { } else if (!strcmp(name, "out_port")) {
fmr->out_port = u16_to_ofp(atoi(value)); fmr->out_port = u16_to_ofp(atoi(value));
} else if (mf_from_name(name)) { } else if (mf_from_name(name)) {

View File

@@ -28,6 +28,7 @@ struct ofpbuf;
struct ofputil_flow_mod; struct ofputil_flow_mod;
struct ofputil_flow_monitor_request; struct ofputil_flow_monitor_request;
struct ofputil_flow_stats_request; struct ofputil_flow_stats_request;
struct ofputil_meter_mod;
void parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_, void parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
bool verbose); bool verbose);
@@ -45,6 +46,9 @@ void parse_ofpacts(const char *, struct ofpbuf *ofpacts);
char *parse_ofp_exact_flow(struct flow *, const char *); char *parse_ofp_exact_flow(struct flow *, const char *);
void parse_ofp_meter_mod_str(struct ofputil_meter_mod *, const char *string,
int command, bool verbose);
void parse_flow_monitor_request(struct ofputil_flow_monitor_request *, void parse_flow_monitor_request(struct ofputil_flow_monitor_request *,
const char *); const char *);

View File

@@ -878,6 +878,8 @@ ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason,
return "group_delete"; return "group_delete";
case OFPRR_EVICTION: case OFPRR_EVICTION:
return "eviction"; return "eviction";
case OFPRR_METER_DELETE:
return "meter_delete";
default: default:
snprintf(reasonbuf, bufsize, "%d", (int) reason); snprintf(reasonbuf, bufsize, "%d", (int) reason);
return reasonbuf; return reasonbuf;
@@ -954,6 +956,236 @@ ofp_print_port_mod(struct ds *string, const struct ofp_header *oh)
} }
} }
static void
ofp_print_meter_flags(struct ds *s, uint16_t flags)
{
if (flags & OFPMF13_KBPS) {
ds_put_cstr(s, "kbps ");
}
if (flags & OFPMF13_PKTPS) {
ds_put_cstr(s, "pktps ");
}
if (flags & OFPMF13_BURST) {
ds_put_cstr(s, "burst ");
}
if (flags & OFPMF13_STATS) {
ds_put_cstr(s, "stats ");
}
flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS);
if (flags) {
ds_put_format(s, "flags:0x%"PRIx16" ", flags);
}
}
static void
ofp_print_meter_band(struct ds *s, uint16_t flags,
const struct ofputil_meter_band *mb)
{
ds_put_cstr(s, "\ntype=");
switch (mb->type) {
case OFPMBT13_DROP:
ds_put_cstr(s, "drop");
break;
case OFPMBT13_DSCP_REMARK:
ds_put_cstr(s, "dscp_remark");
break;
default:
ds_put_format(s, "%u", mb->type);
}
ds_put_format(s, " rate=%"PRIu32, mb->rate);
if (flags & OFPMF13_BURST) {
ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size);
}
if (mb->type == OFPMBT13_DSCP_REMARK) {
ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level);
}
}
static void
ofp_print_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms)
{
uint16_t i;
ds_put_format(s, "meter:%"PRIu32" ", ms->meter_id);
ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count);
ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count);
ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count);
ds_put_cstr(s, "duration:");
ofp_print_duration(s, ms->duration_sec, ms->duration_nsec);
ds_put_char(s, ' ');
ds_put_cstr(s, "bands:\n");
for (i = 0; i < ms->n_bands; ++i) {
ds_put_format(s, "%d: ", i);
ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count);
ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count);
}
}
static void
ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc)
{
uint16_t i;
ds_put_format(s, "meter=%"PRIu32" ", mc->meter_id);
ofp_print_meter_flags(s, mc->flags);
ds_put_cstr(s, "bands=");
for (i = 0; i < mc->n_bands; ++i) {
ofp_print_meter_band(s, mc->flags, &mc->bands[i]);
}
ds_put_char(s, '\n');
}
static void
ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
{
struct ofputil_meter_mod mm;
struct ofpbuf bands;
enum ofperr error;
ofpbuf_init(&bands, 64);
error = ofputil_decode_meter_mod(oh, &mm, &bands);
if (error) {
ofpbuf_uninit(&bands);
ofp_print_error(s, error);
return;
}
switch (mm.command) {
case OFPMC13_ADD:
ds_put_cstr(s, " ADD ");
break;
case OFPMC13_MODIFY:
ds_put_cstr(s, " MOD ");
break;
case OFPMC13_DELETE:
ds_put_cstr(s, " DEL ");
break;
default:
ds_put_format(s, " cmd:%d ", mm.command);
}
ofp_print_meter_config(s, &mm.meter);
ofpbuf_uninit(&bands);
}
static void
ofp_print_meter_stats_request(struct ds *s, const struct ofp_header *oh)
{
uint32_t meter_id;
ofputil_decode_meter_request(oh, &meter_id);
ds_put_format(s, " meter=%"PRIu32, meter_id);
}
static const char *
ofputil_meter_capabilities_to_name(uint32_t bit)
{
enum ofp13_meter_flags flag = bit;
switch (flag) {
case OFPMF13_KBPS: return "kbps";
case OFPMF13_PKTPS: return "pktps";
case OFPMF13_BURST: return "burst";
case OFPMF13_STATS: return "stats";
}
return NULL;
}
static const char *
ofputil_meter_band_types_to_name(uint32_t bit)
{
/*
* Note: Meter band types start from 1. We assume that the lowest bit
* in the band_types corresponds to DROP band type (1).
*/
switch (bit) {
case 1 << (OFPMBT13_DROP - 1): return "drop";
case 1 << (OFPMBT13_DSCP_REMARK - 1): return "dscp_remark";
}
return NULL;
}
static void
ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh)
{
struct ofputil_meter_features mf;
ofputil_decode_meter_features(oh, &mf);
ds_put_format(s, "\nmax_meter:%"PRIu32, mf.max_meters);
ds_put_format(s, " max_bands:%"PRIu8, mf.max_bands);
ds_put_format(s, " max_color:%"PRIu8"\n", mf.max_color);
ds_put_cstr(s, "band_types: ");
ofp_print_bit_names(s, mf.band_types,
ofputil_meter_band_types_to_name, ' ');
ds_put_char(s, '\n');
ds_put_cstr(s, "capabilities: ");
ofp_print_bit_names(s, mf.capabilities,
ofputil_meter_capabilities_to_name, ' ');
ds_put_char(s, '\n');
}
static void
ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh)
{
struct ofpbuf bands;
struct ofpbuf b;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpbuf_init(&bands, 64);
for (;;) {
struct ofputil_meter_config mc;
int retval;
retval = ofputil_decode_meter_config(&b, &mc, &bands);
if (retval) {
if (retval != EOF) {
ofp_print_error(s, retval);
}
break;
}
ds_put_char(s, '\n');
ofp_print_meter_config(s, &mc);
}
ofpbuf_uninit(&bands);
}
static void
ofp_print_meter_stats_reply(struct ds *s, const struct ofp_header *oh)
{
struct ofpbuf bands;
struct ofpbuf b;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpbuf_init(&bands, 64);
for (;;) {
struct ofputil_meter_stats ms;
int retval;
retval = ofputil_decode_meter_stats(&b, &ms, &bands);
if (retval) {
if (retval != EOF) {
ofp_print_error(s, retval);
}
break;
}
ds_put_char(s, '\n');
ofp_print_meter_stats(s, &ms);
}
ofpbuf_uninit(&bands);
}
static void static void
ofp_print_error(struct ds *string, enum ofperr error) ofp_print_error(struct ds *string, enum ofperr error)
{ {
@@ -1910,19 +2142,12 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
case OFPTYPE_QUEUE_GET_CONFIG_REPLY: case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
case OFPTYPE_GET_ASYNC_REQUEST: case OFPTYPE_GET_ASYNC_REQUEST:
case OFPTYPE_GET_ASYNC_REPLY: case OFPTYPE_GET_ASYNC_REPLY:
case OFPTYPE_METER_MOD:
case OFPTYPE_GROUP_REQUEST: case OFPTYPE_GROUP_REQUEST:
case OFPTYPE_GROUP_REPLY: case OFPTYPE_GROUP_REPLY:
case OFPTYPE_GROUP_DESC_REQUEST: case OFPTYPE_GROUP_DESC_REQUEST:
case OFPTYPE_GROUP_DESC_REPLY: case OFPTYPE_GROUP_DESC_REPLY:
case OFPTYPE_GROUP_FEATURES_REQUEST: case OFPTYPE_GROUP_FEATURES_REQUEST:
case OFPTYPE_GROUP_FEATURES_REPLY: case OFPTYPE_GROUP_FEATURES_REPLY:
case OFPTYPE_METER_REQUEST:
case OFPTYPE_METER_REPLY:
case OFPTYPE_METER_CONFIG_REQUEST:
case OFPTYPE_METER_CONFIG_REPLY:
case OFPTYPE_METER_FEATURES_REQUEST:
case OFPTYPE_METER_FEATURES_REPLY:
case OFPTYPE_TABLE_FEATURES_REQUEST: case OFPTYPE_TABLE_FEATURES_REQUEST:
case OFPTYPE_TABLE_FEATURES_REPLY: case OFPTYPE_TABLE_FEATURES_REPLY:
ofp_print_not_implemented(string); ofp_print_not_implemented(string);
@@ -1980,6 +2205,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
ofp_print_port_mod(string, oh); ofp_print_port_mod(string, oh);
break; break;
case OFPTYPE_METER_MOD:
ofp_print_meter_mod(string, oh);
break;
case OFPTYPE_BARRIER_REQUEST: case OFPTYPE_BARRIER_REQUEST:
case OFPTYPE_BARRIER_REPLY: case OFPTYPE_BARRIER_REPLY:
break; break;
@@ -1989,8 +2218,30 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
ofp_print_role_message(string, oh); ofp_print_role_message(string, oh);
break; break;
case OFPTYPE_METER_REQUEST:
case OFPTYPE_METER_CONFIG_REQUEST:
ofp_print_stats_request(string, oh);
ofp_print_meter_stats_request(string, oh);
break;
case OFPTYPE_METER_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_meter_stats_reply(string, oh);
break;
case OFPTYPE_METER_CONFIG_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_meter_config_reply(string, oh);
break;
case OFPTYPE_METER_FEATURES_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_meter_features_reply(string, oh);
break;
case OFPTYPE_DESC_STATS_REQUEST: case OFPTYPE_DESC_STATS_REQUEST:
case OFPTYPE_PORT_DESC_STATS_REQUEST: case OFPTYPE_PORT_DESC_STATS_REQUEST:
case OFPTYPE_METER_FEATURES_REQUEST:
ofp_print_stats_request(string, oh); ofp_print_stats_request(string, oh);
break; break;

View File

@@ -1631,6 +1631,368 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
return 0; return 0;
} }
static enum ofperr
ofputil_pull_bands(struct ofpbuf *msg, size_t len, uint16_t *n_bands,
struct ofpbuf *bands)
{
const struct ofp13_meter_band_header *ombh;
struct ofputil_meter_band *mb;
uint16_t n = 0;
ombh = ofpbuf_try_pull(msg, len);
if (!ombh) {
return OFPERR_OFPBRC_BAD_LEN;
}
while (len >= sizeof (struct ofp13_meter_band_drop)) {
size_t ombh_len = ntohs(ombh->len);
/* All supported band types have the same length */
if (ombh_len != sizeof (struct ofp13_meter_band_drop)) {
return OFPERR_OFPBRC_BAD_LEN;
}
mb = ofpbuf_put_uninit(bands, sizeof *mb);
mb->type = ntohs(ombh->type);
mb->rate = ntohl(ombh->rate);
mb->burst_size = ntohl(ombh->burst_size);
mb->prec_level = (mb->type == OFPMBT13_DSCP_REMARK) ?
((struct ofp13_meter_band_dscp_remark *)ombh)->prec_level : 0;
n++;
len -= ombh_len;
ombh = (struct ofp13_meter_band_header *)(((char *)ombh) + ombh_len);
}
if (len) {
return OFPERR_OFPBRC_BAD_LEN;
}
*n_bands = n;
return 0;
}
enum ofperr
ofputil_decode_meter_mod(const struct ofp_header *oh,
struct ofputil_meter_mod *mm,
struct ofpbuf *bands)
{
const struct ofp13_meter_mod *omm;
struct ofpbuf b;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
omm = ofpbuf_pull(&b, sizeof *omm);
/* Translate the message. */
mm->command = ntohs(omm->command);
mm->meter.meter_id = ntohl(omm->meter_id);
if (mm->command == OFPMC13_DELETE) {
mm->meter.flags = 0;
mm->meter.n_bands = 0;
mm->meter.bands = NULL;
} else {
enum ofperr error;
mm->meter.flags = ntohs(omm->flags);
mm->meter.bands = bands->data;
error = ofputil_pull_bands(&b, b.size, &mm->meter.n_bands,
bands);
if (error) {
return error;
}
}
return 0;
}
void
ofputil_decode_meter_request(const struct ofp_header *oh, uint32_t *meter_id)
{
const struct ofp13_meter_multipart_request *omr = ofpmsg_body(oh);
*meter_id = ntohl(omr->meter_id);
}
struct ofpbuf *
ofputil_encode_meter_request(enum ofp_version ofp_version,
enum ofputil_meter_request_type type,
uint32_t meter_id)
{
struct ofpbuf *msg;
enum ofpraw raw;
switch (type) {
case OFPUTIL_METER_CONFIG:
raw = OFPRAW_OFPST13_METER_CONFIG_REQUEST;
break;
case OFPUTIL_METER_STATS:
raw = OFPRAW_OFPST13_METER_REQUEST;
break;
default:
case OFPUTIL_METER_FEATURES:
raw = OFPRAW_OFPST13_METER_FEATURES_REQUEST;
break;
}
msg = ofpraw_alloc(raw, ofp_version, 0);
if (type != OFPUTIL_METER_FEATURES) {
struct ofp13_meter_multipart_request *omr;
omr = ofpbuf_put_zeros(msg, sizeof *omr);
omr->meter_id = htonl(meter_id);
}
return msg;
}
static void
ofputil_put_bands(uint16_t n_bands, const struct ofputil_meter_band *mb,
struct ofpbuf *msg)
{
uint16_t n = 0;
for (n = 0; n < n_bands; ++n) {
/* Currently all band types have same size */
struct ofp13_meter_band_dscp_remark *ombh;
size_t ombh_len = sizeof *ombh;
ombh = ofpbuf_put_zeros(msg, ombh_len);
ombh->type = htons(mb->type);
ombh->len = htons(ombh_len);
ombh->rate = htonl(mb->rate);
ombh->burst_size = htonl(mb->burst_size);
ombh->prec_level = mb->prec_level;
mb++;
}
}
/* Encode a meter stat for 'mc' and append it to 'replies'. */
void
ofputil_append_meter_config(struct list *replies,
const struct ofputil_meter_config *mc)
{
struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
size_t start_ofs = msg->size;
struct ofp13_meter_config *reply = ofpbuf_put_uninit(msg, sizeof *reply);
reply->flags = htons(mc->flags);
reply->meter_id = htonl(mc->meter_id);
ofputil_put_bands(mc->n_bands, mc->bands, msg);
reply->length = htons(msg->size - start_ofs);
ofpmp_postappend(replies, start_ofs);
}
/* Encode a meter stat for 'ms' and append it to 'replies'. */
void
ofputil_append_meter_stats(struct list *replies,
const struct ofputil_meter_stats *ms)
{
struct ofp13_meter_stats *reply;
uint16_t n = 0;
uint16_t len;
len = sizeof *reply + ms->n_bands * sizeof(struct ofp13_meter_band_stats);
reply = ofpmp_append(replies, len);
reply->meter_id = htonl(ms->meter_id);
reply->len = htons(len);
memset(reply->pad, 0, sizeof reply->pad);
reply->flow_count = htonl(ms->flow_count);
reply->packet_in_count = htonll(ms->packet_in_count);
reply->byte_in_count = htonll(ms->byte_in_count);
reply->duration_sec = htonl(ms->duration_sec);
reply->duration_nsec = htonl(ms->duration_nsec);
for (n = 0; n < ms->n_bands; ++n) {
const struct ofputil_meter_band_stats *src = &ms->bands[n];
struct ofp13_meter_band_stats *dst = &reply->band_stats[n];
dst->packet_band_count = htonll(src->packet_count);
dst->byte_band_count = htonll(src->byte_count);
}
}
/* Converts an OFPMP_METER_CONFIG reply in 'msg' into an abstract
* ofputil_meter_config in 'mc', with mc->bands pointing to bands decoded into
* 'bands'. The caller must have initialized 'bands' and retains ownership of
* it across the call.
*
* Multiple OFPST13_METER_CONFIG replies can be packed into a single OpenFlow
* message. Calling this function multiple times for a single 'msg' iterates
* through the replies. 'bands' is cleared for each reply.
*
* Returns 0 if successful, EOF if no replies were left in this 'msg',
* otherwise a positive errno value. */
int
ofputil_decode_meter_config(struct ofpbuf *msg,
struct ofputil_meter_config *mc,
struct ofpbuf *bands)
{
const struct ofp13_meter_config *omc;
enum ofperr err;
/* Pull OpenFlow headers for the first call. */
if (!msg->l2) {
ofpraw_pull_assert(msg);
}
if (!msg->size) {
return EOF;
}
omc = ofpbuf_try_pull(msg, sizeof *omc);
if (!omc) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPMP_METER_CONFIG reply has %zu "
"leftover bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
ofpbuf_clear(bands);
err = ofputil_pull_bands(msg, ntohs(omc->length) - sizeof *omc,
&mc->n_bands, bands);
if (err) {
return err;
}
mc->meter_id = ntohl(omc->meter_id);
mc->flags = ntohs(omc->flags);
mc->bands = bands->data;
return 0;
}
static enum ofperr
ofputil_pull_band_stats(struct ofpbuf *msg, size_t len, uint16_t *n_bands,
struct ofpbuf *bands)
{
const struct ofp13_meter_band_stats *ombs;
struct ofputil_meter_band_stats *mbs;
uint16_t n, i;
n = len / sizeof *ombs;
if (len != n * sizeof *ombs) {
return OFPERR_OFPBRC_BAD_LEN;
}
ombs = ofpbuf_pull(msg, len);
mbs = ofpbuf_put_uninit(bands, len);
for (i = 0; i < n; ++i) {
mbs[i].packet_count = ntohll(ombs[i].packet_band_count);
mbs[i].byte_count = ntohll(ombs[i].byte_band_count);
}
*n_bands = n;
return 0;
}
/* Converts an OFPMP_METER reply in 'msg' into an abstract
* ofputil_meter_stats in 'ms', with ms->bands pointing to band stats
* decoded into 'bands'.
*
* Multiple OFPMP_METER replies can be packed into a single OpenFlow
* message. Calling this function multiple times for a single 'msg' iterates
* through the replies. 'bands' is cleared for each reply.
*
* Returns 0 if successful, EOF if no replies were left in this 'msg',
* otherwise a positive errno value. */
int
ofputil_decode_meter_stats(struct ofpbuf *msg,
struct ofputil_meter_stats *ms,
struct ofpbuf *bands)
{
const struct ofp13_meter_stats *oms;
uint16_t len;
enum ofperr err;
/* Pull OpenFlow headers for the first call. */
if (!msg->l2) {
ofpraw_pull_assert(msg);
}
if (!msg->size) {
return EOF;
}
oms = ofpbuf_try_pull(msg, sizeof *oms);
if (!oms) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPMP_METER reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
len = ntohs(oms->len);
len -= sizeof *oms;
ofpbuf_clear(bands);
err = ofputil_pull_band_stats(msg, len, &ms->n_bands, bands);
if (err) {
return err;
}
ms->meter_id = ntohl(oms->meter_id);
ms->flow_count = ntohl(oms->flow_count);
ms->packet_in_count = ntohll(oms->packet_in_count);
ms->byte_in_count = ntohll(oms->byte_in_count);
ms->duration_sec = ntohl(oms->duration_sec);
ms->duration_nsec = ntohl(oms->duration_nsec);
ms->bands = bands->data;
return 0;
}
void
ofputil_decode_meter_features(const struct ofp_header *oh,
struct ofputil_meter_features *mf)
{
const struct ofp13_meter_features *omf = ofpmsg_body(oh);
mf->max_meters = ntohl(omf->max_meter);
mf->band_types = ntohl(omf->band_types);
mf->capabilities = ntohl(omf->capabilities);
mf->max_bands = omf->max_bands;
mf->max_color = omf->max_color;
}
struct ofpbuf *
ofputil_encode_meter_features_reply(const struct ofputil_meter_features *mf,
const struct ofp_header *request)
{
struct ofpbuf *reply;
struct ofp13_meter_features *omf;
reply = ofpraw_alloc_stats_reply(request, 0);
omf = ofpbuf_put_zeros(reply, sizeof *omf);
omf->max_meter = htonl(mf->max_meters);
omf->band_types = htonl(mf->band_types);
omf->capabilities = htonl(mf->capabilities);
omf->max_bands = mf->max_bands;
omf->max_color = mf->max_color;
return reply;
}
struct ofpbuf *
ofputil_encode_meter_mod(enum ofp_version ofp_version,
const struct ofputil_meter_mod *mm)
{
struct ofpbuf *msg;
struct ofp13_meter_mod *omm;
msg = ofpraw_alloc(OFPRAW_OFPT13_METER_MOD, ofp_version,
NXM_TYPICAL_LEN + mm->meter.n_bands * 16);
omm = ofpbuf_put_zeros(msg, sizeof *omm);
omm->command = htons(mm->command);
if (mm->command != OFPMC13_DELETE) {
omm->flags = htons(mm->meter.flags);
}
omm->meter_id = htonl(mm->meter.meter_id);
ofputil_put_bands(mm->meter.n_bands, mm->meter.bands, msg);
ofpmsg_update_length(msg);
return msg;
}
static ovs_be16 static ovs_be16
ofputil_tid_command(const struct ofputil_flow_mod *fm, ofputil_tid_command(const struct ofputil_flow_mod *fm,
enum ofputil_protocol protocol) enum ofputil_protocol protocol)

View File

@@ -514,6 +514,93 @@ enum ofperr ofputil_decode_port_mod(const struct ofp_header *,
struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *, struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
enum ofputil_protocol); enum ofputil_protocol);
struct ofputil_meter_band {
uint16_t type;
uint8_t pad;
uint8_t prec_level; /* Non-zero if type == OFPMBT_DSCP_REMARK */
uint32_t rate;
uint32_t burst_size;
};
struct ofputil_meter_band_stats {
uint64_t packet_count;
uint64_t byte_count;
};
struct ofputil_meter_config {
uint32_t meter_id;
uint16_t flags;
uint16_t n_bands;
struct ofputil_meter_band *bands;
};
/* Abstract ofp_meter_mod. */
struct ofputil_meter_mod {
uint16_t command;
struct ofputil_meter_config meter;
};
struct ofputil_meter_stats {
uint32_t meter_id;
uint32_t flow_count;
uint64_t packet_in_count;
uint64_t byte_in_count;
uint32_t duration_sec;
uint32_t duration_nsec;
uint16_t n_bands;
struct ofputil_meter_band_stats *bands; /* band stats */
};
struct ofputil_meter_features {
uint32_t max_meters; /* Maximum number of meters */
uint32_t band_types; /* Can support max 32 band types */
uint32_t capabilities; /* Supported flags */
uint8_t max_bands;
uint8_t max_color;
};
enum ofperr ofputil_decode_meter_mod(const struct ofp_header *,
struct ofputil_meter_mod *,
struct ofpbuf *bands);
struct ofpbuf *ofputil_encode_meter_mod(enum ofp_version ofp_version,
const struct ofputil_meter_mod *);
void ofputil_decode_meter_features(const struct ofp_header *,
struct ofputil_meter_features *);
struct ofpbuf *ofputil_encode_meter_features_reply(const struct
ofputil_meter_features *,
const struct ofp_header *
request);
void ofputil_decode_meter_request(const struct ofp_header *,
uint32_t *meter_id);
void ofputil_append_meter_config(struct list *replies,
const struct ofputil_meter_config *omc);
void ofputil_append_meter_stats(struct list *replies,
const struct ofputil_meter_stats *oms);
enum ofputil_meter_request_type {
OFPUTIL_METER_FEATURES,
OFPUTIL_METER_CONFIG,
OFPUTIL_METER_STATS
};
struct ofpbuf *ofputil_encode_meter_request(enum ofp_version,
enum ofputil_meter_request_type,
uint32_t meter_id);
int ofputil_decode_meter_stats(struct ofpbuf *msg,
struct ofputil_meter_stats *ms,
struct ofpbuf *bands);
int ofputil_decode_meter_config(struct ofpbuf *msg,
struct ofputil_meter_config *mc,
struct ofpbuf *bands);
/* Type for meter_id in ofproto provider interface, UINT32_MAX if none */
typedef struct { uint32_t uint32; } ofproto_meter_id;
/* Abstract ofp_role_request and reply. */ /* Abstract ofp_role_request and reply. */
struct ofputil_role_request { struct ofputil_role_request {
enum ofp12_controller_role role; enum ofp12_controller_role role;

View File

@@ -1739,6 +1739,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
flow->metadata |= metadata->metadata & metadata->mask; flow->metadata |= metadata->metadata & metadata->mask;
break; break;
case OFPACT_METER:
/* Not implemented yet. */
break;
case OFPACT_GOTO_TABLE: { case OFPACT_GOTO_TABLE: {
/* It is assumed that goto-table is the last action. */ /* It is assumed that goto-table is the last action. */
struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a); struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);

View File

@@ -1581,6 +1581,95 @@ OFPST_PORT_DESC reply (xid=0x0):
]) ])
AT_CLEANUP AT_CLEANUP
AT_SETUP([OFPT_METER_MOD request - OF1.3])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
04 1d 00 20 00 00 00 02 00 00 00 0d 00 00 00 05 \
00 01 00 10 00 00 04 00 00 00 00 80 00 00 00 00 \
"], [0], [dnl
OFPT_METER_MOD (OF1.3) (xid=0x2): ADD meter=5 kbps burst stats bands=
type=drop rate=1024 burst_size=128
])
AT_CLEANUP
AT_SETUP([OFPST_METER request - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
AT_CHECK([ovs-ofctl ofp-print "041200180000000200090000000000000000000100000000"], [0], [dnl
OFPST_METER request (OF1.3) (xid=0x2): meter=1
])
AT_CLEANUP
AT_SETUP([OFPST_METER_CONFIG request - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
AT_CHECK([ovs-ofctl ofp-print "0412001800000002000a0000000000000000000100000000"], [0], [dnl
OFPST_METER_CONFIG request (OF1.3) (xid=0x2): meter=1
])
AT_CLEANUP
AT_SETUP([OFPST_METER_FEATURES request - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
AT_CHECK([ovs-ofctl ofp-print "0412001000000002000b000000000000"], [0], [dnl
OFPST_METER_FEATURES request (OF1.3) (xid=0x2):
])
AT_CLEANUP
AT_SETUP([OFPST_METER_FEATURES reply - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
AT_CHECK([ovs-ofctl ofp-print "\
04 13 00 20 00 00 00 02 00 0b 00 00 00 00 00 00 \
00 01 00 00 00 00 00 03 00 00 00 0F 10 02 00 00 \
"], [0], [dnl
OFPST_METER_FEATURES reply (OF1.3) (xid=0x2):
max_meter:65536 max_bands:16 max_color:2
band_types: drop dscp_remark
capabilities: kbps pktps burst stats
])
AT_CLEANUP
AT_SETUP([OFPST_METER_CONFIG reply - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
AT_CHECK([ovs-ofctl ofp-print "\
04 13 00 50 00 00 00 02 00 0a 00 00 00 00 00 00 \
00 28 00 05 00 00 00 01 \
00 01 00 10 00 01 00 00 00 00 05 00 00 00 00 00 \
00 02 00 10 00 10 00 00 00 00 f0 00 00 00 00 00 \
00 18 00 09 00 00 00 02 \
00 01 00 10 00 02 00 00 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
meter=1 kbps burst bands=
type=drop rate=65536 burst_size=1280
type=dscp_remark rate=1048576 burst_size=61440 prec_level=0
meter=2 kbps stats bands=
type=drop rate=131072
])
AT_CLEANUP
AT_SETUP([OFPST_METER reply - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
AT_CHECK([ovs-ofctl ofp-print "\
04 13 00 90 00 00 00 02 00 09 00 00 00 00 00 00 \
00 00 00 01 00 48 00 00 00 00 00 00 00 00 00 05 \
00 00 00 00 00 00 10 00 00 00 00 00 00 02 30 00 \
00 00 01 8a 9a 6e 23 44 \
00 00 00 00 00 00 00 7e 00 00 00 00 00 00 34 33 \
00 00 00 00 00 00 00 e7 00 00 00 00 00 00 94 2e \
00 00 00 02 00 38 00 00 00 00 00 00 00 00 00 02 \
00 00 00 00 00 00 02 00 00 00 00 00 00 00 30 00 \
00 00 01 87 9a 23 6e 44 \
00 00 00 00 00 00 00 2a 00 00 00 00 00 00 04 33 \
"], [0], [dnl
OFPST_METER reply (OF1.3) (xid=0x2):
meter:1 flow_count:5 packet_in_count:4096 byte_in_count:143360 duration:394.2590909252s bands:
0: packet_count:126 byte_count:13363
1: packet_count:231 byte_count:37934
meter:2 flow_count:2 packet_in_count:512 byte_in_count:12288 duration:391.2586013252s bands:
0: packet_count:42 byte_count:1075
])
AT_CLEANUP
AT_SETUP([OFPT_BARRIER_REQUEST - OF1.0]) AT_SETUP([OFPT_BARRIER_REQUEST - OF1.0])
AT_KEYWORDS([ofp-print]) AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print '01 12 00 08 00 00 00 01'], [0], [dnl AT_CHECK([ovs-ofctl ofp-print '01 12 00 08 00 00 00 01'], [0], [dnl