All Classes Namespaces Files Functions Pages
flowlatency.tcl
Go to the documentation of this file.
1 ##
2 # @brief Basic namespace for all Excentis Tcl extensions
3 #
4 namespace eval excentis {
5 
6 ##
7 # @brief This namespace holds all ByteBlower-related Tcl extensions, including the ByteBlower higher-layer Tcl API.
8 #
9 # These procedures are developed for higher-level usage of the ByteBlower API.
10 # They are mainly used to simplify running specific Test Scenarios similar to
11 # scenarios you know from the ByteBlower GUI.
12 #
13 namespace eval ByteBlower {
14 
15 ## \file
16 #
17 # @brief Wrapper module for latency measurement scenarios that forces the required TX and RX components to be present and returns only latency values.
18 #
19 # @copyright Excentis nv - www.excentis.com
20 #
21 
22 
23 ##
24 # @brief Executes a latency calculating scenario based on a declarative scenario configuration and returns the calculated latency values.
25 #
26 # This method assumes the scenario configuration has certain properties and returns clear error messages when a scenario configuration is malformed.
27 # The scenario configuration requirements are:
28 # @ulist
29 # @ulitem{A flow should either be used for latency or for background traffic.}
30 # @ulitem{A background flow may only have one or more TX parts\, but no RX parts.}
31 # @ulitem{A latency flow may only have a single TX part\, which must have the 'latency' option enabled.}
32 # @ulitem{A latency flow may have zero\, one or more RX parts. They must all have a basic latency detector configured.}
33 # @endulist
34 #
35 # @param scenarioConfig
36 # The scenario configuration as expected by the @apiref{excentis::ByteBlower::ExecuteScenario,ExecuteScenario} function.
37 # See the @ref TclApiHLOverview "higher-layer API overview" for more information.
38 #
39 # @param args
40 # Scenario-level option list in the form of a list of key-value pairs:
41 # @dlist
42 # @dlitem{-return, Defines the output mode. Following output modes are supported:
43 # @dlist
44 # @dlitem{numbers, Number of transmitted\, received frames and latency values per flow in the scenario.}
45 # @enddlist
46 # @defaultvalue{numbers}
47 # }
48 # @enddlist
49 #
50 # @return
51 # The latency values per are returned based on the value of the
52 # @command{return} option.
53 # @dlist
54 # @dlitem{numbers,Simplified nested list structure with latency values:
55 # @ulist
56 # @ulitem{Scenario structure (flows) and flow structures (TX and RX) are maintained.}
57 # @ulitem{The TX return value is one element\, the number of transmitted frames.}
58 # @ulitem{The RX return value is a list of 5 values: the amount of received frames\,
59 # the minimum\, average and maximum latency and the jitter.}
60 # @ulitem{All the latency values are presented in nanoseconds.}
61 # @endulist
62 # }
63 # @enddlist
64 #
65 proc FlowLatency { scenarioConfig args } {
66  # Default args
67  set outputmode "numbers"
68 
69  # Parsing args
70  foreach { option value } $args {
71  set option [ string tolower $option ]
72  switch -- $option {
73  -return {
74  set outputmode $value
75  }
76  default {
77  error "ByteBlowerHL FlowLatency error: Invalid argument '$option'"
78  }
79  }
80  }
81 
83  set scenarioResult [ ExecuteScenario $scenarioConfig ]
84 
85  if {$outputmode == "numbers"} {
86  return [ x.FlowLatency.Result.Parse.Numbers $scenarioResult ]
87  }
88 }
89 
90 proc x.FlowLatency.ScenarioConfig.Validate { scenarioConfig } {
91 #
92 # This parses and validates the scenario configuration (or flow list) for a
93 # latency scenario. This is needed because a flow latency scenario imposes
94 # stricter rules on the flow configuration than a generic scenario used by
95 # 'ExecuteScenario'.
96 #
97 # If the stricter configuration is not met, an error is thrown.
98 #
99 # @param scenarioConfig
100 # The scenario configuration passed by the user.
101 # @error
102 # Error is thrown if validation of scenario configuration fails
103 #
104 
105  foreach flowConfig $scenarioConfig {
106  set txCount 0
107  set rxCount 0
108  set latencyTxCount 0
109 
110  # Count TX and RX parts
111  foreach {item value} $flowConfig {
112  switch -- $item {
113  -tx {
114  incr txCount
115  set txParamList $value
116  set index [ lsearch $txParamList "-latency" ]
117  if { $index != -1 && [ lindex $txParamList [ expr $index + 1 ] ] == 1 } {
118  incr latencyTxCount
119  }
120  }
121  -rx {
122  incr rxCount
123  # Rx part is validated later
124  }
125  default { error "ByteBlowerHL FlowLatency error: Invalid flow parameter '$item'\n flow configuration: '$flowConfig'" }
126  }
127  }; # end validate flow configuration
128 
129  # TX and RX count validation
130  if { $txCount == 0} {
131  error "ByteBlowerHL FlowLatency error: flow must have at least one TX part\n flow configuration: '$flowConfig'"
132  }
133  if { $txCount > 1 && $latencyTxCount > 0} {
134  error "ByteBlowerHL FlowLatency error: flow with a latency-enabled TX part may have no other TX parts\n flow configuration: '$flowConfig'"
135  }
136  if { $latencyTxCount == 0 && $rxCount > 0} {
137  error "ByteBlowerHL FlowLatency error: flow without a latency-enabled TX part may not contain RX parts\n flow configuration: '$flowConfig'"
138  }
139  if { $latencyTxCount == 1 && $rxCount == 0} {
140  error "ByteBlowerHL FlowLatency error: flow with a latency-enabled TX part must have at least one latency-enabled RX part\n flow configuration: '$flowConfig'"
141  }
142 
143  # Validate RX parts
144  foreach {item value} $flowConfig {
145  switch -- $item {
146  -rx {
147  set rxParamList $value
148  set basicLatencyCount 0
149  foreach {option value} $rxParamList {
150  switch -- $option {
151  -latency {
152  incr basicLatencyCount
153  foreach {latOption latValue} $value {
154  # if type option is present, it must be 'basic' (basic is also default value)
155  switch -- $latOption {
156  -type {
157  if { ! [ string equal $latValue "" ] && ! [ string equal $latValue basic ] } {
158  error "ByteBlowerHL FlowLatency error: flow RX part may not contain '$latValue' type latency detector\n flow configuration: '$flowConfig'"
159  }
160  }
161  }
162  }
163  }
164  -trigger {
165  error "ByteBlowerHL FlowLatency error: latency flow RX part may not contain trigger\n flow configuration: '$flowConfig'"
166  }
167  -capture {
168  error "ByteBlowerHL FlowLatency error: latency flow RX part may not contain capture tool\n flow configuration: '$flowConfig'"
169  }
170  -outofsequence {
171  error "ByteBlowerHL FlowLatency error: latency flow RX part may not contain out of sequence detector\n flow configuration: '$flowConfig'"
172  }
173  default {
174  # ignore other parameters, not our task to validate them
175  }
176  }
177  }
178  if { $basicLatencyCount == 0 } {
179  error "ByteBlowerHL FlowLatency error: latency flow RX part must contain a latency detector\n flow configuration: '$flowConfig'"
180  }
181  if { $basicLatencyCount > 1 } {
182  error "ByteBlowerHL FlowLatency error: latency flow RX part must contain exactly one latency detector\n flow configuration: '$flowConfig'"
183  }
184  }
185  }
186  }; # end validate flow config
187  }; # end validate scenario config
188 }
189 
190 proc x.FlowLatency.Result.Parse.Numbers { scenarioResult } {
191 #
192 # Parse the scenario result for the numbers option. Because of our setup the
193 # scenario result has a specific format.
194 # * The scenario structure is maintained.
195 # * TX parts within a flow are 'Tx.Stream.Counter.Brief.Get' values
196 # * RX parts within a flow are 'Rx.Latency.Basic.Counters.Get' values
197 #
198 # @param scenarioResult
199 # The normal scenario result returned by ExecuteScenario.
200 # @return
201 # Return information in the format as specified by the 'numbers'
202 # option in @ref FlowLatency.
203 #
204  set scenarioNumbersResult [ list ]
205  foreach flowResult $scenarioResult {
206  set flowNumbersResult [ list ]
207  foreach {item value} $flowResult {
208  switch -- $item {
209  -tx {
210  set txCounters $value
211  # Format: 'NrOfFramesSent <value> <FrameOid_1> <value_1> <FrameOid_2> ...'
212  # Required format: '<value>'
213  set txNumbersResult [ lindex $txCounters 1 ]
214  lappend flowNumbersResult "-tx" $txNumbersResult
215  }
216  -rx {
217  if {$value != "NA"} {
218  set rxCounters $value
219  # Format: 'NrOfFrames <value> MinLatency <value> AvgLatency <value>
220  # MaxLatency <value> Jitter <value>'
221  # Required format: '<value> <value> <value> <value> <value>' (same order)
222  set rxNumbersResult [ list [lindex $rxCounters 1] [lindex $rxCounters 3] [lindex $rxCounters 5] [lindex $rxCounters 7] [lindex $rxCounters 9] ]
223  lappend flowNumbersResult "-rx" $rxNumbersResult
224  } else {
225  lappend flowNumbersResult "-rx" $value
226  }
227  }
228  }
229  }
230  lappend scenarioNumbersResult $flowNumbersResult
231  }
232  return $scenarioNumbersResult
233 }
234 
235 }
236 
237 }