Skip to content

Commit d82f8ab

Browse files
wkzdavem330
authored andcommitted
net: dsa: tag_dsa: offload the bridge forwarding process
Allow the DSA tagger to generate FORWARD frames for offloaded skbs sent from a bridge that we offload, allowing the switch to handle any frame replication that may be required. This also means that source address learning takes place on packets sent from the CPU, meaning that return traffic no longer needs to be flooded as unknown unicast. Signed-off-by: Tobias Waldekranz <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ce5df68 commit d82f8ab

File tree

1 file changed

+44
-8
lines changed

1 file changed

+44
-8
lines changed

net/dsa/tag_dsa.c

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,53 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
126126
u8 extra)
127127
{
128128
struct dsa_port *dp = dsa_slave_to_port(dev);
129+
u8 tag_dev, tag_port;
130+
enum dsa_cmd cmd;
129131
u8 *dsa_header;
132+
u16 pvid = 0;
133+
int err;
134+
135+
if (skb->offload_fwd_mark) {
136+
struct dsa_switch_tree *dst = dp->ds->dst;
137+
struct net_device *br = dp->bridge_dev;
138+
139+
cmd = DSA_CMD_FORWARD;
140+
141+
/* When offloading forwarding for a bridge, inject FORWARD
142+
* packets on behalf of a virtual switch device with an index
143+
* past the physical switches.
144+
*/
145+
tag_dev = dst->last_switch + 1 + dp->bridge_num;
146+
tag_port = 0;
147+
148+
/* If we are offloading forwarding for a VLAN-unaware bridge,
149+
* inject packets to hardware using the bridge's pvid, since
150+
* that's where the packets ingressed from.
151+
*/
152+
if (!br_vlan_enabled(br)) {
153+
/* Safe because __dev_queue_xmit() runs under
154+
* rcu_read_lock_bh()
155+
*/
156+
err = br_vlan_get_pvid_rcu(br, &pvid);
157+
if (err)
158+
return NULL;
159+
}
160+
} else {
161+
cmd = DSA_CMD_FROM_CPU;
162+
tag_dev = dp->ds->index;
163+
tag_port = dp->index;
164+
}
130165

131166
if (skb->protocol == htons(ETH_P_8021Q)) {
132167
if (extra) {
133168
skb_push(skb, extra);
134169
memmove(skb->data, skb->data + extra, 2 * ETH_ALEN);
135170
}
136171

137-
/* Construct tagged FROM_CPU DSA tag from 802.1Q tag. */
172+
/* Construct tagged DSA tag from 802.1Q tag. */
138173
dsa_header = skb->data + 2 * ETH_ALEN + extra;
139-
dsa_header[0] = (DSA_CMD_FROM_CPU << 6) | 0x20 | dp->ds->index;
140-
dsa_header[1] = dp->index << 3;
174+
dsa_header[0] = (cmd << 6) | 0x20 | tag_dev;
175+
dsa_header[1] = tag_port << 3;
141176

142177
/* Move CFI field from byte 2 to byte 1. */
143178
if (dsa_header[2] & 0x10) {
@@ -148,12 +183,13 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
148183
skb_push(skb, DSA_HLEN + extra);
149184
memmove(skb->data, skb->data + DSA_HLEN + extra, 2 * ETH_ALEN);
150185

151-
/* Construct untagged FROM_CPU DSA tag. */
186+
/* Construct untagged DSA tag. */
152187
dsa_header = skb->data + 2 * ETH_ALEN + extra;
153-
dsa_header[0] = (DSA_CMD_FROM_CPU << 6) | dp->ds->index;
154-
dsa_header[1] = dp->index << 3;
155-
dsa_header[2] = 0x00;
156-
dsa_header[3] = 0x00;
188+
189+
dsa_header[0] = (cmd << 6) | tag_dev;
190+
dsa_header[1] = tag_port << 3;
191+
dsa_header[2] = pvid >> 8;
192+
dsa_header[3] = pvid & 0xff;
157193
}
158194

159195
return skb;

0 commit comments

Comments
 (0)