Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subsys: net: lib: Implement Precision Time Protocol (PTP) Support #73713

Merged
merged 36 commits into from
Jun 13, 2024

Conversation

awojasinski
Copy link
Collaborator

This pull request introduces support for the Precision Time Protocol (PTP), enhancing time synchronization capabilities within the Zephyr. PTP is a protocol that allows precise clock synchronization between networked devices over packet-switched networks, such as Ethernet. This implementation is crucial for applications requiring high-precision timekeeping systems.

Key Features

  • IEEE 1588 Compliance: The implementation adheres to the IEEE 1588 standard for precision clock synchronization network protocols.
  • Flexible Configuration: Users can configure various parameters, such as the PTP clock parameters, ports, transport protocol through Kconfig symbols.
  • Integration with Networking Stack via BSD Sockets API
  • Support for IPv4 and IPv6
  • PTP Slave Mode: The implementation supports both PTP slave modes, enabling devices to act as time followers in a network.

Testing

The implementation has been tested with linuxptp Project on nucleo_h563zi - Nucleo H563ZI development board. Additionally sample has been validated on native_sim target executed in docker image with net-tools.

The Pull Request could be split into two PRs. Following commits could be added as a separate PR:

However these changes are small compared to the rest of submitted code. In this PR it's clear why these commits are needed therefor I decided to included them in this PR.

- native_posix
- native_posix/native/64
- native_sim
- native_sim/native/64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you allow the 64 bit versions, I guess you also need a configuration overlay for them, or?

@carlescufi
Copy link
Member

Thanks for the PR!

Question, how does this related to the gPTP implementation we have as an L2 here:
https://github.com/zephyrproject-rtos/zephyr/tree/main/subsys/net/l2/ethernet/gptp

@awojasinski
Copy link
Collaborator Author

@carlescufi gPTP is just a subset of PTP, it works only on L2. You may consider it as one of PTP profiles. Whereas PTP supports L2 Ethernet, UDP IPv4 and IPv6, and even CAN. It has predefined profiles that target different use cases. This PR brings only part of features but in the future it can be extended and gPTP could be replaced with PTP and Kconfig symbol that configures PTP stack to be compliant with gPTP standard.

If you look at ptp4l it implements gPTP as well. It's just a matter of passing proper .cfg file.

Currently main advantage of the PTP over gPTP is IP support

Copy link
Member

@jukkar jukkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is lot of commits and it might make sense to split the PR to two, first the enabling / infra non-ptp related commits, and the other with PTP specific stuff. Currently this is hard to review properly.
While I was reviewing and commenting the code, you submitted a new version so some of my comments might not be valid any more.

# Copyright (c) 2024 BayLibre
# SPDX-License-Identifier: Apache-2.0

menuconfig PTP
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add here a !dependency to gPTP so both cannot be enabled at the same time.

