xref: /dpdk/doc/guides/sample_app_ug/ptpclient.rst (revision 37dda90ee15b7098bc48356868a87d34f727eecc)
1..  SPDX-License-Identifier: BSD-3-Clause
2    Copyright(c) 2015 Intel Corporation.
3
4PTP Client Sample Application
5=============================
6
7The PTP (Precision Time Protocol) client sample application is a simple
8example of using the DPDK IEEE1588 API to communicate with a PTP time transmitter
9to synchronize the time on the NIC and, optionally, on the Linux system.
10
11Note, PTP is a time syncing protocol and cannot be used within DPDK as a
12time-stamping mechanism. See the following for an explanation of the protocol:
13`Precision Time Protocol
14<https://en.wikipedia.org/wiki/Precision_Time_Protocol>`_.
15
16
17Limitations
18-----------
19
20The PTP sample application is intended as a simple reference implementation of
21a PTP client using the DPDK IEEE1588 API.
22In order to keep the application simple the following assumptions are made:
23
24* The first discovered time transmitter is the main for the session.
25* Only L2 PTP packets are supported.
26* Only the PTP v2 protocol is supported.
27* Only the time receiver clock is implemented.
28
29
30How the Application Works
31-------------------------
32
33.. _figure_ptpclient_highlevel:
34
35.. figure:: img/ptpclient.*
36
37   PTP Synchronization Protocol
38
39The PTP synchronization in the sample application works as follows:
40
41* Time transmitter sends *Sync* message - the time receiver saves it as T2.
42* Time transmitter sends *Follow Up* message and sends time of T1.
43* Time receiver sends *Delay Request* frame to PTP time transmitter and stores T3.
44* Time transmitter sends *Delay Response* T4 time which is time of received T3.
45
46The adjustment for time receiver can be represented as:
47
48   adj = -[(T2-T1)-(T4 - T3)]/2
49
50If the command line parameter ``-T 1`` is used the application also
51synchronizes the PTP PHC clock with the Linux kernel clock.
52
53If the command line parameter ``-c 1`` is used,
54the application will also use the servo of the local clock.
55Only one type of servo is currently implemented, the PI controller.
56Default 0 (not used).
57
58
59Compiling the Application
60-------------------------
61
62To compile the sample application see :doc:`compiling`.
63
64The application is located in the ``ptpclient`` sub-directory.
65
66
67Running the Application
68-----------------------
69
70To run the example in a ``linux`` environment:
71
72.. code-block:: console
73
74    ./<build_dir>/examples/dpdk-ptpclient -l 1 -n 4 -- -p 0x1 -T 0 -c 1
75
76Refer to *DPDK Getting Started Guide* for general information on running
77applications and the Environment Abstraction Layer (EAL) options.
78
79* ``-p portmask``: Hexadecimal portmask.
80* ``-T 0``: Update only the PTP time receiver clock.
81* ``-T 1``: Update the PTP time receiver clock and synchronize the Linux Kernel to the PTP clock.
82* ``-c 0``: Not used clock servo controller.
83* ``-c 1``: The clock servo PI controller is used and the log will print information
84            about time transmitter offset.
85            Note that the PMD needs to support the ``rte_eth_timesync_adjust_freq()`` API
86            to enable the servo controller.
87
88Also, by adding ``-T 1`` and ``-c 1``, the time transmitter offset value printed in the log
89will slowly converge and eventually stabilise at the nanosecond level.
90The synchronisation accuracy is much higher compared to not using a servo controller.
91
92
93Code Explanation
94----------------
95
96The following sections provide an explanation of the main components of the
97code.
98
99All DPDK library functions used in the sample code are prefixed with ``rte_``
100and are explained in detail in the *DPDK API Documentation*.
101
102
103The Main Function
104~~~~~~~~~~~~~~~~~
105
106The ``main()`` function performs the initialization and calls the execution
107threads for each lcore.
108
109The first task is to initialize the Environment Abstraction Layer (EAL).  The
110``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
111function. The value returned is the number of parsed arguments:
112
113.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
114    :language: c
115    :start-after: Initialize the Environment Abstraction Layer (EAL). 8<
116    :end-before: >8 End of initialization of EAL.
117    :dedent: 1
118
119And than we parse application specific arguments
120
121.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
122    :language: c
123    :start-after: Parse specific arguments. 8<
124    :end-before: >8 End of parsing specific arguments.
125    :dedent: 1
126
127The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
128used by the application:
129
130.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
131    :language: c
132    :start-after: Creates a new mempool in memory to hold the mbufs. 8<
133    :end-before:  >8 End of a new mempool in memory to hold the mbufs.
134    :dedent: 1
135
136Mbufs are the packet buffer structure used by DPDK. They are explained in
137detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
138
139The ``main()`` function also initializes all the ports using the user defined
140``port_init()`` function with portmask provided by user:
141
142.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
143    :language: c
144    :start-after: Initialize all ports. 8<
145    :end-before: >8 End of initialization of all ports.
146    :dedent: 1
147
148
149Once the initialization is complete, the application is ready to launch a
150function on an lcore. In this example ``lcore_main()`` is called on a single
151lcore.
152
153.. code-block:: c
154
155	lcore_main();
156
157The ``lcore_main()`` function is explained below.
158
159
160The Lcores Main
161~~~~~~~~~~~~~~~
162
163As we saw above the ``main()`` function calls an application function on the
164available lcores.
165
166The main work of the application is done within the loop:
167
168.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
169    :language: c
170    :start-after: Read packet from RX queues. 8<
171    :end-before: >8 End of read packets from RX queues.
172    :dedent: 2
173
174Packets are received one by one on the RX ports and, if required, PTP response
175packets are transmitted on the TX ports.
176
177If the offload flags in the mbuf indicate that the packet is a PTP packet then
178the packet is parsed to determine which type:
179
180.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
181    :language: c
182    :start-after: Packet is parsed to determine which type. 8<
183    :end-before: >8 End of packet is parsed to determine which type.
184    :dedent: 3
185
186
187All packets are freed explicitly using ``rte_pktmbuf_free()``.
188
189The forwarding loop can be interrupted and the application closed using
190``Ctrl-C``.
191
192
193PTP parsing
194~~~~~~~~~~~
195
196The ``parse_ptp_frames()`` function processes PTP packets, implementing time receiver
197PTP IEEE1588 L2 functionality.
198
199.. literalinclude:: ../../../examples/ptpclient/ptpclient.c
200    :language: c
201    :start-after: Parse ptp frames. 8<
202    :end-before:  >8 End of function processes PTP packets.
203
204There are 3 types of packets on the RX path which we must parse to create a minimal
205implementation of the PTP time receiver client:
206
207* SYNC packet.
208* FOLLOW UP packet
209* DELAY RESPONSE packet.
210
211When we parse the *FOLLOW UP* packet we also create and send a *DELAY_REQUEST* packet.
212Also when we parse the *DELAY RESPONSE* packet, and all conditions are met
213we adjust the PTP time receiver clock.
214