+ 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);
+
+ error = nx_pull_match(msg, match_len, update->match, 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,
+ ofpacts);
+ if (error) {
+ return error;
+ }
+
+ update->ofpacts = ofpbuf_data(ofpacts);
+ update->ofpacts_len = ofpbuf_size(ofpacts);
+ return 0;
+ } else {
+ VLOG_WARN_RL(&bad_ofmsg_rl,
+ "NXST_FLOW_MONITOR reply has bad event %"PRIu16,
+ ntohs(nfuh->event));
+ return OFPERR_NXBRC_FM_BAD_EVENT;
+ }
+
+bad_len:
+ VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has %"PRIu32" "
+ "leftover bytes at end", ofpbuf_size(msg));
+ 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);
+
+ return ntohl(cancel->id);
+}
+
+struct ofpbuf *
+ofputil_encode_flow_monitor_cancel(uint32_t id)
+{
+ struct nx_flow_monitor_cancel *nfmc;
+ struct ofpbuf *msg;
+
+ msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION, 0);
+ nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc);
+ nfmc->id = htonl(id);
+ return msg;
+}
+
+void
+ofputil_start_flow_update(struct list *replies)
+{
+ struct ofpbuf *msg;
+
+ msg = ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION,
+ htonl(0), 1024);
+
+ list_init(replies);
+ list_push_back(replies, &msg->list_node);
+}
+
+void
+ofputil_append_flow_update(const struct ofputil_flow_update *update,
+ struct list *replies)
+{
+ struct nx_flow_update_header *nfuh;
+ struct ofpbuf *msg;
+ size_t start_ofs;
+ enum ofp_version version;
+
+ msg = ofpbuf_from_list(list_back(replies));
+ start_ofs = ofpbuf_size(msg);
+ version = ((struct ofp_header *)msg->frame)->version;
+
+ if (update->event == NXFME_ABBREV) {
+ struct nx_flow_update_abbrev *nfua;
+
+ 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);
+ 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(ofpbuf_size(msg) - start_ofs);
+ nfuh->event = htons(update->event);
+
+ ofpmp_postappend(replies, start_ofs);
+}
+\f
+struct ofpbuf *
+ofputil_encode_packet_out(const struct ofputil_packet_out *po,
+ enum ofputil_protocol protocol)
+{
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
+ struct ofpbuf *msg;
+ size_t size;
+
+ size = po->ofpacts_len;
+ if (po->buffer_id == UINT32_MAX) {
+ size += po->packet_len;
+ }
+
+ switch (ofp_version) {
+ case OFP10_VERSION: {
+ struct ofp10_packet_out *opo;
+ size_t actions_ofs;
+
+ msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
+ ofpbuf_put_zeros(msg, sizeof *opo);
+ actions_ofs = ofpbuf_size(msg);
+ ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
+ ofp_version);
+
+ opo = ofpbuf_l3(msg);
+ opo->buffer_id = htonl(po->buffer_id);
+ opo->in_port = htons(ofp_to_u16(po->in_port));
+ opo->actions_len = htons(ofpbuf_size(msg) - actions_ofs);
+ break;
+ }
+
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION:
+ case OFP14_VERSION:{
+ struct ofp11_packet_out *opo;
+ size_t len;
+
+ msg = ofpraw_alloc(OFPRAW_OFPT11_PACKET_OUT, ofp_version, size);
+ ofpbuf_put_zeros(msg, sizeof *opo);
+ len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
+ ofp_version);
+ opo = ofpbuf_l3(msg);
+ opo->buffer_id = htonl(po->buffer_id);
+ opo->in_port = ofputil_port_to_ofp11(po->in_port);
+ opo->actions_len = htons(len);
+ break;
+ }
+
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ if (po->buffer_id == UINT32_MAX) {
+ ofpbuf_put(msg, po->packet, po->packet_len);
+ }
+
+ ofpmsg_update_length(msg);
+
+ return msg;
+}
+\f
+/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
+struct ofpbuf *
+make_echo_request(enum ofp_version ofp_version)
+{
+ return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, ofp_version,
+ htonl(0), 0);
+}
+
+/* Creates and returns an OFPT_ECHO_REPLY message matching the
+ * OFPT_ECHO_REQUEST message in 'rq'. */
+struct ofpbuf *
+make_echo_reply(const struct ofp_header *rq)
+{
+ struct ofpbuf rq_buf;
+ struct ofpbuf *reply;
+
+ ofpbuf_use_const(&rq_buf, rq, ntohs(rq->length));
+ ofpraw_pull_assert(&rq_buf);
+
+ reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, rq, ofpbuf_size(&rq_buf));
+ ofpbuf_put(reply, ofpbuf_data(&rq_buf), ofpbuf_size(&rq_buf));
+ return reply;
+}
+
+struct ofpbuf *
+ofputil_encode_barrier_request(enum ofp_version ofp_version)
+{
+ enum ofpraw type;
+
+ switch (ofp_version) {
+ case OFP14_VERSION:
+ case OFP13_VERSION:
+ case OFP12_VERSION:
+ case OFP11_VERSION:
+ type = OFPRAW_OFPT11_BARRIER_REQUEST;
+ break;
+
+ case OFP10_VERSION:
+ type = OFPRAW_OFPT10_BARRIER_REQUEST;
+ break;
+
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ return ofpraw_alloc(type, ofp_version, 0);
+}
+
+const char *
+ofputil_frag_handling_to_string(enum ofp_config_flags flags)
+{
+ switch (flags & OFPC_FRAG_MASK) {
+ case OFPC_FRAG_NORMAL: return "normal";
+ case OFPC_FRAG_DROP: return "drop";
+ case OFPC_FRAG_REASM: return "reassemble";
+ case OFPC_FRAG_NX_MATCH: return "nx-match";
+ }
+
+ OVS_NOT_REACHED();
+}
+
+bool
+ofputil_frag_handling_from_string(const char *s, enum ofp_config_flags *flags)
+{
+ if (!strcasecmp(s, "normal")) {
+ *flags = OFPC_FRAG_NORMAL;
+ } else if (!strcasecmp(s, "drop")) {
+ *flags = OFPC_FRAG_DROP;
+ } else if (!strcasecmp(s, "reassemble")) {
+ *flags = OFPC_FRAG_REASM;
+ } else if (!strcasecmp(s, "nx-match")) {
+ *flags = OFPC_FRAG_NX_MATCH;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+/* Converts the OpenFlow 1.1+ port number 'ofp11_port' into an OpenFlow 1.0
+ * port number and stores the latter in '*ofp10_port', for the purpose of
+ * decoding OpenFlow 1.1+ protocol messages. Returns 0 if successful,
+ * otherwise an OFPERR_* number. On error, stores OFPP_NONE in '*ofp10_port'.
+ *
+ * See the definition of OFP11_MAX for an explanation of the mapping. */
+enum ofperr
+ofputil_port_from_ofp11(ovs_be32 ofp11_port, ofp_port_t *ofp10_port)
+{
+ uint32_t ofp11_port_h = ntohl(ofp11_port);
+
+ if (ofp11_port_h < ofp_to_u16(OFPP_MAX)) {
+ *ofp10_port = u16_to_ofp(ofp11_port_h);
+ return 0;
+ } else if (ofp11_port_h >= ofp11_to_u32(OFPP11_MAX)) {
+ *ofp10_port = u16_to_ofp(ofp11_port_h - OFPP11_OFFSET);
+ return 0;
+ } else {
+ *ofp10_port = OFPP_NONE;
+ VLOG_WARN_RL(&bad_ofmsg_rl, "port %"PRIu32" is outside the supported "
+ "range 0 through %d or 0x%"PRIx32" through 0x%"PRIx32,
+ ofp11_port_h, ofp_to_u16(OFPP_MAX) - 1,
+ ofp11_to_u32(OFPP11_MAX), UINT32_MAX);
+ return OFPERR_OFPBAC_BAD_OUT_PORT;
+ }
+}
+
+/* Returns the OpenFlow 1.1+ port number equivalent to the OpenFlow 1.0 port
+ * number 'ofp10_port', for encoding OpenFlow 1.1+ protocol messages.
+ *
+ * See the definition of OFP11_MAX for an explanation of the mapping. */
+ovs_be32
+ofputil_port_to_ofp11(ofp_port_t ofp10_port)
+{
+ return htonl(ofp_to_u16(ofp10_port) < ofp_to_u16(OFPP_MAX)
+ ? ofp_to_u16(ofp10_port)
+ : ofp_to_u16(ofp10_port) + OFPP11_OFFSET);
+}
+
+#define OFPUTIL_NAMED_PORTS \
+ OFPUTIL_NAMED_PORT(IN_PORT) \
+ OFPUTIL_NAMED_PORT(TABLE) \
+ OFPUTIL_NAMED_PORT(NORMAL) \
+ OFPUTIL_NAMED_PORT(FLOOD) \
+ OFPUTIL_NAMED_PORT(ALL) \
+ OFPUTIL_NAMED_PORT(CONTROLLER) \
+ OFPUTIL_NAMED_PORT(LOCAL) \
+ OFPUTIL_NAMED_PORT(ANY)
+
+/* For backwards compatibility, so that "none" is recognized as OFPP_ANY */
+#define OFPUTIL_NAMED_PORTS_WITH_NONE \
+ OFPUTIL_NAMED_PORTS \
+ OFPUTIL_NAMED_PORT(NONE)
+
+/* Stores the port number represented by 's' into '*portp'. 's' may be an
+ * integer or, for reserved ports, the standard OpenFlow name for the port
+ * (e.g. "LOCAL").
+ *
+ * Returns true if successful, false if 's' is not a valid OpenFlow port number
+ * or name. The caller should issue an error message in this case, because
+ * this function usually does not. (This gives the caller an opportunity to
+ * look up the port name another way, e.g. by contacting the switch and listing
+ * the names of all its ports).
+ *
+ * This function accepts OpenFlow 1.0 port numbers. It also accepts a subset
+ * of OpenFlow 1.1+ port numbers, mapping those port numbers into the 16-bit
+ * range as described in include/openflow/openflow-1.1.h. */
+bool
+ofputil_port_from_string(const char *s, ofp_port_t *portp)
+{
+ unsigned int port32; /* int is at least 32 bits wide. */
+
+ if (*s == '-') {
+ VLOG_WARN("Negative value %s is not a valid port number.", s);
+ return false;
+ }
+ *portp = 0;
+ if (str_to_uint(s, 10, &port32)) {
+ if (port32 < ofp_to_u16(OFPP_MAX)) {
+ /* Pass. */
+ } else if (port32 < ofp_to_u16(OFPP_FIRST_RESV)) {
+ VLOG_WARN("port %u is a reserved OF1.0 port number that will "
+ "be translated to %u when talking to an OF1.1 or "
+ "later controller", port32, port32 + OFPP11_OFFSET);
+ } else if (port32 <= ofp_to_u16(OFPP_LAST_RESV)) {
+ char name[OFP_MAX_PORT_NAME_LEN];
+
+ ofputil_port_to_string(u16_to_ofp(port32), name, sizeof name);
+ VLOG_WARN_ONCE("referring to port %s as %"PRIu32" is deprecated "
+ "for compatibility with OpenFlow 1.1 and later",
+ name, port32);
+ } else if (port32 < ofp11_to_u32(OFPP11_MAX)) {
+ VLOG_WARN("port %u is outside the supported range 0 through "
+ "%"PRIx16" or 0x%x through 0x%"PRIx32, port32,
+ UINT16_MAX, ofp11_to_u32(OFPP11_MAX), UINT32_MAX);
+ return false;
+ } else {
+ port32 -= OFPP11_OFFSET;
+ }
+
+ *portp = u16_to_ofp(port32);
+ return true;
+ } else {
+ struct pair {
+ const char *name;
+ ofp_port_t value;
+ };
+ static const struct pair pairs[] = {
+#define OFPUTIL_NAMED_PORT(NAME) {#NAME, OFPP_##NAME},
+ OFPUTIL_NAMED_PORTS_WITH_NONE
+#undef OFPUTIL_NAMED_PORT
+ };
+ const struct pair *p;
+
+ for (p = pairs; p < &pairs[ARRAY_SIZE(pairs)]; p++) {
+ if (!strcasecmp(s, p->name)) {
+ *portp = p->value;
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/* Appends to 's' a string representation of the OpenFlow port number 'port'.
+ * Most ports' string representation is just the port number, but for special
+ * ports, e.g. OFPP_LOCAL, it is the name, e.g. "LOCAL". */
+void
+ofputil_format_port(ofp_port_t port, struct ds *s)
+{
+ char name[OFP_MAX_PORT_NAME_LEN];
+
+ ofputil_port_to_string(port, name, sizeof name);
+ ds_put_cstr(s, name);
+}
+
+/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
+ * representation of OpenFlow port number 'port'. Most ports are represented
+ * as just the port number, but special ports, e.g. OFPP_LOCAL, are represented
+ * by name, e.g. "LOCAL". */
+void
+ofputil_port_to_string(ofp_port_t port,
+ char namebuf[OFP_MAX_PORT_NAME_LEN], size_t bufsize)
+{
+ switch (port) {
+#define OFPUTIL_NAMED_PORT(NAME) \
+ case OFPP_##NAME: \
+ ovs_strlcpy(namebuf, #NAME, bufsize); \
+ break;
+ OFPUTIL_NAMED_PORTS
+#undef OFPUTIL_NAMED_PORT
+
+ default:
+ snprintf(namebuf, bufsize, "%"PRIu16, port);
+ break;
+ }
+}
+
+/* Stores the group id represented by 's' into '*group_idp'. 's' may be an
+ * integer or, for reserved group IDs, the standard OpenFlow name for the group
+ * (either "ANY" or "ALL").
+ *
+ * Returns true if successful, false if 's' is not a valid OpenFlow group ID or
+ * name. */
+bool
+ofputil_group_from_string(const char *s, uint32_t *group_idp)
+{
+ if (!strcasecmp(s, "any")) {
+ *group_idp = OFPG11_ANY;
+ } else if (!strcasecmp(s, "all")) {
+ *group_idp = OFPG11_ALL;
+ } else if (!str_to_uint(s, 10, group_idp)) {
+ VLOG_WARN("%s is not a valid group ID. (Valid group IDs are "
+ "32-bit nonnegative integers or the keywords ANY or "
+ "ALL.)", s);
+ return false;
+ }
+
+ return true;
+}
+
+/* Appends to 's' a string representation of the OpenFlow group ID 'group_id'.
+ * Most groups' string representation is just the number, but for special
+ * groups, e.g. OFPG11_ALL, it is the name, e.g. "ALL". */
+void
+ofputil_format_group(uint32_t group_id, struct ds *s)
+{
+ char name[MAX_GROUP_NAME_LEN];
+
+ ofputil_group_to_string(group_id, name, sizeof name);
+ ds_put_cstr(s, name);
+}
+
+
+/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
+ * representation of OpenFlow group ID 'group_id'. Most group are represented
+ * as just their number, but special groups, e.g. OFPG11_ALL, are represented
+ * by name, e.g. "ALL". */
+void
+ofputil_group_to_string(uint32_t group_id,
+ char namebuf[MAX_GROUP_NAME_LEN + 1], size_t bufsize)
+{
+ switch (group_id) {
+ case OFPG11_ALL:
+ ovs_strlcpy(namebuf, "ALL", bufsize);
+ break;
+
+ case OFPG11_ANY:
+ ovs_strlcpy(namebuf, "ANY", bufsize);
+ break;
+
+ default:
+ snprintf(namebuf, bufsize, "%"PRIu32, group_id);
+ break;
+ }
+}
+
+/* Given a buffer 'b' that contains an array of OpenFlow ports of type
+ * 'ofp_version', tries to pull the first element from the array. If
+ * successful, initializes '*pp' with an abstract representation of the
+ * port and returns 0. If no ports remain to be decoded, returns EOF.
+ * On an error, returns a positive OFPERR_* value. */
+int
+ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b,
+ struct ofputil_phy_port *pp)
+{
+ switch (ofp_version) {
+ case OFP10_VERSION: {
+ const struct ofp10_phy_port *opp = ofpbuf_try_pull(b, sizeof *opp);
+ return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
+ }
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION: {
+ const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
+ return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
+ }
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+ default:
+ OVS_NOT_REACHED();
+ }
+}
+
+/* Given a buffer 'b' that contains an array of OpenFlow ports of type
+ * 'ofp_version', returns the number of elements. */
+size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b)
+{
+ return ofpbuf_size(b) / ofputil_get_phy_port_size(ofp_version);
+}
+
+/* ofp-util.def lists the mapping from names to action. */
+static const char *const names[OFPUTIL_N_ACTIONS] = {
+ NULL,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME,
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#include "ofp-util.def"
+};
+
+/* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if
+ * 'name' is "output" then the return value is OFPUTIL_OFPAT10_OUTPUT), or -1
+ * if 'name' is not the name of any action. */
+int
+ofputil_action_code_from_name(const char *name)
+{
+ const char *const *p;
+
+ for (p = names; p < &names[ARRAY_SIZE(names)]; p++) {
+ if (*p && !strcasecmp(name, *p)) {
+ return p - names;
+ }
+ }
+ return -1;
+}
+
+/* Returns name corresponding to the 'enum ofputil_action_code',
+ * or "Unkonwn action", if the name is not available. */
+const char *
+ofputil_action_name_from_code(enum ofputil_action_code code)
+{
+ return code < (int)OFPUTIL_N_ACTIONS && names[code] ? names[code]
+ : "Unknown action";
+}
+
+enum ofputil_action_code
+ofputil_action_code_from_ofp13_action(enum ofp13_action_type type)
+{
+ switch (type) {
+
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case ENUM: \
+ return OFPUTIL_##ENUM;
+#include "ofp-util.def"
+
+ default:
+ return OFPUTIL_ACTION_INVALID;
+ }
+}
+
+/* Appends an action of the type specified by 'code' to 'buf' and returns the
+ * action. Initializes the parts of 'action' that identify it as having type
+ * <ENUM> and length 'sizeof *action' and zeros the rest. For actions that
+ * have variable length, the length used and cleared is that of struct
+ * <STRUCT>. */
+void *
+ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
+{
+ switch (code) {
+ case OFPUTIL_ACTION_INVALID:
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+ OVS_NOT_REACHED();
+
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
+ case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
+#include "ofp-util.def"
+ }
+ OVS_NOT_REACHED();
+}
+
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
+ void \
+ ofputil_init_##ENUM(struct STRUCT *s) \
+ { \
+ memset(s, 0, sizeof *s); \
+ s->type = htons(ENUM); \
+ s->len = htons(sizeof *s); \
+ } \
+ \
+ struct STRUCT * \
+ ofputil_put_##ENUM(struct ofpbuf *buf) \
+ { \
+ struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
+ ofputil_init_##ENUM(s); \
+ return s; \
+ }
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ OFPAT10_ACTION(ENUM, STRUCT, NAME)
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ OFPAT10_ACTION(ENUM, STRUCT, NAME)
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ void \
+ ofputil_init_##ENUM(struct STRUCT *s) \
+ { \
+ memset(s, 0, sizeof *s); \
+ s->type = htons(OFPAT10_VENDOR); \
+ s->len = htons(sizeof *s); \
+ s->vendor = htonl(NX_VENDOR_ID); \
+ s->subtype = htons(ENUM); \
+ } \
+ \
+ struct STRUCT * \
+ ofputil_put_##ENUM(struct ofpbuf *buf) \
+ { \
+ struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
+ ofputil_init_##ENUM(s); \
+ return s; \
+ }
+#include "ofp-util.def"
+
+static void
+ofputil_normalize_match__(struct match *match, bool may_log)
+{
+ enum {
+ MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */
+ MAY_TP_ADDR = 1 << 1, /* tp_src, tp_dst */
+ MAY_NW_PROTO = 1 << 2, /* nw_proto */
+ MAY_IPVx = 1 << 3, /* tos, frag, ttl */
+ MAY_ARP_SHA = 1 << 4, /* arp_sha */
+ MAY_ARP_THA = 1 << 5, /* arp_tha */
+ MAY_IPV6 = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */
+ MAY_ND_TARGET = 1 << 7, /* nd_target */
+ MAY_MPLS = 1 << 8, /* mpls label and tc */
+ } may_match;
+
+ struct flow_wildcards wc;
+
+ /* Figure out what fields may be matched. */
+ if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
+ may_match = MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR;
+ if (match->flow.nw_proto == IPPROTO_TCP ||
+ match->flow.nw_proto == IPPROTO_UDP ||
+ match->flow.nw_proto == IPPROTO_SCTP ||
+ match->flow.nw_proto == IPPROTO_ICMP) {
+ may_match |= MAY_TP_ADDR;
+ }
+ } else if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
+ may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
+ if (match->flow.nw_proto == IPPROTO_TCP ||
+ match->flow.nw_proto == IPPROTO_UDP ||
+ match->flow.nw_proto == IPPROTO_SCTP) {
+ may_match |= MAY_TP_ADDR;
+ } else if (match->flow.nw_proto == IPPROTO_ICMPV6) {
+ may_match |= MAY_TP_ADDR;
+ if (match->flow.tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
+ may_match |= MAY_ND_TARGET | MAY_ARP_SHA;
+ } else if (match->flow.tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+ may_match |= MAY_ND_TARGET | MAY_ARP_THA;
+ }
+ }
+ } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) ||
+ match->flow.dl_type == htons(ETH_TYPE_RARP)) {
+ may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
+ } else if (eth_type_mpls(match->flow.dl_type)) {
+ may_match = MAY_MPLS;
+ } else {
+ may_match = 0;
+ }
+
+ /* Clear the fields that may not be matched. */
+ wc = match->wc;