use ovs_assert instead of assert
[sliver-openvswitch.git] / lib / nx-match.c
index 1ff58bb..4d7fcd6 100644 (file)
@@ -90,13 +90,38 @@ nx_entry_ok(const void *p, unsigned int match_len)
     return header;
 }
 
+/* Given NXM/OXM value 'value' and mask 'mask', each 'width' bytes long,
+ * checks for any 1-bit in the value where there is a 0-bit in the mask.  If it
+ * finds one, logs a warning. */
+static void
+check_mask_consistency(const uint8_t *p, const struct mf_field *mf)
+{
+    unsigned int width = mf->n_bytes;
+    const uint8_t *value = p + 4;
+    const uint8_t *mask = p + 4 + width;
+    unsigned int i;
+
+    for (i = 0; i < width; i++) {
+        if (value[i] & ~mask[i]) {
+            if (!VLOG_DROP_WARN(&rl)) {
+                char *s = nx_match_to_string(p, width * 2 + 4);
+                VLOG_WARN_RL(&rl, "NXM/OXM entry %s has 1-bits in value for "
+                             "bits wildcarded by the mask.  (Future versions "
+                             "of OVS may report this as an OpenFlow error.)",
+                             s);
+                break;
+            }
+        }
+    }
+}
+
 static enum ofperr
 nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
             struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask)
 {
     uint32_t header;
 
-    assert((cookie != NULL) == (cookie_mask != NULL));
+    ovs_assert((cookie != NULL) == (cookie_mask != NULL));
 
     match_init_catchall(match);
     if (cookie) {
@@ -141,6 +166,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
                     error = OFPERR_OFPBMC_BAD_MASK;
                 } else {
                     error = 0;
+                    check_mask_consistency(p, mf);
                     mf_set(mf, &value, &mask, match);
                 }
             }
@@ -547,7 +573,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
     int match_len;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
 
     /* Metadata. */
     if (match->wc.masks.in_port) {
@@ -626,7 +652,8 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
                                    flow->arp_tha, match->wc.masks.arp_tha);
             }
         }
-    } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+               flow->dl_type == htons(ETH_TYPE_RARP)) {
         /* ARP. */
         if (match->wc.masks.nw_proto) {
             nxm_put_16(b, oxm ? OXM_OF_ARP_OP : NXM_OF_ARP_OP,
@@ -643,7 +670,8 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
     }
 
     /* Tunnel ID. */
-    nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, match->wc.masks.tun_id);
+    nxm_put_64m(b, oxm ? OXM_OF_TUNNEL_ID : NXM_NX_TUN_ID,
+               flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
 
     /* Registers. */
     for (i = 0; i < FLOW_N_REGS; i++) {
@@ -989,7 +1017,6 @@ nxm_parse_reg_load(struct ofpact_reg_load *load, const char *s)
 {
     const char *full_s = s;
     uint64_t value = strtoull(s, (char **) &s, 0);
-    ovs_be64 value_be = htonll(value);
 
     if (strncmp(s, "->", 2)) {
         ovs_fatal(0, "%s: missing `->' following value", full_s);
@@ -1005,10 +1032,8 @@ nxm_parse_reg_load(struct ofpact_reg_load *load, const char *s)
                   full_s, value, load->dst.n_bits);
     }
 
-    memset(&load->subvalue, 0, sizeof &load->subvalue);
-    bitwise_copy(&value_be, sizeof value_be, 0,
-                 &load->subvalue, sizeof load->subvalue, load->dst.ofs,
-                 load->dst.n_bits);
+    load->subvalue.be64[0] = htonll(0);
+    load->subvalue.be64[1] = htonll(value);
 }
 \f
 /* nxm_format_reg_move(), nxm_format_reg_load(). */
@@ -1022,21 +1047,39 @@ nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s)
     mf_format_subfield(&move->dst, s);
 }
 
-void
-nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s)
+static void
+set_field_format(const struct ofpact_reg_load *load, struct ds *s)
 {
-    union mf_subvalue right_justified;
-
-    memset(&right_justified, 0, sizeof right_justified);
-    bitwise_copy(&load->subvalue, sizeof load->subvalue, load->dst.ofs,
-                 &right_justified, sizeof right_justified, 0,
-                 load->dst.n_bits);
+    const struct mf_field *mf = load->dst.field;
+    union mf_value value;
+
+    ovs_assert(load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD);
+    ds_put_format(s, "set_field:");
+    memset(&value, 0, sizeof value);
+    bitwise_copy(&load->subvalue, sizeof load->subvalue, 0,
+                 &value, mf->n_bytes, 0, load->dst.n_bits);
+    mf_format(mf, &value, NULL, s);
+    ds_put_format(s, "->%s", mf->name);
+}
 
+static void
+load_format(const struct ofpact_reg_load *load, struct ds *s)
+{
     ds_put_cstr(s, "load:");
-    mf_format_subvalue(&right_justified, s);
+    mf_format_subvalue(&load->subvalue, s);
     ds_put_cstr(s, "->");
     mf_format_subfield(&load->dst, s);
 }
