ofproto-dpif: Always un-wildcard 'dl_type'.
[sliver-openvswitch.git] / lib / flow.c
index 967f268..a42fea1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -229,9 +229,8 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
 
             /* We only process the first fragment. */
             if (frag_hdr->ip6f_offlg != htons(0)) {
-                if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) == htons(0)) {
-                    flow->nw_frag = FLOW_NW_FRAG_ANY;
-                } else {
+                flow->nw_frag = FLOW_NW_FRAG_ANY;
+                if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) {
                     flow->nw_frag |= FLOW_NW_FRAG_LATER;
                     nexthdr = IPPROTO_FRAGMENT;
                     break;
@@ -338,7 +337,7 @@ invalid:
 }
 
 /* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and
- * 'ofp_in_port'.
+ * 'in_port'.
  *
  * Initializes 'packet' header pointers as follows:
  *
@@ -358,7 +357,7 @@ invalid:
  */
 void
 flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
-             const struct flow_tnl *tnl, uint16_t ofp_in_port,
+             const struct flow_tnl *tnl, const union flow_in_port *in_port,
              struct flow *flow)
 {
     struct ofpbuf b = *packet;
@@ -372,7 +371,9 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
         ovs_assert(tnl != &flow->tunnel);
         flow->tunnel = *tnl;
     }
-    flow->in_port = ofp_in_port;
+    if (in_port) {
+        flow->in_port = *in_port;
+    }
     flow->skb_priority = skb_priority;
     flow->skb_mark = skb_mark;
 
@@ -404,33 +405,9 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
         parse_mpls(&b, flow);
     }
 
-    packet->l3 = b.data;
-    flow_extract_l3_onwards(packet, flow, flow->dl_type);
-}
-
-/* Initializes l3 and higher 'flow' members from 'packet'
- *
- * This should be called by or after flow_extract()
- *
- * Initializes 'packet' header pointers as follows:
- *
- *    - packet->l4 to just past the IPv4 header, if one is present and has a
- *      correct length, and otherwise NULL.
- *
- *    - packet->l7 to just past the TCP or UDP or ICMP header, if one is
- *      present and has a correct length, and otherwise NULL.
- */
-void
-flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow,
-                        ovs_be16 dl_type)
-{
-    struct ofpbuf b;
-
-    ofpbuf_use_const(&b, packet->l3, packet->size -
-                     (size_t)((char *)packet->l3 - (char *)packet->l2));
-
     /* Network layer. */
-    if (dl_type == htons(ETH_TYPE_IP)) {
+    packet->l3 = b.data;
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
         const struct ip_header *nh = pull_ip(&b);
         if (nh) {
             packet->l4 = b.data;
@@ -463,7 +440,7 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow,
                 }
             }
         }
-    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         if (parse_ipv6(&b, flow)) {
             return;
         }
@@ -478,8 +455,8 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow,
                 packet->l7 = b.data;
             }
         }
-    } else if (dl_type == htons(ETH_TYPE_ARP) ||
-               dl_type == htons(ETH_TYPE_RARP)) {
+    } 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)
@@ -516,12 +493,14 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
 void
 flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+    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->in_port = flow->in_port;
+    fmd->in_port = flow->in_port.ofp_port;
 }
 
 char *
@@ -627,13 +606,13 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
     return true;
 }
 
-/* Initializes 'dst' as the combination 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.  */
+/* 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_combine(struct flow_wildcards *dst,
-                       const struct flow_wildcards *src1,
-                       const struct flow_wildcards *src2)
+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;
@@ -645,6 +624,51 @@ flow_wildcards_combine(struct flow_wildcards *dst,
     }
 }
 
+/* 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)
@@ -755,6 +779,31 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
     return jhash_bytes(&fields, sizeof fields, basis);
 }
 
+/* Masks the fields in 'wc' that are used by the flow hash 'fields'. */
+void
+flow_mask_hash_fields(struct flow_wildcards *wc, enum nx_hash_fields fields)
+{
+    switch (fields) {
+    case NX_HASH_FIELDS_ETH_SRC:
+        memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+        break;
+
+    case NX_HASH_FIELDS_SYMMETRIC_L4:
+        memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+        memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+        memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+        memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+        memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+        wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
+        break;
+
+    default:
+        NOT_REACHED();
+    }
+}
+
 /* Hashes the portions of 'flow' designated by 'fields'. */
 uint32_t
 flow_hash_fields(const struct flow *flow, enum nx_hash_fields fields,
@@ -791,6 +840,24 @@ flow_hash_fields_valid(enum nx_hash_fields fields)
         || fields == NX_HASH_FIELDS_SYMMETRIC_L4;
 }
 
+/* Returns a hash value for the bits of 'flow' that are active based on
+ * 'wc', given 'basis'. */
+uint32_t
+flow_hash_in_wildcards(const struct flow *flow,
+                       const struct flow_wildcards *wc, uint32_t basis)
+{
+    const uint32_t *wc_u32 = (const uint32_t *) &wc->masks;
+    const uint32_t *flow_u32 = (const uint32_t *) flow;
+    uint32_t hash;
+    size_t i;
+
+    hash = basis;
+    for (i = 0; i < FLOW_U32S; i++) {
+        hash = mhash_add(hash, flow_u32[i] & wc_u32[i]);
+    }
+    return mhash_finish(hash, 4 * FLOW_U32S);
+}
+
 /* Sets the VLAN VID that 'flow' matches to 'vid', which is interpreted as an
  * OpenFlow 1.0 "dl_vlan" value:
  *
@@ -880,9 +947,6 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos)
 void
 flow_compose(struct ofpbuf *b, const struct flow *flow)
 {
-    ovs_be16 inner_dl_type;
-
-    inner_dl_type = flow_innermost_dl_type(flow);
     eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
     if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
         struct eth_header *eth = b->l2;
@@ -894,7 +958,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
         eth_push_vlan(b, flow->vlan_tci);
     }
 
-    if (inner_dl_type == htons(ETH_TYPE_IP)) {
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
         struct ip_header *ip;
 
         b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
@@ -940,10 +1004,10 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
         ip->ip_tot_len = htons((uint8_t *) b->data + b->size
                                - (uint8_t *) b->l3);
         ip->ip_csum = csum(ip, sizeof *ip);
-    } else if (inner_dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         /* XXX */
-    } else if (inner_dl_type == htons(ETH_TYPE_ARP) ||
-               inner_dl_type == htons(ETH_TYPE_RARP)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+               flow->dl_type == htons(ETH_TYPE_RARP)) {
         struct arp_eth_header *arp;
 
         b->l3 = arp = ofpbuf_put_zeros(b, sizeof *arp);
@@ -1050,20 +1114,8 @@ miniflow_destroy(struct miniflow *flow)
 void
 miniflow_expand(const struct miniflow *src, struct flow *dst)
 {
-    uint32_t *dst_u32 = (uint32_t *) dst;
-    int ofs;
-    int i;
-
-    memset(dst_u32, 0, sizeof *dst);
-
-    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++];
-        }
-    }
+    memset(dst, 0, sizeof *dst);
+    flow_union_with_miniflow(dst, src);
 }
 
 static const uint32_t *