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