[ovs-dev] [PATCH v4.1 3/5] ofp-util: Implement OFPMP_TABLE_FEATURES en/decode
Alexander Wu
alexander.wu at huawei.com
Fri Dec 6 09:28:28 UTC 2013
v4:
1. Delete duplication code.
2. Add new acts in *.def.
3. Update abstract table-features to bitmap.
4. Make decode_openflow13_props more general.
5. Update tests. Correct the wriable oxms.
v3:
1. Update names of functions/macros to make them meaningful.
2. Fix codingstyle.
3. Remove useless logic/struct/function.
4. Make printable messages more friendly.
5. Add OVS_ACTIONS macro to display all action features.
6. Modify type of element_size and print error if 0.
7. Change print of next_tables msg, change enums to OFPUTIL_*.
8. Make all prints human-readable.
9. Update printable messages: instruction/action/oxm/next_table.
10. Update action features, now the actions are correct.
v2:
Restructure implement of OFPMP_TABLE_FEATURES
Change decode_*_raw to normalized pull functions
1. add defines and funcs to decode table features
2. restructure OFPMP_TABLE_FEATURES decode function
restructure the function, now them acts like others.
3. Change big array to defines.
Change big array to defines.(oxm, table_feature_prop)
Fix some names, now they're more meaningful.
4. use macros to restructure implement
5. Restructure get_* to more effective ones. (table_features, oxm)
6. remove useless array and prototype
7. Fix CodingStyle accoring to Simon Horman's suggestions.
8. Fix print of NEXT_TABLE_MISS.
Simon Horman's suggestions:
Fix function paras alignment.
Fix hard coding to marco.
Fix VLOG calls with rl.
Fix CodingStyle:
max chars per line - 79
Delete useless blank line.
Restructure implement by macro.
v1:
ofp-util: Implement the encode/decode Table Features functions
1. Implement the encode/decode table features msgs function, and
NOTE that we implement the decode functions *_raw, maybe we
should change it the ofpbuf_pull?
2. Add function to print OFPMP_TABLE_FEATURES.
But now the print is crude and dirty.
Fix it to bitmap or more desc later.
3. Implement the at for OFPMP_TABLE_FEATURES.
(I've tested it via NOX-OF1.3 too.)
Signed-off-by: Alexander Wu <alexander.wu at huawei.com>
---
lib/ofp-print.c | 149 +++++++++++++-
lib/ofp-util.c | 619 ++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/ofp-util.def | 21 ++
lib/ofp-util.h | 133 +++++++++++
tests/ofp-print.at | 172 +++++++++++++++
tests/ofproto.at | 25 ++
6 files changed, 1118 insertions(+), 1 deletions(-)
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 13705d0..2bcf1b9 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -47,6 +47,7 @@
#include "type-props.h"
#include "unaligned.h"
#include "util.h"
+#include "bitmap.h"
static void ofp_print_queue_name(struct ds *string, uint32_t port);
static void ofp_print_error(struct ds *, enum ofperr);
@@ -2485,6 +2486,152 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
}
+/* Appends a string representation of 'prop' to 's'. */
+static void
+table_feature_prop_format(enum ovs_tfprop_type type,
+ const struct bitmap *bitmap,
+ struct ds *s)
+{
+ size_t i = 0;
+
+ ds_put_format(s, "%s: ", table_feature_prop_get_name(
+ table_feature_prop_encode_type(type)));
+
+ switch (type) {
+ case OVSTFPROP_OFPTFPT13_INSTRUCTIONS:
+ case OVSTFPROP_OFPTFPT13_INSTRUCTIONS_MISS: {
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ ds_put_format(s, "%s,", ovs_instruction_name_from_type(
+ ovs_instruction_type_from_inst_type(i)));
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_NEXT_TABLES:
+ case OVSTFPROP_OFPTFPT13_NEXT_TABLES_MISS: {
+ uint32_t table_start = OFTABLE_NUM;
+ uint32_t table_end = 0;
+
+ /* Currently we're sure the table is continuous. So it's enough to
+ * print the start and end of the next tables only. */
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ table_start = i < table_start ? i : table_start;
+ table_end = i > table_end ? i : table_end;
+ }
+
+ if (table_start < table_end) {
+ ds_put_format(s, "%"PRIu32" to %"PRIu32"", table_start, table_end);
+ } else if (table_start == table_end) {
+ ds_put_format(s, "%"PRIu32, table_start);
+ } else {
+ ofp_print_error(s, OFPERR_OFPTFFC_BAD_ARGUMENT);
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_WRITE_ACTIONS:
+ case OVSTFPROP_OFPTFPT13_WRITE_ACTIONS_MISS:
+ case OVSTFPROP_OFPTFPT13_APPLY_ACTIONS:
+ case OVSTFPROP_OFPTFPT13_APPLY_ACTIONS_MISS: {
+ enum ofp13_action_type action_type;
+
+ BITMAP_FOR_EACH_1(action_type, bitmap->end, bitmap->map) {
+ const char *action_name = NULL;
+ action_name = ofputil_action_name_from_code(
+ ofputil_action_code_from_ofp13_action(action_type));
+ ds_put_format(s, "%s,", action_name);
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_MATCH:
+ case OVSTFPROP_OFPTFPT13_WILDCARDS: {
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ const struct mf_field *mf = mf_from_id(i);
+ ds_put_format(s, "%s", mf->name);
+ if (mf->maskable) {
+ ds_put_format(s, ":%d", 1);
+ }
+ ds_put_format(s, ",");
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_WRITE_SETFIELD:
+ case OVSTFPROP_OFPTFPT13_WRITE_SETFIELD_MISS:
+ case OVSTFPROP_OFPTFPT13_APPLY_SETFIELD:
+ case OVSTFPROP_OFPTFPT13_APPLY_SETFIELD_MISS: {
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ const struct mf_field *mf = mf_from_id(i);
+ ds_put_format(s, "%s", mf->name);
+ ds_put_format(s, ",");
+ }
+ break;
+ }
+ default:
+ ds_put_format(s, "unknown(%u)", table_feature_prop_encode_type(type));
+ break;
+ }
+}
+
+static void
+ofp_print_table_features_stats_single(struct ds *s,
+ const struct ofputil_table_features *tf)
+{
+ int i;
+
+ ds_put_format(s, "\n %"PRIu8":", tf->table_id);
+ ds_put_format(s, " name:%s", tf->name);
+ ds_put_format(s, " metadata_match:%"PRIx64, tf->metadata_match);
+ ds_put_format(s, " metadata_write:%"PRIx64, tf->metadata_write);
+ ds_put_format(s, " config:%"PRIx32, tf->config);
+ ds_put_format(s, " max_entries:%"PRIu32, tf->max_entries);
+ ds_put_format(s, "\n Properties:");
+
+ for (i = 0; i < N_OVS_TFPROPS; i++) {
+ if (!tf->bitmaps[i].map) {
+ continue;
+ }
+
+ ds_put_format(s, "\n ");
+ table_feature_prop_format(i, &tf->bitmaps[i], s);
+ }
+ ds_put_format(s, "\n");
+}
+
+static void
+ofp_print_table_features_stats(struct ds *s, const struct ofp_header *oh)
+{
+ int i;
+ int j;
+ enum ofperr error;
+ uint32_t flag;
+
+ struct ofputil_table_features tfs[OFTABLE_NUM];
+ int tfs_num;
+ const int temp_bitmap_size = 0xff;
+
+ memset(tfs, 0, sizeof(tfs));
+
+ for (i = 0; i < OFTABLE_NUM; i++) {
+ for (j = 0; j < N_OVS_TFPROPS; j++) {
+ tfs[i].bitmaps[j].map = bitmap_allocate(temp_bitmap_size);
+ tfs[i].bitmaps[j].end = temp_bitmap_size;
+ }
+ }
+
+ error = ofputil_pull_table_features(oh, &tfs_num, tfs, &flag);
+ if (error) {
+ ofp_print_error(s, error);
+ }
+
+ for (i = 0; i < tfs_num; i++) {
+ ofp_print_table_features_stats_single(s, &tfs[i]);
+ }
+
+ for (i = 0; i < OFTABLE_NUM; i++) {
+ for (j = 0; j < N_OVS_TFPROPS; j++) {
+ bitmap_free(tfs[i].bitmaps[j].map);
+ }
+ }
+}
+
static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
@@ -2525,7 +2672,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
- ofp_print_not_implemented(string);
+ ofp_print_table_features_stats(string, oh);
break;
case OFPTYPE_HELLO:
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 92e0767..33e0d4f 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -42,6 +42,7 @@
#include "unaligned.h"
#include "type-props.h"
#include "vlog.h"
+#include "bitmap.h"
VLOG_DEFINE_THIS_MODULE(ofp_util);
@@ -4078,6 +4079,604 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
return b;
}
+static enum ofperr
+tfprop_count_n_elem(uint32_t *n_elem, uint16_t length, uint16_t elem_size)
+{
+ int n = 0;
+ if (length % elem_size)
+ return OFPERR_OFPTFFC_BAD_LEN;
+
+ n = length / elem_size;
+ *n_elem = n;
+ return 0;
+}
+
+enum ofp13_table_feature_prop_type
+table_feature_prop_encode_type(enum ovs_tfprop_type type)
+{
+ switch(type) {
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) \
+ case OVSTFPROP_##ENUM: \
+ return ENUM;
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+ default:
+ return -1;
+ }
+}
+
+static enum ovs_tfprop_type
+table_feature_prop_decode_type(enum ofp13_table_feature_prop_type type)
+{
+ switch (type) {
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) \
+ case ENUM: \
+ return OVSTFPROP_##ENUM;
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+ case OFPTFPT13_EXPERIMENTER:
+ case OFPTFPT13_EXPERIMENTER_MISS:
+ default:
+ return -1;
+ }
+}
+
+char *table_feature_prop_get_name(enum ofp13_table_feature_prop_type type)
+{
+ switch (type) {
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) \
+ case ENUM: \
+ return NAME;
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+ case OFPTFPT13_EXPERIMENTER:
+ case OFPTFPT13_EXPERIMENTER_MISS:
+ default:
+ return NULL;
+ }
+}
+
+uint16_t table_feature_prop_get_size(enum ofp13_table_feature_prop_type type)
+{
+ switch (type) {
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) \
+ case ENUM: \
+ return sizeof(STRUCT);
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+ case OFPTFPT13_EXPERIMENTER:
+ case OFPTFPT13_EXPERIMENTER_MISS:
+ default:
+ return 0;
+ }
+}
+
+#define PROP_ALIGN 8
+#define MULTIPART_HDR_LEN 8 /* TYPE:2 FLAG:2 PADDING:4 */
+#define MULTIPART_ALIGN 8
+
+static int
+prop_is_valid(const struct ofp_prop_header *prop, size_t n_prop)
+{
+ uint16_t len = ntohs(prop->length);
+ return (len >= sizeof *prop
+ && (ROUND_UP(len, PROP_ALIGN) / PROP_ALIGN) <= n_prop);
+}
+
+static inline struct ofp_prop_header *
+prop_next(const struct ofp_prop_header *prop)
+{
+ return ((struct ofp_prop_header *) (void *)
+ ((uint8_t *) prop + ROUND_UP(ntohs(prop->length), PROP_ALIGN)));
+}
+
+/* This macro is careful to check for props with bad lengths. */
+#define PROP_FOR_EACH(ITER, LEFT, PROPS, N_PROPS) \
+ for ((ITER) = (PROPS), (LEFT) = (N_PROPS); \
+ (LEFT) > 0 && prop_is_valid(ITER, LEFT); \
+ ((LEFT) -= ROUND_UP(ntohs((ITER)->length), PROP_ALIGN) \
+ / PROP_ALIGN, \
+ (ITER) = prop_next(ITER)))
+
+#define OPROP_DATA(OPROP) ((void *)(OPROP + 1))
+static enum ofperr
+trans_openflow13_tfprop(const struct ofp_prop_header *oprop,
+ struct ofputil_table_features *tf)
+{
+ uint32_t data_len;
+
+ enum ofperr error = 0;
+ uint32_t element_size = 0;
+ uint32_t n_elem = 0;
+ int i;
+
+ enum ovs_tfprop_type prop_type
+ = table_feature_prop_decode_type(ntohs(oprop->type));
+ uint16_t prop_len = ntohs(oprop->length);
+ data_len = prop_len - sizeof *oprop;
+ element_size = table_feature_prop_get_size(ntohs(oprop->type));
+ if (element_size == 0) {
+ return OFPERR_OFPTFFC_BAD_TYPE;
+ } else if (data_len % element_size) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ error = tfprop_count_n_elem(&n_elem, data_len, element_size);
+ if (error) {
+ return error;
+ }
+
+ switch (prop_type) {
+ case OVSTFPROP_OFPTFPT13_INSTRUCTIONS:
+ case OVSTFPROP_OFPTFPT13_INSTRUCTIONS_MISS: {
+ struct ofp11_instruction *oinst = OPROP_DATA(oprop);
+ for (i = 0; i < n_elem; i++) {
+ bitmap_set1(tf->bitmaps[prop_type].map, ntohs(oinst[i].type));
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_NEXT_TABLES:
+ case OVSTFPROP_OFPTFPT13_NEXT_TABLES_MISS: {
+ uint8_t *ontable = OPROP_DATA(oprop);
+ for (i = 0; i < n_elem; i++) {
+ bitmap_set1(tf->bitmaps[prop_type].map, ontable[i]);
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_WRITE_ACTIONS:
+ case OVSTFPROP_OFPTFPT13_WRITE_ACTIONS_MISS:
+ case OVSTFPROP_OFPTFPT13_APPLY_ACTIONS:
+ case OVSTFPROP_OFPTFPT13_APPLY_ACTIONS_MISS: {
+ const struct ofp_action_header *oact = OPROP_DATA(oprop);
+ for (i = 0; i < n_elem; i++) {
+ bitmap_set1(tf->bitmaps[prop_type].map, ntohs(oact[i].type));
+ }
+ break;
+ }
+ case OVSTFPROP_OFPTFPT13_MATCH:
+ case OVSTFPROP_OFPTFPT13_WILDCARDS:
+ case OVSTFPROP_OFPTFPT13_WRITE_SETFIELD:
+ case OVSTFPROP_OFPTFPT13_WRITE_SETFIELD_MISS:
+ case OVSTFPROP_OFPTFPT13_APPLY_SETFIELD:
+ case OVSTFPROP_OFPTFPT13_APPLY_SETFIELD_MISS: {
+ const struct mf_field *mf;
+ uint32_t header;
+ const ovs_be32 *be32 = OPROP_DATA(oprop);
+ for (i = 0; i < n_elem; i++) {
+ header = ntohl(be32[i]);
+ mf = mf_from_nxm_header(header);
+ if (!mf) {
+ VLOG_INFO_RL(&bad_ofmsg_rl, "Bad oxm header %"PRIx32" with "
+ "offset %d in table tf properties.", header, i);
+ continue;
+ }
+ bitmap_set1(tf->bitmaps[prop_type].map, mf->id);
+ }
+ break;
+ }
+ default:
+ return OFPERR_OFPTFFC_BAD_TYPE;
+ }
+ return 0;
+}
+
+static enum ofperr
+table_feature_check_len(const struct ofp13_table_features *feature)
+{
+ uint16_t len = ntohs(feature->length);
+
+ if (len < sizeof *feature || len % 8) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ return 0;
+}
+
+static void
+table_feature_get_id(const struct ofp13_table_features *feature,
+ uint8_t *table_id)
+{
+ *table_id = feature->table_id;
+}
+
+static int
+table_feature_is_valid(const struct ofp13_table_features *feature,
+ size_t n_feature)
+{
+ uint16_t len = ntohs(feature->length);
+ return (!(len % 8)
+ && len >= (sizeof *feature)
+ && (len / sizeof *feature) <= n_feature);
+}
+
+static inline struct ofp13_table_features *
+table_feature_next(const struct ofp13_table_features *feature)
+{
+ return ((struct ofp13_table_features *) (void *)
+ ((uint8_t *) feature + ntohs(feature->length)));
+}
+
+/* This macro is careful to check for props with bad lengths. */
+#define TABLE_FEATURE_FOR_EACH(ITER, LEFT, FEATURES, N_FEATURES) \
+ for ((ITER) = (FEATURES), (LEFT) = (N_FEATURES); \
+ (LEFT) > 0 && table_feature_is_valid(ITER, LEFT); \
+ ((LEFT) -= (ntohs((ITER)->length) \
+ / MULTIPART_ALIGN), \
+ (ITER) = table_feature_next(ITER)))
+
+static enum ofperr
+decode_openflow13_table_features(const struct ofp13_table_features features[],
+ size_t n_features,
+ const struct ofp13_table_features *out[])
+{
+ const struct ofp13_table_features *feature;
+ size_t left;
+
+ TABLE_FEATURE_FOR_EACH (feature, left, features, n_features) {
+ uint8_t table_id;
+ enum ofperr error;
+
+ error = table_feature_check_len(feature);
+ if (error) {
+ return error;
+ }
+
+ table_feature_get_id(feature, &table_id);
+
+ if (out[table_id]) {
+ /* CHECK if we could return a more meaningful type */
+ return OFPERR_OFPTFFC_BAD_TABLE;
+ }
+ out[table_id] = feature;
+ }
+
+ if (left) {
+ VLOG_WARN( "Bad table features format at offset %zu.",
+ (n_features - left) * sizeof *feature);
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ return 0;
+}
+
+static enum ofperr
+decode_openflow13_table_feature_prop(const struct ofp_prop_header *prop,
+ uint16_t *type)
+{
+ uint16_t len = ntohs(prop->length);
+ uint16_t data_len = len > sizeof *prop ? len - sizeof *prop : 0;
+
+ switch (prop->type) {
+ case CONSTANT_HTONS(OFPTFPT13_EXPERIMENTER):
+ case CONSTANT_HTONS(OFPTFPT13_EXPERIMENTER_MISS):
+ return OFPERR_OFPTFFC_BAD_ARGUMENT;
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) \
+ case CONSTANT_HTONS(ENUM): \
+ if (data_len > sizeof(STRUCT) \
+ && !(data_len % sizeof(STRUCT)) ) { \
+ *type = OVSTFPROP_##ENUM; \
+ return 0; \
+ } else { \
+ return OFPERR_OFPBIC_BAD_LEN; \
+ }
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+ default:
+ return OFPERR_OFPTFFC_BAD_TYPE;
+ }
+}
+
+enum ofperr
+decode_openflow13_props(const struct ofp_prop_header props[],
+ size_t n_props,
+ const struct ofp_prop_header *out[],
+ enum ofperr (*decode_openflow13_prop)(
+ const struct ofp_prop_header *, uint16_t *))
+{
+ const struct ofp_prop_header *prop;
+ size_t left;
+
+ PROP_FOR_EACH (prop, left, props, n_props) {
+ uint16_t type;
+ enum ofperr error;
+
+ error = decode_openflow13_prop(prop, &type);
+ if (error) {
+ return error;
+ }
+
+ if (out[type]) {
+ return OFPERR_OFPBRC_BAD_TYPE;
+ }
+ out[type] = prop;
+ }
+
+ if (left) {
+ VLOG_WARN( "Bad property format at offset %zu.",
+ (n_props - left) * PROP_ALIGN);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ return 0;
+}
+
+static enum ofperr
+translate_table_features(struct ofputil_table_features *tf,
+ const struct ofp13_table_features *otf)
+{
+ enum ofperr error;
+ const struct ofp_prop_header *props;
+ uint16_t props_len;
+ const struct ofp_prop_header *ps[N_OVS_TFPROPS];
+ int i;
+
+ memset(ps, 0, N_OVS_TFPROPS * sizeof *ps);
+
+ tf->length = ntohs(otf->length);
+ tf->table_id = otf->table_id;
+ ovs_strlcpy(tf->name, otf->name, OFP_MAX_TABLE_NAME_LEN);
+ tf->metadata_match = ntohll(otf->metadata_match);
+ tf->metadata_write = ntohll(otf->metadata_write);
+ tf->config = ntohl(otf->config);
+ tf->max_entries = ntohl(otf->max_entries);
+
+ props = (const struct ofp_prop_header*)(otf + 1);
+ props_len = ntohs(otf->length) - sizeof(*otf);
+ error = decode_openflow13_props(props, props_len / PROP_ALIGN, ps,
+ decode_openflow13_table_feature_prop);
+ if (error) {
+ return error;
+ }
+
+ for (i = 0; i < N_OVS_TFPROPS; i++) {
+ if (ps[i] == NULL) {
+ continue;
+ }
+
+ error = trans_openflow13_tfprop(ps[i], tf);
+ if (error) {
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+enum ofperr
+ofputil_pull_table_features(const struct ofp_header *oh,
+ int *tfs_num,
+ struct ofputil_table_features tfs[],
+ uint32_t *flag)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ struct ofpbuf msg;
+ enum ofpraw raw;
+
+ const struct ofp13_table_features *features;
+ const struct ofp13_table_features *fs[OFTABLE_NUM];
+
+ uint32_t features_len;
+ int i;
+ int tfs_cursor = 0;
+ int error = 0;
+
+ memset(fs, 0, OFTABLE_NUM * sizeof *fs);
+
+ ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&msg);
+ if (raw != OFPRAW_OFPST13_TABLE_FEATURES_REQUEST
+ && raw != OFPRAW_OFPST13_TABLE_FEATURES_REPLY) {
+ VLOG_DBG_RL(&rl, "Bad openflow msg type(%u).\n", raw);
+ return OFPERR_OFPBRC_BAD_TYPE;
+ }
+
+ if (msg.size == 0) /* stands for GET table_features request */ {
+ *flag = OVS_TF_GET;
+ return 0;
+ }
+
+ /* Else if request contains body, then it's a SET table_features request */
+ *flag = OVS_TF_SET;
+
+ features_len = (ntohs(oh->length) - sizeof(*oh) - MULTIPART_HDR_LEN);
+ features = ofpbuf_try_pull(&msg, features_len);
+ if (features == NULL) {
+ VLOG_WARN_RL(&rl, "Table features length %u is longer than space "
+ "in message length %zu.", features_len, msg.size);
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ error = decode_openflow13_table_features(
+ features, features_len / MULTIPART_ALIGN, fs);
+ if (error) {
+ return error;
+ }
+
+ for (i = 0; i < OFTABLE_NUM; i++) {
+ if (fs[i] == NULL) {
+ continue;
+ }
+
+ translate_table_features(&tfs[tfs_cursor++], fs[i]);
+ }
+
+ *tfs_num = tfs_cursor;
+ return error;
+}
+
+static enum ofperr
+encode_openflow13_tfprop(struct ofpbuf *reply,
+ enum ovs_tfprop_type type,
+ const struct bitmap *bitmap)
+{
+ size_t i;
+ uint32_t prop_type;
+ uint16_t element_size;
+ uint32_t data_len;
+ uint32_t padding_len;
+ uint32_t prop_len;
+ void *data;
+
+ uint32_t bit_count;
+ struct ofp13_table_feature_prop_header *oprop;
+
+ oprop = ofpbuf_put_zeros(reply, sizeof *oprop);
+
+ bit_count = bitmap_count1(bitmap->map, bitmap->end);
+ prop_type = table_feature_prop_encode_type(type);
+ element_size = table_feature_prop_get_size(prop_type);
+ if (0 == element_size) {
+ return OFPERR_OFPTFFC_BAD_TYPE;
+ }
+
+ data_len = bit_count * element_size;
+ prop_len = data_len + sizeof *oprop;
+ padding_len = ROUND_UP(prop_len, PROP_ALIGN) - prop_len;
+
+ oprop->type = htons(prop_type);
+ oprop->length = htons(prop_len);
+
+ data = ofpbuf_put_zeros(reply, data_len + padding_len);
+
+ switch (prop_type) {
+ case OFPTFPT13_INSTRUCTIONS:
+ case OFPTFPT13_INSTRUCTIONS_MISS: {
+ struct ofp11_instruction *oinst = data;
+ int cursor = 0;
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ oinst[cursor].type = htons(i);
+ oinst[cursor].len = htons(8);
+ ++cursor;
+ }
+ break;
+ }
+ case OFPTFPT13_NEXT_TABLES:
+ case OFPTFPT13_NEXT_TABLES_MISS: {
+ uint8_t *ontable = data;
+ int cursor = 0;
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ ontable[cursor] = i;
+ ++cursor;
+ }
+ break;
+ }
+ case OFPTFPT13_WRITE_ACTIONS:
+ case OFPTFPT13_WRITE_ACTIONS_MISS:
+ case OFPTFPT13_APPLY_ACTIONS:
+ case OFPTFPT13_APPLY_ACTIONS_MISS: {
+ struct ofp_action_header *oact = data;
+ int cursor = 0;
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ oact[cursor].type = htons(i);
+ oact[cursor].len = htons(8);
+ ++cursor;
+ }
+ break;
+ }
+ case OFPTFPT13_MATCH:
+ case OFPTFPT13_WILDCARDS:
+ case OFPTFPT13_WRITE_SETFIELD:
+ case OFPTFPT13_WRITE_SETFIELD_MISS:
+ case OFPTFPT13_APPLY_SETFIELD:
+ case OFPTFPT13_APPLY_SETFIELD_MISS: {
+ ovs_be32 *be32 = data;
+ int cursor = 0;
+ uint32_t i;
+ uint32_t oxm_header;
+ BITMAP_FOR_EACH_1(i, bitmap->end, bitmap->map) {
+ oxm_header = mf_from_id(i)->oxm_header;
+ if (!oxm_header) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "Bad OXM bit value %"PRIu32, i);
+ continue;
+ }
+
+ be32[cursor] = htonl(oxm_header);
+ ++cursor;
+ }
+ break;
+ }
+ case OFPTFPT13_EXPERIMENTER:
+ case OFPTFPT13_EXPERIMENTER_MISS:
+ default:
+ return OFPERR_OFPTFFC_BAD_ARGUMENT;
+ }
+
+ return 0;
+}
+
+static enum ofperr
+ofputil_encode_table_features_props(struct ofpbuf *reply,
+ const struct ofputil_table_features *tf)
+{
+ int i;
+
+ for (i = 0; i < N_OVS_TFPROPS; i++) {
+ encode_openflow13_tfprop(reply, i, &tf->bitmaps[i]);
+ }
+
+ return 0;
+}
+
+void
+ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
+ struct list *replies)
+{
+ struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
+ size_t start_otf = reply->size;
+ enum ofpraw raw;
+
+ ofpraw_decode_partial(&raw, reply->data, reply->size);
+ if (raw == OFPRAW_OFPST13_TABLE_FEATURES_REPLY) {
+ struct ofp13_table_features *otf;
+
+ ofpbuf_put_zeros(reply, sizeof *otf);
+ ofputil_encode_table_features_props(reply, tf);
+
+ otf = ofpbuf_at_assert(reply, start_otf, sizeof *otf);
+ otf->length = htons(reply->size - start_otf);
+ otf->table_id = tf->table_id;
+ ovs_strlcpy(otf->name, tf->name, OFP_MAX_TABLE_NAME_LEN);
+ otf->metadata_match = htonll(tf->metadata_match);
+ otf->metadata_write = htonll(tf->metadata_write);
+ otf->config = htonl(tf->config);
+ otf->max_entries = htonl(tf->max_entries);
+ } else {
+ NOT_REACHED();
+ }
+ ofpmp_postappend(replies, start_otf);
+}
+
+/* Returns an OpenFlow group features request for OpenFlow version
+ * 'ofp_version'. */
+struct ofpbuf *
+ofputil_encode_table_features_request(enum ofp_version ofp_version)
+{
+ struct ofpbuf *request = NULL;
+
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ ovs_fatal(0, "dump-table-features needs OpenFlow 1.2 or later "
+ "(\'-O OpenFlow12\')");
+ case OFP12_VERSION:
+ case OFP13_VERSION: {
+ request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
+ ofp_version, 0);
+ break;
+ }
+ default:
+ NOT_REACHED();
+ }
+
+ return request;
+}
+
/* ofputil_table_mod */
/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
@@ -5100,6 +5699,7 @@ static const char *const names[OFPUTIL_N_ACTIONS] = {
NULL,
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME,
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#include "ofp-util.def"
};
@@ -5129,6 +5729,21 @@ ofputil_action_name_from_code(enum ofputil_action_code code)
: "Unknown action";
}
+enum ofputil_action_code
+ofputil_action_code_from_ofp13_action(enum ofp13_action_type type)
+{
+ switch (type) {
+
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case ENUM: \
+ return OFPUTIL_##ENUM;
+#include "ofp-util.def"
+
+ default:
+ return OFPUTIL_ACTION_INVALID;
+ }
+}
+
/* Appends an action of the type specified by 'code' to 'buf' and returns the
* action. Initializes the parts of 'action' that identify it as having type
* <ENUM> and length 'sizeof *action' and zeros the rest. For actions that
@@ -5139,6 +5754,8 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
{
switch (code) {
case OFPUTIL_ACTION_INVALID:
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
NOT_REACHED();
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
@@ -5170,6 +5787,8 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
}
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
OFPAT10_ACTION(ENUM, STRUCT, NAME)
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ OFPAT10_ACTION(ENUM, STRUCT, NAME)
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
void \
ofputil_init_##ENUM(struct STRUCT *s) \
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index fae2bf2..44decae 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -44,6 +44,26 @@ OFPAT11_ACTION(OFPAT11_DEC_NW_TTL, ofp_action_header, 0, NULL)
OFPAT11_ACTION(OFPAT12_SET_FIELD, ofp12_action_set_field, 1, "set_field")
OFPAT11_ACTION(OFPAT11_GROUP, ofp11_action_group, 0, "group")
+#ifndef OFPAT13_ACTION
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
+#endif
+OFPAT13_ACTION(OFPAT13_OUTPUT, ofp11_action_output, 0, "output")
+OFPAT13_ACTION(OFPAT13_COPY_TTL_OUT, ofp_action_header, 0, "copy_ttl_out")
+OFPAT13_ACTION(OFPAT13_COPY_TTL_IN, ofp_action_header, 0, "copy_ttl_in")
+OFPAT13_ACTION(OFPAT13_SET_MPLS_TTL, ofp11_action_mpls_ttl, 0, "set_mpls_ttl")
+OFPAT13_ACTION(OFPAT13_DEC_MPLS_TTL, ofp_action_header, 0, "dec_mpls_ttl")
+OFPAT13_ACTION(OFPAT13_PUSH_VLAN, ofp11_action_push, 0, "push_vlan")
+OFPAT13_ACTION(OFPAT13_POP_VLAN, ofp_action_header, 0, "pop_vlan")
+OFPAT13_ACTION(OFPAT13_PUSH_MPLS, ofp11_action_push, 0, "push_mpls")
+OFPAT13_ACTION(OFPAT13_POP_MPLS, ofp11_action_pop_mpls, 0, "pop_mpls")
+OFPAT13_ACTION(OFPAT13_SET_QUEUE, ofp11_action_set_queue, 0, "set_queue")
+OFPAT13_ACTION(OFPAT13_GROUP, ofp11_action_group, 0, "group")
+OFPAT13_ACTION(OFPAT13_SET_NW_TTL, ofp11_action_nw_ttl, 0, "set_nw_ttl")
+OFPAT13_ACTION(OFPAT13_DEC_NW_TTL, ofp_action_header, 0, "dec_nw_ttl")
+OFPAT13_ACTION(OFPAT13_SET_FIELD, ofp12_action_set_field, 1, "set_field")
+OFPAT13_ACTION(OFPAT13_PUSH_PBB, ofp11_action_push, 0, "push_pbb")
+OFPAT13_ACTION(OFPAT13_POP_PBB, ofp_action_header, 0, "pop_pbb")
+
#ifndef NXAST_ACTION
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
#endif
@@ -80,4 +100,5 @@ NXAST_ACTION(NXAST_SAMPLE, nx_action_sample, 0, "sample")
#undef OFPAT10_ACTION
#undef OFPAT11_ACTION
+#undef OFPAT13_ACTION
#undef NXAST_ACTION
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index fef85e0..7f0223c 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -599,6 +599,132 @@ enum ofperr ofputil_decode_table_mod(const struct ofp_header *,
struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *,
enum ofputil_protocol);
+enum ovs_table_features_flag {
+ OVS_TF_GET = (1 << 0),
+ OVS_TF_SET = (1 << 1)
+};
+
+/* Same as N_TABLES, fix N_TABLES here */
+#define OFTABLE_NUM 0xff
+
+#define OVS_TABLE_FEATURE_PROPS \
+ DEFINE_TFPROP(OFPTFPT13_INSTRUCTIONS, \
+ struct ofp11_instruction, instruction_array, \
+ "Instruction") \
+ DEFINE_TFPROP(OFPTFPT13_INSTRUCTIONS_MISS, \
+ struct ofp11_instruction, instruction_array, \
+ "Instruction miss") \
+ DEFINE_TFPROP(OFPTFPT13_NEXT_TABLES, \
+ uint8_t, next_table_array, \
+ "Next tables") \
+ DEFINE_TFPROP(OFPTFPT13_NEXT_TABLES_MISS, \
+ uint8_t, next_table_array, \
+ "Next tables miss") \
+ DEFINE_TFPROP(OFPTFPT13_WRITE_ACTIONS, \
+ struct ofp_action_header, action_array, \
+ "Write actions") \
+ DEFINE_TFPROP(OFPTFPT13_WRITE_ACTIONS_MISS, \
+ struct ofp_action_header, action_array, \
+ "Write actions miss") \
+ DEFINE_TFPROP(OFPTFPT13_APPLY_ACTIONS, \
+ struct ofp_action_header, action_array, \
+ "Apply actions") \
+ DEFINE_TFPROP(OFPTFPT13_APPLY_ACTIONS_MISS, \
+ struct ofp_action_header, action_array, \
+ "Apply actions miss") \
+ DEFINE_TFPROP(OFPTFPT13_MATCH, \
+ ovs_be32, oxm_array, \
+ "Match") \
+ DEFINE_TFPROP(OFPTFPT13_WILDCARDS, \
+ ovs_be32, oxm_array, \
+ "Wildcards") \
+ DEFINE_TFPROP(OFPTFPT13_WRITE_SETFIELD, \
+ ovs_be32, oxm_array_writable, \
+ "Write setfield") \
+ DEFINE_TFPROP(OFPTFPT13_WRITE_SETFIELD_MISS, \
+ ovs_be32, oxm_array_writable, \
+ "Write setfield miss") \
+ DEFINE_TFPROP(OFPTFPT13_APPLY_SETFIELD, \
+ ovs_be32, oxm_array_writable, \
+ "Apply setfield") \
+ DEFINE_TFPROP(OFPTFPT13_APPLY_SETFIELD_MISS, \
+ ovs_be32, oxm_array_writable, \
+ "Apply setfield miss")
+
+enum {
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) + 1
+ N_OVS_TFPROPS = OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+};
+
+enum ovs_tfprop_type {
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) OVSTFPROP_##ENUM,
+ OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+};
+
+struct bitmap {
+ uint32_t end;
+ unsigned long *map;
+};
+
+/* Common property header of network byte order. */
+struct ofp_prop_header {
+ ovs_be16 type;
+ ovs_be16 length;
+};
+
+/* Common property header of host byte order. */
+struct prop_header {
+ uint16_t type;
+ uint16_t length;
+};
+
+/* Abstract function to decode props.
+ * Implement the decode_openflow13_prop callback to use it. */
+enum ofperr
+decode_openflow13_props(const struct ofp_prop_header props[],
+ size_t n_props,
+ const struct ofp_prop_header *out[],
+ enum ofperr (*decode_openflow13_prop)(
+ const struct ofp_prop_header *, uint16_t *));
+
+/* Abstract ofp13_table_features */
+struct ofputil_table_features {
+ uint16_t length; /* Length is padded to 64 bits. */
+ uint8_t table_id; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ char name[OFP_MAX_TABLE_NAME_LEN];
+ uint64_t metadata_match; /* Bits of metadata table can match. */
+ uint64_t metadata_write; /* Bits of metadata table can write. */
+ uint32_t config; /* Bitmap of OFPTC_* values */
+ uint32_t max_entries; /* Max number of entries supported. */
+
+ /* The bitmaps stores table features OFPTFPT13_* properties.
+ * Here are valid bits:
+ * Instructions: OFPIT11_GOTO_TABLE ~ OFPIT13_METER
+ * Next tables: 1 ~ 255
+ * Actions: OFPAT13_OUTPUT ~ OFPAT13_POP_PBB
+ * OXMs(_writable): MFF_TUN_ID ~ MFF_N_IDS
+ */
+ struct bitmap bitmaps[N_OVS_TFPROPS];
+};
+
+enum ofp13_table_feature_prop_type table_feature_prop_encode_type(
+ enum ovs_tfprop_type type);
+enum ofperr ofputil_pull_table_features(const struct ofp_header *oh,
+ int *n,
+ struct ofputil_table_features tfs[],
+ uint32_t *flag);
+struct ofpbuf *ofputil_encode_table_features_request(
+ enum ofp_version ofp_version);
+void ofputil_append_table_features_reply(
+ const struct ofputil_table_features *tf,
+ struct list *replies);
+
+uint16_t table_feature_prop_get_size(enum ofp13_table_feature_prop_type type);
+char *table_feature_prop_get_name(enum ofp13_table_feature_prop_type type);
+
/* Meter band configuration for all supported band types. */
struct ofputil_meter_band {
uint16_t type;
@@ -848,6 +974,7 @@ enum OVS_PACKED_ENUM ofputil_action_code {
OFPUTIL_ACTION_INVALID,
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) OFPUTIL_##ENUM,
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
#include "ofp-util.def"
};
@@ -856,6 +983,7 @@ enum OVS_PACKED_ENUM ofputil_action_code {
enum {
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) + 1
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
OFPUTIL_N_ACTIONS = 1
#include "ofp-util.def"
@@ -863,6 +991,8 @@ enum {
int ofputil_action_code_from_name(const char *);
const char * ofputil_action_name_from_code(enum ofputil_action_code code);
+enum ofputil_action_code ofputil_action_code_from_ofp13_action(
+ enum ofp13_action_type type);
void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
@@ -886,6 +1016,9 @@ void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
void ofputil_init_##ENUM(struct STRUCT *); \
struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ void ofputil_init_##ENUM(struct STRUCT *); \
+ struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
void ofputil_init_##ENUM(struct STRUCT *); \
struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 82e8c3d..e9cc5a9 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1963,6 +1963,178 @@ meter:2 flow_count:2 packet_in_count:512 byte_in_count:12288 duration:391.170094
])
AT_CLEANUP
+AT_SETUP([OFPST_TABLE_FEATURES request - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 13 09 40 00 00 00 d5 00 0c 00 01 00 00 00 00 \
+09 30 00 00 00 00 00 00 74 61 62 6c 65 30 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff \
+ff ff ff ff ff ff ff ff 00 00 00 03 00 0f 42 40 \
+00 00 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \
+00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \
+00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \
+00 01 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \
+00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \
+00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \
+00 02 01 02 01 02 03 04 05 06 07 08 09 0a 0b 0c \
+0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c \
+1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c \
+2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c \
+3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c \
+4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c \
+5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c \
+6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c \
+7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c \
+8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c \
+9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac \
+ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc \
+bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc \
+cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc \
+dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec \
+ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc \
+fd fe 00 00 00 00 00 00 00 03 01 02 01 02 03 04 \
+05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 \
+15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 \
+25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 \
+35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 \
+45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 \
+55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 \
+65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 \
+75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 \
+85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 \
+95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 \
+a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 \
+b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 \
+c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 \
+d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 \
+e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 \
+f5 f6 f7 f8 f9 fa fb fc fd fe 00 00 00 00 00 00 \
+00 04 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \
+00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \
+00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \
+00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \
+00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \
+00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \
+00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \
+00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \
+00 00 00 00 00 00 00 00 00 05 00 84 00 00 00 08 \
+00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \
+00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \
+00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \
+00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \
+00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \
+00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \
+00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \
+00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \
+00 06 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \
+00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \
+00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \
+00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \
+00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \
+00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \
+00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \
+00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \
+00 00 00 00 00 00 00 00 00 07 00 84 00 00 00 08 \
+00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \
+00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \
+00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \
+00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \
+00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \
+00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \
+00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \
+00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \
+00 08 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \
+80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \
+80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \
+80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \
+80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \
+80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \
+00 0a 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \
+80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \
+80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \
+80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \
+80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \
+80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \
+00 0c 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \
+80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \
+80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \
+80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \
+80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \
+80 00 22 02 80 00 24 02 00 0d 00 a8 80 00 4c 08 \
+00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \
+80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \
+00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \
+00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \
+00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \
+80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \
+00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \
+80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+00 0e 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \
+80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \
+80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \
+80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \
+80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \
+80 00 22 02 80 00 24 02 00 0f 00 a8 80 00 4c 08 \
+00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \
+80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \
+00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \
+00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \
+00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \
+80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \
+00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \
+80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+"], [0], [dnl
+OFPST_TABLE_FEATURES reply (OF1.3) (xid=0xd5):
+ 0: name:table0 metadata_match:ffffffffffffffff metadata_write:ffffffffffffffff config:3 max_entries:1000000
+ Properties:
+ Instruction: goto_table,write_metadata,write_actions,apply_actions,clear_actions,
+ Instruction miss: goto_table,write_metadata,write_actions,apply_actions,clear_actions,
+ Next tables: 1 to 254
+ Next tables miss: 1 to 254
+ Write actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Write actions miss: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Apply actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Apply actions miss: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Match: tun_id:1,tun_src:1,tun_dst:1,metadata:1,in_port,in_port_oxm,pkt_mark:1,reg0:1,reg1:1,reg2:1,reg3:1,reg4:1,reg5:1,reg6:1,reg7:1,eth_src:1,eth_dst:1,eth_type,vlan_tci:1,vlan_vid:1,vlan_pcp,mpls_label,mpls_tc,mpls_bos,ip_src:1,ip_dst:1,ipv6_src:1,ipv6_dst:1,ipv6_label:1,nw_proto,nw_tos,ip_dscp,nw_ecn,nw_ttl,ip_frag:1,arp_op,arp_spa:1,arp_tpa:1,arp_sha:1,arp_tha:1,tcp_src:1,tcp_dst:1,tcp_flags:1,udp_src:1,udp_dst:1,sctp_src:1,sctp_dst:1,icmp_type,icmp_code,icmpv6_type,icmpv6_code,nd_target:1,nd_sll:1,nd_tll:1,
+ Wildcards: tun_id:1,tun_src:1,tun_dst:1,metadata:1,in_port,in_port_oxm,pkt_mark:1,reg0:1,reg1:1,reg2:1,reg3:1,reg4:1,reg5:1,reg6:1,reg7:1,eth_src:1,eth_dst:1,eth_type,vlan_tci:1,vlan_vid:1,vlan_pcp,mpls_label,mpls_tc,mpls_bos,ip_src:1,ip_dst:1,ipv6_src:1,ipv6_dst:1,ipv6_label:1,nw_proto,nw_tos,ip_dscp,nw_ecn,nw_ttl,ip_frag:1,arp_op,arp_spa:1,arp_tpa:1,arp_sha:1,arp_tha:1,tcp_src:1,tcp_dst:1,tcp_flags:1,udp_src:1,udp_dst:1,sctp_src:1,sctp_dst:1,icmp_type,icmp_code,icmpv6_type,icmpv6_code,nd_target:1,nd_sll:1,nd_tll:1,
+ Write setfield: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+ Write setfield miss: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+ Apply setfield: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+ Apply setfield miss: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+])
+AT_CLEANUP
+
AT_SETUP([OFPT_BARRIER_REQUEST - OF1.0])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print '01 12 00 08 00 00 00 01'], [0], [dnl
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 27b6b34..f5655e6 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -335,6 +335,31 @@ OFPST_GROUP reply (OF1.1):
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto - table feature - (OpenFlow 1.3)])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-table-features br0], [0], [stdout])
+AT_CHECK([[grep -B 1 -C 15 -w table0 stdout]], [0], [dnl
+OFPST_TABLE_FEATURES reply (OF1.3) (xid=0x2):
+ 0: name:table0 metadata_match:ffffffffffffffff metadata_write:ffffffffffffffff config:3 max_entries:1000000
+ Properties:
+ Instruction: goto_table,write_metadata,write_actions,apply_actions,clear_actions,
+ Instruction miss: goto_table,write_metadata,write_actions,apply_actions,clear_actions,
+ Next tables: 1 to 254
+ Next tables miss: 1 to 254
+ Write actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Write actions miss: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Apply actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Apply actions miss: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb,
+ Match: tun_id:1,tun_src:1,tun_dst:1,metadata:1,in_port,in_port_oxm,pkt_mark:1,reg0:1,reg1:1,reg2:1,reg3:1,reg4:1,reg5:1,reg6:1,reg7:1,eth_src:1,eth_dst:1,eth_type,vlan_tci:1,vlan_vid:1,vlan_pcp,mpls_label,mpls_tc,mpls_bos,ip_src:1,ip_dst:1,ipv6_src:1,ipv6_dst:1,ipv6_label:1,nw_proto,nw_tos,ip_dscp,nw_ecn,nw_ttl,ip_frag:1,arp_op,arp_spa:1,arp_tpa:1,arp_sha:1,arp_tha:1,tcp_src:1,tcp_dst:1,tcp_flags:1,udp_src:1,udp_dst:1,sctp_src:1,sctp_dst:1,icmp_type,icmp_code,icmpv6_type,icmpv6_code,nd_target:1,nd_sll:1,nd_tll:1,
+ Wildcards: tun_id:1,tun_src:1,tun_dst:1,metadata:1,in_port,in_port_oxm,pkt_mark:1,reg0:1,reg1:1,reg2:1,reg3:1,reg4:1,reg5:1,reg6:1,reg7:1,eth_src:1,eth_dst:1,eth_type,vlan_tci:1,vlan_vid:1,vlan_pcp,mpls_label,mpls_tc,mpls_bos,ip_src:1,ip_dst:1,ipv6_src:1,ipv6_dst:1,ipv6_label:1,nw_proto,nw_tos,ip_dscp,nw_ecn,nw_ttl,ip_frag:1,arp_op,arp_spa:1,arp_tpa:1,arp_sha:1,arp_tha:1,tcp_src:1,tcp_dst:1,tcp_flags:1,udp_src:1,udp_dst:1,sctp_src:1,sctp_dst:1,icmp_type,icmp_code,icmpv6_type,icmpv6_code,nd_target:1,nd_sll:1,nd_tll:1,
+ Write setfield: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+ Write setfield miss: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+ Apply setfield: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+ Apply setfield miss: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst,
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto - mod-port (OpenFlow 1.0)])
OVS_VSWITCHD_START
for command_config_state in \
--
1.7.3.1.msysgit.0
More information about the dev
mailing list