]>
git.proxmox.com Git - ceph.git/blob - ceph/src/dpdk/examples/ip_pipeline/config/diagram-generator.py
5 # Copyright(c) 2016 Intel Corporation. All rights reserved.
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
12 # * Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # * Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in
16 # the documentation and/or other materials provided with the
18 # * Neither the name of Intel Corporation nor the names of its
19 # contributors may be used to endorse or promote products derived
20 # from this software without specific prior written permission.
22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 # This script creates a visual representation for a configuration file used by
36 # the DPDK ip_pipeline application.
38 # The input configuration file is translated to an output file in DOT syntax,
39 # which is then used to create the image file using graphviz (www.graphviz.org).
42 from __future__
import print_function
48 # Command to generate the image file
50 DOT_COMMAND
= 'dot -Gsize=20,30 -Tpng %s > %s'
53 # Layout of generated DOT file
56 '#\n# Command to generate image file:\n# \t%s\n#\n\n'
58 'digraph g {\n graph [ splines = true rankdir = "LR" ]\n'
60 ' "%s RX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
62 ' "%s TX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
64 ' "%s RX" [ shape = box style = filled fillcolor = orange ]\n'
66 ' "%s TX" [ shape = box style = filled fillcolor = orange ]\n'
68 ' "%s RX" [ shape = box style = filled fillcolor = gold ]\n'
70 ' "%s TX" [ shape = box style = filled fillcolor = gold ]\n'
72 ' "%s" [ shape = box style = filled fillcolor = darkgreen ]\n'
74 ' "%s" [ shape = box style = filled fillcolor = peachpuff ]\n'
76 ' "%s" [ shape = box style = filled fillcolor = royalblue ]\n'
78 ' "%s" -> "%s" [ label = "%s" color = gray ]\n'
82 # Relationships between the graph nodes and the graph edges:
84 # Edge ID | Edge Label | Writer Node | Reader Node | Dependencies
85 # --------+------------+-------------+---------------+--------------
86 # RXQx.y | RXQx.y | LINKx | PIPELINEz | LINKx
87 # TXQx.y | TXQx.y | PIPELINEz | LINKx | LINKx
88 # SWQx | SWQx | PIPELINEy | PIPELINEz | -
89 # TMx | TMx | PIPELINEy | PIPELINEz | LINKx
90 # KNIx RX | KNIx | KNIx RX | PIPELINEy | KNIx, LINKx
91 # KNIx TX | KNIx | PIPELINEy | KNIx TX | KNIx, LINKx
92 # TAPx RX | TAPx | TAPx RX | PIPELINEy | TAPx
93 # TAPx TX | TAPx | PIPELINEy | TAPx TX | TAPx
94 # SOURCEx | SOURCEx | SOURCEx | PIPELINEy | SOURCEx
95 # SINKx | SINKx | PIPELINEy | SINKx | SINKx
98 # Parse the input configuration file to detect the graph nodes and edges
100 def process_config_file(cfgfile
):
110 dotfile
= cfgfile
+ '.txt'
111 imgfile
= cfgfile
+ '.png'
114 # Read configuration file
116 lines
= open(cfgfile
, 'r')
118 # Remove any leading and trailing white space characters
121 # Remove any comment at end of line
122 line
, sep
, tail
= line
.partition(';')
124 # Look for next "PIPELINE" section
125 match
= re
.search(r
'\[(PIPELINE\d+)\]', line
)
127 pipeline
= match
.group(1)
130 # Look for next "pktq_in" section entry
131 match
= re
.search(r
'pktq_in\s*=\s*(.+)', line
)
133 pipelines
.add(pipeline
)
134 for q
in re
.findall('\S+', match
.group(1)):
135 match_rxq
= re
.search(r
'^RXQ(\d+)\.\d+$', q
)
136 match_swq
= re
.search(r
'^SWQ\d+$', q
)
137 match_tm
= re
.search(r
'^TM(\d+)$', q
)
138 match_kni
= re
.search(r
'^KNI(\d+)$', q
)
139 match_tap
= re
.search(r
'^TAP\d+$', q
)
140 match_source
= re
.search(r
'^SOURCE\d+$', q
)
142 # Set ID for the current packet queue (graph edge)
144 if match_rxq
or match_swq
or match_tm
or match_source
:
146 elif match_kni
or match_tap
:
149 print('Error: Unrecognized pktq_in element "%s"' % q
)
152 # Add current packet queue to the set of graph edges
153 if q_id
not in edges
:
155 if 'label' not in edges
[q_id
]:
156 edges
[q_id
]['label'] = q
157 if 'readers' not in edges
[q_id
]:
158 edges
[q_id
]['readers'] = []
159 if 'writers' not in edges
[q_id
]:
160 edges
[q_id
]['writers'] = []
162 # Add reader for the new edge
163 edges
[q_id
]['readers'].append(pipeline
)
167 link
= 'LINK' + str(match_rxq
.group(1))
168 edges
[q_id
]['writers'].append(link
+ ' RX')
178 link
= 'LINK' + str(match_tm
.group(1))
184 link
= 'LINK' + str(match_kni
.group(1))
185 edges
[q_id
]['writers'].append(q_id
)
192 edges
[q_id
]['writers'].append(q_id
)
198 edges
[q_id
]['writers'].append(q
)
204 # Look for next "pktq_out" section entry
205 match
= re
.search(r
'pktq_out\s*=\s*(.+)', line
)
207 for q
in re
.findall('\S+', match
.group(1)):
208 match_txq
= re
.search(r
'^TXQ(\d+)\.\d+$', q
)
209 match_swq
= re
.search(r
'^SWQ\d+$', q
)
210 match_tm
= re
.search(r
'^TM(\d+)$', q
)
211 match_kni
= re
.search(r
'^KNI(\d+)$', q
)
212 match_tap
= re
.search(r
'^TAP(\d+)$', q
)
213 match_sink
= re
.search(r
'^SINK(\d+)$', q
)
215 # Set ID for the current packet queue (graph edge)
217 if match_txq
or match_swq
or match_tm
or match_sink
:
219 elif match_kni
or match_tap
:
222 print('Error: Unrecognized pktq_out element "%s"' % q
)
225 # Add current packet queue to the set of graph edges
226 if q_id
not in edges
:
228 if 'label' not in edges
[q_id
]:
229 edges
[q_id
]['label'] = q
230 if 'readers' not in edges
[q_id
]:
231 edges
[q_id
]['readers'] = []
232 if 'writers' not in edges
[q_id
]:
233 edges
[q_id
]['writers'] = []
235 # Add writer for the new edge
236 edges
[q_id
]['writers'].append(pipeline
)
240 link
= 'LINK' + str(match_txq
.group(1))
241 edges
[q_id
]['readers'].append(link
+ ' TX')
251 link
= 'LINK' + str(match_tm
.group(1))
257 link
= 'LINK' + str(match_kni
.group(1))
258 edges
[q_id
]['readers'].append(q_id
)
265 edges
[q_id
]['readers'].append(q_id
)
271 edges
[q_id
]['readers'].append(q
)
280 print('Creating DOT file "%s" ...' % dotfile
)
281 dot_cmd
= DOT_COMMAND
% (dotfile
, imgfile
)
282 file = open(dotfile
, 'w')
283 file.write(DOT_INTRO
% dot_cmd
)
284 file.write(DOT_GRAPH_BEGIN
)
286 # Write the graph nodes to the DOT file
287 for l
in sorted(links
):
288 file.write(DOT_NODE_LINK_RX
% l
)
289 file.write(DOT_NODE_LINK_TX
% l
)
290 for k
in sorted(knis
):
291 file.write(DOT_NODE_KNI_RX
% k
)
292 file.write(DOT_NODE_KNI_TX
% k
)
293 for t
in sorted(taps
):
294 file.write(DOT_NODE_TAP_RX
% t
)
295 file.write(DOT_NODE_TAP_TX
% t
)
296 for s
in sorted(sources
):
297 file.write(DOT_NODE_SOURCE
% s
)
298 for s
in sorted(sinks
):
299 file.write(DOT_NODE_SINK
% s
)
300 for p
in sorted(pipelines
):
301 file.write(DOT_NODE_PIPELINE
% p
)
303 # Write the graph edges to the DOT file
304 for q
in sorted(edges
.keys()):
306 if 'writers' not in rw
:
307 print('Error: "%s" has no writer' % q
)
309 if 'readers' not in rw
:
310 print('Error: "%s" has no reader' % q
)
312 for w
in rw
['writers']:
313 for r
in rw
['readers']:
314 file.write(DOT_EDGE_PKTQ
% (w
, r
, rw
['label']))
316 file.write(DOT_GRAPH_END
)
320 # Execute the DOT command to create the image file
322 print('Creating image file "%s" ...' % imgfile
)
323 if os
.system('which dot > /dev/null'):
324 print('Error: Unable to locate "dot" executable.' \
325 'Please install the "graphviz" package (www.graphviz.org).')
331 if __name__
== '__main__':
332 parser
= argparse
.ArgumentParser(description
=\
333 'Create diagram for IP pipeline configuration file.')
338 help='input configuration file (e.g. "ip_pipeline.cfg")',
341 args
= parser
.parse_args()
343 process_config_file(args
.file)