Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: generalize overhead for taggers that use both headers and trailers

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>

authored by

Vladimir Oltean and committed by
David S. Miller
4e500251 6c0de59b

+49 -49
+11 -10
Documentation/networking/dsa/dsa.rst
··· 93 93 the tag length might vary (for example packets with PTP timestamps might 94 94 require an extended switch tag, or there might be one tag length on TX and a 95 95 different one on RX). Either way, the tagging protocol driver must populate the 96 - ``struct dsa_device_ops::overhead`` with the length in octets of the longest 97 - switch frame header. The DSA framework will automatically adjust the MTU of the 98 - master interface to accomodate for this extra size in order for DSA user ports 99 - to support the standard MTU (L2 payload length) of 1500 octets. The ``overhead`` 100 - is also used to request from the network stack, on a best-effort basis, the 101 - allocation of packets with a ``needed_headroom`` or ``needed_tailroom`` 102 - sufficient such that the act of pushing the switch tag on transmission of a 103 - packet does not cause it to reallocate due to lack of memory. 96 + ``struct dsa_device_ops::needed_headroom`` and/or ``struct dsa_device_ops::needed_tailroom`` 97 + with the length in octets of the longest switch frame header/trailer. The DSA 98 + framework will automatically adjust the MTU of the master interface to 99 + accommodate for this extra size in order for DSA user ports to support the 100 + standard MTU (L2 payload length) of 1500 octets. The ``needed_headroom`` and 101 + ``needed_tailroom`` properties are also used to request from the network stack, 102 + on a best-effort basis, the allocation of packets with enough extra space such 103 + that the act of pushing the switch tag on transmission of a packet does not 104 + cause it to reallocate due to lack of memory. 104 105 105 106 Even though applications are not expected to parse DSA-specific frame headers, 106 107 the format on the wire of the tagging protocol represents an Application Binary ··· 170 169 understand what egress port the packet is for (and not deliver it towards other 171 170 ports). Typically this is fulfilled by pushing a frame header. Checking for 172 171 insufficient size in the skb headroom or tailroom is unnecessary provided that 173 - the ``overhead`` and ``tail_tag`` properties were filled out properly, because 174 - DSA ensures there is enough space before calling this method. 172 + the ``needed_headroom`` and ``needed_tailroom`` properties were filled out 173 + properly, because DSA ensures there is enough space before calling this method. 175 174 176 175 The reception of a packet goes through the tagger's ``rcv`` function. The 177 176 passed ``struct sk_buff *skb`` has ``skb->data`` pointing at
+3 -3
include/net/dsa.h
··· 91 91 * as regular on the master net device. 92 92 */ 93 93 bool (*filter)(const struct sk_buff *skb, struct net_device *dev); 94 - unsigned int overhead; 94 + unsigned int needed_headroom; 95 + unsigned int needed_tailroom; 95 96 const char *name; 96 97 enum dsa_tag_protocol proto; 97 98 /* Some tagging protocols either mangle or shift the destination MAC ··· 101 100 * its RX filter. 102 101 */ 103 102 bool promisc_on_master; 104 - bool tail_tag; 105 103 }; 106 104 107 105 /* This structure defines the control interfaces that are overlayed by the ··· 926 926 { 927 927 #if IS_ENABLED(CONFIG_NET_DSA) 928 928 const struct dsa_device_ops *ops = skb->dev->dsa_ptr->tag_ops; 929 - int tag_len = ops->overhead; 929 + int tag_len = ops->needed_headroom; 930 930 931 931 *offset = tag_len; 932 932 *proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
+1 -1
net/core/flow_dissector.c
··· 944 944 945 945 ops = skb->dev->dsa_ptr->tag_ops; 946 946 /* Tail taggers don't break flow dissection */ 947 - if (!ops->tail_tag) { 947 + if (!ops->needed_headroom) { 948 948 if (ops->flow_dissect) 949 949 ops->flow_dissect(skb, &proto, &offset); 950 950 else
+5
net/dsa/dsa_priv.h
··· 154 154 bool dsa_schedule_work(struct work_struct *work); 155 155 const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops); 156 156 157 + static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops) 158 + { 159 + return ops->needed_headroom + ops->needed_tailroom; 160 + } 161 + 157 162 /* master.c */ 158 163 int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp); 159 164 void dsa_master_teardown(struct net_device *dev);
+4 -2
net/dsa/master.c
··· 346 346 347 347 int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) 348 348 { 349 - int mtu = ETH_DATA_LEN + cpu_dp->tag_ops->overhead; 349 + const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops; 350 350 struct dsa_switch *ds = cpu_dp->ds; 351 351 struct device_link *consumer_link; 352 - int ret; 352 + int mtu, ret; 353 + 354 + mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops); 353 355 354 356 /* The DSA master must use SET_NETDEV_DEV for this to work. */ 355 357 consumer_link = device_link_add(ds->dev, dev->dev.parent,
+4 -6
net/dsa/slave.c
··· 1569 1569 1570 1570 mtu_limit = min_t(int, master->max_mtu, dev->max_mtu); 1571 1571 old_master_mtu = master->mtu; 1572 - new_master_mtu = largest_mtu + cpu_dp->tag_ops->overhead; 1572 + new_master_mtu = largest_mtu + dsa_tag_protocol_overhead(cpu_dp->tag_ops); 1573 1573 if (new_master_mtu > mtu_limit) 1574 1574 return -ERANGE; 1575 1575 ··· 1605 1605 out_port_failed: 1606 1606 if (new_master_mtu != old_master_mtu) 1607 1607 dsa_port_mtu_change(cpu_dp, old_master_mtu - 1608 - cpu_dp->tag_ops->overhead, 1608 + dsa_tag_protocol_overhead(cpu_dp->tag_ops), 1609 1609 true); 1610 1610 out_cpu_failed: 1611 1611 if (new_master_mtu != old_master_mtu) ··· 1824 1824 const struct dsa_port *cpu_dp = dp->cpu_dp; 1825 1825 struct net_device *master = cpu_dp->master; 1826 1826 1827 - if (cpu_dp->tag_ops->tail_tag) 1828 - slave->needed_tailroom = cpu_dp->tag_ops->overhead; 1829 - else 1830 - slave->needed_headroom = cpu_dp->tag_ops->overhead; 1827 + slave->needed_headroom = cpu_dp->tag_ops->needed_headroom; 1828 + slave->needed_tailroom = cpu_dp->tag_ops->needed_tailroom; 1831 1829 /* Try to save one extra realloc later in the TX path (in the master) 1832 1830 * by also inheriting the master's needed headroom and tailroom. 1833 1831 * The 8021q driver also does this.
+1 -1
net/dsa/tag_ar9331.c
··· 85 85 .proto = DSA_TAG_PROTO_AR9331, 86 86 .xmit = ar9331_tag_xmit, 87 87 .rcv = ar9331_tag_rcv, 88 - .overhead = AR9331_HDR_LEN, 88 + .needed_headroom = AR9331_HDR_LEN, 89 89 }; 90 90 91 91 MODULE_LICENSE("GPL v2");
+3 -3
net/dsa/tag_brcm.c
··· 205 205 .proto = DSA_TAG_PROTO_BRCM, 206 206 .xmit = brcm_tag_xmit, 207 207 .rcv = brcm_tag_rcv, 208 - .overhead = BRCM_TAG_LEN, 208 + .needed_headroom = BRCM_TAG_LEN, 209 209 }; 210 210 211 211 DSA_TAG_DRIVER(brcm_netdev_ops); ··· 286 286 .proto = DSA_TAG_PROTO_BRCM_LEGACY, 287 287 .xmit = brcm_leg_tag_xmit, 288 288 .rcv = brcm_leg_tag_rcv, 289 - .overhead = BRCM_LEG_TAG_LEN, 289 + .needed_headroom = BRCM_LEG_TAG_LEN, 290 290 }; 291 291 292 292 DSA_TAG_DRIVER(brcm_legacy_netdev_ops); ··· 314 314 .proto = DSA_TAG_PROTO_BRCM_PREPEND, 315 315 .xmit = brcm_tag_xmit_prepend, 316 316 .rcv = brcm_tag_rcv_prepend, 317 - .overhead = BRCM_TAG_LEN, 317 + .needed_headroom = BRCM_TAG_LEN, 318 318 }; 319 319 320 320 DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
+2 -2
net/dsa/tag_dsa.c
··· 303 303 .proto = DSA_TAG_PROTO_DSA, 304 304 .xmit = dsa_xmit, 305 305 .rcv = dsa_rcv, 306 - .overhead = DSA_HLEN, 306 + .needed_headroom = DSA_HLEN, 307 307 }; 308 308 309 309 DSA_TAG_DRIVER(dsa_netdev_ops); ··· 346 346 .proto = DSA_TAG_PROTO_EDSA, 347 347 .xmit = edsa_xmit, 348 348 .rcv = edsa_rcv, 349 - .overhead = EDSA_HLEN, 349 + .needed_headroom = EDSA_HLEN, 350 350 }; 351 351 352 352 DSA_TAG_DRIVER(edsa_netdev_ops);
+1 -1
net/dsa/tag_gswip.c
··· 103 103 .proto = DSA_TAG_PROTO_GSWIP, 104 104 .xmit = gswip_tag_xmit, 105 105 .rcv = gswip_tag_rcv, 106 - .overhead = GSWIP_RX_HEADER_LEN, 106 + .needed_headroom = GSWIP_RX_HEADER_LEN, 107 107 }; 108 108 109 109 MODULE_LICENSE("GPL");
+1 -2
net/dsa/tag_hellcreek.c
··· 54 54 .proto = DSA_TAG_PROTO_HELLCREEK, 55 55 .xmit = hellcreek_xmit, 56 56 .rcv = hellcreek_rcv, 57 - .overhead = HELLCREEK_TAG_LEN, 58 - .tail_tag = true, 57 + .needed_tailroom = HELLCREEK_TAG_LEN, 59 58 }; 60 59 61 60 MODULE_LICENSE("Dual MIT/GPL");
+3 -6
net/dsa/tag_ksz.c
··· 77 77 .proto = DSA_TAG_PROTO_KSZ8795, 78 78 .xmit = ksz8795_xmit, 79 79 .rcv = ksz8795_rcv, 80 - .overhead = KSZ_INGRESS_TAG_LEN, 81 - .tail_tag = true, 80 + .needed_tailroom = KSZ_INGRESS_TAG_LEN, 82 81 }; 83 82 84 83 DSA_TAG_DRIVER(ksz8795_netdev_ops); ··· 148 149 .proto = DSA_TAG_PROTO_KSZ9477, 149 150 .xmit = ksz9477_xmit, 150 151 .rcv = ksz9477_rcv, 151 - .overhead = KSZ9477_INGRESS_TAG_LEN, 152 - .tail_tag = true, 152 + .needed_tailroom = KSZ9477_INGRESS_TAG_LEN, 153 153 }; 154 154 155 155 DSA_TAG_DRIVER(ksz9477_netdev_ops); ··· 181 183 .proto = DSA_TAG_PROTO_KSZ9893, 182 184 .xmit = ksz9893_xmit, 183 185 .rcv = ksz9477_rcv, 184 - .overhead = KSZ_INGRESS_TAG_LEN, 185 - .tail_tag = true, 186 + .needed_tailroom = KSZ_INGRESS_TAG_LEN, 186 187 }; 187 188 188 189 DSA_TAG_DRIVER(ksz9893_netdev_ops);
+1 -1
net/dsa/tag_lan9303.c
··· 125 125 .proto = DSA_TAG_PROTO_LAN9303, 126 126 .xmit = lan9303_xmit, 127 127 .rcv = lan9303_rcv, 128 - .overhead = LAN9303_TAG_LEN, 128 + .needed_headroom = LAN9303_TAG_LEN, 129 129 }; 130 130 131 131 MODULE_LICENSE("GPL");
+1 -1
net/dsa/tag_mtk.c
··· 102 102 .proto = DSA_TAG_PROTO_MTK, 103 103 .xmit = mtk_tag_xmit, 104 104 .rcv = mtk_tag_rcv, 105 - .overhead = MTK_HDR_LEN, 105 + .needed_headroom = MTK_HDR_LEN, 106 106 }; 107 107 108 108 MODULE_LICENSE("GPL");
+2 -2
net/dsa/tag_ocelot.c
··· 143 143 .proto = DSA_TAG_PROTO_OCELOT, 144 144 .xmit = ocelot_xmit, 145 145 .rcv = ocelot_rcv, 146 - .overhead = OCELOT_TOTAL_TAG_LEN, 146 + .needed_headroom = OCELOT_TOTAL_TAG_LEN, 147 147 .promisc_on_master = true, 148 148 }; 149 149 ··· 155 155 .proto = DSA_TAG_PROTO_SEVILLE, 156 156 .xmit = seville_xmit, 157 157 .rcv = ocelot_rcv, 158 - .overhead = OCELOT_TOTAL_TAG_LEN, 158 + .needed_headroom = OCELOT_TOTAL_TAG_LEN, 159 159 .promisc_on_master = true, 160 160 }; 161 161
+1 -1
net/dsa/tag_ocelot_8021q.c
··· 73 73 .proto = DSA_TAG_PROTO_OCELOT_8021Q, 74 74 .xmit = ocelot_xmit, 75 75 .rcv = ocelot_rcv, 76 - .overhead = VLAN_HLEN, 76 + .needed_headroom = VLAN_HLEN, 77 77 .promisc_on_master = true, 78 78 }; 79 79
+1 -1
net/dsa/tag_qca.c
··· 91 91 .proto = DSA_TAG_PROTO_QCA, 92 92 .xmit = qca_tag_xmit, 93 93 .rcv = qca_tag_rcv, 94 - .overhead = QCA_HDR_LEN, 94 + .needed_headroom = QCA_HDR_LEN, 95 95 }; 96 96 97 97 MODULE_LICENSE("GPL");
+1 -1
net/dsa/tag_rtl4_a.c
··· 124 124 .proto = DSA_TAG_PROTO_RTL4_A, 125 125 .xmit = rtl4a_tag_xmit, 126 126 .rcv = rtl4a_tag_rcv, 127 - .overhead = RTL4_A_HDR_LEN, 127 + .needed_headroom = RTL4_A_HDR_LEN, 128 128 }; 129 129 module_dsa_tag_driver(rtl4a_netdev_ops); 130 130
+1 -1
net/dsa/tag_sja1105.c
··· 362 362 .xmit = sja1105_xmit, 363 363 .rcv = sja1105_rcv, 364 364 .filter = sja1105_filter, 365 - .overhead = VLAN_HLEN, 365 + .needed_headroom = VLAN_HLEN, 366 366 .flow_dissect = sja1105_flow_dissect, 367 367 .promisc_on_master = true, 368 368 };
+1 -2
net/dsa/tag_trailer.c
··· 55 55 .proto = DSA_TAG_PROTO_TRAILER, 56 56 .xmit = trailer_xmit, 57 57 .rcv = trailer_rcv, 58 - .overhead = 4, 59 - .tail_tag = true, 58 + .needed_tailroom = 4, 60 59 }; 61 60 62 61 MODULE_LICENSE("GPL");
+1 -2
net/dsa/tag_xrs700x.c
··· 56 56 .proto = DSA_TAG_PROTO_XRS700X, 57 57 .xmit = xrs700x_xmit, 58 58 .rcv = xrs700x_rcv, 59 - .overhead = 1, 60 - .tail_tag = true, 59 + .needed_tailroom = 1, 61 60 }; 62 61 63 62 MODULE_LICENSE("GPL");