[ovs-dev] [PATCH 2/4] userspace: add support for pop_eth and push_eth actions
Lorand Jakab
lojakab at cisco.com
Tue Nov 12 14:36:24 UTC 2013
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 | 12 +++++++++
lib/odp-execute.c | 12 +++++++++
lib/odp-util.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
lib/odp-util.h | 6 +++++
lib/packets.c | 25 +++++++++++++++++++
lib/packets.h | 4 +++
6 files changed, 120 insertions(+)
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index b429201..c36589f 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -519,6 +519,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.
@@ -557,6 +567,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 af3370d..e6ef770 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -207,6 +207,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 e20a0ba..d584d3f 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);
@@ -374,6 +376,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));
@@ -396,6 +399,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(");
@@ -605,6 +619,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),
+ ð_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;
@@ -3332,6 +3371,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 821b2c4..6a7a35c 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;
@@ -226,6 +227,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 dc1970a..a2206b7 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -218,6 +218,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 = ofpbuf_push_uninit(packet, ETH_HEADER_LEN);
+
+ memcpy(eh->eth_dst, dst, ETH_ADDR_LEN);
+ memcpy(eh->eth_src, src, ETH_ADDR_LEN);
+ eh->eth_type = type;
+ packet->l2 = packet->data;
+}
+
+/* Removes Ethernet header, including all VLAN and MPLS headers, from
+ * 'packet'.
+ *
+ * Previous to calling this funciton, 'packet->l3' must be set. */
+void
+pop_eth(struct ofpbuf *packet)
+{
+ packet->size -= (char*)packet->l3 - (char*)packet->l2;
+ packet->data = packet->l3;
+ packet->l2 = NULL;
+}
+
/* 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 f4f00ce..a6defe5 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.8.3.4 (Apple Git-47)
More information about the dev
mailing list