ring_reconfig.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: GPL-2.0
  3. """
  4. Test channel and ring size configuration via ethtool (-L / -G).
  5. """
  6. from lib.py import ksft_run, ksft_exit, ksft_pr
  7. from lib.py import ksft_eq
  8. from lib.py import NetDrvEpEnv, EthtoolFamily, GenerateTraffic
  9. from lib.py import defer, NlError
  10. def channels(cfg) -> None:
  11. """
  12. Twiddle channel counts in various combinations of parameters.
  13. We're only looking for driver adhering to the requested config
  14. if the config is accepted and crashes.
  15. """
  16. ehdr = {'header':{'dev-index': cfg.ifindex}}
  17. chans = cfg.eth.channels_get(ehdr)
  18. all_keys = ["rx", "tx", "combined"]
  19. mixes = [{"combined"}, {"rx", "tx"}, {"rx", "combined"}, {"tx", "combined"},
  20. {"rx", "tx", "combined"},]
  21. # Get the set of keys that device actually supports
  22. restore = {}
  23. supported = set()
  24. for key in all_keys:
  25. if key + "-max" in chans:
  26. supported.add(key)
  27. restore |= {key + "-count": chans[key + "-count"]}
  28. defer(cfg.eth.channels_set, ehdr | restore)
  29. def test_config(config):
  30. try:
  31. cfg.eth.channels_set(ehdr | config)
  32. get = cfg.eth.channels_get(ehdr)
  33. for k, v in config.items():
  34. ksft_eq(get.get(k, 0), v)
  35. except NlError as e:
  36. failed.append(mix)
  37. ksft_pr("Can't set", config, e)
  38. else:
  39. ksft_pr("Okay", config)
  40. failed = []
  41. for mix in mixes:
  42. if not mix.issubset(supported):
  43. continue
  44. # Set all the values in the mix to 1, other supported to 0
  45. config = {}
  46. for key in all_keys:
  47. config[key + "-count"] = 1 if key in mix else 0
  48. test_config(config)
  49. for mix in mixes:
  50. if not mix.issubset(supported):
  51. continue
  52. if mix in failed:
  53. continue
  54. # Set all the values in the mix to max, other supported to 0
  55. config = {}
  56. for key in all_keys:
  57. config[key + "-count"] = chans[key + '-max'] if key in mix else 0
  58. test_config(config)
  59. def _configure_min_ring_cnt(cfg) -> None:
  60. """ Try to configure a single Rx/Tx ring. """
  61. ehdr = {'header':{'dev-index': cfg.ifindex}}
  62. chans = cfg.eth.channels_get(ehdr)
  63. all_keys = ["rx-count", "tx-count", "combined-count"]
  64. restore = {}
  65. config = {}
  66. for key in all_keys:
  67. if key in chans:
  68. restore[key] = chans[key]
  69. config[key] = 0
  70. if chans.get('combined-count', 0) > 1:
  71. config['combined-count'] = 1
  72. elif chans.get('rx-count', 0) > 1 and chans.get('tx-count', 0) > 1:
  73. config['tx-count'] = 1
  74. config['rx-count'] = 1
  75. else:
  76. # looks like we're already on 1 channel
  77. return
  78. cfg.eth.channels_set(ehdr | config)
  79. defer(cfg.eth.channels_set, ehdr | restore)
  80. def ringparam(cfg) -> None:
  81. """
  82. Tweak the ringparam configuration. Try to run some traffic over min
  83. ring size to make sure it actually functions.
  84. """
  85. ehdr = {'header':{'dev-index': cfg.ifindex}}
  86. rings = cfg.eth.rings_get(ehdr)
  87. restore = {}
  88. maxes = {}
  89. params = set()
  90. for key in rings.keys():
  91. if 'max' in key:
  92. param = key[:-4]
  93. maxes[param] = rings[key]
  94. params.add(param)
  95. restore[param] = rings[param]
  96. defer(cfg.eth.rings_set, ehdr | restore)
  97. # Speed up the reconfig by configuring just one ring
  98. _configure_min_ring_cnt(cfg)
  99. # Try to reach min on all settings
  100. for param in params:
  101. val = rings[param]
  102. while True:
  103. try:
  104. cfg.eth.rings_set({'header':{'dev-index': cfg.ifindex},
  105. param: val // 2})
  106. if val == 0:
  107. break
  108. val //= 2
  109. except NlError:
  110. break
  111. get = cfg.eth.rings_get(ehdr)
  112. ksft_eq(get[param], val)
  113. ksft_pr(f"Reached min for '{param}' at {val} (max {rings[param]})")
  114. GenerateTraffic(cfg).wait_pkts_and_stop(10000)
  115. # Try max across all params, if the driver supports large rings
  116. # this may OOM so we ignore errors
  117. try:
  118. ksft_pr("Applying max settings")
  119. config = {p: maxes[p] for p in params}
  120. cfg.eth.rings_set(ehdr | config)
  121. except NlError as e:
  122. ksft_pr("Can't set max params", config, e)
  123. else:
  124. GenerateTraffic(cfg).wait_pkts_and_stop(10000)
  125. def main() -> None:
  126. """ Ksft boiler plate main """
  127. with NetDrvEpEnv(__file__) as cfg:
  128. cfg.eth = EthtoolFamily()
  129. ksft_run([channels,
  130. ringparam],
  131. args=(cfg, ))
  132. ksft_exit()
  133. if __name__ == "__main__":
  134. main()