The PRP trailer detection used a minimum frame size of 70 octets. This minimum applies to whole ethernet packet frames, consisting of headers, payload and frame check sequence (FCS).
Under Linux, VLAN header and FCS are usually removed from messages received from a packet socket, hence the real minimum is at least four octets smaller (66 octets), but can also vary depending on additional headers. Therefore, the original implementation worked fine only for frames larger than 70 octets, but failed for smaller and padded frames. This mostly affected Sync and Follow_Up messages. As a consequence, ptp4l reported bad messages and failed synchronization with the port state stuck to UNCALIBRATED forever. With additional VLAN header in the PTP frames this was even worse. When the VLAN header was not properly detected, the header length used for minimum packet length and padding was just not reliable. And when using a logical VLAN device, there is no easy way to detect VLAN header at all. Therefore, the whole minimum length check and padding detection is removed. Instead, the PRP trailer is always taken from the last six octets of the message, as long as it fits between the end of the PTP data and the FCS (end of message). Signed-off-by: Stephan Wurm <stephan.w...@a-eberle.de> --- The PRP standard is defined by IEC62493-3 and allows for redundant connections, with automatic removal of duplicate frames and trailer data from the logical PRP interface. In contrast, PTP has to handle the redundant lower layer interfaces individually, hence it has to detect the PRP trailer and remove it from the message on its own. This PRP trailer handling was introduced with commit 02c7ab8436ced2e92524bb7b196189c8d381f883. During tests with different PRP setups, we now found some issues with the PRP trailer detection. In one setup with our system connected via PRP to a redundancy device (Siemens RedBox), the communication included all relevant messages, but ptp4l reported port 1 (eth2): bad message port 1 (eth2): bad message port 1 (eth2): delay timeout As a consequence, the port state was alternating between UNCALIBRATED and FAULTY forever. We found the PRP trailer not being removed from Sync and Follow_Up messages, that had a length of exactly 66 octets, including 14 octets ethernet header, 44 octets PTP message, 2 octets of padding and 6 octets trailer. Looking at the original implementation, we found the PRP_MIN_PACKET_LEN to be configured to 70 octets, which would be correct for a whole ethernet frame. But under Linux, a packet socket returns only ethernet header and payload data, but not the frame check sequence (FCS) that is part of the frame size calculation. In another setup, we were using a MOXA RedBox with Power Profile (IEEE C37.238-2011) that includes a mandatory VLAN header. When using ptp4l on top of the physical ethernet interfaces (eth2, eth3), the ports were also stuck to UNCALIBRATED, even after shortening the PTP_MIN_PACKET_LEN to 66 octets. We found that Linux also removes VLAN headers (802.1Q and 802.1ad) from frames received from packet sockets, unless explicitly requesting all additional headers. But this would only work when operating on the physical interfaces. When using the logical VLAN interfaces (here eth2.1 and eth3.1), the VLAN headers are stripped again and the padding calculation in the original PRP trailer detection would fail again for Sync and Follow_Up messages. As a consequence, we removed both the PRP_MIN_PACKET_LEN and padding calculation and are using always the last six octets of a message to detect a PRP trailer, as long as it would fit between the end of a PTP message and the end of a frame (before the FCS). Fixes: 02c7ab8436ced2e92524bb7b196189c8d381f883 Reviewed-by: Johannes Eigner <johannes.eig...@a-eberle.de> --- raw.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/raw.c b/raw.c index a76fab6..1b978f0 100644 --- a/raw.c +++ b/raw.c @@ -57,7 +57,6 @@ struct raw { #define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */ -#define PRP_MIN_PACKET_LEN 70 #define PRP_TRAILER_LEN 6 /* @@ -256,10 +255,10 @@ static void addr_to_mac(void *mac, struct address *addr) } /* Determines if the packet has Parallel Redundancy Protocol (PRP) trailer. */ -static bool has_prp_trailer(unsigned char *ptr, int cnt, int eth_hlen) +static bool has_prp_trailer(unsigned char *ptr, int cnt) { unsigned short suffix_id, lane_size_field, lsdu_size; - int ptp_msg_len, trailer_start, padding_len; + int ptp_msg_len, trailer_start; struct ptp_header *hdr; /* try to parse like a PTP message to find out the message length */ @@ -272,18 +271,12 @@ static bool has_prp_trailer(unsigned char *ptr, int cnt, int eth_hlen) ptp_msg_len = ntohs(hdr->messageLength); - /* PRP requires ethernet packets to be minimum 70 bytes, including trailer */ - trailer_start = ptp_msg_len; - padding_len = 0; - if ((eth_hlen + ptp_msg_len + PRP_TRAILER_LEN) < PRP_MIN_PACKET_LEN) - { - padding_len = PRP_MIN_PACKET_LEN - (eth_hlen + ptp_msg_len + PRP_TRAILER_LEN); - trailer_start += padding_len; - } - - if (cnt < (trailer_start + PRP_TRAILER_LEN)) + if (cnt < (ptp_msg_len + PRP_TRAILER_LEN)) return false; + /* PRP trailer is always in the last six bytes before the FCS */ + trailer_start = cnt - PRP_TRAILER_LEN; + /* PRP trailer (RCT) consists of 3 uint16. | -------------------------------------------------------- | | SeqNr(0-15) | LanId(0-3) LSDUsize(4-15) | Suffix (0-15) | @@ -394,7 +387,7 @@ static int raw_recv(struct transport *t, int fd, void *buf, int buflen, if (cnt < 0) return cnt; - if (has_prp_trailer(buf, cnt, hlen)) + if (has_prp_trailer(buf, cnt)) cnt -= PRP_TRAILER_LEN; if (raw->vlan) { --- base-commit: aa60db270be12e7144e7b0cef2f5dde4213b7057 change-id: 20230623-fix-prp-trailer-detection-f8d0b88a7128 Best regards, -- Stephan Wurm <stephan.w...@a-eberle.de> _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel