
{"id":399,"date":"2025-05-21T21:22:22","date_gmt":"2025-05-21T13:22:22","guid":{"rendered":"https:\/\/www.shirui.me\/blog\/?p=399"},"modified":"2025-05-22T01:39:55","modified_gmt":"2025-05-21T17:39:55","slug":"naive-networking-2","status":"publish","type":"post","link":"https:\/\/www.shirui.me\/blog\/2025\/05\/21\/naive-networking-2\/","title":{"rendered":"Na\u00efve Networking 2"},"content":{"rendered":"\n<p>The following note explains how to deploy a high-performance VPN using WireGuard on VPP with DPDK. This lets lab members connect to computation servers from anywhere on the campus network with minimal overhead.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>While SoftEther VPN with a local-bridge to the NIC offers ~90 MB\/s for a single user on a 1 Gbps network, but drop quickly to 1MB\/s with increasing clients, it cannot leverage DPDK or SR-IOV. To scale beyond a few clients, we upgrade to an Intel E810 NIC and running VPP in user space. DPDK bypasses the kernel\u2019s network stack, enabling zero-copy packet forwarding:<\/p>\n\n\n\n<p><pre class=\"plain\"><code class=\"language-plain\">eth0 (out) &lt;--&gt; VPP (WireGuard + DPDK) &lt;--&gt; eth1 (in)<\/code><\/pre><\/p>\n\n<p>Network topology:<\/p>\n<p><pre class=\"plain\"><code class=\"language-plain\">VPN Client (10.100.1.x)\n    \u2502\n    \u2502 WireGuard tunnel\n    \u2502\nVPN Server\n  wg0: 10.100.1.1\/24     \u2190 VPN subnet\n  dpdk1: 10.10.2.10\/24   \u2190 Internal servers\n  dpdk0: &lt;Internet IP&gt;  \u2190 Public internet\n    \u2502\n    \u251c\u2500\u2500 Servers (10.10.2.0\/24)\n    \u2514\u2500\u2500 Internet<\/code><\/pre><\/p>\n\n<p>Clients on 10.100.1.0\/24 connect through wg0. Internal servers on 10.10.2.0\/24 connect via dpdk1. The VPN server also acts as the NAT gateway for both subnets.<\/p>\n\n<p>Example VPP configuration:<\/p>\n<p><pre class=\"plain\"><code class='language-plain'># 1) Interface configuration\nset interface ip address dpdk0 dhcp client         # Public internet\nset interface ip address dpdk1 10.10.2.10\/24       # Internal server subnet\nset interface state dpdk0 up\nset interface state dpdk1 up\n\n# 2) WireGuard setup\nwireguard create listen-port 51820 private-key &lt;server-private-key&gt;\nset interface ip address wg0 10.100.1.1\/24\nset interface state wg0 up\n\n# 3) Peer configuration\nwireguard peer add wg0 \\\n    public-key &lt;client-public-key&gt; \\\n    allowed-ip 10.100.1.2\/32 \\\n    persistent-keepalive 25\n\n# 4) Routing\nip route add 0.0.0.0\/0 via &lt;internet-gw&gt; dpdk0\nip route add 10.100.1.0\/24 via wg0\n\n# 5) Enable NAT (NAT44) for internet access\nnat44 plugin enable sessions 65535\nnat44 add interface address dpdk0        # SNAT on public interface\nset interface nat44 out dpdk0\nset interface nat44 in dpdk1             # DNAT\/MASQUERADE for internal\nset interface nat44 in wg0               # DNAT\/MASQUERADE for VPN<\/code><\/pre>\n<\/p>\n\n\n\n<p>Of course, on the servers of 10.10.2.0\/24, <code># ip route add 10.100.1.0\/24 via 10.10.2.10<\/code> should be added for &#8220;seeing&#8221; the vpn clients, 10.10.100.0\/24.<\/p>\n\n\n\n<p>And the client side:<\/p>\n\n\n\n<p><pre class=\"plain\"><code class=\"language-plain\">[Interface]\nPrivateKey = Client-Private-Key\nAddress = 10.100.1.2\/24\nDNS = 8.8.8.8\n\n[Peer]\nPublicKey = Server-public-key\nEndpoint = [Server IPV4\/6]:51820\nAllowedIPs = 0.0.0.0\/0, ::\/0\nPersistentKeepalive = 25<\/code><\/pre><\/p>\n\n\n\n<p>Here&#8217;s the results of the configuration:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Traffic Path<\/th><th>NAT Applied?<\/th><th>Explanation<\/th><th>Meets Requirements?<\/th><\/tr><\/thead><tbody><tr><td>VPN Clients \u2194 Internal Servers<\/td><td>\u274c No<\/td><td>Traffic between two &#8220;inside&#8221; interfaces has no NAT.<\/td><td>\u2705 Yes<\/td><\/tr><tr><td>VPN Clients \u2192 Internet (External Network)<\/td><td>\u2705 Yes<\/td><td>Traffic from an &#8220;inside&#8221; to an &#8220;outside&#8221; interface undergoes NAT.<\/td><td>\u2705 Yes<\/td><\/tr><tr><td>Internal Servers \u2192 Internet (External Network)<\/td><td>\u2705 Yes<\/td><td>Traffic from an &#8220;inside&#8221; to an &#8220;outside&#8221; interface undergoes NAT.<\/td><td>\u2705 Yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Optimization<\/strong><\/p>\n\n\n\n<p>If desktop CPUs are used, here are some optimization principles:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Maximize Single-Core Performance<\/strong>: Assign dedicated CPU cores explicitly to DPDK\/VPP tasks to minimize context switching overhead.<\/li>\n\n\n\n<li><strong>NUMA Node Optimization<\/strong>: Desktop CPUs typically have a single NUMA node; ensure DPDK memory allocation is configured accordingly.<\/li>\n\n\n\n<li><strong>CPU Isolation and Affinity<\/strong>: Explicitly isolate and bind VPP and DPDK threads to specific CPU cores.<\/li>\n\n\n\n<li><strong>Disable Power-Saving Features<\/strong>: Ensure CPU frequency stability by disabling dynamic frequency scaling and CPU power-saving modes.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The following note explains how to deploy a high-performance VPN using WireGuard on VPP with DPDK. This lets lab members connect to computation servers from anywhere on the campus network with minimal overhead.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,9],"tags":[32,33],"class_list":["post-399","post","type-post","status-publish","format-standard","hentry","category-misc","category-notes","tag-network","tag-vpn"],"_links":{"self":[{"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/posts\/399","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/comments?post=399"}],"version-history":[{"count":14,"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/posts\/399\/revisions"}],"predecessor-version":[{"id":415,"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/posts\/399\/revisions\/415"}],"wp:attachment":[{"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/media?parent=399"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/categories?post=399"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shirui.me\/blog\/wp-json\/wp\/v2\/tags?post=399"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}