xref: /dpdk/doc/guides/conf.py (revision 1f6f952644c44b6c684be20cd16582c395aa93df)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-3-Clause
3# Copyright(c) 2010-2015 Intel Corporation
4
5from docutils import nodes
6from packaging.version import Version
7from sphinx import __version__ as sphinx_version
8from os import listdir
9from os import environ
10from os.path import basename
11from os.path import dirname
12from os.path import join as path_join
13from sys import argv, stderr
14
15import configparser
16
17try:
18    import sphinx_rtd_theme
19
20    html_theme = "sphinx_rtd_theme"
21except:
22    print('Install the sphinx ReadTheDocs theme for improved html documentation '
23          'layout: https://sphinx-rtd-theme.readthedocs.io/',
24          file=stderr)
25    pass
26
27stop_on_error = ('-W' in argv)
28
29project = 'Data Plane Development Kit'
30html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
31if Version(sphinx_version) >= Version('3.5'):
32    html_permalinks = False
33else:
34    html_add_permalinks = ""
35html_show_copyright = False
36highlight_language = 'none'
37
38release = environ.setdefault('DPDK_VERSION', "None")
39version = release
40
41master_doc = 'index'
42
43# Maximum feature description string length
44feature_str_len = 30
45
46# Figures, tables and code-blocks automatically numbered if they have caption
47numfig = True
48
49# Configuration for man pages
50man_pages = [("testpmd_app_ug/run_app", "testpmd",
51              "tests for dpdk pmds", "", 1),
52             ("tools/pdump", "dpdk-pdump",
53              "enable packet capture on dpdk ports", "", 1),
54             ("tools/proc_info", "dpdk-procinfo",
55              "access dpdk port stats and memory info", "", 1),
56             ("tools/pmdinfo", "dpdk-pmdinfo",
57              "dump a PMDs hardware support info", "", 1),
58             ("tools/devbind", "dpdk-devbind",
59              "check device status and bind/unbind them from drivers", "", 8)]
60
61
62# ####### :numref: fallback ########
63# The following hook functions add some simple handling for the :numref:
64# directive for Sphinx versions prior to 1.3.1. The functions replace the
65# :numref: reference with a link to the target (for all Sphinx doc types).
66# It doesn't try to label figures/tables.
67def numref_role(reftype, rawtext, text, lineno, inliner):
68    """
69    Add a Sphinx role to handle numref references. Note, we can't convert
70    the link here because the doctree isn't build and the target information
71    isn't available.
72    """
73    # Add an identifier to distinguish numref from other references.
74    newnode = nodes.reference('',
75                              '',
76                              refuri='_local_numref_#%s' % text,
77                              internal=True)
78    return [newnode], []
79
80
81def process_numref(app, doctree, from_docname):
82    """
83    Process the numref nodes once the doctree has been built and prior to
84    writing the files. The processing involves replacing the numref with a
85    link plus text to indicate if it is a Figure or Table link.
86    """
87
88    # Iterate over the reference nodes in the doctree.
89    for node in doctree.traverse(nodes.reference):
90        target = node.get('refuri', '')
91
92        # Look for numref nodes.
93        if target.startswith('_local_numref_#'):
94            target = target.replace('_local_numref_#', '')
95
96            # Get the target label and link information from the Sphinx env.
97            data = app.builder.env.domains['std'].data
98            docname, label, _ = data['labels'].get(target, ('', '', ''))
99            relative_url = app.builder.get_relative_uri(from_docname, docname)
100
101            # Add a text label to the link.
102            if target.startswith('figure'):
103                caption = 'Figure'
104            elif target.startswith('table'):
105                caption = 'Table'
106            else:
107                caption = 'Link'
108
109            # New reference node with the updated link information.
110            newnode = nodes.reference('',
111                                      caption,
112                                      refuri='%s#%s' % (relative_url, label),
113                                      internal=True)
114            node.replace_self(newnode)
115
116
117def generate_overview_table(output_filename, table_id, section, table_name, title):
118    """
119    Function to generate the Overview Table from the ini files that define
120    the features for each driver.
121
122    The default features for the table and their order is defined by the
123    'default.ini' file.
124
125    """
126    # Default warning string.
127    warning = 'Warning generate_overview_table()'
128
129    # Get the default features and order from the 'default.ini' file.
130    ini_path = path_join(dirname(output_filename), 'features')
131    config = configparser.ConfigParser()
132    config.optionxform = str
133    config.read(path_join(ini_path, 'default.ini'))
134    default_features = config.items(section)
135
136    # Create a dict of the valid features to validate the other ini files.
137    valid_features = {}
138    max_feature_length = 0
139    for feature in default_features:
140        key = feature[0]
141        valid_features[key] = ' '
142        max_feature_length = max(max_feature_length, len(key))
143
144    # Get a list of driver ini files, excluding 'default.ini'.
145    ini_files = [basename(file) for file in listdir(ini_path)
146                 if file.endswith('.ini') and file != 'default.ini']
147    ini_files.sort()
148
149    # Build up a list of the table header names from the ini filenames.
150    pmd_names = []
151    for ini_filename in ini_files:
152        name = ini_filename[:-4]
153        name = name.replace('_vf', 'vf')
154        pmd_names.append(name)
155    if not pmd_names:
156        # Add an empty column if table is empty (required by RST syntax)
157        pmd_names.append(' ')
158
159    # Pad the table header names.
160    max_header_len = len(max(pmd_names, key=len))
161    header_names = []
162    for name in pmd_names:
163        if '_vec' in name:
164            pmd, vec = name.split('_')
165            name = '{0:{fill}{align}{width}}vec'.format(pmd,
166                    fill='.', align='<', width=max_header_len-3)
167        else:
168            name = '{0:{fill}{align}{width}}'.format(name,
169                    fill=' ', align='<', width=max_header_len)
170        header_names.append(name)
171
172    # Create a dict of the defined features for each driver from the ini files.
173    ini_data = {}
174    for ini_filename in ini_files:
175        config = configparser.ConfigParser()
176        config.optionxform = str
177        config.read(path_join(ini_path, ini_filename))
178
179        # Initialize the dict with the default.ini value.
180        ini_data[ini_filename] = valid_features.copy()
181
182        # Check for a section.
183        if not config.has_section(section):
184            continue
185
186        # Check for valid features names.
187        for name, value in config.items(section):
188            if name not in valid_features:
189                print("{}: Unknown feature '{}' in '{}'".format(warning,
190                                                                name,
191                                                                ini_filename),
192                                                                file=stderr)
193                if stop_on_error:
194                    raise Exception('Warning is treated as a failure')
195                continue
196
197            if value:
198                # Get the first letter only.
199                ini_data[ini_filename][name] = value[0]
200
201    # Print out the RST Driver Overview table from the ini file data.
202    outfile = open(output_filename, 'w')
203    num_cols = len(header_names)
204
205    print_table_css(outfile, table_id)
206    print('.. _' + table_name + ':', file=outfile)
207    print('.. table:: ' + table_name + '\n', file=outfile)
208    print_table_header(outfile, num_cols, header_names, title)
209    print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
210
211
212def print_table_header(outfile, num_cols, header_names, title):
213    """ Print the RST table header. The header names are vertical. """
214    print_table_divider(outfile, num_cols)
215
216    line = ''
217    for name in header_names:
218        line += ' ' + name[0]
219
220    print_table_row(outfile, title, line)
221
222    for i in range(1, len(header_names[0])):
223        line = ''
224        for name in header_names:
225            line += ' ' + name[i]
226
227        print_table_row(outfile, '', line)
228
229    print_table_divider(outfile, num_cols)
230
231
232def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
233    """ Print out the body of the table. Each row is a NIC feature. """
234
235    for feature, _ in default_features:
236        line = ''
237
238        for ini_filename in ini_files:
239            line += ' ' + ini_data[ini_filename][feature]
240
241        print_table_row(outfile, feature, line)
242
243    print_table_divider(outfile, num_cols)
244
245
246def print_table_row(outfile, feature, line):
247    """ Print a single row of the table with fixed formatting. """
248    line = line.rstrip()
249    print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
250
251
252def print_table_divider(outfile, num_cols):
253    """ Print the table divider line. """
254    line = ' '
255    column_dividers = ['='] * num_cols
256    line += ' '.join(column_dividers)
257
258    feature = '=' * feature_str_len
259
260    print_table_row(outfile, feature, line)
261
262
263def print_table_css(outfile, table_id):
264    template = """
265.. raw:: html
266
267   <style>
268      .wy-nav-content {
269         opacity: .99;
270      }
271      table#idx {
272         cursor: default;
273         overflow: hidden;
274      }
275      table#idx p {
276         margin: 0;
277         line-height: inherit;
278      }
279      table#idx th, table#idx td {
280         text-align: center;
281         border: solid 1px #ddd;
282      }
283      table#idx th {
284         padding: 0.5em 0;
285      }
286      table#idx th, table#idx th p {
287         font-size: 11px;
288         white-space: pre-wrap;
289         vertical-align: top;
290         min-width: 0.9em;
291      }
292      table#idx col:first-child {
293         width: 0;
294      }
295      table#idx th:first-child {
296         vertical-align: bottom;
297      }
298      table#idx td {
299         padding: 1px;
300      }
301      table#idx td, table#idx td p {
302         font-size: 11px;
303      }
304      table#idx td:first-child {
305         padding-left: 1em;
306         text-align: left;
307      }
308      table#idx tr:nth-child(2n-1) td {
309         background-color: rgba(210, 210, 210, 0.2);
310      }
311      table#idx th:not(:first-child):hover,
312      table#idx td:not(:first-child):hover {
313         position: relative;
314      }
315      table#idx th:not(:first-child):hover::after,
316      table#idx td:not(:first-child):hover::after {
317         content: '';
318         height: 6000px;
319         top: -3000px;
320         width: 100%;
321         left: 0;
322         position: absolute;
323         z-index: -1;
324         background-color: #ffb;
325      }
326      table#idx tr:hover td {
327         background-color: #ffb;
328      }
329   </style>
330"""
331    print(template.replace("idx", "id%d" % (table_id)), file=outfile)
332
333
334def setup(app):
335    table_file = dirname(__file__) + '/nics/overview_table.txt'
336    generate_overview_table(table_file, 1,
337                            'Features',
338                            'Features availability in networking drivers',
339                            'Feature')
340    table_file = dirname(__file__) + '/nics/rte_flow_items_table.txt'
341    generate_overview_table(table_file, 2,
342                            'rte_flow items',
343                            'rte_flow items availability in networking drivers',
344                            'Item')
345    table_file = dirname(__file__) + '/nics/rte_flow_actions_table.txt'
346    generate_overview_table(table_file, 3,
347                            'rte_flow actions',
348                            'rte_flow actions availability in networking drivers',
349                            'Action')
350    table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
351    generate_overview_table(table_file, 1,
352                            'Features',
353                            'Features availability in crypto drivers',
354                            'Feature')
355    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
356    generate_overview_table(table_file, 2,
357                            'Cipher',
358                            'Cipher algorithms in crypto drivers',
359                            'Cipher algorithm')
360    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
361    generate_overview_table(table_file, 3,
362                            'Auth',
363                            'Authentication algorithms in crypto drivers',
364                            'Authentication algorithm')
365    table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
366    generate_overview_table(table_file, 4,
367                            'AEAD',
368                            'AEAD algorithms in crypto drivers',
369                            'AEAD algorithm')
370    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
371    generate_overview_table(table_file, 5,
372                            'Asymmetric',
373                            'Asymmetric algorithms in crypto drivers',
374                            'Asymmetric algorithm')
375    table_file = dirname(__file__) + '/cryptodevs/overview_os_table.txt'
376    generate_overview_table(table_file, 6,
377                            'OS',
378                            'Operating systems support for crypto drivers',
379                            'Operating system')
380    table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
381    generate_overview_table(table_file, 1,
382                            'Features',
383                            'Features availability in compression drivers',
384                            'Feature')
385    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
386    generate_overview_table(table_file, 1,
387                            'Features',
388                            'Features availability in regex drivers',
389                            'Feature')
390    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
391    generate_overview_table(table_file, 1,
392                            'Features',
393                            'Features availability in vDPA drivers',
394                            'Feature')
395    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
396    generate_overview_table(table_file, 1,
397                            'Features',
398                            'Features availability in bbdev drivers',
399                            'Feature')
400    table_file = dirname(__file__) + '/gpus/overview_feature_table.txt'
401    generate_overview_table(table_file, 1,
402                            'Features',
403                            'Features availability in GPU drivers',
404                            'Feature')
405    table_file = dirname(__file__) + '/eventdevs/overview_feature_table.txt'
406    generate_overview_table(table_file, 1,
407                            'Scheduling Features',
408                            'Features availability in eventdev drivers',
409                            'Feature')
410    table_file = dirname(__file__) + '/eventdevs/overview_rx_adptr_feature_table.txt'
411    generate_overview_table(table_file, 2,
412                            'Eth Rx adapter Features',
413                            'Features availability for Ethdev Rx adapters',
414                            'Feature')
415    table_file = dirname(__file__) + '/eventdevs/overview_tx_adptr_feature_table.txt'
416    generate_overview_table(table_file, 3,
417                            'Eth Tx adapter Features',
418                            'Features availability for Ethdev Tx adapters',
419                            'Feature')
420    table_file = dirname(__file__) + '/eventdevs/overview_crypto_adptr_feature_table.txt'
421    generate_overview_table(table_file, 4,
422                            'Crypto adapter Features',
423                            'Features availability for Crypto adapters',
424                            'Feature')
425    table_file = dirname(__file__) + '/eventdevs/overview_timer_adptr_feature_table.txt'
426    generate_overview_table(table_file, 5,
427                            'Timer adapter Features',
428                            'Features availability for Timer adapters',
429                            'Feature')
430
431    if Version(sphinx_version) < Version('1.3.1'):
432        print('Upgrade sphinx to version >= 1.3.1 for '
433              'improved Figure/Table number handling.',
434              file=stderr)
435        # Add a role to handle :numref: references.
436        app.add_role('numref', numref_role)
437        # Process the numref references once the doctree has been created.
438        app.connect('doctree-resolved', process_numref)
439
440    try:
441        # New function in sphinx 1.8
442        app.add_css_file('css/custom.css')
443    except:
444        app.add_stylesheet('css/custom.css')
445