|
@@ -317,6 +317,47 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* pop_eth does not support VLAN packets as this action is never called
|
|
|
+ * for them.
|
|
|
+ */
|
|
|
+static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)
|
|
|
+{
|
|
|
+ skb_pull_rcsum(skb, ETH_HLEN);
|
|
|
+ skb_reset_mac_header(skb);
|
|
|
+ skb_reset_mac_len(skb);
|
|
|
+
|
|
|
+ /* safe right before invalidate_flow_key */
|
|
|
+ key->mac_proto = MAC_PROTO_NONE;
|
|
|
+ invalidate_flow_key(key);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
|
|
|
+ const struct ovs_action_push_eth *ethh)
|
|
|
+{
|
|
|
+ struct ethhdr *hdr;
|
|
|
+
|
|
|
+ /* Add the new Ethernet header */
|
|
|
+ if (skb_cow_head(skb, ETH_HLEN) < 0)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ skb_push(skb, ETH_HLEN);
|
|
|
+ skb_reset_mac_header(skb);
|
|
|
+ skb_reset_mac_len(skb);
|
|
|
+
|
|
|
+ hdr = eth_hdr(skb);
|
|
|
+ ether_addr_copy(hdr->h_source, ethh->addresses.eth_src);
|
|
|
+ ether_addr_copy(hdr->h_dest, ethh->addresses.eth_dst);
|
|
|
+ hdr->h_proto = skb->protocol;
|
|
|
+
|
|
|
+ skb_postpush_rcsum(skb, hdr, ETH_HLEN);
|
|
|
+
|
|
|
+ /* safe right before invalidate_flow_key */
|
|
|
+ key->mac_proto = MAC_PROTO_ETHERNET;
|
|
|
+ invalidate_flow_key(key);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
|
|
|
__be32 addr, __be32 new_addr)
|
|
|
{
|
|
@@ -1200,6 +1241,14 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
|
|
if (err)
|
|
|
return err == -EINPROGRESS ? 0 : err;
|
|
|
break;
|
|
|
+
|
|
|
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
|
|
+ err = push_eth(skb, key, nla_data(a));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case OVS_ACTION_ATTR_POP_ETH:
|
|
|
+ err = pop_eth(skb, key);
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
if (unlikely(err)) {
|