DSA copies the driver features to slave device, including offload
capabilities. Once a packet is sent through a DSA slave interface,
according to its features, the kernel does not calculate checksums,
expecting that the HW will fill the gaps. DSA adds the defined DSA
tag and sends the tagged packet through the master device.
Ethertype DSA tags expect the driver to calculate checksum based on the
csum_start/csum_offset. However, mtk_soc_eth does not use that info.
It checks the network header and decides if the HW can manage that
packet, unaware that mac layer now contains an extra DSA tag. When
that tag is the Mediatek CPU tag, offload will work as expected.
When it is an incompatible DSA tag or if DSA is stacking two incompatible
DSA tags, the driver will still count on the HW offload. In this case,
packets go to the network with an incorrect checksum.
Before this change, tag_ops->proto == DSA_TAG_PROTO_MTK was used,
which disabled offload for every non-Mediatek tag, including the
RTL8367S switch's RTL8_4 tag that this fix specifically targets.
Replace the hardcoded whitelist with a blacklist scoped to the
RTL8367S: only disable offload for DSA_TAG_PROTO_RTL8_4. The RTL8_4T
(the trailing-tag variant) is left untouched because its rtl8_4t tagger
already checksums the frame in software before appending the tag.
Tags for other DSA-capable switches are left untouched by this fix
and are not claimed to be offload-safe.
Fixes: 3c0a73b4d202 ("ramips: ethernet: ralink: fix offload with diff dsa tag")
Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
Link: https://github.com/openwrt/openwrt/pull/24064
Signed-off-by: Robert Marko <robimarko@gmail.com>
}
#if IS_ENABLED(CONFIG_NET_DSA)
-#define MTK_HDR_LEN 4
-
static netdev_features_t fe_features_check(struct sk_buff *skb,
struct net_device *dev,
netdev_features_t features)
if (skb->ip_summed != CHECKSUM_PARTIAL)
return features;
- /* DSA tag might break existing offload checks as offload feature flags
- * are copied to slave ports and this driver does not use csum_start. */
if (netdev_uses_dsa(dev)) {
const struct dsa_device_ops *tag_ops = dev->dsa_ptr->tag_ops;
- /* If tag is Mediatek, checksum should work */
- if (tag_ops->proto == DSA_TAG_PROTO_MTK)
- /* However, make sure that it is not stacking another
- * L2 protocol, possibly a second incompatible DSA tag
- * 802.1Q does not increase the mac header size because
- * it is embedded inside mediatek tag */
- if (skb_mac_header_len(skb) <= ETH_HLEN + MTK_HDR_LEN)
- return features;
-
- features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+ /* RTL8_4 hides the L2 ethertype this driver relies on for
+ * offload. RTL8_4T (the trailing-tag variant) is unaffected
+ * because its rtl8_4t tagger already checksums the frame in
+ * software before appending the tag, so ip_summed is no longer
+ * CHECKSUM_PARTIAL by the time this driver sees it.
+ */
+ if (tag_ops->proto == DSA_TAG_PROTO_RTL8_4)
+ features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
return features;