Merge ~liaou3/checkbox-iiotg/+git/checkbox-provider-intliotg:refactor_tsn_timesync into ~checkbox-dev/checkbox-iiotg/+git/checkbox-provider-intliotg:master

Proposed by Vincent Liao
Status: Merged
Approved by: Vincent Liao
Approved revision: 3546365f56347c6e982df80c7043fcd6055d1ceb
Merged at revision: ba071093692d9392352e02dbc9b69519446c2cdc
Proposed branch: ~liaou3/checkbox-iiotg/+git/checkbox-provider-intliotg:refactor_tsn_timesync
Merge into: ~checkbox-dev/checkbox-iiotg/+git/checkbox-provider-intliotg:master
Diff against target: 857 lines (+575/-186)
4 files modified
bin/tsn.py (+550/-0)
dev/null (+0/-49)
units/tsn/jobs.pxu (+20/-129)
units/tsn/test-plan.pxu (+5/-8)
Reviewer Review Type Date Requested Status
StanleyHuang Approve
Rick Wu Approve
Weichen Wu Pending
Vic Liu Pending
PeiYao Chang Pending
Review via email: mp+464398@code.launchpad.net

Commit message

Refactor TSN 802.1as-2011

To post a comment you must log in.
Revision history for this message
Rick Wu (rickwu4444) wrote :

Hi Vincent, Please see my inline comment.

review: Needs Information
Revision history for this message
StanleyHuang (stanley31) wrote :

I have some suggestions in inline comments and one questions as following.

- why we need to run clear_qdisc_settings(interface) function in the beginning of each tests?

review: Needs Fixing
Revision history for this message
Vincent Liao (liaou3) wrote :

@Rick

The reason why I use `/usr/share/doc/linuxptp/configs/automotive-slave.cfg` as default instead of `"$SNAP"/usr/share/doc/linuxptp/configs/automotive-slave.cfg` is we are not sure if the user is running this script with checkbox.
If yes, of course it works.
If not, it is better if we use `/usr/share/doc/linuxptp/configs/automotive-slave.cfg` since it is the defaule config for linuxptp.

Revision history for this message
Vincent Liao (liaou3) wrote :

> @Rick
>
> The reason why I use `/usr/share/doc/linuxptp/configs/automotive-slave.cfg` as
> default instead of `"$SNAP"/usr/share/doc/linuxptp/configs/automotive-
> slave.cfg` is we are not sure if the user is running this script with
> checkbox.
> If yes, of course it works.
> If not, it is better if we use `/usr/share/doc/linuxptp/configs/automotive-
> slave.cfg` since it is the defaule config for linuxptp.

And I also reckon it is not a good idea to use `environment variable` in the python script. We should use arg parse instead of depending on environment variable.

Revision history for this message
Rick Wu (rickwu4444) wrote :

LGTM

