Actions may provide information to allow further decoding of
a flow.

For example:

In the case of MPLS, L3 and L4 information may not initially be decoded
from the frame as the ethernet type of the frame is an MPLS type and no
information is known about the type of the inner frame.

However, the type of the inner frame may be provided by an mpls_pop action
in which case L3 and L4 information may be decoded providing a finer
grained match than is otherwise possible.

Signed-off-by: Simon Horman <ho...@verge.net.au>

---

v2.13
* No change

v2.12
* As suggested by Jarno Rajahalme
  - Use flow->encap_dl_type instead of of obtaining the value
    by scanning the actions.

v2.12
* No change

v2.11
* First post

fix
---
 lib/dpif-netdev.c      |    5 +++--
 lib/odp-util.c         |   37 ++++++++++++++++++++-----------------
 lib/odp-util.h         |    2 +-
 ofproto/ofproto-dpif.c |   36 ++++++++++++++++++++++++++++++++----
 tests/test-odp.c       |    2 +-
 5 files changed, 57 insertions(+), 25 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 3892ab7..ffb683c 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -879,7 +879,8 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void 
*state_,
         struct ofpbuf buf;
 
         ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf);
-        odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port);
+        odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port,
+                               htons(0));
 
         *key = buf.data;
         *key_len = buf.size;
@@ -1117,7 +1118,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const 
struct ofpbuf *packet,
 
     buf = &u->buf;
     ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
-    odp_flow_key_from_flow(buf, flow, flow->in_port);
+    odp_flow_key_from_flow(buf, flow, flow->in_port, htons(0));
     key_len = buf->size;
     ofpbuf_pull(buf, key_len);
     ofpbuf_reserve(buf, 2);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 48c82b0..88d2699 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1441,10 +1441,11 @@ odp_to_flow_flags(uint32_t tun_flags)
  * capable of being expanded to allow for that much space. */
 void
 odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
-                       uint32_t odp_in_port)
+                       uint32_t odp_in_port, ovs_be16 encap_dl_type)
 {
     struct ovs_key_ethernet *eth_key;
     size_t encap;
+    ovs_be16 dl_type;
 
     if (flow->skb_priority) {
         nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority);
@@ -1497,7 +1498,18 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow,
 
     nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, flow->dl_type);
 
-    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+    dl_type = flow->dl_type;
+
+    if (flow->mpls_depth) {
+        struct ovs_key_mpls *mpls_key;
+
+        mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS,
+                                            sizeof *mpls_key);
+        mpls_key->mpls_top_label = flow->mpls_lse;
+        dl_type = encap_dl_type;
+    }
+
+    if (dl_type == htons(ETH_TYPE_IP)) {
         struct ovs_key_ipv4 *ipv4_key;
 
         ipv4_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV4,
@@ -1508,7 +1520,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow,
         ipv4_key->ipv4_tos = flow->nw_tos;
         ipv4_key->ipv4_ttl = flow->nw_ttl;
         ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->nw_frag);
-    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
         struct ovs_key_ipv6 *ipv6_key;
 
         ipv6_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV6,
@@ -1520,8 +1532,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow,
         ipv6_key->ipv6_tclass = flow->nw_tos;
         ipv6_key->ipv6_hlimit = flow->nw_ttl;
         ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->nw_frag);
-    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
-               flow->dl_type == htons(ETH_TYPE_RARP)) {
+    } else if (dl_type == htons(ETH_TYPE_ARP) ||
+               dl_type == htons(ETH_TYPE_RARP)) {
         struct ovs_key_arp *arp_key;
 
         arp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ARP,
@@ -1534,16 +1546,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow,
         memcpy(arp_key->arp_tha, flow->arp_tha, ETH_ADDR_LEN);
     }
 
