[ovs-dev] [PATCH 18/19] actions: Allow secondary decoding of a flow

Simon Horman horms at verge.net.au
Mon Dec 24 02:35:24 UTC 2012


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.

ovs-vswtichd: actions_allow_l3_extraction()
---
 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 7eb7cc3..eedb3e5 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 4b6e4f0..4ba4c98 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 9b3096a..3ba76f4 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);
@@ -5996,6 +6003,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)
@@ -7061,7 +7083,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




More information about the dev mailing list