odp-util: fix bug in setting ipv4 frag flag mask
[sliver-openvswitch.git] / lib / odp-util.c
index 14994a9..daf0c5c 100644 (file)
@@ -144,8 +144,9 @@ static void
 format_odp_sample_action(struct ds *ds, const struct nlattr *attr)
 {
     static const struct nl_policy ovs_sample_policy[] = {
-        [OVS_SAMPLE_ATTR_PROBABILITY] = { .type = NL_A_U32 },
-        [OVS_SAMPLE_ATTR_ACTIONS] = { .type = NL_A_NESTED }
+        { NL_A_NO_ATTR, 0, 0, false }, /* OVS_SAMPLE_ATTR_UNSPEC */
+        { NL_A_U32, 0, 0, false },     /* OVS_SAMPLE_ATTR_PROBABILITY */
+        { NL_A_NESTED, 0, 0, false },  /* OVS_SAMPLE_ATTR_ACTIONS */
     };
     struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
     double percentage;
@@ -259,9 +260,9 @@ static void
 format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
 {
     static const struct nl_policy ovs_userspace_policy[] = {
-        [OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 },
-        [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_UNSPEC,
-                                          .optional = true },
+        { NL_A_NO_ATTR, 0, 0, false }, /* OVS_USERSPACE_ATTR_UNSPEC */
+        { NL_A_U32, 0, 0, false },     /* OVS_USERSPACE_ATTR_PID */
+        { NL_A_UNSPEC, 0, 0, true },   /* OVS_USERSPACE_ATTR_USERDATA */
     };
     struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
     const struct nlattr *userdata_attr;
@@ -1058,7 +1059,7 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
             ovs_be16 vlan_tci = nl_attr_get_be16(a);
             if (!is_exact) {
                 ovs_be16 mask = nl_attr_get_be16(ma);
-                ds_put_format(ds, "vid=%"PRIu16"/%"PRIx16",pcp=%d/0x%x,cfi=%d/%d",
+                ds_put_format(ds, "vid=%"PRIu16"/0x%"PRIx16",pcp=%d/0x%x,cfi=%d/%d",
                               vlan_tci_to_vid(vlan_tci),
                               vlan_tci_to_vid(mask),
                               vlan_tci_to_pcp(vlan_tci),
@@ -2310,6 +2311,17 @@ ovs_to_odp_frag(uint8_t nw_frag)
           : OVS_FRAG_TYPE_LATER);
 }
 
+static uint8_t
+ovs_to_odp_frag_mask(uint8_t nw_frag_mask)
+{
+    uint8_t frag_mask = ~(OVS_FRAG_TYPE_FIRST | OVS_FRAG_TYPE_LATER);
+
+    frag_mask |= (nw_frag_mask & FLOW_NW_FRAG_ANY) ? OVS_FRAG_TYPE_FIRST : 0;
+    frag_mask |= (nw_frag_mask & FLOW_NW_FRAG_LATER) ? OVS_FRAG_TYPE_LATER : 0;
+
+    return frag_mask;
+}
+
 static void
 odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
                          const struct flow *flow, odp_port_t odp_in_port)
@@ -2373,7 +2385,7 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
          *                    802.3 SNAP packet with valid eth_type).
          */
         if (is_mask) {
-            nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, data->dl_type);
+            nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(UINT16_MAX));
         }
         goto unencap;
     }
@@ -2390,7 +2402,8 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
         ipv4_key->ipv4_proto = data->nw_proto;
         ipv4_key->ipv4_tos = data->nw_tos;
         ipv4_key->ipv4_ttl = data->nw_ttl;
-        ipv4_key->ipv4_frag = ovs_to_odp_frag(data->nw_frag);
+        ipv4_key->ipv4_frag = is_mask ? ovs_to_odp_frag_mask(data->nw_frag)
+                                      : ovs_to_odp_frag(data->nw_frag);
     } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         struct ovs_key_ipv6 *ipv6_key;
 
@@ -2402,7 +2415,8 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
         ipv6_key->ipv6_proto = data->nw_proto;
         ipv6_key->ipv6_tclass = data->nw_tos;
         ipv6_key->ipv6_hlimit = data->nw_ttl;
-        ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->nw_frag);
+        ipv6_key->ipv6_frag = is_mask ? ovs_to_odp_frag_mask(data->nw_frag)
+                                      : ovs_to_odp_frag(data->nw_frag);
     } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
                flow->dl_type == htons(ETH_TYPE_RARP)) {
         struct ovs_key_arp *arp_key;
@@ -2511,7 +2525,8 @@ uint32_t
 odp_flow_key_hash(const struct nlattr *key, size_t key_len)
 {
     BUILD_ASSERT_DECL(!(NLA_ALIGNTO % sizeof(uint32_t)));
-    return hash_words((const uint32_t *) key, key_len / sizeof(uint32_t), 0);
+    return hash_words(ALIGNED_CAST(const uint32_t *, key),
+                      key_len / sizeof(uint32_t), 0);
 }
 
 static void