New upstream version 17.11-rc3
[deb_dpdk.git] / doc / guides / sample_app_ug / ptpclient.rst
1 ..  BSD LICENSE
2     Copyright(c) 2015 Intel Corporation. All rights reserved.
3     All rights reserved.
4
5     Redistribution and use in source and binary forms, with or without
6     modification, are permitted provided that the following conditions
7     are met:
8
9     * Redistributions of source code must retain the above copyright
10     notice, this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright
12     notice, this list of conditions and the following disclaimer in
13     the documentation and/or other materials provided with the
14     distribution.
15     * Neither the name of Intel Corporation nor the names of its
16     contributors may be used to endorse or promote products derived
17     from this software without specific prior written permission.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
32 PTP Client Sample Application
33 =============================
34
35 The PTP (Precision Time Protocol) client sample application is a simple
36 example of using the DPDK IEEE1588 API to communicate with a PTP master clock
37 to synchronize the time on the NIC and, optionally, on the Linux system.
38
39 Note, PTP is a time syncing protocol and cannot be used within DPDK as a
40 time-stamping mechanism. See the following for an explanation of the protocol:
41 `Precision Time Protocol
42 <https://en.wikipedia.org/wiki/Precision_Time_Protocol>`_.
43
44
45 Limitations
46 -----------
47
48 The PTP sample application is intended as a simple reference implementation of
49 a PTP client using the DPDK IEEE1588 API.
50 In order to keep the application simple the following assumptions are made:
51
52 * The first discovered master is the master for the session.
53 * Only L2 PTP packets are supported.
54 * Only the PTP v2 protocol is supported.
55 * Only the slave clock is implemented.
56
57
58 How the Application Works
59 -------------------------
60
61 .. _figure_ptpclient_highlevel:
62
63 .. figure:: img/ptpclient.*
64
65    PTP Synchronization Protocol
66
67 The PTP synchronization in the sample application works as follows:
68
69 * Master sends *Sync* message - the slave saves it as T2.
70 * Master sends *Follow Up* message and sends time of T1.
71 * Slave sends *Delay Request* frame to PTP Master and stores T3.
72 * Master sends *Delay Response* T4 time which is time of received T3.
73
74 The adjustment for slave can be represented as:
75
76    adj = -[(T2-T1)-(T4 - T3)]/2
77
78 If the command line parameter ``-T 1`` is used the application also
79 synchronizes the PTP PHC clock with the Linux kernel clock.
80
81 Compiling the Application
82 -------------------------
83
84 To compile the sample application see :doc:`compiling`.
85
86 The application is located in the ``ptpclient`` sub-directory.
87
88 .. note::
89    To compile the application edit the ``config/common_linuxapp`` configuration file to enable IEEE1588
90    and then recompile DPDK:
91
92    .. code-block:: console
93
94       CONFIG_RTE_LIBRTE_IEEE1588=y
95
96 Running the Application
97 -----------------------
98
99 To run the example in a ``linuxapp`` environment:
100
101 .. code-block:: console
102
103     ./build/ptpclient -l 1 -n 4 -- -p 0x1 -T 0
104
105 Refer to *DPDK Getting Started Guide* for general information on running
106 applications and the Environment Abstraction Layer (EAL) options.
107
108 * ``-p portmask``: Hexadecimal portmask.
109 * ``-T 0``: Update only the PTP slave clock.
110 * ``-T 1``: Update the PTP slave clock and synchronize the Linux Kernel to the PTP clock.
111
112
113 Code Explanation
114 ----------------
115
116 The following sections provide an explanation of the main components of the
117 code.
118
119 All DPDK library functions used in the sample code are prefixed with ``rte_``
120 and are explained in detail in the *DPDK API Documentation*.
121
122
123 The Main Function
124 ~~~~~~~~~~~~~~~~~
125
126 The ``main()`` function performs the initialization and calls the execution
127 threads for each lcore.
128
129 The first task is to initialize the Environment Abstraction Layer (EAL).  The
130 ``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
131 function. The value returned is the number of parsed arguments:
132
133 .. code-block:: c
134
135     int ret = rte_eal_init(argc, argv);
136     if (ret < 0)
137         rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
138
139 And than we parse application specific arguments
140
141 .. code-block:: c
142
143     argc -= ret;
144     argv += ret;
145
146     ret = ptp_parse_args(argc, argv);
147     if (ret < 0)
148         rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
149
150 The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
151 used by the application:
152
153 .. code-block:: c
154
155     mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
156            MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
157
158 Mbufs are the packet buffer structure used by DPDK. They are explained in
159 detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
160
161 The ``main()`` function also initializes all the ports using the user defined
162 ``port_init()`` function with portmask provided by user:
163
164 .. code-block:: c
165
166     for (portid = 0; portid < nb_ports; portid++)
167         if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
168
169             if (port_init(portid, mbuf_pool) == 0) {
170                 ptp_enabled_ports[ptp_enabled_port_nb] = portid;
171                 ptp_enabled_port_nb++;
172             } else {
173                 rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
174                         portid);
175             }
176         }
177
178
179 Once the initialization is complete, the application is ready to launch a
180 function on an lcore. In this example ``lcore_main()`` is called on a single
181 lcore.
182
183 .. code-block:: c
184
185         lcore_main();
186
187 The ``lcore_main()`` function is explained below.
188
189
190 The Lcores Main
191 ~~~~~~~~~~~~~~~
192
193 As we saw above the ``main()`` function calls an application function on the
194 available lcores.
195
196 The main work of the application is done within the loop:
197
198 .. code-block:: c
199
200         for (portid = 0; portid < ptp_enabled_port_nb; portid++) {
201
202             portid = ptp_enabled_ports[portid];
203             nb_rx = rte_eth_rx_burst(portid, 0, &m, 1);
204
205             if (likely(nb_rx == 0))
206                 continue;
207
208             if (m->ol_flags & PKT_RX_IEEE1588_PTP)
209                 parse_ptp_frames(portid, m);
210
211             rte_pktmbuf_free(m);
212         }
213
214 Packets are received one by one on the RX ports and, if required, PTP response
215 packets are transmitted on the TX ports.
216
217 If the offload flags in the mbuf indicate that the packet is a PTP packet then
218 the packet is parsed to determine which type:
219
220 .. code-block:: c
221
222             if (m->ol_flags & PKT_RX_IEEE1588_PTP)
223                  parse_ptp_frames(portid, m);
224
225
226 All packets are freed explicitly using ``rte_pktmbuf_free()``.
227
228 The forwarding loop can be interrupted and the application closed using
229 ``Ctrl-C``.
230
231
232 PTP parsing
233 ~~~~~~~~~~~
234
235 The ``parse_ptp_frames()`` function processes PTP packets, implementing slave
236 PTP IEEE1588 L2 functionality.
237
238 .. code-block:: c
239
240     void
241     parse_ptp_frames(uint16_t portid, struct rte_mbuf *m) {
242         struct ptp_header *ptp_hdr;
243         struct ether_hdr *eth_hdr;
244         uint16_t eth_type;
245
246         eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
247         eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
248
249         if (eth_type == PTP_PROTOCOL) {
250             ptp_data.m = m;
251             ptp_data.portid = portid;
252             ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(m, char *)
253                         + sizeof(struct ether_hdr));
254
255             switch (ptp_hdr->msgtype) {
256             case SYNC:
257                 parse_sync(&ptp_data);
258                 break;
259             case FOLLOW_UP:
260                 parse_fup(&ptp_data);
261                 break;
262             case DELAY_RESP:
263                 parse_drsp(&ptp_data);
264                 print_clock_info(&ptp_data);
265                 break;
266             default:
267                 break;
268             }
269         }
270     }
271
272 There are 3 types of packets on the RX path which we must parse to create a minimal
273 implementation of the PTP slave client:
274
275 * SYNC packet.
276 * FOLLOW UP packet
277 * DELAY RESPONSE packet.
278
279 When we parse the *FOLLOW UP* packet we also create and send a *DELAY_REQUEST* packet.
280 Also when we parse the *DELAY RESPONSE* packet, and all conditions are met we adjust the PTP slave clock.