[ovs-dev] [PATCH 01/15] Update parse_l2_5_onward to use encap for MPLS

Simon Horman horms at verge.net.au
Sat Feb 16 01:20:49 UTC 2013


On Fri, Feb 15, 2013 at 08:58:52AM -0800, Ben Pfaff wrote:
> On Fri, Feb 15, 2013 at 06:55:55PM +0900, Simon Horman wrote:
> > When encoding MPLS information in ODP flow key data use encap()
> > for encap for frames. This seems to be in keeping with datapath/README.
> > 
> > before: eth(...), eth_type(0x8847), mpls(...), encap(ip(...), tcp(...))
> > after: eth(...), eth_type(0x8847), mpls(...), ip(...), tcp(...)
> 
> I think you got the before and after backward.

Thanks, I have fixed that below.

> We also need to update odp_flow_key_from_flow().

Thanks, I had that  in the next patch in the series.

A combined patch with a revised commit message is below.


From: Simon Horman <horms at verge.net.au>

odp: Use encap() for MPLS-encapsulated ODP flow key data

This patch has two components:

1. odp_flow_key_from_flow() is updated to extract encapsulated frame
   information from MPLS flows. It does this by encoding the encapsualted
   frame in an encap() in the resulting ODP key data.

   A subsequent patch will introduce code to set flow->encap_dl_type
   which will activate this change.

2. Update parse_l2_5_onward() to read an MPLS-encapsulated frame
   from inside encap() in ODP key data. This consumes ODP key data
   produced by odp_flow_key_from_flow().

   before: eth(...), eth_type(0x8847), mpls(...), ip(...), tcp(...)
   after: eth(...), eth_type(0x8847), mpls(...), encap(ip(...), tcp(...))

The use of encap() for MPLS-encapsulated frames was suggested by Ben Pfaff
and seems to be in keeping with datapath/README.

Signed-off-by: Simon Horman <horms at verge.net.au>

---

v2.20 (draft)
* Squash "Update parse_l2_5_onward to use encap for MPLS" and
  "odp_flow_key_from_flow: Allow of encapsulated frames" and
  rename the result "odp: Use encap() for MPLS-encapsulated ODP flow key data".

v2.19
* As suggested by Ben Pfaff
  - Remove encap_dl_type parameter from odp_flow_key_from_flow()
  - Use encap for mpls in ODP flow key data.
    before: eth(...), eth_type(0x8847), mpls(...), ip(...), tcp(...)
    after: eth(...), eth_type(0x8847), mpls(...), encap(ip(...), tcp(...))
* Coding style fix for actions_allow_l3_extraction().
  Use {} in conjunction with if statements.
* Enhance actions_allow_l3_extraction to return when the first MPLS_PUSH
  action with a non-MPLS ether type is found rather than when the first
  MPLS_PUSH action is found.
* Remove actions_allow_l3_extraction() and obtain encap_dl_type
  from xlate_actions() instead.
* Removed non-odp_flow_key_from_flow portions.
  These are now present in ofproto: Allow richer matches based on actions().
* Rename patch from
  "actions: Allow secondary decoding of a flow" to
  "actions: odp_flow_key_from_flow: Allow of encapsulated frames"

v2.18
* Update odp_flow_key_from_flow() to use dl_type_is_ip_any() wrapper.
  As odp_flow_key_from_flow() is paramatised over encap_dl_type
  this seems to be a good approach.

v2.17
* Rebase

v2.13 - v2.16
* 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.11
* First post
---
 lib/odp-util.c        |   85 ++++++++++++++++++++++++++++++++-----------------
 tests/ofproto-dpif.at |    4 +--
 2 files changed, 58 insertions(+), 31 deletions(-)

diff --git a/lib/odp-util.c b/lib/odp-util.c
index f3f66b7..a6002db 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1506,7 +1506,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
                        uint32_t odp_in_port)
 {
     struct ovs_key_ethernet *eth_key;
-    size_t encap;
+    size_t encap_vlan = 0, encap_mpls = 0;
+    ovs_be16 dl_type = flow_innermost_dl_type(flow);
 
     if (flow->skb_priority) {
         nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority);
@@ -1534,12 +1535,10 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
     if (flow->vlan_tci != htons(0) || flow->dl_type == htons(ETH_TYPE_VLAN)) {
         nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN));
         nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, flow->vlan_tci);
