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:
committed by
Ben Pfaff
parent
b4af6ceeea
commit
638a19b045
@@ -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);
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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. */
|
||||||
|
212
lib/ofp-parse.c
212
lib/ofp-parse.c
@@ -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)) {
|
||||||
|
@@ -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 *);
|
||||||
|
|
||||||
|
265
lib/ofp-print.c
265
lib/ofp-print.c
@@ -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;
|
||||||
|
|
||||||
|
362
lib/ofp-util.c
362
lib/ofp-util.c
@@ -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)
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user