net: dsa: generalize overhead for taggers that use both headers and trailers
authorVladimir Oltean <vladimir.oltean@nxp.com>
Fri, 11 Jun 2021 19:01:24 +0000 (22:01 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 11 Jun 2021 19:45:38 +0000 (12:45 -0700)
Some really really weird switches just couldn't decide whether to use a
normal or a tail tagger, so they just did both.

This creates problems for DSA, because we only have the concept of an
'overhead' which can be applied to the headroom or to the tailroom of
the skb (like for example during the central TX reallocation procedure),
depending on the value of bool tail_tag, but not to both.

We need to generalize DSA to cater for these odd switches by
transforming the 'overhead / tail_tag' pair into 'needed_headroom /
needed_tailroom'.

The DSA master's MTU is increased to account for both.

The flow dissector code is modified such that it only calls the DSA
adjustment callback if the tagger has a non-zero header length.

Taggers are trivially modified to declare either needed_headroom or
needed_tailroom, based on the tail_tag value that they currently
declare.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
21 files changed:
Documentation/networking/dsa/dsa.rst
include/net/dsa.h
net/core/flow_dissector.c
net/dsa/dsa_priv.h
net/dsa/master.c
net/dsa/slave.c
net/dsa/tag_ar9331.c
net/dsa/tag_brcm.c
net/dsa/tag_dsa.c
net/dsa/tag_gswip.c
net/dsa/tag_hellcreek.c
net/dsa/tag_ksz.c
net/dsa/tag_lan9303.c
net/dsa/tag_mtk.c
net/dsa/tag_ocelot.c
net/dsa/tag_ocelot_8021q.c
net/dsa/tag_qca.c
net/dsa/tag_rtl4_a.c
net/dsa/tag_sja1105.c
net/dsa/tag_trailer.c
net/dsa/tag_xrs700x.c

index 8688009514cc88bbbb3387a1d9c063d813cc168c..20baacf2bc5cba4ddec564f42cfc5608ef86ce6c 100644 (file)
@@ -93,14 +93,15 @@ A tagging protocol may tag all packets with switch tags of the same length, or
 the tag length might vary (for example packets with PTP timestamps might
 require an extended switch tag, or there might be one tag length on TX and a
 different one on RX). Either way, the tagging protocol driver must populate the
-``struct dsa_device_ops::overhead`` with the length in octets of the longest
-switch frame header. The DSA framework will automatically adjust the MTU of the
-master interface to accomodate for this extra size in order for DSA user ports
-to support the standard MTU (L2 payload length) of 1500 octets. The ``overhead``
-is also used to request from the network stack, on a best-effort basis, the
-allocation of packets with a ``needed_headroom`` or ``needed_tailroom``
-sufficient such that the act of pushing the switch tag on transmission of a
-packet does not cause it to reallocate due to lack of memory.
+``struct dsa_device_ops::needed_headroom`` and/or ``struct dsa_device_ops::needed_tailroom``
+with the length in octets of the longest switch frame header/trailer. The DSA
+framework will automatically adjust the MTU of the master interface to
+accommodate for this extra size in order for DSA user ports to support the
+standard MTU (L2 payload length) of 1500 octets. The ``needed_headroom`` and
+``needed_tailroom`` properties are also used to request from the network stack,
+on a best-effort basis, the allocation of packets with enough extra space such
+that the act of pushing the switch tag on transmission of a packet does not
+cause it to reallocate due to lack of memory.
 
 Even though applications are not expected to parse DSA-specific frame headers,
 the format on the wire of the tagging protocol represents an Application Binary
@@ -169,8 +170,8 @@ The job of this method is to prepare the skb in a way that the switch will
 understand what egress port the packet is for (and not deliver it towards other
 ports). Typically this is fulfilled by pushing a frame header. Checking for
 insufficient size in the skb headroom or tailroom is unnecessary provided that
-the ``overhead`` and ``tail_tag`` properties were filled out properly, because
-DSA ensures there is enough space before calling this method.
+the ``needed_headroom`` and ``needed_tailroom`` properties were filled out
+properly, because DSA ensures there is enough space before calling this method.
 
 The reception of a packet goes through the tagger's ``rcv`` function. The
 passed ``struct sk_buff *skb`` has ``skb->data`` pointing at
index e1a2610a0e06e2f19db1cc444b3e7f7736bd1e22..0a10f6fffc3d6956ecfe9b5a03bb5c29759d1959 100644 (file)
@@ -91,7 +91,8 @@ struct dsa_device_ops {
         * as regular on the master net device.
         */
        bool (*filter)(const struct sk_buff *skb, struct net_device *dev);
-       unsigned int overhead;
+       unsigned int needed_headroom;
+       unsigned int needed_tailroom;
        const char *name;
        enum dsa_tag_protocol proto;
        /* Some tagging protocols either mangle or shift the destination MAC
@@ -100,7 +101,6 @@ struct dsa_device_ops {
         * its RX filter.
         */
        bool promisc_on_master;
-       bool tail_tag;
 };
 
 /* This structure defines the control interfaces that are overlayed by the
@@ -926,7 +926,7 @@ static inline void dsa_tag_generic_flow_dissect(const struct sk_buff *skb,
 {
 #if IS_ENABLED(CONFIG_NET_DSA)
        const struct dsa_device_ops *ops = skb->dev->dsa_ptr->tag_ops;
-       int tag_len = ops->overhead;
+       int tag_len = ops->needed_headroom;
 
        *offset = tag_len;
        *proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
index 3ed7c98a98e1db5a332397d0142572d08a598592..c04455981c1e592fd12c281f7e3e276133fba297 100644 (file)
@@ -944,7 +944,7 @@ bool __skb_flow_dissect(const struct net *net,
 
                        ops = skb->dev->dsa_ptr->tag_ops;
                        /* Tail taggers don't break flow dissection */
-                       if (!ops->tail_tag) {
+                       if (!ops->needed_headroom) {
                                if (ops->flow_dissect)
                                        ops->flow_dissect(skb, &proto, &offset);
                                else
index 92282de54230fe71c1b29b576679228cd2257234..b8b17474b72b18173afc34a3769f382251a08c3b 100644 (file)
@@ -154,6 +154,11 @@ const struct dsa_device_ops *dsa_find_tagger_by_name(const char *buf);
 bool dsa_schedule_work(struct work_struct *work);
 const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops);
 
+static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops)
+{
+       return ops->needed_headroom + ops->needed_tailroom;
+}
+
 /* master.c */
 int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp);
 void dsa_master_teardown(struct net_device *dev);
index 63adbc21a735a445ebf0408d188743b51821191d..3fc90e36772deb6d31ed6025ffa7bc7d20209647 100644 (file)
@@ -346,10 +346,12 @@ static struct lock_class_key dsa_master_addr_list_lock_key;
 
 int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
 {
-       int mtu = ETH_DATA_LEN + cpu_dp->tag_ops->overhead;
+       const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops;
        struct dsa_switch *ds = cpu_dp->ds;
        struct device_link *consumer_link;
-       int ret;
+       int mtu, ret;
+
+       mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops);
 
        /* The DSA master must use SET_NETDEV_DEV for this to work. */
        consumer_link = device_link_add(ds->dev, dev->dev.parent,
index d4756b9201089292acfb05a7a0cb9557b7da5ce9..3ca509eb284d941f746a9c0c5ae50bb3b7413ec7 100644 (file)
@@ -1569,7 +1569,7 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
 
        mtu_limit = min_t(int, master->max_mtu, dev->max_mtu);
        old_master_mtu = master->mtu;
-       new_master_mtu = largest_mtu + cpu_dp->tag_ops->overhead;
+       new_master_mtu = largest_mtu + dsa_tag_protocol_overhead(cpu_dp->tag_ops);
        if (new_master_mtu > mtu_limit)
                return -ERANGE;
 
@@ -1605,7 +1605,7 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
 out_port_failed:
        if (new_master_mtu != old_master_mtu)
                dsa_port_mtu_change(cpu_dp, old_master_mtu -
-                                   cpu_dp->tag_ops->overhead,
+                                   dsa_tag_protocol_overhead(cpu_dp->tag_ops),
                                    true);
 out_cpu_failed:
        if (new_master_mtu != old_master_mtu)
@@ -1824,10 +1824,8 @@ void dsa_slave_setup_tagger(struct net_device *slave)
        const struct dsa_port *cpu_dp = dp->cpu_dp;
        struct net_device *master = cpu_dp->master;
 
-       if (cpu_dp->tag_ops->tail_tag)
-               slave->needed_tailroom = cpu_dp->tag_ops->overhead;
-       else
-               slave->needed_headroom = cpu_dp->tag_ops->overhead;
+       slave->needed_headroom = cpu_dp->tag_ops->needed_headroom;
+       slave->needed_tailroom = cpu_dp->tag_ops->needed_tailroom;
        /* Try to save one extra realloc later in the TX path (in the master)
         * by also inheriting the master's needed headroom and tailroom.
         * The 8021q driver also does this.
index 002cf7f952e2d778fdf377dc13120018c7b7fe07..0efae1a372b3a6fceb7a17ce6717f0404ea63bde 100644 (file)
@@ -85,7 +85,7 @@ static const struct dsa_device_ops ar9331_netdev_ops = {
        .proto  = DSA_TAG_PROTO_AR9331,
        .xmit   = ar9331_tag_xmit,
        .rcv    = ar9331_tag_rcv,
-       .overhead = AR9331_HDR_LEN,
+       .needed_headroom = AR9331_HDR_LEN,
 };
 
 MODULE_LICENSE("GPL v2");
index 40e9f3098c8d34cb334dcc3f756c8266ed9e703c..0750af951fc92c88229d97fe534de55ed5de14f2 100644 (file)
@@ -205,7 +205,7 @@ static const struct dsa_device_ops brcm_netdev_ops = {
        .proto  = DSA_TAG_PROTO_BRCM,
        .xmit   = brcm_tag_xmit,
        .rcv    = brcm_tag_rcv,
-       .overhead = BRCM_TAG_LEN,
+       .needed_headroom = BRCM_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(brcm_netdev_ops);
@@ -286,7 +286,7 @@ static const struct dsa_device_ops brcm_legacy_netdev_ops = {
        .proto = DSA_TAG_PROTO_BRCM_LEGACY,
        .xmit = brcm_leg_tag_xmit,
        .rcv = brcm_leg_tag_rcv,
-       .overhead = BRCM_LEG_TAG_LEN,
+       .needed_headroom = BRCM_LEG_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
@@ -314,7 +314,7 @@ static const struct dsa_device_ops brcm_prepend_netdev_ops = {
        .proto  = DSA_TAG_PROTO_BRCM_PREPEND,
        .xmit   = brcm_tag_xmit_prepend,
        .rcv    = brcm_tag_rcv_prepend,
-       .overhead = BRCM_TAG_LEN,
+       .needed_headroom = BRCM_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
index 7e7b7decdf397152fb88209f4b81a25194151f48..a822355afc903902f482e1818a91d6313ba57d0f 100644 (file)
@@ -303,7 +303,7 @@ static const struct dsa_device_ops dsa_netdev_ops = {
        .proto    = DSA_TAG_PROTO_DSA,
        .xmit     = dsa_xmit,
        .rcv      = dsa_rcv,
-       .overhead = DSA_HLEN,
+       .needed_headroom = DSA_HLEN,
 };
 
 DSA_TAG_DRIVER(dsa_netdev_ops);
@@ -346,7 +346,7 @@ static const struct dsa_device_ops edsa_netdev_ops = {
        .proto    = DSA_TAG_PROTO_EDSA,
        .xmit     = edsa_xmit,
        .rcv      = edsa_rcv,
-       .overhead = EDSA_HLEN,
+       .needed_headroom = EDSA_HLEN,
 };
 
 DSA_TAG_DRIVER(edsa_netdev_ops);
index 2f5bd5e338ab5c908984690833e3d7fb100d2318..5985dab06ab89603090dc3df8ee04b55d30e0e36 100644 (file)
@@ -103,7 +103,7 @@ static const struct dsa_device_ops gswip_netdev_ops = {
        .proto  = DSA_TAG_PROTO_GSWIP,
        .xmit = gswip_tag_xmit,
        .rcv = gswip_tag_rcv,
-       .overhead = GSWIP_RX_HEADER_LEN,
+       .needed_headroom = GSWIP_RX_HEADER_LEN,
 };
 
 MODULE_LICENSE("GPL");
index a09805c8e1abc93c5c7ee17de71277d23bfb8116..424130f85f596d3438ce9ae616c49b4448b54115 100644 (file)
@@ -54,8 +54,7 @@ static const struct dsa_device_ops hellcreek_netdev_ops = {
        .proto    = DSA_TAG_PROTO_HELLCREEK,
        .xmit     = hellcreek_xmit,
        .rcv      = hellcreek_rcv,
-       .overhead = HELLCREEK_TAG_LEN,
-       .tail_tag = true,
+       .needed_tailroom = HELLCREEK_TAG_LEN,
 };
 
 MODULE_LICENSE("Dual MIT/GPL");
index 4820dbcedfa2d469b2ee6a702bcba5ccc9d7cf8c..53565f48934c0f4814151e6d3e08aec2df4c6de2 100644 (file)
@@ -77,8 +77,7 @@ static const struct dsa_device_ops ksz8795_netdev_ops = {
        .proto  = DSA_TAG_PROTO_KSZ8795,
        .xmit   = ksz8795_xmit,
        .rcv    = ksz8795_rcv,
-       .overhead = KSZ_INGRESS_TAG_LEN,
-       .tail_tag = true,
+       .needed_tailroom = KSZ_INGRESS_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(ksz8795_netdev_ops);
@@ -149,8 +148,7 @@ static const struct dsa_device_ops ksz9477_netdev_ops = {
        .proto  = DSA_TAG_PROTO_KSZ9477,
        .xmit   = ksz9477_xmit,
        .rcv    = ksz9477_rcv,
-       .overhead = KSZ9477_INGRESS_TAG_LEN,
-       .tail_tag = true,
+       .needed_tailroom = KSZ9477_INGRESS_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(ksz9477_netdev_ops);
@@ -183,8 +181,7 @@ static const struct dsa_device_ops ksz9893_netdev_ops = {
        .proto  = DSA_TAG_PROTO_KSZ9893,
        .xmit   = ksz9893_xmit,
        .rcv    = ksz9477_rcv,
-       .overhead = KSZ_INGRESS_TAG_LEN,
-       .tail_tag = true,
+       .needed_tailroom = KSZ_INGRESS_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(ksz9893_netdev_ops);
index aa1318dccaf0a3b360ed4fb7549b55e77cd0f5ca..26207ef39ebcf0f43f95f3fd29ed1f92f86d03cc 100644 (file)
@@ -125,7 +125,7 @@ static const struct dsa_device_ops lan9303_netdev_ops = {
        .proto  = DSA_TAG_PROTO_LAN9303,
        .xmit = lan9303_xmit,
        .rcv = lan9303_rcv,
-       .overhead = LAN9303_TAG_LEN,
+       .needed_headroom = LAN9303_TAG_LEN,
 };
 
 MODULE_LICENSE("GPL");
index f9b2966d1936e75332b77d736f753a7f424007d3..cc3ba864ad5badf51fa4fd4297605699b2f20284 100644 (file)
@@ -102,7 +102,7 @@ static const struct dsa_device_ops mtk_netdev_ops = {
        .proto          = DSA_TAG_PROTO_MTK,
        .xmit           = mtk_tag_xmit,
        .rcv            = mtk_tag_rcv,
-       .overhead       = MTK_HDR_LEN,
+       .needed_headroom = MTK_HDR_LEN,
 };
 
 MODULE_LICENSE("GPL");
index 91f0fd1242cd64ffb93cad711edc6d1105be8690..190f4bfd3bef646ade3bcd9df88ab2a60f64e584 100644 (file)
@@ -143,7 +143,7 @@ static const struct dsa_device_ops ocelot_netdev_ops = {
        .proto                  = DSA_TAG_PROTO_OCELOT,
        .xmit                   = ocelot_xmit,
        .rcv                    = ocelot_rcv,
-       .overhead               = OCELOT_TOTAL_TAG_LEN,
+       .needed_headroom        = OCELOT_TOTAL_TAG_LEN,
        .promisc_on_master      = true,
 };
 
@@ -155,7 +155,7 @@ static const struct dsa_device_ops seville_netdev_ops = {
        .proto                  = DSA_TAG_PROTO_SEVILLE,
        .xmit                   = seville_xmit,
        .rcv                    = ocelot_rcv,
-       .overhead               = OCELOT_TOTAL_TAG_LEN,
+       .needed_headroom        = OCELOT_TOTAL_TAG_LEN,
        .promisc_on_master      = true,
 };
 
index 62a93303bd633ccb2e1d7a7ab8957a85888f5aa6..663b74793cfc15b5d6a8353d00d080a5d3d7339b 100644 (file)
@@ -73,7 +73,7 @@ static const struct dsa_device_ops ocelot_8021q_netdev_ops = {
        .proto                  = DSA_TAG_PROTO_OCELOT_8021Q,
        .xmit                   = ocelot_xmit,
        .rcv                    = ocelot_rcv,
-       .overhead               = VLAN_HLEN,
+       .needed_headroom        = VLAN_HLEN,
        .promisc_on_master      = true,
 };
 
index 88181b52f480bd9f8a4da7c654ddde58ef752e7e..693bda013065a7edef8d9e7d7e35650c881e404d 100644 (file)
@@ -91,7 +91,7 @@ static const struct dsa_device_ops qca_netdev_ops = {
        .proto  = DSA_TAG_PROTO_QCA,
        .xmit   = qca_tag_xmit,
        .rcv    = qca_tag_rcv,
-       .overhead = QCA_HDR_LEN,
+       .needed_headroom = QCA_HDR_LEN,
 };
 
 MODULE_LICENSE("GPL");
index cf8ac316f4c7743e98a3c21e1a1b98bfaf67d35b..57c46b4ab2b3ff739f029d2b4d15df54baf4697f 100644 (file)
@@ -124,7 +124,7 @@ static const struct dsa_device_ops rtl4a_netdev_ops = {
        .proto  = DSA_TAG_PROTO_RTL4_A,
        .xmit   = rtl4a_tag_xmit,
        .rcv    = rtl4a_tag_rcv,
-       .overhead = RTL4_A_HDR_LEN,
+       .needed_headroom = RTL4_A_HDR_LEN,
 };
 module_dsa_tag_driver(rtl4a_netdev_ops);
 
index 50496013cdb7fa1338916751cdf99da3a097ee26..ff4a81eae16f3d2b35715dcad8d56ec13917b169 100644 (file)
@@ -362,7 +362,7 @@ static const struct dsa_device_ops sja1105_netdev_ops = {
        .xmit = sja1105_xmit,
        .rcv = sja1105_rcv,
        .filter = sja1105_filter,
-       .overhead = VLAN_HLEN,
+       .needed_headroom = VLAN_HLEN,
        .flow_dissect = sja1105_flow_dissect,
        .promisc_on_master = true,
 };
index 5b97ede56a0fd89dc4276954f26414b164ed086b..ba73804340a556a73613ad520220d46419c65808 100644 (file)
@@ -55,8 +55,7 @@ static const struct dsa_device_ops trailer_netdev_ops = {
        .proto  = DSA_TAG_PROTO_TRAILER,
        .xmit   = trailer_xmit,
        .rcv    = trailer_rcv,
-       .overhead = 4,
-       .tail_tag = true,
+       .needed_tailroom = 4,
 };
 
 MODULE_LICENSE("GPL");
index 858cdf9d29133e9831355e4b31dba844f8b88e36..a31ff7fcb45f63bf1ef24cf184ed08a0511e9c90 100644 (file)
@@ -56,8 +56,7 @@ static const struct dsa_device_ops xrs700x_netdev_ops = {
        .proto  = DSA_TAG_PROTO_XRS700X,
        .xmit   = xrs700x_xmit,
        .rcv    = xrs700x_rcv,
-       .overhead = 1,
-       .tail_tag = true,
+       .needed_tailroom = 1,
 };
 
 MODULE_LICENSE("GPL");