2019-04-28 17:37:10 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2008-10-07 13:45:02 +00:00
|
|
|
/*
|
2020-11-14 23:45:57 +00:00
|
|
|
* Regular and Ethertype DSA tagging
|
dsa: add switch chip cascading support
The initial version of the DSA driver only supported a single switch
chip per network interface, while DSA-capable switch chips can be
interconnected to form a tree of switch chips. This patch adds support
for multiple switch chips on a network interface.
An example topology for a 16-port device with an embedded CPU is as
follows:
+-----+ +--------+ +--------+
| |eth0 10| switch |9 10| switch |
| CPU +----------+ +-------+ |
| | | chip 0 | | chip 1 |
+-----+ +---++---+ +---++---+
|| ||
|| ||
||1000baseT ||1000baseT
||ports 1-8 ||ports 9-16
This requires a couple of interdependent changes in the DSA layer:
- The dsa platform driver data needs to be extended: there is still
only one netdevice per DSA driver instance (eth0 in the example
above), but each of the switch chips in the tree needs its own
mii_bus device pointer, MII management bus address, and port name
array. (include/net/dsa.h) The existing in-tree dsa users need
some small changes to deal with this. (arch/arm)
- The DSA and Ethertype DSA tagging modules need to be extended to
use the DSA device ID field on receive and demultiplex the packet
accordingly, and fill in the DSA device ID field on transmit
according to which switch chip the packet is heading to.
(net/dsa/tag_{dsa,edsa}.c)
- The concept of "CPU port", which is the switch chip port that the
CPU is connected to (port 10 on switch chip 0 in the example), needs
to be extended with the concept of "upstream port", which is the
port on the switch chip that will bring us one hop closer to the CPU
(port 10 for both switch chips in the example above).
- The dsa platform data needs to specify which ports on which switch
chips are links to other switch chips, so that we can enable DSA
tagging mode on them. (For inter-switch links, we always use
non-EtherType DSA tagging, since it has lower overhead. The CPU
link uses dsa or edsa tagging depending on what the 'root' switch
chip supports.) This is done by specifying "dsa" for the given
port in the port array.
- The dsa platform data needs to be extended with information on via
which port to reach any given switch chip from any given switch chip.
This info is specified via the per-switch chip data struct ->rtable[]
array, which gives the nexthop ports for each of the other switches
in the tree.
For the example topology above, the dsa platform data would look
something like this:
static struct dsa_chip_data sw[2] = {
{
.mii_bus = &foo,
.sw_addr = 1,
.port_names[0] = "p1",
.port_names[1] = "p2",
.port_names[2] = "p3",
.port_names[3] = "p4",
.port_names[4] = "p5",
.port_names[5] = "p6",
.port_names[6] = "p7",
.port_names[7] = "p8",
.port_names[9] = "dsa",
.port_names[10] = "cpu",
.rtable = (s8 []){ -1, 9, },
}, {
.mii_bus = &foo,
.sw_addr = 2,
.port_names[0] = "p9",
.port_names[1] = "p10",
.port_names[2] = "p11",
.port_names[3] = "p12",
.port_names[4] = "p13",
.port_names[5] = "p14",
.port_names[6] = "p15",
.port_names[7] = "p16",
.port_names[10] = "dsa",
.rtable = (s8 []){ 10, -1, },
},
},
static struct dsa_platform_data pd = {
.netdev = &foo,
.nr_switches = 2,
.sw = sw,
};
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Gary Thomas <gary@mlbassoc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-03-20 09:52:09 +00:00
|
|
|
* Copyright (c) 2008-2009 Marvell Semiconductor
|
2020-11-14 23:45:57 +00:00
|
|
|
*
|
|
|
|
* Regular DSA
|
|
|
|
* -----------
|
|
|
|
|
|
|
|
* For untagged (in 802.1Q terms) packets, the switch will splice in
|
|
|
|
* the tag between the SA and the ethertype of the original
|
|
|
|
* packet. Tagged frames will instead have their outermost .1Q tag
|
|
|
|
* converted to a DSA tag. It expects the same layout when receiving
|
|
|
|
* packets from the CPU.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* .----.----.----.---------
|
|
|
|
* Pu: | DA | SA | ET | Payload ...
|
|
|
|
* '----'----'----'---------
|
|
|
|
* 6 6 2 N
|
|
|
|
* .----.----.--------.-----.----.---------
|
|
|
|
* Pt: | DA | SA | 0x8100 | TCI | ET | Payload ...
|
|
|
|
* '----'----'--------'-----'----'---------
|
|
|
|
* 6 6 2 2 2 N
|
|
|
|
* .----.----.-----.----.---------
|
|
|
|
* Pd: | DA | SA | DSA | ET | Payload ...
|
|
|
|
* '----'----'-----'----'---------
|
|
|
|
* 6 6 4 2 N
|
|
|
|
*
|
|
|
|
* No matter if a packet is received untagged (Pu) or tagged (Pt),
|
|
|
|
* they will both have the same layout (Pd) when they are sent to the
|
|
|
|
* CPU. This is done by ignoring 802.3, replacing the ethertype field
|
|
|
|
* with more metadata, among which is a bit to signal if the original
|
|
|
|
* packet was tagged or not.
|
|
|
|
*
|
|
|
|
* Ethertype DSA
|
|
|
|
* -------------
|
|
|
|
* Uses the exact same tag format as regular DSA, but also includes a
|
|
|
|
* proper ethertype field (which the mv88e6xxx driver sets to
|
|
|
|
* ETH_P_EDSA/0xdada) followed by two zero bytes:
|
|
|
|
*
|
|
|
|
* .----.----.--------.--------.-----.----.---------
|
|
|
|
* | DA | SA | 0xdada | 0x0000 | DSA | ET | Payload ...
|
|
|
|
* '----'----'--------'--------'-----'----'---------
|
|
|
|
* 6 6 2 2 4 2 N
|
2008-10-07 13:45:02 +00:00
|
|
|
*/
|
|
|
|
|
net: dsa: mv88e6xxx: isolate the ATU databases of standalone and bridged ports
Similar to commit 6087175b7991 ("net: dsa: mt7530: use independent VLAN
learning on VLAN-unaware bridges"), software forwarding between an
unoffloaded LAG port (a bonding interface with an unsupported policy)
and a mv88e6xxx user port directly under a bridge is broken.
We adopt the same strategy, which is to make the standalone ports not
find any ATU entry learned on a bridge port.
Theory: the mv88e6xxx ATU is looked up by FID and MAC address. There are
as many FIDs as VIDs (4096). The FID is derived from the VID when
possible (the VTU maps a VID to a FID), with a fallback to the port
based default FID value when not (802.1Q Mode is disabled on the port,
or the classified VID isn't present in the VTU).
The mv88e6xxx driver makes the following use of FIDs and VIDs:
- the port's DefaultVID (to which untagged & pvid-tagged packets get
classified) is 0 and is absent from the VTU, so this kind of packets is
processed in FID 0, the default FID assigned by mv88e6xxx_setup_port.
- every time a bridge VLAN is created, mv88e6xxx_port_vlan_join() ->
mv88e6xxx_atu_new() associates a FID with that VID which increases
linearly starting from 1. Like this:
bridge vlan add dev lan0 vid 100 # FID 1
bridge vlan add dev lan1 vid 100 # still FID 1
bridge vlan add dev lan2 vid 1024 # FID 2
The FID allocation made by the driver is sub-optimal for the following
reasons:
(a) A standalone port has a DefaultPVID of 0 and a default FID of 0 too.
A VLAN-unaware bridged port has a DefaultPVID of 0 and a default FID
of 0 too. The difference is that the bridged ports may learn ATU
entries, while the standalone port has the requirement that it must
not, and must not find them either. Standalone ports must not use
the same FID as ports belonging to a bridge. All standalone ports
can use the same FID, since the ATU will never have an entry in
that FID.
(b) Multiple VLAN-unaware bridges will all use a DefaultPVID of 0 and a
default FID of 0 on all their ports. The FDBs will not be isolated
between these bridges. Every VLAN-unaware bridge must use the same
FID on all its ports, different from the FID of other bridge ports.
(c) Each bridge VLAN uses a unique FID which is useful for Independent
VLAN Learning, but the same VLAN ID on multiple VLAN-aware bridges
will result in the same FID being used by mv88e6xxx_atu_new().
The correct behavior is for VLAN 1 in br0 to have a different FID
compared to VLAN 1 in br1.
This patch cannot fix all the above. Traditionally the DSA framework did
not care about this, and the reality is that DSA core involvement is
needed for the aforementioned issues to be solved. The only thing we can
solve here is an issue which does not require API changes, and that is
issue (a), aka use a different FID for standalone ports vs ports under
VLAN-unaware bridges.
The first step is deciding what VID and FID to use for standalone ports,
and what VID and FID for bridged ports. The 0/0 pair for standalone
ports is what they used up till now, let's keep using that. For bridged
ports, there are 2 cases:
- VLAN-aware ports will never end up using the port default FID, because
packets will always be classified to a VID in the VTU or dropped
otherwise. The FID is the one associated with the VID in the VTU.
- On VLAN-unaware ports, we _could_ leave their DefaultVID (pvid) at
zero (just as in the case of standalone ports), and just change the
port's default FID from 0 to a different number (say 1).
However, Tobias points out that there is one more requirement to cater to:
cross-chip bridging. The Marvell DSA header does not carry the FID in
it, only the VID. So once a packet crosses a DSA link, if it has a VID
of zero it will get classified to the default FID of that cascade port.
Relying on a port default FID for upstream cascade ports results in
contradictions: a default FID of 0 breaks ATU isolation of bridged ports
on the downstream switch, a default FID of 1 breaks standalone ports on
the downstream switch.
So not only must standalone ports have different FIDs compared to
bridged ports, they must also have different DefaultVID values.
IEEE 802.1Q defines two reserved VID values: 0 and 4095. So we simply
choose 4095 as the DefaultVID of ports belonging to VLAN-unaware
bridges, and VID 4095 maps to FID 1.
For the xmit operation to look up the same ATU database, we need to put
VID 4095 in DSA tags sent to ports belonging to VLAN-unaware bridges
too. All shared ports are configured to map this VID to the bridging
FID, because they are members of that VLAN in the VTU. Shared ports
don't need to have 802.1QMode enabled in any way, they always parse the
VID from the DSA header, they don't need to look at the 802.1Q header.
We install VID 4095 to the VTU in mv88e6xxx_setup_port(), with the
mention that mv88e6xxx_vtu_setup() which was located right below that
call was flushing the VTU so those entries wouldn't be preserved.
So we need to relocate the VTU flushing prior to the port initialization
during ->setup(). Also note that this is why it is safe to assume that
VID 4095 will get associated with FID 1: the user ports haven't been
created, so there is no avenue for the user to create a bridge VLAN
which could otherwise race with the creation of another FID which would
otherwise use up the non-reserved FID value of 1.
[ Currently mv88e6xxx_port_vlan_join() doesn't have the option of
specifying a preferred FID, it always calls mv88e6xxx_atu_new(). ]
mv88e6xxx_port_db_load_purge() is the function to access the ATU for
FDB/MDB entries, and it used to determine the FID to use for
VLAN-unaware FDB entries (VID=0) using mv88e6xxx_port_get_fid().
But the driver only called mv88e6xxx_port_set_fid() once, during probe,
so no surprises, the port FID was always 0, the call to get_fid() was
redundant. As much as I would have wanted to not touch that code, the
logic is broken when we add a new FID which is not the port-based
default. Now the port-based default FID only corresponds to standalone
ports, and FDB/MDB entries belong to the bridging service. So while in
the future, when the DSA API will support FDB isolation, we will have to
figure out the FID based on the bridge number, for now there's a single
bridging FID, so hardcode that.
Lastly, the tagger needs to check, when it is transmitting a VLAN
untagged skb, whether it is sending it towards a bridged or a standalone
port. When we see it is bridged we assume the bridge is VLAN-unaware.
Not because it cannot be VLAN-aware but:
- if we are transmitting from a VLAN-aware bridge we are likely doing so
using TX forwarding offload. That code path guarantees that skbs have
a vlan hwaccel tag in them, so we would not enter the "else" branch
of the "if (skb->protocol == htons(ETH_P_8021Q))" condition.
- if we are transmitting on behalf of a VLAN-aware bridge but with no TX
forwarding offload (no PVT support, out of space in the PVT, whatever),
we would indeed be transmitting with VLAN 4095 instead of the bridge
device's pvid. However we would be injecting a "From CPU" frame, and
the switch won't learn from that - it only learns from "Forward" frames.
So it is inconsequential for address learning. And VLAN 4095 is
absolutely enough for the frame to exit the switch, since we never
remove that VLAN from any port.
Fixes: 57e661aae6a8 ("net: dsa: mv88e6xxx: Link aggregation support")
Reported-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-10-07 16:47:11 +00:00
|
|
|
#include <linux/dsa/mv88e6xxx.h>
|
2008-10-07 13:45:02 +00:00
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/list.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2017-05-17 19:46:03 +00:00
|
|
|
|
2008-10-07 13:45:02 +00:00
|
|
|
#include "dsa_priv.h"
|
|
|
|
|
|
|
|
#define DSA_HLEN 4
|
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
/**
|
|
|
|
* enum dsa_cmd - DSA Command
|
|
|
|
* @DSA_CMD_TO_CPU: Set on packets that were trapped or mirrored to
|
|
|
|
* the CPU port. This is needed to implement control protocols,
|
|
|
|
* e.g. STP and LLDP, that must not allow those control packets to
|
|
|
|
* be switched according to the normal rules.
|
|
|
|
* @DSA_CMD_FROM_CPU: Used by the CPU to send a packet to a specific
|
|
|
|
* port, ignoring all the barriers that the switch normally
|
|
|
|
* enforces (VLANs, STP port states etc.). No source address
|
|
|
|
* learning takes place. "sudo send packet"
|
|
|
|
* @DSA_CMD_TO_SNIFFER: Set on the copies of packets that matched some
|
|
|
|
* user configured ingress or egress monitor criteria. These are
|
|
|
|
* forwarded by the switch tree to the user configured ingress or
|
|
|
|
* egress monitor port, which can be set to the CPU port or a
|
|
|
|
* regular port. If the destination is a regular port, the tag
|
|
|
|
* will be removed before egressing the port. If the destination
|
|
|
|
* is the CPU port, the tag will not be removed.
|
|
|
|
* @DSA_CMD_FORWARD: This tag is used on all bulk traffic passing
|
|
|
|
* through the switch tree, including the flows that are directed
|
|
|
|
* towards the CPU. Its device/port tuple encodes the original
|
|
|
|
* source port on which the packet ingressed. It can also be used
|
|
|
|
* on transmit by the CPU to defer the forwarding decision to the
|
|
|
|
* hardware, based on the current config of PVT/VTU/ATU
|
|
|
|
* etc. Source address learning takes places if enabled on the
|
|
|
|
* receiving DSA/CPU port.
|
|
|
|
*/
|
|
|
|
enum dsa_cmd {
|
|
|
|
DSA_CMD_TO_CPU = 0,
|
|
|
|
DSA_CMD_FROM_CPU = 1,
|
|
|
|
DSA_CMD_TO_SNIFFER = 2,
|
|
|
|
DSA_CMD_FORWARD = 3
|
|
|
|
};
|
2020-11-14 23:45:56 +00:00
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
/**
|
|
|
|
* enum dsa_code - TO_CPU Code
|
|
|
|
*
|
|
|
|
* @DSA_CODE_MGMT_TRAP: DA was classified as a management
|
|
|
|
* address. Typical examples include STP BPDUs and LLDP.
|
|
|
|
* @DSA_CODE_FRAME2REG: Response to a "remote management" request.
|
|
|
|
* @DSA_CODE_IGMP_MLD_TRAP: IGMP/MLD signaling.
|
|
|
|
* @DSA_CODE_POLICY_TRAP: Frame matched some policy configuration on
|
|
|
|
* the device. Typical examples are matching on DA/SA/VID and DHCP
|
|
|
|
* snooping.
|
|
|
|
* @DSA_CODE_ARP_MIRROR: The name says it all really.
|
|
|
|
* @DSA_CODE_POLICY_MIRROR: Same as @DSA_CODE_POLICY_TRAP, but the
|
|
|
|
* particular policy was set to trigger a mirror instead of a
|
|
|
|
* trap.
|
|
|
|
* @DSA_CODE_RESERVED_6: Unused on all devices up to at least 6393X.
|
|
|
|
* @DSA_CODE_RESERVED_7: Unused on all devices up to at least 6393X.
|
|
|
|
*
|
|
|
|
* A 3-bit code is used to relay why a particular frame was sent to
|
|
|
|
* the CPU. We only use this to determine if the packet was mirrored
|
|
|
|
* or trapped, i.e. whether the packet has been forwarded by hardware
|
|
|
|
* or not.
|
|
|
|
*
|
|
|
|
* This is the superset of all possible codes. Any particular device
|
|
|
|
* may only implement a subset.
|
|
|
|
*/
|
|
|
|
enum dsa_code {
|
|
|
|
DSA_CODE_MGMT_TRAP = 0,
|
|
|
|
DSA_CODE_FRAME2REG = 1,
|
|
|
|
DSA_CODE_IGMP_MLD_TRAP = 2,
|
|
|
|
DSA_CODE_POLICY_TRAP = 3,
|
|
|
|
DSA_CODE_ARP_MIRROR = 4,
|
|
|
|
DSA_CODE_POLICY_MIRROR = 5,
|
|
|
|
DSA_CODE_RESERVED_6 = 6,
|
|
|
|
DSA_CODE_RESERVED_7 = 7
|
|
|
|
};
|
2020-11-14 23:45:56 +00:00
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
u8 extra)
|
2008-10-07 13:45:02 +00:00
|
|
|
{
|
2017-10-16 15:12:15 +00:00
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
2021-07-22 15:55:42 +00:00
|
|
|
u8 tag_dev, tag_port;
|
|
|
|
enum dsa_cmd cmd;
|
2008-10-07 13:45:02 +00:00
|
|
|
u8 *dsa_header;
|
2021-07-22 15:55:42 +00:00
|
|
|
|
|
|
|
if (skb->offload_fwd_mark) {
|
2021-12-06 16:57:52 +00:00
|
|
|
unsigned int bridge_num = dsa_port_bridge_num_get(dp);
|
2021-07-22 15:55:42 +00:00
|
|
|
struct dsa_switch_tree *dst = dp->ds->dst;
|
|
|
|
|
|
|
|
cmd = DSA_CMD_FORWARD;
|
|
|
|
|
|
|
|
/* When offloading forwarding for a bridge, inject FORWARD
|
|
|
|
* packets on behalf of a virtual switch device with an index
|
|
|
|
* past the physical switches.
|
|
|
|
*/
|
2021-12-06 16:57:52 +00:00
|
|
|
tag_dev = dst->last_switch + bridge_num;
|
2021-07-22 15:55:42 +00:00
|
|
|
tag_port = 0;
|
|
|
|
} else {
|
|
|
|
cmd = DSA_CMD_FROM_CPU;
|
|
|
|
tag_dev = dp->ds->index;
|
|
|
|
tag_port = dp->index;
|
|
|
|
}
|
2008-10-07 13:45:02 +00:00
|
|
|
|
|
|
|
if (skb->protocol == htons(ETH_P_8021Q)) {
|
2020-11-14 23:45:57 +00:00
|
|
|
if (extra) {
|
|
|
|
skb_push(skb, extra);
|
2021-08-10 13:13:54 +00:00
|
|
|
dsa_alloc_etype_header(skb, extra);
|
2020-11-14 23:45:57 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 15:55:42 +00:00
|
|
|
/* Construct tagged DSA tag from 802.1Q tag. */
|
2021-08-10 13:13:56 +00:00
|
|
|
dsa_header = dsa_etype_header_pos_tx(skb) + extra;
|
2021-07-22 15:55:42 +00:00
|
|
|
dsa_header[0] = (cmd << 6) | 0x20 | tag_dev;
|
|
|
|
dsa_header[1] = tag_port << 3;
|
2008-10-07 13:45:02 +00:00
|
|
|
|
2020-11-14 23:45:58 +00:00
|
|
|
/* Move CFI field from byte 2 to byte 1. */
|
2008-10-07 13:45:02 +00:00
|
|
|
if (dsa_header[2] & 0x10) {
|
|
|
|
dsa_header[1] |= 0x01;
|
|
|
|
dsa_header[2] &= ~0x10;
|
|
|
|
}
|
|
|
|
} else {
|
2021-12-06 16:57:52 +00:00
|
|
|
struct net_device *br = dsa_port_bridge_dev_get(dp);
|
net: dsa: mv88e6xxx: isolate the ATU databases of standalone and bridged ports
Similar to commit 6087175b7991 ("net: dsa: mt7530: use independent VLAN
learning on VLAN-unaware bridges"), software forwarding between an
unoffloaded LAG port (a bonding interface with an unsupported policy)
and a mv88e6xxx user port directly under a bridge is broken.
We adopt the same strategy, which is to make the standalone ports not
find any ATU entry learned on a bridge port.
Theory: the mv88e6xxx ATU is looked up by FID and MAC address. There are
as many FIDs as VIDs (4096). The FID is derived from the VID when
possible (the VTU maps a VID to a FID), with a fallback to the port
based default FID value when not (802.1Q Mode is disabled on the port,
or the classified VID isn't present in the VTU).
The mv88e6xxx driver makes the following use of FIDs and VIDs:
- the port's DefaultVID (to which untagged & pvid-tagged packets get
classified) is 0 and is absent from the VTU, so this kind of packets is
processed in FID 0, the default FID assigned by mv88e6xxx_setup_port.
- every time a bridge VLAN is created, mv88e6xxx_port_vlan_join() ->
mv88e6xxx_atu_new() associates a FID with that VID which increases
linearly starting from 1. Like this:
bridge vlan add dev lan0 vid 100 # FID 1
bridge vlan add dev lan1 vid 100 # still FID 1
bridge vlan add dev lan2 vid 1024 # FID 2
The FID allocation made by the driver is sub-optimal for the following
reasons:
(a) A standalone port has a DefaultPVID of 0 and a default FID of 0 too.
A VLAN-unaware bridged port has a DefaultPVID of 0 and a default FID
of 0 too. The difference is that the bridged ports may learn ATU
entries, while the standalone port has the requirement that it must
not, and must not find them either. Standalone ports must not use
the same FID as ports belonging to a bridge. All standalone ports
can use the same FID, since the ATU will never have an entry in
that FID.
(b) Multiple VLAN-unaware bridges will all use a DefaultPVID of 0 and a
default FID of 0 on all their ports. The FDBs will not be isolated
between these bridges. Every VLAN-unaware bridge must use the same
FID on all its ports, different from the FID of other bridge ports.
(c) Each bridge VLAN uses a unique FID which is useful for Independent
VLAN Learning, but the same VLAN ID on multiple VLAN-aware bridges
will result in the same FID being used by mv88e6xxx_atu_new().
The correct behavior is for VLAN 1 in br0 to have a different FID
compared to VLAN 1 in br1.
This patch cannot fix all the above. Traditionally the DSA framework did
not care about this, and the reality is that DSA core involvement is
needed for the aforementioned issues to be solved. The only thing we can
solve here is an issue which does not require API changes, and that is
issue (a), aka use a different FID for standalone ports vs ports under
VLAN-unaware bridges.
The first step is deciding what VID and FID to use for standalone ports,
and what VID and FID for bridged ports. The 0/0 pair for standalone
ports is what they used up till now, let's keep using that. For bridged
ports, there are 2 cases:
- VLAN-aware ports will never end up using the port default FID, because
packets will always be classified to a VID in the VTU or dropped
otherwise. The FID is the one associated with the VID in the VTU.
- On VLAN-unaware ports, we _could_ leave their DefaultVID (pvid) at
zero (just as in the case of standalone ports), and just change the
port's default FID from 0 to a different number (say 1).
However, Tobias points out that there is one more requirement to cater to:
cross-chip bridging. The Marvell DSA header does not carry the FID in
it, only the VID. So once a packet crosses a DSA link, if it has a VID
of zero it will get classified to the default FID of that cascade port.
Relying on a port default FID for upstream cascade ports results in
contradictions: a default FID of 0 breaks ATU isolation of bridged ports
on the downstream switch, a default FID of 1 breaks standalone ports on
the downstream switch.
So not only must standalone ports have different FIDs compared to
bridged ports, they must also have different DefaultVID values.
IEEE 802.1Q defines two reserved VID values: 0 and 4095. So we simply
choose 4095 as the DefaultVID of ports belonging to VLAN-unaware
bridges, and VID 4095 maps to FID 1.
For the xmit operation to look up the same ATU database, we need to put
VID 4095 in DSA tags sent to ports belonging to VLAN-unaware bridges
too. All shared ports are configured to map this VID to the bridging
FID, because they are members of that VLAN in the VTU. Shared ports
don't need to have 802.1QMode enabled in any way, they always parse the
VID from the DSA header, they don't need to look at the 802.1Q header.
We install VID 4095 to the VTU in mv88e6xxx_setup_port(), with the
mention that mv88e6xxx_vtu_setup() which was located right below that
call was flushing the VTU so those entries wouldn't be preserved.
So we need to relocate the VTU flushing prior to the port initialization
during ->setup(). Also note that this is why it is safe to assume that
VID 4095 will get associated with FID 1: the user ports haven't been
created, so there is no avenue for the user to create a bridge VLAN
which could otherwise race with the creation of another FID which would
otherwise use up the non-reserved FID value of 1.
[ Currently mv88e6xxx_port_vlan_join() doesn't have the option of
specifying a preferred FID, it always calls mv88e6xxx_atu_new(). ]
mv88e6xxx_port_db_load_purge() is the function to access the ATU for
FDB/MDB entries, and it used to determine the FID to use for
VLAN-unaware FDB entries (VID=0) using mv88e6xxx_port_get_fid().
But the driver only called mv88e6xxx_port_set_fid() once, during probe,
so no surprises, the port FID was always 0, the call to get_fid() was
redundant. As much as I would have wanted to not touch that code, the
logic is broken when we add a new FID which is not the port-based
default. Now the port-based default FID only corresponds to standalone
ports, and FDB/MDB entries belong to the bridging service. So while in
the future, when the DSA API will support FDB isolation, we will have to
figure out the FID based on the bridge number, for now there's a single
bridging FID, so hardcode that.
Lastly, the tagger needs to check, when it is transmitting a VLAN
untagged skb, whether it is sending it towards a bridged or a standalone
port. When we see it is bridged we assume the bridge is VLAN-unaware.
Not because it cannot be VLAN-aware but:
- if we are transmitting from a VLAN-aware bridge we are likely doing so
using TX forwarding offload. That code path guarantees that skbs have
a vlan hwaccel tag in them, so we would not enter the "else" branch
of the "if (skb->protocol == htons(ETH_P_8021Q))" condition.
- if we are transmitting on behalf of a VLAN-aware bridge but with no TX
forwarding offload (no PVT support, out of space in the PVT, whatever),
we would indeed be transmitting with VLAN 4095 instead of the bridge
device's pvid. However we would be injecting a "From CPU" frame, and
the switch won't learn from that - it only learns from "Forward" frames.
So it is inconsequential for address learning. And VLAN 4095 is
absolutely enough for the frame to exit the switch, since we never
remove that VLAN from any port.
Fixes: 57e661aae6a8 ("net: dsa: mv88e6xxx: Link aggregation support")
Reported-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-10-07 16:47:11 +00:00
|
|
|
u16 vid;
|
|
|
|
|
|
|
|
vid = br ? MV88E6XXX_VID_BRIDGED : MV88E6XXX_VID_STANDALONE;
|
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
skb_push(skb, DSA_HLEN + extra);
|
2021-08-10 13:13:54 +00:00
|
|
|
dsa_alloc_etype_header(skb, DSA_HLEN + extra);
|
2008-10-07 13:45:02 +00:00
|
|
|
|
net: dsa: mv88e6xxx: isolate the ATU databases of standalone and bridged ports
Similar to commit 6087175b7991 ("net: dsa: mt7530: use independent VLAN
learning on VLAN-unaware bridges"), software forwarding between an
unoffloaded LAG port (a bonding interface with an unsupported policy)
and a mv88e6xxx user port directly under a bridge is broken.
We adopt the same strategy, which is to make the standalone ports not
find any ATU entry learned on a bridge port.
Theory: the mv88e6xxx ATU is looked up by FID and MAC address. There are
as many FIDs as VIDs (4096). The FID is derived from the VID when
possible (the VTU maps a VID to a FID), with a fallback to the port
based default FID value when not (802.1Q Mode is disabled on the port,
or the classified VID isn't present in the VTU).
The mv88e6xxx driver makes the following use of FIDs and VIDs:
- the port's DefaultVID (to which untagged & pvid-tagged packets get
classified) is 0 and is absent from the VTU, so this kind of packets is
processed in FID 0, the default FID assigned by mv88e6xxx_setup_port.
- every time a bridge VLAN is created, mv88e6xxx_port_vlan_join() ->
mv88e6xxx_atu_new() associates a FID with that VID which increases
linearly starting from 1. Like this:
bridge vlan add dev lan0 vid 100 # FID 1
bridge vlan add dev lan1 vid 100 # still FID 1
bridge vlan add dev lan2 vid 1024 # FID 2
The FID allocation made by the driver is sub-optimal for the following
reasons:
(a) A standalone port has a DefaultPVID of 0 and a default FID of 0 too.
A VLAN-unaware bridged port has a DefaultPVID of 0 and a default FID
of 0 too. The difference is that the bridged ports may learn ATU
entries, while the standalone port has the requirement that it must
not, and must not find them either. Standalone ports must not use
the same FID as ports belonging to a bridge. All standalone ports
can use the same FID, since the ATU will never have an entry in
that FID.
(b) Multiple VLAN-unaware bridges will all use a DefaultPVID of 0 and a
default FID of 0 on all their ports. The FDBs will not be isolated
between these bridges. Every VLAN-unaware bridge must use the same
FID on all its ports, different from the FID of other bridge ports.
(c) Each bridge VLAN uses a unique FID which is useful for Independent
VLAN Learning, but the same VLAN ID on multiple VLAN-aware bridges
will result in the same FID being used by mv88e6xxx_atu_new().
The correct behavior is for VLAN 1 in br0 to have a different FID
compared to VLAN 1 in br1.
This patch cannot fix all the above. Traditionally the DSA framework did
not care about this, and the reality is that DSA core involvement is
needed for the aforementioned issues to be solved. The only thing we can
solve here is an issue which does not require API changes, and that is
issue (a), aka use a different FID for standalone ports vs ports under
VLAN-unaware bridges.
The first step is deciding what VID and FID to use for standalone ports,
and what VID and FID for bridged ports. The 0/0 pair for standalone
ports is what they used up till now, let's keep using that. For bridged
ports, there are 2 cases:
- VLAN-aware ports will never end up using the port default FID, because
packets will always be classified to a VID in the VTU or dropped
otherwise. The FID is the one associated with the VID in the VTU.
- On VLAN-unaware ports, we _could_ leave their DefaultVID (pvid) at
zero (just as in the case of standalone ports), and just change the
port's default FID from 0 to a different number (say 1).
However, Tobias points out that there is one more requirement to cater to:
cross-chip bridging. The Marvell DSA header does not carry the FID in
it, only the VID. So once a packet crosses a DSA link, if it has a VID
of zero it will get classified to the default FID of that cascade port.
Relying on a port default FID for upstream cascade ports results in
contradictions: a default FID of 0 breaks ATU isolation of bridged ports
on the downstream switch, a default FID of 1 breaks standalone ports on
the downstream switch.
So not only must standalone ports have different FIDs compared to
bridged ports, they must also have different DefaultVID values.
IEEE 802.1Q defines two reserved VID values: 0 and 4095. So we simply
choose 4095 as the DefaultVID of ports belonging to VLAN-unaware
bridges, and VID 4095 maps to FID 1.
For the xmit operation to look up the same ATU database, we need to put
VID 4095 in DSA tags sent to ports belonging to VLAN-unaware bridges
too. All shared ports are configured to map this VID to the bridging
FID, because they are members of that VLAN in the VTU. Shared ports
don't need to have 802.1QMode enabled in any way, they always parse the
VID from the DSA header, they don't need to look at the 802.1Q header.
We install VID 4095 to the VTU in mv88e6xxx_setup_port(), with the
mention that mv88e6xxx_vtu_setup() which was located right below that
call was flushing the VTU so those entries wouldn't be preserved.
So we need to relocate the VTU flushing prior to the port initialization
during ->setup(). Also note that this is why it is safe to assume that
VID 4095 will get associated with FID 1: the user ports haven't been
created, so there is no avenue for the user to create a bridge VLAN
which could otherwise race with the creation of another FID which would
otherwise use up the non-reserved FID value of 1.
[ Currently mv88e6xxx_port_vlan_join() doesn't have the option of
specifying a preferred FID, it always calls mv88e6xxx_atu_new(). ]
mv88e6xxx_port_db_load_purge() is the function to access the ATU for
FDB/MDB entries, and it used to determine the FID to use for
VLAN-unaware FDB entries (VID=0) using mv88e6xxx_port_get_fid().
But the driver only called mv88e6xxx_port_set_fid() once, during probe,
so no surprises, the port FID was always 0, the call to get_fid() was
redundant. As much as I would have wanted to not touch that code, the
logic is broken when we add a new FID which is not the port-based
default. Now the port-based default FID only corresponds to standalone
ports, and FDB/MDB entries belong to the bridging service. So while in
the future, when the DSA API will support FDB isolation, we will have to
figure out the FID based on the bridge number, for now there's a single
bridging FID, so hardcode that.
Lastly, the tagger needs to check, when it is transmitting a VLAN
untagged skb, whether it is sending it towards a bridged or a standalone
port. When we see it is bridged we assume the bridge is VLAN-unaware.
Not because it cannot be VLAN-aware but:
- if we are transmitting from a VLAN-aware bridge we are likely doing so
using TX forwarding offload. That code path guarantees that skbs have
a vlan hwaccel tag in them, so we would not enter the "else" branch
of the "if (skb->protocol == htons(ETH_P_8021Q))" condition.
- if we are transmitting on behalf of a VLAN-aware bridge but with no TX
forwarding offload (no PVT support, out of space in the PVT, whatever),
we would indeed be transmitting with VLAN 4095 instead of the bridge
device's pvid. However we would be injecting a "From CPU" frame, and
the switch won't learn from that - it only learns from "Forward" frames.
So it is inconsequential for address learning. And VLAN 4095 is
absolutely enough for the frame to exit the switch, since we never
remove that VLAN from any port.
Fixes: 57e661aae6a8 ("net: dsa: mv88e6xxx: Link aggregation support")
Reported-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-10-07 16:47:11 +00:00
|
|
|
/* Construct DSA header from untagged frame. */
|
2021-08-10 13:13:56 +00:00
|
|
|
dsa_header = dsa_etype_header_pos_tx(skb) + extra;
|
2021-07-22 15:55:42 +00:00
|
|
|
|
|
|
|
dsa_header[0] = (cmd << 6) | tag_dev;
|
|
|
|
dsa_header[1] = tag_port << 3;
|
net: dsa: mv88e6xxx: isolate the ATU databases of standalone and bridged ports
Similar to commit 6087175b7991 ("net: dsa: mt7530: use independent VLAN
learning on VLAN-unaware bridges"), software forwarding between an
unoffloaded LAG port (a bonding interface with an unsupported policy)
and a mv88e6xxx user port directly under a bridge is broken.
We adopt the same strategy, which is to make the standalone ports not
find any ATU entry learned on a bridge port.
Theory: the mv88e6xxx ATU is looked up by FID and MAC address. There are
as many FIDs as VIDs (4096). The FID is derived from the VID when
possible (the VTU maps a VID to a FID), with a fallback to the port
based default FID value when not (802.1Q Mode is disabled on the port,
or the classified VID isn't present in the VTU).
The mv88e6xxx driver makes the following use of FIDs and VIDs:
- the port's DefaultVID (to which untagged & pvid-tagged packets get
classified) is 0 and is absent from the VTU, so this kind of packets is
processed in FID 0, the default FID assigned by mv88e6xxx_setup_port.
- every time a bridge VLAN is created, mv88e6xxx_port_vlan_join() ->
mv88e6xxx_atu_new() associates a FID with that VID which increases
linearly starting from 1. Like this:
bridge vlan add dev lan0 vid 100 # FID 1
bridge vlan add dev lan1 vid 100 # still FID 1
bridge vlan add dev lan2 vid 1024 # FID 2
The FID allocation made by the driver is sub-optimal for the following
reasons:
(a) A standalone port has a DefaultPVID of 0 and a default FID of 0 too.
A VLAN-unaware bridged port has a DefaultPVID of 0 and a default FID
of 0 too. The difference is that the bridged ports may learn ATU
entries, while the standalone port has the requirement that it must
not, and must not find them either. Standalone ports must not use
the same FID as ports belonging to a bridge. All standalone ports
can use the same FID, since the ATU will never have an entry in
that FID.
(b) Multiple VLAN-unaware bridges will all use a DefaultPVID of 0 and a
default FID of 0 on all their ports. The FDBs will not be isolated
between these bridges. Every VLAN-unaware bridge must use the same
FID on all its ports, different from the FID of other bridge ports.
(c) Each bridge VLAN uses a unique FID which is useful for Independent
VLAN Learning, but the same VLAN ID on multiple VLAN-aware bridges
will result in the same FID being used by mv88e6xxx_atu_new().
The correct behavior is for VLAN 1 in br0 to have a different FID
compared to VLAN 1 in br1.
This patch cannot fix all the above. Traditionally the DSA framework did
not care about this, and the reality is that DSA core involvement is
needed for the aforementioned issues to be solved. The only thing we can
solve here is an issue which does not require API changes, and that is
issue (a), aka use a different FID for standalone ports vs ports under
VLAN-unaware bridges.
The first step is deciding what VID and FID to use for standalone ports,
and what VID and FID for bridged ports. The 0/0 pair for standalone
ports is what they used up till now, let's keep using that. For bridged
ports, there are 2 cases:
- VLAN-aware ports will never end up using the port default FID, because
packets will always be classified to a VID in the VTU or dropped
otherwise. The FID is the one associated with the VID in the VTU.
- On VLAN-unaware ports, we _could_ leave their DefaultVID (pvid) at
zero (just as in the case of standalone ports), and just change the
port's default FID from 0 to a different number (say 1).
However, Tobias points out that there is one more requirement to cater to:
cross-chip bridging. The Marvell DSA header does not carry the FID in
it, only the VID. So once a packet crosses a DSA link, if it has a VID
of zero it will get classified to the default FID of that cascade port.
Relying on a port default FID for upstream cascade ports results in
contradictions: a default FID of 0 breaks ATU isolation of bridged ports
on the downstream switch, a default FID of 1 breaks standalone ports on
the downstream switch.
So not only must standalone ports have different FIDs compared to
bridged ports, they must also have different DefaultVID values.
IEEE 802.1Q defines two reserved VID values: 0 and 4095. So we simply
choose 4095 as the DefaultVID of ports belonging to VLAN-unaware
bridges, and VID 4095 maps to FID 1.
For the xmit operation to look up the same ATU database, we need to put
VID 4095 in DSA tags sent to ports belonging to VLAN-unaware bridges
too. All shared ports are configured to map this VID to the bridging
FID, because they are members of that VLAN in the VTU. Shared ports
don't need to have 802.1QMode enabled in any way, they always parse the
VID from the DSA header, they don't need to look at the 802.1Q header.
We install VID 4095 to the VTU in mv88e6xxx_setup_port(), with the
mention that mv88e6xxx_vtu_setup() which was located right below that
call was flushing the VTU so those entries wouldn't be preserved.
So we need to relocate the VTU flushing prior to the port initialization
during ->setup(). Also note that this is why it is safe to assume that
VID 4095 will get associated with FID 1: the user ports haven't been
created, so there is no avenue for the user to create a bridge VLAN
which could otherwise race with the creation of another FID which would
otherwise use up the non-reserved FID value of 1.
[ Currently mv88e6xxx_port_vlan_join() doesn't have the option of
specifying a preferred FID, it always calls mv88e6xxx_atu_new(). ]
mv88e6xxx_port_db_load_purge() is the function to access the ATU for
FDB/MDB entries, and it used to determine the FID to use for
VLAN-unaware FDB entries (VID=0) using mv88e6xxx_port_get_fid().
But the driver only called mv88e6xxx_port_set_fid() once, during probe,
so no surprises, the port FID was always 0, the call to get_fid() was
redundant. As much as I would have wanted to not touch that code, the
logic is broken when we add a new FID which is not the port-based
default. Now the port-based default FID only corresponds to standalone
ports, and FDB/MDB entries belong to the bridging service. So while in
the future, when the DSA API will support FDB isolation, we will have to
figure out the FID based on the bridge number, for now there's a single
bridging FID, so hardcode that.
Lastly, the tagger needs to check, when it is transmitting a VLAN
untagged skb, whether it is sending it towards a bridged or a standalone
port. When we see it is bridged we assume the bridge is VLAN-unaware.
Not because it cannot be VLAN-aware but:
- if we are transmitting from a VLAN-aware bridge we are likely doing so
using TX forwarding offload. That code path guarantees that skbs have
a vlan hwaccel tag in them, so we would not enter the "else" branch
of the "if (skb->protocol == htons(ETH_P_8021Q))" condition.
- if we are transmitting on behalf of a VLAN-aware bridge but with no TX
forwarding offload (no PVT support, out of space in the PVT, whatever),
we would indeed be transmitting with VLAN 4095 instead of the bridge
device's pvid. However we would be injecting a "From CPU" frame, and
the switch won't learn from that - it only learns from "Forward" frames.
So it is inconsequential for address learning. And VLAN 4095 is
absolutely enough for the frame to exit the switch, since we never
remove that VLAN from any port.
Fixes: 57e661aae6a8 ("net: dsa: mv88e6xxx: Link aggregation support")
Reported-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-10-07 16:47:11 +00:00
|
|
|
dsa_header[2] = vid >> 8;
|
|
|
|
dsa_header[3] = vid & 0xff;
|
2008-10-07 13:45:02 +00:00
|
|
|
}
|
|
|
|
|
2015-07-31 18:42:56 +00:00
|
|
|
return skb;
|
2008-10-07 13:45:02 +00:00
|
|
|
}
|
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
u8 extra)
|
2008-10-07 13:45:02 +00:00
|
|
|
{
|
2021-07-29 14:56:00 +00:00
|
|
|
bool trap = false, trunk = false;
|
2020-11-14 23:45:57 +00:00
|
|
|
int source_device, source_port;
|
|
|
|
enum dsa_code code;
|
|
|
|
enum dsa_cmd cmd;
|
2008-10-07 13:45:02 +00:00
|
|
|
u8 *dsa_header;
|
|
|
|
|
2020-11-14 23:45:58 +00:00
|
|
|
/* The ethertype field is part of the DSA header. */
|
2021-08-10 13:13:55 +00:00
|
|
|
dsa_header = dsa_etype_header_pos_rx(skb);
|
2008-10-07 13:45:02 +00:00
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
cmd = dsa_header[0] >> 6;
|
|
|
|
switch (cmd) {
|
|
|
|
case DSA_CMD_FORWARD:
|
2021-10-03 15:50:53 +00:00
|
|
|
trunk = !!(dsa_header[1] & 4);
|
2020-11-14 23:45:57 +00:00
|
|
|
break;
|
2020-11-14 23:45:56 +00:00
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
case DSA_CMD_TO_CPU:
|
2020-11-14 23:45:56 +00:00
|
|
|
code = (dsa_header[1] & 0x6) | ((dsa_header[2] >> 4) & 1);
|
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
switch (code) {
|
|
|
|
case DSA_CODE_FRAME2REG:
|
|
|
|
/* Remote management is not implemented yet,
|
|
|
|
* drop.
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
case DSA_CODE_ARP_MIRROR:
|
|
|
|
case DSA_CODE_POLICY_MIRROR:
|
|
|
|
/* Mark mirrored packets to notify any upper
|
|
|
|
* device (like a bridge) that forwarding has
|
|
|
|
* already been done by hardware.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case DSA_CODE_MGMT_TRAP:
|
|
|
|
case DSA_CODE_IGMP_MLD_TRAP:
|
|
|
|
case DSA_CODE_POLICY_TRAP:
|
|
|
|
/* Traps have, by definition, not been
|
|
|
|
* forwarded by hardware, so don't mark them.
|
|
|
|
*/
|
2021-07-29 14:56:00 +00:00
|
|
|
trap = true;
|
2020-11-14 23:45:57 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Reserved code, this could be anything. Drop
|
|
|
|
* seems like the safest option.
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-11-14 23:45:56 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-06-01 20:07:14 +00:00
|
|
|
return NULL;
|
2020-11-14 23:45:56 +00:00
|
|
|
}
|
2008-10-07 13:45:02 +00:00
|
|
|
|
dsa: add switch chip cascading support
The initial version of the DSA driver only supported a single switch
chip per network interface, while DSA-capable switch chips can be
interconnected to form a tree of switch chips. This patch adds support
for multiple switch chips on a network interface.
An example topology for a 16-port device with an embedded CPU is as
follows:
+-----+ +--------+ +--------+
| |eth0 10| switch |9 10| switch |
| CPU +----------+ +-------+ |
| | | chip 0 | | chip 1 |
+-----+ +---++---+ +---++---+
|| ||
|| ||
||1000baseT ||1000baseT
||ports 1-8 ||ports 9-16
This requires a couple of interdependent changes in the DSA layer:
- The dsa platform driver data needs to be extended: there is still
only one netdevice per DSA driver instance (eth0 in the example
above), but each of the switch chips in the tree needs its own
mii_bus device pointer, MII management bus address, and port name
array. (include/net/dsa.h) The existing in-tree dsa users need
some small changes to deal with this. (arch/arm)
- The DSA and Ethertype DSA tagging modules need to be extended to
use the DSA device ID field on receive and demultiplex the packet
accordingly, and fill in the DSA device ID field on transmit
according to which switch chip the packet is heading to.
(net/dsa/tag_{dsa,edsa}.c)
- The concept of "CPU port", which is the switch chip port that the
CPU is connected to (port 10 on switch chip 0 in the example), needs
to be extended with the concept of "upstream port", which is the
port on the switch chip that will bring us one hop closer to the CPU
(port 10 for both switch chips in the example above).
- The dsa platform data needs to specify which ports on which switch
chips are links to other switch chips, so that we can enable DSA
tagging mode on them. (For inter-switch links, we always use
non-EtherType DSA tagging, since it has lower overhead. The CPU
link uses dsa or edsa tagging depending on what the 'root' switch
chip supports.) This is done by specifying "dsa" for the given
port in the port array.
- The dsa platform data needs to be extended with information on via
which port to reach any given switch chip from any given switch chip.
This info is specified via the per-switch chip data struct ->rtable[]
array, which gives the nexthop ports for each of the other switches
in the tree.
For the example topology above, the dsa platform data would look
something like this:
static struct dsa_chip_data sw[2] = {
{
.mii_bus = &foo,
.sw_addr = 1,
.port_names[0] = "p1",
.port_names[1] = "p2",
.port_names[2] = "p3",
.port_names[3] = "p4",
.port_names[4] = "p5",
.port_names[5] = "p6",
.port_names[6] = "p7",
.port_names[7] = "p8",
.port_names[9] = "dsa",
.port_names[10] = "cpu",
.rtable = (s8 []){ -1, 9, },
}, {
.mii_bus = &foo,
.sw_addr = 2,
.port_names[0] = "p9",
.port_names[1] = "p10",
.port_names[2] = "p11",
.port_names[3] = "p12",
.port_names[4] = "p13",
.port_names[5] = "p14",
.port_names[6] = "p15",
.port_names[7] = "p16",
.port_names[10] = "dsa",
.rtable = (s8 []){ 10, -1, },
},
},
static struct dsa_platform_data pd = {
.netdev = &foo,
.nr_switches = 2,
.sw = sw,
};
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Gary Thomas <gary@mlbassoc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-03-20 09:52:09 +00:00
|
|
|
source_device = dsa_header[0] & 0x1f;
|
2008-10-07 13:45:02 +00:00
|
|
|
source_port = (dsa_header[1] >> 3) & 0x1f;
|
dsa: add switch chip cascading support
The initial version of the DSA driver only supported a single switch
chip per network interface, while DSA-capable switch chips can be
interconnected to form a tree of switch chips. This patch adds support
for multiple switch chips on a network interface.
An example topology for a 16-port device with an embedded CPU is as
follows:
+-----+ +--------+ +--------+
| |eth0 10| switch |9 10| switch |
| CPU +----------+ +-------+ |
| | | chip 0 | | chip 1 |
+-----+ +---++---+ +---++---+
|| ||
|| ||
||1000baseT ||1000baseT
||ports 1-8 ||ports 9-16
This requires a couple of interdependent changes in the DSA layer:
- The dsa platform driver data needs to be extended: there is still
only one netdevice per DSA driver instance (eth0 in the example
above), but each of the switch chips in the tree needs its own
mii_bus device pointer, MII management bus address, and port name
array. (include/net/dsa.h) The existing in-tree dsa users need
some small changes to deal with this. (arch/arm)
- The DSA and Ethertype DSA tagging modules need to be extended to
use the DSA device ID field on receive and demultiplex the packet
accordingly, and fill in the DSA device ID field on transmit
according to which switch chip the packet is heading to.
(net/dsa/tag_{dsa,edsa}.c)
- The concept of "CPU port", which is the switch chip port that the
CPU is connected to (port 10 on switch chip 0 in the example), needs
to be extended with the concept of "upstream port", which is the
port on the switch chip that will bring us one hop closer to the CPU
(port 10 for both switch chips in the example above).
- The dsa platform data needs to specify which ports on which switch
chips are links to other switch chips, so that we can enable DSA
tagging mode on them. (For inter-switch links, we always use
non-EtherType DSA tagging, since it has lower overhead. The CPU
link uses dsa or edsa tagging depending on what the 'root' switch
chip supports.) This is done by specifying "dsa" for the given
port in the port array.
- The dsa platform data needs to be extended with information on via
which port to reach any given switch chip from any given switch chip.
This info is specified via the per-switch chip data struct ->rtable[]
array, which gives the nexthop ports for each of the other switches
in the tree.
For the example topology above, the dsa platform data would look
something like this:
static struct dsa_chip_data sw[2] = {
{
.mii_bus = &foo,
.sw_addr = 1,
.port_names[0] = "p1",
.port_names[1] = "p2",
.port_names[2] = "p3",
.port_names[3] = "p4",
.port_names[4] = "p5",
.port_names[5] = "p6",
.port_names[6] = "p7",
.port_names[7] = "p8",
.port_names[9] = "dsa",
.port_names[10] = "cpu",
.rtable = (s8 []){ -1, 9, },
}, {
.mii_bus = &foo,
.sw_addr = 2,
.port_names[0] = "p9",
.port_names[1] = "p10",
.port_names[2] = "p11",
.port_names[3] = "p12",
.port_names[4] = "p13",
.port_names[5] = "p14",
.port_names[6] = "p15",
.port_names[7] = "p16",
.port_names[10] = "dsa",
.rtable = (s8 []){ 10, -1, },
},
},
static struct dsa_platform_data pd = {
.netdev = &foo,
.nr_switches = 2,
.sw = sw,
};
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Gary Thomas <gary@mlbassoc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-03-20 09:52:09 +00:00
|
|
|
|
2021-01-13 08:42:55 +00:00
|
|
|
if (trunk) {
|
|
|
|
struct dsa_port *cpu_dp = dev->dsa_ptr;
|
2022-02-23 14:00:49 +00:00
|
|
|
struct dsa_lag *lag;
|
2021-01-13 08:42:55 +00:00
|
|
|
|
|
|
|
/* The exact source port is not available in the tag,
|
|
|
|
* so we inject the frame directly on the upper
|
|
|
|
* team/bond.
|
|
|
|
*/
|
2022-02-23 14:00:49 +00:00
|
|
|
lag = dsa_lag_by_id(cpu_dp->dst, source_port + 1);
|
|
|
|
skb->dev = lag ? lag->dev : NULL;
|
2021-01-13 08:42:55 +00:00
|
|
|
} else {
|
|
|
|
skb->dev = dsa_master_find_slave(dev, source_device,
|
|
|
|
source_port);
|
|
|
|
}
|
|
|
|
|
2017-09-29 21:19:15 +00:00
|
|
|
if (!skb->dev)
|
2017-06-01 20:07:14 +00:00
|
|
|
return NULL;
|
2008-10-07 13:45:02 +00:00
|
|
|
|
2021-07-29 14:56:00 +00:00
|
|
|
/* When using LAG offload, skb->dev is not a DSA slave interface,
|
|
|
|
* so we cannot call dsa_default_offload_fwd_mark and we need to
|
|
|
|
* special-case it.
|
|
|
|
*/
|
|
|
|
if (trunk)
|
|
|
|
skb->offload_fwd_mark = true;
|
|
|
|
else if (!trap)
|
|
|
|
dsa_default_offload_fwd_mark(skb);
|
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
/* If the 'tagged' bit is set; convert the DSA tag to a 802.1Q
|
|
|
|
* tag, and delete the ethertype (extra) if applicable. If the
|
|
|
|
* 'tagged' bit is cleared; delete the DSA tag, and ethertype
|
|
|
|
* if applicable.
|
2008-10-07 13:45:02 +00:00
|
|
|
*/
|
|
|
|
if (dsa_header[0] & 0x20) {
|
|
|
|
u8 new_header[4];
|
|
|
|
|
2020-11-14 23:45:58 +00:00
|
|
|
/* Insert 802.1Q ethertype and copy the VLAN-related
|
2008-10-07 13:45:02 +00:00
|
|
|
* fields, but clear the bit that will hold CFI (since
|
|
|
|
* DSA uses that bit location for another purpose).
|
|
|
|
*/
|
|
|
|
new_header[0] = (ETH_P_8021Q >> 8) & 0xff;
|
|
|
|
new_header[1] = ETH_P_8021Q & 0xff;
|
|
|
|
new_header[2] = dsa_header[2] & ~0x10;
|
|
|
|
new_header[3] = dsa_header[3];
|
|
|
|
|
2020-11-14 23:45:58 +00:00
|
|
|
/* Move CFI bit from its place in the DSA header to
|
|
|
|
* its 802.1Q-designated place.
|
2008-10-07 13:45:02 +00:00
|
|
|
*/
|
|
|
|
if (dsa_header[1] & 0x01)
|
|
|
|
new_header[2] |= 0x10;
|
|
|
|
|
2020-11-14 23:45:58 +00:00
|
|
|
/* Update packet checksum if skb is CHECKSUM_COMPLETE. */
|
2008-10-07 13:45:02 +00:00
|
|
|
if (skb->ip_summed == CHECKSUM_COMPLETE) {
|
|
|
|
__wsum c = skb->csum;
|
|
|
|
c = csum_add(c, csum_partial(new_header + 2, 2, 0));
|
|
|
|
c = csum_sub(c, csum_partial(dsa_header + 2, 2, 0));
|
|
|
|
skb->csum = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(dsa_header, new_header, DSA_HLEN);
|
2020-11-14 23:45:57 +00:00
|
|
|
|
|
|
|
if (extra)
|
2021-08-10 13:13:53 +00:00
|
|
|
dsa_strip_etype_header(skb, extra);
|
2008-10-07 13:45:02 +00:00
|
|
|
} else {
|
|
|
|
skb_pull_rcsum(skb, DSA_HLEN);
|
2021-08-10 13:13:53 +00:00
|
|
|
dsa_strip_etype_header(skb, DSA_HLEN + extra);
|
2008-10-07 13:45:02 +00:00
|
|
|
}
|
|
|
|
|
2017-04-08 15:55:23 +00:00
|
|
|
return skb;
|
2008-10-07 13:45:02 +00:00
|
|
|
}
|
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
#if IS_ENABLED(CONFIG_NET_DSA_TAG_DSA)
|
|
|
|
|
|
|
|
static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
|
{
|
|
|
|
return dsa_xmit_ll(skb, dev, 0);
|
|
|
|
}
|
|
|
|
|
2021-07-31 14:14:32 +00:00
|
|
|
static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
|
2020-11-14 23:45:57 +00:00
|
|
|
{
|
|
|
|
if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return dsa_rcv_ll(skb, dev, 0);
|
|
|
|
}
|
|
|
|
|
2019-04-28 17:37:21 +00:00
|
|
|
static const struct dsa_device_ops dsa_netdev_ops = {
|
2020-11-14 23:45:57 +00:00
|
|
|
.name = "dsa",
|
|
|
|
.proto = DSA_TAG_PROTO_DSA,
|
|
|
|
.xmit = dsa_xmit,
|
|
|
|
.rcv = dsa_rcv,
|
2021-06-11 19:01:24 +00:00
|
|
|
.needed_headroom = DSA_HLEN,
|
2008-10-07 13:45:02 +00:00
|
|
|
};
|
2019-04-28 17:37:12 +00:00
|
|
|
|
2020-11-14 23:45:57 +00:00
|
|
|
DSA_TAG_DRIVER(dsa_netdev_ops);
|
2019-04-28 17:37:12 +00:00
|
|
|
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_DSA);
|
2020-11-14 23:45:57 +00:00
|
|
|
#endif /* CONFIG_NET_DSA_TAG_DSA */
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_NET_DSA_TAG_EDSA)
|
|
|
|
|
|
|
|
#define EDSA_HLEN 8
|
|
|
|
|
|
|
|
static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
|
{
|
|
|
|
u8 *edsa_header;
|
|
|
|
|
|
|
|
skb = dsa_xmit_ll(skb, dev, EDSA_HLEN - DSA_HLEN);
|
|
|
|
if (!skb)
|
|
|
|
return NULL;
|
2019-04-28 17:37:15 +00:00
|
|
|
|
2021-08-10 13:13:56 +00:00
|
|
|
edsa_header = dsa_etype_header_pos_tx(skb);
|
2020-11-14 23:45:57 +00:00
|
|
|
edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff;
|
|
|
|
edsa_header[1] = ETH_P_EDSA & 0xff;
|
|
|
|
edsa_header[2] = 0x00;
|
|
|
|
edsa_header[3] = 0x00;
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2021-07-31 14:14:32 +00:00
|
|
|
static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
|
2020-11-14 23:45:57 +00:00
|
|
|
{
|
|
|
|
if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
skb_pull_rcsum(skb, EDSA_HLEN - DSA_HLEN);
|
|
|
|
|
|
|
|
return dsa_rcv_ll(skb, dev, EDSA_HLEN - DSA_HLEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct dsa_device_ops edsa_netdev_ops = {
|
|
|
|
.name = "edsa",
|
|
|
|
.proto = DSA_TAG_PROTO_EDSA,
|
|
|
|
.xmit = edsa_xmit,
|
|
|
|
.rcv = edsa_rcv,
|
2021-06-11 19:01:24 +00:00
|
|
|
.needed_headroom = EDSA_HLEN,
|
2020-11-14 23:45:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DSA_TAG_DRIVER(edsa_netdev_ops);
|
|
|
|
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_EDSA);
|
|
|
|
#endif /* CONFIG_NET_DSA_TAG_EDSA */
|
|
|
|
|
|
|
|
static struct dsa_tag_driver *dsa_tag_drivers[] = {
|
|
|
|
#if IS_ENABLED(CONFIG_NET_DSA_TAG_DSA)
|
|
|
|
&DSA_TAG_DRIVER_NAME(dsa_netdev_ops),
|
|
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_NET_DSA_TAG_EDSA)
|
|
|
|
&DSA_TAG_DRIVER_NAME(edsa_netdev_ops),
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
module_dsa_tag_drivers(dsa_tag_drivers);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|