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.12
* No change

v2.11
* First post
---
 lib/dpif-linux.c       |    2 +-
 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 +-
 6 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 87eb9c1..477a7f1 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1390,7 +1390,7 @@ dpif_linux_vport_send(int dp_ifindex, uint32_t port_no,
     flow_extract(&packet, 0, 0, NULL, 0, &flow);
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
-    odp_flow_key_from_flow(&key, &flow, OVSP_NONE);
+    odp_flow_key_from_flow(&key, &flow, OVSP_NONE, htons(0));
 
     ofpbuf_use_stack(&actions, &action, sizeof action);
     nl_msg_put_u32(&actions, OVS_ACTION_ATTR_OUTPUT, port_no);
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 818fbbf..94e174d 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -289,6 +289,8 @@ static void action_xlate_ctx_init(struct action_xlate_ctx *,
                                   struct ofproto_dpif *, const struct flow *,
                                   ovs_be16 initial_tci, struct rule_dpif *,
                                   uint8_t tcp_flags, const struct ofpbuf *);
+static ovs_be16 actions_allow_l3_extraction(const struct ofpact *ofpacts,
+                                            size_t ofpacts_len);
 static void xlate_actions(struct action_xlate_ctx *,
                           const struct ofpact *ofpacts, size_t ofpacts_len,
                           struct ofpbuf *odp_actions);
@@ -4079,7 +4081,7 @@ facet_free(struct facet *facet)
 static bool
 execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow,
                     const struct nlattr *odp_actions, size_t actions_len,
-                    struct ofpbuf *packet)
+                    struct ofpbuf *packet, ovs_be16 encap_dl_type)
 {
     struct odputil_keybuf keybuf;
     struct ofpbuf key;
@@ -4087,7 +4089,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),
+                           encap_dl_type);
 
     error = dpif_execute(ofproto->backer->dpif, key.data, key.size,
                          odp_actions, actions_len, packet);
@@ -4804,7 +4807,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);
     }
@@ -5166,7 +5170,9 @@ rule_execute(struct rule *rule_, const struct flow *flow,
     xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions);
 
     execute_odp_actions(ofproto, flow, odp_actions.data,
-                        odp_actions.size, packet);
+                        odp_actions.size, packet,
+                        actions_allow_l3_extraction(rule->up.ofpacts,
+                                                    rule->up.ofpacts_len));
 
     ofpbuf_uninit(&odp_actions);
 
@@ -5204,7 +5210,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);
@@ -5924,6 +5931,21 @@ may_receive(const struct ofport_dpif *port, struct 
action_xlate_ctx *ctx)
     return true;
 }
 
+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);
+}
+
 static void
 do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                  struct action_xlate_ctx *ctx)
@@ -6971,7 +6993,9 @@ 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),
+                           actions_allow_l3_extraction(ofpacts,
+                                                       ofpacts_len));
 
     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