mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-26 23:55:40 +08:00
Merge branch 'Generic-adjustment-for-flow-dissector-in-DSA'
Vladimir Oltean says: ==================== Generic adjustment for flow dissector in DSA This is the v2 of a series initially submitted in May: https://www.spinics.net/lists/netdev/msg651866.html The end goal is to get rid of the unintuitive code for the flow dissector that currently exists in the taggers. It can all be replaced by a single, common function. Some background work needs to be done for that. Especially the ocelot driver poses some problems, since it has a different tag length between RX and TX, and I didn't want to make DSA aware of that, since I could instead make the tag lengths equal. Changes in v3: - Added an optimization (08/15) that makes the generic case not need to call the .flow_dissect function pointer. Basically .flow_dissect now currently only exists for sja1105. - Moved the .promisc_on_master property to the tagger structure. - Added the .tail_tag property to the tagger structure. - Disabled "suppresscc = all" from my .gitconfig. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
dfa6692104
@ -439,6 +439,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
|
||||
ocelot->vcap_is2_actions= felix->info->vcap_is2_actions;
|
||||
ocelot->vcap = felix->info->vcap;
|
||||
ocelot->ops = felix->info->ops;
|
||||
ocelot->inj_prefix = OCELOT_TAG_PREFIX_SHORT;
|
||||
ocelot->xtr_prefix = OCELOT_TAG_PREFIX_SHORT;
|
||||
|
||||
port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
|
||||
GFP_KERNEL);
|
||||
@ -509,7 +511,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
|
||||
return PTR_ERR(target);
|
||||
}
|
||||
|
||||
template = devm_kzalloc(ocelot->dev, OCELOT_TAG_LEN,
|
||||
template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN,
|
||||
GFP_KERNEL);
|
||||
if (!template) {
|
||||
dev_err(ocelot->dev,
|
||||
@ -538,6 +540,28 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The CPU port module is connected to the Node Processor Interface (NPI). This
|
||||
* is the mode through which frames can be injected from and extracted to an
|
||||
* external CPU, over Ethernet.
|
||||
*/
|
||||
static void felix_npi_port_init(struct ocelot *ocelot, int port)
|
||||
{
|
||||
ocelot->npi = port;
|
||||
|
||||
ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
|
||||
QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port),
|
||||
QSYS_EXT_CPU_CFG);
|
||||
|
||||
/* NPI port Injection/Extraction configuration */
|
||||
ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR,
|
||||
ocelot->xtr_prefix);
|
||||
ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR,
|
||||
ocelot->inj_prefix);
|
||||
|
||||
/* Disable transmission of pause frames */
|
||||
ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0);
|
||||
}
|
||||
|
||||
/* Hardware initialization done here so that we can allocate structures with
|
||||
* devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
|
||||
* us to allocate structures twice (leak memory) and map PCI memory twice
|
||||
@ -570,11 +594,8 @@ static int felix_setup(struct dsa_switch *ds)
|
||||
for (port = 0; port < ds->num_ports; port++) {
|
||||
ocelot_init_port(ocelot, port);
|
||||
|
||||
/* Bring up the CPU port module and configure the NPI port */
|
||||
if (dsa_is_cpu_port(ds, port))
|
||||
ocelot_configure_cpu(ocelot, port,
|
||||
OCELOT_TAG_PREFIX_NONE,
|
||||
OCELOT_TAG_PREFIX_LONG);
|
||||
felix_npi_port_init(ocelot, port);
|
||||
|
||||
/* Set the default QoS Classification based on PCP and DEI
|
||||
* bits of vlan tag.
|
||||
|
@ -1155,6 +1155,8 @@ static void vsc9959_xmit_template_populate(struct ocelot *ocelot, int port)
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
u8 *template = ocelot_port->xmit_template;
|
||||
u64 bypass, dest, src;
|
||||
__be32 *prefix;
|
||||
u8 *injection;
|
||||
|
||||
/* Set the source port as the CPU port module and not the
|
||||
* NPI port
|
||||
@ -1163,9 +1165,14 @@ static void vsc9959_xmit_template_populate(struct ocelot *ocelot, int port)
|
||||
dest = BIT(port);
|
||||
bypass = true;
|
||||
|
||||
packing(template, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(template, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(template, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
|
||||
injection = template + OCELOT_SHORT_PREFIX_LEN;
|
||||
prefix = (__be32 *)template;
|
||||
|
||||
packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(injection, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
|
||||
|
||||
*prefix = cpu_to_be32(0x8880000a);
|
||||
}
|
||||
|
||||
static const struct felix_info felix_info_vsc9959 = {
|
||||
|
@ -1003,6 +1003,8 @@ static void vsc9953_xmit_template_populate(struct ocelot *ocelot, int port)
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
u8 *template = ocelot_port->xmit_template;
|
||||
u64 bypass, dest, src;
|
||||
__be32 *prefix;
|
||||
u8 *injection;
|
||||
|
||||
/* Set the source port as the CPU port module and not the
|
||||
* NPI port
|
||||
@ -1011,9 +1013,14 @@ static void vsc9953_xmit_template_populate(struct ocelot *ocelot, int port)
|
||||
dest = BIT(port);
|
||||
bypass = true;
|
||||
|
||||
packing(template, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(template, &dest, 67, 57, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(template, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
|
||||
injection = template + OCELOT_SHORT_PREFIX_LEN;
|
||||
prefix = (__be32 *)template;
|
||||
|
||||
packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(injection, &dest, 67, 57, OCELOT_TAG_LEN, PACK, 0);
|
||||
packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
|
||||
|
||||
*prefix = cpu_to_be32(0x88800005);
|
||||
}
|
||||
|
||||
static const struct felix_info seville_info_vsc9953 = {
|
||||
|
@ -1346,22 +1346,14 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_init_port);
|
||||
|
||||
/* Configure and enable the CPU port module, which is a set of queues.
|
||||
* If @npi contains a valid port index, the CPU port module is connected
|
||||
* to the Node Processor Interface (NPI). This is the mode through which
|
||||
* frames can be injected from and extracted to an external CPU,
|
||||
* over Ethernet.
|
||||
/* Configure and enable the CPU port module, which is a set of queues
|
||||
* accessible through register MMIO, frame DMA or Ethernet (in case
|
||||
* NPI mode is used).
|
||||
*/
|
||||
void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
|
||||
enum ocelot_tag_prefix injection,
|
||||
enum ocelot_tag_prefix extraction)
|
||||
static void ocelot_cpu_port_init(struct ocelot *ocelot)
|
||||
{
|
||||
int cpu = ocelot->num_phys_ports;
|
||||
|
||||
ocelot->npi = npi;
|
||||
ocelot->inj_prefix = injection;
|
||||
ocelot->xtr_prefix = extraction;
|
||||
|
||||
/* The unicast destination PGID for the CPU port module is unused */
|
||||
ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
|
||||
/* Instead set up a multicast destination PGID for traffic copied to
|
||||
@ -1373,31 +1365,13 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
|
||||
ANA_PORT_PORT_CFG_PORTID_VAL(cpu),
|
||||
ANA_PORT_PORT_CFG, cpu);
|
||||
|
||||
if (npi >= 0 && npi < ocelot->num_phys_ports) {
|
||||
ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
|
||||
QSYS_EXT_CPU_CFG_EXT_CPU_PORT(npi),
|
||||
QSYS_EXT_CPU_CFG);
|
||||
|
||||
/* Enable NPI port */
|
||||
ocelot_fields_write(ocelot, npi,
|
||||
QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
|
||||
/* NPI port Injection/Extraction configuration */
|
||||
ocelot_fields_write(ocelot, npi, SYS_PORT_MODE_INCL_XTR_HDR,
|
||||
extraction);
|
||||
ocelot_fields_write(ocelot, npi, SYS_PORT_MODE_INCL_INJ_HDR,
|
||||
injection);
|
||||
|
||||
/* Disable transmission of pause frames */
|
||||
ocelot_fields_write(ocelot, npi, SYS_PAUSE_CFG_PAUSE_ENA, 0);
|
||||
}
|
||||
|
||||
/* Enable CPU port module */
|
||||
ocelot_fields_write(ocelot, cpu, QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
|
||||
/* CPU port Injection/Extraction configuration */
|
||||
ocelot_fields_write(ocelot, cpu, SYS_PORT_MODE_INCL_XTR_HDR,
|
||||
extraction);
|
||||
ocelot->xtr_prefix);
|
||||
ocelot_fields_write(ocelot, cpu, SYS_PORT_MODE_INCL_INJ_HDR,
|
||||
injection);
|
||||
ocelot->inj_prefix);
|
||||
|
||||
/* Configure the CPU port to be VLAN aware */
|
||||
ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
|
||||
@ -1405,7 +1379,6 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
|
||||
ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1),
|
||||
ANA_PORT_VLAN_CFG, cpu);
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_configure_cpu);
|
||||
|
||||
int ocelot_init(struct ocelot *ocelot)
|
||||
{
|
||||
@ -1445,6 +1418,7 @@ int ocelot_init(struct ocelot *ocelot)
|
||||
ocelot_mact_init(ocelot);
|
||||
ocelot_vlan_init(ocelot);
|
||||
ocelot_vcap_init(ocelot);
|
||||
ocelot_cpu_port_init(ocelot);
|
||||
|
||||
for (port = 0; port < ocelot->num_phys_ports; port++) {
|
||||
/* Clear all counters (5 groups) */
|
||||
|
@ -930,10 +930,6 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
|
||||
if (!ocelot->ports)
|
||||
return -ENOMEM;
|
||||
|
||||
/* No NPI port */
|
||||
ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE,
|
||||
OCELOT_TAG_PREFIX_NONE);
|
||||
|
||||
for_each_available_child_of_node(ports, portnp) {
|
||||
struct ocelot_port_private *priv;
|
||||
struct ocelot_port *ocelot_port;
|
||||
@ -1120,6 +1116,9 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
|
||||
ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
|
||||
ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
|
||||
ocelot->vcap = vsc7514_vcap_props;
|
||||
ocelot->inj_prefix = OCELOT_TAG_PREFIX_NONE;
|
||||
ocelot->xtr_prefix = OCELOT_TAG_PREFIX_NONE;
|
||||
ocelot->npi = -1;
|
||||
|
||||
err = ocelot_init(ocelot);
|
||||
if (err)
|
||||
|
@ -74,8 +74,8 @@ struct dsa_device_ops {
|
||||
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
|
||||
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt);
|
||||
int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset);
|
||||
void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset);
|
||||
/* Used to determine which traffic should match the DSA filter in
|
||||
* eth_type_trans, and which, if any, should bypass it and be processed
|
||||
* as regular on the master net device.
|
||||
@ -84,6 +84,13 @@ struct dsa_device_ops {
|
||||
unsigned int overhead;
|
||||
const char *name;
|
||||
enum dsa_tag_protocol proto;
|
||||
/* Some tagging protocols either mangle or shift the destination MAC
|
||||
* address, in which case the DSA master would drop packets on ingress
|
||||
* if what it understands out of the destination MAC address is not in
|
||||
* its RX filter.
|
||||
*/
|
||||
bool promisc_on_master;
|
||||
bool tail_tag;
|
||||
};
|
||||
|
||||
/* This structure defines the control interfaces that are overlayed by the
|
||||
@ -705,6 +712,32 @@ static inline bool dsa_can_decode(const struct sk_buff *skb,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* All DSA tags that push the EtherType to the right (basically all except tail
|
||||
* tags, which don't break dissection) can be treated the same from the
|
||||
* perspective of the flow dissector.
|
||||
*
|
||||
* We need to return:
|
||||
* - offset: the (B - A) difference between:
|
||||
* A. the position of the real EtherType and
|
||||
* B. the current skb->data (aka ETH_HLEN bytes into the frame, aka 2 bytes
|
||||
* after the normal EtherType was supposed to be)
|
||||
* The offset in bytes is exactly equal to the tagger overhead (and half of
|
||||
* that, in __be16 shorts).
|
||||
*
|
||||
* - proto: the value of the real EtherType.
|
||||
*/
|
||||
static inline void dsa_tag_generic_flow_dissect(const struct sk_buff *skb,
|
||||
__be16 *proto, int *offset)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
const struct dsa_device_ops *ops = skb->dev->dsa_ptr->tag_ops;
|
||||
int tag_len = ops->overhead;
|
||||
|
||||
*offset = tag_len;
|
||||
*proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
static inline int __dsa_netdevice_ops_check(struct net_device *dev)
|
||||
{
|
||||
|
@ -101,6 +101,7 @@
|
||||
#define OCELOT_TAG_LEN 16
|
||||
#define OCELOT_SHORT_PREFIX_LEN 4
|
||||
#define OCELOT_LONG_PREFIX_LEN 16
|
||||
#define OCELOT_TOTAL_TAG_LEN (OCELOT_SHORT_PREFIX_LEN + OCELOT_TAG_LEN)
|
||||
|
||||
#define OCELOT_SPEED_2500 0
|
||||
#define OCELOT_SPEED_1000 1
|
||||
@ -672,9 +673,6 @@ void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
|
||||
int ocelot_regfields_init(struct ocelot *ocelot,
|
||||
const struct reg_field *const regfields);
|
||||
struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res);
|
||||
void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
|
||||
enum ocelot_tag_prefix injection,
|
||||
enum ocelot_tag_prefix extraction);
|
||||
int ocelot_init(struct ocelot *ocelot);
|
||||
void ocelot_deinit(struct ocelot *ocelot);
|
||||
void ocelot_init_port(struct ocelot *ocelot, int port);
|
||||
|
@ -932,8 +932,14 @@ bool __skb_flow_dissect(const struct net *net,
|
||||
int offset = 0;
|
||||
|
||||
ops = skb->dev->dsa_ptr->tag_ops;
|
||||
if (ops->flow_dissect &&
|
||||
!ops->flow_dissect(skb, &proto, &offset)) {
|
||||
/* Tail taggers don't break flow dissection */
|
||||
if (!ops->tail_tag) {
|
||||
if (ops->flow_dissect)
|
||||
ops->flow_dissect(skb, &proto, &offset);
|
||||
else
|
||||
dsa_tag_generic_flow_dissect(skb,
|
||||
&proto,
|
||||
&offset);
|
||||
hlen -= offset;
|
||||
nhoff += offset;
|
||||
}
|
||||
|
@ -259,6 +259,18 @@ static void dsa_netdev_ops_set(struct net_device *dev,
|
||||
dev->dsa_ptr->netdev_ops = ops;
|
||||
}
|
||||
|
||||
static void dsa_master_set_promiscuity(struct net_device *dev, int inc)
|
||||
{
|
||||
const struct dsa_device_ops *ops = dev->dsa_ptr->tag_ops;
|
||||
|
||||
if (!ops->promisc_on_master)
|
||||
return;
|
||||
|
||||
rtnl_lock();
|
||||
dev_set_promiscuity(dev, inc);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static ssize_t tagging_show(struct device *d, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
@ -314,9 +326,12 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
|
||||
dev->dsa_ptr = cpu_dp;
|
||||
lockdep_set_class(&dev->addr_list_lock,
|
||||
&dsa_master_addr_list_lock_key);
|
||||
|
||||
dsa_master_set_promiscuity(dev, 1);
|
||||
|
||||
ret = dsa_master_ethtool_setup(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_err_reset_promisc;
|
||||
|
||||
dsa_netdev_ops_set(dev, &dsa_netdev_ops);
|
||||
|
||||
@ -329,6 +344,8 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
|
||||
out_err_ndo_teardown:
|
||||
dsa_netdev_ops_set(dev, NULL);
|
||||
dsa_master_ethtool_teardown(dev);
|
||||
out_err_reset_promisc:
|
||||
dsa_master_set_promiscuity(dev, -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -338,6 +355,7 @@ void dsa_master_teardown(struct net_device *dev)
|
||||
dsa_netdev_ops_set(dev, NULL);
|
||||
dsa_master_ethtool_teardown(dev);
|
||||
dsa_master_reset_mtu(dev);
|
||||
dsa_master_set_promiscuity(dev, -1);
|
||||
|
||||
dev->dsa_ptr = NULL;
|
||||
|
||||
|
@ -107,6 +107,18 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
|
||||
return skb;
|
||||
}
|
||||
|
||||
/* Frames with this tag have one of these two layouts:
|
||||
* -----------------------------------
|
||||
* | MAC DA | MAC SA | 4b tag | Type | DSA_TAG_PROTO_BRCM
|
||||
* -----------------------------------
|
||||
* -----------------------------------
|
||||
* | 4b tag | MAC DA | MAC SA | Type | DSA_TAG_PROTO_BRCM_PREPEND
|
||||
* -----------------------------------
|
||||
* In both cases, at receive time, skb->data points 2 bytes before the actual
|
||||
* Ethernet type field and we have an offset of 4bytes between where skb->data
|
||||
* and where the payload starts. So the same low-level receive function can be
|
||||
* used.
|
||||
*/
|
||||
static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct packet_type *pt,
|
||||
@ -149,27 +161,6 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int brcm_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
/* We have been called on the DSA master network device after
|
||||
* eth_type_trans() which pulled the Ethernet header already.
|
||||
* Frames have one of these two layouts:
|
||||
* -----------------------------------
|
||||
* | MAC DA | MAC SA | 4b tag | Type | DSA_TAG_PROTO_BRCM
|
||||
* -----------------------------------
|
||||
* -----------------------------------
|
||||
* | 4b tag | MAC DA | MAC SA | Type | DSA_TAG_PROTO_BRCM_PREPEND
|
||||
* -----------------------------------
|
||||
* skb->data points 2 bytes before the actual Ethernet type field and
|
||||
* we have an offset of 4bytes between where skb->data and where the
|
||||
* payload starts.
|
||||
*/
|
||||
*offset = BRCM_TAG_LEN;
|
||||
*proto = ((__be16 *)skb->data)[1];
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
|
||||
@ -205,7 +196,6 @@ static const struct dsa_device_ops brcm_netdev_ops = {
|
||||
.xmit = brcm_tag_xmit,
|
||||
.rcv = brcm_tag_rcv,
|
||||
.overhead = BRCM_TAG_LEN,
|
||||
.flow_dissect = brcm_tag_flow_dissect,
|
||||
};
|
||||
|
||||
DSA_TAG_DRIVER(brcm_netdev_ops);
|
||||
@ -240,7 +230,6 @@ static const struct dsa_device_ops brcm_prepend_netdev_ops = {
|
||||
.xmit = brcm_tag_xmit_prepend,
|
||||
.rcv = brcm_tag_rcv_prepend,
|
||||
.overhead = BRCM_TAG_LEN,
|
||||
.flow_dissect = brcm_tag_flow_dissect,
|
||||
};
|
||||
|
||||
DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
|
||||
|
@ -142,20 +142,11 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int dsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
*offset = 4;
|
||||
*proto = ((__be16 *)skb->data)[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops dsa_netdev_ops = {
|
||||
.name = "dsa",
|
||||
.proto = DSA_TAG_PROTO_DSA,
|
||||
.xmit = dsa_xmit,
|
||||
.rcv = dsa_rcv,
|
||||
.flow_dissect = dsa_tag_flow_dissect,
|
||||
.overhead = DSA_HLEN,
|
||||
};
|
||||
|
||||
|
@ -192,20 +192,11 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int edsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
*offset = 8;
|
||||
*proto = ((__be16 *)skb->data)[3];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops edsa_netdev_ops = {
|
||||
.name = "edsa",
|
||||
.proto = DSA_TAG_PROTO_EDSA,
|
||||
.xmit = edsa_xmit,
|
||||
.rcv = edsa_rcv,
|
||||
.flow_dissect = edsa_tag_flow_dissect,
|
||||
.overhead = EDSA_HLEN,
|
||||
};
|
||||
|
||||
|
@ -237,6 +237,7 @@ static const struct dsa_device_ops ksz9893_netdev_ops = {
|
||||
.xmit = ksz9893_xmit,
|
||||
.rcv = ksz9477_rcv,
|
||||
.overhead = KSZ_INGRESS_TAG_LEN,
|
||||
.tail_tag = true,
|
||||
};
|
||||
|
||||
DSA_TAG_DRIVER(ksz9893_netdev_ops);
|
||||
|
@ -105,21 +105,11 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
*offset = 4;
|
||||
*proto = ((__be16 *)skb->data)[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops mtk_netdev_ops = {
|
||||
.name = "mtk",
|
||||
.proto = DSA_TAG_PROTO_MTK,
|
||||
.xmit = mtk_tag_xmit,
|
||||
.rcv = mtk_tag_rcv,
|
||||
.flow_dissect = mtk_tag_flow_dissect,
|
||||
.overhead = MTK_HDR_LEN,
|
||||
};
|
||||
|
||||
|
@ -141,10 +141,12 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
struct ocelot *ocelot = ds->priv;
|
||||
struct ocelot_port *ocelot_port;
|
||||
u8 *prefix, *injection;
|
||||
u64 qos_class, rew_op;
|
||||
u8 *injection;
|
||||
int err;
|
||||
|
||||
if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
|
||||
err = skb_cow_head(skb, OCELOT_TOTAL_TAG_LEN);
|
||||
if (unlikely(err < 0)) {
|
||||
netdev_err(netdev, "Cannot make room for tag.\n");
|
||||
return NULL;
|
||||
}
|
||||
@ -153,7 +155,10 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
|
||||
|
||||
injection = skb_push(skb, OCELOT_TAG_LEN);
|
||||
|
||||
memcpy(injection, ocelot_port->xmit_template, OCELOT_TAG_LEN);
|
||||
prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN);
|
||||
|
||||
memcpy(prefix, ocelot_port->xmit_template, OCELOT_TOTAL_TAG_LEN);
|
||||
|
||||
/* Fix up the fields which are not statically determined
|
||||
* in the template
|
||||
*/
|
||||
@ -187,11 +192,11 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
|
||||
* so it points to the beginning of the frame.
|
||||
*/
|
||||
skb_push(skb, ETH_HLEN);
|
||||
/* We don't care about the long prefix, it is just for easy entrance
|
||||
/* We don't care about the short prefix, it is just for easy entrance
|
||||
* into the DSA master's RX filter. Discard it now by moving it into
|
||||
* the headroom.
|
||||
*/
|
||||
skb_pull(skb, OCELOT_LONG_PREFIX_LEN);
|
||||
skb_pull(skb, OCELOT_SHORT_PREFIX_LEN);
|
||||
/* And skb->data now points to the extraction frame header.
|
||||
* Keep a pointer to it.
|
||||
*/
|
||||
@ -205,7 +210,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
|
||||
skb_pull(skb, ETH_HLEN);
|
||||
|
||||
/* Remove from inet csum the extraction header */
|
||||
skb_postpull_rcsum(skb, start, OCELOT_LONG_PREFIX_LEN + OCELOT_TAG_LEN);
|
||||
skb_postpull_rcsum(skb, start, OCELOT_TOTAL_TAG_LEN);
|
||||
|
||||
packing(extraction, &src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
|
||||
packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
|
||||
@ -231,7 +236,8 @@ static const struct dsa_device_ops ocelot_netdev_ops = {
|
||||
.proto = DSA_TAG_PROTO_OCELOT,
|
||||
.xmit = ocelot_xmit,
|
||||
.rcv = ocelot_rcv,
|
||||
.overhead = OCELOT_TAG_LEN + OCELOT_LONG_PREFIX_LEN,
|
||||
.overhead = OCELOT_TOTAL_TAG_LEN,
|
||||
.promisc_on_master = true,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -89,21 +89,11 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int qca_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
*offset = QCA_HDR_LEN;
|
||||
*proto = ((__be16 *)skb->data)[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops qca_netdev_ops = {
|
||||
.name = "qca",
|
||||
.proto = DSA_TAG_PROTO_QCA,
|
||||
.xmit = qca_tag_xmit,
|
||||
.rcv = qca_tag_rcv,
|
||||
.flow_dissect = qca_tag_flow_dissect,
|
||||
.overhead = QCA_HDR_LEN,
|
||||
};
|
||||
|
||||
|
@ -106,22 +106,11 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int rtl4a_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
*offset = RTL4_A_HDR_LEN;
|
||||
/* Skip past the tag and fetch the encapsulated Ethertype */
|
||||
*proto = ((__be16 *)skb->data)[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops rtl4a_netdev_ops = {
|
||||
.name = "rtl4a",
|
||||
.proto = DSA_TAG_PROTO_RTL4_A,
|
||||
.xmit = rtl4a_tag_xmit,
|
||||
.rcv = rtl4a_tag_rcv,
|
||||
.flow_dissect = rtl4a_tag_flow_dissect,
|
||||
.overhead = RTL4_A_HDR_LEN,
|
||||
};
|
||||
module_dsa_tag_driver(rtl4a_netdev_ops);
|
||||
|
@ -346,6 +346,16 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
|
||||
is_meta);
|
||||
}
|
||||
|
||||
static void sja1105_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset)
|
||||
{
|
||||
/* No tag added for management frames, all ok */
|
||||
if (unlikely(sja1105_is_link_local(skb)))
|
||||
return;
|
||||
|
||||
dsa_tag_generic_flow_dissect(skb, proto, offset);
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops sja1105_netdev_ops = {
|
||||
.name = "sja1105",
|
||||
.proto = DSA_TAG_PROTO_SJA1105,
|
||||
@ -353,6 +363,8 @@ static const struct dsa_device_ops sja1105_netdev_ops = {
|
||||
.rcv = sja1105_rcv,
|
||||
.filter = sja1105_filter,
|
||||
.overhead = VLAN_HLEN,
|
||||
.flow_dissect = sja1105_flow_dissect,
|
||||
.promisc_on_master = true,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -83,6 +83,7 @@ static const struct dsa_device_ops trailer_netdev_ops = {
|
||||
.xmit = trailer_xmit,
|
||||
.rcv = trailer_rcv,
|
||||
.overhead = 4,
|
||||
.tail_tag = true,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
Loading…
Reference in New Issue
Block a user