Message ID | 20210730023620.1942-1-vdasari@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | None | expand |
Hi Ben/Ashish, When you get a chance, Can you please take a look at my code? -Vasu *Vasu Dasari* On Thu, Jul 29, 2021 at 10:36 PM Vasu Dasari <vdasari@gmail.com> wrote: > Extended OpenFlow monitoring support > * OpenFlow 1.3 with ONF extensions > * OpenFlow 1.4+ as defined in OpenFlow specification 1.4+. > > ONF extensions are similar to Nicira extensions except for > onf_flow_monitor_request{} > where out_port is defined as 32-bit number OF(1.1) number, oxm match > formats are > used in update and request messages. > > Flow monitoring support in 1.4+ is slightly different from Nicira and ONF > extensions. > * More flow monitoring flags are defined. > * Monitor add/modify/delete command is intruduced in flow_monitor > request message. > * Addition of out_group as part of flow_monitor request message > > Description of changes: > 1. Generate ofp-msgs.inc to be able to support 1.3, 1.4+ flow Monitoring > messages. > include/openvswitch/ofp-msgs.h > > 2. Modify openflow header files with protocol specific headers. > include/openflow/openflow-1.3.h > include/openflow/openflow-1.4.h > > 3. Modify OvS abstraction of openflow headers. ofp-monitor.h leverages > enums > from on nicira extensions for creating protocol abstraction headers. > OF(1.4+) > enums are superset of nicira extensions. > include/openvswitch/ofp-monitor.h > > 4. Changes to these files reflect encoding and decoding of new protocol > messages. > lib/ofp-monitor.c > > 5. Changes to mmodules using ofp-monitor APIs. Most of the changes here > are to > migrate enums from nicira to OF 1.4+ versions. > ofproto/connmgr.c > ofproto/connmgr.h > ofproto/ofproto-provider.h > ofproto/ofproto.c > > 6. Extended protocol decoding tests to verify all protocol versions > FLOW_MONITOR_CANCEL > FLOW_MONITOR_PAUSED > FLOW_MONITOR_RESUMED > FLOW_MONITOR request > FLOW_MONITOR reply > tests/ofp-print.at > > 7. Modify flow monitoring tests to be able executed by all protocol > versions. > tests/ofproto.at > > 7. Modified documentation highlighting the change > utilities/ovs-ofctl.8.in > NEWS > > Signed-off-by: Vasu Dasari <vdasari@gmail.com> > Reported-at: > https://mail.openvswitch.org/pipermail/ovs-dev/2021-June/383915.html > --- > v1: > - Fixed 0-day Robot errors > > --- > NEWS | 6 +- > include/openflow/openflow-1.3.h | 89 ++++ > include/openflow/openflow-1.4.h | 93 +++- > include/openvswitch/ofp-monitor.h | 9 +- > include/openvswitch/ofp-msgs.h | 39 +- > lib/ofp-monitor.c | 844 ++++++++++++++++++++++++------ > lib/ofp-print.c | 24 +- > ofproto/connmgr.c | 47 +- > ofproto/connmgr.h | 6 +- > ofproto/ofproto-provider.h | 4 +- > ofproto/ofproto.c | 89 +++- > tests/ofp-print.at | 122 ++++- > tests/ofproto.at | 176 +++++-- > utilities/ovs-ofctl.8.in | 3 + > utilities/ovs-ofctl.c | 6 + > 15 files changed, 1265 insertions(+), 292 deletions(-) > > diff --git a/NEWS b/NEWS > index 02884b774..47ad9de2a 100644 > --- a/NEWS > +++ b/NEWS > @@ -25,8 +25,10 @@ v2.16.0 - xx xxx xxxx > - In ovs-vsctl and vtep-ctl, the "find" command now accept new > operators {in} and {not-in}. > - OpenFlow: > - * Extend 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 > - Userspace datapath: > * Auto load balancing of PMDs now partially supports cross-NUMA > polling > cases, e.g if all PMD threads are running on the same NUMA node. > diff --git a/include/openflow/openflow-1.3.h > b/include/openflow/openflow-1.3.h > index c48a8ea7f..1a818dbb4 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..8e6a163fd 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 c14834f84..325f45966 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 57c7d17cb..373526738 100644 > --- a/ofproto/ofproto-provider.h > +++ b/ofproto/ofproto-provider.h > @@ -419,7 +419,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); > > @@ -480,6 +480,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 11aadbf20..980d4d53b 100644 > --- a/ofproto/ofproto.c > +++ b/ofproto/ofproto.c > @@ -3157,7 +3157,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) > { > @@ -5215,7 +5215,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); > > @@ -5630,8 +5630,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); > @@ -5641,7 +5641,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, > @@ -5650,7 +5650,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); > @@ -5931,7 +5931,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); > > @@ -6337,7 +6337,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) > @@ -6346,8 +6346,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; > @@ -6358,7 +6359,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; > > @@ -6377,7 +6378,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, > @@ -6391,7 +6392,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; > @@ -6401,11 +6402,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; > } > @@ -6414,13 +6419,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 > @@ -6449,7 +6454,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); > } > } > @@ -6512,16 +6517,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 899c0be55..3502454b9 100644 > --- a/tests/ofproto.at > +++ b/tests/ofproto.at > @@ -4592,8 +4592,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: > ]) > @@ -4607,7 +4610,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 > @@ -4625,71 +4628,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: > ]) > > @@ -4703,13 +4709,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: > @@ -4732,8 +4738,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: > ]) > @@ -4747,14 +4756,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: > ]) > @@ -4775,8 +4787,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: > ]) > @@ -4796,17 +4811,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: > ]) > @@ -4869,7 +4886,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]) > > @@ -4897,24 +4914,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 > @@ -4931,7 +4954,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 > @@ -4940,17 +4963,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 2017c6eba..d9336a43b 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 614b73006..5e6823240 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")) { > -- > 2.29.2 > >
I will take a look. Thanks, Ashish On Tue, Aug 24, 2021 at 9:29 AM Vasu Dasari <vdasari@gmail.com> wrote: > Hi Ben/Ashish, > > When you get a chance, Can you please take a look at my code? > > -Vasu > > *Vasu Dasari* > > > On Thu, Jul 29, 2021 at 10:36 PM Vasu Dasari <vdasari@gmail.com> wrote: > >> Extended OpenFlow monitoring support >> * OpenFlow 1.3 with ONF extensions >> * OpenFlow 1.4+ as defined in OpenFlow specification 1.4+. >> >> ONF extensions are similar to Nicira extensions except for >> onf_flow_monitor_request{} >> where out_port is defined as 32-bit number OF(1.1) number, oxm match >> formats are >> used in update and request messages. >> >> Flow monitoring support in 1.4+ is slightly different from Nicira and ONF >> extensions. >> * More flow monitoring flags are defined. >> * Monitor add/modify/delete command is intruduced in flow_monitor >> request message. >> * Addition of out_group as part of flow_monitor request message >> >> Description of changes: >> 1. Generate ofp-msgs.inc to be able to support 1.3, 1.4+ flow Monitoring >> messages. >> include/openvswitch/ofp-msgs.h >> >> 2. Modify openflow header files with protocol specific headers. >> include/openflow/openflow-1.3.h >> include/openflow/openflow-1.4.h >> >> 3. Modify OvS abstraction of openflow headers. ofp-monitor.h leverages >> enums >> from on nicira extensions for creating protocol abstraction headers. >> OF(1.4+) >> enums are superset of nicira extensions. >> include/openvswitch/ofp-monitor.h >> >> 4. Changes to these files reflect encoding and decoding of new protocol >> messages. >> lib/ofp-monitor.c >> >> 5. Changes to mmodules using ofp-monitor APIs. Most of the changes here >> are to >> migrate enums from nicira to OF 1.4+ versions. >> ofproto/connmgr.c >> ofproto/connmgr.h >> ofproto/ofproto-provider.h >> ofproto/ofproto.c >> >> 6. Extended protocol decoding tests to verify all protocol versions >> FLOW_MONITOR_CANCEL >> FLOW_MONITOR_PAUSED >> FLOW_MONITOR_RESUMED >> FLOW_MONITOR request >> FLOW_MONITOR reply >> tests/ofp-print.at >> >> 7. Modify flow monitoring tests to be able executed by all protocol >> versions. >> tests/ofproto.at >> >> 7. Modified documentation highlighting the change >> utilities/ovs-ofctl.8.in >> NEWS >> >> Signed-off-by: Vasu Dasari <vdasari@gmail.com> >> Reported-at: >> https://mail.openvswitch.org/pipermail/ovs-dev/2021-June/383915.html >> --- >> v1: >> - Fixed 0-day Robot errors >> >> --- >> NEWS | 6 +- >> include/openflow/openflow-1.3.h | 89 ++++ >> include/openflow/openflow-1.4.h | 93 +++- >> include/openvswitch/ofp-monitor.h | 9 +- >> include/openvswitch/ofp-msgs.h | 39 +- >> lib/ofp-monitor.c | 844 ++++++++++++++++++++++++------ >> lib/ofp-print.c | 24 +- >> ofproto/connmgr.c | 47 +- >> ofproto/connmgr.h | 6 +- >> ofproto/ofproto-provider.h | 4 +- >> ofproto/ofproto.c | 89 +++- >> tests/ofp-print.at | 122 ++++- >> tests/ofproto.at | 176 +++++-- >> utilities/ovs-ofctl.8.in | 3 + >> utilities/ovs-ofctl.c | 6 + >> 15 files changed, 1265 insertions(+), 292 deletions(-) >> >> diff --git a/NEWS b/NEWS >> index 02884b774..47ad9de2a 100644 >> --- a/NEWS >> +++ b/NEWS >> @@ -25,8 +25,10 @@ v2.16.0 - xx xxx xxxx >> - In ovs-vsctl and vtep-ctl, the "find" command now accept new >> operators {in} and {not-in}. >> - OpenFlow: >> - * Extend 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 >> - Userspace datapath: >> * Auto load balancing of PMDs now partially supports cross-NUMA >> polling >> cases, e.g if all PMD threads are running on the same NUMA node. >> diff --git a/include/openflow/openflow-1.3.h >> b/include/openflow/openflow-1.3.h >> index c48a8ea7f..1a818dbb4 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..8e6a163fd 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 c14834f84..325f45966 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 57c7d17cb..373526738 100644 >> --- a/ofproto/ofproto-provider.h >> +++ b/ofproto/ofproto-provider.h >> @@ -419,7 +419,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); >> >> @@ -480,6 +480,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 11aadbf20..980d4d53b 100644 >> --- a/ofproto/ofproto.c >> +++ b/ofproto/ofproto.c >> @@ -3157,7 +3157,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) >> { >> @@ -5215,7 +5215,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); >> >> @@ -5630,8 +5630,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); >> @@ -5641,7 +5641,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, >> @@ -5650,7 +5650,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); >> @@ -5931,7 +5931,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); >> >> @@ -6337,7 +6337,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) >> @@ -6346,8 +6346,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; >> @@ -6358,7 +6359,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; >> >> @@ -6377,7 +6378,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, >> @@ -6391,7 +6392,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; >> @@ -6401,11 +6402,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; >> } >> @@ -6414,13 +6419,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 >> @@ -6449,7 +6454,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); >> } >> } >> @@ -6512,16 +6517,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 899c0be55..3502454b9 100644 >> --- a/tests/ofproto.at >> +++ b/tests/ofproto.at >> @@ -4592,8 +4592,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: >> ]) >> @@ -4607,7 +4610,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 >> @@ -4625,71 +4628,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: >> ]) >> >> @@ -4703,13 +4709,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: >> @@ -4732,8 +4738,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: >> ]) >> @@ -4747,14 +4756,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: >> ]) >> @@ -4775,8 +4787,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: >> ]) >> @@ -4796,17 +4811,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: >> ]) >> @@ -4869,7 +4886,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]) >> >> @@ -4897,24 +4914,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 >> @@ -4931,7 +4954,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 >> @@ -4940,17 +4963,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 2017c6eba..d9336a43b 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 614b73006..5e6823240 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")) { >> -- >> 2.29.2 >> >>
Great, thanks! *Vasu Dasari* On Tue, Aug 24, 2021 at 4:11 PM Ashish Varma <ashishvarma.ovs@gmail.com> wrote: > I will take a look. > > Thanks, > Ashish > > On Tue, Aug 24, 2021 at 9:29 AM Vasu Dasari <vdasari@gmail.com> wrote: > >> Hi Ben/Ashish, >> >> When you get a chance, Can you please take a look at my code? >> >> -Vasu >> >> *Vasu Dasari* >> >> >> On Thu, Jul 29, 2021 at 10:36 PM Vasu Dasari <vdasari@gmail.com> wrote: >> >>> Extended OpenFlow monitoring support >>> * OpenFlow 1.3 with ONF extensions >>> * OpenFlow 1.4+ as defined in OpenFlow specification 1.4+. >>> >>> ONF extensions are similar to Nicira extensions except for >>> onf_flow_monitor_request{} >>> where out_port is defined as 32-bit number OF(1.1) number, oxm match >>> formats are >>> used in update and request messages. >>> >>> Flow monitoring support in 1.4+ is slightly different from Nicira and ONF >>> extensions. >>> * More flow monitoring flags are defined. >>> * Monitor add/modify/delete command is intruduced in flow_monitor >>> request message. >>> * Addition of out_group as part of flow_monitor request message >>> >>> Description of changes: >>> 1. Generate ofp-msgs.inc to be able to support 1.3, 1.4+ flow Monitoring >>> messages. >>> include/openvswitch/ofp-msgs.h >>> >>> 2. Modify openflow header files with protocol specific headers. >>> include/openflow/openflow-1.3.h >>> include/openflow/openflow-1.4.h >>> >>> 3. Modify OvS abstraction of openflow headers. ofp-monitor.h leverages >>> enums >>> from on nicira extensions for creating protocol abstraction headers. >>> OF(1.4+) >>> enums are superset of nicira extensions. >>> include/openvswitch/ofp-monitor.h >>> >>> 4. Changes to these files reflect encoding and decoding of new protocol >>> messages. >>> lib/ofp-monitor.c >>> >>> 5. Changes to mmodules using ofp-monitor APIs. Most of the changes here >>> are to >>> migrate enums from nicira to OF 1.4+ versions. >>> ofproto/connmgr.c >>> ofproto/connmgr.h >>> ofproto/ofproto-provider.h >>> ofproto/ofproto.c >>> >>> 6. Extended protocol decoding tests to verify all protocol versions >>> FLOW_MONITOR_CANCEL >>> FLOW_MONITOR_PAUSED >>> FLOW_MONITOR_RESUMED >>> FLOW_MONITOR request >>> FLOW_MONITOR reply >>> tests/ofp-print.at >>> >>> 7. Modify flow monitoring tests to be able executed by all protocol >>> versions. >>> tests/ofproto.at >>> >>> 7. Modified documentation highlighting the change >>> utilities/ovs-ofctl.8.in >>> NEWS >>> >>> Signed-off-by: Vasu Dasari <vdasari@gmail.com> >>> Reported-at: >>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-June/383915.html >>> --- >>> v1: >>> - Fixed 0-day Robot errors >>> >>> --- >>> NEWS | 6 +- >>> include/openflow/openflow-1.3.h | 89 ++++ >>> include/openflow/openflow-1.4.h | 93 +++- >>> include/openvswitch/ofp-monitor.h | 9 +- >>> include/openvswitch/ofp-msgs.h | 39 +- >>> lib/ofp-monitor.c | 844 ++++++++++++++++++++++++------ >>> lib/ofp-print.c | 24 +- >>> ofproto/connmgr.c | 47 +- >>> ofproto/connmgr.h | 6 +- >>> ofproto/ofproto-provider.h | 4 +- >>> ofproto/ofproto.c | 89 +++- >>> tests/ofp-print.at | 122 ++++- >>> tests/ofproto.at | 176 +++++-- >>> utilities/ovs-ofctl.8.in | 3 + >>> utilities/ovs-ofctl.c | 6 + >>> 15 files changed, 1265 insertions(+), 292 deletions(-) >>> >>> diff --git a/NEWS b/NEWS >>> index 02884b774..47ad9de2a 100644 >>> --- a/NEWS >>> +++ b/NEWS >>> @@ -25,8 +25,10 @@ v2.16.0 - xx xxx xxxx >>> - In ovs-vsctl and vtep-ctl, the "find" command now accept new >>> operators {in} and {not-in}. >>> - OpenFlow: >>> - * Extend 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 >>> - Userspace datapath: >>> * Auto load balancing of PMDs now partially supports cross-NUMA >>> polling >>> cases, e.g if all PMD threads are running on the same NUMA node. >>> diff --git a/include/openflow/openflow-1.3.h >>> b/include/openflow/openflow-1.3.h >>> index c48a8ea7f..1a818dbb4 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..8e6a163fd 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 c14834f84..325f45966 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 57c7d17cb..373526738 100644 >>> --- a/ofproto/ofproto-provider.h >>> +++ b/ofproto/ofproto-provider.h >>> @@ -419,7 +419,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); >>> >>> @@ -480,6 +480,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 11aadbf20..980d4d53b 100644 >>> --- a/ofproto/ofproto.c >>> +++ b/ofproto/ofproto.c >>> @@ -3157,7 +3157,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) >>> { >>> @@ -5215,7 +5215,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); >>> >>> @@ -5630,8 +5630,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); >>> @@ -5641,7 +5641,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, >>> @@ -5650,7 +5650,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); >>> @@ -5931,7 +5931,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); >>> >>> @@ -6337,7 +6337,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) >>> @@ -6346,8 +6346,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; >>> @@ -6358,7 +6359,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; >>> >>> @@ -6377,7 +6378,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, >>> @@ -6391,7 +6392,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; >>> @@ -6401,11 +6402,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; >>> } >>> @@ -6414,13 +6419,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 >>> @@ -6449,7 +6454,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); >>> } >>> } >>> @@ -6512,16 +6517,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 899c0be55..3502454b9 100644 >>> --- a/tests/ofproto.at >>> +++ b/tests/ofproto.at >>> @@ -4592,8 +4592,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: >>> ]) >>> @@ -4607,7 +4610,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 >>> @@ -4625,71 +4628,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: >>> ]) >>> >>> @@ -4703,13 +4709,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: >>> @@ -4732,8 +4738,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: >>> ]) >>> @@ -4747,14 +4756,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: >>> ]) >>> @@ -4775,8 +4787,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: >>> ]) >>> @@ -4796,17 +4811,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: >>> ]) >>> @@ -4869,7 +4886,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]) >>> >>> @@ -4897,24 +4914,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 >>> @@ -4931,7 +4954,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 >>> @@ -4940,17 +4963,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 2017c6eba..d9336a43b 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 614b73006..5e6823240 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")) { >>> -- >>> 2.29.2 >>> >>>
diff --git a/NEWS b/NEWS index 02884b774..47ad9de2a 100644 --- a/NEWS +++ b/NEWS @@ -25,8 +25,10 @@ v2.16.0 - xx xxx xxxx - In ovs-vsctl and vtep-ctl, the "find" command now accept new operators {in} and {not-in}. - OpenFlow: - * Extend 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 - Userspace datapath: * Auto load balancing of PMDs now partially supports cross-NUMA polling cases, e.g if all PMD threads are running on the same NUMA node. diff --git a/include/openflow/openflow-1.3.h b/include/openflow/openflow-1.3.h index c48a8ea7f..1a818dbb4 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..8e6a163fd 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 c14834f84..325f45966 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 57c7d17cb..373526738 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -419,7 +419,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); @@ -480,6 +480,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 11aadbf20..980d4d53b 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -3157,7 +3157,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) { @@ -5215,7 +5215,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); @@ -5630,8 +5630,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); @@ -5641,7 +5641,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, @@ -5650,7 +5650,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); @@ -5931,7 +5931,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); @@ -6337,7 +6337,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) @@ -6346,8 +6346,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; @@ -6358,7 +6359,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; @@ -6377,7 +6378,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, @@ -6391,7 +6392,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; @@ -6401,11 +6402,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; } @@ -6414,13 +6419,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 @@ -6449,7 +6454,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); } } @@ -6512,16 +6517,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 899c0be55..3502454b9 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -4592,8 +4592,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: ]) @@ -4607,7 +4610,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 @@ -4625,71 +4628,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: ]) @@ -4703,13 +4709,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: @@ -4732,8 +4738,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: ]) @@ -4747,14 +4756,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: ]) @@ -4775,8 +4787,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: ]) @@ -4796,17 +4811,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: ]) @@ -4869,7 +4886,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]) @@ -4897,24 +4914,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 @@ -4931,7 +4954,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 @@ -4940,17 +4963,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 2017c6eba..d9336a43b 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 614b73006..5e6823240 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")) {
Extended OpenFlow monitoring support * OpenFlow 1.3 with ONF extensions * OpenFlow 1.4+ as defined in OpenFlow specification 1.4+. ONF extensions are similar to Nicira extensions except for onf_flow_monitor_request{} where out_port is defined as 32-bit number OF(1.1) number, oxm match formats are used in update and request messages. Flow monitoring support in 1.4+ is slightly different from Nicira and ONF extensions. * More flow monitoring flags are defined. * Monitor add/modify/delete command is intruduced in flow_monitor request message. * Addition of out_group as part of flow_monitor request message Description of changes: 1. Generate ofp-msgs.inc to be able to support 1.3, 1.4+ flow Monitoring messages. include/openvswitch/ofp-msgs.h 2. Modify openflow header files with protocol specific headers. include/openflow/openflow-1.3.h include/openflow/openflow-1.4.h 3. Modify OvS abstraction of openflow headers. ofp-monitor.h leverages enums from on nicira extensions for creating protocol abstraction headers. OF(1.4+) enums are superset of nicira extensions. include/openvswitch/ofp-monitor.h 4. Changes to these files reflect encoding and decoding of new protocol messages. lib/ofp-monitor.c 5. Changes to mmodules using ofp-monitor APIs. Most of the changes here are to migrate enums from nicira to OF 1.4+ versions. ofproto/connmgr.c ofproto/connmgr.h ofproto/ofproto-provider.h ofproto/ofproto.c 6. Extended protocol decoding tests to verify all protocol versions FLOW_MONITOR_CANCEL FLOW_MONITOR_PAUSED FLOW_MONITOR_RESUMED FLOW_MONITOR request FLOW_MONITOR reply tests/ofp-print.at 7. Modify flow monitoring tests to be able executed by all protocol versions. tests/ofproto.at 7. Modified documentation highlighting the change utilities/ovs-ofctl.8.in NEWS Signed-off-by: Vasu Dasari <vdasari@gmail.com> Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2021-June/383915.html --- v1: - Fixed 0-day Robot errors --- NEWS | 6 +- include/openflow/openflow-1.3.h | 89 ++++ include/openflow/openflow-1.4.h | 93 +++- include/openvswitch/ofp-monitor.h | 9 +- include/openvswitch/ofp-msgs.h | 39 +- lib/ofp-monitor.c | 844 ++++++++++++++++++++++++------ lib/ofp-print.c | 24 +- ofproto/connmgr.c | 47 +- ofproto/connmgr.h | 6 +- ofproto/ofproto-provider.h | 4 +- ofproto/ofproto.c | 89 +++- tests/ofp-print.at | 122 ++++- tests/ofproto.at | 176 +++++-- utilities/ovs-ofctl.8.in | 3 + utilities/ovs-ofctl.c | 6 + 15 files changed, 1265 insertions(+), 292 deletions(-)