mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-19 09:04:57 +00:00
4e50025129
Some really really weird switches just couldn't decide whether to use a normal or a tail tagger, so they just did both. This creates problems for DSA, because we only have the concept of an 'overhead' which can be applied to the headroom or to the tailroom of the skb (like for example during the central TX reallocation procedure), depending on the value of bool tail_tag, but not to both. We need to generalize DSA to cater for these odd switches by transforming the 'overhead / tail_tag' pair into 'needed_headroom / needed_tailroom'. The DSA master's MTU is increased to account for both. The flow dissector code is modified such that it only calls the DSA adjustment callback if the tagger has a non-zero header length. Taggers are trivially modified to declare either needed_headroom or needed_tailroom, based on the tail_tag value that they currently declare. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
64 lines
1.3 KiB
C
64 lines
1.3 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* net/dsa/tag_trailer.c - Trailer tag format handling
|
|
* Copyright (c) 2008-2009 Marvell Semiconductor
|
|
*/
|
|
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/list.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "dsa_priv.h"
|
|
|
|
static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
u8 *trailer;
|
|
|
|
trailer = skb_put(skb, 4);
|
|
trailer[0] = 0x80;
|
|
trailer[1] = 1 << dp->index;
|
|
trailer[2] = 0x10;
|
|
trailer[3] = 0x00;
|
|
|
|
return skb;
|
|
}
|
|
|
|
static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev,
|
|
struct packet_type *pt)
|
|
{
|
|
u8 *trailer;
|
|
int source_port;
|
|
|
|
if (skb_linearize(skb))
|
|
return NULL;
|
|
|
|
trailer = skb_tail_pointer(skb) - 4;
|
|
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
|
|
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
|
|
return NULL;
|
|
|
|
source_port = trailer[1] & 7;
|
|
|
|
skb->dev = dsa_master_find_slave(dev, 0, source_port);
|
|
if (!skb->dev)
|
|
return NULL;
|
|
|
|
if (pskb_trim_rcsum(skb, skb->len - 4))
|
|
return NULL;
|
|
|
|
return skb;
|
|
}
|
|
|
|
static const struct dsa_device_ops trailer_netdev_ops = {
|
|
.name = "trailer",
|
|
.proto = DSA_TAG_PROTO_TRAILER,
|
|
.xmit = trailer_xmit,
|
|
.rcv = trailer_rcv,
|
|
.needed_tailroom = 4,
|
|
};
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_TRAILER);
|
|
|
|
module_dsa_tag_driver(trailer_netdev_ops);
|