[ovs-dev] [PATCH v3 1/3] userspace: add support for pop_eth and push_eth actions

Lorand Jakab lojakab at cisco.com
Tue May 13 14:02:14 UTC 2014


These actions will allow L2->L3 and L3->L2 switching, and are supposed
to be added to flows installed in the datapath transparently by
ovs-vswitchd.

Signed-off-by: Lorand Jakab <lojakab at cisco.com>
---
 include/linux/openvswitch.h | 16 ++++++++++--
 lib/dpif-netdev.c           |  2 ++
 lib/dpif.c                  |  2 ++
 lib/odp-execute.c           | 12 +++++++++
 lib/odp-util.c              | 61 +++++++++++++++++++++++++++++++++++++++++++++
 lib/odp-util.h              |  6 +++++
 lib/packets.c               | 25 +++++++++++++++++++
 lib/packets.h               |  4 +++
 8 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index d7f85ff..70ccbc9 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -565,6 +565,16 @@ struct ovs_action_hash {
 };
 
 /**
+ * struct ovs_action_push_eth - %OVS_ACTION_ATTR_PUSH_ETH action argument.
+ * @addresses: Source and destination MAC addresses.
+ * @eth_type: Ethernet type
+ */
+struct ovs_action_push_eth {
+	struct ovs_key_ethernet addresses;
+	__be16	 eth_type;
+};
+
+/**
  * enum ovs_action_attr - Action types.
  *
  * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
@@ -602,10 +612,12 @@ enum ovs_action_attr {
 	OVS_ACTION_ATTR_PUSH_VLAN,    /* struct ovs_action_push_vlan. */
 	OVS_ACTION_ATTR_POP_VLAN,     /* No argument. */
 	OVS_ACTION_ATTR_SAMPLE,       /* Nested OVS_SAMPLE_ATTR_*. */
-	OVS_ACTION_ATTR_PUSH_MPLS,    /* struct ovs_action_push_mpls. */
-	OVS_ACTION_ATTR_POP_MPLS,     /* __be16 ethertype. */
 	OVS_ACTION_ATTR_RECIRC,	      /* u32 recirc_id. */
 	OVS_ACTION_ATTR_HASH,	      /* struct ovs_action_hash. */
+	OVS_ACTION_ATTR_PUSH_ETH,     /* struct ovs_action_push_eth. */
+	OVS_ACTION_ATTR_POP_ETH,      /* No argument. */
+	OVS_ACTION_ATTR_PUSH_MPLS = 61, /* struct ovs_action_push_mpls. */
+	OVS_ACTION_ATTR_POP_MPLS = 62,  /* __be16 ethertype. */
 	__OVS_ACTION_ATTR_MAX
 };
 
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index a255a96..40503a2 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2171,6 +2171,8 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
         }
         break;
 
+    case OVS_ACTION_ATTR_PUSH_ETH:
+    case OVS_ACTION_ATTR_POP_ETH:
     case OVS_ACTION_ATTR_PUSH_VLAN:
     case OVS_ACTION_ATTR_POP_VLAN:
     case OVS_ACTION_ATTR_PUSH_MPLS:
diff --git a/lib/dpif.c b/lib/dpif.c
index 41b8eb7..d7cfc5c 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1126,6 +1126,8 @@ dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet,
         aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
         break;
 
+    case OVS_ACTION_ATTR_PUSH_ETH:
+    case OVS_ACTION_ATTR_POP_ETH:
     case OVS_ACTION_ATTR_PUSH_VLAN:
     case OVS_ACTION_ATTR_POP_VLAN:
     case OVS_ACTION_ATTR_PUSH_MPLS:
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 12ad679..64847a9 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -219,6 +219,18 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal,
             }
             break;
 
+        case OVS_ACTION_ATTR_PUSH_ETH: {
+            const struct ovs_action_push_eth *eth = nl_attr_get(a);
+            push_eth(packet, eth->addresses.eth_dst, eth->addresses.eth_src,
+                     eth->eth_type);
+            break;
+        }
+
+        case OVS_ACTION_ATTR_POP_ETH: {
+            pop_eth(packet);
+            break;
+        }
+
         case OVS_ACTION_ATTR_PUSH_VLAN: {
             const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
             eth_push_vlan(packet, htons(ETH_TYPE_VLAN), vlan->vlan_tci);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index af464a0..a22ab01 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -75,6 +75,8 @@ odp_action_len(uint16_t type)
     switch ((enum ovs_action_attr) type) {
     case OVS_ACTION_ATTR_OUTPUT: return sizeof(uint32_t);
     case OVS_ACTION_ATTR_USERSPACE: return -2;
+    case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth);
+    case OVS_ACTION_ATTR_POP_ETH: return 0;
     case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan);
     case OVS_ACTION_ATTR_POP_VLAN: return 0;
     case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);
