+/* Consider the two value/mask pairs 'a_value/a_mask' and 'b_value/b_mask' as
+ * restrictions on a field's value. Then, this function initializes
+ * 'dst_value/dst_mask' such that it combines the restrictions of both pairs.
+ * This is not always possible, i.e. if one pair insists on a value of 0 in
+ * some bit and the other pair insists on a value of 1 in that bit. This
+ * function returns false in a case where the combined restriction is
+ * impossible (in which case 'dst_value/dst_mask' is not fully initialized),
+ * true otherwise.
+ *
+ * (As usually true for value/mask pairs in OVS, any 1-bit in a value must have
+ * a corresponding 1-bit in its mask.) */
+bool
+mf_subvalue_intersect(const union mf_subvalue *a_value,
+ const union mf_subvalue *a_mask,
+ const union mf_subvalue *b_value,
+ const union mf_subvalue *b_mask,
+ union mf_subvalue *dst_value,
+ union mf_subvalue *dst_mask)
+{
+ for (int i = 0; i < ARRAY_SIZE(a_value->be64); i++) {
+ ovs_be64 av = a_value->be64[i];
+ ovs_be64 am = a_mask->be64[i];
+ ovs_be64 bv = b_value->be64[i];
+ ovs_be64 bm = b_mask->be64[i];
+ ovs_be64 *dv = &dst_value->be64[i];
+ ovs_be64 *dm = &dst_mask->be64[i];
+
+ if ((av ^ bv) & (am & bm)) {
+ return false;
+ }
+ *dv = av | bv;
+ *dm = am | bm;
+ }
+ return true;
+}
+
+/* Returns the "number of bits" in 'v', e.g. 1 if only the lowest-order bit is
+ * set, 2 if the second-lowest-order bit is set, and so on. */
+int
+mf_subvalue_width(const union mf_subvalue *v)
+{
+ return 1 + bitwise_rscan(v, sizeof *v, true, sizeof *v * 8 - 1, -1);
+}
+
+/* For positive 'n', shifts the bits in 'value' 'n' bits to the left, and for
+ * negative 'n', shifts the bits '-n' bits to the right. */
+void
+mf_subvalue_shift(union mf_subvalue *value, int n)
+{
+ if (n) {
+ union mf_subvalue tmp;
+ memset(&tmp, 0, sizeof tmp);
+
+ if (n > 0 && n < 8 * sizeof tmp) {
+ bitwise_copy(value, sizeof *value, 0,
+ &tmp, sizeof tmp, n,
+ 8 * sizeof tmp - n);
+ } else if (n < 0 && n > -8 * sizeof tmp) {
+ bitwise_copy(value, sizeof *value, -n,
+ &tmp, sizeof tmp, 0,
+ 8 * sizeof tmp + n);
+ }
+ *value = tmp;
+ }
+}
+
+/* Appends a formatted representation of 'sv' to 's'. */
+void
+mf_subvalue_format(const union mf_subvalue *sv, struct ds *s)
+{
+ ds_put_hex(s, sv, sizeof *sv);
+}
+