]> git.baikalelectronics.ru Git - kernel.git/commitdiff
flow_dissector: Add support for HSR
authorKurt Kanzenbach <kurt@linutronix.de>
Mon, 28 Feb 2022 19:58:56 +0000 (20:58 +0100)
committerJakub Kicinski <kuba@kernel.org>
Thu, 3 Mar 2022 06:44:49 +0000 (22:44 -0800)
Network drivers such as igb or igc call eth_get_headlen() to determine the
header length for their to be constructed skbs in receive path.

When running HSR on top of these drivers, it results in triggering BUG_ON() in
skb_pull(). The reason is the skb headlen is not sufficient for HSR to work
correctly. skb_pull() notices that.

For instance, eth_get_headlen() returns 14 bytes for TCP traffic over HSR which
is not correct. The problem is, the flow dissection code does not take HSR into
account. Therefore, add support for it.

Reported-by: Anthony Harivel <anthony.harivel@linutronix.de>
Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
Link: https://lore.kernel.org/r/20220228195856.88187-1-kurt@linutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/if_hsr.h
net/core/flow_dissector.c
net/hsr/hsr_main.h

index 38bbc537d4e4e8b634f987257a9b1b0d34163844..408539d5ea5f339d4889bdb476f3e343ea5b86ec 100644 (file)
@@ -9,6 +9,22 @@ enum hsr_version {
        PRP_V1,
 };
 
+/* HSR Tag.
+ * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
+ * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest,
+ * h_source, h_proto = 0x88FB }, and add { path, LSDU_size, sequence Nr,
+ * encapsulated protocol } instead.
+ *
+ * Field names as defined in the IEC:2010 standard for HSR.
+ */
+struct hsr_tag {
+       __be16          path_and_LSDU_size;
+       __be16          sequence_nr;
+       __be16          encap_proto;
+} __packed;
+
+#define HSR_HLEN       6
+
 #if IS_ENABLED(CONFIG_HSR)
 extern bool is_hsr_master(struct net_device *dev);
 extern int hsr_get_version(struct net_device *dev, enum hsr_version *ver);
index 15833e1d6ea11aaca87efc4ce5c43533af604b9d..34441a32e3be5da3562ee53e18ce4f476267527c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/stddef.h>
 #include <linux/if_ether.h>
+#include <linux/if_hsr.h>
 #include <linux/mpls.h>
 #include <linux/tcp.h>
 #include <linux/ptp_classify.h>
@@ -1282,6 +1283,22 @@ proto_again:
                break;
        }
 
+       case htons(ETH_P_HSR): {
+               struct hsr_tag *hdr, _hdr;
+
+               hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen,
+                                          &_hdr);
+               if (!hdr) {
+                       fdret = FLOW_DISSECT_RET_OUT_BAD;
+                       break;
+               }
+
+               proto = hdr->encap_proto;
+               nhoff += HSR_HLEN;
+               fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+               break;
+       }
+
        default:
                fdret = FLOW_DISSECT_RET_OUT_BAD;
                break;
index ca556bda3467bd28f010d33c8f0312edcab2af1f..b158ba409f9a4e26136d6ca0b74d3a786fb15614 100644 (file)
 /* PRP V1 life redundancy box MAC address */
 #define PRP_TLV_REDBOX_MAC                30
 
-/* HSR Tag.
- * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
- * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest,
- * h_source, h_proto = 0x88FB }, and add { path, LSDU_size, sequence Nr,
- * encapsulated protocol } instead.
- *
- * Field names as defined in the IEC:2010 standard for HSR.
- */
-struct hsr_tag {
-       __be16          path_and_LSDU_size;
-       __be16          sequence_nr;
-       __be16          encap_proto;
-} __packed;
-
-#define HSR_HLEN       6
-
 #define HSR_V1_SUP_LSDUSIZE            52
 
 #define HSR_HSIZE_SHIFT        8