return error;
}
+static enum ofperr
+handle_nxt_resume(struct ofconn *ofconn, const struct ofp_header *oh)
+{
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ struct ofputil_packet_in_private pin;
+ enum ofperr error;
+
+ error = ofputil_decode_packet_in_private(oh, false, &pin, NULL, NULL);
+ if (error) {
+ return error;
+ }
+
+ error = (ofproto->ofproto_class->nxt_resume
+ ? ofproto->ofproto_class->nxt_resume(ofproto, &pin)
+ : OFPERR_NXR_NOT_SUPPORTED);
+
+ ofputil_packet_in_private_destroy(&pin);
+
+ return error;
+}
+
static void
update_port_config(struct ofconn *ofconn, struct ofport *port,
enum ofputil_port_config config,
return 0;
}
+/* Returns the vacancy of 'oftable', a number that ranges from 0 (if the table
+ * is full) to 100 (if the table is empty).
+ *
+ * A table without a limit on flows is considered to be empty. */
+static uint8_t
+oftable_vacancy(const struct oftable *t)
+{
+ return (!t->max_flows ? 100
+ : t->n_flows >= t->max_flows ? 0
+ : (t->max_flows - t->n_flows) * 100.0 / t->max_flows);
+}
+
static void
query_table_desc__(struct ofputil_table_desc *td,
struct ofproto *ofproto, uint8_t table_id)
{
- unsigned int count = ofproto->tables[table_id].n_flows;
- unsigned int max_flows = ofproto->tables[table_id].max_flows;
+ const struct oftable *t = &ofproto->tables[table_id];
td->table_id = table_id;
- td->eviction = (ofproto->tables[table_id].eviction & EVICTION_OPENFLOW
+ td->eviction = (t->eviction & EVICTION_OPENFLOW
? OFPUTIL_TABLE_EVICTION_ON
: OFPUTIL_TABLE_EVICTION_OFF);
td->eviction_flags = OFPROTO_EVICTION_FLAGS;
- td->vacancy = (ofproto->tables[table_id].vacancy_enabled
+ td->vacancy = (t->vacancy_event
? OFPUTIL_TABLE_VACANCY_ON
: OFPUTIL_TABLE_VACANCY_OFF);
- td->table_vacancy.vacancy_down = ofproto->tables[table_id].vacancy_down;
- td->table_vacancy.vacancy_up = ofproto->tables[table_id].vacancy_up;
- td->table_vacancy.vacancy = max_flows ? (count * 100) / max_flows : 0;
+ td->table_vacancy.vacancy_down = t->vacancy_down;
+ td->table_vacancy.vacancy_up = t->vacancy_up;
+ td->table_vacancy.vacancy = oftable_vacancy(t);
}
/* This function queries the database for dumping table-desc. */
return 0;
}
+/* This function determines and sends the vacancy event, based on the value
+ * of current vacancy and threshold vacancy. If the current vacancy is less
+ * than or equal to vacancy_down, vacancy up events must be enabled, and when
+ * the current vacancy is greater or equal to vacancy_up, vacancy down events
+ * must be enabled. */
+static void
+send_table_status(struct ofproto *ofproto, uint8_t table_id)
+{
+ struct oftable *t = &ofproto->tables[table_id];
+ if (!t->vacancy_event) {
+ return;
+ }
+
+ uint8_t vacancy = oftable_vacancy(t);
+ enum ofp14_table_reason event;
+ if (vacancy < t->vacancy_down) {
+ event = OFPTR_VACANCY_DOWN;
+ } else if (vacancy > t->vacancy_up) {
+ event = OFPTR_VACANCY_UP;
+ } else {
+ return;
+ }
+
+ if (event == t->vacancy_event) {
+ struct ofputil_table_desc td;
+ query_table_desc__(&td, ofproto, table_id);
+ connmgr_send_table_status(ofproto->connmgr, &td, event);
+
+ t->vacancy_event = (event == OFPTR_VACANCY_DOWN
+ ? OFPTR_VACANCY_UP
+ : OFPTR_VACANCY_DOWN);
+ }
+}
+
static void
append_port_stat(struct ofport *port, struct ovs_list *replies)
{
ofmonitor_report(ofproto->connmgr, new_rule, NXFME_ADDED, 0,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
+
+ /* Send Vacancy Events for OF1.4+. */
+ send_table_status(ofproto, new_rule->table_id);
}
send_buffered_packet(req, fm->buffer_id, new_rule);
ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
+
+ /* Send Vacancy Event for OF1.4+. */
+ send_table_status(ofproto, rule->table_id);
+
ofproto_rule_remove__(ofproto, rule);
learned_cookies_dec(ofproto, rule_get_actions(rule),
&dead_cookies);
uint32_t format;
format = ntohl(msg->format);
- if (format != NXPIF_OPENFLOW10 && format != NXPIF_NXM) {
+ if (!ofputil_packet_in_format_is_valid(format)) {
return OFPERR_OFPBRC_EPERM;
}
if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
ovs_mutex_lock(&ofproto_mutex);
- oftable->vacancy_enabled = (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON
- ? OFPTC14_VACANCY_EVENTS
- : 0);
oftable->vacancy_down = tm->table_vacancy.vacancy_down;
oftable->vacancy_up = tm->table_vacancy.vacancy_up;
+ if (tm->vacancy == OFPUTIL_TABLE_VACANCY_OFF) {
+ oftable->vacancy_event = 0;
+ } else if (!oftable->vacancy_event) {
+ uint8_t vacancy = oftable_vacancy(oftable);
+ oftable->vacancy_event = (vacancy < oftable->vacancy_up
+ ? OFPTR_VACANCY_UP
+ : OFPTR_VACANCY_DOWN);
+ }
ovs_mutex_unlock(&ofproto_mutex);
}
}
case OFPTYPE_GET_ASYNC_REQUEST:
return handle_nxt_get_async_request(ofconn, oh);
+ case OFPTYPE_NXT_RESUME:
+ return handle_nxt_resume(ofconn, oh);
+
/* Statistics requests. */
case OFPTYPE_DESC_STATS_REQUEST:
return handle_desc_stats_request(ofconn, oh);
case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_REQUESTFORWARD:
+ case OFPTYPE_TABLE_STATUS:
case OFPTYPE_NXT_TLV_TABLE_REPLY:
default:
if (ofpmsg_is_stat_request(oh)) {