@@ -412,6 +414,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
 {
     int expected_len;
     enum ovs_action_attr type = nl_attr_type(a);
+    const struct ovs_action_push_eth *eth;
     const struct ovs_action_push_vlan *vlan;
 
     expected_len = odp_action_len(nl_attr_type(a));
@@ -440,6 +443,17 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
         format_odp_key_attr(nl_attr_get(a), NULL, NULL, ds, true);
         ds_put_cstr(ds, ")");
         break;
+    case OVS_ACTION_ATTR_PUSH_ETH:
+        eth = nl_attr_get(a);
+        ds_put_format(ds, "push_eth(src="ETH_ADDR_FMT",dst="ETH_ADDR_FMT
+                      ",type=0x%04"PRIx16")",
+                      ETH_ADDR_ARGS(eth->addresses.eth_src),
+                      ETH_ADDR_ARGS(eth->addresses.eth_dst),
+                      ntohs(eth->eth_type));
+        break;
+    case OVS_ACTION_ATTR_POP_ETH:
+        ds_put_cstr(ds, "pop_eth");
+        break;
     case OVS_ACTION_ATTR_PUSH_VLAN:
         vlan = nl_attr_get(a);
         ds_put_cstr(ds, "push_vlan(");
@@ -640,6 +654,31 @@ parse_odp_action(const char *s, const struct simap *port_names,
     }
 
     {
+        struct ovs_action_push_eth push;
+        int eth_type = 0;
+        int n = -1;
+
+        if (ovs_scan(s, "push_eth(src="ETH_ADDR_SCAN_FMT","
+                     "dst="ETH_ADDR_SCAN_FMT",type=%i)%n",
+                     ETH_ADDR_SCAN_ARGS(push.addresses.eth_src),
+                     ETH_ADDR_SCAN_ARGS(push.addresses.eth_dst),
+                     &eth_type, &n)) {
+
+            push.eth_type = htons(eth_type);
+
+            nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH,
+                              &push, sizeof push);
+
+            return n;
+        }
+    }
+
+    if (!strncmp(s, "pop_eth", 7)) {
+        nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH);
+        return 7;
+    }
+
+    {
         struct ovs_action_push_vlan push;
         int tpid = ETH_TYPE_VLAN;
         int vid, pcp;
@@ -3479,6 +3518,28 @@ odp_put_userspace_action(uint32_t pid,
 }
 
 void
+odp_put_pop_eth_action(struct ofpbuf *odp_actions)
+{
+    nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH);
+}
+
+void
+odp_put_push_eth_action(struct ofpbuf *odp_actions,
+                        const uint8_t eth_src[ETH_ADDR_LEN],
+                        const uint8_t eth_dst[ETH_ADDR_LEN],
+                        const ovs_be16 eth_type)
+{
+    struct ovs_action_push_eth eth;
+
+    memcpy(eth.addresses.eth_src, eth_src, ETH_ADDR_LEN);
+    memcpy(eth.addresses.eth_dst, eth_dst, ETH_ADDR_LEN);
+    eth.eth_type = eth_type;
+
+    nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_ETH,
+                      &eth, sizeof eth);
+}
+
+void
 odp_put_tunnel_action(const struct flow_tnl *tunnel,
                       struct ofpbuf *odp_actions)
 {
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 0dfbcca..64b16b0 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -26,6 +26,7 @@
 #include "hmap.h"
 #include "openflow/openflow.h"
 #include "util.h"
+#include "packets.h"
 
 struct ds;
 struct flow;
@@ -233,6 +234,11 @@ BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 16);
 size_t odp_put_userspace_action(uint32_t pid,
                                 const void *userdata, size_t userdata_size,
                                 struct ofpbuf *odp_actions);
+void odp_put_pop_eth_action(struct ofpbuf *odp_actions);
+void odp_put_push_eth_action(struct ofpbuf *odp_actions,
+                             const uint8_t eth_src[ETH_ADDR_LEN],
+                             const uint8_t eth_dst[ETH_ADDR_LEN],
+                             const ovs_be16 eth_type);
 void odp_put_tunnel_action(const struct flow_tnl *tunnel,
                            struct ofpbuf *odp_actions);
 void odp_put_pkt_mark_action(const uint32_t pkt_mark,
diff --git a/lib/packets.c b/lib/packets.c
index 6244c3f..c1f7ade 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -206,6 +206,31 @@ eth_pop_vlan(struct ofpbuf *packet)
     }
 }
 
+/* Push Ethernet header onto 'packet' assuming it is layer 3 */
+void
+push_eth(struct ofpbuf *packet, const uint8_t dst[ETH_ADDR_LEN],
+         const uint8_t src[ETH_ADDR_LEN], ovs_be16 type)
+{
+    struct eth_header *eh;
+
+    eh = ofpbuf_resize_l2(packet, ETH_HEADER_LEN);
+    memcpy(eh->eth_dst, dst, ETH_ADDR_LEN);
+    memcpy(eh->eth_src, src, ETH_ADDR_LEN);
+    eh->eth_type = type;
+}
+
+/* Removes Ethernet header, including all VLAN and MPLS headers, from 'packet'.
+ *
+ * Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */
+void
+pop_eth(struct ofpbuf *packet)
+{
+    ovs_assert(ofpbuf_l3(packet) != NULL);
+
+    ofpbuf_resize_l2_5(packet, -packet->l3_ofs);
+    ofpbuf_set_l2_5(packet, NULL);
+}
+
 /* Set ethertype of the packet. */
 static void
 set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
diff --git a/lib/packets.h b/lib/packets.h
index f294d84..1c36f7c 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -194,6 +194,10 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
                      const uint8_t mask[ETH_ADDR_LEN],
                      uint8_t dst[ETH_ADDR_LEN]);
 
+void push_eth(struct ofpbuf *packet, const uint8_t dst[ETH_ADDR_LEN],
+              const uint8_t src[ETH_ADDR_LEN], ovs_be16 type);
+void pop_eth(struct ofpbuf *packet);
+
 void set_mpls_lse(struct ofpbuf *, ovs_be32 label);
 void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse);
 void pop_mpls(struct ofpbuf *, ovs_be16 ethtype);
-- 
1.8.5.2 (Apple Git-48)




More information about the dev mailing list