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:: ' + table_name + '\n', file=outfile) 207 print_table_header(outfile, num_cols, header_names, title) 208 print_table_body(outfile, num_cols, ini_files, ini_data, default_features) 209 210 211def print_table_header(outfile, num_cols, header_names, title): 212 """ Print the RST table header. The header names are vertical. """ 213 print_table_divider(outfile, num_cols) 214 215 line = '' 216 for name in header_names: 217 line += ' ' + name[0] 218 219 print_table_row(outfile, title, line) 220 221 for i in range(1, len(header_names[0])): 222 line = '' 223 for name in header_names: 224 line += ' ' + name[i] 225 226 print_table_row(outfile, '', line) 227 228 print_table_divider(outfile, num_cols) 229 230 231def print_table_body(outfile, num_cols, ini_files, ini_data, default_features): 232 """ Print out the body of the table. Each row is a NIC feature. """ 233 234 for feature, _ in default_features: 235 line = '' 236 237 for ini_filename in ini_files: 238 line += ' ' + ini_data[ini_filename][feature] 239 240 print_table_row(outfile, feature, line) 241 242 print_table_divider(outfile, num_cols) 243 244 245def print_table_row(outfile, feature, line): 246 """ Print a single row of the table with fixed formatting. """ 247 line = line.rstrip() 248 print(' {:<{}}{}'.format(feature, feature_str_len, line), file=outfile) 249 250 251def print_table_divider(outfile, num_cols): 252 """ Print the table divider line. """ 253 line = ' ' 254 column_dividers = ['='] * num_cols 255 line += ' '.join(column_dividers) 256 257 feature = '=' * feature_str_len 258 259 print_table_row(outfile, feature, line) 260 261 262def print_table_css(outfile, table_id): 263 template = """ 264.. raw:: html 265 266 <style> 267 .wy-nav-content { 268 opacity: .99; 269 } 270 table#idx { 271 cursor: default; 272 overflow: hidden; 273 } 274 table#idx p { 275 margin: 0; 276 line-height: inherit; 277 } 278 table#idx th, table#idx td { 279 text-align: center; 280 border: solid 1px #ddd; 281 } 282 table#idx th { 283 padding: 0.5em 0; 284 } 285 table#idx th, table#idx th p { 286 font-size: 11px; 287 white-space: pre-wrap; 288 vertical-align: top; 289 min-width: 0.9em; 290 } 291 table#idx col:first-child { 292 width: 0; 293 } 294 table#idx th:first-child { 295 vertical-align: bottom; 296 } 297 table#idx td { 298 padding: 1px; 299 } 300 table#idx td, table#idx td p { 301 font-size: 11px; 302 } 303 table#idx td:first-child { 304 padding-left: 1em; 305 text-align: left; 306 } 307 table#idx tr:nth-child(2n-1) td { 308 background-color: rgba(210, 210, 210, 0.2); 309 } 310 table#idx th:not(:first-child):hover, 311 table#idx td:not(:first-child):hover { 312 position: relative; 313 } 314 table#idx th:not(:first-child):hover::after, 315 table#idx td:not(:first-child):hover::after { 316 content: ''; 317 height: 6000px; 318 top: -3000px; 319 width: 100%; 320 left: 0; 321 position: absolute; 322 z-index: -1; 323 background-color: #ffb; 324 } 325 table#idx tr:hover td { 326 background-color: #ffb; 327 } 328 </style> 329""" 330 print(template.replace("idx", "id%d" % (table_id)), file=outfile) 331 332 333def setup(app): 334 table_file = dirname(__file__) + '/nics/overview_table.txt' 335 generate_overview_table(table_file, 1, 336 'Features', 337 'Features availability in networking drivers', 338 'Feature') 339 table_file = dirname(__file__) + '/nics/rte_flow_items_table.txt' 340 generate_overview_table(table_file, 2, 341 'rte_flow items', 342 'rte_flow items availability in networking drivers', 343 'Item') 344 table_file = dirname(__file__) + '/nics/rte_flow_actions_table.txt' 345 generate_overview_table(table_file, 3, 346 'rte_flow actions', 347 'rte_flow actions availability in networking drivers', 348 'Action') 349 table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt' 350 generate_overview_table(table_file, 1, 351 'Features', 352 'Features availability in crypto drivers', 353 'Feature') 354 table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt' 355 generate_overview_table(table_file, 2, 356 'Cipher', 357 'Cipher algorithms in crypto drivers', 358 'Cipher algorithm') 359 table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt' 360 generate_overview_table(table_file, 3, 361 'Auth', 362 'Authentication algorithms in crypto drivers', 363 'Authentication algorithm') 364 table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt' 365 generate_overview_table(table_file, 4, 366 'AEAD', 367 'AEAD algorithms in crypto drivers', 368 'AEAD algorithm') 369 table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt' 370 generate_overview_table(table_file, 5, 371 'Asymmetric', 372 'Asymmetric algorithms in crypto drivers', 373 'Asymmetric algorithm') 374 table_file = dirname(__file__) + '/cryptodevs/overview_os_table.txt' 375 generate_overview_table(table_file, 6, 376 'OS', 377 'Operating systems support for crypto drivers', 378 'Operating system') 379 table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt' 380 generate_overview_table(table_file, 1, 381 'Features', 382 'Features availability in compression drivers', 383 'Feature') 384 table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt' 385 generate_overview_table(table_file, 1, 386 'Features', 387 'Features availability in regex drivers', 388 'Feature') 389 table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt' 390 generate_overview_table(table_file, 1, 391 'Features', 392 'Features availability in vDPA drivers', 393 'Feature') 394 table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt' 395 generate_overview_table(table_file, 1, 396 'Features', 397 'Features availability in bbdev drivers', 398 'Feature') 399 table_file = dirname(__file__) + '/gpus/overview_feature_table.txt' 400 generate_overview_table(table_file, 1, 401 'Features', 402 'Features availability in GPU drivers', 403 'Feature') 404 table_file = dirname(__file__) + '/eventdevs/overview_feature_table.txt' 405 generate_overview_table(table_file, 1, 406 'Scheduling Features', 407 'Features availability in eventdev drivers', 408 'Feature') 409 table_file = dirname(__file__) + '/eventdevs/overview_rx_adptr_feature_table.txt' 410 generate_overview_table(table_file, 2, 411 'Eth Rx adapter Features', 412 'Features availability for Ethdev Rx adapters', 413 'Feature') 414 table_file = dirname(__file__) + '/eventdevs/overview_tx_adptr_feature_table.txt' 415 generate_overview_table(table_file, 3, 416 'Eth Tx adapter Features', 417 'Features availability for Ethdev Tx adapters', 418 'Feature') 419 table_file = dirname(__file__) + '/eventdevs/overview_crypto_adptr_feature_table.txt' 420 generate_overview_table(table_file, 4, 421 'Crypto adapter Features', 422 'Features availability for Crypto adapters', 423 'Feature') 424 table_file = dirname(__file__) + '/eventdevs/overview_timer_adptr_feature_table.txt' 425 generate_overview_table(table_file, 5, 426 'Timer adapter Features', 427 'Features availability for Timer adapters', 428 'Feature') 429 430 if Version(sphinx_version) < Version('1.3.1'): 431 print('Upgrade sphinx to version >= 1.3.1 for ' 432 'improved Figure/Table number handling.', 433 file=stderr) 434 # Add a role to handle :numref: references. 435 app.add_role('numref', numref_role) 436 # Process the numref references once the doctree has been created. 437 app.connect('doctree-resolved', process_numref) 438 439 try: 440 # New function in sphinx 1.8 441 app.add_css_file('css/custom.css') 442 except: 443 app.add_stylesheet('css/custom.css') 444