-        encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
+        encap_vlan = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
         if (flow->vlan_tci == htons(0)) {
             goto unencap;
         }
-    } else {
-        encap = 0;
     }
 
     if (ntohs(flow->dl_type) < ETH_TYPE_MIN) {
@@ -1548,7 +1547,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)) {
+    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_lse = flow->mpls_lse;
+        if (flow->encap_dl_type) {
+            encap_mpls = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
+        }
+    }
+
+    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,
@@ -1559,7 +1569,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,
@@ -1571,8 +1581,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,
@@ -1585,15 +1595,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_lse = flow->mpls_lse;
-    }
-
-    if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
+    if (dl_type_is_ip_any(dl_type) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         if (flow->nw_proto == IPPROTO_TCP) {
             struct ovs_key_tcp *tcp_key;
 
@@ -1608,7 +1610,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;
 
@@ -1616,7 +1618,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;
 
@@ -1640,8 +1642,11 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
     }
 
 unencap:
-    if (encap) {
-        nl_msg_end_nested(buf, encap);
+    if (encap_mpls) {
+        nl_msg_end_nested(buf, encap_mpls);
+    }
+    if (encap_vlan) {
+        nl_msg_end_nested(buf, encap_vlan);
     }
 }
 
@@ -1801,10 +1806,14 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                   const struct nlattr *key, size_t key_len)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+    enum odp_key_fitness fitness, mpls_fitness = 0;
     ovs_be16 dl_type;
 
     /* Parse MPLS label stack entry */
     if (eth_type_mpls(flow->dl_type)) {
+        const struct nlattr *encap
+            = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP)
+               ? attrs[OVS_KEY_ATTR_ENCAP] : NULL);
         /* Calculate fitness of outer attributes. */
         expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS);
 
@@ -1815,12 +1824,27 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
         flow->mpls_lse = nl_attr_get_be32(attrs[OVS_KEY_ATTR_MPLS]);
         flow->mpls_depth++;
 
-        if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
-            flow->encap_dl_type = htons(ETH_TYPE_IP);
-        } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
-            flow->encap_dl_type = htons(ETH_TYPE_IPV6);
-        } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) {
-            flow->encap_dl_type = htons(ETH_TYPE_ARP);
+        /* Encap may not be present if nothing is known about the
+         * encapsulated frame */
+        if (encap) {
+            expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_ENCAP);
+            mpls_fitness = check_expectations(present_attrs, out_of_range_attr,
+                                              expected_attrs, key, key_len);
+
+            /* Now parse the encapsulated attributes. */
+            if (!parse_flow_nlattrs(nl_attr_get(encap), nl_attr_get_size(encap),
+                                    attrs, &present_attrs, &out_of_range_attr)) {
+                return ODP_FIT_ERROR;
+            }
+            expected_attrs = 0;
+
+            if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
+                flow->encap_dl_type = htons(ETH_TYPE_IP);
+            } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
+                flow->encap_dl_type = htons(ETH_TYPE_IPV6);
+            } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) {
+                flow->encap_dl_type = htons(ETH_TYPE_ARP);
+            }
         }
     }
 
@@ -1939,8 +1963,11 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
         }
     }
 
-    return check_expectations(present_attrs, out_of_range_attr, expected_attrs,
-                              key, key_len);
+    fitness = check_expectations(present_attrs, out_of_range_attr,
+                                 expected_attrs, key, key_len);
+
+    /* The overall fitness is the worse of the outer and inner attributes. */
+    return MAX(fitness, mpls_fitness);
 }
 
 /* Parse 802.1Q header then encapsulated L3 attributes. */
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 8f11b82..15069bd 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -359,7 +359,7 @@ dnl Modified MPLS actions.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 for i in 1 2 3; do
-    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1),encap(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
 
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
@@ -398,7 +398,7 @@ dnl Modified MPLS pop action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 for i in 1 2 3; do
-    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1),encap(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
 
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
-- 
1.7.10.4









More information about the dev mailing list