Allow push and pop mpls actions to act on layer 3 packets by teaching
them not to access non-existent L2 headers of such packets.

Signed-off-by: Simon Horman <simon.hor...@netronome.com>
---
v11
* group l2 code in pop_mpls()

v10
* Limit scope of hdr in {push,pop}_mpls()

v9
* New Patch
---
 include/uapi/linux/openvswitch.h |  2 ++
 net/openvswitch/actions.c        | 24 +++++++++++++++---------
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index d95a3018f6a1..5cde501433eb 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -737,6 +737,8 @@ enum ovs_nat_attr {
  * is no MPLS label stack, as determined by ethertype, no action is taken.
  * @OVS_ACTION_ATTR_CT: Track the connection. Populate the conntrack-related
  * entries in the flow key.
+ * @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet header onto the    
  * packet.
+ * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the packet.
  *
  * Only a single header can be set with a single %OVS_ACTION_ATTR_SET.  Not all
  * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 1ecbd7715f6d..12e8a8942a42 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -163,8 +163,6 @@ static int push_mpls(struct sk_buff *skb, struct 
sw_flow_key *key,
                return -ENOMEM;
 
        skb_push(skb, MPLS_HLEN);
-       memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb),
-               skb->mac_len);
        skb_reset_mac_header(skb);
 
        new_mpls_lse = (__be32 *)skb_mpls_header(skb);
@@ -172,7 +170,11 @@ static int push_mpls(struct sk_buff *skb, struct 
sw_flow_key *key,
 
        skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN);
 
-       update_ethertype(skb, eth_hdr(skb), mpls->mpls_ethertype);
+       if (skb->mac_len) {
+               update_ethertype(skb, eth_hdr(skb), mpls->mpls_ethertype);
+               memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb),
+                       skb->mac_len);
+       }
        if (!skb->inner_protocol)
                skb_set_inner_protocol(skb, skb->protocol);
        skb->protocol = mpls->mpls_ethertype;
@@ -184,7 +186,6 @@ static int push_mpls(struct sk_buff *skb, struct 
sw_flow_key *key,
 static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
                    const __be16 ethertype)
 {
-       struct ethhdr *hdr;
        int err;
 
        err = skb_ensure_writable(skb, skb->mac_len + MPLS_HLEN);
@@ -199,11 +200,16 @@ static int pop_mpls(struct sk_buff *skb, struct 
sw_flow_key *key,
        __skb_pull(skb, MPLS_HLEN);
        skb_reset_mac_header(skb);
 
-       /* skb_mpls_header() is used to locate the ethertype
-        * field correctly in the presence of VLAN tags.
-        */
-       hdr = (struct ethhdr *)(skb_mpls_header(skb) - ETH_HLEN);
-       update_ethertype(skb, hdr, ethertype);
+       if (skb->mac_len) {
+               struct ethhdr *hdr;
+
+               /* skb_mpls_header() is used to locate the ethertype
+                * field correctly in the presence of VLAN tags.
+                */
+               hdr = (struct ethhdr *)(skb_mpls_header(skb) - ETH_HLEN);
+               update_ethertype(skb, hdr, ethertype);
+       }
+
        if (eth_p_mpls(skb->protocol))
                skb->protocol = ethertype;
 
-- 
2.7.0.rc3.207.g0ac5344

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

Reply via email to