rule->priority = !ofpfw ? UINT16_MAX : priority;
/* Initialize most of rule->wc. */
+ flow_wildcards_init_catchall(wc);
wc->wildcards = ofpfw & WC_INVARIANTS;
if (ofpfw & OFPFW_NW_TOS) {
wc->wildcards |= FWW_NW_TOS;
}
- memset(wc->reg_masks, 0, sizeof wc->reg_masks);
wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_SRC_SHIFT);
wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_DST_SHIFT);
}
}
+int
+ofputil_flow_format_from_string(const char *s)
+{
+ return (!strcmp(s, "openflow10") ? NXFF_OPENFLOW10
+ : !strcmp(s, "tun_id_from_cookie") ? NXFF_TUN_ID_FROM_COOKIE
+ : !strcmp(s, "nxm") ? NXFF_NXM
+ : -1);
+}
+
+static bool
+regs_fully_wildcarded(const struct flow_wildcards *wc)
+{
+ int i;
+
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ if (wc->reg_masks[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
+ * (e.g. to add or remove a flow). 'cookie_support' should be true if the
+ * command to be sent includes a flow cookie (as OFPT_FLOW_MOD does, for
+ * example) or false if the command does not (OFPST_FLOW and OFPST_AGGREGATE do
+ * not, for example). If 'cookie_support' is true, then 'cookie' should be the
+ * cookie to be sent; otherwise its value is ignored.
+ *
+ * The "best" flow format is chosen on this basis:
+ *
+ * - It must be capable of expressing the rule. NXFF_OPENFLOW10 flows can't
+ * handle tunnel IDs. NXFF_TUN_ID_FROM_COOKIE flows can't handle registers
+ * or fixing the Ethernet multicast bit, and can't handle tunnel IDs that
+ * conflict with the high 32 bits of the cookie or commands that don't
+ * support cookies.
+ *
+ * - Otherwise, the chosen format should be as backward compatible as
+ * possible. (NXFF_OPENFLOW10 is more backward compatible than
+ * NXFF_TUN_ID_FROM_COOKIE, which is more backward compatible than
+ * NXFF_NXM.)
+ */
+enum nx_flow_format
+ofputil_min_flow_format(const struct cls_rule *rule, bool cookie_support,
+ ovs_be64 cookie)
+{
+ const struct flow_wildcards *wc = &rule->wc;
+ ovs_be32 cookie_hi = htonl(ntohll(cookie) >> 32);
+
+ if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)
+ || !regs_fully_wildcarded(wc)
+ || (!(wc->wildcards & FWW_TUN_ID)
+ && (!cookie_support
+ || (cookie_hi && cookie_hi != rule->flow.tun_id)))) {
+ return NXFF_NXM;
+ } else if (!(wc->wildcards & FWW_TUN_ID)) {
+ return NXFF_TUN_ID_FROM_COOKIE;
+ } else {
+ return NXFF_OPENFLOW10;
+ }
+}
+
+/* Returns an OpenFlow message that can be used to set the flow format to
+ * 'flow_format'. */
+struct ofpbuf *
+ofputil_make_set_flow_format(enum nx_flow_format flow_format)
+{
+ struct ofpbuf *msg;
+
+ if (flow_format == NXFF_OPENFLOW10
+ || flow_format == NXFF_TUN_ID_FROM_COOKIE) {
+ struct nxt_tun_id_cookie *tic;
+
+ tic = make_nxmsg(sizeof *tic, NXT_TUN_ID_FROM_COOKIE, &msg);
+ tic->set = flow_format == NXFF_TUN_ID_FROM_COOKIE;
+ } else {
+ struct nxt_set_flow_format *sff;
+
+ sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
+ sff->format = htonl(flow_format);
+ }
+
+ return msg;
+}
+
/* 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.
const struct ofputil_msg_type *type;
struct ofpbuf b;
- b.data = (void *) oh;
- b.size = ntohs(oh->length);
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofputil_decode_msg_type(oh, &type);
if (ofputil_msg_type_code(type) == OFPUTIL_OFPT_FLOW_MOD) {
int error;
/* Dissect the message. */
- ofm = ofpbuf_try_pull(&b, sizeof *ofm);
- if (!ofm) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
+ ofm = ofpbuf_pull(&b, sizeof *ofm);
error = ofputil_pull_actions(&b, b.size, &fm->actions, &fm->n_actions);
if (error) {
return error;
int error;
/* Dissect the message. */
- nfm = ofpbuf_try_pull(&b, sizeof *nfm);
- if (!nfm) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
+ nfm = ofpbuf_pull(&b, sizeof *nfm);
error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
&fm->cr);
if (error) {
msg = ofpbuf_new(sizeof *ofm + actions_len);
ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
ofputil_cls_rule_to_match(&fm->cr, flow_format, &ofm->match);
- ofm->cookie = fm->cookie;
+ if (flow_format != NXFF_TUN_ID_FROM_COOKIE
+ || fm->cr.wc.wildcards & FWW_TUN_ID) {
+ ofm->cookie = fm->cookie;
+ } else {
+ uint32_t cookie_lo = ntohll(fm->cookie);
+ uint32_t cookie_hi = ntohl(fm->cr.flow.tun_id);
+ ofm->cookie = htonll(cookie_lo | ((uint64_t) cookie_hi << 32));
+ }
ofm->command = htons(fm->command);
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
struct ofpbuf b;
int error;
- b.data = (void *) oh;
- b.size = ntohs(oh->length);
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
- nfsr = ofpbuf_try_pull(&b, sizeof *nfsr);
- if (!nfsr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
+ nfsr = ofpbuf_pull(&b, sizeof *nfsr);
error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match);
if (error) {
return error;
struct ofpbuf b;
int code;
- b.data = (void *) oh;
- b.size = ntohs(oh->length);
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofputil_decode_msg_type(oh, &type);
code = ofputil_msg_type_code(type);
oem->type = htons(NXET_VENDOR);
oem->code = htons(NXVC_VENDOR_ERROR);
- nve = ofpbuf_put_uninit(buf, sizeof *nve);
+ nve = (struct nx_vendor_error *)oem->data;
nve->vendor = htonl(vendor_id);
nve->type = htons(type);
nve->code = htons(code);
}
if (len) {
+ buf->size -= len;
ofpbuf_put(buf, data, len);
}