meta-flow: New functions for reading and writing generalized subfields.
authorBen Pfaff <blp@nicira.com>
Wed, 11 Apr 2012 21:45:34 +0000 (14:45 -0700)
committerBen Pfaff <blp@nicira.com>
Sat, 14 Apr 2012 04:36:53 +0000 (21:36 -0700)
The existing functions for reading and writing the values of subfields only
handle subfields up to 64 bits wide.  These new functions handle subfields
of any width.

Also update some existing comments.

Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/meta-flow.c
lib/meta-flow.h

index 0e4e2f8..8706d4a 100644 (file)
@@ -2145,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'.
  *
- * Example: suppose that 'mf' is originally the following 2-byte field in
- * 'rule':
+ * 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 '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)
@@ -2218,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. */
index 4917834..efa9bad 100644 (file)
@@ -198,6 +198,7 @@ union mf_value {
     uint8_t mac[ETH_ADDR_LEN];
     struct in6_addr ipv6;
 };
+BUILD_ASSERT_DECL(sizeof(union mf_value) == 16);
 
 /* Part of a field. */
 struct mf_subfield {
@@ -206,6 +207,19 @@ struct mf_subfield {
     unsigned int n_bits;        /* Number of bits. */
 };
 
+/* Data for some part of an mf_field.
+ *
+ * The data is stored "right-justified".  For example, if "union mf_subvalue
+ * value" contains NXM_OF_VLAN_TCI[0..11], then one could access the
+ * corresponding data in value.be16[7] as the bits in the mask htons(0xfff). */
+union mf_subvalue {
+    uint8_t u8[16];
+    ovs_be16 be16[8];
+    ovs_be32 be32[4];
+    ovs_be64 be64[2];
+};
+BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue));
+
 /* Finding mf_fields. */
 const struct mf_field *mf_from_id(enum mf_field_id);
 const struct mf_field *mf_from_name(const char *name);
@@ -244,12 +258,18 @@ void mf_set_wild(const struct mf_field *, struct cls_rule *);
 void mf_random_value(const struct mf_field *, union mf_value *value);
 
 /* Subfields. */
+void mf_write_subfield(const struct mf_subfield *, const union mf_subvalue *,
+                       struct cls_rule *);
 void mf_set_subfield(const struct mf_subfield *, uint64_t value,
                      struct cls_rule *);
 void mf_set_subfield_value(const struct mf_subfield *, uint64_t value,
                            struct flow *);
+
+void mf_read_subfield(const struct mf_subfield *, const struct flow *,
+                      union mf_subvalue *);
 uint64_t mf_get_subfield(const struct mf_subfield *, const struct flow *);
 
+
 void mf_format_subfield(const struct mf_subfield *, struct ds *);
 char *mf_parse_subfield__(struct mf_subfield *sf, const char **s);
 const char *mf_parse_subfield(struct mf_subfield *, const char *);