-    if (flow->mpls_depth) {
-        struct ovs_key_mpls *mpls_key;
-
-        mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS,
-                                            sizeof *mpls_key);
-        mpls_key->mpls_top_label = flow->mpls_lse;
-    }
-
-    if ((flow->dl_type == htons(ETH_TYPE_IP)
-         || flow->dl_type == htons(ETH_TYPE_IPV6))
+    if ((dl_type == htons(ETH_TYPE_IP) || dl_type == htons(ETH_TYPE_IPV6))
         && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
 
         if (flow->nw_proto == IPPROTO_TCP) {
@@ -1560,7 +1563,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow,
                                                sizeof *udp_key);
             udp_key->udp_src = flow->tp_src;
             udp_key->udp_dst = flow->tp_dst;
-        } else if (flow->dl_type == htons(ETH_TYPE_IP)
+        } else if (dl_type == htons(ETH_TYPE_IP)
                 && flow->nw_proto == IPPROTO_ICMP) {
             struct ovs_key_icmp *icmp_key;
 
@@ -1568,7 +1571,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow,
                                                 sizeof *icmp_key);
             icmp_key->icmp_type = ntohs(flow->tp_src);
             icmp_key->icmp_code = ntohs(flow->tp_dst);
-        } else if (flow->dl_type == htons(ETH_TYPE_IPV6)
+        } else if (dl_type == htons(ETH_TYPE_IPV6)
                 && flow->nw_proto == IPPROTO_ICMPV6) {
             struct ovs_key_icmpv6 *icmpv6_key;
 
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 9d38f33..e4ded77 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -85,7 +85,7 @@ int odp_flow_key_from_string(const char *s, const struct 
simap *port_names,
                              struct ofpbuf *);
 
 void odp_flow_key_from_flow(struct ofpbuf *, const struct flow *,
-                            uint32_t odp_in_port);
+                            uint32_t odp_in_port, ovs_be16 encap_dl_type);
 
 uint32_t odp_flow_key_hash(const struct nlattr *, size_t);
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 38f4398..042a7ca 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3235,6 +3235,22 @@ flow_miss_should_make_facet(struct ofproto_dpif *ofproto,
                                         list_size(&miss->packets));
 }
 
+static ovs_be16
+actions_allow_l3_extraction(const struct ofpact *ofpacts, size_t ofpacts_len)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        if (a->type == OFPACT_EXIT)
+            break;
+        if (a->type == OFPACT_POP_MPLS)
+            return ofpact_get_POP_MPLS(a)->ethertype;
+    }
+
+    return htons(0);
+}
+
+
 /* Handles 'miss', which matches 'rule', without creating a facet or subfacet
  * or creating any datapath flow.  May add an "execute" operation to 'ops' and
  * increment '*n_ops'. */
@@ -4087,7 +4103,8 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const 
struct flow *flow,
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, flow,
-                           ofp_port_to_odp_port(ofproto, flow->in_port));
+                           ofp_port_to_odp_port(ofproto, flow->in_port),
+                           flow->encap_dl_type);
 
     error = dpif_execute(ofproto->backer->dpif, key.data, key.size,
                          odp_actions, actions_len, packet);
@@ -4416,6 +4433,14 @@ facet_check_consistency(struct facet *facet)
             continue;
         }
 
+        if (actions_allow_l3_extraction(rule->up.ofpacts,
+                                        rule->up.ofpacts_len)) {
+            /* The actions for flows that depend on actions for evaluation
+             * may legitimately vary from one packet to the next.
+             * We're done. */
+            continue;
+        }
+
         if (!subfacet_should_install(subfacet, subfacet->slow, &odp_actions)) {
             continue;
         }
@@ -4804,7 +4829,8 @@ subfacet_get_key(struct subfacet *subfacet, struct 
odputil_keybuf *keybuf,
         struct flow *flow = &subfacet->facet->flow;
 
         ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
-        odp_flow_key_from_flow(key, flow, subfacet->odp_in_port);
+        odp_flow_key_from_flow(key, flow, subfacet->odp_in_port,
+                               htons(0));
     } else {
         ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
     }
@@ -5204,7 +5230,8 @@ send_packet(const struct ofport_dpif *ofport, struct 
ofpbuf *packet)
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, &flow,
-                           ofp_port_to_odp_port(ofproto, flow.in_port));
+                           ofp_port_to_odp_port(ofproto, flow.in_port),
+                           htons(0));
 
     ofpbuf_init(&odp_actions, 32);
     compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
@@ -6971,7 +6998,8 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf 
*packet,
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, flow,
-                           ofp_port_to_odp_port(ofproto, flow->in_port));
+                           ofp_port_to_odp_port(ofproto, flow->in_port),
+                           flow->encap_dl_type);
 
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
 
diff --git a/tests/test-odp.c b/tests/test-odp.c
index 5ed31a9..6fc618b 100644
--- a/tests/test-odp.c
+++ b/tests/test-odp.c
@@ -70,7 +70,7 @@ parse_keys(void)
         /* Convert cls_rule back to odp_key. */
         ofpbuf_uninit(&odp_key);
         ofpbuf_init(&odp_key, 0);
-        odp_flow_key_from_flow(&odp_key, &flow, flow.in_port);
+        odp_flow_key_from_flow(&odp_key, &flow, flow.in_port, htons(0));
 
         if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
             printf ("too long: %zu > %d\n",
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to