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)