- ds_put_format(ds, "tunnel%08"PRIx32":in_port%04"PRIx16
- ":vlan%"PRIu16":pcp%"PRIu8
- " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT
- " type%04"PRIx16
- " proto%"PRIu8
- " tos%"PRIu8
- " ip"IP_FMT"->"IP_FMT
- " port%"PRIu16"->%"PRIu16,
- ntohl(flow->tun_id),
- flow->in_port,
- ntohs(flow->dl_vlan),
- flow->dl_vlan_pcp,
- ETH_ADDR_ARGS(flow->dl_src),
- ETH_ADDR_ARGS(flow->dl_dst),
- ntohs(flow->dl_type),
- flow->nw_proto,
- flow->nw_tos,
- IP_ARGS(&flow->nw_src),
- IP_ARGS(&flow->nw_dst),
- ntohs(flow->tp_src),
- ntohs(flow->tp_dst));
+ /* If you change struct flow_wildcards and thereby trigger this
+ * assertion, please check that the new struct flow_wildcards has no holes
+ * in it before you update the assertion. */
+ BUILD_ASSERT_DECL(sizeof *wc == 56 + FLOW_N_REGS * 4);
+ return hash_bytes(wc, sizeof *wc, 0);
+}
+
+/* Returns true if 'a' and 'b' represent the same wildcards, false if they are
+ * different. */
+bool
+flow_wildcards_equal(const struct flow_wildcards *a,
+ const struct flow_wildcards *b)
+{
+ int i;
+
+ if (a->wildcards != b->wildcards
+ || a->tun_id_mask != b->tun_id_mask
+ || a->nw_src_mask != b->nw_src_mask
+ || a->nw_dst_mask != b->nw_dst_mask
+ || a->vlan_tci_mask != b->vlan_tci_mask
+ || !ipv6_addr_equals(&a->ipv6_src_mask, &b->ipv6_src_mask)
+ || !ipv6_addr_equals(&a->ipv6_dst_mask, &b->ipv6_dst_mask)) {
+ return false;
+ }
+
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ if (a->reg_masks[i] != b->reg_masks[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Returns true if at least one bit or field is wildcarded in 'a' but not in
+ * 'b', false otherwise. */
+bool
+flow_wildcards_has_extra(const struct flow_wildcards *a,
+ const struct flow_wildcards *b)
+{
+ int i;
+ struct in6_addr ipv6_masked;
+
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ if ((a->reg_masks[i] & b->reg_masks[i]) != b->reg_masks[i]) {
+ return true;
+ }
+ }
+
+ ipv6_masked = ipv6_addr_bitand(&a->ipv6_src_mask, &b->ipv6_src_mask);
+ if (!ipv6_addr_equals(&ipv6_masked, &b->ipv6_src_mask)) {
+ return true;
+ }
+
+ ipv6_masked = ipv6_addr_bitand(&a->ipv6_dst_mask, &b->ipv6_dst_mask);
+ if (!ipv6_addr_equals(&ipv6_masked, &b->ipv6_dst_mask)) {
+ return true;
+ }
+
+ return (a->wildcards & ~b->wildcards
+ || (a->tun_id_mask & b->tun_id_mask) != b->tun_id_mask
+ || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
+ || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask
+ || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask);
+}
+
+static bool
+set_nw_mask(ovs_be32 *maskp, ovs_be32 mask)
+{
+ if (ip_is_cidr(mask)) {
+ *maskp = mask;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* Sets the IP (or ARP) source wildcard mask to CIDR 'mask' (consisting of N
+ * high-order 1-bit and 32-N low-order 0-bits). Returns true if successful,
+ * false if 'mask' is not a CIDR mask. */
+bool
+flow_wildcards_set_nw_src_mask(struct flow_wildcards *wc, ovs_be32 mask)
+{
+ return set_nw_mask(&wc->nw_src_mask, mask);
+}
+
+/* Sets the IP (or ARP) destination wildcard mask to CIDR 'mask' (consisting of
+ * N high-order 1-bit and 32-N low-order 0-bits). Returns true if successful,
+ * false if 'mask' is not a CIDR mask. */
+bool
+flow_wildcards_set_nw_dst_mask(struct flow_wildcards *wc, ovs_be32 mask)
+{
+ return set_nw_mask(&wc->nw_dst_mask, mask);