xlat 0.1.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +7 -0
  3. data/.rspec +3 -0
  4. data/Cargo.lock +348 -0
  5. data/Cargo.toml +7 -0
  6. data/Dockerfile +49 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +100 -0
  9. data/Rakefile +82 -0
  10. data/benchmark/run.rb +38 -0
  11. data/benchmark/tcp.cfg +23 -0
  12. data/clab/.gitignore +5 -0
  13. data/clab/464xlat-ce-pd.clab.yml +138 -0
  14. data/clab/build.sh +6 -0
  15. data/exe/xlat-siit +91 -0
  16. data/ext/xlat/io_buffer_ext/Cargo.toml +11 -0
  17. data/ext/xlat/io_buffer_ext/extconf.rb +4 -0
  18. data/ext/xlat/io_buffer_ext/src/gvl.rs +49 -0
  19. data/ext/xlat/io_buffer_ext/src/io_buffer.rs +67 -0
  20. data/ext/xlat/io_buffer_ext/src/lib.rs +83 -0
  21. data/fuzz/corpus/010507e2c9f3b5132cbf036c7197f155cd85cca8 +0 -0
  22. data/fuzz/corpus/019a67cbfe27ed6606fe9d9cbee1ba16eb160667 +0 -0
  23. data/fuzz/corpus/021f01b7a6d4ba3e8e45a733c453d6c84f8c4c38 +0 -0
  24. data/fuzz/corpus/02db19829d1a4cbe18127e9ab1f3792e0d7fd5f7 +0 -0
  25. data/fuzz/corpus/059b719daf320e809db75d37ecf7823ba33ca7aa +0 -0
  26. data/fuzz/corpus/080ce49cbdb1983f8b9af09d511c5ec5a6bb14ed +0 -0
  27. data/fuzz/corpus/080d7d8674e7d60ce13b48995567a4ad21a3d652 +0 -0
  28. data/fuzz/corpus/08d488926f31661a1b25f60a723ae1931c762255 +0 -0
  29. data/fuzz/corpus/09ee56fb3259c88ad2cb94951313d792f36da221 +0 -0
  30. data/fuzz/corpus/0bffe4074467b5c4ba2bd5aa33839c5a1b8c1d63 +0 -0
  31. data/fuzz/corpus/0dac63180387255727c844898164ce20ff08fded +0 -0
  32. data/fuzz/corpus/0dc6f6c09c5b7bb4da8d496ac924e7e0d4aa37ad +0 -0
  33. data/fuzz/corpus/0e3e8e947fd9bfed02f927d1a2651e484d231fc0 +0 -0
  34. data/fuzz/corpus/0e5fa83f0ef8ecbf774ac96b8bdeda31395a284d +0 -0
  35. data/fuzz/corpus/12f93fa0b09c44d6c61ccde2731b5554bb180144 +0 -0
  36. data/fuzz/corpus/1659c552b9be677f2c30210430a97c3628f615be +0 -0
  37. data/fuzz/corpus/183aeabfe58d5ccfd5f2ed84e2f5ee4931f14eb7 +0 -0
  38. data/fuzz/corpus/1b9293272fbacbfff7aff4fd951dd7beb6aed3bf +0 -0
  39. data/fuzz/corpus/1c30abedb2d0943ef79b0620f7b3a7e8cdebc67f +0 -0
  40. data/fuzz/corpus/1c479cc892198d0cc389cc681206393c8ae4cbb6 +0 -0
  41. data/fuzz/corpus/1ca9480af5da2221fc320bb281d7c4ff73d5f33c +0 -0
  42. data/fuzz/corpus/1d6087f18146fac3b663bcc635fb470cb651884b +0 -0
  43. data/fuzz/corpus/258d23cbc2c8081782f0dd539270848e275a8e15 +0 -0
  44. data/fuzz/corpus/27512fa5c0ac5f4d8393ab442b50af3e83047c01 +0 -0
  45. data/fuzz/corpus/29933024f32228a8b65419d63dcbb56124db0df7 +0 -0
  46. data/fuzz/corpus/2b19339a2f24978c8413912a8003ae8ba8885684 +0 -0
  47. data/fuzz/corpus/2f8d2861a271e3ee2f658b01ef6ba854d8837aff +0 -0
  48. data/fuzz/corpus/2fed10d20fc4ed25da9cebd41209886304b39465 +0 -0
  49. data/fuzz/corpus/30fd38c3af4877eda7b1ca2dee1a60c4fe0f757c +0 -0
  50. data/fuzz/corpus/3137ba78351b6757255261a4f364e44693c3c85f +0 -0
  51. data/fuzz/corpus/34e68133b209c490f960f9682d33d41aab99e60f +0 -0
  52. data/fuzz/corpus/359870740db1c245d6dfdad1f119c7b17c3f25fc +0 -0
  53. data/fuzz/corpus/37b1bb01b0544125df396b925e2c4242a90d1c52 +0 -0
  54. data/fuzz/corpus/387cab0f8ac36f0f5496f6b0aed7d6c7ca3f2dbf +0 -0
  55. data/fuzz/corpus/3c4e48335e11c3bd066bbb43db4bf82249668869 +0 -0
  56. data/fuzz/corpus/3ec111be62099aaa9b960f4b69c65a3b12962970 +0 -0
  57. data/fuzz/corpus/3fb2f3f01b304e48d9c60477dfe5834693ef80db +0 -0
  58. data/fuzz/corpus/40cf2f11c2ea03c56864f5097d2f989b14762426 +0 -0
  59. data/fuzz/corpus/40cfc6a6a60f2451974522e5450ba6434f61a8bb +0 -0
  60. data/fuzz/corpus/4c3f43f4654332520eb57a9bcfe95951857272ce +0 -0
  61. data/fuzz/corpus/4c85fdf6934e86766274dd668f3f69f15c7bbc11 +0 -0
  62. data/fuzz/corpus/4f708dd44266b8b567e295c03811feef57c0a493 +0 -0
  63. data/fuzz/corpus/50cfff5d1cfc310686d7c1f38787cb77ec6fd892 +0 -0
  64. data/fuzz/corpus/53b2e1cb235c4479711d9ac74a375330d69f9e4c +0 -0
  65. data/fuzz/corpus/560373973be830ca5a34ab8e4d4b25a942ad5ed6 +0 -0
  66. data/fuzz/corpus/57768a4d41ccb6149219ba3eb7fe9e5b191dc4aa +0 -0
  67. data/fuzz/corpus/5a7833a1a882226aa3831298fdb0d23b580016d8 +0 -0
  68. data/fuzz/corpus/5b394ecc62e63d030cfeff7e0c484c233c7e9d63 +0 -0
  69. data/fuzz/corpus/5c10ea32f35ab603f1acd9b3c3ac3c397c1c690a +0 -0
  70. data/fuzz/corpus/5d4f6df161ce9c6465641cea9e0e97771f4249cf +0 -0
  71. data/fuzz/corpus/5f29c11e0f583226dfa98c236b8d48c772bccbf1 +0 -0
  72. data/fuzz/corpus/603d6df8d387f6b191f9b732d8928638e2deab10 +0 -0
  73. data/fuzz/corpus/60e17201e5bc64340b37ac96ff6302546c231eea +0 -0
  74. data/fuzz/corpus/65cc3e13ae39a4cd1b207a3395b5205d3fbcae7b +0 -0
  75. data/fuzz/corpus/692c3712da22c928e0d1b5f91ea7a74ba6fcdf5f +0 -0
  76. data/fuzz/corpus/69ee357cc3bda8a068bc875dda0879bb462b4984 +0 -0
  77. data/fuzz/corpus/6a2310279f4fa43ee4ed3809bc039f8ec7bfdeb4 +0 -0
  78. data/fuzz/corpus/6bfdbaafbe1d257b49f58b7a2fa3fef51894d76a +0 -0
  79. data/fuzz/corpus/6d3c4288760aaf7131fb3caebb5b3aad6a1828fd +0 -0
  80. data/fuzz/corpus/6e2f243fb0020e9bfb797c0100da18a67c8f1cb7 +0 -0
  81. data/fuzz/corpus/6ee7bf4cd8249100046bd4ba28b6646dfd436bd4 +0 -0
  82. data/fuzz/corpus/70e0947673dd1cc2680f907ecfde339688c3fadb +0 -0
  83. data/fuzz/corpus/76b1ab6e0edbfeefd4a23fc8a18f7d5937fe3787 +0 -0
  84. data/fuzz/corpus/77d6e8a03cec0da5803042fd51030e97fb11f5fd +0 -0
  85. data/fuzz/corpus/79b7efd2703e6343b8daf769aea6a76b199d7aa2 +0 -0
  86. data/fuzz/corpus/7ab28e22d79e7f2774ab2b8baaddeedf58f37475 +0 -0
  87. data/fuzz/corpus/7cb99d73cc9c03dc463a7892b27ae78a857c2450 +0 -0
  88. data/fuzz/corpus/81f5010a3c5a44639c0fbb6325c163cd5f8b7ee9 +0 -0
  89. data/fuzz/corpus/8317c66a4178b54bfd405332490dfd82a3949244 +0 -0
  90. data/fuzz/corpus/871b1e5a6ad58fbd654725c0c280f1aa278cd7b5 +0 -0
  91. data/fuzz/corpus/879bd3b24e7c968141bf3c69fdfb11da99af8e8e +0 -0
  92. data/fuzz/corpus/8a6bc02a79659eb0c71d5bc784da0f1b351b4336 +0 -0
  93. data/fuzz/corpus/8d6d41bc7e792d6737c35d7c989c9772ad3ae1d6 +0 -0
  94. data/fuzz/corpus/8ee4e2e6827b38feaa739c7a61535087ae1ca91c +0 -0
  95. data/fuzz/corpus/911a7cad153c517c75ea7d410c4f093865da5b50 +0 -0
  96. data/fuzz/corpus/932c12b633a087eff4f195da9fed03e202190515 +0 -0
  97. data/fuzz/corpus/93c883857d41e5cdaaa4c2b04dd316da73c9c519 +0 -0
  98. data/fuzz/corpus/944e31de1264ab5347f37d1454b6bcdd06b85b51 +0 -0
  99. data/fuzz/corpus/9882bea35622d45012774dbf8f9658c597f07d51 +0 -0
  100. data/fuzz/corpus/989f9271f90207d498fb69eeba16b8393f8cc70b +0 -0
  101. data/fuzz/corpus/9927a043166634231659695111b473cbd19fbeec +0 -0
  102. data/fuzz/corpus/9a33c2ce796569be8450658c6231936816ee55bb +0 -0
  103. data/fuzz/corpus/9a51def27a9547cf9aa059809a2d5482f75ae8af +0 -0
  104. data/fuzz/corpus/9b915fd1452d10a00ae2ecb0d53784a127341e79 +0 -0
  105. data/fuzz/corpus/9de518e7fb61598ac152a91feaf2d7bbe3e8b943 +0 -0
  106. data/fuzz/corpus/9eaee706fb7d021dc5f0ecc79b524de9c74f439e +0 -0
  107. data/fuzz/corpus/9ecb6bbe9d4c7414406e4c002b449279bf898ee4 +0 -0
  108. data/fuzz/corpus/a389244e26c3e525393db7c6b89495981c5160e5 +0 -0
  109. data/fuzz/corpus/a52173807baf225d705386e47e57a115a8cb537c +0 -0
  110. data/fuzz/corpus/a6fdb8761221dfd348c29c9eb224eb5cf5e4849a +0 -0
  111. data/fuzz/corpus/a76ca8a3f3ffb4ff898f896b65a5bae2d0ed002a +0 -0
  112. data/fuzz/corpus/a91ff9c074e9503baa27194d220dca03926a4f3d +0 -0
  113. data/fuzz/corpus/aa66cf1089cea0a8aa7e54394e75d4f2949bba74 +0 -0
  114. data/fuzz/corpus/aafdf57c09c20115384292e1b39cf7dae6674fff +0 -0
  115. data/fuzz/corpus/af0d6601066ec5c6bac2f0a57b5753ef2826463d +0 -0
  116. data/fuzz/corpus/b26766574788c20a8ec6927c19327f3919c7a69f +0 -0
  117. data/fuzz/corpus/b2b582043818797e2a53a72e3f24e545fbda3b57 +0 -0
  118. data/fuzz/corpus/b31e0aa5172beb560c264d8b5c84932870271e9e +0 -0
  119. data/fuzz/corpus/b396625aa6e69a5eef782446bbc09606050abb8a +0 -0
  120. data/fuzz/corpus/b5693370c14ce015236f7746ee63d0af38ec89e4 +0 -0
  121. data/fuzz/corpus/b8fd1ed5f8c575a8ac6a7c468bf93f1f96f8edb4 +0 -0
  122. data/fuzz/corpus/b928cbb72b744adec35cba73db6b09b4c0c8af42 +0 -0
  123. data/fuzz/corpus/b9e36aaac143135fadf4bbcac8d892a7b515cbaf +0 -0
  124. data/fuzz/corpus/bae2b0281a4ce082295254dd4f49183ca6b5f2d3 +0 -0
  125. data/fuzz/corpus/bfdc9d194a5a4ed98adfa14a47cec84ca91aa4ad +0 -0
  126. data/fuzz/corpus/c2f64ce75de11ecb09496d5d95955da7730872e1 +0 -0
  127. data/fuzz/corpus/c45f32e7bfa9ea837d6cdd1844d7c8d354981242 +0 -0
  128. data/fuzz/corpus/c64d7ac2a14b5227524521fab16ff0ca4e5170d6 +0 -0
  129. data/fuzz/corpus/c6f8466a86b7371cbf715317cbd313f609ee739b +0 -0
  130. data/fuzz/corpus/c9d6e62a62fffb21687fae534b8113a07f92aee6 +0 -0
  131. data/fuzz/corpus/d0171338648afb30043ea71f3561c60fd8372a1d +0 -0
  132. data/fuzz/corpus/d0faa1afa3e94f6a51a1a4c0d3dafb2600592593 +0 -0
  133. data/fuzz/corpus/d467fc34aec5d7f2b24a3df67dbf99080dc00681 +0 -0
  134. data/fuzz/corpus/d696b7b20d1cd2a3c2bf47c302afbba1696632c9 +0 -0
  135. data/fuzz/corpus/d6d7695a3c86643a3ad779b75ea4d00fb535a3d9 +0 -0
  136. data/fuzz/corpus/d7b303e5aec6bac4311102a324cbea23663b2b20 +0 -0
  137. data/fuzz/corpus/d8afc09fe51ea23526db161a2a1cdacba0b1fefe +0 -0
  138. data/fuzz/corpus/d9bb42d0a55b8a200e3dfea84ca2e6e265ef2366 +0 -0
  139. data/fuzz/corpus/da6d7c1f2a7d5b0dabe71f048c9c1624c8ebdbd9 +0 -0
  140. data/fuzz/corpus/da70dbded78bc388cd692dc36b9da4697d5b6ad2 +0 -0
  141. data/fuzz/corpus/da71cde284c9f10c6c6952e2e800558720914c30 +0 -0
  142. data/fuzz/corpus/dcdfeaf43771474c3b236ffe79e14dc78b3b09ec +0 -0
  143. data/fuzz/corpus/dcef32e091776dc98ac4a4cf951528857d0b7ce1 +0 -0
  144. data/fuzz/corpus/ddedc95cd0c2db9ad8895fb33227e3e759f57ed9 +0 -0
  145. data/fuzz/corpus/de361721e7f714ac3a55ef5839801e0bf3566b37 +0 -0
  146. data/fuzz/corpus/e1c05af770b1443f8cfeff261affb50b3c551aa0 +0 -0
  147. data/fuzz/corpus/e62f88307794127ffccadf614b7062c3e78ce5c0 +0 -0
  148. data/fuzz/corpus/e85854d63d682e0a16f9aefa477a4337dbc63f5d +0 -0
  149. data/fuzz/corpus/e86666a117e96697f7823d6d61b448a76c7c8c64 +0 -0
  150. data/fuzz/corpus/e91897c8cefdd583e1d60e6a833fab40d775cff1 +0 -0
  151. data/fuzz/corpus/eb8ed69481cf71efdac8df0759d28624f2bc40cc +0 -0
  152. data/fuzz/corpus/ee9308e841589fbabf3013d9366ac6556d82bdf9 +0 -0
  153. data/fuzz/corpus/ef2a0b39689c489d499abc4188b45fafdba66ab8 +0 -0
  154. data/fuzz/corpus/f013d9c3de8fe4958ad84c56c651031314a92e26 +0 -0
  155. data/fuzz/corpus/f19cf033be3041feeee3eefe45ba5adbf2f5d421 +0 -0
  156. data/fuzz/corpus/f1c9fa3baf1730afaa330216edcb5ba34d2590b0 +0 -0
  157. data/fuzz/corpus/f1ed8642840969d76fff003dc68e48a717050e72 +0 -0
  158. data/fuzz/corpus/f2fbe027944e00facddfcb425be9c0269fe3b8b9 +0 -0
  159. data/fuzz/corpus/f7f6ff7ec8323de5100118914bacde5b4cc81a9e +0 -0
  160. data/fuzz/corpus/fade0bf074f861cdb9013fbdd3b084a60d9ac858 +0 -0
  161. data/fuzz/corpus/fd85b215e07f3ce968a5e0b810c6d04930b533e8 +0 -0
  162. data/fuzz/corpus/fd883fb9a67accfc7c61ddda6a781677cc8efc33 +0 -0
  163. data/fuzz/corpus/fd8953a87e3026bdb15d52faa387a6d49586cd66 +0 -0
  164. data/fuzz/corpus/fe46814360987e6b9cdaebf31a8a4ec7d26125b4 +0 -0
  165. data/fuzz/corpus/ffd623a08d5c93aae2ffed33346316d76d9abf1c +0 -0
  166. data/fuzz/instrumentation.rb +13 -0
  167. data/fuzz/run +11 -0
  168. data/fuzz/test_harness.rb +38 -0
  169. data/fuzz/test_tracer.rb +16 -0
  170. data/lib/xlat/adapters/linux_tun.rb +55 -0
  171. data/lib/xlat/address_translation.rb +32 -0
  172. data/lib/xlat/address_translators/rfc6052.rb +46 -0
  173. data/lib/xlat/common.rb +13 -0
  174. data/lib/xlat/pcap.rb +48 -0
  175. data/lib/xlat/protocols/icmp/base.rb +76 -0
  176. data/lib/xlat/protocols/icmp/echo.rb +71 -0
  177. data/lib/xlat/protocols/icmp/error.rb +70 -0
  178. data/lib/xlat/protocols/icmp.rb +14 -0
  179. data/lib/xlat/protocols/ip/ipv4.rb +106 -0
  180. data/lib/xlat/protocols/ip/ipv6.rb +133 -0
  181. data/lib/xlat/protocols/ip.rb +208 -0
  182. data/lib/xlat/protocols/tcp.rb +71 -0
  183. data/lib/xlat/protocols/tcpudp.rb +52 -0
  184. data/lib/xlat/protocols/udp.rb +66 -0
  185. data/lib/xlat/protocols.rb +0 -0
  186. data/lib/xlat/rfc7915.rb +580 -0
  187. data/lib/xlat/runner.rb +51 -0
  188. data/lib/xlat/version.rb +5 -0
  189. data/lib/xlat.rb +8 -0
  190. data/sig/xlat.rbs +4 -0
  191. metadata +246 -0