+
+void
+nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s)
+{
+    if (load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD) {
+        set_field_format(load, s);
+    } else {
+        load_format(load, s);
+    }
+}
 \f
 enum ofperr
 nxm_reg_move_from_openflow(const struct nx_action_reg_move *narm,
@@ -1065,10 +1108,7 @@ nxm_reg_load_from_openflow(const struct nx_action_reg_load *narl,
     load->dst.field = mf_from_nxm_header(ntohl(narl->dst));
     load->dst.ofs = nxm_decode_ofs(narl->ofs_nbits);
     load->dst.n_bits = nxm_decode_n_bits(narl->ofs_nbits);
-    memset(&load->subvalue, 0, sizeof &load->subvalue);
-    bitwise_copy(&narl->value, sizeof narl->value, 0,
-                 &load->subvalue, sizeof load->subvalue, load->dst.ofs,
-                 load->dst.n_bits);
+    load->subvalue.be64[1] = narl->value;
 
     /* Reject 'narl' if a bit numbered 'n_bits' or higher is set to 1 in
      * narl->value. */
@@ -1079,6 +1119,38 @@ nxm_reg_load_from_openflow(const struct nx_action_reg_load *narl,
 
     return nxm_reg_load_check(load, NULL);
 }
+
+enum ofperr
+nxm_reg_load_from_openflow12_set_field(
+    const struct ofp12_action_set_field * oasf, struct ofpbuf *ofpacts)
+{
+    uint16_t oasf_len = ntohs(oasf->len);
+    uint32_t oxm_header = ntohl(oasf->dst);
+    uint8_t oxm_length = NXM_LENGTH(oxm_header);
+    struct ofpact_reg_load *load;
+    const struct mf_field *mf;
+
+    /* ofp12_action_set_field is padded to 64 bits by zero */
+    if (oasf_len != ROUND_UP(sizeof(*oasf) + oxm_length, 8)) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    if (!is_all_zeros((const uint8_t *)(oasf) + sizeof *oasf + oxm_length,
+                      oasf_len - oxm_length - sizeof *oasf)) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+
+    if (NXM_HASMASK(oxm_header)) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    mf = mf_from_nxm_header(oxm_header);
+    if (!mf) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    load = ofpact_put_REG_LOAD(ofpacts);
+    ofpact_set_field_init(load, mf, oasf + 1);
+
+    return nxm_reg_load_check(load, NULL);
+}
 \f
 enum ofperr
 nxm_reg_move_check(const struct ofpact_reg_move *move, const struct flow *flow)
@@ -1113,18 +1185,83 @@ nxm_reg_move_to_nxast(const struct ofpact_reg_move *move,
     narm->dst = htonl(move->dst.field->nxm_header);
 }
 
-void
-nxm_reg_load_to_nxast(const struct ofpact_reg_load *load,
-                      struct ofpbuf *openflow)
+static void
+reg_load_to_nxast(const struct ofpact_reg_load *load, struct ofpbuf *openflow)
 {
     struct nx_action_reg_load *narl;
 
     narl = ofputil_put_NXAST_REG_LOAD(openflow);
     narl->ofs_nbits = nxm_encode_ofs_nbits(load->dst.ofs, load->dst.n_bits);
     narl->dst = htonl(load->dst.field->nxm_header);
-    narl->value = htonll(0);
+    narl->value = load->subvalue.be64[1];
+}
+
+static void
+set_field_to_ofast(const struct ofpact_reg_load *load,
+                      struct ofpbuf *openflow)
+{
+    const struct mf_field *mf = load->dst.field;
+    struct ofp12_action_set_field *oasf;
+    uint16_t padded_value_len;
+
+    oasf = ofputil_put_OFPAT12_SET_FIELD(openflow);
+    oasf->dst = htonl(mf->oxm_header);
+
+    /* Set field is the only action of variable length (so far),
+     * so handling the variable length portion is open-coded here */
+    padded_value_len = ROUND_UP(mf->n_bytes, 8);
+    ofpbuf_put_uninit(openflow, padded_value_len);
+    oasf->len = htons(ntohs(oasf->len) + padded_value_len);
+    memset(oasf + 1, 0, padded_value_len);
+
     bitwise_copy(&load->subvalue, sizeof load->subvalue, load->dst.ofs,
-                 &narl->value, sizeof narl->value, 0, load->dst.n_bits);
+                 oasf + 1, mf->n_bytes, load->dst.ofs, load->dst.n_bits);
+    return;
+}
+
+void
+nxm_reg_load_to_nxast(const struct ofpact_reg_load *load,
+                      struct ofpbuf *openflow)
+{
+
+    if (load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD) {
+        struct ofp_header *oh = (struct ofp_header *)openflow->l2;
+
+        switch(oh->version) {
+        case OFP13_VERSION:
+        case OFP12_VERSION:
+            set_field_to_ofast(load, openflow);
+            break;
+
+        case OFP11_VERSION:
+        case OFP10_VERSION:
+            if (load->dst.n_bits < 64) {
+                reg_load_to_nxast(load, openflow);
+            } else {
+                /* Split into 64bit chunks */
+                int chunk, ofs;
+                for (ofs = 0; ofs < load->dst.n_bits; ofs += chunk) {
+                    struct ofpact_reg_load subload = *load;
+
+                    chunk = MIN(load->dst.n_bits - ofs, 64);
+
+                    subload.dst.field =  load->dst.field;
+                    subload.dst.ofs = load->dst.ofs + ofs;
+                    subload.dst.n_bits = chunk;
+                    bitwise_copy(&load->subvalue, sizeof load->subvalue, ofs,
+                                 &subload.subvalue, sizeof subload.subvalue, 0,
+                                 chunk);
+                    reg_load_to_nxast(&subload, openflow);
+                }
+            }
+            break;
+
+        default:
+            NOT_REACHED();
+        }
+    } else {
+        reg_load_to_nxast(load, openflow);
+    }
 }
 \f
 /* nxm_execute_reg_move(), nxm_execute_reg_load(). */