[ovs-dev] [PATCH v8 1/5] userspace: add support for pop_eth and push_eth actions
Lorand Jakab
lojakab at cisco.com
Mon Nov 17 17:24:09 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 c8fa66e..e1b8d38 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -605,6 +605,16 @@ struct ovs_action_push_tnl {
#endif
/**
+ * 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.
@@ -658,6 +668,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 83dbd61..a1566e7 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -3164,6 +3164,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 d179d8a..086f0ba 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1044,6 +1044,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 720d24e..ccc2566 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -471,6 +471,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 633919a..7be7a27 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -79,6 +79,8 @@ odp_action_len(uint16_t type)
case OVS_ACTION_ATTR_TUNNEL_PUSH: return -2;
case OVS_ACTION_ATTR_TUNNEL_POP: 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);
@@ -598,6 +600,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;
@@ -655,6 +658,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(");
@@ -1046,6 +1060,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),
+ ð_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;
@@ -3780,6 +3819,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,
+ ð, 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 00dbf7b..0bbc347 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 af99e3b..ca56ff6 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 65d2274..1435af5 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