+ } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+ flow->dl_type == htons(ETH_TYPE_RARP)) {
+ const struct arp_eth_header *arp = pull_arp(&b);
+ if (arp && arp->ar_hrd == htons(1)
+ && arp->ar_pro == htons(ETH_TYPE_IP)
+ && arp->ar_hln == ETH_ADDR_LEN
+ && arp->ar_pln == 4) {
+ /* We only match on the lower 8 bits of the opcode. */
+ if (ntohs(arp->ar_op) <= 0xff) {
+ flow->nw_proto = ntohs(arp->ar_op);
+ }
+
+ flow->nw_src = arp->ar_spa;
+ flow->nw_dst = arp->ar_tpa;
+ memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN);
+ memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN);
+ }
+ }
+}
+
+/* For every bit of a field that is wildcarded in 'wildcards', sets the
+ * corresponding bit in 'flow' to zero. */
+void
+flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
+{
+ uint32_t *flow_u32 = (uint32_t *) flow;
+ const uint32_t *wc_u32 = (const uint32_t *) &wildcards->masks;
+ size_t i;
+
+ for (i = 0; i < FLOW_U32S; i++) {
+ flow_u32[i] &= wc_u32[i];
+ }
+}
+
+/* Initializes 'fmd' with the metadata found in 'flow'. */
+void
+flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
+{
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
+
+ fmd->tun_id = flow->tunnel.tun_id;
+ fmd->tun_src = flow->tunnel.ip_src;
+ fmd->tun_dst = flow->tunnel.ip_dst;
+ fmd->metadata = flow->metadata;
+ memcpy(fmd->regs, flow->regs, sizeof fmd->regs);
+ fmd->pkt_mark = flow->pkt_mark;
+ fmd->in_port = flow->in_port.ofp_port;
+}
+
+char *
+flow_to_string(const struct flow *flow)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ flow_format(&ds, flow);
+ return ds_cstr(&ds);
+}
+
+const char *
+flow_tun_flag_to_string(uint32_t flags)
+{
+ switch (flags) {
+ case FLOW_TNL_F_DONT_FRAGMENT:
+ return "df";
+ case FLOW_TNL_F_CSUM:
+ return "csum";
+ case FLOW_TNL_F_KEY:
+ return "key";
+ default:
+ return NULL;
+ }
+}
+
+void
+format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
+ uint32_t flags, char del)
+{
+ uint32_t bad = 0;
+
+ if (!flags) {
+ return;
+ }
+ while (flags) {
+ uint32_t bit = rightmost_1bit(flags);
+ const char *s;
+
+ s = bit_to_string(bit);
+ if (s) {
+ ds_put_format(ds, "%s%c", s, del);
+ } else {
+ bad |= bit;
+ }
+
+ flags &= ~bit;
+ }
+
+ if (bad) {
+ ds_put_format(ds, "0x%"PRIx32"%c", bad, del);
+ }
+ ds_chomp(ds, del);
+}
+
+void
+flow_format(struct ds *ds, const struct flow *flow)
+{
+ struct match match;
+
+ match_wc_init(&match, flow);
+ match_format(&match, ds, OFP_DEFAULT_PRIORITY);
+}
+
+void
+flow_print(FILE *stream, const struct flow *flow)
+{
+ char *s = flow_to_string(flow);
+ fputs(s, stream);
+ free(s);
+}
+\f
+/* flow_wildcards functions. */
+
+/* Initializes 'wc' as a set of wildcards that matches every packet. */
+void
+flow_wildcards_init_catchall(struct flow_wildcards *wc)
+{
+ memset(&wc->masks, 0, sizeof wc->masks);
+}
+
+/* Initializes 'wc' as an exact-match set of wildcards; that is, 'wc' does not
+ * wildcard any bits or fields. */
+void
+flow_wildcards_init_exact(struct flow_wildcards *wc)
+{
+ memset(&wc->masks, 0xff, sizeof wc->masks);
+ memset(wc->masks.zeros, 0, sizeof wc->masks.zeros);
+}
+
+/* Returns true if 'wc' matches every packet, false if 'wc' fixes any bits or
+ * fields. */
+bool
+flow_wildcards_is_catchall(const struct flow_wildcards *wc)
+{
+ const uint32_t *wc_u32 = (const uint32_t *) &wc->masks;
+ size_t i;
+
+ for (i = 0; i < FLOW_U32S; i++) {
+ if (wc_u32[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/* Sets 'dst' as the bitwise AND of wildcards in 'src1' and 'src2'.
+ * That is, a bit or a field is wildcarded in 'dst' if it is wildcarded
+ * in 'src1' or 'src2' or both. */
+void
+flow_wildcards_and(struct flow_wildcards *dst,
+ const struct flow_wildcards *src1,
+ const struct flow_wildcards *src2)
+{
+ uint32_t *dst_u32 = (uint32_t *) &dst->masks;
+ const uint32_t *src1_u32 = (const uint32_t *) &src1->masks;
+ const uint32_t *src2_u32 = (const uint32_t *) &src2->masks;
+ size_t i;
+
+ for (i = 0; i < FLOW_U32S; i++) {
+ dst_u32[i] = src1_u32[i] & src2_u32[i];
+ }
+}
+
+/* Sets 'dst' as the bitwise OR of wildcards in 'src1' and 'src2'. That
+ * is, a bit or a field is wildcarded in 'dst' if it is neither
+ * wildcarded in 'src1' nor 'src2'. */
+void
+flow_wildcards_or(struct flow_wildcards *dst,
+ const struct flow_wildcards *src1,
+ const struct flow_wildcards *src2)
+{
+ uint32_t *dst_u32 = (uint32_t *) &dst->masks;
+ const uint32_t *src1_u32 = (const uint32_t *) &src1->masks;
+ const uint32_t *src2_u32 = (const uint32_t *) &src2->masks;
+ size_t i;
+
+ for (i = 0; i < FLOW_U32S; i++) {
+ dst_u32[i] = src1_u32[i] | src2_u32[i];
+ }
+}
+
+/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent
+ * fields in 'dst', storing the result in 'dst'. */
+static void
+flow_union_with_miniflow(struct flow *dst, const struct miniflow *src)
+{
+ uint32_t *dst_u32 = (uint32_t *) dst;
+ int ofs;
+ int i;
+
+ ofs = 0;
+ for (i = 0; i < MINI_N_MAPS; i++) {
+ uint32_t map;
+
+ for (map = src->map[i]; map; map = zero_rightmost_1bit(map)) {
+ dst_u32[raw_ctz(map) + i * 32] |= src->values[ofs++];
+ }
+ }
+}
+
+/* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask. */
+void
+flow_wildcards_fold_minimask(struct flow_wildcards *wc,
+ const struct minimask *mask)
+{
+ flow_union_with_miniflow(&wc->masks, &mask->masks);
+}
+
+/* Returns a hash of the wildcards in 'wc'. */
+uint32_t
+flow_wildcards_hash(const struct flow_wildcards *wc, uint32_t basis)
+{
+ return flow_hash(&wc->masks, basis);
+}
+
+/* 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)
+{
+ return flow_equal(&a->masks, &b->masks);
+}
+
+/* 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)
+{
+ const uint32_t *a_u32 = (const uint32_t *) &a->masks;
+ const uint32_t *b_u32 = (const uint32_t *) &b->masks;
+ size_t i;
+
+ for (i = 0; i < FLOW_U32S; i++) {
+ if ((a_u32[i] & b_u32[i]) != b_u32[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Returns true if 'a' and 'b' are equal, except that 0-bits (wildcarded bits)
+ * in 'wc' do not need to be equal in 'a' and 'b'. */
+bool
+flow_equal_except(const struct flow *a, const struct flow *b,
+ const struct flow_wildcards *wc)
+{
+ const uint32_t *a_u32 = (const uint32_t *) a;
+ const uint32_t *b_u32 = (const uint32_t *) b;
+ const uint32_t *wc_u32 = (const uint32_t *) &wc->masks;
+ size_t i;
+
+ for (i = 0; i < FLOW_U32S; i++) {
+ if ((a_u32[i] ^ b_u32[i]) & wc_u32[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/* Sets the wildcard mask for register 'idx' in 'wc' to 'mask'.
+ * (A 0-bit indicates a wildcard bit.) */
+void
+flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
+{
+ wc->masks.regs[idx] = mask;
+}
+
+/* Hashes 'flow' based on its L2 through L4 protocol information. */
+uint32_t
+flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
+{
+ struct {
+ union {
+ ovs_be32 ipv4_addr;
+ struct in6_addr ipv6_addr;
+ };
+ ovs_be16 eth_type;
+ ovs_be16 vlan_tci;
+ ovs_be16 tp_port;
+ uint8_t eth_addr[ETH_ADDR_LEN];
+ uint8_t ip_proto;
+ } fields;
+
+ int i;
+
+ memset(&fields, 0, sizeof fields);
+ for (i = 0; i < ETH_ADDR_LEN; i++) {
+ fields.eth_addr[i] = flow->dl_src[i] ^ flow->dl_dst[i];
+ }
+ fields.vlan_tci = flow->vlan_tci & htons(VLAN_VID_MASK);
+ fields.eth_type = flow->dl_type;
+
+ /* UDP source and destination port are not taken into account because they
+ * will not necessarily be symmetric in a bidirectional flow. */
+ if (fields.eth_type == htons(ETH_TYPE_IP)) {
+ fields.ipv4_addr = flow->nw_src ^ flow->nw_dst;
+ fields.ip_proto = flow->nw_proto;
+ if (fields.ip_proto == IPPROTO_TCP) {
+ fields.tp_port = flow->tp_src ^ flow->tp_dst;
+ }
+ } else if (fields.eth_type == htons(ETH_TYPE_IPV6)) {
+ const uint8_t *a = &flow->ipv6_src.s6_addr[0];
+ const uint8_t *b = &flow->ipv6_dst.s6_addr[0];
+ uint8_t *ipv6_addr = &fields.ipv6_addr.s6_addr[0];
+
+ for (i=0; i<16; i++) {
+ ipv6_addr[i] = a[i] ^ b[i];
+ }
+ fields.ip_proto = flow->nw_proto;
+ if (fields.ip_proto == IPPROTO_TCP) {
+ fields.tp_port = flow->tp_src ^ flow->tp_dst;
+ }
+ }
+ return jhash_bytes(&fields, sizeof fields, basis);
+}