nl_netdev.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: GPL-2.0
  3. import time
  4. from os import system
  5. from lib.py import ksft_run, ksft_exit, ksft_pr
  6. from lib.py import ksft_eq, ksft_ge, ksft_ne, ksft_busy_wait
  7. from lib.py import NetdevFamily, NetdevSimDev, ip
  8. def empty_check(nf) -> None:
  9. devs = nf.dev_get({}, dump=True)
  10. ksft_ge(len(devs), 1)
  11. def lo_check(nf) -> None:
  12. lo_info = nf.dev_get({"ifindex": 1})
  13. ksft_eq(len(lo_info['xdp-features']), 0)
  14. ksft_eq(len(lo_info['xdp-rx-metadata-features']), 0)
  15. def napi_list_check(nf) -> None:
  16. with NetdevSimDev(queue_count=100) as nsimdev:
  17. nsim = nsimdev.nsims[0]
  18. ip(f"link set dev {nsim.ifname} up")
  19. napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
  20. ksft_eq(len(napis), 100)
  21. for q in [50, 0, 99]:
  22. for i in range(4):
  23. nsim.dfs_write("queue_reset", f"{q} {i}")
  24. napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
  25. ksft_eq(len(napis), 100,
  26. comment=f"queue count after reset queue {q} mode {i}")
  27. def napi_set_threaded(nf) -> None:
  28. """
  29. Test that verifies various cases of napi threaded
  30. set and unset at napi and device level.
  31. """
  32. with NetdevSimDev(queue_count=2) as nsimdev:
  33. nsim = nsimdev.nsims[0]
  34. ip(f"link set dev {nsim.ifname} up")
  35. napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
  36. ksft_eq(len(napis), 2)
  37. napi0_id = napis[0]['id']
  38. napi1_id = napis[1]['id']
  39. # set napi threaded and verify
  40. nf.napi_set({'id': napi0_id, 'threaded': "enabled"})
  41. napi0 = nf.napi_get({'id': napi0_id})
  42. ksft_eq(napi0['threaded'], "enabled")
  43. ksft_ne(napi0.get('pid'), None)
  44. # check it is not set for napi1
  45. napi1 = nf.napi_get({'id': napi1_id})
  46. ksft_eq(napi1['threaded'], "disabled")
  47. ksft_eq(napi1.get('pid'), None)
  48. ip(f"link set dev {nsim.ifname} down")
  49. ip(f"link set dev {nsim.ifname} up")
  50. # verify if napi threaded is still set
  51. napi0 = nf.napi_get({'id': napi0_id})
  52. ksft_eq(napi0['threaded'], "enabled")
  53. ksft_ne(napi0.get('pid'), None)
  54. # check it is still not set for napi1
  55. napi1 = nf.napi_get({'id': napi1_id})
  56. ksft_eq(napi1['threaded'], "disabled")
  57. ksft_eq(napi1.get('pid'), None)
  58. # unset napi threaded and verify
  59. nf.napi_set({'id': napi0_id, 'threaded': "disabled"})
  60. napi0 = nf.napi_get({'id': napi0_id})
  61. ksft_eq(napi0['threaded'], "disabled")
  62. ksft_eq(napi0.get('pid'), None)
  63. # set threaded at device level
  64. system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded")
  65. # check napi threaded is set for both napis
  66. napi0 = nf.napi_get({'id': napi0_id})
  67. ksft_eq(napi0['threaded'], "enabled")
  68. ksft_ne(napi0.get('pid'), None)
  69. napi1 = nf.napi_get({'id': napi1_id})
  70. ksft_eq(napi1['threaded'], "enabled")
  71. ksft_ne(napi1.get('pid'), None)
  72. # unset threaded at device level
  73. system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded")
  74. # check napi threaded is unset for both napis
  75. napi0 = nf.napi_get({'id': napi0_id})
  76. ksft_eq(napi0['threaded'], "disabled")
  77. ksft_eq(napi0.get('pid'), None)
  78. napi1 = nf.napi_get({'id': napi1_id})
  79. ksft_eq(napi1['threaded'], "disabled")
  80. ksft_eq(napi1.get('pid'), None)
  81. # set napi threaded for napi0
  82. nf.napi_set({'id': napi0_id, 'threaded': 1})
  83. napi0 = nf.napi_get({'id': napi0_id})
  84. ksft_eq(napi0['threaded'], "enabled")
  85. ksft_ne(napi0.get('pid'), None)
  86. # unset threaded at device level
  87. system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded")
  88. # check napi threaded is unset for both napis
  89. napi0 = nf.napi_get({'id': napi0_id})
  90. ksft_eq(napi0['threaded'], "disabled")
  91. ksft_eq(napi0.get('pid'), None)
  92. napi1 = nf.napi_get({'id': napi1_id})
  93. ksft_eq(napi1['threaded'], "disabled")
  94. ksft_eq(napi1.get('pid'), None)
  95. def dev_set_threaded(nf) -> None:
  96. """
  97. Test that verifies various cases of napi threaded
  98. set and unset at device level using sysfs.
  99. """
  100. with NetdevSimDev(queue_count=2) as nsimdev:
  101. nsim = nsimdev.nsims[0]
  102. ip(f"link set dev {nsim.ifname} up")
  103. napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
  104. ksft_eq(len(napis), 2)
  105. napi0_id = napis[0]['id']
  106. napi1_id = napis[1]['id']
  107. # set threaded
  108. system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded")
  109. # check napi threaded is set for both napis
  110. napi0 = nf.napi_get({'id': napi0_id})
  111. ksft_eq(napi0['threaded'], "enabled")
  112. ksft_ne(napi0.get('pid'), None)
  113. napi1 = nf.napi_get({'id': napi1_id})
  114. ksft_eq(napi1['threaded'], "enabled")
  115. ksft_ne(napi1.get('pid'), None)
  116. # unset threaded
  117. system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded")
  118. # check napi threaded is unset for both napis
  119. napi0 = nf.napi_get({'id': napi0_id})
  120. ksft_eq(napi0['threaded'], "disabled")
  121. ksft_eq(napi0.get('pid'), None)
  122. napi1 = nf.napi_get({'id': napi1_id})
  123. ksft_eq(napi1['threaded'], "disabled")
  124. ksft_eq(napi1.get('pid'), None)
  125. def nsim_rxq_reset_down(nf) -> None:
  126. """
  127. Test that the queue API supports resetting a queue
  128. while the interface is down. We should convert this
  129. test to testing real HW once more devices support
  130. queue API.
  131. """
  132. with NetdevSimDev(queue_count=4) as nsimdev:
  133. nsim = nsimdev.nsims[0]
  134. ip(f"link set dev {nsim.ifname} down")
  135. for i in [0, 2, 3]:
  136. nsim.dfs_write("queue_reset", f"1 {i}")
  137. def page_pool_check(nf) -> None:
  138. with NetdevSimDev() as nsimdev:
  139. nsim = nsimdev.nsims[0]
  140. def up():
  141. ip(f"link set dev {nsim.ifname} up")
  142. def down():
  143. ip(f"link set dev {nsim.ifname} down")
  144. def get_pp():
  145. pp_list = nf.page_pool_get({}, dump=True)
  146. return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex]
  147. # No page pools when down
  148. down()
  149. ksft_eq(len(get_pp()), 0)
  150. # Up, empty page pool appears
  151. up()
  152. pp_list = get_pp()
  153. ksft_ge(len(pp_list), 0)
  154. refs = sum([pp["inflight"] for pp in pp_list])
  155. ksft_eq(refs, 0)
  156. # Down, it disappears, again
  157. down()
  158. pp_list = get_pp()
  159. ksft_eq(len(pp_list), 0)
  160. # Up, allocate a page
  161. up()
  162. nsim.dfs_write("pp_hold", "y")
  163. pp_list = nf.page_pool_get({}, dump=True)
  164. refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex])
  165. ksft_ge(refs, 1)
  166. # Now let's leak a page
  167. down()
  168. pp_list = get_pp()
  169. ksft_eq(len(pp_list), 1)
  170. refs = sum([pp["inflight"] for pp in pp_list])
  171. ksft_eq(refs, 1)
  172. attached = [pp for pp in pp_list if "detach-time" not in pp]
  173. ksft_eq(len(attached), 0)
  174. # New pp can get created, and we'll have two
  175. up()
  176. pp_list = get_pp()
  177. attached = [pp for pp in pp_list if "detach-time" not in pp]
  178. detached = [pp for pp in pp_list if "detach-time" in pp]
  179. ksft_eq(len(attached), 1)
  180. ksft_eq(len(detached), 1)
  181. # Free the old page and the old pp is gone
  182. nsim.dfs_write("pp_hold", "n")
  183. # Freeing check is once a second so we may need to retry
  184. ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2)
  185. # And down...
  186. down()
  187. ksft_eq(len(get_pp()), 0)
  188. # Last, leave the page hanging for destroy, nothing to check
  189. # we're trying to exercise the orphaning path in the kernel
  190. up()
  191. nsim.dfs_write("pp_hold", "y")
  192. def main() -> None:
  193. nf = NetdevFamily()
  194. ksft_run([empty_check, lo_check, page_pool_check, napi_list_check,
  195. dev_set_threaded, napi_set_threaded, nsim_rxq_reset_down],
  196. args=(nf, ))
  197. ksft_exit()
  198. if __name__ == "__main__":
  199. main()