review: Approve
Revision history for this message
StanleyHuang (stanley31) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/tsn.py b/bin/tsn.py
2new file mode 100755
3index 0000000..c85e686
4--- /dev/null
5+++ b/bin/tsn.py
6@@ -0,0 +1,550 @@
7+#!/usr/bin/python3
8+
9+import argparse
10+import subprocess
11+import shlex
12+from threading import Event
13+from typing import List
14+from contextlib import contextmanager
15+
16+
17+def clear_qdisc_settings(interface: str) -> None:
18+ """Clear the previous qdisc settings.
19+
20+ This function clears the previous qdisc settings by running the tc
21+ command with the 'qdisc del' option. It may return an error if there
22+ is no previous settings.
23+ This will get errors if there is no previous settings.
24+
25+ Args:
26+ interface (str): The name of the network interface.
27+
28+ Returns:
29+ None
30+ """
31+ # Build the tc command to delete the root qdisc settings
32+ cmd = "tc qdisc del dev {} root".format(interface)
33+
34+ # Run the tc command with shell=True and a timeout of 1 second
35+ subprocess.run(cmd, shell=True, timeout=1)
36+
37+
38+@contextmanager
39+def clear_qdisc_settings_before_and_after(interface: str):
40+ """Clear the previous qdisc settings.
41+
42+ This context manager clears the previous qdisc settings by running the
43+ tc command with the 'qdisc del' option. It may return an error if there
44+ is no previous settings.
45+
46+ Args:
47+ interface (str): The name of the network interface.
48+
49+ Yields:
50+ None
51+
52+ Raises:
53+ subprocess.CalledProcessError: If the tc command fails to delete
54+ the root qdisc settings.
55+ """
56+
57+ # Run the tc command to delete the root qdisc settings
58+ try:
59+ # Clear qdisc settings before the function call
60+ clear_qdisc_settings(interface)
61+ yield
62+ finally:
63+ # Clear qdisc settings after the function call
64+ clear_qdisc_settings(interface)
65+
66+
67+def clear_qdisc_settings_before_and_after_decorator(func):
68+ """
69+ Decorator that clears the qdisc settings before and after calling
70+ the decorated function.
71+
72+ Args:
73+ func (Callable): The function to be decorated.
74+
75+ Returns:
76+ Callable: The decorated function.
77+
78+ This decorator wraps the given function with a context manager that
79+ clears the qdisc settings before and after the function call.
80+ It ensures that the qdisc settings are cleared even if an
81+ exception occurs during the function execution.
82+
83+ Example usage:
84+ @clear_qdisc_settings_before_and_after_decorator
85+ def my_function(interface, *args, **kwargs):
86+ # Function logic here
87+
88+ my_function("eth0") # The qdisc settings will be cleared before
89+ and after the function call
90+ """
91+
92+ def wrapper(interface, *args, **kwargs):
93+ """
94+ Wrapper function that clears the qdisc settings before and
95+ after calling the decorated function.
96+
97+ Args:
98+ interface (str): The interface to set the clock on.
99+ *args: Variable length argument list.
100+ **kwargs: Arbitrary keyword arguments.
101+
102+ This function wraps the given function with a context manager that
103+ clears the qdisc settings before and after the function call.
104+ It ensures that the qdisc settings are cleared even if an exception
105+ occurs during the function execution.
106+ """
107+ with clear_qdisc_settings_before_and_after(interface):
108+ # Call the decorated function with the given arguments
109+ # and keyword arguments
110+ func(interface, *args, **kwargs)
111+
112+ return wrapper
113+
114+
115+def ptp4l(interface: str, cfg: str, timeout: int = 0) -> subprocess.Popen:
116+ """Run ptp4l command to sync physical hardware clock between systems.
117+
118+ Args:
119+ interface (str): The interface to set the clock on.
120+ cfg (str): The path to the configuration file.
121+ timeout (int): The time to wait for the command to complete, \
122+ in seconds.
123+
124+ Returns:
125+ subprocess.Popen: A process object representing \
126+ the running ptp4l command.
127+ """
128+ # Build the ptp4l command with the provided parameters.
129+ cmd = "timeout {} ptp4l -i {} -f {} -m".format(
130+ timeout,
131+ interface,
132+ cfg,
133+ )
134+
135+ # Run the ptp4l command with the provided parameters.
136+ # The command is run with stdout and stderr redirected to pipes.
137+ # Text mode is enabled to allow access to the output as text.
138+ process = subprocess.Popen(
139+ shlex.split(cmd),
140+ stdout=subprocess.PIPE, # Redirect stdout to a pipe.
141+ stderr=subprocess.PIPE, # Redirect stderr to a pipe.
142+ text=True, # Enable text mode, so output can be accessed as text.
143+ )
144+
145+ # Return the process object representing the running ptp4l command.
146+ return process
147+
148+
149+def phc2sys(interface: str, timeout: int = 60) -> subprocess.Popen:
150+ """Run phc2sys command to sync system clock to physical hardware clock.
151+
152+ Args:
153+ interface (str): The network interface to sync.
154+ timeout (int): The time to wait for the command to complete,
155+ in seconds. Defaults to 60 seconds.
156+
157+ Returns:
158+ subprocess.Popen: A process object representing the
159+ running phc2sys command.
160+ """
161+ # Build the phc2sys command with the provided parameters.
162+ # The command uses the timeout utility to limit the execution time.
163+ # phc2sys is used to sync the system clock to the physical hardware clock.
164+ # The -s specifies the interface to sync.
165+ # The -O 0 flag sets the offset between system clock
166+ # and physical hardware clock to 0.
167+ # The -c specify the slave clock source.
168+ # The -w flag wait for ptp4l.
169+ # The -m flag print the messages.
170+ # The --step_threshold=1 flag sets the step threshold to 1.
171+ # The --transportSpecific=1 the transport specific field. [0-255]
172+ cmd = (
173+ "timeout {} phc2sys -s {} "
174+ "-O 0 -c CLOCK_REALTIME -w -m "
175+ "--step_threshold=1 --transportSpecific=1"
176+ ).format(timeout, interface)
177+
178+ # Run the phc2sys command with the provided parameters.
179+ # The command is run with stdout and stderr redirected to pipes.
180+ # Text mode is enabled to allow access to the output as text.
181+ process = subprocess.Popen(
182+ shlex.split(cmd),
183+ stdout=subprocess.PIPE, # Redirect stdout to a pipe.
184+ stderr=subprocess.PIPE, # Redirect stderr to a pipe.
185+ text=True, # Enable text mode, so output can be accessed as text.
186+ )
187+
188+ # Return the process object representing the running phc2sys command.
189+ return process
190+
191+
192+def server_mode(
193+ interfaces: List,
194+ cfg: str = "/usr/share/doc/linuxptp/configs/automotive-master.cfg",
195+) -> None:
196+ """Run ptp4l as master in every port.
197+
198+ Args:
199+ interfaces (List): List of network interfaces.
200+ cfg (str, optional): Path to the configuration file.
201+ Defaults to
202+ "/usr/share/doc/linuxptp/configs/automotive-master.cfg".
203+
204+ This function runs ptp4l as master in every port specified
205+ in the interfaces list.
206+ It terminates all running ptp4l processes on KeyboardInterrupt.
207+ """
208+
209+ # List to store the process objects
210+ processes = []
211+
212+ # Iterate over each interface and run ptp4l as master
213+ for interface in interfaces:
214+ # Clear qdisc settings for the interface
215+ clear_qdisc_settings(interface=interface)
216+
217+ # Run ptp4l as master with the provided interface and configuration
218+ process = ptp4l(interface=interface, cfg=cfg)
219+
220+ # Add the process object to the list
221+ processes.append(process)
222+
223+ # Print message about the running ptp4l process
224+ print("Start running ptp4l on {} as master".format(interface))
225+
226+ # Print message to press ctrl + c to end this
227+ print("Press ctrl + c to end this.")
228+
229+ try:
230+ # Wait for KeyboardInterrupt
231+ Event().wait()
232+ except KeyboardInterrupt:
233+ # Terminate all running ptp4l processes
234+ for process in processes:
235+ process.terminate()
236+
237+ # Print message about terminating all ptp4l processes
238+ print("Terminated all ptp4l process")
239+
240+ # Return None
241+ return
242+
243+
244+@clear_qdisc_settings_before_and_after_decorator
245+def time_sync_ptp4l(
246+ interface: str,
247+ cfg: str = "/usr/share/doc/linuxptp/configs/automotive-slave.cfg",
248+ timeout: int = 60,
249+) -> None:
250+ """
251+ Test ptp4l by running it as a subprocess and checking its output.
252+
253+ Args:
254+ interface (str): The network interface to run ptp4l on.
255+ cfg (str, optional): The path to the ptp4l configuration file.
256+ Defaults to "/usr/share/doc/linuxptp/configs/automotive-slave.cfg".
257+ timeout (int, optional): The maximum time to wait for ptp4l to run.
258+ Defaults to 60 seconds.
259+
260+ Raises:
261+ SystemExit: If ptp4l encounters an error or the master offset is not
262+ between -100 and 100.
263+
264+ Prints:
265+ Standard Output (stdout): The output of ptp4l.
266+ Standard Error (stderr): The error output of ptp4l, if any.
267+ [PASS] Masteroffset is between -100 to 100: If the master offset is
268+ between -100 and 100.
269+ [FAIL] Masteroffset is not between -100 to 100: If the master offset
270+ is not between -100 and 100.
271+ """
272+
273+ # Run ptp4l as a subprocess and get its output
274+ process = ptp4l(interface=interface, cfg=cfg, timeout=timeout)
275+ stdout, stderr = process.communicate()
276+
277+ # Print the output of ptp4l
278+ print("Standard Output (stdout):")
279+ print(stdout)
280+ print("Standard Error (stderr):")
281+ print(stderr)
282+
283+ # If ptp4l encountered an error, raise a SystemExit exception
284+ if stderr:
285+ raise SystemExit(
286+ "[Error] Catch error while running ptp4l on {}".format(interface)
287+ )
288+
289+ # Check the last 10 seconds of ptp4l output
290+ lines = stdout.splitlines()
291+ for line in lines[-10:]:
292+ offset = int(line.split()[3])
293+ if not -100 < offset < 100:
294+ raise SystemExit("[FAIL] Masteroffset is not between -100 to 100")
295+
296+ # If the master offset is between -100 and 100, print a success message
297+ print("[PASS] Masteroffset is between -100 to 100")
298+
299+
300+@clear_qdisc_settings_before_and_after_decorator
301+def time_sync_phc2sys(
302+ interface: str,
303+ cfg: str = "/usr/share/doc/linuxptp/configs/automotive-slave.cfg",
304+ timeout: int = 60,
305+) -> None:
306+ """
307+ Test phc2sys by running it as a subprocess and checking its output.
308+
309+ Args:
310+ interface (str): The network interface to run phc2sys on.
311+ cfg (str, optional): The path to the phc2sys configuration file.
312+ Defaults to "/usr/share/doc/linuxptp/configs/automotive-slave.cfg".
313+ timeout (int, optional): The maximum time to wait for phc2sys to run.
314+ Defaults to 60 seconds.
315+
316+ Raises:
317+ SystemExit: If phc2sys encounters an error or the master offset is not
318+ between -100 and 100, or the state is not equal to "s2" for the
319+ last 10 seconds, or the path delay is not equal to 0.
320+
321+ Prints:
322+ Standard Output (stdout): The output of phc2sys.
323+ Standard Error (stderr): The error output of phc2sys, if any.
324+ [PASS] Syncing system time to physical hardware clock successfully: If
325+ phc2sys syncs the system time to physical hardware clock
326+ successfully.
327+ """
328+
329+ # Run ptp4l as a subprocess and get its output
330+ ptp4l(interface=interface, cfg=cfg, timeout=timeout)
331+
332+ # Run phc2sys as a subprocess and get its output
333+ process = phc2sys(interface=interface, timeout=timeout)
334+ stdout, stderr = process.communicate()
335+
336+ # Print the output of phc2sys
337+ print("Standard Output (stdout):")
338+ print(stdout)
339+ print("Standard Error (stderr):")
340+ print(stderr)
341+
342+ # If phc2sys encountered an error, raise a SystemExit exception
343+ if stderr:
344+ print(f"[Error] Catch error while running ptp4l on {interface}")
345+ raise SystemExit(
346+ "[Error] Catch error while running ptp4l on {}".format(interface)
347+ )
348+
349+ # Check the last 10 seconds of phc2sys output
350+ lines = stdout.splitlines()
351+ for line in lines[-10:]:
352+ offset = int(line.split()[4])
353+ state = line.split()[5]
354+ delay = int(line.split()[9])
355+
356+ # If the master offset is not between -100 and 100,
357+ # raise a SystemExit exception
358+ if not -100 < offset < 100:
359+ print("[FAIL] phc offset is not between -100 to 100")
360+ raise SystemExit(1)
361+
362+ # If the state is not equal to "s2" for the last 10 seconds,
363+ # raise a SystemExit exception
364+ if state != "s2":
365+ raise SystemExit("[FAIL] state is not equal to s2 "
366+ "for the last 10 seconds\n"
367+ "s0: unsynced\n"
368+ "s1: syncing\n"
369+ "s2: synced")
370+
371+ # If the path delay is not equal to 0 for the last 10 seconds,
372+ # raise a SystemExit exception
373+ if delay != 0:
374+ raise SystemExit("[FAIL] path delay is not equal to 0\n"
375+ "path delay should be 0 if using hardware "
376+ "cross timestamping")
377+
378+ # If phc2sys syncs the system time to physical hardware clock successfully,
379+ # print a success message
380+ print("[PASS] Syncing system time to physical hardware clock successfully")
381+
382+
383+@clear_qdisc_settings_before_and_after_decorator
384+def time_based_shaper(interface: str, timeout: int = 10) -> None:
385+ """
386+ Setup a time-based shaper on the specified interface.
387+
388+ Args:
389+ interface (str): The interface to set the shaper on.
390+ timeout (int): The timeout for the shaper in seconds.
391+
392+ Raises:
393+ SystemExit: If there are more than 5% packets not within the required
394+ time interval.
395+ """
396+
397+ # Add mqprio qdisc with four traffic classes
398+ cmd = (
399+ "tc qdisc add dev {} handle 8001: parent root mqprio num_tc 4 "
400+ "map 0 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 queues 1@0 1@1 1@2 1@3 hw 0"
401+ ).format(interface)
402+ subprocess.run(cmd, shell=True, timeout=1)
403+
404+ # Replace parent qdisc with etf offload
405+ cmd = (
406+ "tc qdisc replace dev {} parent 8001:4 etf offload clockid CLOCK_TAI "
407+ "delta 500000"
408+ ).format(interface)
409+ subprocess.run(cmd, shell=True, timeout=1)
410+
411+ # Show the current qdisc settings
412+ cmd = "tc qdisc show dev {}".format(interface)
413+ subprocess.run(cmd, shell=True, timeout=1)
414+
415+ # Run udp_tai with specified parameters
416+ cmd = "udp_tai -c 3 -i {} -P 1000000 -p 90 -d 600000".format(interface)
417+ process_udp_tai = subprocess.Popen(
418+ shlex.split(cmd), stdout=subprocess.PIPE, text=True
419+ )
420+
421+ # Capture packets with tcpdump and
422+ # check that they are within the required time interval
423+ cmd = (
424+ "tcpdump -G {} -Q out -ttt -ni {} --time-stamp-precision=nano "
425+ "-j adapter_unsynced port 7788 -c {}".format(
426+ timeout, interface, timeout * 1000
427+ )
428+ )
429+ process = subprocess.Popen(
430+ shlex.split(cmd), stdout=subprocess.PIPE, text=True
431+ )
432+ try:
433+ stdout, stderr = process.communicate(timeout=timeout * 2)
434+ except subprocess.TimeoutExpired:
435+ process.kill()
436+ raise SystemExit("Reach timeout {}".format(timeout * 2))
437+ finally:
438+ process_udp_tai.kill()
439+
440+ if stdout is None or stderr is not None:
441+ raise SystemExit("No output from tcpdump!")
442+
443+ # Print the output of tcpdump
444+ print("Standard Output (stdout):")
445+ print(stdout)
446+ print("Standard Error (stderr):")
447+ print(stderr)
448+
449+ lines = stdout.splitlines()
450+ cnt = 0
451+ for line in lines:
452+ try:
453+ time = int(line.split()[0].split(".")[1])
454+ except (IndexError, ValueError):
455+ raise SystemExit(
456+ "[ERROR] Cannot find the time in the line: {}".format(line)
457+ )
458+ if not 999500 < time < 1000500:
459+ cnt += 1
460+
461+ # If there are more than 5% packets not within the required time interval,
462+ # raise a SystemExit exception
463+ if cnt > timeout * 1000 * 0.05:
464+ raise SystemExit(
465+ "[FAIL] There are {}/{} (more than 5%) packets not "
466+ "within the required time interval (999500 - 1000500)".format(
467+ cnt, timeout * 1000
468+ )
469+ )
470+
471+ print(
472+ "[PASS] There are {}/{} packets (less than 5%) within "
473+ "the required time interval (999500 - 1000500)".format(
474+ cnt, timeout * 1000
475+ )
476+ )
477+
478+
479+def main():
480+ """
481+ Main function to parse command line arguments and perform the
482+ specified testing item or server_mode.
483+ """
484+ # Create ArgumentParser object
485+ parser = argparse.ArgumentParser(
486+ prog="TSN Testing Tool",
487+ description="This is a tool to help you perform the TSN testing",
488+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
489+ )
490+
491+ # Add arguments
492+ parser.add_argument(
493+ "--run",
494+ action="store",
495+ choices=["server", "ptp4l", "phc2sys", "time_based_shaper"],
496+ help="Run a testing item or server_mode",
497+ )
498+ parser.add_argument(
499+ "--interfaces", "-i", nargs="+", help="TSN ethernet interface"
500+ )
501+ parser.add_argument(
502+ "--timeout",
503+ "-t",
504+ action="store",
505+ type=int,
506+ default=60,
507+ help="Timeout for the testing item",
508+ )
509+ parser.add_argument(
510+ "--master-config",
511+ action="store",
512+ type=str,
513+ default="/usr/share/doc/linuxptp/configs/automotive-master.cfg",
514+ help="gPTP config file for master",
515+ )
516+ parser.add_argument(
517+ "--client-config",
518+ action="store",
519+ type=str,
520+ default="/usr/share/doc/linuxptp/configs/automotive-slave.cfg",
521+ help="gPTP config file for client",
522+ )
523+
524+ # Parse command line arguments
525+ args = parser.parse_args()
526+
527+ # Perform the specified testing item or server_mode
528+ if args.run == "server":
529+ # Run server_mode
530+ server_mode(args.interfaces, cfg=args.master_config)
531+ return
532+ elif len(args.interfaces) != 1:
533+ # Exit if interfaces is not a single element
534+ raise SystemExit("We only need one interface for testing!")
535+
536+ if args.run == "ptp4l":
537+ # Time sync with ptp4l
538+ time_sync_ptp4l(
539+ args.interfaces[0],
540+ cfg=args.client_config,
541+ timeout=args.timeout,
542+ )
543+ elif args.run == "phc2sys":
544+ # Time sync with phc2sys
545+ time_sync_phc2sys(
546+ args.interfaces[0],
547+ cfg=args.client_config,
548+ timeout=args.timeout,
549+ )
550+ elif args.run == "time_based_shaper":
551+ # Time based shaper
552+ time_based_shaper(interface=args.interfaces[0], timeout=args.timeout)
553+
554+
555+if __name__ == "__main__":
556+ main()
557diff --git a/bin/tsn_time_based_shaper.sh b/bin/tsn_time_based_shaper.sh
558deleted file mode 100755
559index 6106700..0000000
560--- a/bin/tsn_time_based_shaper.sh
561+++ /dev/null
562@@ -1,49 +0,0 @@
563-#!/bin/bash
564-
565-set -e
566-
567-timeout=$1
568-eth_interface=$2
569-server_user=$3
570-server_ip=$4
571-server_pwd=$5
572-server_eth_interface=$6
573-
574-echo "## Clearing previous queue discipline configuration..."
575-echo "## You will get errors if there's no previous configuration, but you could ignore it."
576-tc qdisc del dev "$eth_interface" root || true
577-echo ""
578-
579-echo "## Setting time schedule..."
580-tc qdisc add dev "$eth_interface" handle 8001: parent root mqprio num_tc 4 map 0 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 queues 1@0 1@1 1@2 1@3 hw 0
581-tc qdisc replace dev "$eth_interface" parent 8001:4 etf offload clockid CLOCK_TAI delta 500000
582-echo ""
583-
584-echo "## Showing qdisc settings..."
585-tc qdisc show dev "$eth_interface"
586-echo ""
587-
588-echo "## Start sending and receiving udp packets..."
589-out=$(mktemp)
590-timeout "$timeout" udp_tai -c 3 -i "$eth_interface" -P 1000000 -p 90 -d 600000 > /dev/null &
591-(sshpass -p "u" ssh -o StrictHostKeyChecking=no "$server_user"@"$server_ip" "echo $server_pwd | sudo -S tcpdump -G $timeout -Q in -ttt -ni $server_eth_interface --time-stamp-precision=nano -j adapter_unsynced port 7788 -c 20000") | tee "$out"
592-
593-echo "## Checking result..."
594-lines=$(tail -n 10000 "$out")
595-count=0
596-while read -r line
597-do
598- interval=$(echo "$line" | awk '{print $1}' | awk -F "." '{print $2}')
599- if [ "$interval" -gt 1000500 ] || [ "$interval" -lt 999500 ]; then
600- count=$((count+1))
601- fi
602-done <<< "$lines"
603-
604-echo "In the last 10000 packets there are $count packets are not within 1000000+/-500 ns interval."
605-echo "Pass condition: Less than 5% packets not within the required interval"
606-if [ $count -lt 500 ]; then
607- echo "PASS"
608-else
609- echo "FAIL"
610- exit 1
611-fi
612diff --git a/units/tsn/jobs.pxu b/units/tsn/jobs.pxu
613index 92f6082..cd98d21 100644
614--- a/units/tsn/jobs.pxu
615+++ b/units/tsn/jobs.pxu
616@@ -27,31 +27,6 @@ command:
617 exit "$exit_code"
618
619 unit: job
620-id: tsn/testing-snap-install-check
621-category_id: tsn
622-_summary: TSN testing snap installation check
623-_description:
624- To check if the TSN related snap is installed
625- - linuxptp-rt
626- - ethtool-rt
627- - iproute2-rt
628-depends: tsn/tsn-detected
629-plugin: shell
630-command:
631- snap_list="linuxptp-rt ethtool-rt iproute2-rt"
632- exit_code=0
633- for snap in $snap_list; do
634- if ! snap list | grep -q $snap; then
635- echo "ERROR: snap package \"${snap}\" not found!"
636- echo "Try install it with the command below"
637- echo "sudo snap install ${snap} --edge --devmode"
638- echo ""
639- exit_code=1
640- fi
641- done
642- exit $exit_code
643-
644-unit: job
645 category_id: tsn
646 id: tsn/tsn-devices
647 plugin: resource
648@@ -145,146 +120,62 @@ unit: template
649 template-resource: tsn/tsn-devices
650 template-unit: job
651 template-engine: jinja2
652-id: tsn/ieee802.1as-2011/time-sync-between-two-system-as-client-{{ interface }}
653-category_id: tsn
654-_summary:
655- Check establish time-sync with another machine as client via {{ interface }}
656-_purpose:
657- Use {{ interface }} on the SUT to achieve time sync with the second machine as client
658-depends:
659- tsn/tsn-detected
660- tsn/testing-snap-install-check
661-plugin: shell
662-user: root
663-environ:
664- TSN_SERVER_IP
665- TSN_SERVER_USER
666- TSN_SERVER_PWD
667- TSN_SERVER_INTERFACE
668- TSN_MAX_MASTER_OFFSET
669- TSN_SYNC_TIME
670-command:
671- set -e
672- out=$(mktemp)
673- tsn_time_sync.sh ${TSN_SYNC_TIME:-60} client {{ interface }} "$TSN_SERVER_USER" "$TSN_SERVER_IP" "$TSN_SERVER_PWD" "$TSN_SERVER_INTERFACE" | tee "$out"
674- echo ""
675- lines=$(tail -n 10 "$out")
676- while read -r line
677- do
678- offset=$(echo "$line" | grep -o 'master offset\s*-\?[0-9]\+ s' | awk '{print $3}')
679- if [ "$offset" -gt "${TSN_MAX_MASTER_OFFSET:-100}" ] || [ "$offset" -lt -"${TSN_MAX_MASTER_OFFSET:-100}" ]; then
680- echo "FAIL: master offset is not within -"${TSN_MAX_MASTER_OFFSET:-100}" to "${TSN_MAX_MASTER_OFFSET:-100}" for the last 10 seconds."
681- exit 1
682- fi
683- done <<< "$lines"
684- echo "PASS: master offset is within -"${TSN_MAX_MASTER_OFFSET:-100}" to "${TSN_MAX_MASTER_OFFSET:-100}" for the last 10 seconds."
685-
686-unit: template
687-template-resource: tsn/tsn-devices
688-template-unit: job
689-template-engine: jinja2
690-id: tsn/ieee802.1as-2011/time-sync-between-two-system-as-master-{{ interface }}
691-category_id: tsn
692-_summary:
693- Check establish time-sync with another machine as master via {{ interface }}
694-_purpose:
695- Use {{ interface }} on the SUT to achieve time sync with the second machine as master
696-depends:
697- tsn/tsn-detected
698-plugin: shell
699-user: root
700-environ:
701- TSN_SERVER_IP
702- TSN_SERVER_USER
703- TSN_SERVER_PWD
704- TSN_SERVER_INTERFACE
705- TSN_MAX_MASTER_OFFSET
706- TSN_SYNC_TIME
707-command:
708- set -e
709- out=$(mktemp)
710- tsn_time_sync.sh ${TSN_SYNC_TIME:-60} master {{ interface }} "$TSN_SERVER_USER" "$TSN_SERVER_IP" "$TSN_SERVER_PWD" "$TSN_SERVER_INTERFACE" | tee "$out"
711- echo ""
712- lines=$(tail -n 10 "$out")
713- while read -r line
714- do
715- offset=$(echo "$line" | grep -o 'master offset\s*-\?[0-9]\+ s' | awk '{print $3}')
716- if [ "$offset" -gt "${TSN_MAX_MASTER_OFFSET:-100}" ] || [ "$offset" -lt -"${TSN_MAX_MASTER_OFFSET:-100}" ]; then
717- echo "FAIL: master offset is not within -"${TSN_MAX_MASTER_OFFSET:-100}" to "${TSN_MAX_MASTER_OFFSET:-100}" for the last 10 seconds."
718- exit 1
719- fi
720- done <<< "$lines"
721- echo "PASS: master offset is within -"${TSN_MAX_MASTER_OFFSET:-100}" to "${TSN_MAX_MASTER_OFFSET:-100}" for the last 10 seconds."
722-
723-unit: template
724-template-resource: tsn/tsn-devices
725-template-unit: job
726-template-engine: jinja2
727-id: tsn/ieee802.1as-2011/time-sync-system-clock-with-PHC-as-client-{{ interface }}
728+template-id: tsn/ieee802-1as-2011/ptp4l-interfaces
729+_template-summary: Time sync to another machine via ethernet interfaces
730+id: tsn/ieee802-1as-2011/ptp4l-{{ interface }}
731 category_id: tsn
732 _summary:
733- System time sync with PTP hardware clock as client
734+ Time sync to another machine as client via {{ interface }}
735 depends:
736 tsn/tsn-detected
737- tsn/ieee802.1as-2011/time-sync-between-two-system-as-client-{{ interface }}
738 plugin: shell
739 user: root
740-_purpose:
741- To check if the system can sync time between system clock and PTP hardware clock as client via {{ interface }}
742 environ:
743- TSN_SERVER_IP
744- TSN_SERVER_USER
745- TSN_SERVER_PWD
746- TSN_SERVER_INTERFACE
747- TSN_SYNC_TIME
748+ SNAP
749+ PTP4L_TESTING_TIME
750+ PTP_CLIENT_CFG
751 command:
752- tsn_phc2sys.sh ${TSN_SYNC_TIME:-60} client {{ interface }} "$TSN_SERVER_USER" "$TSN_SERVER_IP" "$TSN_SERVER_PWD" "$TSN_SERVER_INTERFACE"
753+ tsn.py --run ptp4l -i {{ interface }} -t ${PTP4L_TESTING_TIME:-60} --client-config ${PTP_CLIENT_CFG:-"$SNAP"/usr/share/doc/linuxptp/configs/automotive-slave.cfg}
754
755 unit: template
756 template-resource: tsn/tsn-devices
757 template-unit: job
758 template-engine: jinja2
759-id: tsn/ieee802.1as-2011/time-sync-system-clock-with-PHC-as-master-{{ interface }}
760+template-id: tsn/ieee802-1as-2011/phc2sys-interfaces
761+id: tsn/ieee802-1as-2011/phc2sys-{{ interface }}
762 category_id: tsn
763 _summary:
764- System time sync with PTP hardware clock as master
765+ System time sync to PTP hardware clock on {{ interface }}
766 depends:
767 tsn/tsn-detected
768- tsn/ieee802.1as-2011/time-sync-between-two-system-as-master-{{ interface }}
769+ tsn/ieee802-1as-2011/ptp4l-{{ interface }}
770 plugin: shell
771 user: root
772-_purpose:
773- To check if the system can sync time between system clock and PTP hardware clock as master via {{ interface }}
774 environ:
775- TSN_SERVER_IP
776- TSN_SERVER_USER
777- TSN_SERVER_PWD
778- TSN_SERVER_INTERFACE
779- TSN_SYNC_TIME
780+ SNAP
781+ PHC2SYS_TESTING_TIME
782+ PTP_CLIENT_CFG
783 command:
784- tsn_phc2sys.sh ${TSN_SYNC_TIME:-60} master {{ interface }} "$TSN_SERVER_USER" "$TSN_SERVER_IP" "$TSN_SERVER_PWD" "$TSN_SERVER_INTERFACE"
785+ tsn.py --run phc2sys -i {{ interface }} -t ${PHC2SYS_TESTING_TIME:-60} --client-config ${PTP_CLIENT_CFG:-"$SNAP"/usr/share/doc/linuxptp/configs/automotive-slave.cfg}
786
787 unit: template
788 template-resource: tsn/tsn-devices
789 template-unit: job
790 template-engine: jinja2
791+template-id: tsn/time-based-shaping/udp-packet-time-check-interfaces
792 id: tsn/time-based-shaping/udp-packet-time-check-{{ interface }}
793 category_id: tsn
794 _summary: UDP packet time intervals check
795 depends:
796 tsn/tsn-detected
797- tsn/testing-snap-install-check
798 plugin: shell
799 user: root
800 _purpose:
801- To check if the system can transmit udp packet precisely at 1 ms intervals
802+ To check if the system can send udp packet precisely at 1 ms intervals
803 environ:
804- TSN_SERVER_IP
805- TSN_SERVER_USER
806- TSN_SERVER_PWD
807- TSN_SERVER_INTERFACE
808+ TIME_BASED_SHAPER_TESTING_TIME
809 command:
810- tsn_time_based_shaper.sh 30 {{ interface }} "$TSN_SERVER_USER" "$TSN_SERVER_IP" "$TSN_SERVER_PWD" "$TSN_SERVER_INTERFACE"
811+ tsn.py --run time_based_shaper --interface {{ interface }} --timeout ${TIME_BASED_SHAPER_TESTING_TIME:-10}
812
813 unit: template
814 template-resource: tsn/tsn-devices
815diff --git a/units/tsn/test-plan.pxu b/units/tsn/test-plan.pxu
816index c5cc31d..97e132c 100644
817--- a/units/tsn/test-plan.pxu
818+++ b/units/tsn/test-plan.pxu
819@@ -29,13 +29,13 @@ include:
820 tsn/test-env-setup-for-.*
821 tsn/testing-snap-install-check
822 nested_part:
823- tsn-ieee802.1as-2011
824+ tsn/ieee802-1as-2011
825 tsn-ieee802.1qav
826 tsn-ieee802.1qbu
827 tsn-time-based-shaping
828 tsn-ieee802.1qbv
829
830-id: tsn-ieee802.1as-2011
831+id: tsn/ieee802-1as-2011
832 _name: Time Sensitive Networking Test Plan for IEEE 802.1AS-2011
833 _description:
834 This testplan is to check if it could follow IEEE 802.1AS-2011.
835@@ -46,11 +46,8 @@ unit: test plan
836 bootstrap_include:
837 tsn/tsn-devices
838 include:
839- tsn/testing-snap-install-check
840- tsn/ieee802.1as-2011/time-sync-between-two-system-as-client-.*
841- tsn/ieee802.1as-2011/time-sync-between-two-system-as-master-.*
842- tsn/ieee802.1as-2011/time-sync-system-clock-with-PHC-as-client-.*
843- tsn/ieee802.1as-2011/time-sync-system-clock-with-PHC-as-master-.*
844+ tsn/ieee802-1as-2011/ptp4l-interfaces
845+ tsn/ieee802-1as-2011/phc2sys-interfaces
846
847 id: tsn-time-based-shaping
848 _name: Time Sensitive Networking Test Plan for Time-Based Shaping
849@@ -63,7 +60,7 @@ bootstrap_include:
850 tsn/tsn-devices
851 include:
852 tsn/testing-snap-install-check
853- tsn/time-based-shaping/udp-packet-time-check-.*
854+ tsn/time-based-shaping/udp-packet-time-check-interfaces
855
856 id: tsn-ieee802.1qav
857 _name: Time Sensitive Networking Test Plan for IEEE 802.1Qav

Subscribers

People subscribed via source and target branches