summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS6
-rw-r--r--include/openflow/openflow-1.3.h89
-rw-r--r--include/openflow/openflow-1.4.h93
-rw-r--r--include/openvswitch/ofp-monitor.h9
-rw-r--r--include/openvswitch/ofp-msgs.h39
-rw-r--r--lib/ofp-monitor.c844
-rw-r--r--lib/ofp-print.c24
-rw-r--r--ofproto/connmgr.c47
-rw-r--r--ofproto/connmgr.h6
-rw-r--r--ofproto/ofproto-provider.h4
-rw-r--r--ofproto/ofproto.c89
-rw-r--r--tests/ofp-print.at122
-rw-r--r--tests/ofproto.at176
-rw-r--r--utilities/ovs-ofctl.8.in3
-rw-r--r--utilities/ovs-ofctl.c6
15 files changed, 1265 insertions, 292 deletions
diff --git a/NEWS b/NEWS
index 79abfd7e3..b084b6133 100644
--- a/NEWS
+++ b/NEWS
@@ -24,8 +24,10 @@ Post-v2.17.0
applications to relax atomicity requirements when dealing with
columns whose value has been rewritten (but not changed).
- OpenFlow:
- * Added Flow Monitoring support for OpenFlow 1.0-1.2 with Nicira
- Extensions.
+ * Extended Flow Monitoring support for all supported OpenFlow versions:
+ OpenFlow versions 1.0-1.2 with Nicira Extensions
+ OpenFlow versions 1.3 with Open Network Foundation extension
+ OpenFlow versions 1.4+, as defined in the OpenFlow specification
v2.17.0 - 17 Feb 2022
diff --git a/include/openflow/openflow-1.3.h b/include/openflow/openflow-1.3.h
index c48a8ea7f..2567b503c 100644
--- a/include/openflow/openflow-1.3.h
+++ b/include/openflow/openflow-1.3.h
@@ -374,4 +374,93 @@ struct ofp13_async_config {
};
OFP_ASSERT(sizeof(struct ofp13_async_config) == 24);
+struct onf_flow_monitor_request {
+ ovs_be32 id; /* Controller-assigned ID for this monitor. */
+ ovs_be16 flags; /* ONFFMF_*. */
+ ovs_be16 match_len; /* Length of oxm_fields. */
+ ovs_be32 out_port; /* Required output port, if not OFPP_NONE. */
+ uint8_t table_id; /* One table's ID or 0xff for all tables. */
+ uint8_t zeros[3]; /* Align to 64 bits (must be zero). */
+ /* Followed by an ofp11_match structure. */
+};
+OFP_ASSERT(sizeof(struct onf_flow_monitor_request) == 16);
+
+/* Header for experimenter requests and replies. */
+struct onf_experimenter_header {
+ struct ofp_header header;
+ ovs_be32 vendor; /* ONF_EXPERIMENTER_ID. */
+ ovs_be32 subtype; /* One of ONFT_*. */
+};
+OFP_ASSERT(sizeof(struct onf_experimenter_header) == 16);
+
+enum onf_flow_monitor_msg_type {
+ ONFT_FLOW_MONITOR_CANCEL = 1870,
+ ONFT_FLOW_MONITOR_PAUSED = 1871,
+ ONFT_FLOW_MONITOR_RESUMED = 1872
+};
+
+/* 'flags' bits in struct onf_flow_monitor_request. */
+enum onf_flow_monitor_flags {
+ /* When to send updates. */
+ ONFFMF_INITIAL = 1 << 0, /* Initially matching flows. */
+ ONFFMF_ADD = 1 << 1, /* New matching flows as they are added. */
+ ONFFMF_DELETE = 1 << 2, /* Old matching flows as they are removed. */
+ ONFFMF_MODIFY = 1 << 3, /* Matching flows as they are changed. */
+
+ /* What to include in updates. */
+ ONFFMF_ACTIONS = 1 << 4, /* If set, actions are included. */
+ ONFFMF_OWN = 1 << 5, /* If set, include own changes in full. */
+};
+
+/* ONFST_FLOW_MONITOR reply header. */
+struct onf_flow_update_header {
+ ovs_be16 length; /* Length of this entry. */
+ ovs_be16 event; /* One of ONFFME_*. */
+ /* ...other data depending on 'event'... */
+};
+OFP_ASSERT(sizeof(struct onf_flow_update_header) == 4);
+
+/* 'event' values in struct onf_flow_update_header. */
+enum onf_flow_update_event {
+ /* struct onf_flow_update_full. */
+ ONFFME_ADDED = 0, /* Flow was added. */
+ ONFFME_DELETED = 1, /* Flow was deleted. */
+ ONFFME_MODIFIED = 2, /* Flow (generally its actions) was changed. */
+
+ /* struct onf_flow_update_abbrev. */
+ ONFFME_ABBREV = 3, /* Abbreviated reply. */
+};
+
+/* ONFST_FLOW_MONITOR reply for ONFFME_ADDED, ONFFME_DELETED, and
+* ONFFME_MODIFIED. */
+struct onf_flow_update_full {
+ ovs_be16 length; /* Length is 24. */
+ ovs_be16 event; /* One of ONFFME_*. */
+ ovs_be16 reason; /* OFPRR_* for ONFFME_DELETED, else zero. */
+ ovs_be16 priority; /* Priority of the entry. */
+ ovs_be16 idle_timeout; /* Number of seconds idle before expiration. */
+ ovs_be16 hard_timeout; /* Number of seconds before expiration. */
+ ovs_be16 match_len; /* Length of oxm_fields. */
+ uint8_t table_id; /* ID of flow's table. */
+ uint8_t pad; /* Reserved, currently zeroed. */
+ ovs_be64 cookie; /* Opaque controller-issued identifier. */
+ /* Followed by:
+ * - Exactly match_len (possibly 0) bytes containing the oxm_fields, then
+ * - Exactly (match_len + 7)/8*8 - match_len (between 0 and 7) bytes of
+ * all-zero bytes, then
+ * - Instructions to fill out the remainder 'length' bytes (always a
+ * multiple of 8). If ONFFMF_ACTIONS was not specified, or 'event' is
+ * ONFFME_DELETED, no actions are included.
+ */
+};
+OFP_ASSERT(sizeof(struct onf_flow_update_full) == 24);
+
+/* ONFST_FLOW_MONITOR reply for ONFFME_ABBREV. */
+struct onf_flow_update_abbrev {
+ ovs_be16 length; /* Length is 8. */
+ ovs_be16 event; /* ONFFME_ABBREV. */
+ ovs_be32 xid; /* Controller-specified xid from flow_mod. */
+};
+OFP_ASSERT(sizeof(struct onf_flow_update_abbrev) == 8);
+
#endif /* openflow/openflow-1.3.h */
diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h
index be191180b..16260e2de 100644
--- a/include/openflow/openflow-1.4.h
+++ b/include/openflow/openflow-1.4.h
@@ -358,27 +358,100 @@ OFP_ASSERT(sizeof(struct ofp14_flow_monitor_request) == 16);
/* Flow monitor commands */
enum ofp14_flow_monitor_command {
- OFPFMC14_ADD = 0, /* New flow monitor. */
- OFPFMC14_MODIFY = 1, /* Modify existing flow monitor. */
- OFPFMC14_DELETE = 2, /* Delete/cancel existing flow monitor. */
+ OFPFMC_ADD = 0, /* New flow monitor. */
+ OFPFMC_MODIFY = 1, /* Modify existing flow monitor. */
+ OFPFMC_DELETE = 2, /* Delete/cancel existing flow monitor. */
};
/* 'flags' bits in struct of_flow_monitor_request. */
enum ofp14_flow_monitor_flags {
/* When to send updates. */
/* Common to NX and OpenFlow 1.4 */
- OFPFMF14_INITIAL = 1 << 0, /* Initially matching flows. */
- OFPFMF14_ADD = 1 << 1, /* New matching flows as they are added. */
- OFPFMF14_REMOVED = 1 << 2, /* Old matching flows as they are removed. */
- OFPFMF14_MODIFY = 1 << 3, /* Matching flows as they are changed. */
+ OFPFMF_INITIAL = 1 << 0, /* Initially matching flows. */
+ OFPFMF_ADD = 1 << 1, /* New matching flows as they are added. */
+ OFPFMF_REMOVED = 1 << 2, /* Old matching flows as they are removed. */
+ OFPFMF_MODIFY = 1 << 3, /* Matching flows as they are changed. */
/* What to include in updates. */
/* Common to NX and OpenFlow 1.4 */
- OFPFMF14_INSTRUCTIONS = 1 << 4, /* If set, instructions are included. */
- OFPFMF14_NO_ABBREV = 1 << 5, /* If set, include own changes in full. */
+ OFPFMF_INSTRUCTIONS = 1 << 4, /* If set, instructions are included. */
+ OFPFMF_NO_ABBREV = 1 << 5, /* If set, include own changes in full. */
/* OpenFlow 1.4 */
- OFPFMF14_ONLY_OWN = 1 << 6, /* If set, don't include other controllers.
+ OFPFMF_ONLY_OWN = 1 << 6, /* If set, don't include other controllers.
*/
};
+/* OFPMP_FLOW_MONITOR reply header.
+ *
+ * The body of an OFPMP_FLOW_MONITOR reply is an array of variable-length
+ * structures, each of which begins with this header. The 'length' member may
+ * be used to traverse the array, and the 'event' member may be used to
+ * determine the particular structure.
+ * Every instance is a multiple of 8 bytes long. */
+struct ofp_flow_update_header {
+ ovs_be16 length; /* Length of this entry. */
+ ovs_be16 event; /* One of OFPFME_*. */
+ /* ...other data depending on 'event'... */
+};
+OFP_ASSERT(sizeof(struct ofp_flow_update_header) == 4);
+
+/* 'event' values in struct ofp_flow_update_header. */
+enum ofp_flow_update_event {
+ /* struct ofp_flow_update_full. */
+ OFPFME_INITIAL = 0, /* Flow present when flow monitor created. */
+ OFPFME_ADDED = 1, /* Flow was added. */
+ OFPFME_REMOVED = 2, /* Flow was removed. */
+ OFPFME_MODIFIED = 3, /* Flow instructions were changed. */
+
+ /* struct ofp_flow_update_abbrev. */
+ OFPFME_ABBREV = 4, /* Abbreviated reply. */
+
+ /* struct ofp_flow_update_header. */
+ OFPFME_PAUSED = 5, /* Monitoring paused (out of buffer space). */
+ OFPFME_RESUMED = 6, /* Monitoring resumed. */
+};
+
+/* OFPMP_FLOW_MONITOR reply for OFPFME_INITIAL, OFPFME_ADDED, OFPFME_REMOVED,
+ * and OFPFME_MODIFIED. */
+struct ofp_flow_update_full {
+ ovs_be16 length; /* Length is 32 + match + instructions. */
+ ovs_be16 event; /* One of OFPFME_*. */
+ uint8_t table_id; /* ID of flow's table. */
+ uint8_t reason; /* OFPRR_* for OFPFME_REMOVED, else zero. */
+ ovs_be16 idle_timeout; /* Number of seconds idle before expiration. */
+ ovs_be16 hard_timeout; /* Number of seconds before expiration. */
+ ovs_be16 priority; /* Priority of the entry. */
+ uint8_t zeros[4]; /* Reserved, currently zeroed. */
+ ovs_be64 cookie; /* Opaque controller-issued identifier. */
+ /* Instruction set.
+ * If OFPFMF_INSTRUCTIONS was not specified, or 'event' is
+ * OFPFME_REMOVED, no instructions are included.
+ */
+};
+OFP_ASSERT(sizeof(struct ofp_flow_update_full) == 24);
+
+/* OFPMP_FLOW_MONITOR reply for OFPFME_ABBREV.
+ *
+ * When the controller does not specify OFPFMF_NO_ABBREV in a monitor request,
+ * any flow tables changes due to the controller's own requests (on the same
+ * OpenFlow channel) will be abbreviated, when possible, to this form, which
+ * simply specifies the 'xid' of the OpenFlow request (e.g. an OFPT_FLOW_MOD)
+ * that caused the change.
+ * Some changes cannot be abbreviated and will be sent in full.
+ */
+struct ofp_flow_update_abbrev {
+ ovs_be16 length; /* Length is 8. */
+ ovs_be16 event; /* OFPFME_ABBREV. */
+ ovs_be32 xid; /* Controller-specified xid from flow_mod. */
+};
+OFP_ASSERT(sizeof(struct ofp_flow_update_abbrev) == 8);
+
+/* OFPMP_FLOW_MONITOR reply for OFPFME_PAUSED and OFPFME_RESUMED.*/
+struct ofp_flow_update_paused {
+ ovs_be16 length; /* Length is 8. */
+ ovs_be16 event; /* One of OFPFME_*. */
+ uint8_t zeros[4]; /* Reserved, currently zeroed. */
+};
+OFP_ASSERT(sizeof(struct ofp_flow_update_paused) == 8);
+
#endif /* openflow/openflow-1.4.h */
diff --git a/include/openvswitch/ofp-monitor.h b/include/openvswitch/ofp-monitor.h
index 835efd0f3..7c7cfcff4 100644
--- a/include/openvswitch/ofp-monitor.h
+++ b/include/openvswitch/ofp-monitor.h
@@ -61,8 +61,10 @@ void ofputil_flow_removed_format(struct ds *,
/* Abstract nx_flow_monitor_request. */
struct ofputil_flow_monitor_request {
uint32_t id;
- enum nx_flow_monitor_flags flags;
+ enum ofp14_flow_monitor_command command;
+ enum ofp14_flow_monitor_flags flags;
ofp_port_t out_port;
+ uint32_t out_group;
uint8_t table_id;
struct match match;
};
@@ -85,7 +87,7 @@ char *parse_flow_monitor_request(struct ofputil_flow_monitor_request *,
/* Abstract nx_flow_update. */
struct ofputil_flow_update {
- enum nx_flow_update_event event;
+ enum ofp_flow_update_event event;
/* Used only for NXFME_ADDED, NXFME_DELETED, NXFME_MODIFIED. */
enum ofp_flow_removed_reason reason;
@@ -119,6 +121,9 @@ uint32_t ofputil_decode_flow_monitor_cancel(const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_monitor_cancel(
uint32_t id, enum ofputil_protocol protocol);
+struct ofpbuf * ofputil_encode_flow_monitor_pause(
+ enum ofp_flow_update_event command, enum ofputil_protocol protocol);
+
struct ofputil_requestforward {
ovs_be32 xid;
/* Also used for OF 1.0-1.3 when using Nicira Extension: */
diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h
index c5fde0270..921a937e5 100644
--- a/include/openvswitch/ofp-msgs.h
+++ b/include/openvswitch/ofp-msgs.h
@@ -453,14 +453,33 @@ enum ofpraw {
/* OFPST 1.4+ (16): uint8_t[8][]. */
OFPRAW_OFPST14_FLOW_MONITOR_REQUEST,
+ /* ONFST 1.3 (1870): uint8_t[8][]. */
+ OFPRAW_ONFST13_FLOW_MONITOR_REQUEST,
/* NXST 1.0-1.2 (2): uint8_t[8][]. */
OFPRAW_NXST_FLOW_MONITOR_REQUEST,
/* OFPST 1.4+ (16): uint8_t[8][]. */
OFPRAW_OFPST14_FLOW_MONITOR_REPLY,
+ /* ONFST 1.3 (1870): uint8_t[8][]. */
+ OFPRAW_ONFST13_FLOW_MONITOR_REPLY,
/* NXST 1.0-1.2 (2): uint8_t[8][]. */
OFPRAW_NXST_FLOW_MONITOR_REPLY,
+ /* ONFT 1.3 (1870): struct nx_flow_monitor_cancel. */
+ OFPRAW_ONFT13_FLOW_MONITOR_CANCEL,
+ /* NXT 1.0-1.2 (21): struct nx_flow_monitor_cancel. */
+ OFPRAW_NXT_FLOW_MONITOR_CANCEL,
+
+ /* ONFT 1.3 (1871): void. */
+ OFPRAW_ONFT13_FLOW_MONITOR_PAUSED,
+ /* NXT 1.0-1.2 (22): void. */
+ OFPRAW_NXT_FLOW_MONITOR_PAUSED,
+
+ /* ONFT 1.3 (1872): void. */
+ OFPRAW_ONFT13_FLOW_MONITOR_RESUMED,
+ /* NXT 1.0-1.2 (23): void. */
+ OFPRAW_NXT_FLOW_MONITOR_RESUMED,
+
/* Nicira extension messages.
*
* Nicira extensions that correspond to standard OpenFlow messages are listed
@@ -481,15 +500,6 @@ enum ofpraw {
/* NXT 1.0+ (20): struct nx_controller_id. */
OFPRAW_NXT_SET_CONTROLLER_ID,
- /* NXT 1.0+ (21): struct nx_flow_monitor_cancel. */
- OFPRAW_NXT_FLOW_MONITOR_CANCEL,
-
- /* NXT 1.0+ (22): void. */
- OFPRAW_NXT_FLOW_MONITOR_PAUSED,
-
- /* NXT 1.0+ (23): void. */
- OFPRAW_NXT_FLOW_MONITOR_RESUMED,
-
/* NXT 1.0+ (24): struct nx_tlv_table_mod, struct nx_tlv_map[]. */
OFPRAW_NXT_TLV_TABLE_MOD,
@@ -741,8 +751,10 @@ enum ofptype {
* OFPRAW_OFPST14_PORT_DESC_REPLY. */
OFPTYPE_FLOW_MONITOR_STATS_REQUEST, /* OFPRAW_OFPST14_FLOW_MONITOR_REQUEST.
+ * OFPRAW_ONFST13_FLOW_MONITOR_REQUEST.
* OFPRAW_NXST_FLOW_MONITOR_REQUEST. */
OFPTYPE_FLOW_MONITOR_STATS_REPLY, /* OFPRAW_OFPST14_FLOW_MONITOR_REPLY.
+ * OFPRAW_ONFST13_FLOW_MONITOR_REPLY.
* OFPRAW_NXST_FLOW_MONITOR_REPLY. */
/* Nicira extensions. */
@@ -762,9 +774,12 @@ enum ofptype {
OFPTYPE_CT_FLUSH_ZONE, /* OFPRAW_NXT_CT_FLUSH_ZONE. */
/* Flow monitor extension. */
- OFPTYPE_FLOW_MONITOR_CANCEL, /* OFPRAW_NXT_FLOW_MONITOR_CANCEL. */
- OFPTYPE_FLOW_MONITOR_PAUSED, /* OFPRAW_NXT_FLOW_MONITOR_PAUSED. */
- OFPTYPE_FLOW_MONITOR_RESUMED, /* OFPRAW_NXT_FLOW_MONITOR_RESUMED. */
+ OFPTYPE_FLOW_MONITOR_CANCEL, /* OFPRAW_NXT_FLOW_MONITOR_CANCEL.
+ * OFPRAW_ONFT13_FLOW_MONITOR_CANCEL. */
+ OFPTYPE_FLOW_MONITOR_PAUSED, /* OFPRAW_NXT_FLOW_MONITOR_PAUSED.
+ * OFPRAW_ONFT13_FLOW_MONITOR_PAUSED. */
+ OFPTYPE_FLOW_MONITOR_RESUMED, /* OFPRAW_NXT_FLOW_MONITOR_RESUMED.
+ * OFPRAW_ONFT13_FLOW_MONITOR_RESUMED */
};
/* Decoding messages into OFPTYPE_* values. */
diff --git a/lib/ofp-monitor.c b/lib/ofp-monitor.c
index 51f01b100..1756c9e8e 100644
--- a/lib/ofp-monitor.c
+++ b/lib/ofp-monitor.c
@@ -328,6 +328,98 @@ ofputil_flow_removed_format(struct ds *s,
ds_put_format(s, " pkts%"PRIu64" bytes%"PRIu64"\n",
fr->packet_count, fr->byte_count);
}
+
+static uint16_t
+nx_to_ofp_flow_monitor_flags(uint16_t flags)
+{
+ uint16_t oxm_flags = 0;
+
+ if (flags & NXFMF_INITIAL) {
+ oxm_flags |= OFPFMF_INITIAL;
+ }
+ if (flags & NXFMF_ADD) {
+ oxm_flags |= OFPFMF_ADD;
+ }
+ if (flags & NXFMF_DELETE) {
+ oxm_flags |= OFPFMF_REMOVED;
+ }
+ if (flags & NXFMF_MODIFY) {
+ oxm_flags |= OFPFMF_MODIFY;
+ }
+ if (flags & NXFMF_ACTIONS) {
+ oxm_flags |= OFPFMF_INSTRUCTIONS;
+ }
+ if (flags & NXFMF_OWN) {
+ oxm_flags |= OFPFMF_ONLY_OWN;
+ }
+
+ return oxm_flags;
+}
+
+static uint16_t
+ofp_to_nx_flow_monitor_flags(uint16_t flags)
+{
+ uint16_t nx_flags = 0;
+
+ if (flags & OFPFMF_INITIAL) {
+ nx_flags |= NXFMF_INITIAL;
+ }
+ if (flags & OFPFMF_ADD) {
+ nx_flags |= NXFMF_ADD;
+ }
+ if (flags & OFPFMF_REMOVED) {
+ nx_flags |= NXFMF_DELETE;
+ }
+ if (flags & OFPFMF_MODIFY) {
+ nx_flags |= NXFMF_MODIFY;
+ }
+ if (flags & OFPFMF_INSTRUCTIONS) {
+ nx_flags |= NXFMF_ACTIONS;
+ }
+ if (flags & OFPFMF_ONLY_OWN) {
+ nx_flags |= NXFMF_OWN;
+ }
+
+ return nx_flags;
+}
+
+static enum ofp_flow_update_event
+nx_to_ofp_flow_update_event(enum nx_flow_update_event event)
+{
+ switch (event) {
+ case NXFME_ADDED:
+ return OFPFME_ADDED;
+ case NXFME_DELETED:
+ return OFPFME_REMOVED;
+ case NXFME_MODIFIED:
+ return OFPFME_MODIFIED;
+ case NXFME_ABBREV:
+ return OFPFME_ABBREV;
+ default:
+ OVS_NOT_REACHED();
+ }
+}
+
+static enum nx_flow_update_event
+ofp_to_nx_flow_update_event(enum ofp_flow_update_event event)
+{
+ switch (event) {
+ case OFPFME_INITIAL:
+ case OFPFME_ADDED:
+ return NXFME_ADDED;
+ case OFPFME_REMOVED:
+ return NXFME_DELETED;
+ case OFPFME_MODIFIED:
+ return NXFME_MODIFIED;
+ case OFPFME_ABBREV:
+ return NXFME_ABBREV;
+ default:
+ case OFPFME_PAUSED:
+ case OFPFME_RESUMED:
+ OVS_NOT_REACHED();
+ }
+}
+
/* ofputil_flow_monitor_request */
@@ -345,43 +437,129 @@ int
ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq,
struct ofpbuf *msg)
{
- struct nx_flow_monitor_request *nfmr;
uint16_t flags;
+ enum ofperr error;
+ enum ofpraw raw;
- if (!msg->header) {
- ofpraw_pull_assert(msg);
+ error = (msg->header ? ofpraw_decode(&raw, msg->header)
+ : ofpraw_pull(&raw, msg));
+ if (error) {
+ return error;
}
if (!msg->size) {
return EOF;
}
- nfmr = ofpbuf_try_pull(msg, sizeof *nfmr);
- if (!nfmr) {
- VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR request has %"PRIu32" "
- "leftover bytes at end", msg->size);
- return OFPERR_OFPBRC_BAD_LEN;
- }
+ switch ((int) raw) {
+ case OFPRAW_NXST_FLOW_MONITOR_REQUEST: {
+ struct nx_flow_monitor_request *nfmr;
- flags = ntohs(nfmr->flags);
- if (!(flags & (NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY))
- || flags & ~(NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE
- | NXFMF_MODIFY | NXFMF_ACTIONS | NXFMF_OWN)) {
- VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR has bad flags %#"PRIx16, flags);
- return OFPERR_OFPMOFC_BAD_FLAGS;
+ nfmr = ofpbuf_try_pull(msg, sizeof *nfmr);
+ if (!nfmr) {
+ VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR request has %"PRIu32" "
+ "leftover bytes at end", msg->size);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ flags = ntohs(nfmr->flags);
+ if (!(flags & (NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY))
+ || flags & ~(NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE
+ | NXFMF_MODIFY | NXFMF_ACTIONS | NXFMF_OWN)) {
+ VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR has bad flags %#"PRIx16,
+ flags);
+ return OFPERR_OFPMOFC_BAD_FLAGS;
+ }
+
+ if (!is_all_zeros(nfmr->zeros, sizeof nfmr->zeros)) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ rq->id = ntohl(nfmr->id);
+ rq->command = OFPFMC_ADD;
+ rq->flags = nx_to_ofp_flow_monitor_flags(flags);
+ rq->out_port = u16_to_ofp(ntohs(nfmr->out_port));
+ rq->table_id = nfmr->table_id;
+ rq->out_group = OFPG_ANY;
+
+ return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL,
+ NULL, false, NULL, NULL);
}
+ case OFPRAW_ONFST13_FLOW_MONITOR_REQUEST: {
+ struct onf_flow_monitor_request *ofmr;
+
+ ofmr = ofpbuf_try_pull(msg, sizeof *ofmr);
+ if (!ofmr) {
+ VLOG_WARN_RL(&rl, "ONFST_FLOW_MONITOR request has %"PRIu32" "
+ "leftover bytes at end", msg->size);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ flags = ntohs(ofmr->flags);
+ if (!(flags & (ONFFMF_ADD | ONFFMF_DELETE | ONFFMF_MODIFY))
+ || flags & ~(ONFFMF_INITIAL | ONFFMF_ADD | ONFFMF_DELETE
+ | ONFFMF_MODIFY | ONFFMF_ACTIONS | ONFFMF_OWN)) {
+ VLOG_WARN_RL(&rl, "ONFST_FLOW_MONITOR has bad flags %#"PRIx16,
+ flags);
+ return OFPERR_OFPMOFC_BAD_FLAGS;
+ }
+
+ if (!is_all_zeros(ofmr->zeros, sizeof ofmr->zeros)) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ rq->id = ntohl(ofmr->id);
+ rq->command = OFPFMC_ADD;
+ rq->flags = nx_to_ofp_flow_monitor_flags(flags);
+ error = ofputil_port_from_ofp11(ofmr->out_port, &rq->out_port);
+ if (error) {
+ return error;
+ }
+ rq->table_id = ofmr->table_id;
+ rq->out_group = OFPG_ANY;
- if (!is_all_zeros(nfmr->zeros, sizeof nfmr->zeros)) {
- return OFPERR_NXBRC_MUST_BE_ZERO;
+ return ofputil_pull_ofp11_match(msg, NULL, NULL, &rq->match, NULL);
}
+ case OFPRAW_OFPST14_FLOW_MONITOR_REQUEST: {
+ struct ofp14_flow_monitor_request *ofmr;
+
+ ofmr = ofpbuf_try_pull(msg, sizeof *ofmr);
+ if (!ofmr) {
+ VLOG_WARN_RL(&rl, "OFPST_FLOW_MONITOR request has %"PRIu32" "
+ "leftover bytes at end", msg->size);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
- rq->id = ntohl(nfmr->id);
- rq->flags = flags;
- rq->out_port = u16_to_ofp(ntohs(nfmr->out_port));
- rq->table_id = nfmr->table_id;
+ flags = ntohs(ofmr->flags);
+ rq->id = ntohl(ofmr->monitor_id);
+ rq->command = ofmr->command;
+
+ if (ofmr->command == OFPFMC_DELETE) {
+ return ofputil_pull_ofp11_match(msg, NULL, NULL, &rq->match, NULL);
+ }
- return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL,
- NULL, false, NULL, NULL);
+ if (!(flags & (OFPFMF_ADD | OFPFMF_REMOVED | OFPFMF_MODIFY))
+ || flags & ~(OFPFMF_INITIAL | OFPFMF_ADD | OFPFMF_REMOVED
+ | OFPFMF_MODIFY | OFPFMF_INSTRUCTIONS | OFPFMF_ONLY_OWN)) {
+ VLOG_WARN_RL(&rl, "OFPST_FLOW_MONITOR has bad flags %#"PRIx16,
+ flags);
+ return OFPERR_OFPMOFC_BAD_FLAGS;
+ }
+
+ rq->command = ofmr->command;
+ rq->flags = flags;
+ error = ofputil_port_from_ofp11(ofmr->out_port, &rq->out_port);
+ if (error) {
+ return error;
+ }
+ rq->out_group = ntohl(ofmr->out_group);
+ rq->table_id = ofmr->table_id;
+
+ return ofputil_pull_ofp11_match(msg, NULL, NULL, &rq->match, NULL);
+ }
+ default:
+ OVS_NOT_REACHED();
+ }
}
void
@@ -389,66 +567,143 @@ ofputil_append_flow_monitor_request(
const struct ofputil_flow_monitor_request *rq, struct ofpbuf *msg,
enum ofputil_protocol protocol)
{
- struct nx_flow_monitor_request *nfmr;
size_t start_ofs;
int match_len;
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
if (!msg->size) {
- ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, version, msg);
- }
+ switch (version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
+ struct nx_flow_monitor_request *nfmr;
+
+ if (!msg->size) {
+ ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, version, msg);
+ }
- start_ofs = msg->size;
- ofpbuf_put_zeros(msg, sizeof *nfmr);
- match_len = nx_put_match(msg, &rq->match, htonll(0), htonll(0));
-
- nfmr = ofpbuf_at_assert(msg, start_ofs, sizeof *nfmr);
- nfmr->id = htonl(rq->id);
- nfmr->flags = htons(rq->flags);
- nfmr->out_port = htons(ofp_to_u16(rq->out_port));
- nfmr->match_len = htons(match_len);
- nfmr->table_id = rq->table_id;
+ start_ofs = msg->size;
+ ofpbuf_put_zeros(msg, sizeof *nfmr);
+ match_len = nx_put_match(msg, &rq->match, htonll(0), htonll(0));
+
+ nfmr = ofpbuf_at_assert(msg, start_ofs, sizeof *nfmr);
+ nfmr->id = htonl(rq->id);
+ nfmr->flags = htons(ofp_to_nx_flow_monitor_flags(rq->flags));
+ nfmr->out_port = htons(ofp_to_u16(rq->out_port));
+ nfmr->match_len = htons(match_len);
+ nfmr->table_id = rq->table_id;
+ break;
+ }
+ case OFP13_VERSION: {
+ struct onf_flow_monitor_request *ofmr;
+
+ if (!msg->size) {
+ ofpraw_put(OFPRAW_ONFST13_FLOW_MONITOR_REQUEST, version, msg);
+ }
+
+ start_ofs = msg->size;
+ ofpbuf_put_zeros(msg, sizeof *ofmr);
+ match_len = oxm_put_match(msg, &rq->match, version);
+
+ ofmr = ofpbuf_at_assert(msg, start_ofs, sizeof *ofmr);
+ ofmr->id = htonl(rq->id);
+ ofmr->flags = htons(ofp_to_nx_flow_monitor_flags(rq->flags));
+ ofmr->match_len = htons(match_len);
+ ofmr->out_port = ofputil_port_to_ofp11(rq->out_port);
+ ofmr->table_id = rq->table_id;
+ break;
+ }
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
+ struct ofp14_flow_monitor_request *ofmr;
+
+ if (!msg->size) {
+ ofpraw_put(OFPRAW_OFPST14_FLOW_MONITOR_REQUEST, version, msg);
+ }
+
+ start_ofs = msg->size;
+ ofpbuf_put_zeros(msg, sizeof *ofmr);
+ oxm_put_match(msg, &rq->match, version);
+
+ ofmr = ofpbuf_at_assert(msg, start_ofs, sizeof *ofmr);
+ ofmr->monitor_id = htonl(rq->id);
+ ofmr->command = OFPFMC_ADD;
+ ofmr->out_port = ofputil_port_to_ofp11(rq->out_port);
+ ofmr->out_group = htonl(rq->out_group);
+ ofmr->flags = htons(rq->flags);
+ ofmr->table_id = rq->table_id;
+ break;
+ }
+ default:
+ OVS_NOT_REACHED();
+ }
+ }
}
static const char *
-nx_flow_monitor_flags_to_name(uint32_t bit)
+ofp_flow_monitor_flags_to_name(uint32_t bit)
{
- enum nx_flow_monitor_flags fmf = bit;
+ enum ofp14_flow_monitor_flags fmf = bit;
switch (fmf) {
- case NXFMF_INITIAL: return "initial";
- case NXFMF_ADD: return "add";
- case NXFMF_DELETE: return "delete";
- case NXFMF_MODIFY: return "modify";
- case NXFMF_ACTIONS: return "actions";
- case NXFMF_OWN: return "own";
+ case OFPFMF_INITIAL: return "initial";
+ case OFPFMF_ADD: return "add";
+ case OFPFMF_REMOVED: return "delete";
+ case OFPFMF_MODIFY: return "modify";
+ case OFPFMF_INSTRUCTIONS: return "actions";
+ case OFPFMF_NO_ABBREV: return "no-abbrev";
+ case OFPFMF_ONLY_OWN: return "own";
}
return NULL;
}
+static const char *
+ofp_flow_monitor_command_to_string(enum ofp14_flow_monitor_command command)
+{
+ switch (command) {
+ case OFPFMC_ADD: return "add";
+ case OFPFMC_MODIFY: return "modify";
+ case OFPFMC_DELETE: return "delete";
+ default:
+ OVS_NOT_REACHED();
+ }
+}
+
void
ofputil_flow_monitor_request_format(
struct ds *s, const struct ofputil_flow_monitor_request *request,
const struct ofputil_port_map *port_map,
const struct ofputil_table_map *table_map)
{
+ if (request->command == OFPFMC_DELETE) {
+ ds_put_format(s, "\n id=%"PRIu32" command=%s", request->id,
+ ofp_flow_monitor_command_to_string(request->command));
+ return;
+ }
ds_put_format(s, "\n id=%"PRIu32" flags=", request->id);
- ofp_print_bit_names(s, request->flags, nx_flow_monitor_flags_to_name, ',');
+ ofp_print_bit_names(s, request->flags,
+ ofp_flow_monitor_flags_to_name, ',');
if (request->out_port != OFPP_NONE) {
ds_put_cstr(s, " out_port=");
ofputil_format_port(request->out_port, port_map, s);
}
+ if (request->out_group && (request->out_group != OFPG_ANY)) {
+ ds_put_format(s, " out_group=%d", request->out_group);
+ }
+
if (request->table_id != 0xff) {
ds_put_format(s, " table=");
ofputil_format_table(request->table_id, table_map, s);
}
- ds_put_char(s, ' ');
- match_format(&request->match, port_map, s, OFP_DEFAULT_PRIORITY);
- ds_chomp(s, ' ');
+ if (request->command != OFPFMC_DELETE) {
+ ds_put_char(s, ' ');
+ match_format(&request->match, port_map, s, OFP_DEFAULT_PRIORITY);
+ ds_chomp(s, ' ');
+ }
}
static char * OVS_WARN_UNUSED_RESULT
@@ -464,9 +719,10 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
fmr->id = atomic_count_inc(&id);
- fmr->flags = (NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY
- | NXFMF_OWN | NXFMF_ACTIONS);
+ fmr->flags = (OFPFMF_INITIAL | OFPFMF_ADD | OFPFMF_REMOVED | OFPFMF_MODIFY
+ | OFPFMF_ONLY_OWN | OFPFMF_INSTRUCTIONS);
fmr->out_port = OFPP_NONE;
+ fmr->out_group = OFPG_ANY;
fmr->table_id = 0xff;
match_init_catchall(&fmr->match);
@@ -476,17 +732,19 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
char *error = NULL;
if (!strcmp(name, "!initial")) {
- fmr->flags &= ~NXFMF_INITIAL;
+ fmr->flags &= ~OFPFMF_INITIAL;
} else if (!strcmp(name, "!add")) {
- fmr->flags &= ~NXFMF_ADD;
+ fmr->flags &= ~OFPFMF_ADD;
} else if (!strcmp(name, "!delete")) {
- fmr->flags &= ~NXFMF_DELETE;
+ fmr->flags &= ~OFPFMF_REMOVED;
} else if (!strcmp(name, "!modify")) {
- fmr->flags &= ~NXFMF_MODIFY;
+ fmr->flags &= ~OFPFMF_MODIFY;
} else if (!strcmp(name, "!actions")) {
- fmr->flags &= ~NXFMF_ACTIONS;
+ fmr->flags &= ~OFPFMF_INSTRUCTIONS;
+ } else if (!strcmp(name, "!abbrev")) {
+ fmr->flags &= ~OFPFMF_NO_ABBREV;
} else if (!strcmp(name, "!own")) {
- fmr->flags &= ~NXFMF_OWN;
+ fmr->flags &= ~OFPFMF_ONLY_OWN;
} else if (ofp_parse_protocol(name, &p)) {
match_set_dl_type(&fmr->match, htons(p->dl_type));
if (p->nw_proto) {
@@ -511,6 +769,8 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
}
} else if (!strcmp(name, "out_port")) {
fmr->out_port = u16_to_ofp(atoi(value));
+ } else if (!strcmp(name, "out_group")) {
+ fmr->out_group = atoi(value);
} else {
return xasprintf("%s: unknown keyword %s", str_, name);
}
@@ -562,101 +822,226 @@ int
ofputil_decode_flow_update(struct ofputil_flow_update *update,
struct ofpbuf *msg, struct ofpbuf *ofpacts)
{
- struct nx_flow_update_header *nfuh;
unsigned int length;
struct ofp_header *oh;
+ enum ofperr error;
+ enum ofpraw raw;
if (!msg->header) {
ofpraw_pull_assert(msg);
}
+ error = ofpraw_decode(&raw, msg->header);
+ if (error) {
+ return error;
+ }
+
ofpbuf_clear(ofpacts);
if (!msg->size) {
return EOF;
}
- if (msg->size < sizeof(struct nx_flow_update_header)) {
- goto bad_len;
- }
-
oh = msg->header;
- nfuh = msg->data;
- update->event = ntohs(nfuh->event);
- length = ntohs(nfuh->length);
- if (length > msg->size || length % 8) {
- goto bad_len;
- }
+ switch ((int) raw) {
+ case OFPRAW_ONFST13_FLOW_MONITOR_REPLY:
+ case OFPRAW_NXST_FLOW_MONITOR_REPLY: {
+ struct nx_flow_update_header *nfuh;
- if (update->event == NXFME_ABBREV) {
- struct nx_flow_update_abbrev *nfua;
+ if (msg->size < sizeof(struct nx_flow_update_header)) {
+ goto bad_len;
+ }
- if (length != sizeof *nfua) {
+ nfuh = msg->data;
+ update->event = nx_to_ofp_flow_update_event(ntohs(nfuh->event));
+ length = ntohs(nfuh->length);
+ if (length > msg->size || length % 8) {
goto bad_len;
}
- nfua = ofpbuf_pull(msg, sizeof *nfua);
- update->xid = nfua->xid;
- return 0;
- } else if (update->event == NXFME_ADDED
- || update->event == NXFME_DELETED
- || update->event == NXFME_MODIFIED) {
- struct nx_flow_update_full *nfuf;
- unsigned int actions_len;
- unsigned int match_len;
- enum ofperr error;
+ if (update->event == OFPFME_ABBREV) {
+ struct nx_flow_update_abbrev *nfua;
+
+ if (length != sizeof *nfua) {
+ goto bad_len;
+ }
+
+ nfua = ofpbuf_pull(msg, sizeof *nfua);
+ update->xid = nfua->xid;
+ return 0;
+ } else if (update->event == OFPFME_ADDED
+ || update->event == OFPFME_REMOVED
+ || update->event == OFPFME_MODIFIED) {
+ struct nx_flow_update_full *nfuf;
+ unsigned int actions_len;
+ unsigned int match_len;
+
+ if (length < sizeof *nfuf) {
+ goto bad_len;
+ }
- if (length < sizeof *nfuf) {
+ nfuf = ofpbuf_pull(msg, sizeof *nfuf);
+ match_len = ntohs(nfuf->match_len);
+ if (sizeof *nfuf + match_len > length) {
+ goto bad_len;
+ }
+
+ update->reason = ntohs(nfuf->reason);
+ update->idle_timeout = ntohs(nfuf->idle_timeout);
+ update->hard_timeout = ntohs(nfuf->hard_timeout);
+ update->table_id = nfuf->table_id;
+ update->cookie = nfuf->cookie;
+ update->priority = ntohs(nfuf->priority);
+
+ if (raw == OFPRAW_ONFST13_FLOW_MONITOR_REPLY) {
+ uint16_t padded_match_len = 0;
+ unsigned int instructions_len;
+
+ error = ofputil_pull_ofp11_match(
+ msg, NULL, NULL, &update->match, &padded_match_len);
+ if (error) {
+ return error;
+ }
+
+ instructions_len = length - sizeof *nfuf - padded_match_len;
+ error = ofpacts_pull_openflow_instructions(
+ msg, instructions_len, oh->version, NULL, NULL, ofpacts);
+ if (error) {
+ return error;
+ }
+ } else {
+ error = nx_pull_match(msg, match_len, &update->match, NULL,
+ NULL, false, NULL, NULL);
+ if (error) {
+ return error;
+ }
+
+ actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8);
+ error = ofpacts_pull_openflow_actions(
+ msg, actions_len, oh->version, NULL, NULL, ofpacts);
+ if (error) {
+ return error;
+ }
+ }
+
+ update->ofpacts = ofpacts->data;
+ update->ofpacts_len = ofpacts->size;
+ return 0;
+ } else {
+ VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR reply has bad event %"PRIu16,
+ ntohs(nfuh->event));
+ return OFPERR_NXBRC_FM_BAD_EVENT;
+ }
+ }
+ case OFPRAW_OFPST14_FLOW_MONITOR_REPLY: {
+ struct ofp_flow_update_header *ofuh;
+ uint16_t padded_match_len = 0;
+
+ if (msg->size < sizeof(struct ofp_flow_update_header)) {
goto bad_len;
}
- nfuf = ofpbuf_pull(msg, sizeof *nfuf);
- match_len = ntohs(nfuf->match_len);
- if (sizeof *nfuf + match_len > length) {
+ ofuh = msg->data;
+ update->event = ntohs(ofuh->event);
+ length = ntohs(ofuh->length);
+ if (length > msg->size || length % 8) {
goto bad_len;
}
- update->reason = ntohs(nfuf->reason);
- update->idle_timeout = ntohs(nfuf->idle_timeout);
- update->hard_timeout = ntohs(nfuf->hard_timeout);
- update->table_id = nfuf->table_id;
- update->cookie = nfuf->cookie;
- update->priority = ntohs(nfuf->priority);
+ if (update->event == OFPFME_ABBREV) {
+ struct ofp_flow_update_abbrev *ofua;
- error = nx_pull_match(msg, match_len, &update->match, NULL, NULL,
- false, NULL, NULL);
- if (error) {
- return error;
- }
+ if (length != sizeof *ofua) {
+ goto bad_len;
+ }
- actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8);
- error = ofpacts_pull_openflow_actions(msg, actions_len, oh->version,
- NULL, NULL, ofpacts);
- if (error) {
- return error;
- }
+ ofua = ofpbuf_pull(msg, sizeof *ofua);
+ update->xid = ofua->xid;
+ return 0;
+ } else if (update->event == OFPFME_PAUSED
+ || update->event == OFPFME_RESUMED) {
+ struct ofp_flow_update_paused *ofup;
- update->ofpacts = ofpacts->data;
- update->ofpacts_len = ofpacts->size;
- return 0;
- } else {
- VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR reply has bad event %"PRIu16,
- ntohs(nfuh->event));
- return OFPERR_NXBRC_FM_BAD_EVENT;
- }
+ if (length != sizeof *ofup) {
+ goto bad_len;
+ }
+
+ ofup = ofpbuf_pull(msg, sizeof *ofup);
+ return 0;
+ } else if (update->event == OFPFME_INITIAL
+ || update->event == OFPFME_ADDED
+ || update->event == OFPFME_REMOVED
+ || update->event == OFPFME_MODIFIED) {
+ struct ofp_flow_update_full *ofuf;
+ unsigned int instructions_len;
+
+ if (length < sizeof *ofuf) {
+ goto bad_len;
+ }
+ ofuf = ofpbuf_pull(msg, sizeof *ofuf);
+ if (sizeof *ofuf > length) {
+ goto bad_len;
+ }
+
+ update->reason = ofuf->reason;
+ update->idle_timeout = ntohs(ofuf->idle_timeout);
+ update->hard_timeout = ntohs(ofuf->hard_timeout);
+ update->table_id = ofuf->table_id;
+ update->cookie = ofuf->cookie;
+ update->priority = ntohs(ofuf->priority);
+
+ error = ofputil_pull_ofp11_match(
+ msg, NULL, NULL, &update->match, &padded_match_len);
+ if (error) {
+ return error;
+ }
+
+ instructions_len = length - sizeof *ofuf - padded_match_len;
+ error = ofpacts_pull_openflow_instructions(
+ msg, instructions_len, oh->version, NULL, NULL, ofpacts);
+ if (error) {
+ return error;
+ }
+
+ update->ofpacts = ofpacts->data;
+ update->ofpacts_len = ofpacts->size;
+ return 0;
+ } else {
+ VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR reply has bad event %"PRIu16,
+ ntohs(ofuh->event));
+ return OFPERR_NXBRC_FM_BAD_EVENT;
+ }
+ }
+ default:
+ OVS_NOT_REACHED();
+ }
bad_len:
- VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR reply has %"PRIu32" "
- "leftover bytes at end", msg->size);
+ VLOG_WARN_RL(&rl, "%s reply has %"PRIu32" leftover bytes at end",
+ ofpraw_get_name(raw), msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
uint32_t
ofputil_decode_flow_monitor_cancel(const struct ofp_header *oh)
{
- const struct nx_flow_monitor_cancel *cancel = ofpmsg_body(oh);
+ enum ofperr error;
+ enum ofpraw raw;
- return ntohl(cancel->id);
+ error = ofpraw_decode(&raw, oh);
+ if (error) {
+ return error;
+ }
+
+ switch ((int) raw) {
+ case OFPRAW_ONFT13_FLOW_MONITOR_CANCEL:
+ case OFPRAW_NXT_FLOW_MONITOR_CANCEL: {
+ const struct nx_flow_monitor_cancel *cancel = ofpmsg_body(oh);
+ return ntohl(cancel->id);
+ }
+ default:
+ OVS_NOT_REACHED();
+ }
}
struct ofpbuf *
@@ -666,9 +1051,99 @@ ofputil_encode_flow_monitor_cancel(uint32_t id, enum ofputil_protocol protocol)
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
struct ofpbuf *msg;
- msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, version, 0);
- nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc);
- nfmc->id = htonl(id);
+ switch (version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION: {
+ if (version == OFP13_VERSION) {
+ msg = ofpraw_alloc(OFPRAW_ONFT13_FLOW_MONITOR_CANCEL, version, 0);
+ } else {
+ msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, version, 0);
+ }
+ nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc);
+ nfmc->id = htonl(id);
+ break;
+ }
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
+ struct ofp14_flow_monitor_request *ofmr;
+
+ msg = ofpbuf_new(0);
+
+ ofpraw_put(OFPRAW_OFPST14_FLOW_MONITOR_REQUEST, version, msg);
+
+ size_t start_ofs = msg->size;
+ ofpbuf_put_zeros(msg, sizeof *ofmr);
+
+ ofmr = ofpbuf_at_assert(msg, start_ofs, sizeof *ofmr);
+ ofmr->monitor_id = htonl(id);
+ ofmr->command = OFPFMC_DELETE;
+ break;
+ }
+ default:
+ OVS_NOT_REACHED();
+ }
+ return msg;
+}
+
+struct ofpbuf *
+ofputil_encode_flow_monitor_pause(enum ofp_flow_update_event command,
+ enum ofputil_protocol protocol)
+{
+ struct ofpbuf *msg;
+ enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
+
+ if (!(command == OFPFME_PAUSED || command == OFPFME_RESUMED)) {
+ OVS_NOT_REACHED();
+ }
+
+ switch (version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ if (command == OFPFME_PAUSED) {
+ msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_MONITOR_PAUSED,
+ version, htonl(0), 0);
+ } else {
+ msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_MONITOR_RESUMED,
+ version, htonl(0), 0);
+ }
+ break;
+ case OFP13_VERSION:
+ if (command == OFPFME_PAUSED) {
+ msg = ofpraw_alloc_xid(OFPRAW_ONFT13_FLOW_MONITOR_PAUSED,
+ version, htonl(0), 0);
+ } else {
+ msg = ofpraw_alloc_xid(OFPRAW_ONFT13_FLOW_MONITOR_RESUMED,
+ version, htonl(0), 0);
+ }
+ break;
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
+ msg = ofpraw_alloc_xid(OFPRAW_OFPST14_FLOW_MONITOR_REPLY, version,
+ htonl(0), 1024);
+ struct ofp_flow_update_header *ofuh;
+ size_t start_ofs = msg->size;
+
+ struct ofp_flow_update_paused *ofup;
+
+ ofpbuf_put_zeros(msg, sizeof *ofup);
+ ofup = ofpbuf_at_assert(msg, start_ofs, sizeof *ofup);
+ ofup->event = htons(command);
+ ofup->length = htons(8);
+
+ ofuh = ofpbuf_at_assert(msg, start_ofs, sizeof *ofuh);
+ ofuh->length = htons(msg->size - start_ofs);
+ ofuh->event = htons(command);
+
+ ofpmsg_update_length(msg);
+ break;
+ }
+ default:
+ OVS_NOT_REACHED();
+ }
+
return msg;
}
@@ -679,8 +1154,25 @@ ofputil_start_flow_update(struct ovs_list *replies,
struct ofpbuf *msg;
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
- msg = ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY, version,
- htonl(0), 1024);
+ switch (version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ msg = ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY, version,
+ htonl(0), 1024);
+ break;
+ case OFP13_VERSION:
+ msg = ofpraw_alloc_xid(OFPRAW_ONFST13_FLOW_MONITOR_REPLY, version,
+ htonl(0), 1024);
+ break;
+ case OFP14_VERSION:
+ case OFP15_VERSION:
+ msg = ofpraw_alloc_xid(OFPRAW_OFPST14_FLOW_MONITOR_REPLY, version,
+ htonl(0), 1024);
+ break;
+ default:
+ OVS_NOT_REACHED();
+ }
ovs_list_init(replies);
ovs_list_push_back(replies, &msg->list_node);
@@ -695,7 +1187,6 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
CONST_CAST(struct ofputil_flow_update *, update);
const struct tun_table *orig_tun_table;
enum ofp_version version = ofpmp_version(replies);
- struct nx_flow_update_header *nfuh;
struct ofpbuf *msg;
size_t start_ofs;
@@ -705,32 +1196,80 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
msg = ofpbuf_from_list(ovs_list_back(replies));
start_ofs = msg->size;
- if (update->event == NXFME_ABBREV) {
- struct nx_flow_update_abbrev *nfua;
+ switch (version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION: {
+ struct nx_flow_update_header *nfuh;
- nfua = ofpbuf_put_zeros(msg, sizeof *nfua);
- nfua->xid = update->xid;
- } else {
- struct nx_flow_update_full *nfuf;
- int match_len;
+ if (update->event == OFPFME_ABBREV) {
+ struct nx_flow_update_abbrev *nfua;
- ofpbuf_put_zeros(msg, sizeof *nfuf);
- match_len = nx_put_match(msg, &update->match, htonll(0), htonll(0));
- ofpacts_put_openflow_actions(update->ofpacts, update->ofpacts_len, msg,
- version);
- nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf);
- nfuf->reason = htons(update->reason);
- nfuf->priority = htons(update->priority);
- nfuf->idle_timeout = htons(update->idle_timeout);
- nfuf->hard_timeout = htons(update->hard_timeout);
- nfuf->match_len = htons(match_len);
- nfuf->table_id = update->table_id;
- nfuf->cookie = update->cookie;
- }
+ nfua = ofpbuf_put_zeros(msg, sizeof *nfua);
+ nfua->xid = update->xid;
+ } else {
+ struct nx_flow_update_full *nfuf;
+ int match_len;
+
+ ofpbuf_put_zeros(msg, sizeof *nfuf);
+ if (version == OFP13_VERSION) {
+ match_len = oxm_put_match(msg, &update->match, version);
+ ofpacts_put_openflow_instructions(
+ update->ofpacts, update->ofpacts_len, msg, version);
+ } else {
+ match_len = nx_put_match(msg, &update->match,
+ htonll(0), htonll(0));
+ ofpacts_put_openflow_actions(
+ update->ofpacts, update->ofpacts_len, msg, version);
+ }
+ nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf);
+ nfuf->reason = htons(update->reason);
+ nfuf->priority = htons(update->priority);
+ nfuf->idle_timeout = htons(update->idle_timeout);
+ nfuf->hard_timeout = htons(update->hard_timeout);
+ nfuf->match_len = htons(match_len);
+ nfuf->table_id = update->table_id;
+ nfuf->cookie = update->cookie;
+ }
+
+ nfuh = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuh);
+ nfuh->length = htons(msg->size - start_ofs);
+ nfuh->event = htons(ofp_to_nx_flow_update_event(update->event));
+ break;
+ }
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
+ struct ofp_flow_update_header *ofuh;
- nfuh = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuh);
- nfuh->length = htons(msg->size - start_ofs);
- nfuh->event = htons(update->event);
+ if (update->event == OFPFME_ABBREV) {
+ struct ofp_flow_update_abbrev *ofua;
+
+ ofua = ofpbuf_put_zeros(msg, sizeof *ofua);
+ ofua->xid = update->xid;
+ } else {
+ struct ofp_flow_update_full *ofuf;
+
+ ofpbuf_put_zeros(msg, sizeof *ofuf);
+ oxm_put_match(msg, &update->match, version);
+ ofpacts_put_openflow_instructions(update->ofpacts,
+ update->ofpacts_len,
+ msg, version);
+ ofuf = ofpbuf_at_assert(msg, start_ofs, sizeof *ofuf);
+ ofuf->reason = update->reason;
+ ofuf->priority = htons(update->priority);
+ ofuf->idle_timeout = htons(update->idle_timeout);
+ ofuf->hard_timeout = htons(update->hard_timeout);
+ ofuf->table_id = update->table_id;
+ ofuf->cookie = update->cookie;
+ }
+
+ ofuh = ofpbuf_at_assert(msg, start_ofs, sizeof *ofuh);
+ ofuh->length = htons(msg->size - start_ofs);
+ ofuh->event = htons(update->event);
+ break;
+ }
+ }
ofpmp_postappend(replies, start_ofs);
update_->match.flow.tunnel.metadata.tab = orig_tun_table;
@@ -746,24 +1285,37 @@ ofputil_flow_update_format(struct ds *s,
ds_put_cstr(s, "\n event=");
switch (update->event) {
- case NXFME_ADDED:
+ case OFPFME_INITIAL:
+ ds_put_cstr(s, "INITIAL");
+ break;
+
+ case OFPFME_ADDED:
ds_put_cstr(s, "ADDED");
break;
- case NXFME_DELETED:
+ case OFPFME_REMOVED:
ds_put_format(s, "DELETED reason=%s",
ofp_flow_removed_reason_to_string(update->reason,
reasonbuf,
sizeof reasonbuf));
break;
- case NXFME_MODIFIED:
+ case OFPFME_MODIFIED:
ds_put_cstr(s, "MODIFIED");
break;
- case NXFME_ABBREV:
+ case OFPFME_ABBREV:
ds_put_format(s, "ABBREV xid=0x%"PRIx32, ntohl(update->xid));
return;
+
+ case OFPFME_PAUSED:
+ ds_put_cstr(s, "PAUSED");
+ return;
+
+ case OFPFME_RESUMED:
+ ds_put_cstr(s, "RESUMED");
+ return;
+
}
ds_put_format(s, " table=");
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index b0facbf9f..bd37fa17a 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -744,10 +744,10 @@ ofp_print_nxt_flow_monitor_cancel(struct ds *string,
}
static enum ofperr
-ofp_print_nxst_flow_monitor_request(struct ds *string,
- const struct ofp_header *oh,
- const struct ofputil_port_map *port_map,
- const struct ofputil_table_map *table_map)
+ofp_print_flow_monitor_request(struct ds *string,
+ const struct ofp_header *oh,
+ const struct ofputil_port_map *port_map,
+ const struct ofputil_table_map *table_map)
{
struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
for (;;) {
@@ -765,10 +765,10 @@ ofp_print_nxst_flow_monitor_request(struct ds *string,
}
static enum ofperr
-ofp_print_nxst_flow_monitor_reply(struct ds *string,
- const struct ofp_header *oh,
- const struct ofputil_port_map *port_map,
- const struct ofputil_table_map *table_map)
+ofp_print_flow_monitor_reply(struct ds *string,
+ const struct ofp_header *oh,
+ const struct ofputil_port_map *port_map,
+ const struct ofputil_table_map *table_map)
{
uint64_t ofpacts_stub[1024 / 8];
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
@@ -1147,12 +1147,12 @@ ofp_to_string__(const struct ofp_header *oh,
break;
case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
- return ofp_print_nxst_flow_monitor_request(string, msg, port_map,
- table_map);
+ return ofp_print_flow_monitor_request(string, msg, port_map,
+ table_map);
case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
- return ofp_print_nxst_flow_monitor_reply(string, msg, port_map,
- table_map);
+ return ofp_print_flow_monitor_reply(string, msg, port_map,
+ table_map);
case OFPTYPE_BUNDLE_CONTROL:
return ofp_print_bundle_ctrl(string, msg);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index b6af9ddb5..7b14cae77 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -2099,6 +2099,7 @@ ofmonitor_create(const struct ofputil_flow_monitor_request *request,
m->id = request->id;
m->flags = request->flags;
m->out_port = request->out_port;
+ m->out_group = request->out_group;
m->table_id = request->table_id;
minimatch_init(&m->match, &request->match);
@@ -2134,7 +2135,7 @@ ofmonitor_destroy(struct ofmonitor *m)
void
ofmonitor_report(struct connmgr *mgr, struct rule *rule,
- enum nx_flow_update_event event,
+ enum ofp_flow_update_event event,
enum ofp_flow_removed_reason reason,
const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid,
const struct rule_actions *old_actions)
@@ -2144,39 +2145,42 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
return;
}
- enum nx_flow_monitor_flags update;
+ enum ofp14_flow_monitor_flags update;
switch (event) {
- case NXFME_ADDED:
- update = NXFMF_ADD;
+ case OFPFME_ADDED:
+ update = OFPFMF_ADD;
rule->add_seqno = rule->modify_seqno = monitor_seqno++;
break;
- case NXFME_DELETED:
- update = NXFMF_DELETE;
+ case OFPFME_REMOVED:
+ update = OFPFMF_REMOVED;
break;
- case NXFME_MODIFIED:
- update = NXFMF_MODIFY;
+ case OFPFME_MODIFIED:
+ update = OFPFMF_MODIFY;
rule->modify_seqno = monitor_seqno++;
break;
default:
- case NXFME_ABBREV:
+ case OFPFME_INITIAL:
+ case OFPFME_PAUSED:
+ case OFPFME_RESUMED:
+ case OFPFME_ABBREV:
OVS_NOT_REACHED();
}
struct ofconn *ofconn;
LIST_FOR_EACH (ofconn, connmgr_node, &mgr->conns) {
if (ofconn->monitor_paused) {
- /* Only send NXFME_DELETED notifications for flows that were added
+ /* Only send OFPFME_REMOVED notifications for flows that were added
* before we paused. */
- if (event != NXFME_DELETED
+ if (event != OFPFME_REMOVED
|| rule->add_seqno > ofconn->monitor_paused) {
continue;
}
}
- enum nx_flow_monitor_flags flags = 0;
+ enum ofp14_flow_monitor_flags flags = 0;
struct ofmonitor *m;
HMAP_FOR_EACH (m, ofconn_node, &ofconn->monitors) {
if (m->flags & update
@@ -2186,6 +2190,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
&& ofpacts_output_to_port(old_actions->ofpacts,
old_actions->ofpacts_len,
m->out_port)))
+ && ofproto_rule_has_out_group(rule, m->out_group)
&& cls_rule_is_loose_match(&rule->cr, &m->match)) {
flags |= m->flags;
}
@@ -2198,12 +2203,12 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
ofconn->sent_abbrev_update = false;
}
- if (flags & NXFMF_OWN || ofconn != abbrev_ofconn
+ if (flags & OFPFMF_ONLY_OWN || ofconn != abbrev_ofconn
|| ofconn->monitor_paused) {
struct ofputil_flow_update fu;
fu.event = event;
- fu.reason = event == NXFME_DELETED ? reason : 0;
+ fu.reason = event == OFPFME_REMOVED ? reason : 0;
fu.table_id = rule->table_id;
fu.cookie = rule->flow_cookie;
minimatch_expand(&rule->cr.match, &fu.match);
@@ -2214,7 +2219,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
fu.hard_timeout = rule->hard_timeout;
ovs_mutex_unlock(&rule->mutex);
- if (flags & NXFMF_ACTIONS) {
+ if (flags & OFPFMF_INSTRUCTIONS) {
const struct rule_actions *actions
= rule_get_actions(rule);
fu.ofpacts = actions->ofpacts;
@@ -2228,7 +2233,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
} else if (!ofconn->sent_abbrev_update) {
struct ofputil_flow_update fu;
- fu.event = NXFME_ABBREV;
+ fu.event = OFPFME_ABBREV;
fu.xid = abbrev_xid;
ofputil_append_flow_update(&fu, &ofconn->updates,
ofproto_get_tun_tab(rule->ofproto));
@@ -2263,9 +2268,8 @@ ofmonitor_flush(struct connmgr *mgr)
COVERAGE_INC(ofmonitor_pause);
ofconn->monitor_paused = monitor_seqno++;
protocol = ofconn_get_protocol(ofconn);
- struct ofpbuf *pause = ofpraw_alloc_xid(
- OFPRAW_NXT_FLOW_MONITOR_PAUSED,
- ofputil_protocol_to_ofp_version(protocol), htonl(0), 0);
+ struct ofpbuf *pause = ofputil_encode_flow_monitor_pause(
+ OFPFME_PAUSED,protocol);
ofconn_send(ofconn, pause, counter);
}
}
@@ -2289,9 +2293,8 @@ ofmonitor_resume(struct ofconn *ofconn)
ofconn_get_protocol(ofconn));
protocol = ofconn_get_protocol(ofconn);
- struct ofpbuf *resumed = ofpraw_alloc_xid(
- OFPRAW_NXT_FLOW_MONITOR_RESUMED,
- ofputil_protocol_to_ofp_version(protocol), htonl(0), 0);
+ struct ofpbuf *resumed = ofputil_encode_flow_monitor_pause(
+ OFPFME_RESUMED, protocol);
ovs_list_push_back(&msgs, &resumed->list_node);
ofconn_send_replies(ofconn, &msgs);
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 56fdc3504..3471d38f9 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -168,10 +168,11 @@ struct ofmonitor {
struct hmap_node ofconn_node; /* In ofconn's 'monitors' hmap. */
uint32_t id;
- enum nx_flow_monitor_flags flags;
+ enum ofp14_flow_monitor_flags flags;
/* Matching. */
ofp_port_t out_port;
+ uint32_t out_group;
uint8_t table_id;
struct minimatch match;
};
@@ -187,7 +188,8 @@ void ofmonitor_destroy(struct ofmonitor *)
OVS_REQUIRES(ofproto_mutex);
void ofmonitor_report(struct connmgr *, struct rule *,
- enum nx_flow_update_event, enum ofp_flow_removed_reason,
+ enum ofp_flow_update_event event,
+ enum ofp_flow_removed_reason,
const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid,
const struct rule_actions *old_actions)
OVS_REQUIRES(ofproto_mutex);
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 47e96e62e..7e3fb6698 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -425,7 +425,7 @@ struct rule {
* 'add_seqno' is the sequence number when this rule was created.
* 'modify_seqno' is the sequence number when this rule was last modified.
* See 'monitor_seqno' in connmgr.c for more information. */
- enum nx_flow_monitor_flags monitor_flags OVS_GUARDED_BY(ofproto_mutex);
+ enum ofp14_flow_monitor_flags monitor_flags OVS_GUARDED_BY(ofproto_mutex);
uint64_t add_seqno OVS_GUARDED_BY(ofproto_mutex);
uint64_t modify_seqno OVS_GUARDED_BY(ofproto_mutex);
@@ -486,6 +486,8 @@ const struct rule_actions *rule_actions_create(const struct ofpact *, size_t);
void rule_actions_destroy(const struct rule_actions *);
bool ofproto_rule_has_out_port(const struct rule *, ofp_port_t port)
OVS_REQUIRES(ofproto_mutex);
+bool ofproto_rule_has_out_group(const struct rule *rule, uint32_t group_id)
+ OVS_REQUIRES(ofproto_mutex);
#define DECL_OFPROTO_COLLECTION(TYPE, NAME) \
DECL_OBJECT_COLLECTION(TYPE, NAME) \
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f59413c73..8d5815ff5 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3220,7 +3220,7 @@ ofproto_rule_has_out_port(const struct rule *rule, ofp_port_t port)
}
/* Returns true if 'rule' has group and equals group_id. */
-static bool
+bool
ofproto_rule_has_out_group(const struct rule *rule, uint32_t group_id)
OVS_REQUIRES(ofproto_mutex)
{
@@ -5292,7 +5292,7 @@ add_flow_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
if (old_rule) {
ovsrcu_postpone(remove_rule_rcu, old_rule);
} else {
- ofmonitor_report(ofproto->connmgr, new_rule, NXFME_ADDED, 0,
+ ofmonitor_report(ofproto->connmgr, new_rule, OFPFME_ADDED, 0,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
@@ -5712,8 +5712,8 @@ replace_rule_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
learned_cookies_dec(ofproto, old_actions, dead_cookies);
if (replaced_rule) {
- enum nx_flow_update_event event = ofm->command == OFPFC_ADD
- ? NXFME_ADDED : NXFME_MODIFIED;
+ enum ofp_flow_update_event event = ofm->command == OFPFC_ADD
+ ? OFPFME_ADDED : OFPFME_MODIFIED;
bool changed_cookie = (new_rule->flow_cookie
!= old_rule->flow_cookie);
@@ -5723,7 +5723,7 @@ replace_rule_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
old_actions->ofpacts,
old_actions->ofpacts_len);
- if (event != NXFME_MODIFIED || changed_actions
+ if (event != OFPFME_MODIFIED || changed_actions
|| changed_cookie) {
ofmonitor_report(ofproto->connmgr, new_rule, event, 0,
req ? req->ofconn : NULL,
@@ -5732,7 +5732,7 @@ replace_rule_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
}
} else {
/* XXX: This is slight duplication with delete_flows_finish__() */
- ofmonitor_report(ofproto->connmgr, old_rule, NXFME_DELETED,
+ ofmonitor_report(ofproto->connmgr, old_rule, OFPFME_REMOVED,
OFPRR_EVICTION,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
@@ -6013,7 +6013,7 @@ delete_flows_finish__(struct ofproto *ofproto,
* before the rule is actually destroyed. */
rule->removed_reason = reason;
- ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
+ ofmonitor_report(ofproto->connmgr, rule, OFPFME_REMOVED, reason,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
@@ -6419,7 +6419,7 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
static void
ofproto_compose_flow_refresh_update(const struct rule *rule,
- enum nx_flow_monitor_flags flags,
+ enum ofp14_flow_monitor_flags flags,
struct ovs_list *msgs,
const struct tun_table *tun_table,
enum ofputil_protocol protocol)
@@ -6428,8 +6428,9 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
const struct rule_actions *actions;
struct ofputil_flow_update fu;
- fu.event = (flags & (NXFMF_INITIAL | NXFMF_ADD)
- ? NXFME_ADDED : NXFME_MODIFIED);
+ fu.event = flags & OFPFMF_INITIAL ? OFPFME_INITIAL :
+ flags & OFPFMF_ADD ?
+ OFPFME_ADDED : OFPFME_MODIFIED;
fu.reason = 0;
ovs_mutex_lock(&rule->mutex);
fu.idle_timeout = rule->idle_timeout;
@@ -6440,7 +6441,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
minimatch_expand(&rule->cr.match, &fu.match);
fu.priority = rule->cr.priority;
- actions = flags & NXFMF_ACTIONS ? rule_get_actions(rule) : NULL;
+ actions = flags & OFPFMF_INSTRUCTIONS ? rule_get_actions(rule) : NULL;
fu.ofpacts = actions ? actions->ofpacts : NULL;
fu.ofpacts_len = actions ? actions->ofpacts_len : 0;
@@ -6459,7 +6460,7 @@ ofmonitor_compose_refresh_updates(struct rule_collection *rules,
struct rule *rule;
RULE_COLLECTION_FOR_EACH (rule, rules) {
- enum nx_flow_monitor_flags flags = rule->monitor_flags;
+ enum ofp14_flow_monitor_flags flags = rule->monitor_flags;
rule->monitor_flags = 0;
ofproto_compose_flow_refresh_update(rule, flags, msgs,
@@ -6473,7 +6474,7 @@ ofproto_collect_ofmonitor_refresh_rule(const struct ofmonitor *m,
struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
- enum nx_flow_monitor_flags update;
+ enum ofp14_flow_monitor_flags update;
if (rule_is_hidden(rule)) {
return;
@@ -6483,11 +6484,15 @@ ofproto_collect_ofmonitor_refresh_rule(const struct ofmonitor *m,
return;
}
+ if (!ofproto_rule_has_out_group(rule, m->out_group)) {
+ return;
+ }
+
if (seqno) {
if (rule->add_seqno > seqno) {
- update = NXFMF_ADD | NXFMF_MODIFY;
+ update = OFPFMF_ADD | OFPFMF_MODIFY;
} else if (rule->modify_seqno > seqno) {
- update = NXFMF_MODIFY;
+ update = OFPFMF_MODIFY;
} else {
return;
}
@@ -6496,13 +6501,13 @@ ofproto_collect_ofmonitor_refresh_rule(const struct ofmonitor *m,
return;
}
} else {
- update = NXFMF_INITIAL;
+ update = OFPFMF_INITIAL;
}
if (!rule->monitor_flags) {
rule_collection_add(rules, rule);
}
- rule->monitor_flags |= update | (m->flags & NXFMF_ACTIONS);
+ rule->monitor_flags |= update | (m->flags & OFPFMF_INSTRUCTIONS);
}
static void
@@ -6531,7 +6536,7 @@ ofproto_collect_ofmonitor_initial_rules(struct ofmonitor *m,
struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
- if (m->flags & NXFMF_INITIAL) {
+ if (m->flags & OFPFMF_INITIAL) {
ofproto_collect_ofmonitor_refresh_rules(m, 0, rules);
}
}
@@ -6594,16 +6599,50 @@ handle_flow_monitor_request(struct ofconn *ofconn, const struct ovs_list *msgs)
}
struct ofmonitor *m;
- error = ofmonitor_create(&request, ofconn, &m);
- if (error) {
- goto error;
+ switch (request.command) {
+ case OFPFMC_ADD: {
+ error = ofmonitor_create(&request, ofconn, &m);
+ if (error) {
+ goto error;
+ }
+
+ if (n_monitors >= allocated_monitors) {
+ monitors = x2nrealloc(monitors, &allocated_monitors,
+ sizeof *monitors);
+ }
+ monitors[n_monitors++] = m;
+ break;
}
+ case OFPFMC_MODIFY:
+ /* Modify operation is to delete old monitor and create a
+ * new one. */
+ m = ofmonitor_lookup(ofconn, request.id);
+ if (!m) {
+ error = OFPERR_OFPMOFC_UNKNOWN_MONITOR;
+ goto error;
+ }
+ ofmonitor_destroy(m);
+
+ error = ofmonitor_create(&request, ofconn, &m);
+ if (error) {
+ goto error;
+ }
- if (n_monitors >= allocated_monitors) {
- monitors = x2nrealloc(monitors, &allocated_monitors,
- sizeof *monitors);
+ if (n_monitors >= allocated_monitors) {
+ monitors = x2nrealloc(monitors, &allocated_monitors,
+ sizeof *monitors);
+ }
+ monitors[n_monitors++] = m;
+ break;
+ case OFPFMC_DELETE:
+ m = ofmonitor_lookup(ofconn, request.id);
+ if (!m) {
+ error = OFPERR_OFPMOFC_UNKNOWN_MONITOR;
+ goto error;
+ }
+ ofmonitor_destroy(m);
+ break;
}
- monitors[n_monitors++] = m;
continue;
error:
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 2c7e163bd..ab5c37649 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -3258,32 +3258,89 @@ NXT_SET_CONTROLLER_ID (xid=0x3): id=123
])
AT_CLEANUP
-AT_SETUP([NXT_FLOW_MONITOR_CANCEL])
+AT_SETUP([FLOW_MONITOR_CANCEL])
AT_KEYWORDS([ofp-print])
+
+dnl OpenFlow 1.0-1.2
AT_CHECK([ovs-ofctl ofp-print "\
01 04 00 14 00 00 00 03 00 00 23 20 00 00 00 15 \
01 02 30 40 \
"], [0], [dnl
NXT_FLOW_MONITOR_CANCEL (xid=0x3): id=16920640
])
+
+dnl OpenFlow 1.3
+AT_CHECK([ovs-ofctl ofp-print "\
+04 04 00 14 00 00 00 06 4f 4e 46 00 00 00 07 4e \
+01 02 30 40 \
+"], [0], [dnl
+ONFT_FLOW_MONITOR_CANCEL (OF1.3) (xid=0x6): id=16920640
+])
+
+dnl OpenFlow 1.4+
+AT_CHECK([ovs-ofctl ofp-print "\
+05 12 00 28 00 00 00 04 00 10 00 00 00 00 00 00 \
+01 02 30 40 00 00 00 00 00 00 00 00 00 00 00 02 \
+00 01 00 04 00 00 00 00 \
+"], [0], [dnl
+OFPST_FLOW_MONITOR request (OF1.4) (xid=0x4):
+ id=16920640 command=delete
+])
+
AT_CLEANUP
-AT_SETUP([NXT_FLOW_MONITOR_PAUSED])
+AT_SETUP([FLOW_MONITOR_PAUSED])
AT_KEYWORDS([ofp-print])
+
+dnl OpenFlow 1.0-1.2
AT_CHECK([ovs-ofctl ofp-print "\
01 04 00 10 00 00 00 03 00 00 23 20 00 00 00 16 \
"], [0], [dnl
NXT_FLOW_MONITOR_PAUSED (xid=0x3):
])
+
+dnl OpenFlow 1.3
+AT_CHECK([ovs-ofctl ofp-print "\
+04 04 00 10 00 00 00 03 4f 4e 46 00 00 00 07 4F \
+"], [0], [dnl
+ONFT_FLOW_MONITOR_PAUSED (OF1.3) (xid=0x3):
+])
+
+dnl OpenFlow 1.4+
+AT_CHECK([ovs-ofctl ofp-print "\
+05 13 00 18 00 00 00 00 00 10 00 00 00 00 00 00 \
+00 08 00 05 00 00 00 00 \
+"], [0], [dnl
+OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
+ event=PAUSED
+])
AT_CLEANUP
-AT_SETUP([NXT_FLOW_MONITOR_RESUMED])
+AT_SETUP([FLOW_MONITOR_RESUMED])
AT_KEYWORDS([ofp-print])
+
+dnl OpenFlow 1.0-1.2
AT_CHECK([ovs-ofctl ofp-print "\
01 04 00 10 00 00 00 03 00 00 23 20 00 00 00 17 \
"], [0], [dnl
NXT_FLOW_MONITOR_RESUMED (xid=0x3):
])
+
+dnl OpenFlow 1.3
+AT_CHECK([ovs-ofctl ofp-print "\
+04 04 00 10 00 00 00 03 4f 4e 46 00 00 00 07 50 \
+"], [0], [dnl
+ONFT_FLOW_MONITOR_RESUMED (OF1.3) (xid=0x3):
+])
+
+dnl OpenFlow 1.4+
+AT_CHECK([ovs-ofctl ofp-print "\
+05 13 00 18 00 00 00 00 00 10 00 00 00 00 00 00
+00 08 00 06 00 00 00 00
+"], [0], [dnl
+OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
+ event=RESUMED
+])
AT_CLEANUP
AT_SETUP([NXT_SET_FLOW_FORMAT])
@@ -3629,8 +3686,10 @@ NXST_AGGREGATE reply (xid=0x4): packet_count=7 byte_count=420 flow_count=7
])
AT_CLEANUP
-AT_SETUP([NXST_FLOW_MONITOR request])
+AT_SETUP([FLOW_MONITOR request])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+
+dnl OpenFlow 1.0-1.2
AT_CHECK([ovs-ofctl ofp-print "\
01 10 00 40 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 02 00 00 00 00 \
00 00 40 00 00 3f ff fe 00 00 01 00 00 00 00 00 \
@@ -3640,10 +3699,37 @@ NXST_FLOW_MONITOR request (xid=0x4):
id=16384 flags=initial,add,delete,modify,actions,own out_port=LOCAL table=1
id=8192 flags=delete table=2 in_port=1
])
+
+dnl OpenFlow 1.3
+AT_CHECK([ovs-ofctl ofp-print "\
+04 12 00 48 00 00 00 06 ff ff 00 00 00 00 00 00 \
+4f 4e 46 00 00 00 07 4e \
+00 00 10 00 00 3f 00 04 ff ff ff fe 01 00 00 00 00 01 00 04 00 00 00 00 \
+00 00 20 00 00 04 ff ff 00 00 00 02 01 00 00 00 00 01 00 04 00 00 00 00 \
+"], [0], [dnl
+ONFST_FLOW_MONITOR request (OF1.3) (xid=0x6):
+ id=4096 flags=initial,add,delete,modify,actions,own out_port=LOCAL table=1
+ id=8192 flags=delete out_port=2 table=1
+])
+
+dnl OpenFlow 1.4+
+AT_CHECK([ovs-ofctl ofp-print "\
+05 12 00 58 00 00 00 06 00 10 00 00 00 00 00 00 \
+00 00 10 00 ff ff ff fe ff ff ff ff 00 5f 00 00 00 01 00 04 00 00 00 00 \
+00 00 20 00 00 00 00 01 00 00 00 40 00 5f 01 01 00 01 00 04 00 00 00 00 \
+00 00 40 00 00 00 00 02 00 00 00 40 00 5f 02 02 00 01 00 04 00 00 00 00 \
+"], [0], [dnl
+OFPST_FLOW_MONITOR request (OF1.4) (xid=0x6):
+ id=4096 flags=initial,add,delete,modify,actions,own out_port=LOCAL table=0
+ id=8192 flags=initial,add,delete,modify,actions,own out_port=1 out_group=64 table=1
+ id=16384 command=delete
+])
AT_CLEANUP
-AT_SETUP([NXST_FLOW_MONITOR reply])
+AT_SETUP([FLOW_MONITOR reply])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+
+dnl OpenFlow 1.0-1.2
AT_CHECK([ovs-ofctl ofp-print "\
01 11 00 40 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 02 00 00 00 00 \
00 20 00 01 00 05 80 00 00 05 00 10 00 06 01 00 12 34 56 78 9a bc de f0 \
@@ -3654,6 +3740,32 @@ NXST_FLOW_MONITOR reply (xid=0x4):
event=DELETED reason=eviction table=1 idle_timeout=5 hard_timeout=16 cookie=0x123456789abcdef0 in_port=1
event=ABBREV xid=0x186a0
])
+
+dnl OpenFlow 1.3
+AT_CHECK([ovs-ofctl ofp-print "\
+04 13 00 48 00 00 00 06 ff ff 00 00 00 00 00 00 4f 4e 46 00 00 00 07 4e \
+00 28 00 01 00 05 80 00 00 00 00 00 00 0c 00 00 \
+12 34 56 78 9a bc de f0 00 01 00 0c 80 00 00 04 \
+00 00 00 01 00 00 00 00 \
+00 08 00 03 00 01 86 a0 \
+"], [0], [dnl
+ONFST_FLOW_MONITOR reply (OF1.3) (xid=0x6):
+ event=DELETED reason=eviction table=0 cookie=0x123456789abcdef0 in_port=1
+ event=ABBREV xid=0x186a0
+])
+
+dnl OpenFlow 1.4+
+AT_CHECK([ovs-ofctl ofp-print "\
+05 13 00 40 00 00 00 00 00 10 00 00 00 00 00 00 \
+00 28 00 02 00 05 00 00 00 00 80 00 00 00 00 00 \
+12 34 56 78 9a bc de f0 00 01 00 0c 80 00 00 04 \
+00 00 00 01 00 00 00 00 \
+00 08 00 04 00 01 86 a0 \
+"], [0], [dnl
+OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
+ event=DELETED reason=eviction table=0 cookie=0x123456789abcdef0 in_port=1
+ event=ABBREV xid=0x186a0
+])
AT_CLEANUP
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 5f5a3fda4..03b479253 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -4593,8 +4593,11 @@ ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:1
ovs-ofctl -O $2 monitor br0 watch: --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier
+
+# For OF(1.4+), replace INITIAL to ADDED
+sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
- [NXST_FLOW_MONITOR reply$3:
+ [$4 reply$3:
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1
OFPT_BARRIER_REPLY$3:
])
@@ -4608,7 +4611,7 @@ ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,dl_vlan_pcp=1,actions=output:7
ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:8
ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,dl_vlan_pcp=0,actions=output:9
ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,dl_vlan_pcp=1,actions=output:10
-ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,actions=output:11
+ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,dl_vlan_pcp=3,actions=output:11
ovs-ofctl add-flow br0 in_port=0,dl_vlan=8191,dl_vlan_pcp=0,actions=output:12
ovs-ofctl add-flow br0 in_port=0,dl_vlan=8191,dl_vlan_pcp=1,actions=output:13
ovs-ofctl add-flow br0 in_port=0,dl_vlan=8191,actions=output:14
@@ -4626,71 +4629,74 @@ ovs-ofctl mod-flows br0 cookie=5,dl_vlan=123,actions=output:3
ovs-ofctl del-flows br0 dl_vlan=123
ovs-ofctl del-flows br0
ovs-appctl -t ovs-ofctl ofctl/barrier
+
+# For OF(1.4+), replace INITIAL to ADDED
+sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log | multiline_sort], [0],
-[NXST_FLOW_MONITOR reply$3 (xid=0x0):
+[$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=124 actions=output:2
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:5
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:6
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:7
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:8
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:9
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:10
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
- event=ADDED table=0 cookie=0 in_port=0,vlan_tci=0x0000 actions=output:11
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
+ event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=3 actions=output:11
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=0 actions=output:12
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=1 actions=output:13
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=4095 actions=output:14
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:15
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:16
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0 actions=output:17
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:18
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:19
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0 actions=output:20
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan_pcp=0 actions=output:21
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0,dl_vlan_pcp=1 actions=output:22
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=0 actions=output:23
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:3
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:3
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:3
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=MODIFIED table=0 cookie=0x5 in_port=0,dl_vlan=123 actions=output:3
event=MODIFIED table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:3
event=MODIFIED table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:3
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=DELETED reason=delete table=0 cookie=0x5 in_port=0,dl_vlan=123 actions=output:3
event=DELETED reason=delete table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:3
event=DELETED reason=delete table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:3
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=DELETED reason=delete table=0 cookie=0 in_port=0 actions=output:23
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0 actions=output:20
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:18
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:19
+ event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=3 actions=output:11
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=124 actions=output:2
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=4095 actions=output:14
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=0 actions=output:12
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=1 actions=output:13
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan_pcp=0 actions=output:21
event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan_pcp=1 actions=output:22
- event=DELETED reason=delete table=0 cookie=0 in_port=0,vlan_tci=0x0000 actions=output:11
OFPT_BARRIER_REPLY$3:
])
@@ -4704,13 +4710,13 @@ ovs-appctl -t ovs-ofctl ofctl/barrier
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
])
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log | multiline_sort], [0],
-[NXST_FLOW_MONITOR reply$3 (xid=0x0):
+[$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=1 actions=output:2
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=2 actions=output:1
OFPT_BARRIER_REPLY$3:
send: OFPT_FLOW_MOD$3: DEL actions=drop
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=DELETED reason=delete table=0 cookie=0 in_port=1 actions=output:2
event=DELETED reason=delete table=0 cookie=0 in_port=2 actions=output:1
OFPT_BARRIER_REPLY$3:
@@ -4733,8 +4739,11 @@ ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:1
ovs-ofctl -O $2 monitor br0 watch:\!own --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier
+
+# For OF(1.4+), replace INITIAL to ADDED
+sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
- [NXST_FLOW_MONITOR reply$3:
+ [$4 reply$3:
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1
OFPT_BARRIER_REPLY$3:
])
@@ -4748,14 +4757,17 @@ ovs-appctl -t ovs-ofctl ofctl/send $send_buf
ovs-appctl -t ovs-ofctl ofctl/barrier
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
])
+
+# For OF(1.4+), replace INITIAL to ADDED
+sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
-[NXST_FLOW_MONITOR reply$3 (xid=0x0):
+[$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=1 actions=output:2
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 in_port=2 actions=output:1
OFPT_BARRIER_REPLY$3:
send: OFPT_FLOW_MOD$3: DEL actions=drop
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=ABBREV xid=0x12345678
OFPT_BARRIER_REPLY$3:
])
@@ -4776,8 +4788,11 @@ ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:2
ovs-ofctl -O $2 monitor br0 watch:out_port=2 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier
+
+# For OF(1.4+), replace INITIAL to ADDED
+sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
- [NXST_FLOW_MONITOR reply$3:
+ [$4 reply$3:
event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:2
OFPT_BARRIER_REPLY$3:
])
@@ -4797,17 +4812,19 @@ ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-ofctl mod-flows br0 dl_vlan=123,actions=output:2
ovs-appctl -t ovs-ofctl ofctl/barrier
+# For OF(1.4+), replace INITIAL to ADDED
+sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
-[NXST_FLOW_MONITOR reply$3 (xid=0x0):
+[$4 reply$3 (xid=0x0):
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=output:1,output:2
OFPT_BARRIER_REPLY$3:
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1,output:2
OFPT_BARRIER_REPLY$3:
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=output:1
OFPT_BARRIER_REPLY$3:
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3 (xid=0x0):
event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:2
OFPT_BARRIER_REPLY$3:
])
@@ -4870,7 +4887,7 @@ ovs-appctl -t ovs-ofctl ofctl/unblock
# A barrier doesn't work for this purpose.
# https://www.mail-archive.com/dev@openvswitch.org/msg27013.html
# https://www.mail-archive.com/dev@openvswitch.org/msg27675.html
-OVS_WAIT_UNTIL([grep NXT_FLOW_MONITOR_RESUMED monitor.log])
+OVS_WAIT_UNTIL([grep RESUMED monitor.log])
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
@@ -4898,24 +4915,30 @@ AT_CHECK([test $adds = $deletes])
# and MODIFIED lines lines depends on hash order, that is, it varies
# as we change the hash function or change architecture. Therefore,
# we use a couple of tests below to accept both orders.
+
+# Rename all version specific strings to a generic one
+sed -i'.raw' -e 's|NXT_FLOW_MONITOR|FLOW_MONITOR|' -e 's|ONFT_FLOW_MONITOR|FLOW_MONITOR|' monitor.log
+sed -i -z 's|OFPST_FLOW_MONITOR reply$3 (xid=0x0):\n event=PAUSED|FLOW_MONITOR_PAUSED$3:|' monitor.log
+sed -i -z 's|OFPST_FLOW_MONITOR reply$3 (xid=0x0):\n event=RESUMED|FLOW_MONITOR_RESUMED$3:|' monitor.log
+
AT_CHECK([ofctl_strip < monitor.log | sed -n -e '
/reg1=0x22$/p
/cookie=0x[[23]]/p
-/NXT_FLOW_MONITOR_PAUSED$3:/p
-/NXT_FLOW_MONITOR_RESUMED$3:/p
+/FLOW_MONITOR_PAUSED$3:/p
+/FLOW_MONITOR_RESUMED$3:/p
' > monitor.log.subset])
AT_CHECK([grep -v MODIFIED monitor.log.subset], [0], [dnl
event=ADDED table=0 cookie=0x1 reg1=0x22
-NXT_FLOW_MONITOR_PAUSED$3:
+FLOW_MONITOR_PAUSED$3:
event=DELETED reason=delete table=0 cookie=0x1 reg1=0x22
event=ADDED table=0 cookie=0x3 in_port=1
-NXT_FLOW_MONITOR_RESUMED$3:
+FLOW_MONITOR_RESUMED$3:
])
AT_CHECK([grep -v ADDED monitor.log.subset], [0], [dnl
-NXT_FLOW_MONITOR_PAUSED$3:
+FLOW_MONITOR_PAUSED$3:
event=DELETED reason=delete table=0 cookie=0x1 reg1=0x22
event=MODIFIED table=0 cookie=0x2 in_port=2 actions=output:2
-NXT_FLOW_MONITOR_RESUMED$3:
+FLOW_MONITOR_RESUMED$3:
])
OVS_VSWITCHD_STOP
@@ -4932,7 +4955,7 @@ ovs-ofctl -O $2 monitor br0 watch:udp,udp_dst=8 --detach --no-chdir --pidfile >m
AT_CAPTURE_FILE([monitor.log])
# Wait till reply comes backs with OF Version
-OVS_WAIT_UNTIL([grep "NXST_FLOW_MONITOR reply$3" monitor.log])
+OVS_WAIT_UNTIL([grep "$4 reply$3" monitor.log])
ovs-appctl -t ovs-ofctl exit
# Make sure protocol type in messages from vswitchd, matches that of requested protocol
@@ -4941,17 +4964,64 @@ ovs-ofctl add-flow br0 sctp,sctp_dst=9,action=normal
OVS_WAIT_UNTIL([grep "event=ADDED " monitor.log])
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
-NXST_FLOW_MONITOR reply$3:
-NXST_FLOW_MONITOR reply$3 (xid=0x0):
+$4 reply$3:
+$4 reply$3 (xid=0x0):
event=ADDED table=0 cookie=0 sctp,tp_dst=9 actions=NORMAL
])
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP
])
-CHECK_FLOW_MONITORING([1.0], [OpenFlow10], [])
-CHECK_FLOW_MONITORING([1.1], [OpenFlow11], [ (OF1.1)])
-CHECK_FLOW_MONITORING([1.2], [OpenFlow12], [ (OF1.2)])
+CHECK_FLOW_MONITORING([1.0], [OpenFlow10], [], NXST_FLOW_MONITOR)
+CHECK_FLOW_MONITORING([1.1], [OpenFlow11], [ (OF1.1)], NXST_FLOW_MONITOR)
+CHECK_FLOW_MONITORING([1.2], [OpenFlow12], [ (OF1.2)], NXST_FLOW_MONITOR)
+CHECK_FLOW_MONITORING([1.3], [OpenFlow13], [ (OF1.3)], ONFST_FLOW_MONITOR)
+CHECK_FLOW_MONITORING([1.4], [OpenFlow14], [ (OF1.4)], OFPST_FLOW_MONITOR)
+CHECK_FLOW_MONITORING([1.5], [OpenFlow15], [ (OF1.5)], OFPST_FLOW_MONITOR)
+
+AT_SETUP([ofproto - OpenFlow14 flow monitoring with out_group])
+AT_KEYWORDS([monitor])
+OVS_VSWITCHD_START
+
+AT_CHECK([ovs-ofctl -O OpenFlow14 add-group br0 group_id=1,type=all,bucket=output:1])
+AT_CHECK([ovs-ofctl -O OpenFlow14 add-group br0 group_id=2,type=all,bucket=output:2])
+
+ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=121,actions=output:1
+ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=122,actions=group:1
+ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=123,actions=group:2
+
+# Start a monitor watching the flow table and check the initial reply.
+ovs-ofctl -OOpenFlow14 monitor br0 watch:out_group=2 --detach --no-chdir --pidfile >monitor.log 2>&1
+AT_CAPTURE_FILE([monitor.log])
+ovs-appctl -t ovs-ofctl ofctl/barrier
+AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
+[OFPST_FLOW_MONITOR reply (OF1.4):
+ event=INITIAL table=0 cookie=0 in_port=0,dl_vlan=123 actions=group:2
+OFPT_BARRIER_REPLY (OF1.4):
+])
+
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+
+# Add, modify flows and check the updates.
+ovs-ofctl -OOpenFlow14 mod-flows br0 dl_vlan=121,actions=group:2
+ovs-ofctl -OOpenFlow14 mod-flows br0 dl_vlan=122,actions=group:2
+ovs-ofctl -OOpenFlow14 mod-flows br0 dl_vlan=123,actions=group:1
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=124,actions=group:2
+
+AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
+[OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
+ event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=121 actions=group:2
+OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
+ event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=group:2
+OFPT_BARRIER_REPLY (OF1.4):
+OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
+ event=ADDED table=0 cookie=0 in_port=0,dl_vlan=124 actions=group:2
+])
+
+OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
AT_SETUP([ofproto - event filtering (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index e903ca12b..3fe6a0cc5 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -626,6 +626,9 @@ monitored.
If set, only flows that output to \fIport\fR are monitored. The
\fIport\fR may be an OpenFlow port number or keyword
(e.g. \fBLOCAL\fR).
+.IP "\fBout_group=\fIgroup\fR"
+If set, only flows that output to \fIgroup\fR number are monitored.
+This field requires OpenFlow 1.4 (-OOpenFlow14) or later.
.IP "\fIfield\fB=\fIvalue\fR"
Monitors only flows that have \fIfield\fR specified as the given
\fIvalue\fR. Any syntax valid for matching on \fBdump\-flows\fR may
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index b6d103ffd..fe9114580 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2313,6 +2313,12 @@ ofctl_monitor(struct ovs_cmdl_context *ctx)
msg = ofpbuf_new(0);
ofputil_append_flow_monitor_request(&fmr, msg, protocol);
+
+ if (verbosity) {
+ ofpmsg_update_length(msg);
+ ofp_print(stdout, msg->data, msg->size, NULL,
+ NULL, verbosity + 2);
+ }
dump_transaction(vconn, msg);
fflush(stdout);
} else if (!strcmp(arg, "resume")) {