diff options
-rw-r--r-- | lib/ofp-print.c | 387 | ||||
-rw-r--r-- | lib/ofp-util.c | 514 | ||||
-rw-r--r-- | lib/ofp-util.h | 35 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.c | 33 | ||||
-rw-r--r-- | ofproto/ofproto-provider.h | 68 | ||||
-rw-r--r-- | ofproto/ofproto.c | 168 | ||||
-rw-r--r-- | tests/ofp-print.at | 100 | ||||
-rw-r--r-- | tests/ofproto-dpif.at | 51 | ||||
-rw-r--r-- | tests/ofproto.at | 108 |
9 files changed, 848 insertions, 616 deletions
diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 2b0b20f2b..01d34b1cf 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -51,7 +51,9 @@ static void ofp_print_queue_name(struct ds *string, uint32_t port); static void ofp_print_error(struct ds *, enum ofperr); - +static void ofp_print_table_features(struct ds *, + const struct ofputil_table_features *, + const struct ofputil_table_stats *); /* Returns a string that represents the contents of the Ethernet frame in the * 'len' bytes starting at 'data'. The caller must free the returned string.*/ @@ -1573,216 +1575,27 @@ ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh, } static void -ofp_print_one_ofpst_table_reply(struct ds *string, enum ofp_version ofp_version, - const char *name, struct ofp12_table_stats *ts) -{ - char name_[OFP_MAX_TABLE_NAME_LEN + 1]; - - /* ofp13_table_stats is different */ - if (ofp_version > OFP12_VERSION) { - return; - } - - ovs_strlcpy(name_, name, sizeof name_); - - ds_put_format(string, " %d: %-8s: ", ts->table_id, name_); - ds_put_format(string, "wild=0x%05"PRIx64", ", ntohll(ts->wildcards)); - ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries)); - ds_put_format(string, "active=%"PRIu32"\n", ntohl(ts->active_count)); - ds_put_cstr(string, " "); - ds_put_format(string, "lookup=%"PRIu64", ", ntohll(ts->lookup_count)); - ds_put_format(string, "matched=%"PRIu64"\n", ntohll(ts->matched_count)); - - if (ofp_version < OFP11_VERSION) { - return; - } - - ds_put_cstr(string, " "); - ds_put_format(string, "match=0x%08"PRIx64", ", ntohll(ts->match)); - ds_put_format(string, "instructions=0x%08"PRIx32", ", - ntohl(ts->instructions)); - ds_put_format(string, "config=0x%08"PRIx32"\n", ntohl(ts->config)); - ds_put_cstr(string, " "); - ds_put_format(string, "write_actions=0x%08"PRIx32", ", - ntohl(ts->write_actions)); - ds_put_format(string, "apply_actions=0x%08"PRIx32"\n", - ntohl(ts->apply_actions)); - - if (ofp_version < OFP12_VERSION) { - return; - } - - ds_put_cstr(string, " "); - ds_put_format(string, "write_setfields=0x%016"PRIx64"\n", - ntohll(ts->write_setfields)); - ds_put_cstr(string, " "); - ds_put_format(string, "apply_setfields=0x%016"PRIx64"\n", - ntohll(ts->apply_setfields)); - ds_put_cstr(string, " "); - ds_put_format(string, "metadata_match=0x%016"PRIx64"\n", - ntohll(ts->metadata_match)); - ds_put_cstr(string, " "); - ds_put_format(string, "metadata_write=0x%016"PRIx64"\n", - ntohll(ts->metadata_write)); -} - -static void -ofp_print_ofpst_table_reply13(struct ds *string, const struct ofp_header *oh, - int verbosity) -{ - struct ofp13_table_stats *ts; - struct ofpbuf b; - size_t n; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - ofpraw_pull_assert(&b); - - n = ofpbuf_size(&b) / sizeof *ts; - ds_put_format(string, " %"PRIuSIZE" tables\n", n); - if (verbosity < 1) { - return; - } - - for (;;) { - ts = ofpbuf_try_pull(&b, sizeof *ts); - if (!ts) { - return; - } - ds_put_format(string, - " %d: active=%"PRIu32", lookup=%"PRIu64 \ - ", matched=%"PRIu64"\n", - ts->table_id, ntohl(ts->active_count), - ntohll(ts->lookup_count), ntohll(ts->matched_count)); - } -} - -static void -ofp_print_ofpst_table_reply12(struct ds *string, const struct ofp_header *oh, - int verbosity) -{ - struct ofp12_table_stats *ts; - struct ofpbuf b; - size_t n; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - ofpraw_pull_assert(&b); - - n = ofpbuf_size(&b) / sizeof *ts; - ds_put_format(string, " %"PRIuSIZE" tables\n", n); - if (verbosity < 1) { - return; - } - - for (;;) { - ts = ofpbuf_try_pull(&b, sizeof *ts); - if (!ts) { - return; - } - - ofp_print_one_ofpst_table_reply(string, OFP12_VERSION, ts->name, ts); - } -} - -static void -ofp_print_ofpst_table_reply11(struct ds *string, const struct ofp_header *oh, - int verbosity) -{ - struct ofp11_table_stats *ts; - struct ofpbuf b; - size_t n; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - ofpraw_pull_assert(&b); - - n = ofpbuf_size(&b) / sizeof *ts; - ds_put_format(string, " %"PRIuSIZE" tables\n", n); - if (verbosity < 1) { - return; - } - - for (;;) { - struct ofp12_table_stats ts12; - - ts = ofpbuf_try_pull(&b, sizeof *ts); - if (!ts) { - return; - } - - ts12.table_id = ts->table_id; - ts12.wildcards = htonll(ntohl(ts->wildcards)); - ts12.max_entries = ts->max_entries; - ts12.active_count = ts->active_count; - ts12.lookup_count = ts->lookup_count; - ts12.matched_count = ts->matched_count; - ts12.match = htonll(ntohl(ts->match)); - ts12.instructions = ts->instructions; - ts12.config = ts->config; - ts12.write_actions = ts->write_actions; - ts12.apply_actions = ts->apply_actions; - ofp_print_one_ofpst_table_reply(string, OFP11_VERSION, ts->name, &ts12); - } -} - -static void -ofp_print_ofpst_table_reply10(struct ds *string, const struct ofp_header *oh, - int verbosity) +ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh) { - struct ofp10_table_stats *ts; struct ofpbuf b; - size_t n; ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - n = ofpbuf_size(&b) / sizeof *ts; - ds_put_format(string, " %"PRIuSIZE" tables\n", n); - if (verbosity < 1) { - return; - } - for (;;) { - struct ofp12_table_stats ts12; + struct ofputil_table_features features; + struct ofputil_table_stats stats; + int retval; - ts = ofpbuf_try_pull(&b, sizeof *ts); - if (!ts) { + retval = ofputil_decode_table_stats_reply(&b, &stats, &features); + if (retval) { + if (retval != EOF) { + ofp_print_error(string, retval); + } return; } - ts12.table_id = ts->table_id; - ts12.wildcards = htonll(ntohl(ts->wildcards)); - ts12.max_entries = ts->max_entries; - ts12.active_count = ts->active_count; - ts12.lookup_count = get_32aligned_be64(&ts->lookup_count); - ts12.matched_count = get_32aligned_be64(&ts->matched_count); - ofp_print_one_ofpst_table_reply(string, OFP10_VERSION, ts->name, &ts12); - } -} - -static void -ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh, - int verbosity) -{ - switch ((enum ofp_version)oh->version) { - case OFP15_VERSION: - case OFP14_VERSION: - case OFP13_VERSION: - ofp_print_ofpst_table_reply13(string, oh, verbosity); - break; - - case OFP12_VERSION: - ofp_print_ofpst_table_reply12(string, oh, verbosity); - break; - - case OFP11_VERSION: - ofp_print_ofpst_table_reply11(string, oh, verbosity); - break; - - case OFP10_VERSION: - ofp_print_ofpst_table_reply10(string, oh, verbosity); - break; - - default: - OVS_NOT_REACHED(); + ofp_print_table_features(string, &features, &stats); } } @@ -2495,22 +2308,21 @@ static void print_table_action_features(struct ds *s, const struct ofputil_table_action_features *taf) { - ds_put_cstr(s, " actions: "); - ofpact_bitmap_format(taf->ofpacts, s); - ds_put_char(s, '\n'); + if (taf->ofpacts) { + ds_put_cstr(s, " actions: "); + ofpact_bitmap_format(taf->ofpacts, s); + ds_put_char(s, '\n'); + } - ds_put_cstr(s, " supported on Set-Field: "); if (!bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS)) { int i; + ds_put_cstr(s, " supported on Set-Field:"); BITMAP_FOR_EACH_1 (i, MFF_N_IDS, taf->set_fields.bm) { - ds_put_format(s, "%s,", mf_from_id(i)->name); + ds_put_format(s, " %s", mf_from_id(i)->name); } - ds_chomp(s, ','); - } else { - ds_put_cstr(s, "none"); + ds_put_char(s, '\n'); } - ds_put_char(s, '\n'); } static bool @@ -2521,30 +2333,38 @@ table_action_features_equal(const struct ofputil_table_action_features *a, && bitmap_equal(a->set_fields.bm, b->set_fields.bm, MFF_N_IDS)); } +static bool +table_action_features_empty(const struct ofputil_table_action_features *taf) +{ + return !taf->ofpacts && bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS); +} + static void print_table_instruction_features( struct ds *s, const struct ofputil_table_instruction_features *tif) { int start, end; - ds_put_cstr(s, " next tables: "); - for (start = bitmap_scan(tif->next, 1, 0, 255); start < 255; - start = bitmap_scan(tif->next, 1, end, 255)) { - end = bitmap_scan(tif->next, 0, start + 1, 255); - if (end == start + 1) { - ds_put_format(s, "%d,", start); - } else { - ds_put_format(s, "%d-%d,", start, end - 1); + if (!bitmap_is_all_zeros(tif->next, 255)) { + ds_put_cstr(s, " next tables: "); + for (start = bitmap_scan(tif->next, 1, 0, 255); start < 255; + start = bitmap_scan(tif->next, 1, end, 255)) { + end = bitmap_scan(tif->next, 0, start + 1, 255); + if (end == start + 1) { + ds_put_format(s, "%d,", start); + } else { + ds_put_format(s, "%d-%d,", start, end - 1); + } } + ds_chomp(s, ','); + if (ds_last(s) == ' ') { + ds_put_cstr(s, "none"); + } + ds_put_char(s, '\n'); } - ds_chomp(s, ','); - if (ds_last(s) == ' ') { - ds_put_cstr(s, "none"); - } - ds_put_char(s, '\n'); - ds_put_cstr(s, " instructions: "); if (tif->instructions) { + ds_put_cstr(s, " instructions: "); int i; for (i = 0; i < 32; i++) { @@ -2553,19 +2373,18 @@ print_table_instruction_features( } } ds_chomp(s, ','); - } else { - ds_put_cstr(s, "none"); + ds_put_char(s, '\n'); } - ds_put_char(s, '\n'); - if (table_action_features_equal(&tif->write, &tif->apply)) { - ds_put_cstr(s, " Write-Actions and Apply-Actions features:\n"); - print_table_action_features(s, &tif->write); - } else { + if (!table_action_features_equal(&tif->write, &tif->apply)) { ds_put_cstr(s, " Write-Actions features:\n"); print_table_action_features(s, &tif->write); ds_put_cstr(s, " Apply-Actions features:\n"); print_table_action_features(s, &tif->apply); + } else if (tif->write.ofpacts + || !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) { + ds_put_cstr(s, " Write-Actions and Apply-Actions features:\n"); + print_table_action_features(s, &tif->write); } } @@ -2580,51 +2399,65 @@ table_instruction_features_equal( && table_action_features_equal(&a->apply, &b->apply)); } -static void -ofp_print_table_features(struct ds *s, const struct ofp_header *oh) +static bool +table_instruction_features_empty( + const struct ofputil_table_instruction_features *tif) { - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - - for (;;) { - struct ofputil_table_features tf; - int retval; - int i; + return (bitmap_is_all_zeros(tif->next, 255) + && !tif->instructions + && table_action_features_empty(&tif->write) + && table_action_features_empty(&tif->apply)); +} - retval = ofputil_decode_table_features(&b, &tf, true); - if (retval) { - if (retval != EOF) { - ofp_print_error(s, retval); - } - return; - } +static void +ofp_print_table_features(struct ds *s, + const struct ofputil_table_features *features, + const struct ofputil_table_stats *stats) +{ + int i; - ds_put_format(s, "\n table %"PRIu8":\n", tf.table_id); - ds_put_format(s, " name=\"%s\"\n", tf.name); + ds_put_format(s, "\n table %"PRIu8, features->table_id); + if (features->name[0]) { + ds_put_format(s, " (\"%s\")", features->name); + } + ds_put_cstr(s, ":\n"); + if (stats) { + ds_put_format(s, " active=%"PRIu32", ", stats->active_count); + ds_put_format(s, "lookup=%"PRIu64", ", stats->lookup_count); + ds_put_format(s, "matched=%"PRIu64"\n", stats->matched_count); + } + if (features->metadata_match || features->metadata_match) { ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n", - ntohll(tf.metadata_match), ntohll(tf.metadata_write)); + ntohll(features->metadata_match), + ntohll(features->metadata_write)); + } + if (features->config) { ds_put_cstr(s, " config="); - ofp_print_table_miss_config(s, tf.config); + ofp_print_table_miss_config(s, features->config); + } - ds_put_format(s, " max_entries=%"PRIu32"\n", tf.max_entries); + if (features->max_entries) { + ds_put_format(s, " max_entries=%"PRIu32"\n", features->max_entries); + } - if (table_instruction_features_equal(&tf.nonmiss, &tf.miss)) { - ds_put_cstr(s, " instructions (table miss and others):\n"); - print_table_instruction_features(s, &tf.nonmiss); - } else { - ds_put_cstr(s, " instructions (other than table miss):\n"); - print_table_instruction_features(s, &tf.nonmiss); - ds_put_cstr(s, " instructions (table miss):\n"); - print_table_instruction_features(s, &tf.miss); - } + if (!table_instruction_features_equal(&features->nonmiss, + &features->miss)) { + ds_put_cstr(s, " instructions (other than table miss):\n"); + print_table_instruction_features(s, &features->nonmiss); + ds_put_cstr(s, " instructions (table miss):\n"); + print_table_instruction_features(s, &features->miss); + } else if (!table_instruction_features_empty(&features->nonmiss)) { + ds_put_cstr(s, " instructions (table miss and others):\n"); + print_table_instruction_features(s, &features->nonmiss); + } + if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)){ ds_put_cstr(s, " matching:\n"); - BITMAP_FOR_EACH_1 (i, MFF_N_IDS, tf.match.bm) { + BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) { const struct mf_field *f = mf_from_id(i); - bool mask = bitmap_is_set(tf.mask.bm, i); - bool wildcard = bitmap_is_set(tf.wildcard.bm, i); + bool mask = bitmap_is_set(features->mask.bm, i); + bool wildcard = bitmap_is_set(features->wildcard.bm, i); ds_put_format(s, " %s: %s\n", f->name, @@ -2635,6 +2468,28 @@ ofp_print_table_features(struct ds *s, const struct ofp_header *oh) } } +static void +ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh) +{ + struct ofpbuf b; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + + for (;;) { + struct ofputil_table_features tf; + int retval; + + retval = ofputil_decode_table_features(&b, &tf, true); + if (retval) { + if (retval != EOF) { + ofp_print_error(s, retval); + } + return; + } + ofp_print_table_features(s, &tf, NULL); + } +} + static const char * bundle_flags_to_name(uint32_t bit) { @@ -2760,7 +2615,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_table_features(string, oh); + ofp_print_table_features_reply(string, oh); break; case OFPTYPE_HELLO: @@ -2911,7 +2766,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, case OFPTYPE_TABLE_STATS_REPLY: ofp_print_stats(string, oh); - ofp_print_ofpst_table_reply(string, oh, verbosity); + ofp_print_table_stats_reply(string, oh); break; case OFPTYPE_AGGREGATE_STATS_REPLY: diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 0b78fee1b..c6027301d 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4606,6 +4606,8 @@ ofputil_decode_table_features(struct ofpbuf *msg, struct ofp13_table_features *otf; unsigned int len; + memset(tf, 0, sizeof *tf); + if (!msg->frame) { ofpraw_pull_assert(msg); } @@ -4991,108 +4993,160 @@ ofputil_decode_role_status(const struct ofp_header *oh, /* Table stats. */ +/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be + * matched and a field that must be wildcarded. This function returns a bitmap + * that contains both kinds of fields. */ +static struct mf_bitmap +wild_or_nonmatchable_fields(const struct ofputil_table_features *features) +{ + struct mf_bitmap wc = features->match; + bitmap_not(wc.bm, MFF_N_IDS); + bitmap_or(wc.bm, features->wildcard.bm, MFF_N_IDS); + return wc; +} + +struct ofp10_wc_map { + enum ofp10_flow_wildcards wc10; + enum mf_field_id mf; +}; + +static const struct ofp10_wc_map ofp10_wc_map[] = { + { OFPFW10_IN_PORT, MFF_IN_PORT }, + { OFPFW10_DL_VLAN, MFF_VLAN_VID }, + { OFPFW10_DL_SRC, MFF_ETH_SRC }, + { OFPFW10_DL_DST, MFF_ETH_DST}, + { OFPFW10_DL_TYPE, MFF_ETH_TYPE }, + { OFPFW10_NW_PROTO, MFF_IP_PROTO }, + { OFPFW10_TP_SRC, MFF_TCP_SRC }, + { OFPFW10_TP_DST, MFF_TCP_DST }, + { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC }, + { OFPFW10_NW_DST_MASK, MFF_IPV4_DST }, + { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP }, + { OFPFW10_NW_TOS, MFF_IP_DSCP }, +}; + +static ovs_be32 +mf_bitmap_to_of10(const struct mf_bitmap *fields) +{ + const struct ofp10_wc_map *p; + uint32_t wc10 = 0; + + for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) { + if (bitmap_is_set(fields->bm, p->mf)) { + wc10 |= p->wc10; + } + } + return htonl(wc10); +} + +static struct mf_bitmap +mf_bitmap_from_of10(ovs_be32 wc10) +{ + struct mf_bitmap fields = MF_BITMAP_INITIALIZER; + const struct ofp10_wc_map *p; + + for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) { + if (wc10 & htonl(p->wc10)) { + bitmap_set1(fields.bm, p->mf); + } + } + return fields; +} + static void -ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *in, +ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *stats, + const struct ofputil_table_features *features, struct ofpbuf *buf) { - struct wc_map { - enum ofp10_flow_wildcards wc10; - enum mf_field_id mf; - }; - - static const struct wc_map wc_map[] = { - { OFPFW10_IN_PORT, MFF_IN_PORT }, - { OFPFW10_DL_VLAN, MFF_VLAN_VID }, - { OFPFW10_DL_SRC, MFF_ETH_SRC }, - { OFPFW10_DL_DST, MFF_ETH_DST}, - { OFPFW10_DL_TYPE, MFF_ETH_TYPE }, - { OFPFW10_NW_PROTO, MFF_IP_PROTO }, - { OFPFW10_TP_SRC, MFF_TCP_SRC }, - { OFPFW10_TP_DST, MFF_TCP_DST }, - { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC }, - { OFPFW10_NW_DST_MASK, MFF_IPV4_DST }, - { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP }, - { OFPFW10_NW_TOS, MFF_IP_DSCP }, - }; - + struct mf_bitmap wc = wild_or_nonmatchable_fields(features); struct ofp10_table_stats *out; - const struct wc_map *p; out = ofpbuf_put_zeros(buf, sizeof *out); - out->table_id = in->table_id; - ovs_strlcpy(out->name, in->name, sizeof out->name); - out->wildcards = 0; - for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) { - if (bitmap_is_set(in->wildcards.bm, p->mf)) { - out->wildcards |= htonl(p->wc10); + out->table_id = features->table_id; + ovs_strlcpy(out->name, features->name, sizeof out->name); + out->wildcards = mf_bitmap_to_of10(&wc); + out->max_entries = htonl(features->max_entries); + out->active_count = htonl(stats->active_count); + put_32aligned_be64(&out->lookup_count, htonll(stats->lookup_count)); + put_32aligned_be64(&out->matched_count, htonll(stats->matched_count)); +} + +struct ofp11_wc_map { + enum ofp11_flow_match_fields wc11; + enum mf_field_id mf; +}; + +static const struct ofp11_wc_map ofp11_wc_map[] = { + { OFPFMF11_IN_PORT, MFF_IN_PORT }, + { OFPFMF11_DL_VLAN, MFF_VLAN_VID }, + { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP }, + { OFPFMF11_DL_TYPE, MFF_ETH_TYPE }, + { OFPFMF11_NW_TOS, MFF_IP_DSCP }, + { OFPFMF11_NW_PROTO, MFF_IP_PROTO }, + { OFPFMF11_TP_SRC, MFF_TCP_SRC }, + { OFPFMF11_TP_DST, MFF_TCP_DST }, + { OFPFMF11_MPLS_LABEL, MFF_MPLS_LABEL }, + { OFPFMF11_MPLS_TC, MFF_MPLS_TC }, + /* I don't know what OFPFMF11_TYPE means. */ + { OFPFMF11_DL_SRC, MFF_ETH_SRC }, + { OFPFMF11_DL_DST, MFF_ETH_DST }, + { OFPFMF11_NW_SRC, MFF_IPV4_SRC }, + { OFPFMF11_NW_DST, MFF_IPV4_DST }, + { OFPFMF11_METADATA, MFF_METADATA }, +}; + +static ovs_be32 +mf_bitmap_to_of11(const struct mf_bitmap *fields) +{ + const struct ofp11_wc_map *p; + uint32_t wc11 = 0; + + for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) { + if (bitmap_is_set(fields->bm, p->mf)) { + wc11 |= p->wc11; } } - out->max_entries = htonl(in->max_entries); - out->active_count = htonl(in->active_count); - put_32aligned_be64(&out->lookup_count, htonll(in->lookup_count)); - put_32aligned_be64(&out->matched_count, htonll(in->matched_count)); + return htonl(wc11); } -static ovs_be32 -fields_to_ofp11_flow_match_fields(const struct mf_bitmap *fields) -{ - struct map { - enum ofp11_flow_match_fields fmf11; - enum mf_field_id mf; - }; - - static const struct map map[] = { - { OFPFMF11_IN_PORT, MFF_IN_PORT }, - { OFPFMF11_DL_VLAN, MFF_VLAN_VID }, - { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP }, - { OFPFMF11_DL_TYPE, MFF_ETH_TYPE }, - { OFPFMF11_NW_TOS, MFF_IP_DSCP }, - { OFPFMF11_NW_PROTO, MFF_IP_PROTO }, - { OFPFMF11_TP_SRC, MFF_TCP_SRC }, - { OFPFMF11_TP_DST, MFF_TCP_DST }, - { OFPFMF11_MPLS_LABEL, MFF_MPLS_LABEL }, - { OFPFMF11_MPLS_TC, MFF_MPLS_TC }, - /* I don't know what OFPFMF11_TYPE means. */ - { OFPFMF11_DL_SRC, MFF_ETH_SRC }, - { OFPFMF11_DL_DST, MFF_ETH_DST }, - { OFPFMF11_NW_SRC, MFF_IPV4_SRC }, - { OFPFMF11_NW_DST, MFF_IPV4_DST }, - { OFPFMF11_METADATA, MFF_METADATA }, - }; - - const struct map *p; - uint32_t fmf11; - - fmf11 = 0; - for (p = map; p < &map[ARRAY_SIZE(map)]; p++) { - if (bitmap_is_set(fields->bm, p->mf)) { - fmf11 |= p->fmf11; +static struct mf_bitmap +mf_bitmap_from_of11(ovs_be32 wc11) +{ + struct mf_bitmap fields = MF_BITMAP_INITIALIZER; + const struct ofp11_wc_map *p; + + for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) { + if (wc11 & htonl(p->wc11)) { + bitmap_set1(fields.bm, p->mf); } } - return htonl(fmf11); + return fields; } static void -ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *in, +ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *stats, + const struct ofputil_table_features *features, struct ofpbuf *buf) { + struct mf_bitmap wc = wild_or_nonmatchable_fields(features); struct ofp11_table_stats *out; out = ofpbuf_put_zeros(buf, sizeof *out); - out->table_id = in->table_id; - ovs_strlcpy(out->name, in->name, sizeof out->name); - out->wildcards = fields_to_ofp11_flow_match_fields(&in->wildcards); - out->match = fields_to_ofp11_flow_match_fields(&in->match); - out->instructions = htonl(in->instructions); - out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts, - OFP11_VERSION); - out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts, - OFP11_VERSION); - out->config = htonl(in->config); - out->max_entries = htonl(in->max_entries); - out->active_count = htonl(in->active_count); - out->lookup_count = htonll(in->lookup_count); - out->matched_count = htonll(in->matched_count); + out->table_id = features->table_id; + ovs_strlcpy(out->name, features->name, sizeof out->name); + out->wildcards = mf_bitmap_to_of11(&wc); + out->match = mf_bitmap_to_of11(&features->match); + out->instructions = ovsinst_bitmap_to_openflow( + features->nonmiss.instructions, OFP11_VERSION); + out->write_actions = ofpact_bitmap_to_openflow( + features->nonmiss.write.ofpacts, OFP11_VERSION); + out->apply_actions = ofpact_bitmap_to_openflow( + features->nonmiss.apply.ofpacts, OFP11_VERSION); + out->config = htonl(features->config); + out->max_entries = htonl(features->max_entries); + out->active_count = htonl(stats->active_count); + out->lookup_count = htonll(stats->lookup_count); + out->matched_count = htonll(stats->matched_count); } static ovs_be64 @@ -5114,84 +5168,274 @@ mf_bitmap_to_oxm_bitmap(const struct mf_bitmap *fields, return htonll(oxm_bitmap); } +static struct mf_bitmap +mf_bitmap_from_oxm_bitmap(ovs_be64 oxm_bitmap, enum ofp_version version) +{ + struct mf_bitmap fields = MF_BITMAP_INITIALIZER; + + for (enum mf_field_id id = 0; id < MFF_N_IDS; id++) { + const struct mf_field *f = mf_from_id(id); + uint32_t oxm = f->oxm_header; + uint32_t vendor = NXM_VENDOR(oxm); + int field = NXM_FIELD(oxm); + + if (version >= f->oxm_version + && vendor == OFPXMC12_OPENFLOW_BASIC + && field < 64 + && oxm_bitmap & htonll(UINT64_C(1) << field)) { + bitmap_set1(fields.bm, id); + } + } + return fields; +} + static void -ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *in, +ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats, + const struct ofputil_table_features *features, struct ofpbuf *buf) { struct ofp12_table_stats *out; out = ofpbuf_put_zeros(buf, sizeof *out); - out->table_id = in->table_id; - ovs_strlcpy(out->name, in->name, sizeof out->name); - out->match = mf_bitmap_to_oxm_bitmap(&in->match, OFP12_VERSION); - out->wildcards = mf_bitmap_to_oxm_bitmap(&in->wildcards, OFP12_VERSION); - out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts, - OFP12_VERSION); - out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts, - OFP12_VERSION); - out->write_setfields = mf_bitmap_to_oxm_bitmap(&in->write_setfields, - OFP12_VERSION); - out->apply_setfields = mf_bitmap_to_oxm_bitmap(&in->apply_setfields, - OFP12_VERSION); - out->metadata_match = in->metadata_match; - out->metadata_write = in->metadata_write; - out->instructions = htonl(in->instructions & OFPIT11_ALL); - printf ("%d\n", in->instructions); - out->config = htonl(in->config); - out->max_entries = htonl(in->max_entries); - out->active_count = htonl(in->active_count); - out->lookup_count = htonll(in->lookup_count); - out->matched_count = htonll(in->matched_count); + out->table_id = features->table_id; + ovs_strlcpy(out->name, features->name, sizeof out->name); + out->match = mf_bitmap_to_oxm_bitmap(&features->match, OFP12_VERSION); + out->wildcards = mf_bitmap_to_oxm_bitmap(&features->wildcard, + OFP12_VERSION); + out->write_actions = ofpact_bitmap_to_openflow( + features->nonmiss.write.ofpacts, OFP12_VERSION); + out->apply_actions = ofpact_bitmap_to_openflow( + features->nonmiss.apply.ofpacts, OFP12_VERSION); + out->write_setfields = mf_bitmap_to_oxm_bitmap( + &features->nonmiss.write.set_fields, OFP12_VERSION); + out->apply_setfields = mf_bitmap_to_oxm_bitmap( + &features->nonmiss.apply.set_fields, OFP12_VERSION); + out->metadata_match = features->metadata_match; + out->metadata_write = features->metadata_write; + out->instructions = ovsinst_bitmap_to_openflow( + features->nonmiss.instructions, OFP12_VERSION); + out->config = htonl(features->config); + out->max_entries = htonl(features->max_entries); + out->active_count = htonl(stats->active_count); + out->lookup_count = htonll(stats->lookup_count); + out->matched_count = htonll(stats->matched_count); } static void -ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *in, +ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *stats, struct ofpbuf *buf) { struct ofp13_table_stats *out; - out = ofpbuf_put_uninit(buf, sizeof *out); - out->table_id = in->table_id; - out->active_count = htonl(in->active_count); - out->lookup_count = htonll(in->lookup_count); - out->matched_count = htonll(in->matched_count); + out = ofpbuf_put_zeros(buf, sizeof *out); + out->table_id = stats->table_id; + out->active_count = htonl(stats->active_count); + out->lookup_count = htonll(stats->lookup_count); + out->matched_count = htonll(stats->matched_count); } struct ofpbuf * -ofputil_encode_table_stats_reply(const struct ofputil_table_stats stats[], - int n, const struct ofp_header *request) +ofputil_encode_table_stats_reply(const struct ofp_header *request) { - struct ofpbuf *reply; - int i; + return ofpraw_alloc_stats_reply(request, 0); +} + +void +ofputil_append_table_stats_reply(struct ofpbuf *reply, + const struct ofputil_table_stats *stats, + const struct ofputil_table_features *features) +{ + struct ofp_header *oh = ofpbuf_l2(reply); - reply = ofpraw_alloc_stats_reply(request, n * sizeof *stats); + ovs_assert(stats->table_id == features->table_id); - for (i = 0; i < n; i++) { - switch ((enum ofp_version) request->version) { - case OFP10_VERSION: - ofputil_put_ofp10_table_stats(&stats[i], reply); - break; + switch ((enum ofp_version) oh->version) { + case OFP10_VERSION: + ofputil_put_ofp10_table_stats(stats, features, reply); + break; - case OFP11_VERSION: - ofputil_put_ofp11_table_stats(&stats[i], reply); - break; + case OFP11_VERSION: + ofputil_put_ofp11_table_stats(stats, features, reply); + break; - case OFP12_VERSION: - ofputil_put_ofp12_table_stats(&stats[i], reply); - break; + case OFP12_VERSION: + ofputil_put_ofp12_table_stats(stats, features, reply); + break; - case OFP13_VERSION: - case OFP14_VERSION: - case OFP15_VERSION: - ofputil_put_ofp13_table_stats(&stats[i], reply); - break; + case OFP13_VERSION: + case OFP14_VERSION: + case OFP15_VERSION: + ofputil_put_ofp13_table_stats(stats, reply); + break; - default: - OVS_NOT_REACHED(); - } + default: + OVS_NOT_REACHED(); } +} - return reply; +static int +ofputil_decode_ofp10_table_stats(struct ofpbuf *msg, + struct ofputil_table_stats *stats, + struct ofputil_table_features *features) +{ + struct ofp10_table_stats *ots; + + ots = ofpbuf_try_pull(msg, sizeof *ots); + if (!ots) { + return OFPERR_OFPBRC_BAD_LEN; + } + + features->table_id = ots->table_id; + ovs_strlcpy(features->name, ots->name, sizeof features->name); + features->max_entries = ntohl(ots->max_entries); + features->match = features->wildcard = mf_bitmap_from_of10(ots->wildcards); + + stats->table_id = ots->table_id; + stats->active_count = ntohl(ots->active_count); + stats->lookup_count = ntohll(get_32aligned_be64(&ots->lookup_count)); + stats->matched_count = ntohll(get_32aligned_be64(&ots->matched_count)); + + return 0; +} + +static int +ofputil_decode_ofp11_table_stats(struct ofpbuf *msg, + struct ofputil_table_stats *stats, + struct ofputil_table_features *features) +{ + struct ofp11_table_stats *ots; + + ots = ofpbuf_try_pull(msg, sizeof *ots); + if (!ots) { + return OFPERR_OFPBRC_BAD_LEN; + } + + features->table_id = ots->table_id; + ovs_strlcpy(features->name, ots->name, sizeof features->name); + features->max_entries = ntohl(ots->max_entries); + features->nonmiss.instructions = ovsinst_bitmap_from_openflow( + ots->instructions, OFP11_VERSION); + features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow( + ots->write_actions, OFP11_VERSION); + features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow( + ots->write_actions, OFP11_VERSION); + features->miss = features->nonmiss; + features->config = ntohl(ots->config); + features->match = mf_bitmap_from_of11(ots->match); + features->wildcard = mf_bitmap_from_of11(ots->wildcards); + bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS); + + stats->table_id = ots->table_id; + stats->active_count = ntohl(ots->active_count); + stats->lookup_count = ntohll(ots->lookup_count); + stats->matched_count = ntohll(ots->matched_count); + + return 0; +} + +static int +ofputil_decode_ofp12_table_stats(struct ofpbuf *msg, + struct ofputil_table_stats *stats, + struct ofputil_table_features *features) +{ + struct ofp12_table_stats *ots; + + ots = ofpbuf_try_pull(msg, sizeof *ots); + if (!ots) { + return OFPERR_OFPBRC_BAD_LEN; + } + + features->table_id = ots->table_id; + ovs_strlcpy(features->name, ots->name, sizeof features->name); + features->metadata_match = ots->metadata_match; + features->metadata_write = ots->metadata_write; + features->config = ntohl(ots->config); + features->max_entries = ntohl(ots->max_entries); + + features->nonmiss.instructions = ovsinst_bitmap_from_openflow( + ots->instructions, OFP12_VERSION); + features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow( + ots->write_actions, OFP12_VERSION); + features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow( + ots->apply_actions, OFP12_VERSION); + features->nonmiss.write.set_fields = mf_bitmap_from_oxm_bitmap( + ots->write_setfields, OFP12_VERSION); + features->nonmiss.apply.set_fields = mf_bitmap_from_oxm_bitmap( + ots->apply_setfields, OFP12_VERSION); + features->miss = features->nonmiss; + + features->match = mf_bitmap_from_oxm_bitmap(ots->match, OFP12_VERSION); + features->wildcard = mf_bitmap_from_oxm_bitmap(ots->wildcards, + OFP12_VERSION); + bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS); + + stats->table_id = ots->table_id; + stats->active_count = ntohl(ots->active_count); + stats->lookup_count = ntohll(ots->lookup_count); + stats->matched_count = ntohll(ots->matched_count); + + return 0; +} + +static int +ofputil_decode_ofp13_table_stats(struct ofpbuf *msg, + struct ofputil_table_stats *stats, + struct ofputil_table_features *features) +{ + struct ofp13_table_stats *ots; + + ots = ofpbuf_try_pull(msg, sizeof *ots); + if (!ots) { + return OFPERR_OFPBRC_BAD_LEN; + } + + features->table_id = ots->table_id; + + stats->table_id = ots->table_id; + stats->active_count = ntohl(ots->active_count); + stats->lookup_count = ntohll(ots->lookup_count); + stats->matched_count = ntohll(ots->matched_count); + + return 0; +} + +int +ofputil_decode_table_stats_reply(struct ofpbuf *msg, + struct ofputil_table_stats *stats, + struct ofputil_table_features *features) +{ + const struct ofp_header *oh; + + if (!msg->frame) { + ofpraw_pull_assert(msg); + } + oh = msg->frame; + + if (!ofpbuf_size(msg)) { + return EOF; + } + + memset(stats, 0, sizeof *stats); + memset(features, 0, sizeof *features); + + switch ((enum ofp_version) oh->version) { + case OFP10_VERSION: + return ofputil_decode_ofp10_table_stats(msg, stats, features); + + case OFP11_VERSION: + return ofputil_decode_ofp11_table_stats(msg, stats, features); + + case OFP12_VERSION: + return ofputil_decode_ofp12_table_stats(msg, stats, features); + + case OFP13_VERSION: + case OFP14_VERSION: + case OFP15_VERSION: + return ofputil_decode_ofp13_table_stats(msg, stats, features); + + default: + OVS_NOT_REACHED(); + } } /* ofputil_flow_monitor_request */ diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 38e7006cd..1ccfb2250 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -767,31 +767,28 @@ struct ofpbuf *ofputil_encode_role_status( enum ofperr ofputil_decode_role_status(const struct ofp_header *oh, struct ofputil_role_status *rs); -/* Abstract table stats. */ -struct ofputil_table_stats { - uint8_t table_id; - char name[OFP_MAX_TABLE_NAME_LEN]; - ovs_be64 metadata_match; /* Bits of metadata table can match. */ - ovs_be64 metadata_write; /* Bits of metadata table can write. */ - uint32_t config; /* Bitmap of OFPTC_* values */ - uint32_t max_entries; /* Max number of entries supported. */ - - struct mf_bitmap match; /* Fields table can match. */ - struct mf_bitmap wildcards; /* Fields table can wildcard. */ - uint64_t write_ofpacts; /* OFPACT_* supported on Write-Actions. */ - uint64_t apply_ofpacts; /* OFPACT_* supported on Apply-Actions. */ - struct mf_bitmap write_setfields; /* Fields that can be set in W-A. */ - struct mf_bitmap apply_setfields; /* Fields that can be set in A-A. */ - uint32_t instructions; /* Bitmap of OFPIT_* values supported. */ +/* Abstract table stats. + * + * This corresponds to the OpenFlow 1.3 table statistics structure, which only + * includes actual statistics. In earlier versions of OpenFlow, several + * members describe table features, so this structure has to be paired with + * struct ofputil_table_features to get all information. */ +struct ofputil_table_stats { + uint8_t table_id; /* Identifier of table. */ uint32_t active_count; /* Number of active entries. */ uint64_t lookup_count; /* Number of packets looked up in table. */ uint64_t matched_count; /* Number of packets that hit table. */ }; -struct ofpbuf *ofputil_encode_table_stats_reply( - const struct ofputil_table_stats[], int n, - const struct ofp_header *request); +struct ofpbuf *ofputil_encode_table_stats_reply(const struct ofp_header *rq); +void ofputil_append_table_stats_reply(struct ofpbuf *reply, + const struct ofputil_table_stats *, + const struct ofputil_table_features *); + +int ofputil_decode_table_stats_reply(struct ofpbuf *reply, + struct ofputil_table_stats *, + struct ofputil_table_features *); /* Queue configuration request. */ struct ofpbuf *ofputil_encode_queue_get_config_request(enum ofp_version, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 1f1a27b74..a8a417d6c 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1503,27 +1503,23 @@ flush(struct ofproto *ofproto_) } static void -get_features(struct ofproto *ofproto_ OVS_UNUSED, - bool *arp_match_ip, uint64_t *ofpacts) +query_tables(struct ofproto *ofproto, + struct ofputil_table_features *features, + struct ofputil_table_stats *stats) { - *arp_match_ip = true; - *ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; -} - -static void -get_tables(struct ofproto *ofproto, struct ofputil_table_stats *stats) -{ - int i; + strcpy(features->name, "classifier"); - strcpy(stats->name, "classifier"); + if (stats) { + int i; - for (i = 0; i < ofproto->n_tables; i++) { - unsigned long missed, matched; + for (i = 0; i < ofproto->n_tables; i++) { + unsigned long missed, matched; - atomic_read(&ofproto->tables[i].n_matched, &matched); - stats[i].matched_count = matched; - atomic_read(&ofproto->tables[i].n_missed, &missed); - stats[i].lookup_count = matched + missed; + atomic_read(&ofproto->tables[i].n_matched, &matched); + stats[i].matched_count = matched; + atomic_read(&ofproto->tables[i].n_missed, &missed); + stats[i].lookup_count = matched + missed; + } } } @@ -5058,8 +5054,7 @@ const struct ofproto_class ofproto_dpif_class = { NULL, /* get_memory_usage. */ type_get_memory_usage, flush, - get_features, - get_tables, + query_tables, port_alloc, port_construct, port_destruct, diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 2d98a97e0..551539689 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -768,70 +768,49 @@ struct ofproto_class { * than to do it one by one. */ void (*flush)(struct ofproto *ofproto); - /* Helper for the OpenFlow OFPT_FEATURES_REQUEST request. + /* Helper for the OpenFlow OFPT_TABLE_FEATURES request. * - * The implementation should store true in '*arp_match_ip' if the switch - * supports matching IP addresses inside ARP requests and replies, false - * otherwise. - * - * The implementation should store in '*ofpacts' a bitmap of the supported - * OFPACT_* actions. */ - void (*get_features)(struct ofproto *ofproto, - bool *arp_match_ip, - uint64_t *ofpacts); - - /* Helper for the OpenFlow OFPST_TABLE statistics request. - * - * The 'stats' array contains 'ofproto->n_tables' elements. Each element is - * initialized as: + * The 'features' array contains 'ofproto->n_tables' elements. Each + * element is initialized as: * * - 'table_id' to the array index. * * - 'name' to "table#" where # is the table ID. * - * - 'match' and 'wildcards' to all fields. - * - * - 'write_actions' and 'apply_actions' to all actions. - * - * - 'write_setfields' and 'apply_setfields' to all writable fields. - * * - 'metadata_match' and 'metadata_write' to OVS_BE64_MAX. * - * - 'instructions' to all instructions. - * * - 'config' to the table miss configuration. * * - 'max_entries' to 1,000,000. * - * - 'active_count' to the classifier_count() for the table. + * - Both 'nonmiss' and 'miss' to: * - * - 'lookup_count' and 'matched_count' to 0. + * * 'next' to all 1-bits for all later tables. * - * The implementation should update any members in each element for which - * it has better values: + * * 'instructions' to all instructions. * - * - 'name' to a more meaningful name. + * * 'write' and 'apply' both to: * - * - 'wildcards' to the set of wildcards actually supported by the table - * (if it doesn't support all OpenFlow wildcards). + * - 'ofpacts': All actions. * - * - 'instructions' to set the instructions actually supported by - * the table. + * - 'set_fields': All fields. * - * - 'write_actions' to set the write actions actually supported by - * the table (if it doesn't support all OpenFlow actions). + * - 'match', 'mask', and 'wildcard' to all fields. * - * - 'apply_actions' to set the apply actions actually supported by - * the table (if it doesn't support all OpenFlow actions). + * If 'stats' is nonnull, it also contains 'ofproto->n_tables' elements. + * Each element is initialized as: * - * - 'write_setfields' to set the write setfields actually supported by - * the table. + * - 'table_id' to the array index. + * + * - 'active_count' to the classifier_count() for the table. * - * - 'apply_setfields' to set the apply setfields actually supported by - * the table. + * - 'lookup_count' and 'matched_count' to 0. + * + * The implementation should update any members in each element for which + * it has better values: * - * - 'max_entries' to the maximum number of flows actually supported by - * the hardware. + * - Any member of 'features' to better describe the implementation's + * capabilities. * * - 'lookup_count' to the number of packets looked up in this flow table * so far. @@ -839,8 +818,9 @@ struct ofproto_class { * - 'matched_count' to the number of packets looked up in this flow * table so far that matched one of the flow entries. */ - void (*get_tables)(struct ofproto *ofproto, - struct ofputil_table_stats *stats); + void (*query_tables)(struct ofproto *ofproto, + struct ofputil_table_features *features, + struct ofputil_table_stats *stats); /* ## ---------------- ## */ /* ## ofport Functions ## */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 5ab7391a8..50b9ec6f6 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2777,6 +2777,103 @@ handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } +static void +query_tables(struct ofproto *ofproto, + struct ofputil_table_features **featuresp, + struct ofputil_table_stats **statsp) +{ + struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER; + struct ofputil_table_features *features; + struct ofputil_table_stats *stats; + int i; + + for (i = 0; i < MFF_N_IDS; i++) { + if (mf_from_id(i)->writable) { + bitmap_set1(rw_fields.bm, i); + } + } + + features = *featuresp = xcalloc(ofproto->n_tables, sizeof *features); + for (i = 0; i < ofproto->n_tables; i++) { + struct ofputil_table_features *f = &features[i]; + unsigned int config; + + f->table_id = i; + sprintf(f->name, "table%d", i); + f->metadata_match = OVS_BE64_MAX; + f->metadata_write = OVS_BE64_MAX; + atomic_read(&ofproto->tables[i].config, &config); + f->config = config; + f->max_entries = 1000000; + + bitmap_set_multiple(f->nonmiss.next, i + 1, + ofproto->n_tables - (i + 1), true); + f->nonmiss.instructions = (1u << N_OVS_INSTRUCTIONS) - 1; + if (i == ofproto->n_tables - 1) { + f->nonmiss.instructions &= ~(1u << OVSINST_OFPIT11_GOTO_TABLE); + } + f->nonmiss.write.ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; + f->nonmiss.write.set_fields = rw_fields; + f->nonmiss.apply = f->nonmiss.write; + f->miss = f->nonmiss; + + bitmap_set_multiple(f->match.bm, 0, MFF_N_IDS, 1); + bitmap_set_multiple(f->mask.bm, 0, MFF_N_IDS, 1); + bitmap_set_multiple(f->wildcard.bm, 0, MFF_N_IDS, 1); + } + + if (statsp) { + stats = *statsp = xcalloc(ofproto->n_tables, sizeof *stats); + for (i = 0; i < ofproto->n_tables; i++) { + struct ofputil_table_stats *s = &stats[i]; + struct classifier *cls = &ofproto->tables[i].cls; + + s->table_id = i; + s->active_count = classifier_count(cls); + } + } else { + stats = NULL; + } + + ofproto->ofproto_class->query_tables(ofproto, features, stats); + + for (i = 0; i < ofproto->n_tables; i++) { + const struct oftable *table = &ofproto->tables[i]; + struct ofputil_table_features *f = &features[i]; + + if (table->name) { + ovs_strzcpy(f->name, table->name, sizeof f->name); + } + + if (table->max_flows < f->max_entries) { + f->max_entries = table->max_flows; + } + } +} + +static void +query_switch_features(struct ofproto *ofproto, + bool *arp_match_ip, uint64_t *ofpacts) +{ + struct ofputil_table_features *features, *f; + + *arp_match_ip = false; + *ofpacts = 0; + + query_tables(ofproto, &features, NULL); + for (f = features; f < &features[ofproto->n_tables]; f++) { + *ofpacts |= f->nonmiss.apply.ofpacts | f->miss.apply.ofpacts; + if (bitmap_is_set(f->match.bm, MFF_ARP_SPA) || + bitmap_is_set(f->match.bm, MFF_ARP_TPA)) { + *arp_match_ip = true; + } + } + free(features); + + /* Sanity check. */ + ovs_assert(*ofpacts & (UINT64_C(1) << OFPACT_OUTPUT)); +} + static enum ofperr handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -2786,9 +2883,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) bool arp_match_ip; struct ofpbuf *b; - ofproto->ofproto_class->get_features(ofproto, &arp_match_ip, - &features.ofpacts); - ovs_assert(features.ofpacts & (UINT64_C(1) << OFPACT_OUTPUT)); + query_switch_features(ofproto, &arp_match_ip, &features.ofpacts); features.datapath_id = ofproto->datapath_id; features.n_buffers = pktbuf_capacity(); @@ -3063,70 +3158,23 @@ static enum ofperr handle_table_stats_request(struct ofconn *ofconn, const struct ofp_header *request) { - struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER; - struct ofproto *p = ofconn_get_ofproto(ofconn); + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); + struct ofputil_table_features *features; struct ofputil_table_stats *stats; - struct ofpbuf *msg; - int n_tables; + struct ofpbuf *reply; size_t i; - for (i = 0; i < MFF_N_IDS; i++) { - if (mf_from_id(i)->writable) { - bitmap_set1(rw_fields.bm, i); - } - } - - /* Set up default values. - * - * ofp12_table_stats is used as a generic structure as - * it is able to hold all the fields for ofp10_table_stats - * and ofp11_table_stats (and of course itself). - */ - stats = xcalloc(p->n_tables, sizeof *stats); - for (i = 0; i < p->n_tables; i++) { - unsigned int config; - - stats[i].table_id = i; - sprintf(stats[i].name, "table%"PRIuSIZE, i); - bitmap_set_multiple(stats[i].match.bm, 0, MFF_N_IDS, 1); - bitmap_set_multiple(stats[i].wildcards.bm, 0, MFF_N_IDS, 1); - stats[i].write_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; - stats[i].apply_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; - stats[i].write_setfields = rw_fields; - stats[i].apply_setfields = rw_fields; - stats[i].metadata_match = OVS_BE64_MAX; - stats[i].metadata_write = OVS_BE64_MAX; - stats[i].instructions = OFPIT13_ALL; - atomic_read(&p->tables[i].config, &config); - stats[i].config = config; - stats[i].max_entries = 1000000; /* An arbitrary big number. */ - stats[i].active_count = classifier_count(&p->tables[i].cls); - } - - p->ofproto_class->get_tables(p, stats); - - /* Post-process the tables, dropping hidden tables. */ - n_tables = p->n_tables; - for (i = 0; i < p->n_tables; i++) { - const struct oftable *table = &p->tables[i]; - - if (table->flags & OFTABLE_HIDDEN) { - n_tables = i; - break; - } - - if (table->name) { - ovs_strzcpy(stats[i].name, table->name, sizeof stats[i].name); - } + query_tables(ofproto, &features, &stats); - if (table->max_flows < stats[i].max_entries) { - stats[i].max_entries = table->max_flows; + reply = ofputil_encode_table_stats_reply(request); + for (i = 0; i < ofproto->n_tables; i++) { + if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) { + ofputil_append_table_stats_reply(reply, &stats[i], &features[i]); } } + ofconn_send_reply(ofconn, reply); - msg = ofputil_encode_table_stats_reply(stats, n_tables, request); - ofconn_send_reply(ofconn, msg); - + free(features); free(stats); return 0; diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 3e35baa3c..d461e96f7 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -1384,34 +1384,84 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 3f ff ff 00 10 00 00 00 00 00 0b 00 00 00 00 \ 00 00 00 00 00 00 00 00 00 00 00 00 \ "], [0], [dnl -OFPST_TABLE reply (xid=0x1): 1 tables - 0: classifier: wild=0x3fffff, max=1048576, active=11 - lookup=0, matched=0 +OFPST_TABLE reply (xid=0x1): + table 0 ("classifier"): + active=11, lookup=0, matched=0 + max_entries=1048576 + matching: + in_port: exact match or wildcard + eth_src: exact match or wildcard + eth_dst: exact match or wildcard + eth_type: exact match or wildcard + vlan_vid: exact match or wildcard + vlan_pcp: exact match or wildcard + ip_src: exact match or wildcard + ip_dst: exact match or wildcard + nw_proto: exact match or wildcard + nw_tos: exact match or wildcard + tcp_src: exact match or wildcard + tcp_dst: exact match or wildcard ]) AT_CLEANUP AT_SETUP([OFPST_TABLE reply - OF1.2]) AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) -(mid="wild=0xfffffffff, max=1000000," - tail=" - match=0xfffffffff, instructions=0x00000007, config=0x00000000 - write_actions=0x00000000, apply_actions=0x00000000 - write_setfields=0x0000000fffffffff - apply_setfields=0x0000000fffffffff - metadata_match=0x0000000000000000 - metadata_write=0x0000000000000000" - echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 255 tables - 0: classifier: $mid active=1 - lookup=74614, matched=106024$tail" +(tail=" + max_entries=1000000 + instructions (table miss and others): + instructions: write_metadata,goto_table + Write-Actions and Apply-Actions features: + supported on Set-Field: metadata in_port_oxm eth_src eth_dst eth_type vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_proto ip_dscp nw_ecn arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll + matching: + metadata: exact match or wildcard + in_port_oxm: exact match or wildcard + eth_src: exact match or wildcard + eth_dst: exact match or wildcard + eth_type: exact match or wildcard + vlan_vid: exact match or wildcard + vlan_pcp: exact match or wildcard + mpls_label: exact match or wildcard + mpls_tc: exact match or wildcard + ip_src: exact match or wildcard + ip_dst: exact match or wildcard + ipv6_src: exact match or wildcard + ipv6_dst: exact match or wildcard + ipv6_label: exact match or wildcard + nw_proto: exact match or wildcard + ip_dscp: exact match or wildcard + nw_ecn: exact match or wildcard + arp_op: exact match or wildcard + arp_spa: exact match or wildcard + arp_tpa: exact match or wildcard + arp_sha: exact match or wildcard + arp_tha: exact match or wildcard + tcp_src: exact match or wildcard + tcp_dst: exact match or wildcard + udp_src: exact match or wildcard + udp_dst: exact match or wildcard + sctp_src: exact match or wildcard + sctp_dst: exact match or wildcard + icmp_type: exact match or wildcard + icmp_code: exact match or wildcard + icmpv6_type: exact match or wildcard + icmpv6_code: exact match or wildcard + nd_target: exact match or wildcard + nd_sll: exact match or wildcard + nd_tll: exact match or wildcard" + echo "OFPST_TABLE reply (OF1.2) (xid=0x2): + table 0 (\"classifier\"): + active=1, lookup=74614, matched=106024$tail" x=1 while test $x -lt 254; do - printf " %d: %-8s: $mid active=0 - lookup=0, matched=0$tail + printf " + table %d (\"%s\"): + active=0, lookup=0, matched=0$tail " $x table$x x=`expr $x + 1` done - echo " 254: table254: $mid active=2 - lookup=0, matched=0$tail") > expout + echo " + table 254 (\"table254\"): + active=2, lookup=0, matched=0$tail") > expout (pad32="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" pad7="00 00 00 00 00 00 00 " @@ -1453,9 +1503,12 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 00 00 00 00 00 01 00 01 00 00 00 00 00 00 0c \ 00 00 00 00 00 00 02 01 00 00 00 00 00 00 01 01 \ "], [0], [dnl -OFPST_TABLE reply (OF1.3) (xid=0x1): 2 tables - 0: active=11, lookup=512, matched=256 - 1: active=12, lookup=513, matched=257 +OFPST_TABLE reply (OF1.3) (xid=0x1): + table 0: + active=11, lookup=512, matched=256 + + table 1: + active=12, lookup=513, matched=257 ]) AT_CLEANUP @@ -2270,8 +2323,7 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \ 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], [OFPST_TABLE_FEATURES reply (OF1.3) (xid=0xd5): - table 0: - name="table0" + table 0 ("table0"): metadata: match=0xffffffffffffffff write=0xffffffffffffffff config=Unknown max_entries=1000000 @@ -2280,7 +2332,7 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \ instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table Write-Actions and Apply-Actions features: actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue - supported on Set-Field: 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 + supported on Set-Field: 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 matching: tun_id: exact match or wildcard tun_src: exact match or wildcard diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 4386639cb..e63f5a79c 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -5527,11 +5527,14 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl NXST_FLOW reply: ]) -(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables" - echo " 0: active=1, lookup=0, matched=0" +(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): + table 0: + active=1, lookup=0, matched=0" x=1 while test $x -lt 254; do - echo " $x: active=0, lookup=0, matched=0" + echo " + table $x: + active=0, lookup=0, matched=0" x=`expr $x + 1` done) > expout AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) @@ -5539,7 +5542,6 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) OVS_VSWITCHD_STOP AT_CLEANUP - AT_SETUP([ofproto-dpif packet-out controller (patch port)]) OVS_VSWITCHD_START( [-- \ @@ -5571,19 +5573,24 @@ NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_l metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 ]) -(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables" +(printf "OFPST_TABLE reply (OF1.3) (xid=0x2):" x=0 while test $x -lt 254; do - echo " $x: active=0, lookup=0, matched=0" + echo " + table $x: + active=0, lookup=0, matched=0" x=`expr $x + 1` done) > expout AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) -(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables" - echo " 0: active=0, lookup=3, matched=0" +(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): + table 0: + active=0, lookup=3, matched=0" x=1 while test $x -lt 254; do - echo " $x: active=0, lookup=0, matched=0" + echo " + table $x: + active=0, lookup=0, matched=0" x=`expr $x + 1` done) > expout AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br1 ], [0], [expout]) @@ -5630,12 +5637,17 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-flows br0 | ofctl_strip | sort], [0], [dn OFPST_FLOW reply (OF1.3): ]) -(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables" - echo " 0: active=1, lookup=3, matched=3" - echo " 1: active=1, lookup=3, matched=3" +(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): + table 0: + active=1, lookup=3, matched=3 + + table 1: + active=1, lookup=3, matched=3" x=2 while test $x -lt 254; do - echo " $x: active=0, lookup=0, matched=0" + echo " + table $x: + active=0, lookup=0, matched=0" x=`expr $x + 1` done) > expout AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) @@ -5678,12 +5690,17 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-flows br0 | ofctl_strip | sort], [0], [dn OFPST_FLOW reply (OF1.3): ]) -(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables" - echo " 0: active=0, lookup=3, matched=0" - echo " 1: active=1, lookup=3, matched=3" +(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): + table 0: + active=0, lookup=3, matched=0 + + table 1: + active=1, lookup=3, matched=3" x=2 while test $x -lt 254; do - echo " $x: active=0, lookup=0, matched=0" + echo " + table $x: + active=0, lookup=0, matched=0" x=`expr $x + 1` done) > expout AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout]) diff --git a/tests/ofproto.at b/tests/ofproto.at index 5eef15b70..9ac3c6ee6 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -1028,15 +1028,30 @@ AT_CLEANUP AT_SETUP([ofproto - flow table configuration (OpenFlow 1.0)]) OVS_VSWITCHD_START # Check the default configuration. -(echo "OFPST_TABLE reply (xid=0x2): 254 tables - 0: classifier: wild=0x3fffff, max=1000000, active=0 - lookup=0, matched=0" - x=1 +(printf "OFPST_TABLE reply (xid=0x2):" + x=0 + name=classifier while test $x -lt 254; do - printf " %d: %-8s: wild=0x3fffff, max=1000000, active=0 - lookup=0, matched=0 -" $x table$x + printf " + table %d (\"%s\"): + active=0, lookup=0, matched=0 + max_entries=1000000 + matching: + in_port: exact match or wildcard + eth_src: exact match or wildcard + eth_dst: exact match or wildcard + eth_type: exact match or wildcard + vlan_vid: exact match or wildcard + vlan_pcp: exact match or wildcard + ip_src: exact match or wildcard + ip_dst: exact match or wildcard + nw_proto: exact match or wildcard + nw_tos: exact match or wildcard + tcp_src: exact match or wildcard + tcp_dst: exact match or wildcard +" $x $name x=`expr $x + 1` + name=table$x done) > expout AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) # Change the configuration. @@ -1051,12 +1066,8 @@ AT_CHECK( ]) # Check that the configuration was updated. mv expout orig-expout -(echo "OFPST_TABLE reply (xid=0x2): 254 tables - 0: main : wild=0x3fffff, max=1000000, active=0 - lookup=0, matched=0 - 1: table1 : wild=0x3fffff, max= 1024, active=0 - lookup=0, matched=0" - tail -n +6 orig-expout) > expout +sed -e 's/classifier/main/ +21s/1000000/1024/' orig-expout > expout AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -1064,22 +1075,58 @@ AT_CLEANUP AT_SETUP([ofproto - flow table configuration (OpenFlow 1.2)]) OVS_VSWITCHD_START # Check the default configuration. -(mid="wild=0x1ffffffffd, max=1000000," - tail=" - lookup=0, matched=0 - match=0x1ffffffffd, instructions=0x0000003e, config=0x00000003 - write_actions=0x03ff8001, apply_actions=0x03ff8001 - write_setfields=0x0000000c0fe7fbdd - apply_setfields=0x0000000c0fe7fbdd - metadata_match=0xffffffffffffffff - metadata_write=0xffffffffffffffff" - echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables - 0: classifier: $mid active=0$tail" - x=1 +(printf "OFPST_TABLE reply (OF1.2) (xid=0x2):" + x=0 + name=classifier while test $x -lt 254; do - printf " %d: %-8s: $mid active=0$tail -" $x table$x + echo " + table $x (\"$name\"): + active=0, lookup=0, matched=0 + metadata: match=0xffffffffffffffff write=0xffffffffffffffff + max_entries=1000000 + instructions (table miss and others): + instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table + Write-Actions and Apply-Actions features: + actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue + supported on Set-Field: metadata in_port_oxm eth_src eth_dst vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ip_dscp nw_ecn arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst + matching: + metadata: exact match or wildcard + in_port_oxm: exact match or wildcard + eth_src: exact match or wildcard + eth_dst: exact match or wildcard + eth_type: exact match or wildcard + vlan_vid: exact match or wildcard + vlan_pcp: exact match or wildcard + mpls_label: exact match or wildcard + mpls_tc: exact match or wildcard + ip_src: exact match or wildcard + ip_dst: exact match or wildcard + ipv6_src: exact match or wildcard + ipv6_dst: exact match or wildcard + ipv6_label: exact match or wildcard + nw_proto: exact match or wildcard + ip_dscp: exact match or wildcard + nw_ecn: exact match or wildcard + arp_op: exact match or wildcard + arp_spa: exact match or wildcard + arp_tpa: exact match or wildcard + arp_sha: exact match or wildcard + arp_tha: exact match or wildcard + tcp_src: exact match or wildcard + tcp_dst: exact match or wildcard + udp_src: exact match or wildcard + udp_dst: exact match or wildcard + sctp_src: exact match or wildcard + sctp_dst: exact match or wildcard + icmp_type: exact match or wildcard + icmp_code: exact match or wildcard + icmpv6_type: exact match or wildcard + icmpv6_code: exact match or wildcard + nd_target: exact match or wildcard + nd_sll: exact match or wildcard + nd_tll: exact match or wildcard" x=`expr $x + 1` + name=table$x done) > expout AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout]) # Change the configuration. @@ -1094,11 +1141,8 @@ AT_CHECK( ]) # Check that the configuration was updated. mv expout orig-expout -(echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables - 0: main : wild=0x1ffffffffd, max=1000000, active=0" - tail -n +3 orig-expout | head -7 - echo " 1: table1 : wild=0x1ffffffffd, max= 1024, active=0" - tail -n +11 orig-expout) > expout +sed 's/classifier/main/ +51s/1000000/1024/' < orig-expout > expout AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout]) OVS_VSWITCHD_STOP AT_CLEANUP |