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:
committed by
David S. Miller
parent
e275d49a69
commit
19fbcb36a3
@@ -5558,6 +5558,73 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
|
||||
}
|
||||
EXPORT_SYMBOL(skb_vlan_push);
|
||||
|
||||
/**
|
||||
* skb_eth_pop() - Drop the Ethernet header at the head of a packet
|
||||
*
|
||||
* @skb: Socket buffer to modify
|
||||
*
|
||||
* Drop the Ethernet header of @skb.
|
||||
*
|
||||
* Expects that skb->data points to the mac header and that no VLAN tags are
|
||||
* present.
|
||||
*
|
||||
* Returns 0 on success, -errno otherwise.
|
||||
*/
|
||||
int skb_eth_pop(struct sk_buff *skb)
|
||||
{
|
||||
if (!pskb_may_pull(skb, ETH_HLEN) || skb_vlan_tagged(skb) ||
|
||||
skb_network_offset(skb) < ETH_HLEN)
|
||||
return -EPROTO;
|
||||
|
||||
skb_pull_rcsum(skb, ETH_HLEN);
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_mac_len(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(skb_eth_pop);
|
||||
|
||||
/**
|
||||
* skb_eth_push() - Add a new Ethernet header at the head of a packet
|
||||
*
|
||||
* @skb: Socket buffer to modify
|
||||
* @dst: Destination MAC address of the new header
|
||||
* @src: Source MAC address of the new header
|
||||
*
|
||||
* Prepend @skb with a new Ethernet header.
|
||||
*
|
||||
* Expects that skb->data points to the mac header, which must be empty.
|
||||
*
|
||||
* Returns 0 on success, -errno otherwise.
|
||||
*/
|
||||
int skb_eth_push(struct sk_buff *skb, const unsigned char *dst,
|
||||
const unsigned char *src)
|
||||
{
|
||||
struct ethhdr *eth;
|
||||
int err;
|
||||
|
||||
if (skb_network_offset(skb) || skb_vlan_tag_present(skb))
|
||||
return -EPROTO;
|
||||
|
||||
err = skb_cow_head(skb, sizeof(*eth));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
skb_push(skb, sizeof(*eth));
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_mac_len(skb);
|
||||
|
||||
eth = eth_hdr(skb);
|
||||
ether_addr_copy(eth->h_dest, dst);
|
||||
ether_addr_copy(eth->h_source, src);
|
||||
eth->h_proto = skb->protocol;
|
||||
|
||||
skb_postpush_rcsum(skb, eth, sizeof(*eth));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(skb_eth_push);
|
||||
|
||||
/* Update the ethertype of hdr and the skb csum value if required. */
|
||||
static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr,
|
||||
__be16 ethertype)
|
||||
|
||||
Reference in New Issue
Block a user