case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_SCTP:
if (!(wc & (OFPFW11_TP_SRC))) {
match_set_tp_src(match, ofmatch->tp_src);
}
}
break;
- case IPPROTO_SCTP:
- /* We don't support SCTP and it seems that we should tell the
- * controller, since OF1.1 implementations are supposed to. */
- return OFPERR_OFPBMC_BAD_FIELD;
-
default:
/* OF1.1 says explicitly to ignore this. */
break;
ofmatch->wildcards = htonl(wc);
}
+/* Returns the "typical" length of a match for 'protocol', for use in
+ * estimating space to preallocate. */
+int
+ofputil_match_typical_len(enum ofputil_protocol protocol)
+{
+ switch (protocol) {
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID:
+ return sizeof(struct ofp10_match);
+
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID:
+ return NXM_TYPICAL_LEN;
+
+ case OFPUTIL_P_OF11_STD:
+ return sizeof(struct ofp11_match);
+
+ case OFPUTIL_P_OF12_OXM:
+ case OFPUTIL_P_OF13_OXM:
+ return NXM_TYPICAL_LEN;
+
+ default:
+ NOT_REACHED();
+ }
+}
+
+/* Appends to 'b' an struct ofp11_match_header followed by a match that
+ * expresses 'match' properly for 'protocol', plus enough zero bytes to pad the
+ * data appended out to a multiple of 8. 'protocol' must be one that is usable
+ * in OpenFlow 1.1 or later.
+ *
+ * This function can cause 'b''s data to be reallocated.
+ *
+ * Returns the number of bytes appended to 'b', excluding the padding. Never
+ * returns zero. */
+int
+ofputil_put_ofp11_match(struct ofpbuf *b, const struct match *match,
+ enum ofputil_protocol protocol)
+{
+ switch (protocol) {
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID:
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID:
+ NOT_REACHED();
+
+ case OFPUTIL_P_OF11_STD: {
+ struct ofp11_match *om;
+
+ /* Make sure that no padding is needed. */
+ BUILD_ASSERT_DECL(sizeof *om % 8 == 0);
+
+ om = ofpbuf_put_uninit(b, sizeof *om);
+ ofputil_match_to_ofp11_match(match, om);
+ return sizeof *om;
+ }
+
+ case OFPUTIL_P_OF12_OXM:
+ case OFPUTIL_P_OF13_OXM:
+ return oxm_put_match(b, match);
+ }
+
+ NOT_REACHED();
+}
+
/* Given a 'dl_type' value in the format used in struct flow, returns the
* corresponding 'dl_type' value for use in an ofp10_match or ofp11_match
* structure. */
enum ofputil_protocol ofputil_flow_dump_protocols[] = {
OFPUTIL_P_OF13_OXM,
OFPUTIL_P_OF12_OXM,
+ OFPUTIL_P_OF11_STD,
OFPUTIL_P_OF10_NXM,
OFPUTIL_P_OF10_STD,
};
switch (version) {
case OFP10_VERSION:
return OFPUTIL_P_OF10_STD_ANY | OFPUTIL_P_OF10_NXM_ANY;
+ case OFP11_VERSION:
+ return OFPUTIL_P_OF11_STD;
case OFP12_VERSION:
return OFPUTIL_P_OF12_OXM;
case OFP13_VERSION:
return OFPUTIL_P_OF13_OXM;
- case OFP11_VERSION:
default:
return 0;
}
case OFPUTIL_P_OF10_NXM:
case OFPUTIL_P_OF10_NXM_TID:
return OFP10_VERSION;
+ case OFPUTIL_P_OF11_STD:
+ return OFP11_VERSION;
case OFPUTIL_P_OF12_OXM:
return OFP12_VERSION;
case OFPUTIL_P_OF13_OXM:
case OFPUTIL_P_OF10_NXM_TID:
return enable ? OFPUTIL_P_OF10_NXM_TID : OFPUTIL_P_OF10_NXM;
+ case OFPUTIL_P_OF11_STD:
+ return OFPUTIL_P_OF11_STD;
+
case OFPUTIL_P_OF12_OXM:
return OFPUTIL_P_OF12_OXM;
case OFPUTIL_P_OF10_NXM_TID:
return ofputil_protocol_set_tid(OFPUTIL_P_OF10_NXM, tid);
+ case OFPUTIL_P_OF11_STD:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF11_STD, tid);
+
case OFPUTIL_P_OF12_OXM:
return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid);
case OFPUTIL_P_OF10_STD_TID:
return "OpenFlow10+table_id";
+ case OFPUTIL_P_OF11_STD:
+ return "OpenFlow11";
+
case OFPUTIL_P_OF12_OXM:
return "OXM-OpenFlow12";
: -1);
}
-static bool
-regs_fully_wildcarded(const struct flow_wildcards *wc)
-{
- int i;
-
- for (i = 0; i < FLOW_N_REGS; i++) {
- if (wc->masks.regs[i] != 0) {
- return false;
- }
- }
- return true;
-}
-
-/* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
- * to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs,
- * registers, or fixing the Ethernet multicast bit. Otherwise, it's better to
- * use OpenFlow 1.0 protocol for backward compatibility. */
-enum ofputil_protocol
-ofputil_usable_protocols(const struct match *match)
-{
- const struct flow_wildcards *wc = &match->wc;
-
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
-
- /* These tunnel params can't be sent in a flow_mod */
- if (wc->masks.tunnel.ip_ttl
- || wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) {
- return OFPUTIL_P_NONE;
- }
-
- /* skb_mark and skb_priority can't be sent in a flow_mod */
- if (wc->masks.skb_mark || wc->masks.skb_priority) {
- return OFPUTIL_P_NONE;
- }
-
- /* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */
- if (!eth_mask_is_exact(wc->masks.dl_src)
- && !eth_addr_is_zero(wc->masks.dl_src)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
- if (!eth_mask_is_exact(wc->masks.dl_dst)
- && !eth_addr_is_zero(wc->masks.dl_dst)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM, OXM, and OF1.1+ support matching metadata. */
- if (wc->masks.metadata != htonll(0)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching ARP hardware addresses. */
- if (!eth_addr_is_zero(wc->masks.arp_sha) ||
- !eth_addr_is_zero(wc->masks.arp_tha)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching IPv6 traffic. */
- if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching registers. */
- if (!regs_fully_wildcarded(wc)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching tun_id, tun_src, and tun_dst. */
- if (wc->masks.tunnel.tun_id != htonll(0)
- || wc->masks.tunnel.ip_src != htonl(0)
- || wc->masks.tunnel.ip_dst != htonl(0)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching fragments. */
- if (wc->masks.nw_frag) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching IPv6 flow label. */
- if (wc->masks.ipv6_label) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching IP ECN bits. */
- if (wc->masks.nw_tos & IP_ECN_MASK) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support matching IP TTL/hop limit. */
- if (wc->masks.nw_ttl) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support non-CIDR IPv4 address masks. */
- if (!ip_is_cidr(wc->masks.nw_src) || !ip_is_cidr(wc->masks.nw_dst)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OXM support bitwise matching on transport port. */
- if ((wc->masks.tp_src && wc->masks.tp_src != htons(UINT16_MAX)) ||
- (wc->masks.tp_dst && wc->masks.tp_dst != htons(UINT16_MAX))) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OF1.1+ support matching MPLS label */
- if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OF1.1+ support matching MPLS TC */
- if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* NXM and OF1.3+ support matching MPLS stack flag */
- /* Allow for OF1.2 as there doesn't seem to be a
- * particularly good reason not to */
- if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
- return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
-
- /* Other formats can express this rule. */
- return OFPUTIL_P_ANY;
-}
-
void
ofputil_format_version(struct ds *msg, enum ofp_version version)
{
uint32_t *allowed_versionsp)
{
uint16_t bitmap_len = ntohs(oheh->length) - sizeof *oheh;
- const ovs_be32 *bitmap = (const ovs_be32 *) (oheh + 1);
+ const ovs_be32 *bitmap = ALIGNED_CAST(const ovs_be32 *, oheh + 1);
uint32_t allowed_versions;
if (!bitmap_len || bitmap_len % sizeof *bitmap) {
/* Returns true if 'allowed_versions' needs to be accompanied by a version
* bitmap to be correctly expressed in an OFPT_HELLO message. */
-static inline bool
+static bool
should_send_version_bitmap(uint32_t allowed_versions)
{
return !is_pow2((allowed_versions >> 1) + 1);
oheh = ofpbuf_put_zeros(msg, ROUND_UP(map_len + sizeof *oheh, 8));
oheh->type = htons(OFPHET_VERSIONBITMAP);
oheh->length = htons(map_len + sizeof *oheh);
- *(ovs_be32 *)(oheh + 1) = htonl(allowed_versions);
+ *ALIGNED_CAST(ovs_be32 *, oheh + 1) = htonl(allowed_versions);
ofpmsg_update_length(msg);
}
case OFPUTIL_P_OF10_STD:
return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10);
+ case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
- /* There are only one of each OpenFlow 1.2+ protocols and we already
+ /* There is only one variant of each OpenFlow 1.1+ protocol, and we
* verified above that we're not trying to change versions. */
NOT_REACHED();
return msg;
}
+struct ofputil_flow_mod_flag {
+ uint16_t raw_flag;
+ enum ofp_version min_version, max_version;
+ enum ofputil_flow_mod_flags flag;
+};
+
+static const struct ofputil_flow_mod_flag ofputil_flow_mod_flags[] = {
+ { OFPFF_SEND_FLOW_REM, OFP10_VERSION, 0, OFPUTIL_FF_SEND_FLOW_REM },
+ { OFPFF_CHECK_OVERLAP, OFP10_VERSION, 0, OFPUTIL_FF_CHECK_OVERLAP },
+ { OFPFF10_EMERG, OFP10_VERSION, OFP10_VERSION,
+ OFPUTIL_FF_EMERG },
+ { OFPFF12_RESET_COUNTS, OFP12_VERSION, 0, OFPUTIL_FF_RESET_COUNTS },
+ { OFPFF13_NO_PKT_COUNTS, OFP13_VERSION, 0, OFPUTIL_FF_NO_PKT_COUNTS },
+ { OFPFF13_NO_BYT_COUNTS, OFP13_VERSION, 0, OFPUTIL_FF_NO_BYT_COUNTS },
+ { 0, 0, 0, 0 },
+};
+
+static enum ofperr
+ofputil_decode_flow_mod_flags(ovs_be16 raw_flags_,
+ enum ofp_flow_mod_command command,
+ enum ofp_version version,
+ enum ofputil_flow_mod_flags *flagsp)
+{
+ uint16_t raw_flags = ntohs(raw_flags_);
+ const struct ofputil_flow_mod_flag *f;
+
+ *flagsp = 0;
+ for (f = ofputil_flow_mod_flags; f->raw_flag; f++) {
+ if (raw_flags & f->raw_flag
+ && version >= f->min_version
+ && (!f->max_version || version <= f->max_version)) {
+ raw_flags &= ~f->raw_flag;
+ *flagsp |= f->flag;
+ }
+ }
+
+ /* In OF1.0 and OF1.1, "add" always resets counters, and other commands
+ * never do.
+ *
+ * In OF1.2 and later, OFPFF12_RESET_COUNTS controls whether each command
+ * resets counters. */
+ if ((version == OFP10_VERSION || version == OFP11_VERSION)
+ && command == OFPFC_ADD) {
+ *flagsp |= OFPUTIL_FF_RESET_COUNTS;
+ }
+
+ return raw_flags ? OFPERR_OFPFMFC_BAD_FLAGS : 0;
+}
+
+static ovs_be16
+ofputil_encode_flow_mod_flags(enum ofputil_flow_mod_flags flags,
+ enum ofp_version version)
+{
+ const struct ofputil_flow_mod_flag *f;
+ uint16_t raw_flags;
+
+ raw_flags = 0;
+ for (f = ofputil_flow_mod_flags; f->raw_flag; f++) {
+ if (f->flag & flags
+ && version >= f->min_version
+ && (!f->max_version || version <= f->max_version)) {
+ raw_flags |= f->raw_flag;
+ }
+ }
+
+ return htons(raw_flags);
+}
+
/* Converts an OFPT_FLOW_MOD or NXT_FLOW_MOD message 'oh' into an abstract
* flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error
* code.
enum ofputil_protocol protocol,
struct ofpbuf *ofpacts)
{
- uint16_t command;
+ ovs_be16 raw_flags;
+ enum ofperr error;
struct ofpbuf b;
enum ofpraw raw;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
if (raw == OFPRAW_OFPT11_FLOW_MOD) {
- /* Standard OpenFlow 1.1 flow_mod. */
+ /* Standard OpenFlow 1.1+ flow_mod. */
const struct ofp11_flow_mod *ofm;
- enum ofperr error;
ofm = ofpbuf_pull(&b, sizeof *ofm);
return error;
}
- error = ofpacts_pull_openflow11_instructions(&b, b.size, ofm->table_id,
- ofpacts);
+ error = ofpacts_pull_openflow11_instructions(&b, b.size, ofpacts);
if (error) {
return error;
}
/* Translate the message. */
fm->priority = ntohs(ofm->priority);
- if (ofm->command == OFPFC_ADD) {
+ if (ofm->command == OFPFC_ADD
+ || (oh->version == OFP11_VERSION
+ && (ofm->command == OFPFC_MODIFY ||
+ ofm->command == OFPFC_MODIFY_STRICT)
+ && ofm->cookie_mask == htonll(0))) {
+ /* In OpenFlow 1.1 only, a "modify" or "modify-strict" that does
+ * not match on the cookie is treated as an "add" if there is no
+ * match. */
fm->cookie = htonll(0);
fm->cookie_mask = htonll(0);
fm->new_cookie = ofm->cookie;
fm->cookie_mask = ofm->cookie_mask;
fm->new_cookie = htonll(UINT64_MAX);
}
+ fm->modify_cookie = false;
fm->command = ofm->command;
fm->table_id = ofm->table_id;
fm->idle_timeout = ntohs(ofm->idle_timeout);
&& ofm->out_group != htonl(OFPG_ANY)) {
return OFPERR_OFPFMFC_UNKNOWN;
}
- fm->flags = ntohs(ofm->flags);
+ raw_flags = ofm->flags;
} else {
+ uint16_t command;
+
if (raw == OFPRAW_OFPT10_FLOW_MOD) {
/* Standard OpenFlow 1.0 flow_mod. */
const struct ofp10_flow_mod *ofm;
- enum ofperr error;
/* Get the ofp10_flow_mod. */
ofm = ofpbuf_pull(&b, sizeof *ofm);
fm->hard_timeout = ntohs(ofm->hard_timeout);
fm->buffer_id = ntohl(ofm->buffer_id);
fm->out_port = u16_to_ofp(ntohs(ofm->out_port));
- fm->flags = ntohs(ofm->flags);
+ raw_flags = ofm->flags;
} else if (raw == OFPRAW_NXT_FLOW_MOD) {
/* Nicira extended flow_mod. */
const struct nx_flow_mod *nfm;
- enum ofperr error;
/* Dissect the message. */
nfm = ofpbuf_pull(&b, sizeof *nfm);
fm->hard_timeout = ntohs(nfm->hard_timeout);
fm->buffer_id = ntohl(nfm->buffer_id);
fm->out_port = u16_to_ofp(ntohs(nfm->out_port));
- fm->flags = ntohs(nfm->flags);
+ raw_flags = nfm->flags;
} else {
NOT_REACHED();
}
- if (fm->flags & OFPFF10_EMERG) {
- /* We do not support the OpenFlow 1.0 emergency flow cache, which
- * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
- *
- * OpenFlow 1.0 specifies the error code to use when idle_timeout
- * or hard_timeout is nonzero. Otherwise, there is no good error
- * code, so just state that the flow table is full. */
- return (fm->hard_timeout || fm->idle_timeout
- ? OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT
- : OFPERR_OFPFMFC_TABLE_FULL);
- }
-
+ fm->modify_cookie = fm->new_cookie != htonll(UINT64_MAX);
if (protocol & OFPUTIL_P_TID) {
fm->command = command & 0xff;
fm->table_id = command >> 8;
fm->ofpacts = ofpacts->data;
fm->ofpacts_len = ofpacts->size;
+ error = ofputil_decode_flow_mod_flags(raw_flags, fm->command,
+ oh->version, &fm->flags);
+ if (error) {
+ return error;
+ }
+
+ if (fm->flags & OFPUTIL_FF_EMERG) {
+ /* We do not support the OpenFlow 1.0 emergency flow cache, which
+ * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
+ *
+ * OpenFlow 1.0 specifies the error code to use when idle_timeout
+ * or hard_timeout is nonzero. Otherwise, there is no good error
+ * code, so just state that the flow table is full. */
+ return (fm->hard_timeout || fm->idle_timeout
+ ? OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT
+ : OFPERR_OFPFMFC_TABLE_FULL);
+ }
+
return 0;
}
while (len >= sizeof (struct ofp13_meter_band_drop)) {
size_t ombh_len = ntohs(ombh->len);
- /* All supported band types have the same length */
+ /* All supported band types have the same length. */
if (ombh_len != sizeof (struct ofp13_meter_band_drop)) {
return OFPERR_OFPBRC_BAD_LEN;
}
((struct ofp13_meter_band_dscp_remark *)ombh)->prec_level : 0;
n++;
len -= ombh_len;
- ombh = (struct ofp13_meter_band_header *)(((char *)ombh) + ombh_len);
+ ombh = ALIGNED_CAST(struct ofp13_meter_band_header *,
+ (char *) ombh + ombh_len);
}
if (len) {
return OFPERR_OFPBRC_BAD_LEN;
mm->meter.flags = ntohs(omm->flags);
mm->meter.bands = bands->data;
- error = ofputil_pull_bands(&b, b.size, &mm->meter.n_bands,
- bands);
+ error = ofputil_pull_bands(&b, b.size, &mm->meter.n_bands, bands);
if (error) {
return error;
}
uint16_t n = 0;
for (n = 0; n < n_bands; ++n) {
- /* Currently all band types have same size */
+ /* Currently all band types have same size. */
struct ofp13_meter_band_dscp_remark *ombh;
size_t ombh_len = sizeof *ombh;
omc = ofpbuf_try_pull(msg, sizeof *omc);
if (!omc) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "OFPMP_METER_CONFIG reply has %zu "
- "leftover bytes at end", msg->size);
+ VLOG_WARN_RL(&bad_ofmsg_rl,
+ "OFPMP_METER_CONFIG reply has %zu leftover bytes at end",
+ msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
struct ofputil_meter_band_stats *mbs;
uint16_t n, i;
+ ombs = ofpbuf_try_pull(msg, len);
+ if (!ombs) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
n = len / sizeof *ombs;
if (len != n * sizeof *ombs) {
return OFPERR_OFPBRC_BAD_LEN;
}
- ombs = ofpbuf_pull(msg, len);
-
mbs = ofpbuf_put_uninit(bands, len);
for (i = 0; i < n; ++i) {
struct ofpbuf *bands)
{
const struct ofp13_meter_stats *oms;
- uint16_t len;
enum ofperr err;
/* Pull OpenFlow headers for the first call. */
oms = ofpbuf_try_pull(msg, sizeof *oms);
if (!oms) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "OFPMP_METER reply has %zu leftover "
- "bytes at end", msg->size);
+ VLOG_WARN_RL(&bad_ofmsg_rl,
+ "OFPMP_METER reply has %zu leftover bytes at end",
+ msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
- len = ntohs(oms->len);
- len -= sizeof *oms;
ofpbuf_clear(bands);
- err = ofputil_pull_band_stats(msg, len, &ms->n_bands, bands);
+ err = ofputil_pull_band_stats(msg, ntohs(oms->len) - sizeof *oms,
+ &ms->n_bands, bands);
if (err) {
return err;
}
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
enum ofputil_protocol protocol)
{
+ enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
+ ovs_be16 raw_flags = ofputil_encode_flow_mod_flags(fm->flags, version);
struct ofpbuf *msg;
switch (protocol) {
+ case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM: {
struct ofp11_flow_mod *ofm;
+ int tailroom;
- msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD,
- ofputil_protocol_to_ofp_version(protocol),
- NXM_TYPICAL_LEN + fm->ofpacts_len);
+ tailroom = ofputil_match_typical_len(protocol) + fm->ofpacts_len;
+ msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, version, tailroom);
ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
- if (fm->command == OFPFC_ADD) {
+ if ((protocol == OFPUTIL_P_OF11_STD
+ && (fm->command == OFPFC_MODIFY ||
+ fm->command == OFPFC_MODIFY_STRICT)
+ && fm->cookie_mask == htonll(0))
+ || fm->command == OFPFC_ADD) {
ofm->cookie = fm->new_cookie;
} else {
ofm->cookie = fm->cookie;
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = ofputil_port_to_ofp11(fm->out_port);
ofm->out_group = htonl(OFPG11_ANY);
- ofm->flags = htons(fm->flags);
- oxm_put_match(msg, &fm->match);
+ ofm->flags = raw_flags;
+ ofputil_put_ofp11_match(msg, &fm->match, protocol);
ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len, msg);
break;
}
ofm->priority = htons(fm->priority);
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = htons(ofp_to_u16(fm->out_port));
- ofm->flags = htons(fm->flags);
+ ofm->flags = raw_flags;
ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
break;
}
nfm->priority = htons(fm->priority);
nfm->buffer_id = htonl(fm->buffer_id);
nfm->out_port = htons(ofp_to_u16(fm->out_port));
- nfm->flags = htons(fm->flags);
+ nfm->flags = raw_flags;
nfm->match_len = htons(match_len);
ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
break;
return msg;
}
-/* Returns a bitmask with a 1-bit for each protocol that could be used to
- * send all of the 'n_fm's flow table modification requests in 'fms', and a
- * 0-bit for each protocol that is inadequate.
- *
- * (The return value will have at least one 1-bit.) */
-enum ofputil_protocol
-ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
- size_t n_fms)
-{
- enum ofputil_protocol usable_protocols;
- size_t i;
-
- usable_protocols = OFPUTIL_P_ANY;
- for (i = 0; i < n_fms; i++) {
- const struct ofputil_flow_mod *fm = &fms[i];
-
- usable_protocols &= ofputil_usable_protocols(&fm->match);
- if (fm->table_id != 0xff) {
- usable_protocols &= OFPUTIL_P_TID;
- }
-
- /* Matching of the cookie is only supported through NXM or OF1.1+. */
- if (fm->cookie_mask != htonll(0)) {
- usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
- }
-
- return usable_protocols;
-}
-
static enum ofperr
ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr,
const struct ofp10_flow_stats_request *ofsr,
enum ofpraw raw;
switch (protocol) {
+ case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM: {
struct ofp11_flow_stats_request *ofsr;
? OFPRAW_OFPST11_AGGREGATE_REQUEST
: OFPRAW_OFPST11_FLOW_REQUEST);
msg = ofpraw_alloc(raw, ofputil_protocol_to_ofp_version(protocol),
- NXM_TYPICAL_LEN);
+ ofputil_match_typical_len(protocol));
ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
ofsr->table_id = fsr->table_id;
ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port);
ofsr->out_group = htonl(OFPG11_ANY);
ofsr->cookie = fsr->cookie;
ofsr->cookie_mask = fsr->cookie_mask;
- oxm_put_match(msg, &fsr->match);
+ ofputil_put_ofp11_match(msg, &fsr->match, protocol);
break;
}
return msg;
}
-/* Returns a bitmask with a 1-bit for each protocol that could be used to
- * accurately encode 'fsr', and a 0-bit for each protocol that is inadequate.
- *
- * (The return value will have at least one 1-bit.) */
-enum ofputil_protocol
-ofputil_flow_stats_request_usable_protocols(
- const struct ofputil_flow_stats_request *fsr)
-{
- enum ofputil_protocol usable_protocols;
-
- usable_protocols = ofputil_usable_protocols(&fsr->match);
- if (fsr->cookie_mask != htonll(0)) {
- usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
- | OFPUTIL_P_OF13_OXM;
- }
- return usable_protocols;
-}
-
/* Converts an OFPST_FLOW or NXST_FLOW reply in 'msg' into an abstract
* ofputil_flow_stats in 'fs'.
*
bool flow_age_extension,
struct ofpbuf *ofpacts)
{
+ const struct ofp_header *oh;
enum ofperr error;
enum ofpraw raw;
if (error) {
return error;
}
+ oh = msg->l2;
if (!msg->size) {
return EOF;
}
if (ofpacts_pull_openflow11_instructions(msg, length - sizeof *ofs -
- padded_match_len,
- ofs->table_id, ofpacts)) {
+ padded_match_len, ofpacts)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions");
return EINVAL;
}
fs->duration_nsec = ntohl(ofs->duration_nsec);
fs->idle_timeout = ntohs(ofs->idle_timeout);
fs->hard_timeout = ntohs(ofs->hard_timeout);
- fs->flags = (raw == OFPRAW_OFPST13_FLOW_REPLY) ? ntohs(ofs->flags) : 0;
+ if (raw == OFPRAW_OFPST13_FLOW_REPLY) {
+ error = ofputil_decode_flow_mod_flags(ofs->flags, -1, oh->version,
+ &fs->flags);
+ if (error) {
+ return error;
+ }
+ } else {
+ fs->flags = 0;
+ }
fs->idle_age = -1;
fs->hard_age = -1;
fs->cookie = ofs->cookie;
ofpraw_decode_partial(&raw, reply->data, reply->size);
if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
+ const struct ofp_header *oh = reply->data;
struct ofp11_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
ofs->priority = htons(fs->priority);
ofs->idle_timeout = htons(fs->idle_timeout);
ofs->hard_timeout = htons(fs->hard_timeout);
- ofs->flags = (raw == OFPRAW_OFPST13_FLOW_REPLY) ? htons(fs->flags) : 0;
+ if (raw == OFPRAW_OFPST13_FLOW_REPLY) {
+ ofs->flags = ofputil_encode_flow_mod_flags(fs->flags, oh->version);
+ } else {
+ ofs->flags = 0;
+ }
memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->cookie = fs->cookie;
ofs->packet_count = htonll(unknown_to_zero(fs->packet_count));
struct ofpbuf *msg;
switch (protocol) {
+ case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM: {
struct ofp12_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
ofputil_protocol_to_ofp_version(protocol),
- htonl(0), NXM_TYPICAL_LEN);
+ htonl(0),
+ ofputil_match_typical_len(protocol));
ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
ofr->cookie = fr->cookie;
ofr->priority = htons(fr->priority);
ofr->hard_timeout = htons(fr->hard_timeout);
ofr->packet_count = htonll(fr->packet_count);
ofr->byte_count = htonll(fr->byte_count);
- oxm_put_match(msg, &fr->match);
+ ofputil_put_ofp11_match(msg, &fr->match, protocol);
break;
}
pin->fmd.tun_dst = match->flow.tunnel.ip_dst;
pin->fmd.metadata = match->flow.metadata;
memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs);
+ pin->fmd.pkt_mark = match->flow.pkt_mark;
}
enum ofperr
}
}
+ if (pin->fmd.pkt_mark != 0) {
+ match_set_pkt_mark(match, pin->fmd.pkt_mark);
+ }
+
match_set_in_port(match, pin->fmd.in_port);
}
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_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;
return error;
}
+static size_t
+ofputil_get_port_stats_size(enum ofp_version ofp_version)
+{
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ return sizeof(struct ofp10_port_stats);
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ return sizeof(struct ofp11_port_stats);
+ case OFP13_VERSION:
+ return sizeof(struct ofp13_port_stats);
+ default:
+ NOT_REACHED();
+ }
+}
/* Returns the number of port stats elements in OFPTYPE_PORT_STATS_REPLY
* message 'oh'. */
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
- BUILD_ASSERT(sizeof(struct ofp10_port_stats) ==
- sizeof(struct ofp11_port_stats));
- return b.size / sizeof(struct ofp10_port_stats);
+ return b.size / ofputil_get_port_stats_size(oh->version);
}
/* Converts an OFPST_PORT_STATS reply in 'msg' into an abstract
return request;
}
+static size_t
+ofputil_get_queue_stats_size(enum ofp_version ofp_version)
+{
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ return sizeof(struct ofp10_queue_stats);
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ return sizeof(struct ofp11_queue_stats);
+ case OFP13_VERSION:
+ return sizeof(struct ofp13_queue_stats);
+ default:
+ NOT_REACHED();
+ }
+}
+
/* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
* message 'oh'. */
size_t
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
- BUILD_ASSERT(sizeof(struct ofp10_queue_stats) ==
- sizeof(struct ofp11_queue_stats));
- return b.size / sizeof(struct ofp10_queue_stats);
+ return b.size / ofputil_get_queue_stats_size(oh->version);
}
static enum ofperr
{
oqs->port_no = u16_to_ofp(ntohs(qs10->port_no));
oqs->queue_id = ntohl(qs10->queue_id);
- oqs->stats.tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
- oqs->stats.tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
- oqs->stats.tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
+ oqs->tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
+ oqs->tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
+ oqs->tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
+ oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
return 0;
}
}
oqs->queue_id = ntohl(qs11->queue_id);
- oqs->stats.tx_bytes = ntohll(qs11->tx_bytes);
- oqs->stats.tx_packets = ntohll(qs11->tx_packets);
- oqs->stats.tx_errors = ntohll(qs11->tx_errors);
+ oqs->tx_bytes = ntohll(qs11->tx_bytes);
+ oqs->tx_packets = ntohll(qs11->tx_packets);
+ oqs->tx_errors = ntohll(qs11->tx_errors);
+ oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
return 0;
}
ofputil_queue_stats_from_ofp13(struct ofputil_queue_stats *oqs,
const struct ofp13_queue_stats *qs13)
{
- enum ofperr error
- = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
+ enum ofperr error = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
if (!error) {
- /* FIXME: Get qs13->duration_sec and qs13->duration_nsec,
- * Add to netdev_queue_stats? */
+ oqs->duration_sec = ntohl(qs13->duration_sec);
+ oqs->duration_nsec = ntohl(qs13->duration_nsec);
}
return error;
qs10->port_no = htons(ofp_to_u16(oqs->port_no));
memset(qs10->pad, 0, sizeof qs10->pad);
qs10->queue_id = htonl(oqs->queue_id);
- put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->stats.tx_bytes));
- put_32aligned_be64(&qs10->tx_packets, htonll(oqs->stats.tx_packets));
- put_32aligned_be64(&qs10->tx_errors, htonll(oqs->stats.tx_errors));
+ put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->tx_bytes));
+ put_32aligned_be64(&qs10->tx_packets, htonll(oqs->tx_packets));
+ put_32aligned_be64(&qs10->tx_errors, htonll(oqs->tx_errors));
}
static void
{
qs11->port_no = ofputil_port_to_ofp11(oqs->port_no);
qs11->queue_id = htonl(oqs->queue_id);
- qs11->tx_bytes = htonll(oqs->stats.tx_bytes);
- qs11->tx_packets = htonll(oqs->stats.tx_packets);
- qs11->tx_errors = htonll(oqs->stats.tx_errors);
+ qs11->tx_bytes = htonll(oqs->tx_bytes);
+ qs11->tx_packets = htonll(oqs->tx_packets);
+ qs11->tx_errors = htonll(oqs->tx_errors);
}
static void
struct ofp13_queue_stats *qs13)
{
ofputil_queue_stats_to_ofp11(oqs, &qs13->qs);
- /* OF 1.3 adds duration fields */
- /* FIXME: Need to implement queue alive duration (sec + nsec) */
- qs13->duration_sec = htonl(~0);
- qs13->duration_nsec = htonl(~0);
+ if (oqs->duration_sec != UINT32_MAX) {
+ qs13->duration_sec = htonl(oqs->duration_sec);
+ qs13->duration_nsec = htonl(oqs->duration_nsec);
+ } else {
+ qs13->duration_sec = htonl(UINT32_MAX);
+ qs13->duration_nsec = htonl(UINT32_MAX);
+ }
}
/* Encode a queue stat for 'oqs' and append it to 'replies'. */