v4.3: Rollback table id 255 to 253 according to OpenFlow spec and current implement Update AT.
v4.2: Fix last table features id to 255. Add more comments. Fix wrong print of last table feature. 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...@huawei.com> --- lib/ofp-print.c | 155 +++++++++++++- lib/ofp-util.c | 623 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/ofp-util.def | 21 ++ lib/ofp-util.h | 130 +++++++++++ tests/ofp-print.at | 172 +++++++++++++++ tests/ofproto.at | 25 ++ 6 files changed, 1125 insertions(+), 1 deletions(-) diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 13705d0..63151a4 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,158 @@ 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 = OFPTT_MAX; + 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) { + if (i < table_start) { + table_start = i; + } + if (i > table_end) { + table_end = i; + } + } + + 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 if (bitmap_count1(bitmap->map, bitmap->end) == 0) { + ds_put_format(s, "There is no next-table."); + } 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[OFPTT_MAX]; + int tfs_num; + const int temp_bitmap_size = OFPTT_ALL; + + memset(tfs, 0, sizeof(tfs)); + + for (i = 0; i < OFPTT_MAX; 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 < OFPTT_MAX; 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 +2678,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 7fc4c7c..c9a3647 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); @@ -4156,6 +4157,608 @@ 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]) { + 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))) { \ + *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) { + VLOG_WARN_RL(&bad_ofmsg_rl, "Decode property failed:%d.", error); + return error; + } + + if (out[type]) { + VLOG_WARN_RL(&bad_ofmsg_rl, "Duplicate property:%"PRIu16".", type); + return OFPERR_OFPBRC_BAD_TYPE; + } + out[type] = prop; + } + + if (left) { + VLOG_WARN_RL(&bad_ofmsg_rl, "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[OFPTT_ALL]; + + uint32_t features_len; + int i; + int tfs_cursor = 0; + int error = 0; + + memset(fs, 0, 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 < OFPTT_MAX; 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; + + bit_count = bitmap_count1(bitmap->map, bitmap->end); + if (bit_count == 0) { + return 0; + } + + oprop = ofpbuf_put_zeros(reply, sizeof *oprop); + + prop_type = table_feature_prop_encode_type(type); + element_size = table_feature_prop_get_size(prop_type); + if (element_size == 0) { + 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 + 1; + ++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 @@ -5178,6 +5781,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" }; @@ -5207,6 +5811,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 @@ -5217,6 +5836,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) \ @@ -5248,6 +5869,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..314b820 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -599,6 +599,129 @@ 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) +}; + +#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: 0 ~ 254 + * 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 +971,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 +980,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 +988,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 +1013,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 2f09c1b..685c97a 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -1978,6 +1978,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 01 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 00 00 00 00 00 00 00 00 03 01 01 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 00 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 253 + Next tables miss: 1 to 253 + 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 be7387d..a9f7c67 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 253 + Next tables miss: 1 to 253 + 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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev