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

Lorand Jakab lojakab at cisco.com
Mon Nov 3 14:31:15 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>
---
 datapath/linux/compat/include/linux/openvswitch.h | 12 +++++
 lib/dpif-netdev.c                                 |  2 +
 lib/dpif.c                                        |  2 +
 lib/odp-execute.c                                 | 19 +++++++
 lib/odp-util.c                                    | 61 +++++++++++++++++++++++
 lib/odp-util.h                                    |  6 +++
 lib/packets.c                                     | 25 ++++++++++
 lib/packets.h                                     |  4 ++
 8 files changed, 131 insertions(+)

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index b2257e6..63f1d05 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -581,6 +581,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.
@@ -629,6 +639,8 @@ enum ovs_action_attr {
 	OVS_ACTION_ATTR_HASH,	      /* struct ovs_action_hash. */
 	OVS_ACTION_ATTR_PUSH_MPLS,    /* struct ovs_action_push_mpls. */
 	OVS_ACTION_ATTR_POP_MPLS,     /* __be16 ethertype. */
+	OVS_ACTION_ATTR_PUSH_ETH,     /* struct ovs_action_push_eth. */
+	OVS_ACTION_ATTR_POP_ETH,      /* No argument. */
 	OVS_ACTION_ATTR_SET_MASKED,   /* One nested OVS_KEY_ATTR_* including
 				       * data immediately followed by a mask.
 				       * The data must be zero for the unmasked
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 2009206..7dde0cd 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -3036,6 +3036,8 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
         VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
         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 64e6a0e..b94110c 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1037,6 +1037,8 @@ dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt,
     }
 
     case OVS_ACTION_ATTR_HASH:
+    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 230e6e1..5308686 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -454,6 +454,25 @@ odp_execute_actions(void *dp, struct dpif_packet **packets, int cnt, bool steal,
             break;
         }
 
+        case OVS_ACTION_ATTR_PUSH_ETH: {
+            const struct ovs_action_push_eth *eth = nl_attr_get(a);
+
+            for (i = 0; i < cnt; i++) {
+                struct ofpbuf *ofp = &packets[i]->ofpbuf;
+
+                push_eth(ofp, eth->addresses.eth_dst, eth->addresses.eth_src,
+                        eth->eth_type);
+            }
+            break;
+        }
+
+        case OVS_ACTION_ATTR_POP_ETH: {
+            for (i = 0; i < cnt; i++) {
+                pop_eth(&packets[i]->ofpbuf);
+            }
+            break;
+        }
+
         case OVS_ACTION_ATTR_PUSH_VLAN: {
             const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
index b89d74b..5362897 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);
@@ -511,6 +513,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;
     size_t size;
 
@@ -562,6 +565,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(");
@@ -819,6 +833,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;
@@ -3531,6 +3570,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 11b54dd..b1584d6 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -27,6 +27,7 @@
 #include "odp-netlink.h"
 #include "openflow/openflow.h"
 #include "util.h"
+#include "packets.h"
 
 struct ds;
 struct nlattr;
@@ -251,6 +252,11 @@ size_t odp_put_userspace_action(uint32_t pid,
                                 const void *userdata, size_t userdata_size,
                                 odp_port_t tunnel_out_port,
                                 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);
 
diff --git a/lib/packets.c b/lib/packets.c
index 65d8109..4b5699a 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -207,6 +207,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 fc7e602..547480a 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -196,6 +196,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.9.3 (Apple Git-50)




More information about the dev mailing list