@@ -195,6 +195,28 @@ dsa_slave_to_master(const struct net_device *dev)
return dp->cpu_dp->master;
}
+/* 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,
+ int tag_len)
+{
+ *offset = tag_len;
+ *proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
+}
+
/* switch.c */
int dsa_switch_register_notifier(struct dsa_switch *ds);
void dsa_switch_unregister_notifier(struct dsa_switch *ds);
@@ -83,12 +83,21 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
return skb;
}
+static int ar9331_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+ int *offset)
+{
+ dsa_tag_generic_flow_dissect(skb, proto, offset, AR9331_HDR_LEN);
+
+ return 0;
+}
+
static const struct dsa_device_ops ar9331_netdev_ops = {
.name = "ar9331",
.proto = DSA_TAG_PROTO_AR9331,
.xmit = ar9331_tag_xmit,
.rcv = ar9331_tag_rcv,
.overhead = AR9331_HDR_LEN,
+ .flow_dissect = ar9331_flow_dissect,
};
MODULE_LICENSE("GPL v2");
@@ -160,9 +160,10 @@ static int brcm_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
* 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 we can use the generic helper in both cases.
*/
- *offset = BRCM_TAG_LEN;
- *proto = ((__be16 *)skb->data)[1];
+ dsa_tag_generic_flow_dissect(skb, proto, offset, BRCM_TAG_LEN);
+
return 0;
}
#endif
@@ -145,8 +145,8 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
static int dsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
int *offset)
{
- *offset = 4;
- *proto = ((__be16 *)skb->data)[1];
+ dsa_tag_generic_flow_dissect(skb, proto, offset, DSA_HLEN);
+
return 0;
}
@@ -164,8 +164,8 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
static int edsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
int *offset)
{
- *offset = 8;
- *proto = ((__be16 *)skb->data)[3];
+ dsa_tag_generic_flow_dissect(skb, proto, offset, EDSA_HLEN);
+
return 0;
}
@@ -128,12 +128,21 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
return skb;
}
+static int lan9303_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+ int *offset)
+{
+ dsa_tag_generic_flow_dissect(skb, proto, offset, LAN9303_TAG_LEN);
+
+ return 0;
+}
+
static const struct dsa_device_ops lan9303_netdev_ops = {
.name = "lan9303",
.proto = DSA_TAG_PROTO_LAN9303,
.xmit = lan9303_xmit,
.rcv = lan9303_rcv,
.overhead = LAN9303_TAG_LEN,
+ .flow_dissect = lan9303_flow_dissect,
};
MODULE_LICENSE("GPL");
@@ -92,8 +92,7 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
static int mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
int *offset)
{
- *offset = 4;
- *proto = ((__be16 *)skb->data)[1];
+ dsa_tag_generic_flow_dissect(skb, proto, offset, MTK_HDR_LEN);
return 0;
}
@@ -238,12 +238,21 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
return skb;
}
+static int ocelot_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+ int *offset)
+{
+ dsa_tag_generic_flow_dissect(skb, proto, offset, OCELOT_TOTAL_TAG_LEN);
+
+ return 0;
+}
+
static struct dsa_device_ops ocelot_netdev_ops = {
.name = "ocelot",
.proto = DSA_TAG_PROTO_OCELOT,
.xmit = ocelot_xmit,
.rcv = ocelot_rcv,
.overhead = OCELOT_TOTAL_TAG_LEN,
+ .flow_dissect = ocelot_flow_dissect,
};
MODULE_LICENSE("GPL v2");
@@ -90,8 +90,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev,
static int qca_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
int *offset)
{
- *offset = QCA_HDR_LEN;
- *proto = ((__be16 *)skb->data)[0];
+ dsa_tag_generic_flow_dissect(skb, proto, offset, QCA_HDR_LEN);
return 0;
}
@@ -304,6 +304,18 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
is_meta);
}
+static int 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 0;
+
+ dsa_tag_generic_flow_dissect(skb, proto, offset, VLAN_HLEN);
+
+ return 0;
+}
+
static struct dsa_device_ops sja1105_netdev_ops = {
.name = "sja1105",
.proto = DSA_TAG_PROTO_SJA1105,
@@ -311,6 +323,7 @@ static struct dsa_device_ops sja1105_netdev_ops = {
.rcv = sja1105_rcv,
.filter = sja1105_filter,
.overhead = VLAN_HLEN,
+ .flow_dissect = sja1105_flow_dissect,
};
MODULE_LICENSE("GPL v2");