[ovs-dev] [RFC L3 2/4] userspace: add support for pop_eth and push_eth actions

Lorand Jakab lojakab at cisco.com
Fri Oct 4 13:38:12 UTC 2013


These actions will allow L2->L3 and L3->L2 switching

Signed-off-by: Lorand Jakab <lojakab at cisco.com>
---
 include/linux/openvswitch.h |   12 ++++++++
 lib/odp-execute.c           |   12 ++++++++
 lib/odp-util.c              |   61 +++++++++++++++++++++++++++++++++++++++++++
 lib/odp-util.h              |    6 ++++
 lib/packets.c               |   15 ++++++++++
 lib/packets.h               |    4 +++
 6 files changed, 110 insertions(+), 0 deletions(-)

diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index 09c26b5..cee2204 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -507,6 +507,16 @@ struct ovs_action_push_vlan {
 };
 
 /**
+ * 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.
@@ -545,6 +555,8 @@ enum ovs_action_attr {
 	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_PUSH_ETH,     /* struct ovs_action_push_eth. */
+	OVS_ACTION_ATTR_POP_ETH,      /* No argument. */
 	__OVS_ACTION_ATTR_MAX
 };
 
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index c91cc4a..935b66b 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -190,6 +190,18 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
             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, vlan->vlan_tci);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 5c7ccfb..eda679e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -74,6 +74,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);
@@ -383,6 +385,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));
@@ -405,6 +408,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(");
@@ -616,6 +630,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 (sscanf(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) > 0 && n > 0) {
+
+            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;
@@ -3296,6 +3335,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 2712cb0..fd900a1 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;
@@ -194,6 +195,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 922c5db..7e843b7 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -218,6 +218,21 @@ eth_pop_vlan(struct ofpbuf *packet)
     }
 }
 
+/* Push Ethernet header */
+void
+push_eth(struct ofpbuf *packet, const uint8_t dst[ETH_ADDR_LEN],
+         const uint8_t src[ETH_ADDR_LEN], ovs_be16 type)
+{
+    /* TODO */
+}
+
+/* Pop Ethernet header */
+void
+pop_eth(struct ofpbuf *packet)
+{
+    /* TODO */
+}
+
 /* Set ethertype of the packet. */
 void
 set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
diff --git a/lib/packets.h b/lib/packets.h
index 7388152..0effe8f 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -152,6 +152,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.7.7.5 (Apple Git-26)




More information about the dev mailing list