diff options
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | include/openflow/openflow-1.3.h | 89 | ||||
-rw-r--r-- | include/openflow/openflow-1.4.h | 93 | ||||
-rw-r--r-- | include/openvswitch/ofp-monitor.h | 9 | ||||
-rw-r--r-- | include/openvswitch/ofp-msgs.h | 39 | ||||
-rw-r--r-- | lib/ofp-monitor.c | 844 | ||||
-rw-r--r-- | lib/ofp-print.c | 24 | ||||
-rw-r--r-- | ofproto/connmgr.c | 47 | ||||
-rw-r--r-- | ofproto/connmgr.h | 6 | ||||
-rw-r--r-- | ofproto/ofproto-provider.h | 4 | ||||
-rw-r--r-- | ofproto/ofproto.c | 89 | ||||
-rw-r--r-- | tests/ofp-print.at | 122 | ||||
-rw-r--r-- | tests/ofproto.at | 176 | ||||
-rw-r--r-- | utilities/ovs-ofctl.8.in | 3 | ||||
-rw-r--r-- | utilities/ovs-ofctl.c | 6 |
15 files changed, 1265 insertions, 292 deletions
@@ -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")) { |