meta-flow: New functions for reading and writing generalized subfields.
[sliver-openvswitch.git] / lib / meta-flow.c
index a0e2aa8..8706d4a 100644 (file)
@@ -290,7 +290,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     {
         MFF_TCP_SRC, "tcp_src", "tp_src",
         MF_FIELD_SIZES(be16),
-        MFM_NONE, FWW_TP_SRC,
+        MFM_FULLY, 0,
         MFS_DECIMAL,
         MFP_TCP,
         true,
@@ -298,7 +298,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     }, {
         MFF_TCP_DST, "tcp_dst", "tp_dst",
         MF_FIELD_SIZES(be16),
-        MFM_NONE, FWW_TP_DST,
+        MFM_FULLY, 0,
         MFS_DECIMAL,
         MFP_TCP,
         true,
@@ -308,7 +308,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     {
         MFF_UDP_SRC, "udp_src", NULL,
         MF_FIELD_SIZES(be16),
-        MFM_NONE, FWW_TP_SRC,
+        MFM_FULLY, 0,
         MFS_DECIMAL,
         MFP_UDP,
         true,
@@ -316,7 +316,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     }, {
         MFF_UDP_DST, "udp_dst", NULL,
         MF_FIELD_SIZES(be16),
-        MFM_NONE, FWW_TP_DST,
+        MFM_FULLY, 0,
         MFS_DECIMAL,
         MFP_UDP,
         true,
@@ -326,7 +326,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     {
         MFF_ICMPV4_TYPE, "icmp_type", NULL,
         MF_FIELD_SIZES(u8),
-        MFM_NONE, FWW_TP_SRC,
+        MFM_NONE, 0,
         MFS_DECIMAL,
         MFP_ICMPV4,
         false,
@@ -334,7 +334,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     }, {
         MFF_ICMPV4_CODE, "icmp_code", NULL,
         MF_FIELD_SIZES(u8),
-        MFM_NONE, FWW_TP_DST,
+        MFM_NONE, 0,
         MFS_DECIMAL,
         MFP_ICMPV4,
         false,
@@ -344,7 +344,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     {
         MFF_ICMPV6_TYPE, "icmpv6_type", NULL,
         MF_FIELD_SIZES(u8),
-        MFM_NONE, FWW_TP_SRC,
+        MFM_NONE, 0,
         MFS_DECIMAL,
         MFP_ICMPV6,
         false,
@@ -352,7 +352,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     }, {
         MFF_ICMPV6_CODE, "icmpv6_code", NULL,
         MF_FIELD_SIZES(u8),
-        MFM_NONE, FWW_TP_DST,
+        MFM_NONE, 0,
         MFS_DECIMAL,
         MFP_ICMPV6,
         false,
@@ -509,14 +509,6 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
     case MFF_ARP_THA:
-    case MFF_TCP_SRC:
-    case MFF_TCP_DST:
-    case MFF_UDP_SRC:
-    case MFF_UDP_DST:
-    case MFF_ICMPV4_TYPE:
-    case MFF_ICMPV4_CODE:
-    case MFF_ICMPV6_TYPE:
-    case MFF_ICMPV6_CODE:
     case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
@@ -575,6 +567,17 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_ARP_TPA:
         return !wc->nw_dst_mask;
 
+    case MFF_TCP_SRC:
+    case MFF_UDP_SRC:
+    case MFF_ICMPV4_TYPE:
+    case MFF_ICMPV6_TYPE:
+        return !wc->tp_src_mask;
+    case MFF_TCP_DST:
+    case MFF_UDP_DST:
+    case MFF_ICMPV4_CODE:
+    case MFF_ICMPV6_CODE:
+        return !wc->tp_dst_mask;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -603,14 +606,6 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
     case MFF_ARP_THA:
-    case MFF_TCP_SRC:
-    case MFF_TCP_DST:
-    case MFF_UDP_SRC:
-    case MFF_UDP_DST:
-    case MFF_ICMPV4_TYPE:
-    case MFF_ICMPV4_CODE:
-    case MFF_ICMPV6_TYPE:
-    case MFF_ICMPV6_CODE:
     case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
@@ -683,6 +678,24 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
         mask->be32 = wc->nw_dst_mask;
         break;
 
+    case MFF_TCP_SRC:
+    case MFF_UDP_SRC:
+        mask->be16 = wc->tp_src_mask;
+        break;
+    case MFF_TCP_DST:
+    case MFF_UDP_DST:
+        mask->be16 = wc->tp_dst_mask;
+        break;
+
+    case MFF_ICMPV4_TYPE:
+    case MFF_ICMPV6_TYPE:
+        mask->u8 = ntohs(wc->tp_src_mask);
+        break;
+    case MFF_ICMPV4_CODE:
+    case MFF_ICMPV6_CODE:
+        mask->u8 = ntohs(wc->tp_dst_mask);
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -1485,7 +1498,7 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
     case MFF_UDP_SRC:
     case MFF_ICMPV4_TYPE:
     case MFF_ICMPV6_TYPE:
-        rule->wc.wildcards |= FWW_TP_SRC;
+        rule->wc.tp_src_mask = htons(0);
         rule->flow.tp_src = htons(0);
         break;
 
@@ -1493,7 +1506,7 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
     case MFF_UDP_DST:
     case MFF_ICMPV4_CODE:
     case MFF_ICMPV6_CODE:
-        rule->wc.wildcards |= FWW_TP_DST;
+        rule->wc.tp_dst_mask = htons(0);
         rule->flow.tp_dst = htons(0);
         break;
 
@@ -1546,10 +1559,6 @@ mf_set(const struct mf_field *mf,
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
     case MFF_ARP_THA:
-    case MFF_TCP_SRC:
-    case MFF_TCP_DST:
-    case MFF_UDP_SRC:
-    case MFF_UDP_DST:
     case MFF_ICMPV4_TYPE:
     case MFF_ICMPV4_CODE:
     case MFF_ICMPV6_TYPE:
@@ -1623,6 +1632,16 @@ mf_set(const struct mf_field *mf,
         cls_rule_set_nw_dst_masked(rule, value->be32, mask->be32);
         break;
 
+    case MFF_TCP_SRC:
+    case MFF_UDP_SRC:
+        cls_rule_set_tp_src_masked(rule, value->be16, mask->be16);
+        break;
+
+    case MFF_TCP_DST:
+    case MFF_UDP_DST:
+        cls_rule_set_tp_dst_masked(rule, value->be16, mask->be16);
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -2126,25 +2145,48 @@ mf_format(const struct mf_field *mf,
     }
 }
 \f
-/* Makes a subfield starting at bit offset 'ofs' and continuing for 'n_bits' in
- * 'rule''s field 'mf' exactly match the 'n_bits' least-significant bits of
- * 'x'.
+/* Makes subfield 'sf' within 'rule' exactly match the 'sf->n_bits'
+ * least-significant bits in 'x'.
+ *
+ * See mf_set_subfield() for an example.
+ *
+ * The difference between this function and mf_set_subfield() is that the
+ * latter function can only handle subfields up to 64 bits wide, whereas this
+ * one handles the general case.  On the other hand, mf_set_subfield() is
+ * arguably easier to use. */
+void
+mf_write_subfield(const struct mf_subfield *sf, const union mf_subvalue *x,
+                  struct cls_rule *rule)
+{
+    const struct mf_field *field = sf->field;
+    union mf_value value, mask;
+
+    mf_get(field, rule, &value, &mask);
+    bitwise_copy(x, sizeof *x, 0, &value, field->n_bytes, sf->ofs, sf->n_bits);
+    bitwise_one (                 &mask,  field->n_bytes, sf->ofs, sf->n_bits);
+    mf_set(field, &value, &mask, rule);
+}
+
+/* Makes subfield 'sf' within 'rule' exactly match the 'sf->n_bits'
+ * least-significant bits of 'x'.
  *
- * Example: suppose that 'mf' is originally the following 2-byte field in
- * 'rule':
+ * Example: suppose that 'sf->field' is originally the following 2-byte field
+ * in 'rule':
  *
  *     value == 0xe00a == 2#1110000000001010
  *      mask == 0xfc3f == 2#1111110000111111
  *
- * The call mf_set_subfield(mf, 0x55, 8, 7, rule) would have the following
- * effect (note that 0x55 is 2#1010101):
+ * The call mf_set_subfield(sf, 0x55, 8, 7, rule), where sf->ofs == 8 and
+ * sf->n_bits == 7 would have the following effect (note that 0x55 is
+ * 2#1010101):
  *
  *     value == 0xd50a == 2#1101010100001010
  *      mask == 0xff3f == 2#1111111100111111
+ *                           ^^^^^^^ affected bits
  *
  * The caller is responsible for ensuring that the result will be a valid
- * wildcard pattern for 'mf'.  The caller is responsible for ensuring that
- * 'rule' meets 'mf''s prerequisites. */
+ * wildcard pattern for 'sf->field'.  The caller is responsible for ensuring
+ * that 'rule' meets 'sf->field''s prerequisites. */
 void
 mf_set_subfield(const struct mf_subfield *sf, uint64_t x,
                 struct cls_rule *rule)
@@ -2199,6 +2241,22 @@ mf_set_subfield_value(const struct mf_subfield *sf, uint64_t x,
     }
 }
 
+/* Initializes 'x' to the value of 'sf' within 'flow'.  'sf' must be valid for
+ * reading 'flow', e.g. as checked by mf_check_src(). */
+void
+mf_read_subfield(const struct mf_subfield *sf, const struct flow *flow,
+                 union mf_subvalue *x)
+{
+    union mf_value value;
+
+    mf_get_value(sf->field, flow, &value);
+
+    memset(x, 0, sizeof *x);
+    bitwise_copy(&value, sf->field->n_bytes, sf->ofs,
+                 x, sizeof *x, 0,
+                 sf->n_bits);
+}
+
 /* Returns the value of 'sf' within 'flow'.  'sf' must be valid for reading
  * 'flow', e.g. as checked by mf_check_src() and sf->n_bits must be 64 or
  * less. */
@@ -2228,7 +2286,7 @@ mf_format_subfield(const struct mf_subfield *sf, struct ds *s)
         ds_put_cstr(s, sf->field->name);
     }
 
-    if (sf->ofs == 0 && sf->n_bits == sf->field->n_bits) {
+    if (sf->field && sf->ofs == 0 && sf->n_bits == sf->field->n_bits) {
         ds_put_cstr(s, "[]");
     } else if (sf->n_bits == 1) {
         ds_put_format(s, "[%d]", sf->ofs);