Skip to content

Commit

Permalink
dsa: add support for Trailer tagging format
Browse files Browse the repository at this point in the history
This adds support for the Trailer switch tagging format.  This is
another tagging that doesn't explicitly mark tagged packets with a
distinct ethertype, so that we need to add a similar hack in the
receive path as for the Original DSA tagging format.

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Lennert Buytenhek authored and David S. Miller committed Oct 9, 2008
1 parent 2e5f032 commit 396138f
Showing 10 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/linux/if_ether.h
Original file line number Diff line number Diff line change
@@ -102,6 +102,7 @@
#define ETH_P_HDLC 0x0019 /* HDLC frames */
#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */
#define ETH_P_DSA 0x001B /* Distributed Switch Arch. */
#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */
#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */

/*
10 changes: 10 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
@@ -812,6 +812,16 @@ static inline bool netdev_uses_dsa_tags(struct net_device *dev)
return 0;
}

static inline bool netdev_uses_trailer_tags(struct net_device *dev)
{
#ifdef CONFIG_NET_DSA_TAG_TRAILER
if (dev->dsa_ptr != NULL)
return dsa_uses_trailer_tags(dev->dsa_ptr);
#endif

return 0;
}

/**
* netdev_priv - access network device private data
* @dev: network device
1 change: 1 addition & 0 deletions include/net/dsa.h
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ struct dsa_platform_data {
};

extern bool dsa_uses_dsa_tags(void *dsa_ptr);
extern bool dsa_uses_trailer_tags(void *dsa_ptr);


#endif
4 changes: 4 additions & 0 deletions net/dsa/Kconfig
Original file line number Diff line number Diff line change
@@ -18,6 +18,10 @@ config NET_DSA_TAG_EDSA
bool
default n

config NET_DSA_TAG_TRAILER
bool
default n


# switch drivers
config NET_DSA_MV88E6XXX
1 change: 1 addition & 0 deletions net/dsa/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# tagging formats
obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o

# switch drivers
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
7 changes: 7 additions & 0 deletions net/dsa/dsa.c
Original file line number Diff line number Diff line change
@@ -217,6 +217,13 @@ bool dsa_uses_dsa_tags(void *dsa_ptr)
return !!(ds->tag_protocol == htons(ETH_P_DSA));
}

bool dsa_uses_trailer_tags(void *dsa_ptr)
{
struct dsa_switch *ds = dsa_ptr;

return !!(ds->tag_protocol == htons(ETH_P_TRAILER));
}


/* link polling *************************************************************/
static void dsa_link_poll_work(struct work_struct *ugly)
3 changes: 3 additions & 0 deletions net/dsa/dsa_priv.h
Original file line number Diff line number Diff line change
@@ -109,5 +109,8 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev);
/* tag_edsa.c */
int edsa_xmit(struct sk_buff *skb, struct net_device *dev);

/* tag_trailer.c */
int trailer_xmit(struct sk_buff *skb, struct net_device *dev);


#endif
5 changes: 5 additions & 0 deletions net/dsa/slave.c
Original file line number Diff line number Diff line change
@@ -248,6 +248,11 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
case htons(ETH_P_EDSA):
slave_dev->hard_start_xmit = edsa_xmit;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
case htons(ETH_P_TRAILER):
slave_dev->hard_start_xmit = trailer_xmit;
break;
#endif
default:
BUG();
130 changes: 130 additions & 0 deletions net/dsa/tag_trailer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* net/dsa/tag_trailer.c - Trailer tag format handling
* Copyright (c) 2008 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <linux/etherdevice.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include "dsa_priv.h"

int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct sk_buff *nskb;
int padlen;
u8 *trailer;

dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;

/*
* We have to make sure that the trailer ends up as the very
* last 4 bytes of the packet. This means that we have to pad
* the packet to the minimum ethernet frame size, if necessary,
* before adding the trailer.
*/
padlen = 0;
if (skb->len < 60)
padlen = 60 - skb->len;

nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC);
if (nskb == NULL) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
skb_reserve(nskb, NET_IP_ALIGN);

skb_reset_mac_header(nskb);
skb_set_network_header(nskb, skb_network_header(skb) - skb->head);
skb_set_transport_header(nskb, skb_transport_header(skb) - skb->head);
skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len));
kfree_skb(skb);

if (padlen) {
u8 *pad = skb_put(nskb, padlen);
memset(pad, 0, padlen);
}

trailer = skb_put(nskb, 4);
trailer[0] = 0x80;
trailer[1] = 1 << p->port;
trailer[2] = 0x10;
trailer[3] = 0x00;

nskb->protocol = htons(ETH_P_TRAILER);

nskb->dev = p->parent->master_netdev;
dev_queue_xmit(nskb);

return NETDEV_TX_OK;
}

static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dsa_switch *ds = dev->dsa_ptr;
u8 *trailer;
int source_port;

if (unlikely(ds == NULL))
goto out_drop;

skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL)
goto out;

if (skb_linearize(skb))
goto out_drop;

trailer = skb_tail_pointer(skb) - 4;
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
(trailer[3] & 0xef) != 0x00 || trailer[3] != 0x00)
goto out_drop;

source_port = trailer[1] & 7;
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
goto out_drop;

pskb_trim_rcsum(skb, skb->len - 4);

skb->dev = ds->ports[source_port];
skb_push(skb, ETH_HLEN);
skb->protocol = eth_type_trans(skb, skb->dev);

skb->dev->last_rx = jiffies;
skb->dev->stats.rx_packets++;
skb->dev->stats.rx_bytes += skb->len;

netif_receive_skb(skb);

return 0;

out_drop:
kfree_skb(skb);
out:
return 0;
}

static struct packet_type trailer_packet_type = {
.type = __constant_htons(ETH_P_TRAILER),
.func = trailer_rcv,
};

static int __init trailer_init_module(void)
{
dev_add_pack(&trailer_packet_type);
return 0;
}
module_init(trailer_init_module);

static void __exit trailer_cleanup_module(void)
{
dev_remove_pack(&trailer_packet_type);
}
module_exit(trailer_cleanup_module);
2 changes: 2 additions & 0 deletions net/ethernet/eth.c
Original file line number Diff line number Diff line change
@@ -193,6 +193,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
*/
if (netdev_uses_dsa_tags(dev))
return htons(ETH_P_DSA);
if (netdev_uses_trailer_tags(dev))
return htons(ETH_P_TRAILER);

if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;

0 comments on commit 396138f

Please sign in to comment.