Merge branch 'mainstream'
[sliver-openvswitch.git] / lib / odp-util.c
index 62cc638..873e05a 100644 (file)
@@ -26,6 +26,7 @@
 #include <string.h>
 #include "byte-order.h"
 #include "coverage.h"
+#include "dpif.h"
 #include "dynamic-string.h"
 #include "flow.h"
 #include "netlink.h"
@@ -378,7 +379,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
 
     expected_len = odp_action_len(nl_attr_type(a));
     if (expected_len != -2 && nl_attr_get_size(a) != expected_len) {
-        ds_put_format(ds, "bad length %zu, expected %d for: ",
+        ds_put_format(ds, "bad length %"PRIuSIZE", expected %d for: ",
                       nl_attr_get_size(a), expected_len);
         format_generic_odp_action(ds, a);
         return;
@@ -845,7 +846,7 @@ odp_tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
         return ODP_FIT_ERROR;
     }
     if (unknown) {
-            return ODP_FIT_TOO_MUCH;
+        return ODP_FIT_TOO_MUCH;
     }
     return ODP_FIT_PERFECT;
 }
@@ -977,14 +978,14 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
 
             if (bad_key_len || bad_mask_len) {
                 if (bad_key_len) {
-                    ds_put_format(ds, "(bad key length %zu, expected %d)(",
+                    ds_put_format(ds, "(bad key length %"PRIuSIZE", expected %d)(",
                                   nl_attr_get_size(a),
                                   odp_flow_key_attr_len(nl_attr_type(a)));
                 }
                 format_generic_odp_key(a, ds);
                 if (bad_mask_len) {
                     ds_put_char(ds, '/');
-                    ds_put_format(ds, "(bad mask length %zu, expected %d)(",
+                    ds_put_format(ds, "(bad mask length %"PRIuSIZE", expected %d)(",
                                   nl_attr_get_size(ma),
                                   odp_flow_key_attr_len(nl_attr_type(ma)));
                 }
@@ -2596,6 +2597,74 @@ odp_flow_key_from_mask(struct ofpbuf *buf, const struct flow *mask,
     odp_flow_key_from_flow__(buf, mask, flow, u32_to_odp(odp_in_port_mask));
 }
 
+/* Generate ODP flow key from the given packet metadata */
+void
+odp_key_from_pkt_metadata(struct ofpbuf *buf, const struct pkt_metadata *md)
+{
+    nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, md->skb_priority);
+
+    if (md->tunnel.ip_dst) {
+        tun_key_to_attr(buf, &md->tunnel);
+    }
+
+    nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, md->pkt_mark);
+
+    /* Add an ingress port attribute if 'odp_in_port' is not the magical
+     * value "ODPP_NONE". */
+    if (md->in_port != ODPP_NONE) {
+        nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, md->in_port);
+    }
+}
+
+/* Generate packet metadata from the given ODP flow key. */
+void
+odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
+                        struct pkt_metadata *md)
+{
+    const struct nlattr *nla;
+    size_t left;
+    uint32_t wanted_attrs = 1u << OVS_KEY_ATTR_PRIORITY |
+        1u << OVS_KEY_ATTR_SKB_MARK | 1u << OVS_KEY_ATTR_TUNNEL |
+        1u << OVS_KEY_ATTR_IN_PORT;
+
+    memset(md, 0, sizeof *md);
+    md->in_port = ODPP_NONE;
+
+    NL_ATTR_FOR_EACH (nla, left, key, key_len) {
+        uint16_t type = nl_attr_type(nla);
+        size_t len = nl_attr_get_size(nla);
+        int expected_len = odp_flow_key_attr_len(type);
+
+        if (len != expected_len && expected_len >= 0) {
+            continue;
+        }
+
+        if (type == OVS_KEY_ATTR_PRIORITY) {
+            md->skb_priority = nl_attr_get_u32(nla);
+            wanted_attrs &= ~(1u << OVS_KEY_ATTR_PRIORITY);
+        } else if (type == OVS_KEY_ATTR_SKB_MARK) {
+            md->pkt_mark = nl_attr_get_u32(nla);
+            wanted_attrs &= ~(1u << OVS_KEY_ATTR_SKB_MARK);
+        } else if (type == OVS_KEY_ATTR_TUNNEL) {
+            enum odp_key_fitness res;
+
+            res = odp_tun_key_from_attr(nla, &md->tunnel);
+            if (res == ODP_FIT_ERROR) {
+                memset(&md->tunnel, 0, sizeof md->tunnel);
+            } else if (res == ODP_FIT_PERFECT) {
+                wanted_attrs &= ~(1u << OVS_KEY_ATTR_TUNNEL);
+            }
+        } else if (type == OVS_KEY_ATTR_IN_PORT) {
+            md->in_port = nl_attr_get_odp_port(nla);
+            wanted_attrs &= ~(1u << OVS_KEY_ATTR_IN_PORT);
+        }
+
+        if (!wanted_attrs) {
+            return; /* Have everything. */
+        }
+    }
+}
+
 uint32_t
 odp_flow_key_hash(const struct nlattr *key, size_t key_len)
 {
@@ -2676,7 +2745,7 @@ parse_flow_nlattrs(const struct nlattr *key, size_t key_len,
         if (len != expected_len && expected_len >= 0) {
             char namebuf[OVS_KEY_ATTR_BUFSIZE];
 
-            VLOG_ERR_RL(&rl, "attribute %s has length %zu but should have "
+            VLOG_ERR_RL(&rl, "attribute %s has length %"PRIuSIZE" but should have "
                         "length %d", ovs_key_attr_to_string(type, namebuf,
                                                             sizeof namebuf),
                         len, expected_len);
@@ -2871,7 +2940,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     } else {
         goto done;
     }
-    if (is_mask) {
+    if (check_len > 0) { /* Happens only when 'is_mask'. */
         if (!is_all_zeros(check_start, check_len) &&
             flow->dl_type != htons(0xffff)) {
             return ODP_FIT_ERROR;
@@ -3035,7 +3104,9 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     if (!is_mask && !(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN))) {
         return ODP_FIT_TOO_LITTLE;
     } else {
-        tci = nl_attr_get_be16(attrs[OVS_KEY_ATTR_VLAN]);
+        tci = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN)
+               ? nl_attr_get_be16(attrs[OVS_KEY_ATTR_VLAN])
+               : htons(0));
         if (!is_mask) {
             if (tci == htons(0)) {
                 /* Corner case for a truncated 802.1Q header. */
@@ -3146,8 +3217,9 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
         return ODP_FIT_ERROR;
     }
 
-    if ((is_mask && (src_flow->vlan_tci & htons(VLAN_CFI))) ||
-        (!is_mask && src_flow->dl_type == htons(ETH_TYPE_VLAN))) {
+    if (is_mask
+        ? (src_flow->vlan_tci & htons(VLAN_CFI)) != 0
+        : src_flow->dl_type == htons(ETH_TYPE_VLAN)) {
         return parse_8021q_onward(attrs, present_attrs, out_of_range_attr,
                                   expected_attrs, flow, key, key_len, src_flow);
     }
@@ -3383,7 +3455,7 @@ commit_mpls_action(const struct flow *flow, struct flow *base,
         break;
     }
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     base->dl_type = flow->dl_type;