* @note 5.3.3 - timestamp with respect to epoch
*/
struct ptp_timestamp {
/* Seconds encoded on 48 bits. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add doxygen comments to all the fields in the structs as otherwise the generated documentation looks weird. Please check all the struct comments in this and other header files in this PR.

Comment on lines 106 to 108
struct ptp_text name;
struct ptp_text value;
struct ptp_text desc;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really going to work properly as you have now multiple flexible members in a one struct? How is the compiler going to know where the name,value and desc structs will start because the sizeof(struct ptp_text) is 1?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This structure is defined in the standard. These struct ptp_text members are only containers for fault logs. You don't treat it as continuous space they are only pointers to some space where these values are stored.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But how you have specified them means that they are not pointers. The first flexible member name will indeed point to correct position, but the next one value will point to second byte in name because sizeof(name) is 1.
Note that what I am talking about here is related to how one access the value or desc field from C code, I am not talking about how the memory layout of the protocol message. So if you try to access the desc field using ptp_fault_record.desc, the value will be garbage even if the memory layout is correct. This can be highly confusing to the user.

config PTP_SLAVE_ONLY
bool "Configure Clock as slaveOnly PTP Instance"
depends on PTP_ORDINARY_CLOCK
default n
Copy link
Member

@jukkar jukkar Jun 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to mention default n as that is the default

Comment on lines 38 to 39
msg->ref--;
if (msg->ref) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not atomic. Perhaps it should?

};

socket = transport_socket_open(iface, (struct sockaddr *)&addr);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Comment on lines +202 to +203
if (IS_ENABLED(CONFIG_PTP_UDP_IPv4_PROTOCOL)) {
m_addr.sa_family = AF_INET;
net_sin(&m_addr)->sin_port = htons(port);
net_sin(&m_addr)->sin_addr.s_addr = mcast_addr.s_addr;

} else if (IS_ENABLED(CONFIG_PTP_UDP_IPv6_PROTOCOL)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be runtime configurable, so we should allow for example one interface to have IPv4, one IPv6 etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, in the future I could implement something that would allow to specify protocol per port but for now I would like to proceed with one protocol for all ports.

msghdr.msg_controllen = sizeof(ctrl);

cnt = zsock_recvmsg(port->socket[idx], &msghdr, ZSOCK_MSG_DONTWAIT);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line can be omitted

}

switch (mgmt->id) {
case PTP_MGMT_CLOCK_DESCRIPTION:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to add __fallthrough; after each case if we do not break

return PTP_EVT_FAULT_DETECTED;
}
}
/* fall through */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use __fallthrough; instead of this comment

Add dynamic memory allocation for PTP messages. Memory allocation
is done with Zephyr's memory slab. It's size can be configured
with `PTP_MSG_POLL_SIZE` Kconfig symbol.

Signed-off-by: Adam Wojasinski <[email protected]>
Add functions preparing messages to network byte order before sending
and changing to host byte order after reception and before processing
by PTP stack.

Signed-off-by: Adam Wojasinski <[email protected]>
Add allocation of container used for TLVs and dummy functions for
preparing correct byte order of data. TLV stands for Type, Length,
Value, and it is extension of PTP messages that's used to transmit
extra information. This data is attached at the end of PTP message.

Signed-off-by: Adam Wojasinski <[email protected]>
This commit adds handling of Management TLVs

Signed-off-by: Adam Wojasinski <[email protected]>
This commit introduces module responsible for sending and receiving
messages. It is based on BSD Sockets API.

Signed-off-by: Adam Wojasinski <[email protected]>
Based on Port ID decision about message processing can be made.

Signed-off-by: Adam Wojasinski <[email protected]>
Foreign timeTransmitters are other PTP Clocks in a domain. They announce
their parameters via announce messages. PTP Ports should record
these foreign timeTransmitters.

Signed-off-by: Adam Wojasinski <[email protected]>
Initial implementation of the clock adjustment and delay calculation.
Timestamp values used for calculations will be obtained from
proper PTP messages (Sync, Follow_Up, Delay_Req, and Delay_Resp)

Signed-off-by: Adam Wojasinski <[email protected]>
This commit adds routines for handling incoming messages
needed for correct operation of the PTP stack in end to end
mode with multicast operation mode.

Signed-off-by: Adam Wojasinski <[email protected]>
Add handler for STATE_DECISION_EVENT it consists of following routines:
- state decision algorithm
- best timeTransmitter clock algorithm
- data sets comparison algorithm

Based on IEEE 1588-2019 section 9.3.3

Signed-off-by: Adam Wojasinski <[email protected]>
Introduction of routines processing received PTP Management messages.
The processing is split into clock-oriented and port-oriented parts.

Signed-off-by: Adam Wojasinski <[email protected]>
This commit introduces routines for PTP message transmission.
It includes transmission of three types of messages (Announce,
Sync, Delay_Req) that should be send periodically depending
on the PTP Port's state.

Signed-off-by: Adam Wojasinski <[email protected]>
Timers are used to trigger message transmission and detect
inactivity of other PTP Clocks what should result in an action
of the PTP Port.

Signed-off-by: Adam Wojasinski <[email protected]>
The commit adds functions that enable and disable PTP Port.
This is going to be used by event handling routine.

Signed-off-by: Adam Wojasinski <[email protected]>
Introduction of PTP stack's core functions responsible for
event generation and handling of these events. Events are generated
base on timeouts and/or PTP messages received via BSD sockets
assigned to a specific PTP Port. These function will be used
in PTP thread.

Signed-off-by: Adam Wojasinski <[email protected]>
The STATE_DECISION_EVENT in PTP is a pivotal mechanism that
facilitates dynamic state management within the protocol,
allowing devices to adapt their operational states based on the BTCA's
recommendations and the health of the network.

Signed-off-by: Adam Wojasinski <[email protected]>
This commit adds implementation of the PTP thread that will
poll sockets descriptors and PTP Port's timeres for timeouts,
generate events and handle them and trigger STATE_DECISION_EVENT
handling when needed.

Signed-off-by: Adam Wojasinski <[email protected]>
Adding network interface status monitor function. Depending
on the interface operation state and change of the state
events are generated and handled by the function.

Signed-off-by: Adam Wojasinski <[email protected]>
Add documentation page for IEEE 1588-2019 (PTP) library.

Signed-off-by: Adam Wojasinski <[email protected]>
Add conditions to enable ptp_clock driver implementation
for native_posix when PTP subsystem is enabled.

Signed-off-by: Adam Wojasinski <[email protected]>
This application demonstrates PTP functionality

Signed-off-by: Adam Wojasinski <[email protected]>
Introducing a new PTP maintenance entry with awojasinski
as maintainer.

Signed-off-by: Adam Wojasinski <[email protected]>
@awojasinski
Copy link
Collaborator Author

Pushed rebased branch to pull in fix for failing test

@nashif nashif merged commit f16d556 into zephyrproject-rtos:main Jun 13, 2024
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants