From: Saloni Jain <saloni.j...@tcs.com> This commit enables the eviction mechanism on the basis of importance as per the openflow specification 1.4.
ovs-ofctl -O OpenFlow14 mod-table <bridge> <table> evict Enable eviction on <table> of <bridge>. Eviction adds a mechanism enabling the switch to automatically eliminate entries of lower importance to make space for newer entries. This enables to smoother degradation of behaviour when the table is full. If want to enable eviction on all tables, user can set the <table> as 'all'. ovs-ofctl -O OpenFlow14 mod-table <bridge> <table> noevict Disable eviction on <table> of <bridge>. ovs-ofctl -O OpenFlow14 dump-tables-desc <bridge> This command provides a way to list the current configuration (eviction for importance) of the tables on a <bridge>, which is set using the mod-table command. Signed-off-by:Saloni Jain <saloni.j...@tcs.com> --- include/openflow/openflow-1.4.h | 10 ++ lib/learning-switch.c | 2 + lib/ofp-msgs.h | 10 ++ lib/ofp-parse.c | 4 + lib/ofp-print.c | 59 +++++++++ lib/ofp-util.c | 271 ++++++++++++++++++++++++++++++++++++++- lib/ofp-util.h | 40 ++++++ lib/rconn.c | 2 + ofproto/ofproto-provider.h | 1 + ofproto/ofproto.c | 137 ++++++++++++++++++-- tests/ofproto.at | 105 +++++++++++++++ utilities/ovs-ofctl.c | 20 +++ 12 files changed, 647 insertions(+), 14 deletions(-) diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h index 2a765cf..dcb4439 100644 --- a/include/openflow/openflow-1.4.h +++ b/include/openflow/openflow-1.4.h @@ -155,6 +155,16 @@ struct ofp14_table_mod { }; OFP_ASSERT(sizeof(struct ofp14_table_mod) == 8); +/* Body of reply to OFPMP_TABLE_DESC request. */ +struct ofp14_table_desc { + ovs_be16 length; /* Length is padded to 64 bits. */ + uint8_t table_id; /* Identifier of table. Lower numbered tables are consulted first. */ + uint8_t pad[1]; /* Align to 32-bits. */ + ovs_be32 config; /* Bitmap of OFPTC_* values. */ + /* Followed by 0 or more OFPTMPT14_* properties. */ +}; +OFP_ASSERT(sizeof(struct ofp14_table_desc) == 8); + /* ## ---------------- ## */ /* ## ofp14_port_stats ## */ diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 2b7495c..c634391 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -438,6 +438,8 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg) case OFPTYPE_METER_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_BUNDLE_CONTROL: case OFPTYPE_BUNDLE_ADD_MESSAGE: default: diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h index a78747e..aa55a3d 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -367,6 +367,12 @@ enum ofpraw { /* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */ OFPRAW_OFPST13_TABLE_FEATURES_REPLY, + /* OFPST 1.4+ (15): void. */ + OFPRAW_OFPST14_TABLE_DESC_REQUEST, + + /* OFPST 1.4+ (15): struct ofp14_table_desc, uint8_t[8][]. */ + OFPRAW_OFPST14_TABLE_DESC_REPLY, + /* OFPST 1.0-1.4 (13): void. */ OFPRAW_OFPST10_PORT_DESC_REQUEST, /* OFPST 1.5+ (13): ovs_be32. */ @@ -599,6 +605,10 @@ enum ofptype { OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */ + OFPTYPE_TABLE_DESC_REQUEST, /* OFPRAW_OFPST14_TABLE_DESC_REQUEST. */ + + OFPTYPE_TABLE_DESC_REPLY, /* OFPRAW_OFPST14_TABLE_DESC_REPLY. */ + OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST10_PORT_DESC_REQUEST. * OFPRAW_OFPST15_PORT_DESC_REQUEST. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index f7cf10d..93d2921 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -867,6 +867,10 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id, tm->miss_config = OFPUTIL_TABLE_MISS_CONTINUE; } else if (strcmp(flow_miss_handling, "drop") == 0) { tm->miss_config = OFPUTIL_TABLE_MISS_DROP; + } else if (strcmp(flow_miss_handling, "evict") == 0) { + tm->config = OFPUTIL_TABLE_CONFIG_EVICTION; + } else if (strcmp(flow_miss_handling, "noevict") == 0) { + tm->config = OFPUTIL_TABLE_CONFIG_NO_EVICTION; } else { return xasprintf("invalid flow_miss_handling %s", flow_miss_handling); } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 0eea8cc..00e2ab7 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -976,6 +976,27 @@ ofp_print_table_miss_config(struct ds *string, enum ofputil_table_miss miss) } } +/* This Function will print the config properties of table set through mod-table command */ +static void +ofp_print_table_config(struct ds *string, const struct ofputil_table_desc *td) +{ + switch (td->config) { + case OFPUTIL_TABLE_CONFIG_EVICTION: + ds_put_cstr(string, "Eviction"); + if (td->evict.flags & OFPUTIL_TABLE_EVICTION_IMPORTANCE) { + ds_put_cstr(string, " flag: Importance\n"); + } + break; + case OFPUTIL_TABLE_CONFIG_NO_EVICTION: + case OFPUTIL_TABLE_CONFIG_DEFAULT: + ds_put_cstr(string, "No Eviction\n"); + break; + default: + ds_put_format(string, "Unknown (%d)\n", td->config); + break; + } +} + static void ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) { @@ -1000,6 +1021,17 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) } } +/* This function will print the Table description properties */ +static void +ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc *td) +{ + ds_put_format(string, "\n table %"PRIu8, td->table_id); + ds_put_cstr(string, ":\n"); + + ds_put_cstr(string, " config= "); + ofp_print_table_config(string, td); +} + static void ofp_print_queue_get_config_request(struct ds *string, const struct ofp_header *oh) @@ -2494,6 +2526,28 @@ ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh) } } +static void +ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh) +{ + struct ofpbuf b; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + + for (;;) { + struct ofputil_table_desc td; + int retval; + + retval = ofputil_decode_table_desc(&b, &td); + if (retval) { + if (retval != EOF) { + ofp_print_error(s, retval); + } + return; + } + ofp_print_table_desc(s, &td); + } +} + static const char * bundle_flags_to_name(uint32_t bit) { @@ -2622,6 +2676,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_table_features_reply(string, oh); break; + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: + ofp_print_table_desc_reply(string, oh); + break; + case OFPTYPE_HELLO: ofp_print_hello(string, oh); break; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 16553ec..c9fd641 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -53,11 +53,54 @@ static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5); static enum ofputil_table_miss ofputil_table_miss_from_config( ovs_be32 config_, enum ofp_version); +static enum ofputil_table_config ofputil_table_utilconfig_from_config( + ovs_be32 config_, enum ofp_version version); + +static const struct ovstableprop_map *get_ovsprop_map(void); + +ovs_be32 ovsprop_bitmap_to_openflow(uint32_t ovsprop_bitmap); + struct ofp_prop_header { ovs_be16 type; ovs_be16 len; }; +/* Two-way translation between OFPUTIL eviction flag and representation of + * eviction flags "OFPTMPEF_*" used in OpenFlow specification. */ +struct ovstableprop_map { + enum ofputil_table_mod_prop_eviction_flag flag; /* Internal name for eviction flag. */ + int ofp_flag; /* OFPTMPEF_* number from OpenFlow spec. */ +}; + +static const struct ovstableprop_map * +get_ovsprop_map() +{ + /* OpenFlow 1.4 eviction flags. */ + static const struct ovstableprop_map of14[] = { + { OFPUTIL_TABLE_EVICTION_OTHER, 1 }, + { OFPUTIL_TABLE_EVICTION_IMPORTANCE, 2 }, + { OFPUTIL_TABLE_EVICTION_LIFETIME, 4 }, + { 0, -1 }, + }; + return of14; +} + +/* Converts 'ovstableprop_bitmap', a bitmap whose bits correspond to OFPUTIL_* + * values, into a bitmap of eviction flags. */ +ovs_be32 +ovsprop_bitmap_to_openflow(uint32_t ovsprop_bitmap) +{ + uint32_t ofpevict_bitmap = 0; + const struct ovstableprop_map *x; + + for (x = get_ovsprop_map(); x->ofp_flag >= 0; x++) { + if (ovsprop_bitmap & (1u << x->flag)) { + ofpevict_bitmap |= 1u << x->ofp_flag; + } + } + return htonl(ofpevict_bitmap); +} + /* Pulls a property, beginning with struct ofp_prop_header, from the beginning * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is * nonnull, the entire property, including the header, in '*property'. Returns @@ -4552,6 +4595,25 @@ parse_instruction_ids(struct ofpbuf *payload, bool loose, uint32_t *insts) } static enum ofperr +parse_table_property(struct ofpbuf *payload, uint32_t *flags) +{ + *flags = 0; + while (ofpbuf_size(payload) > 0) { + enum ofperr error; + uint16_t ofp_flags = 0; + error = ofputil_pull_property__(payload, NULL, 1, &ofp_flags); + if (error) { + return error; + } + /* ofp_flags contains the bitmap sent from vswitchd containing value + * of type eviction flags OFPTMPEF_* flags are calculated from this + * value of ofp_flags.*/ + *flags |= 1u << ofp_flags; + } + return 0; +} + +static enum ofperr parse_table_features_next_table(struct ofpbuf *payload, unsigned long int *next_tables) { @@ -4785,6 +4847,32 @@ ofputil_encode_table_features_request(enum ofp_version ofp_version) return request; } +/* Encodes and returns a request to obtain the table desc feature of a switch. + * The message is encoded for OpenFlow version 'ofp_version'.*/ +struct ofpbuf * +ofputil_encode_table_desc_request(enum ofp_version ofp_version) +{ + struct ofpbuf *request = NULL; + + switch (ofp_version) { + case OFP10_VERSION: + case OFP11_VERSION: + case OFP12_VERSION: + case OFP13_VERSION: + ovs_fatal(0, "dump-table-desc needs OpenFlow 1.4 or later " + "(\'-O OpenFlow14\')"); + case OFP14_VERSION: + case OFP15_VERSION: + request = ofpraw_alloc(OFPRAW_OFPST14_TABLE_DESC_REQUEST, + ofp_version, 0); + break; + default: + OVS_NOT_REACHED(); + } + + return request; +} + static void put_fields_property(struct ofpbuf *reply, const struct mf_bitmap *fields, @@ -4850,6 +4938,17 @@ put_table_instruction_features( OFPTFPT13_APPLY_SETFIELD, miss_offset, version); } +static void +put_table_mod_eviction_property(struct ofpbuf *reply, + const struct ofputil_table_mod_prop_eviction *tme) +{ + size_t start_ofs; + start_ofs = start_property(reply, OFPTMPT14_EVICTION); + put_bitmap_properties(reply, + ntohl(ovsprop_bitmap_to_openflow(tme->flags))); + end_property(reply, start_ofs); +} + void ofputil_append_table_features_reply(const struct ofputil_table_features *tf, struct list *replies) @@ -4880,6 +4979,29 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf, ofpmp_postappend(replies, start_ofs); } +/* Function to append Table desc information in a reply list. */ +void +ofputil_append_table_desc_reply(const struct ofputil_table_desc *td, + struct list *replies) +{ + struct ofpbuf *reply = ofpbuf_from_list(list_back(replies)); + enum ofp_version version = ofpmp_version(replies); + size_t start_ofs = ofpbuf_size(reply); + struct ofp14_table_desc *otd; + enum ofputil_table_config config; + + otd = ofpbuf_put_zeros(reply, sizeof *otd); + otd->table_id = td->table_id; + config = ofputil_table_utilconfig_to_config(td->config, version); + otd->config = config; + if (td->config == OFPUTIL_TABLE_CONFIG_EVICTION) { + put_table_mod_eviction_property(reply, &td->evict); + } + otd = ofpbuf_at_assert(reply, start_ofs, sizeof *otd); + otd->length = htons(ofpbuf_size(reply) - start_ofs); + ofpmp_postappend(replies, start_ofs); +} + /* ofputil_table_mod */ /* Given 'config', taken from an OpenFlow 'version' message that specifies @@ -4910,6 +5032,32 @@ ofputil_table_miss_from_config(ovs_be32 config_, enum ofp_version version) } } + +/* Given 'config', taken from an OpenFlow 'version' message that specifies + * table configuration (a table mod message), + * returns the table configuration that it specifies. */ +static enum ofputil_table_config +ofputil_table_utilconfig_from_config(ovs_be32 config_, enum ofp_version version) +{ + uint32_t config = ntohl(config_); + + if (version >= OFP14_VERSION) { + switch (config) { + case OFPTC14_EVICTION: + return OFPUTIL_TABLE_CONFIG_EVICTION; + case OFPTC11_TABLE_MISS_MASK: + return OFPUTIL_TABLE_CONFIG_NO_EVICTION; + case OFPTC11_TABLE_MISS_CONTROLLER: /* for handling Default Value 0 */ + return OFPUTIL_TABLE_CONFIG_DEFAULT; + default: + VLOG_WARN_RL(&bad_ofmsg_rl, "bad table config %d", config); + return OFPUTIL_TABLE_CONFIG_DEFAULT; + } + } else { + return OFPUTIL_TABLE_CONFIG_DEFAULT; + } +} + /* Given a table miss configuration, returns the corresponding OpenFlow table * configuration for use in an OpenFlow message of the given 'version'. */ ovs_be32 @@ -4936,6 +5084,33 @@ ofputil_table_miss_to_config(enum ofputil_table_miss miss, } } +/* Given a table configuration, returns the corresponding OpenFlow table + * configuration for use in an OpenFlow message of the given 'version'. + Point for using Miss Mask as return value of No Eviction + * OFPTC11_TABLE_MISS_MASK is using same value as OFPTC14_DEPRECATED_MASK + * as defined in Openflow 1.4. In openflow-common.h, OFPTC14_DEPRECATED_MASK + * is not defined. Hence using MISS_MASK value*/ +ovs_be32 +ofputil_table_utilconfig_to_config(enum ofputil_table_config config, + enum ofp_version version) +{ + if (version >= OFP14_VERSION) { + switch (config) { + case OFPUTIL_TABLE_CONFIG_EVICTION: + return htonl(OFPTC14_EVICTION); + case OFPUTIL_TABLE_CONFIG_NO_EVICTION: + return htonl(OFPTC11_TABLE_MISS_MASK); + case OFPUTIL_TABLE_CONFIG_DEFAULT: + return htonl(0); + default: + OVS_NOT_REACHED(); + } + } else { + return htonl(0); + } +} + + /* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in * '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */ enum ofperr @@ -4960,8 +5135,8 @@ ofputil_decode_table_mod(const struct ofp_header *oh, pm->table_id = otm->table_id; pm->miss_config = ofputil_table_miss_from_config(otm->config, oh->version); - /* We do not understand any properties yet, so we do not bother - * parsing them. */ + pm->config = ofputil_table_utilconfig_from_config(otm->config, + oh->version); } else { return OFPERR_OFPBRC_BAD_TYPE; } @@ -4969,6 +5144,75 @@ ofputil_decode_table_mod(const struct ofp_header *oh, return 0; } + +/* Decodes the OpenFlow "table desc" message in '*oh' into an abstract form in + * '*td'. Returns 0 if successful, otherwise an OFPERR_* value. */ +int +ofputil_decode_table_desc(struct ofpbuf *msg, + struct ofputil_table_desc *td) +{ + const struct ofp_header *oh; + struct ofp14_table_desc *otd; + struct ofpbuf properties; + unsigned int len; + + memset(td, 0, sizeof *td); + + if (!msg->frame) { + ofpraw_pull_assert(msg); + } + oh = ofpbuf_l2(msg); + + if (!ofpbuf_size(msg)) { + return EOF; + } + + if (ofpbuf_size(msg) < sizeof *otd) { + return OFPERR_OFPBPC_BAD_LEN; + } + + otd = ofpbuf_data(msg); + len = ntohs(otd->length); + if (len < sizeof *otd || len % 8 || len > ofpbuf_size(msg)) { + return OFPERR_OFPBPC_BAD_LEN; + } + ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len); + ofpbuf_pull(&properties, sizeof *otd); + + td->table_id = otd->table_id; + if (td->table_id == OFPTT_ALL) { + return OFPERR_OFPTFFC_BAD_TABLE; + } + + td->config = ofputil_table_utilconfig_from_config(otd->config, + oh->version); + while (ofpbuf_size(&properties) > 0) { + struct ofpbuf payload; + enum ofperr error; + uint16_t type; + + error = pull_table_feature_property(&properties, &payload, &type); + if (error) { + return error; + } + switch ((enum ofp14_table_mod_prop_type) type) { + case OFPTMPT14_EVICTION: + error = parse_table_property(&payload, &td->evict.flags); + break; + case OFPTMPT14_VACANCY: + case OFPTMPT14_EXPERIMENTER: + default: + log_property(true, "unknown table features property %"PRIu16, + type); + break; + } + if (error) { + return error; + } + } + return 0; +} + /* Converts the abstract form of a "table mod" message in '*pm' into an OpenFlow * message suitable for 'protocol', and returns that encoded form in a buffer * owned by the caller. */ @@ -5000,12 +5244,21 @@ ofputil_encode_table_mod(const struct ofputil_table_mod *pm, case OFP14_VERSION: case OFP15_VERSION: { struct ofp14_table_mod *otm; + enum ofputil_table_config config ; b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0); - otm = ofpbuf_put_zeros(b, sizeof *otm); - otm->table_id = pm->table_id; - otm->config = ofputil_table_miss_to_config(pm->miss_config, - ofp_version); + otm = ofpbuf_put_zeros(b, sizeof *otm); + otm->table_id = pm->table_id; + + /* As per the openflow specification miss_config is handled only for + * versions less than OFP13_VERSION so this handling is not required here. + * miss_config = ofputil_table_miss_to_config(pm->miss_config, ofp_version);*/ + config = ofputil_table_utilconfig_to_config(pm->config, + ofp_version); + + /* Mod -table arguments are miss-config and config fields. + for handling both in Standard structure, we are doing following */ + otm->config = config; break; } default: @@ -5378,6 +5631,12 @@ ofputil_encode_table_stats_reply(const struct ofp_header *request) return ofpraw_alloc_stats_reply(request, 0); } +struct ofpbuf * +ofputil_encode_table_desc_reply(const struct ofp_header *request) +{ + return ofpraw_alloc_stats_reply(request, 0); +} + void ofputil_append_table_stats_reply(struct ofpbuf *reply, const struct ofputil_table_stats *stats, diff --git a/lib/ofp-util.h b/lib/ofp-util.h index e3e11b4..0e34556 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -607,15 +607,43 @@ enum ofputil_table_miss { OFPUTIL_TABLE_MISS_DROP, /* Drop the packet. */ }; +/* Abstract version of OFPTC14_TABLE_CONFIG*.*/ +enum ofputil_table_config { + OFPUTIL_TABLE_CONFIG_DEFAULT, /* Table Config default behaviour*/ + OFPUTIL_TABLE_CONFIG_EVICTION, /* Eviction for importance Configured */ + OFPUTIL_TABLE_CONFIG_NO_EVICTION, /* No Eviction for Table*/ +}; + +/* Abstract version of OFPTMPEF_* */ +enum ofputil_table_mod_prop_eviction_flag{ + OFPUTIL_TABLE_EVICTION_OTHER = 1, /* Eviction Enabled Using other Factors */ + OFPUTIL_TABLE_EVICTION_IMPORTANCE = 2, /* Eviction Enabled Using flow entry importance */ + OFPUTIL_TABLE_EVICTION_LIFETIME = 4, /* Eviction Enabled Using flow entry lifetime */ +}; + ovs_be32 ofputil_table_miss_to_config(enum ofputil_table_miss, enum ofp_version); +ovs_be32 ofputil_table_utilconfig_to_config(enum ofputil_table_config config, + enum ofp_version version); + + /* Abstract ofp_table_mod. */ struct ofputil_table_mod { uint8_t table_id; /* ID of the table, 0xff indicates all tables. */ + enum ofputil_table_config config; enum ofputil_table_miss miss_config; }; +/* Abstract ofp14_table_desc. */ +struct ofputil_table_desc{ + uint8_t table_id; /* ID of the table, 0xff indicates all tables. */ + enum ofputil_table_config config; + struct ofputil_table_mod_prop_eviction{ + uint32_t flags; + }evict; +}; + enum ofperr ofputil_decode_table_mod(const struct ofp_header *, struct ofputil_table_mod *); struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *, @@ -682,11 +710,20 @@ struct ofputil_table_features { int ofputil_decode_table_features(struct ofpbuf *, struct ofputil_table_features *, bool loose); + +int ofputil_decode_table_desc(struct ofpbuf *, + struct ofputil_table_desc *); + struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version); +struct ofpbuf *ofputil_encode_table_desc_request(enum ofp_version); + void ofputil_append_table_features_reply( const struct ofputil_table_features *tf, struct list *replies); +void ofputil_append_table_desc_reply( + const struct ofputil_table_desc *td, struct list *replies); + /* Meter band configuration for all supported band types. */ struct ofputil_meter_band { uint16_t type; @@ -813,6 +850,9 @@ struct ofputil_table_stats { }; struct ofpbuf *ofputil_encode_table_stats_reply(const struct ofp_header *rq); + +struct ofpbuf *ofputil_encode_table_desc_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 *); diff --git a/lib/rconn.c b/lib/rconn.c index 5c28806..46f08ff 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -1389,6 +1389,8 @@ is_admitted_msg(const struct ofpbuf *b) case OFPTYPE_GROUP_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_BUNDLE_CONTROL: case OFPTYPE_BUNDLE_ADD_MESSAGE: return false; diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 8204862..69f878b 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -243,6 +243,7 @@ struct oftable { /* Table configuration. */ ATOMIC(enum ofputil_table_miss) miss_config; + ATOMIC(enum ofputil_table_config) config; atomic_ulong n_matched; atomic_ulong n_missed; diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index fd9822b..7d4feeb 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -88,6 +88,8 @@ static void oftable_enable_eviction(struct oftable *, const struct mf_subfield *fields, size_t n_fields); +static void enable_eviction_for_importance(struct oftable *); + static void oftable_remove_rule(struct rule *rule) OVS_REQUIRES(ofproto_mutex); static void oftable_remove_rule__(struct ofproto *, struct rule *) OVS_REQUIRES(ofproto_mutex); @@ -1286,7 +1288,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id, return; } - if (s->groups) { + if (s->groups || table->config == OFPUTIL_TABLE_CONFIG_EVICTION) { oftable_enable_eviction(table, s->groups, s->n_groups); } else { oftable_disable_eviction(table); @@ -3329,6 +3331,54 @@ handle_table_features_request(struct ofconn *ofconn, return 0; } +/* This function queries the database for dumping table-desc*/ +static void +query_tables_desc(struct ofproto *ofproto, + struct ofputil_table_desc **descp) +{ + struct ofputil_table_desc *table_desc; + size_t i; + table_desc = *descp = xcalloc(ofproto->n_tables, sizeof *table_desc); + for (i = 0; i < ofproto->n_tables; i++) { + struct ofputil_table_desc *td = &table_desc[i]; + td->table_id = i; + atomic_read_relaxed(&ofproto->tables[i].config, &td->config); + if (td->config == OFPUTIL_TABLE_CONFIG_EVICTION) { + td->evict.flags = OFPUTIL_TABLE_EVICTION_IMPORTANCE; + } + } +} + +/* Function to handle dump-table-desc request */ +static enum ofperr +handle_table_desc_request(struct ofconn *ofconn, + const struct ofp_header *request) +{ + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); + struct ofputil_table_desc *table_desc; + struct list replies; + struct ofpbuf msg; + size_t i; + + ofpbuf_use_const(&msg, request, ntohs(request->length)); + ofpraw_pull_assert(&msg); + if (ofpbuf_size(&msg) || ofpmp_more(request)) { + return OFPERR_OFPTFFC_EPERM; + } + query_tables_desc(ofproto, &table_desc); + + ofpmp_init(&replies, request); + for (i = 0; i < ofproto->n_tables; i++) { + if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) { + ofputil_append_table_desc_reply(&table_desc[i], &replies); + } + } + ofconn_send_replies(ofconn, &replies); + free(table_desc); + + return 0; +} + static void append_port_stat(struct ofport *port, struct list *replies) { @@ -5932,26 +5982,69 @@ ofproto_table_get_miss_config(const struct ofproto *ofproto, uint8_t table_id) return value; } +/* OFPUTIL_TABLE_CONFIG_NO_EVICTION and OFPUTIL_TABLE_CONFIG_DEFAULT + * these two values are considered different because we have to understand in switch + * that user wants to disable Eviction by explicitly giving Noevict or no value is passed + * at all which is default case */ static enum ofperr table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm) { if (!check_table_id(ofproto, tm->table_id)) { return OFPERR_OFPTMFC_BAD_TABLE; - } else if (tm->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) { + } else if (tm->config == OFPUTIL_TABLE_CONFIG_EVICTION) { if (tm->table_id == OFPTT_ALL) { int i; for (i = 0; i < ofproto->n_tables; i++) { - atomic_store_relaxed(&ofproto->tables[i].miss_config, - tm->miss_config); + atomic_store_relaxed(&ofproto->tables[i].config, + tm->config); + enable_eviction_for_importance(&ofproto->tables[i]); + } + } else { + atomic_store_relaxed(&ofproto->tables[tm->table_id].config, + tm->config); + enable_eviction_for_importance(&ofproto->tables[tm->table_id]); + } + } else if (tm->config == OFPUTIL_TABLE_CONFIG_NO_EVICTION) { + if (tm->table_id == OFPTT_ALL) { + int i; + for (i = 0; i < ofproto->n_tables; i++) { + atomic_store_relaxed(&ofproto->tables[i].config, + tm->config); + oftable_disable_eviction(&ofproto->tables[i]); } } else { - atomic_store_relaxed(&ofproto->tables[tm->table_id].miss_config, - tm->miss_config); + atomic_store_relaxed(&ofproto->tables[tm->table_id].config, + tm->config); + oftable_disable_eviction(&ofproto->tables[tm->table_id]); } } + if (tm->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) { + if (tm->table_id == OFPTT_ALL) { + int i; + for (i = 0; i < ofproto->n_tables; i++) { + atomic_store_relaxed(&ofproto->tables[i].miss_config, + tm->miss_config); + } + } else { + atomic_store_relaxed(&ofproto->tables[tm->table_id].miss_config, + tm->miss_config); + } + } return 0; } +/* This function is only used when eviction is performed on the + basis of importance. This function enables eviction on a particular table given */ +static void +enable_eviction_for_importance(struct oftable *tables) +{ + struct mf_subfield *field = NULL; + size_t n_field = 0; + + field = xmalloc(n_field* sizeof *field); + oftable_enable_eviction(tables, field, n_field); +} + static enum ofperr handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -6139,6 +6232,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: return handle_table_features_request(ofconn, oh); + case OFPTYPE_TABLE_DESC_REQUEST: + return handle_table_desc_request(ofconn, oh); + case OFPTYPE_PORT_STATS_REQUEST: return handle_port_stats_request(ofconn, oh); @@ -6204,6 +6300,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_METER_CONFIG_STATS_REPLY: case OFPTYPE_METER_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: default: if (ofpmsg_is_stat_request(oh)) { @@ -6457,7 +6554,7 @@ eviction_group_find(struct oftable *table, uint32_t id) /* Returns an eviction priority for 'rule'. The return value should be * interpreted so that higher priorities make a rule more attractive candidates * for eviction. - * Called only if have a timeout. */ + * Called if have a timeout and for eviction on basis of importance */ static uint32_t rule_eviction_priority(struct ofproto *ofproto, struct rule *rule) OVS_REQUIRES(ofproto_mutex) @@ -6465,12 +6562,28 @@ rule_eviction_priority(struct ofproto *ofproto, struct rule *rule) long long int expiration = LLONG_MAX; long long int modified; uint32_t expiration_offset; + struct oftable *table = &ofproto->tables[rule->table_id]; + bool has_eviction_by_importance; /* 'modified' needs protection even when we hold 'ofproto_mutex'. */ ovs_mutex_lock(&rule->mutex); modified = rule->modified; ovs_mutex_unlock(&rule->mutex); + /* For eviction on basis of importance only those entries will be added which + * have eviction fields set, importance parameter given in flow entry and table + * config parameter for eviction is set. */ + has_eviction_by_importance = (table->eviction_fields && rule->importance && table->config == OFPUTIL_TABLE_CONFIG_EVICTION); + + + /* As per the openflow specification 1.4, flow entries with lesser importance + * will be evicted before flow entries with higher importance.So invert the value + * of importance for calculating the rule eviction priority as higher priorities + * make a rule more attractive candidates for eviction. */ + if (has_eviction_by_importance) { + return UINT32_MAX - (rule->importance); + } + if (rule->hard_timeout) { expiration = modified + rule->hard_timeout * 1000; } @@ -6512,12 +6625,19 @@ eviction_group_add_rule(struct rule *rule) struct ofproto *ofproto = rule->ofproto; struct oftable *table = &ofproto->tables[rule->table_id]; bool has_timeout; + bool has_eviction_by_importance; /* Timeouts may be modified only when holding 'ofproto_mutex'. We have it * so no additional protection is needed. */ has_timeout = rule->hard_timeout || rule->idle_timeout; - if (table->eviction_fields && has_timeout) { + /* For eviction on basis of importance only those entries will be added which + * have eviction fields set, importance parameter is not zero in flow entry and + * table config parameter for eviction is set. All rules are added in a single + * group when eviction is done on basis of importance */ + has_eviction_by_importance = (table->eviction_fields && rule->importance && table->config == OFPUTIL_TABLE_CONFIG_EVICTION); + + if ((table->eviction_fields && has_timeout) || has_eviction_by_importance) { struct eviction_group *evg; evg = eviction_group_find(table, eviction_group_hash_rule(rule)); @@ -6539,6 +6659,7 @@ oftable_init(struct oftable *table) classifier_init(&table->cls, flow_segment_u32s); table->max_flows = UINT_MAX; atomic_init(&table->miss_config, OFPUTIL_TABLE_MISS_DEFAULT); + atomic_init(&table->config, OFPUTIL_TABLE_CONFIG_DEFAULT); classifier_set_prefix_fields(&table->cls, default_prefix_fields, ARRAY_SIZE(default_prefix_fields)); diff --git a/tests/ofproto.at b/tests/ofproto.at index def0783..151041b 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -1270,6 +1270,111 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto - table description (OpenFlow 1.4)]) +OVS_VSWITCHD_START +(x=0 + while test $x -lt 254; do + y=`expr $x + 1` + echo " table $x: + config= No Eviction" + x=$y + done) > expout +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d +/^OFPST_TABLE_DESC/d'], [0], [expout]) + +# Change the configuration. +AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 evict]) +# Check that the configuration was updated. +mv expout orig-expout +FLAG_STRING=" flag: Importance" +sed -e "2s/No Eviction/Eviction/ +2s/$/$FLAG_STRING/" <orig-expout > expout +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d +/^OFPST_TABLE_DESC/d'], [0], [expout]) +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - eviction using importance upon table overflow (OpenFlow 1.4)]) +OVS_VSWITCHD_START +# Configure a maximum of 4 flows. +AT_CHECK( + [ovs-vsctl \ + -- --id=@t0 create Flow_Table flow-limit=4 \ + -- set bridge br0 flow_tables:0=@t0 \ + | ${PERL} $srcdir/uuidfilt.pl], + [0], [<0> +]) +# set the Eviction configuration. +AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 evict]) +# Add 4 flows. +for in_port in 4 3 2 1; do + ovs-ofctl -O Openflow14 add-flow br0 importance=$((in_port + 30)),priority=$((in_port + 5)),hard_timeout=$((in_port + 500)),actions=drop +done +AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl + hard_timeout=501, importance=31, priority=6 actions=drop + hard_timeout=502, importance=32, priority=7 actions=drop + hard_timeout=503, importance=33, priority=8 actions=drop + hard_timeout=504, importance=34, priority=9 actions=drop +OFPST_FLOW reply (OF1.4): +]) +# Adding another flow will cause the one with lowest importance to be evicted. +AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 hard_timeout=505,importance=35,priority=10,in_port=2,actions=drop]) +AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl + hard_timeout=502, importance=32, priority=7 actions=drop + hard_timeout=503, importance=33, priority=8 actions=drop + hard_timeout=504, importance=34, priority=9 actions=drop + hard_timeout=505, importance=35, priority=10,in_port=2 actions=drop +OFPST_FLOW reply (OF1.4): +]) +# Disable the Eviction configuration. +AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 noevict]) +# Adding another flow will cause the system to give error for FULL TABLE. +AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 hard_timeout=506,importance=36,priority=11,actions=drop],[1], [], [stderr]) +AT_CHECK([head -n 1 stderr | ofctl_strip], [0], + [OFPT_ERROR (OF1.4): OFPFMFC_TABLE_FULL +]) +#Dump flows. It should show only the old values +AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl + hard_timeout=502, importance=32, priority=7 actions=drop + hard_timeout=503, importance=33, priority=8 actions=drop + hard_timeout=504, importance=34, priority=9 actions=drop + hard_timeout=505, importance=35, priority=10,in_port=2 actions=drop +OFPST_FLOW reply (OF1.4): +]) +# mod-flow that would modify a flow will be done successfully. +AT_CHECK([ovs-ofctl -O Openflow14 mod-flows br0 in_port=2,actions=NORMAL]) +AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl + hard_timeout=502, importance=32, priority=7 actions=drop + hard_timeout=503, importance=33, priority=8 actions=drop + hard_timeout=504, importance=34, priority=9 actions=drop + hard_timeout=505, importance=35, priority=10,in_port=2 actions=NORMAL +OFPST_FLOW reply (OF1.4): +]) +# Also a mod-flow that would add a flow will be refused. +AT_CHECK([ovs-ofctl mod-flows br0 in_port=5,actions=drop], [1], [], [stderr]) +AT_CHECK([head -n 1 stderr | ofctl_strip], [0], + [OFPT_ERROR: OFPFMFC_TABLE_FULL +]) +# Now set the eviction on timeout basis. +AT_CHECK( + [ovs-vsctl \ + -- --id=@t0 create Flow_Table flow-limit=4 overflow-policy=evict \ + -- set bridge br0 flow_tables:0=@t0 \ + | ${PERL} $srcdir/uuidfilt.pl], + [0], [<0> +]) +#Now add a new flow +AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 importance=37,hard_timeout=507,priority=11,in_port=6,actions=drop]) +AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl + hard_timeout=503, importance=33, priority=8 actions=drop + hard_timeout=504, importance=34, priority=9 actions=drop + hard_timeout=505, importance=35, priority=10,in_port=2 actions=NORMAL + hard_timeout=507, importance=37, priority=11,in_port=6 actions=drop +OFPST_FLOW reply (OF1.4): +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto - hard limits on flow table size (OpenFlow 1.0)]) OVS_VSWITCHD_START # Configure a maximum of 4 flows. diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 67465ce..af2226c 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -699,6 +699,24 @@ ofctl_dump_table_features(int argc OVS_UNUSED, char *argv[]) vconn_close(vconn); } +/* ovs-ofctl dump-table-desc provides a way to list the current configuration of + * the tables on a switch, which is set using the ovs-ofctl table-mod command. */ +static void +ofctl_dump_table_desc(int argc OVS_UNUSED, char *argv[]) +{ + struct ofpbuf *request; + struct vconn *vconn; + + open_vconn(argv[1], &vconn); + request = ofputil_encode_table_desc_request(vconn_get_version(vconn)); + if (request) { + dump_stats_transaction(vconn, request); + } + + vconn_close(vconn); +} + + static bool fetch_port_by_stats(struct vconn *, const char *port_name, ofp_port_t port_no, struct ofputil_phy_port *); @@ -3474,6 +3492,8 @@ static const struct command all_commands[] = { 1, 1, ofctl_dump_tables }, { "dump-table-features", "switch", 1, 1, ofctl_dump_table_features }, + { "dump-table-desc", "switch", + 1, 1, ofctl_dump_table_desc}, { "dump-flows", "switch", 1, 2, ofctl_dump_flows }, { "dump-aggregate", "switch", -- 1.7.9.5 =====-----=====-----===== Notice: The information contained in this e-mail message and/or attachments to it may contain confidential or privileged information. If you are not the intended recipient, any dissemination, use, review, distribution, printing or copying of the information contained in this e-mail message and/or attachments to it are strictly prohibited. If you have received this communication in error, please notify us by reply e-mail or telephone and immediately and permanently delete the message and any attachments. Thank you _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev