1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2018 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define NET_LOG_LEVEL CONFIG_NET_L2_ETHERNET_LOG_LEVEL
10 /* Custom PTP device name to avoid conflicts with PTP devices on SOC */
11 #define PTP_VIRT_CLOCK_NAME "PTP_CLOCK_VIRT"
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL);
15
16 #include <zephyr/types.h>
17 #include <stdbool.h>
18 #include <stddef.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <zephyr/sys/printk.h>
22 #include <zephyr/linker/sections.h>
23
24 #include <zephyr/ztest.h>
25
26 #include <zephyr/drivers/ptp_clock.h>
27 #include <zephyr/net/ptp_time.h>
28
29 #include <zephyr/net/ethernet.h>
30 #include <zephyr/net/buf.h>
31 #include <zephyr/net/net_ip.h>
32 #include <zephyr/net/net_l2.h>
33
34 #include <zephyr/random/random.h>
35
36 #define NET_LOG_ENABLED 1
37 #include "net_private.h"
38
39 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
40 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
41 #else
42 #define DBG(fmt, ...)
43 #endif
44
45 /* Interface 1 addresses */
46 static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
47 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
48
49 /* Interface 2 addresses */
50 static struct in6_addr my_addr2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
52
53 /* Interface 3 addresses */
54 static struct in6_addr my_addr3 = { { { 0x20, 0x01, 0x0d, 0xb8, 2, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
56
57 /* Extra address is assigned to ll_addr */
58 static struct in6_addr ll_addr = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0,
59 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02,
60 0x04 } } };
61
62 #define MAX_NUM_INTERFACES 3
63
64 /* Keep track of all ethernet interfaces */
65 static struct net_if *eth_interfaces[MAX_NUM_INTERFACES];
66
67 static ZTEST_BMEM int ptp_clocks[MAX_NUM_INTERFACES - 1];
68 static int ptp_interface[MAX_NUM_INTERFACES - 1];
69 static int non_ptp_interface;
70 static bool test_failed;
71 static bool test_started;
72
73 static K_SEM_DEFINE(wait_data, 0, UINT_MAX);
74
75 #define WAIT_TIME K_SECONDS(1)
76
77 struct eth_context {
78 struct net_if *iface;
79 uint8_t mac_addr[6];
80
81 struct net_ptp_time time;
82 const struct device *ptp_clock;
83 };
84
85 static struct eth_context eth_context_1;
86 static struct eth_context eth_context_2;
87 static struct eth_context eth_context_3;
88
eth_iface_init(struct net_if * iface)89 static void eth_iface_init(struct net_if *iface)
90 {
91 const struct device *dev = net_if_get_device(iface);
92 struct eth_context *context = dev->data;
93
94 net_if_set_link_addr(iface, context->mac_addr,
95 sizeof(context->mac_addr),
96 NET_LINK_ETHERNET);
97
98 ethernet_init(iface);
99 }
100
eth_tx(const struct device * dev,struct net_pkt * pkt)101 static int eth_tx(const struct device *dev, struct net_pkt *pkt)
102 {
103 struct eth_context *context = dev->data;
104
105 if (ð_context_1 != context && ð_context_2 != context) {
106 zassert_true(false, "Context pointers do not match\n");
107 }
108
109 if (!pkt->frags) {
110 DBG("No data to send!\n");
111 return -ENODATA;
112 }
113
114 if (test_started) {
115 k_sem_give(&wait_data);
116 }
117
118
119 return 0;
120 }
121
eth_capabilities(const struct device * dev)122 static enum ethernet_hw_caps eth_capabilities(const struct device *dev)
123 {
124 return ETHERNET_PTP;
125 }
126
eth_get_ptp_clock(const struct device * dev)127 static const struct device *eth_get_ptp_clock(const struct device *dev)
128 {
129 struct eth_context *context = dev->data;
130
131 return context->ptp_clock;
132 }
133
134 static struct ethernet_api api_funcs = {
135 .iface_api.init = eth_iface_init,
136
137 .get_capabilities = eth_capabilities,
138 .get_ptp_clock = eth_get_ptp_clock,
139 .send = eth_tx,
140 };
141
generate_mac(uint8_t * mac_addr)142 static void generate_mac(uint8_t *mac_addr)
143 {
144 /* 00-00-5E-00-53-xx Documentation RFC 7042 */
145 mac_addr[0] = 0x00;
146 mac_addr[1] = 0x00;
147 mac_addr[2] = 0x5E;
148 mac_addr[3] = 0x00;
149 mac_addr[4] = 0x53;
150 mac_addr[5] = sys_rand8_get();
151 }
152
eth_init(const struct device * dev)153 static int eth_init(const struct device *dev)
154 {
155 struct eth_context *context = dev->data;
156
157 generate_mac(context->mac_addr);
158
159 return 0;
160 }
161
162 ETH_NET_DEVICE_INIT(eth3_test, "eth3_test", eth_init, NULL,
163 ð_context_3, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
164 NET_ETH_MTU);
165
166 ETH_NET_DEVICE_INIT(eth2_test, "eth2_test", eth_init, NULL,
167 ð_context_2, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
168 NET_ETH_MTU);
169
170 ETH_NET_DEVICE_INIT(eth1_test, "eth1_test", eth_init, NULL,
171 ð_context_1, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
172 NET_ETH_MTU);
173
timestamp_to_nsec(struct net_ptp_time * ts)174 static uint64_t timestamp_to_nsec(struct net_ptp_time *ts)
175 {
176 if (!ts) {
177 return 0;
178 }
179
180 return (ts->second * NSEC_PER_SEC) + ts->nanosecond;
181 }
182
183 struct ptp_context {
184 struct eth_context *eth_context;
185 };
186
my_ptp_clock_set(const struct device * dev,struct net_ptp_time * tm)187 static int my_ptp_clock_set(const struct device *dev, struct net_ptp_time *tm)
188 {
189 struct ptp_context *ptp_ctx = dev->data;
190 struct eth_context *eth_ctx = ptp_ctx->eth_context;
191
192 if (ð_context_3 != eth_ctx && ð_context_2 != eth_ctx) {
193 zassert_true(false, "Context pointers do not match\n");
194 }
195
196 memcpy(ð_ctx->time, tm, sizeof(struct net_ptp_time));
197
198 return 0;
199 }
200
my_ptp_clock_get(const struct device * dev,struct net_ptp_time * tm)201 static int my_ptp_clock_get(const struct device *dev, struct net_ptp_time *tm)
202 {
203 struct ptp_context *ptp_ctx = dev->data;
204 struct eth_context *eth_ctx = ptp_ctx->eth_context;
205
206 memcpy(tm, ð_ctx->time, sizeof(struct net_ptp_time));
207
208 return 0;
209 }
210
my_ptp_clock_adjust(const struct device * dev,int increment)211 static int my_ptp_clock_adjust(const struct device *dev, int increment)
212 {
213 struct ptp_context *ptp_ctx = dev->data;
214 struct eth_context *eth_ctx = ptp_ctx->eth_context;
215
216 eth_ctx->time.nanosecond += increment;
217
218 return 0;
219 }
220
my_ptp_clock_rate_adjust(const struct device * dev,double ratio)221 static int my_ptp_clock_rate_adjust(const struct device *dev, double ratio)
222 {
223 return 0;
224 }
225
226 static struct ptp_context ptp_test_1_context;
227 static struct ptp_context ptp_test_2_context;
228
229 static const struct ptp_clock_driver_api api = {
230 .set = my_ptp_clock_set,
231 .get = my_ptp_clock_get,
232 .adjust = my_ptp_clock_adjust,
233 .rate_adjust = my_ptp_clock_rate_adjust,
234 };
235
ptp_test_1_init(const struct device * port)236 static int ptp_test_1_init(const struct device *port)
237 {
238 const struct device *const eth_dev = DEVICE_GET(eth3_test);
239 struct eth_context *context = eth_dev->data;
240 struct ptp_context *ptp_context = port->data;
241
242 context->ptp_clock = port;
243 ptp_context->eth_context = context;
244
245 return 0;
246 }
247
248 DEVICE_DEFINE(ptp_clock_1, PTP_VIRT_CLOCK_NAME, ptp_test_1_init,
249 NULL, &ptp_test_1_context, NULL,
250 POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, &api);
251
ptp_test_2_init(const struct device * port)252 static int ptp_test_2_init(const struct device *port)
253 {
254 const struct device *const eth_dev = DEVICE_GET(eth2_test);
255 struct eth_context *context = eth_dev->data;
256 struct ptp_context *ptp_context = port->data;
257
258 context->ptp_clock = port;
259 ptp_context->eth_context = context;
260
261 return 0;
262 }
263
264 DEVICE_DEFINE(ptp_clock_2, PTP_VIRT_CLOCK_NAME, ptp_test_2_init,
265 NULL, &ptp_test_2_context, NULL,
266 POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, &api);
267
268 struct user_data {
269 int eth_if_count;
270 int total_if_count;
271 };
272
273 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
iface2str(struct net_if * iface)274 static const char *iface2str(struct net_if *iface)
275 {
276 #ifdef CONFIG_NET_L2_ETHERNET
277 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
278 return "Ethernet";
279 }
280 #endif
281
282 return "<unknown type>";
283 }
284 #endif
285
iface_cb(struct net_if * iface,void * user_data)286 static void iface_cb(struct net_if *iface, void *user_data)
287 {
288 struct user_data *ud = user_data;
289
290 /*
291 * The below code is to only use struct net_if devices defined in this
292 * test as board on which it is run can have its own set of interfaces.
293 *
294 * As a result one will not rely on linker's specific 'net_if_area'
295 * placement.
296 */
297 if ((iface != net_if_lookup_by_dev(DEVICE_GET(eth3_test))) &&
298 (iface != net_if_lookup_by_dev(DEVICE_GET(eth2_test))) &&
299 (iface != net_if_lookup_by_dev(DEVICE_GET(eth1_test)))) {
300 return;
301 }
302
303 DBG("Interface %p (%s) [%d]\n", iface, iface2str(iface),
304 net_if_get_by_iface(iface));
305
306 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
307 static int ptp_iface_idx;
308 const struct device *clk;
309
310 if (ud->eth_if_count >= ARRAY_SIZE(eth_interfaces)) {
311 DBG("Invalid interface %p\n", iface);
312 return;
313 }
314
315 clk = net_eth_get_ptp_clock(iface);
316 if (!clk) {
317 non_ptp_interface = ud->eth_if_count;
318 } else {
319 ptp_interface[ptp_iface_idx] = ud->eth_if_count;
320 ptp_clocks[ptp_iface_idx] = net_if_get_by_iface(iface);
321 ptp_iface_idx++;
322 }
323
324 eth_interfaces[ud->eth_if_count++] = iface;
325 }
326
327 /* By default all interfaces are down initially */
328 net_if_down(iface);
329
330 ud->total_if_count++;
331 }
332
test_check_interfaces(void)333 static void test_check_interfaces(void)
334 {
335 struct user_data ud = { 0 };
336
337 /* Make sure we have enough interfaces */
338 net_if_foreach(iface_cb, &ud);
339
340 zassert_equal(ud.eth_if_count, MAX_NUM_INTERFACES,
341 "Invalid number of ethernet interfaces %d vs %d\n",
342 ud.eth_if_count, MAX_NUM_INTERFACES);
343
344 zassert_equal(ud.total_if_count, ud.eth_if_count,
345 "Invalid number of interfaces %d vs %d\n",
346 ud.total_if_count, ud.eth_if_count);
347 }
348
349 /* As we are testing the ethernet controller clock, the IP addresses are not
350 * relevant for this testing. Anyway, set the IP addresses to the interfaces so
351 * we have a real life scenario.
352 */
test_address_setup(void)353 static void test_address_setup(void)
354 {
355 struct net_if_addr *ifaddr;
356 struct net_if *iface1, *iface2, *iface3;
357
358 iface1 = eth_interfaces[0];
359 iface2 = eth_interfaces[1];
360 iface3 = eth_interfaces[2];
361
362 zassert_not_null(iface1, "Interface 1\n");
363 zassert_not_null(iface2, "Interface 2\n");
364 zassert_not_null(iface3, "Interface 3\n");
365
366 ifaddr = net_if_ipv6_addr_add(iface1, &my_addr1,
367 NET_ADDR_MANUAL, 0);
368 if (!ifaddr) {
369 DBG("Cannot add IPv6 address %s\n",
370 net_sprint_ipv6_addr(&my_addr1));
371 zassert_not_null(ifaddr, "addr1\n");
372 }
373
374 /* For testing purposes we need to set the addresses preferred */
375 ifaddr->addr_state = NET_ADDR_PREFERRED;
376
377 ifaddr = net_if_ipv6_addr_add(iface1, &ll_addr,
378 NET_ADDR_MANUAL, 0);
379 if (!ifaddr) {
380 DBG("Cannot add IPv6 address %s\n",
381 net_sprint_ipv6_addr(&ll_addr));
382 zassert_not_null(ifaddr, "ll_addr\n");
383 }
384
385 ifaddr->addr_state = NET_ADDR_PREFERRED;
386
387 ifaddr = net_if_ipv6_addr_add(iface2, &my_addr2,
388 NET_ADDR_MANUAL, 0);
389 if (!ifaddr) {
390 DBG("Cannot add IPv6 address %s\n",
391 net_sprint_ipv6_addr(&my_addr2));
392 zassert_not_null(ifaddr, "addr2\n");
393 }
394
395 ifaddr->addr_state = NET_ADDR_PREFERRED;
396
397 ifaddr = net_if_ipv6_addr_add(iface3, &my_addr3,
398 NET_ADDR_MANUAL, 0);
399 if (!ifaddr) {
400 DBG("Cannot add IPv6 address %s\n",
401 net_sprint_ipv6_addr(&my_addr3));
402 zassert_not_null(ifaddr, "addr3\n");
403 }
404
405 net_if_up(iface1);
406 net_if_up(iface2);
407 net_if_up(iface3);
408
409 test_failed = false;
410 }
411
test_ptp_clock_interfaces(void)412 static void test_ptp_clock_interfaces(void)
413 {
414 const struct device *clk_by_index;
415 const struct device *clk;
416 int idx;
417
418 idx = ptp_interface[0];
419 clk = net_eth_get_ptp_clock(eth_interfaces[idx]);
420 zassert_not_null(clk, "Clock not found for interface %p\n",
421 eth_interfaces[idx]);
422
423 idx = ptp_interface[1];
424 clk = net_eth_get_ptp_clock(eth_interfaces[idx]);
425 zassert_not_null(clk, "Clock not found for interface %p\n",
426 eth_interfaces[idx]);
427
428 clk = net_eth_get_ptp_clock(eth_interfaces[non_ptp_interface]);
429 zassert_is_null(clk, "Clock found for interface %p\n",
430 eth_interfaces[non_ptp_interface]);
431
432 clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[0]);
433 zassert_not_null(clk_by_index,
434 "Clock not found for interface index %d\n",
435 ptp_clocks[0]);
436 }
437
test_ptp_clock_iface(int idx)438 static void test_ptp_clock_iface(int idx)
439 {
440 int rnd_value = sys_rand32_get();
441 struct net_ptp_time tm = {
442 .second = 1,
443 .nanosecond = 1,
444 };
445 const struct device *clk;
446 uint64_t orig, new_value;
447
448 clk = net_eth_get_ptp_clock(eth_interfaces[idx]);
449
450 zassert_not_null(clk, "Clock not found for interface %p\n",
451 eth_interfaces[idx]);
452
453 ptp_clock_set(clk, &tm);
454
455 orig = timestamp_to_nsec(&tm);
456
457 if (rnd_value == 0 || rnd_value < 0) {
458 rnd_value = 2;
459 }
460
461 ptp_clock_adjust(clk, rnd_value);
462
463 (void)memset(&tm, 0, sizeof(tm));
464 ptp_clock_get(clk, &tm);
465
466 new_value = timestamp_to_nsec(&tm);
467
468 /* The clock value must be the same after incrementing it */
469 zassert_equal(orig + rnd_value, new_value,
470 "Time adjust failure (%llu vs %llu)\n",
471 orig + rnd_value, new_value);
472 }
473
test_ptp_clock_iface_1(void)474 static void test_ptp_clock_iface_1(void)
475 {
476 test_ptp_clock_iface(ptp_interface[0]);
477 }
478
test_ptp_clock_iface_2(void)479 static void test_ptp_clock_iface_2(void)
480 {
481 test_ptp_clock_iface(ptp_interface[1]);
482 }
483
484 static ZTEST_BMEM const struct device *clk0;
485 static ZTEST_BMEM const struct device *clk1;
486
test_ptp_clock_get_by_index(void)487 static void test_ptp_clock_get_by_index(void)
488 {
489 const struct device *clk, *clk_by_index;
490 int idx;
491
492 idx = ptp_interface[0];
493
494 clk = net_eth_get_ptp_clock(eth_interfaces[idx]);
495 zassert_not_null(clk, "PTP 0 not found");
496
497 clk0 = clk;
498
499 clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[0]);
500 zassert_not_null(clk_by_index, "PTP 0 not found");
501
502 zassert_equal(clk, clk_by_index, "Interface index %d invalid", idx);
503
504 idx = ptp_interface[1];
505
506 clk = net_eth_get_ptp_clock(eth_interfaces[idx]);
507 zassert_not_null(clk, "PTP 1 not found");
508
509 clk1 = clk;
510
511 clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[1]);
512 zassert_not_null(clk_by_index, "PTP 1 not found");
513
514 zassert_equal(clk, clk_by_index, "Interface index %d invalid", idx);
515 }
516
test_ptp_clock_get_by_index_user(void)517 static void test_ptp_clock_get_by_index_user(void)
518 {
519 const struct device *clk_by_index;
520
521 clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[0]);
522 zassert_not_null(clk_by_index, "PTP 0 not found");
523 zassert_equal(clk0, clk_by_index, "Invalid PTP clock 0");
524
525 clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[1]);
526 zassert_not_null(clk_by_index, "PTP 1 not found");
527 zassert_equal(clk1, clk_by_index, "Invalid PTP clock 1");
528 }
529
530 static ZTEST_BMEM struct net_ptp_time tm;
531 static ZTEST_BMEM struct net_ptp_time empty;
532
test_ptp_clock_get_by_xxx(const char * who)533 static void test_ptp_clock_get_by_xxx(const char *who)
534 {
535 const struct device *clk_by_index;
536 int ret;
537
538 clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[0]);
539 zassert_not_null(clk_by_index, "PTP 0 not found (%s)", who);
540 zassert_equal(clk0, clk_by_index, "Invalid PTP clock 0 (%s)", who);
541
542 (void)memset(&tm, 0, sizeof(tm));
543 ptp_clock_get(clk_by_index, &tm);
544
545 ret = memcmp(&tm, &empty, sizeof(tm));
546 zassert_not_equal(ret, 0, "ptp_clock_get() failed in %s mode", who);
547 }
548
test_ptp_clock_get_kernel(void)549 static void test_ptp_clock_get_kernel(void)
550 {
551 const struct device *clk;
552
553 /* Make sure that this function is really run in kernel mode by
554 * calling a function that will not work in user mode.
555 */
556 clk = net_eth_get_ptp_clock(eth_interfaces[0]);
557
558 test_ptp_clock_get_by_xxx("kernel");
559 }
560
test_ptp_clock_get_user(void)561 static void test_ptp_clock_get_user(void)
562 {
563 test_ptp_clock_get_by_xxx("user");
564 }
565
setup(void)566 void *setup(void)
567 {
568 const struct device *clk;
569
570 clk = device_get_binding(PTP_VIRT_CLOCK_NAME);
571 if (clk != NULL) {
572 k_object_access_grant(clk, k_current_get());
573 }
574 return NULL;
575 }
576
ZTEST(ptp_clock_test_suite,test_ptp_clock)577 ZTEST(ptp_clock_test_suite, test_ptp_clock)
578 {
579 test_check_interfaces();
580 test_address_setup();
581 test_ptp_clock_interfaces();
582 test_ptp_clock_iface_1();
583 test_ptp_clock_iface_2();
584 test_ptp_clock_get_by_index();
585 test_ptp_clock_get_by_index_user();
586 test_ptp_clock_get_kernel();
587 test_ptp_clock_get_user();
588 }
589
590 ZTEST_SUITE(ptp_clock_test_suite, NULL, setup, NULL, NULL, NULL);
591