net/sched: act_vlan: Add {POP,PUSH}_ETH actions

Implement TCA_VLAN_ACT_POP_ETH and TCA_VLAN_ACT_PUSH_ETH, to
respectively pop and push a base Ethernet header at the beginning of a
frame.

POP_ETH is just a matter of pulling ETH_HLEN bytes. VLAN tags, if any,
must be stripped before calling POP_ETH.

PUSH_ETH is restricted to skbs with no mac_header, and only the MAC
addresses can be configured. The Ethertype is automatically set from
skb->protocol. These restrictions ensure that all skb's fields remain
consistent, so that this action can't confuse other part of the
networking stack (like GSO).

Since openvswitch already had these actions, consolidate the code in
skbuff.c (like for vlan and mpls push/pop).

Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Guillaume Nault
2020-10-03 00:44:28 +02:00
committed by David S. Miller
parent e275d49a69
commit 19fbcb36a3
6 changed files with 126 additions and 18 deletions

View File

@@ -277,9 +277,11 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
*/
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);
int err;
err = skb_eth_pop(skb);
if (err)
return err;
/* safe right before invalidate_flow_key */
key->mac_proto = MAC_PROTO_NONE;
@@ -290,22 +292,12 @@ static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)
static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
const struct ovs_action_push_eth *ethh)
{
struct ethhdr *hdr;
int err;
/* 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);
err = skb_eth_push(skb, ethh->addresses.eth_dst,
ethh->addresses.eth_src);
if (err)
return err;
/* safe right before invalidate_flow_key */
key->mac_proto = MAC_PROTO_ETHERNET;