data/clab/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.bak
2
+ .tls/
3
+ authorized_keys
4
+ topology-data.json
5
+ ansible-inventory.yml
@@ -0,0 +1,138 @@
1
+ name: 464xlat-ue-pd
2
+
3
+ # Scenario:
4
+ # The user equipment (ue) has IPv6-only connectivity with a /64 delegated prefix.
5
+ # UE performs on-host CLAT using a /96 prefix chosen within its delegated prefix.
6
+ # The server (sv) has IPv4-only connectivity.
7
+ # The provider-side translator (plat) provides NAT64 service between UE and the server.
8
+ #
9
+ # CLAT is SIIT (xlat), and PLAT is NAT66 (nftables) + SIIT (xlat).
10
+ #
11
+ # [ue] <--> [rt1] <--> [plat] <--> [rt2] <--> [sv]
12
+ #
13
+ # Addresses:
14
+ # 64:ff9b::/96 plat: PLAT-side IPv6 prefix (Pref64::/n)
15
+ # 2001:db8:2::/48 rt1: UE pool
16
+ # 2001:db8:2:cafe::/64 ue: delegated prefix
17
+ # 2001:db8:2:cafe::1 ue: primary address
18
+ # 2001:db8:2:cafe:46:700::/96 ue: CLAT-side IPv6 prefix
19
+ # 2001:db8:66:d1e0::/96 plat: NAT66 outer prefix (local use)
20
+ # fe80::1 rt1: link-local
21
+ # fe80::2 rt2: link-local
22
+ # fe80::64 plat: link-local
23
+ # fe80::cafe ue: link-local
24
+ # 192.0.0.1 ue: loopback address for IPv4 service continuity
25
+ # 192.0.2.0/24 rt2: server segment
26
+ # 192.0.2.1 rt2: gateway address for the segment
27
+ # 192.0.2.80 server: primary address
28
+ # 203.0.113.0/29 plat: NAT64 outer pool
29
+
30
+ mgmt:
31
+ external-access: false
32
+
33
+ topology:
34
+ nodes:
35
+ ue:
36
+ kind: linux
37
+ image: &image localhost/xlat/xlat
38
+ cmd: --multiqueue=4 tun-xlat 64:ff9b::/96 2001:db8:2:cafe:46:700::/96
39
+ exec:
40
+ - &remove_default_rt sh -c 'ip -4 route del default && ip -6 route del default'
41
+ - &enable_forwarding sysctl -w net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1
42
+ - &wait_xlat sh -c 'for i in $(seq 10); do if ip link show tun-xlat; then break; else sleep 1; fi; done'
43
+
44
+ # Direct IPv4 traffic to Xlat
45
+ - ip link set dev tun-xlat up
46
+ - ip route add 0.0.0.0/0 dev tun-xlat
47
+ - ip route add 2001:db8:2:cafe:46:700::/96 dev tun-xlat
48
+
49
+ # Assign a dummy IPv4 address from IPv4 Service Continuity Prefix [RFC7335]
50
+ - ip addr add 192.0.0.1/32 dev lo
51
+
52
+ # rt1: IPv6 uplink
53
+ - ip addr add 2001:db8:2:cafe::1/64 dev eth1
54
+ - ip addr add fe80::cafe/64 dev eth1
55
+ - ip route add ::/0 via fe80::1 dev eth1
56
+
57
+ rt1:
58
+ kind: linux
59
+ image: *image
60
+ entrypoint: /bin/sleep
61
+ cmd: infinity
62
+ exec:
63
+ - *remove_default_rt
64
+ - *enable_forwarding
65
+
66
+ # ue
67
+ - ip addr add fe80::1/64 dev eth1
68
+ - ip route add 2001:db8:2:cafe::/64 via fe80::cafe dev eth1
69
+
70
+ # plat
71
+ - ip addr add fe80::1/64 dev eth2
72
+ - ip route add 64:ff9b::/96 via fe80::64 dev eth2
73
+
74
+ plat:
75
+ kind: linux
76
+ image: *image
77
+ cmd: --multiqueue=4 tun-xlat 2001:db8:66:d1e0::/96 64:ff9b::/96
78
+ env:
79
+ XLAT_PROFILE: 'on'
80
+ # XLAT_NOJIT: 'on'
81
+ exec:
82
+ - *remove_default_rt
83
+ - *enable_forwarding
84
+ - *wait_xlat
85
+
86
+ # rt1
87
+ - ip addr add fe80::64/64 dev eth1
88
+ - ip route add ::/0 via fe80::1 dev eth1
89
+
90
+ # rt2
91
+ - ip addr add fe80::64/64 dev eth2
92
+ - ip route add 0.0.0.0/0 via inet6 fe80::2 dev eth2
93
+
94
+ # Configure NAT66: Pref64::/96 -> internal prefix + IPv4 outer
95
+ - nft "add table ip6 nat"
96
+ - nft "add chain ip6 nat postrouting { type nat hook postrouting priority srcnat; }"
97
+ - nft "add rule ip6 nat postrouting ip6 daddr 64:ff9b::/96 counter snat to 2001:db8:66:d1e0::cb00:7100/125" # 203.0.113.0/29
98
+
99
+ # Direct NAT64 traffic to Xlat
100
+ - ip link set dev tun-xlat up
101
+ - ip route add 64:ff9b::/96 dev tun-xlat
102
+ - ip route add 203.0.113.0/29 dev tun-xlat
103
+
104
+ rt2:
105
+ kind: linux
106
+ image: *image
107
+ entrypoint: /bin/sleep
108
+ cmd: infinity
109
+ exec:
110
+ - *remove_default_rt
111
+ - *enable_forwarding
112
+
113
+ # plat
114
+ - ip addr add fe80::2/64 dev eth1
115
+ - ip route add 203.0.113.0/29 via inet6 fe80::64 dev eth1
116
+
117
+ # sv
118
+ - ip addr add 192.0.2.1/24 dev eth2
119
+
120
+ sv:
121
+ kind: linux
122
+ image: busybox
123
+ cmd: httpd -f -h /tmp
124
+ exec:
125
+ - *remove_default_rt
126
+ - *enable_forwarding
127
+
128
+ - sh -c 'echo Hello > /tmp/index.html'
129
+
130
+ # rt2: IPv4 uplink
131
+ - ip addr add 192.0.2.80/24 dev eth1
132
+ - ip route add 0.0.0.0/0 via 192.0.2.1 dev eth1
133
+
134
+ links:
135
+ - endpoints: ["ue:eth1", "rt1:eth1"]
136
+ - endpoints: ["plat:eth1", "rt1:eth2"]
137
+ - endpoints: ["plat:eth2", "rt2:eth1"]
138
+ - endpoints: ["sv:eth1", "rt2:eth2"]
data/clab/build.sh ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ set -eu
3
+
4
+ cd "$(dirname "${BASH_SOURCE[0]}")"
5
+
6
+ docker build -t localhost/xlat/xlat ..
data/exe/xlat-siit ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'logger'
4
+ require 'optparse'
5
+ require 'xlat/adapters/linux_tun'
6
+ require 'xlat/address_translators/rfc6052'
7
+ require 'xlat/rfc7915'
8
+ require 'xlat/runner'
9
+
10
+ opt = OptionParser.new do |opt|
11
+ opt.banner = "Usage: #{File.basename($0)} [options] IFNAME SRC::/N DST::/N"
12
+ opt.on('--multiqueue COUNT', Integer) {|n| @multiqueue = n }
13
+ end
14
+ opt.parse!(ARGV)
15
+
16
+ if ARGV.size != 3
17
+ $stderr.puts opt.help
18
+ exit 1
19
+ end
20
+
21
+ ifname, src_prefix, dst_prefix = *ARGV
22
+ src_translator = Xlat::AddressTranslators::Rfc6052.new(src_prefix)
23
+ dst_translator = Xlat::AddressTranslators::Rfc6052.new(dst_prefix)
24
+
25
+ def do_work(stderr, ifname, src_translator, dst_translator, multiqueue)
26
+ logger = Logger.new(stderr)
27
+
28
+ Xlat::Adapters::LinuxTun.open(ifname, multiqueue:) do |tun|
29
+ tun.mtu = 1500
30
+
31
+ loop do
32
+ Xlat::Runner.new(
33
+ adapter: tun,
34
+ translator: Xlat::Rfc7915.new(
35
+ source_address_translator: src_translator,
36
+ destination_address_translator: dst_translator,
37
+ ),
38
+ logger:,
39
+ ).run
40
+ rescue
41
+ logger.error { $!.full_message }
42
+ end
43
+ end
44
+ end
45
+
46
+ begin
47
+ require 'pf2'
48
+ rescue LoadError
49
+ def profile = yield
50
+ else
51
+ def profile
52
+ return yield unless ENV.key?('XLAT_PROFILE')
53
+
54
+ Pf2.start(threads: [Thread.current])
55
+ $profiling = true
56
+ begin
57
+ yield
58
+ ensure
59
+ $profiling = false
60
+ Pf2.stop
61
+ end
62
+ end
63
+ end
64
+
65
+ Signal.trap(:USR1) do
66
+ if $profiling
67
+ profile = Pf2.stop
68
+ begin
69
+ File.write("/tmp/xlat-#$$.pf2profile", profile)
70
+ ensure
71
+ Pf2.start
72
+ end
73
+ end
74
+ end
75
+
76
+ RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable) && !ENV.key?('XLAT_NOJIT')
77
+
78
+ if @multiqueue
79
+ workers = []
80
+ while true
81
+ while workers.size < @multiqueue
82
+ workers << Ractor.new($stderr.dup, ifname, src_translator, dst_translator, true, &method(:do_work))
83
+ end
84
+ r, = Ractor.select(*workers)
85
+ workers.delete(r)
86
+ end
87
+ else
88
+ profile do
89
+ do_work($stderr, ifname, src_translator, dst_translator, false)
90
+ end
91
+ end
@@ -0,0 +1,11 @@
1
+ [package]
2
+ name = "io_buffer_ext"
3
+ edition = "2021"
4
+ publish = false
5
+
6
+ [lib]
7
+ crate-type = ["cdylib"]
8
+
9
+ [dependencies]
10
+ magnus = { version = "0.7", features = ["rb-sys"] }
11
+ rb-sys = { version = "0.9" }
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ require 'rb_sys/mkmf'
3
+
4
+ create_rust_makefile('xlat/io_buffer_ext')
@@ -0,0 +1,49 @@
1
+ use std::{cell::Cell, ffi::c_void, mem, ptr};
2
+
3
+ struct Data<'a, F, R>
4
+ where
5
+ F: FnOnce() -> R,
6
+ {
7
+ fun: F,
8
+ ret: &'a Cell<Option<R>>,
9
+ }
10
+
11
+ /// Safety: `pdata` must point to a valid `Data<F, R>` object, which will be bitwise-copied.
12
+ unsafe extern "C" fn trampoline<F, R>(pdata: *mut c_void) -> *mut c_void
13
+ where
14
+ F: FnOnce() -> R,
15
+ {
16
+ let Data { fun, ret } = unsafe { ptr::read(pdata as *const Data<F, R>) };
17
+ ret.set(Some(fun()));
18
+
19
+ ptr::null_mut()
20
+ }
21
+
22
+ pub fn call_without_gvl2<F, R>(fun: F) -> R
23
+ where
24
+ F: FnOnce() -> R,
25
+ {
26
+ let cell = Cell::new(None);
27
+
28
+ let data = mem::ManuallyDrop::new(Data { fun, ret: &cell });
29
+
30
+ loop {
31
+ unsafe {
32
+ rb_sys::rb_thread_call_without_gvl2(
33
+ Some(trampoline::<F, R>),
34
+ ptr::addr_of!(data) as *mut c_void, // ManuallyDrop is transparent
35
+ None,
36
+ ptr::null_mut(),
37
+ );
38
+ }
39
+
40
+ // If rb_thread_call_without_gvl2 returns before invoking the callback
41
+ // due to interrupts, the cell remains to be None, and
42
+ // it's safe to retry because data is not consumed yet.
43
+ if let Some(r) = cell.take() {
44
+ return r;
45
+ }
46
+
47
+ unsafe { rb_sys::rb_thread_check_ints() }
48
+ }
49
+ }
@@ -0,0 +1,67 @@
1
+ use std::{mem::MaybeUninit, ptr};
2
+
3
+ use magnus::{
4
+ rb_sys::{AsRawValue as _, FromRawValue as _},
5
+ value::{Lazy, ReprValue as _},
6
+ Error, RClass, Ruby, TryConvert, Value,
7
+ };
8
+
9
+ #[derive(Clone, Copy)]
10
+ pub struct IOBuffer(Value);
11
+
12
+ static RB_C_IO_BUFFER: Lazy<RClass> = Lazy::new(|_ruby| {
13
+ let val = unsafe { Value::from_raw(rb_sys::rb_cIOBuffer) };
14
+ RClass::from_value(val).unwrap()
15
+ });
16
+
17
+ impl IOBuffer {
18
+ pub fn from_value(val: Value) -> Option<Self> {
19
+ if val.is_kind_of(Ruby::get_with(val).get_inner(&RB_C_IO_BUFFER)) {
20
+ Some(IOBuffer(val))
21
+ } else {
22
+ None
23
+ }
24
+ }
25
+
26
+ pub fn get_bytes_for_reading(&self) -> *const [u8] {
27
+ let mut ptr = MaybeUninit::uninit();
28
+ let mut len = MaybeUninit::uninit();
29
+ unsafe {
30
+ rb_sys::rb_io_buffer_get_bytes_for_reading(
31
+ self.0.as_raw(),
32
+ ptr.as_mut_ptr(),
33
+ len.as_mut_ptr(),
34
+ );
35
+ ptr::slice_from_raw_parts(ptr.assume_init().cast::<u8>(), len.assume_init() as usize)
36
+ }
37
+ }
38
+
39
+ pub fn get_bytes_for_writing(&self) -> *mut [u8] {
40
+ let mut ptr = MaybeUninit::uninit();
41
+ let mut len = MaybeUninit::uninit();
42
+ unsafe {
43
+ rb_sys::rb_io_buffer_get_bytes_for_writing(
44
+ self.0.as_raw(),
45
+ ptr.as_mut_ptr(),
46
+ len.as_mut_ptr(),
47
+ );
48
+ ptr::slice_from_raw_parts_mut(
49
+ ptr.assume_init().cast::<u8>(),
50
+ len.assume_init() as usize,
51
+ )
52
+ }
53
+ }
54
+ }
55
+
56
+ impl TryConvert for IOBuffer {
57
+ fn try_convert(val: Value) -> Result<Self, Error> {
58
+ Self::from_value(val).ok_or_else(|| {
59
+ Error::new(
60
+ Ruby::get_with(val).exception_type_error(),
61
+ format!("no implicit conversion of {} into IO::Buffer", unsafe {
62
+ val.classname()
63
+ },),
64
+ )
65
+ })
66
+ }
67
+ }
@@ -0,0 +1,83 @@
1
+ use std::{
2
+ fs::File,
3
+ io::{ErrorKind, IoSlice, IoSliceMut, Read, Write},
4
+ mem::ManuallyDrop,
5
+ os::fd::{AsRawFd as _, FromRawFd as _, RawFd},
6
+ };
7
+
8
+ use magnus::{function, prelude::*, Error, Object, RArray, RFile, Ruby};
9
+
10
+ mod gvl;
11
+ mod io_buffer;
12
+
13
+ fn file_from_rfile(io: RFile) -> Result<ManuallyDrop<File>, Error> {
14
+ let raw_fd = io.as_raw_fd();
15
+ if raw_fd == -1 as RawFd {
16
+ Err(Error::new(
17
+ Ruby::get_with(io).exception_io_error(),
18
+ "closed stream",
19
+ ))
20
+ } else {
21
+ // Don't take FD ownership from Ruby
22
+ Ok(ManuallyDrop::new(unsafe { File::from_raw_fd(raw_fd) }))
23
+ }
24
+ }
25
+
26
+ /// writev(IO, Array[IO::Buffer]) -> Integer
27
+ fn writev(ruby: &Ruby, io: RFile, bufs: RArray) -> Result<usize, Error> {
28
+ let mut w = file_from_rfile(io)?;
29
+
30
+ let vec = bufs
31
+ .into_iter()
32
+ .map(|v| {
33
+ io_buffer::IOBuffer::try_convert(v)
34
+ .map(|buf| IoSlice::new(unsafe { &*buf.get_bytes_for_reading() }))
35
+ })
36
+ .collect::<Result<Vec<_>, _>>()?;
37
+
38
+ loop {
39
+ match gvl::call_without_gvl2(|| w.write_vectored(&vec)) {
40
+ Ok(n) => return Ok(n),
41
+ Err(err) => {
42
+ if err.kind() != ErrorKind::Interrupted {
43
+ return Err(Error::new(ruby.exception_io_error(), err.to_string()));
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ /// readv(IO, Array[IO::Buffer]) -> Integer
51
+ fn readv(ruby: &Ruby, io: RFile, bufs: RArray) -> Result<usize, Error> {
52
+ let mut r = file_from_rfile(io)?;
53
+
54
+ let mut vec = bufs
55
+ .into_iter()
56
+ .map(|v| {
57
+ io_buffer::IOBuffer::try_convert(v)
58
+ .map(|buf| IoSliceMut::new(unsafe { &mut *buf.get_bytes_for_writing() }))
59
+ })
60
+ .collect::<Result<Vec<_>, _>>()?;
61
+
62
+ loop {
63
+ match gvl::call_without_gvl2(|| r.read_vectored(&mut vec)) {
64
+ Ok(n) => return Ok(n),
65
+ Err(err) => {
66
+ if err.kind() != ErrorKind::Interrupted {
67
+ return Err(Error::new(ruby.exception_io_error(), err.to_string()));
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ #[magnus::init]
75
+ fn init(ruby: &Ruby) -> Result<(), Error> {
76
+ // We don't share objects across Ractors
77
+ unsafe { rb_sys::rb_ext_ractor_safe(true) };
78
+
79
+ let module = ruby.define_module("Xlat")?.define_module("IOBufferExt")?;
80
+ module.define_singleton_method("readv", function!(readv, 2))?;
81
+ module.define_singleton_method("writev", function!(writev, 2))?;
82
+ Ok(())
83
+ }