summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--datapath/linux/compat/include/linux/openvswitch.h4
-rw-r--r--lib/odp-execute.c17
-rw-r--r--lib/odp-util.c56
-rw-r--r--lib/odp-util.h6
-rw-r--r--lib/packets.c41
-rw-r--r--lib/packets.h4
-rw-r--r--ofproto/ofproto-dpif-sflow.c14
7 files changed, 128 insertions, 14 deletions
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 72627f9ef..d22102e22 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -770,7 +770,6 @@ enum ovs_ct_attr {
/*
* 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;
@@ -850,8 +849,7 @@ enum ovs_nat_attr {
* entries in the flow key.
* @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet header onto the
* packet.
- * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the
- * packet.
+ * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the packet.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 53d76a291..08bc50a46 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -732,6 +732,21 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
case OVS_ACTION_ATTR_METER:
/* Not implemented yet. */
break;
+ case OVS_ACTION_ATTR_PUSH_ETH: {
+ const struct ovs_action_push_eth *eth = nl_attr_get(a);
+
+ DP_PACKET_BATCH_FOR_EACH (packet, batch) {
+ push_eth(packet, &eth->addresses.eth_dst,
+ &eth->addresses.eth_src);
+ }
+ break;
+ }
+
+ case OVS_ACTION_ATTR_POP_ETH:
+ DP_PACKET_BATCH_FOR_EACH (packet, batch) {
+ pop_eth(packet);
+ }
+ break;
case OVS_ACTION_ATTR_OUTPUT:
case OVS_ACTION_ATTR_TUNNEL_PUSH:
@@ -739,8 +754,6 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
case OVS_ACTION_ATTR_USERSPACE:
case OVS_ACTION_ATTR_RECIRC:
case OVS_ACTION_ATTR_CT:
- case OVS_ACTION_ATTR_PUSH_ETH:
- case OVS_ACTION_ATTR_POP_ETH:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-util.c b/lib/odp-util.c
index ebb572dc1..e24bd7486 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1078,14 +1078,41 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
odp_put_userspace_action(pid, user_data, user_data_size,
tunnel_out_port, include_actions, actions);
res = n + n1;
+ goto out;
} else if (s[n] == ')') {
odp_put_userspace_action(pid, user_data, user_data_size,
ODPP_NONE, include_actions, actions);
res = n + 1;
- } else {
- res = -EINVAL;
+ goto out;
+ }
+ }
+
+ {
+ struct ovs_action_push_eth push;
+ int eth_type = 0;
+ int n1 = -1;
+
+ if (ovs_scan(&s[n], "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, &n1)) {
+
+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH,
+ &push, sizeof push);
+
+ res = n + n1;
+ goto out;
}
}
+
+ if (!strncmp(&s[n], "pop_eth", 7)) {
+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH);
+ res = 7;
+ goto out;
+ }
+
+ res = -EINVAL;
out:
ofpbuf_uninit(&buf);
return res;
@@ -5528,6 +5555,31 @@ 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 struct eth_addr *eth_src,
+ const struct eth_addr *eth_dst)
+{
+ struct ovs_action_push_eth eth;
+
+ memset(&eth, 0, sizeof eth);
+ if (eth_src) {
+ eth.addresses.eth_src = *eth_src;
+ }
+ if (eth_dst) {
+ eth.addresses.eth_dst = *eth_dst;
+ }
+
+ 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 45686d025..fafbb10ee 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -328,4 +328,10 @@ void odp_put_tunnel_action(const struct flow_tnl *tunnel,
void odp_put_tnl_push_action(struct ofpbuf *odp_actions,
struct ovs_action_push_tnl *data);
+
+void odp_put_pop_eth_action(struct ofpbuf *odp_actions);
+void odp_put_push_eth_action(struct ofpbuf *odp_actions,
+ const struct eth_addr *eth_src,
+ const struct eth_addr *eth_dst);
+
#endif /* odp-util.h */
diff --git a/lib/packets.c b/lib/packets.c
index 42d48207c..d51c91ab3 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -227,6 +227,47 @@ eth_pop_vlan(struct dp_packet *packet)
}
}
+/* Push Ethernet header onto 'packet' assuming it is layer 3 */
+void
+push_eth(struct dp_packet *packet, const struct eth_addr *dst,
+ const struct eth_addr *src)
+{
+ struct eth_header *eh;
+
+ ovs_assert(packet->packet_type != htonl(PT_ETH));
+ eh = dp_packet_resize_l2(packet, ETH_HEADER_LEN);
+ eh->eth_dst = *dst;
+ eh->eth_src = *src;
+ eh->eth_type = pt_ns_type_be(packet->packet_type);
+ packet->packet_type = htonl(PT_ETH);
+}
+
+/* Removes Ethernet header, including VLAN header, from 'packet'.
+ *
+ * Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */
+void
+pop_eth(struct dp_packet *packet)
+{
+ char *l2_5 = dp_packet_l2_5(packet);
+ char *l3 = dp_packet_l3(packet);
+ ovs_be16 ethertype;
+ int increment;
+
+ ovs_assert(packet->packet_type == htonl(PT_ETH));
+ ovs_assert(l3 != NULL);
+
+ if (l2_5) {
+ increment = packet->l2_5_ofs;
+ ethertype = *(ALIGNED_CAST(ovs_be16 *, (l2_5 - 2)));
+ } else {
+ increment = packet->l3_ofs;
+ ethertype = *(ALIGNED_CAST(ovs_be16 *, (l3 - 2)));
+ }
+
+ dp_packet_resize_l2(packet, -increment);
+ packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, ntohs(ethertype));
+}
+
/* Set ethertype of the packet. */
static void
set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
diff --git a/lib/packets.h b/lib/packets.h
index 87f063f7b..7dbf6dd0b 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -403,6 +403,10 @@ struct eth_header {
});
BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header));
+void push_eth(struct dp_packet *packet, const struct eth_addr *dst,
+ const struct eth_addr *src);
+void pop_eth(struct dp_packet *packet);
+
#define LLC_DSAP_SNAP 0xaa
#define LLC_SSAP_SNAP 0xaa
#define LLC_CNTL_SNAP 3
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 59fafa14c..43483d7e1 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1188,13 +1188,13 @@ dpif_sflow_read_actions(const struct flow *flow,
dpif_sflow_pop_mpls_lse(sflow_actions);
break;
}
- case OVS_ACTION_ATTR_PUSH_ETH:
- case OVS_ACTION_ATTR_POP_ETH:
- /* TODO: SFlow does not currently define a MAC-in-MAC
- * encapsulation structure. We could use an extension
- * structure to report this.
- */
- break;
+ case OVS_ACTION_ATTR_PUSH_ETH:
+ case OVS_ACTION_ATTR_POP_ETH:
+ /* TODO: SFlow does not currently define a MAC-in-MAC
+ * encapsulation structure. We could use an extension
+ * structure to report this.
+ */
+ break;
case OVS_ACTION_ATTR_SAMPLE:
case OVS_ACTION_ATTR_CLONE:
case OVS_ACTION_ATTR_UNSPEC: