From 04f47eabf797e2d5b315b9a2b8d371928ffb5155 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 21 Nov 2025 23:38:26 -0600 Subject: [PATCH] Better hot path benchmarks, minor fixups --- e2e/handshakes_test.go | 39 ++++++++++++++++++++++++++++++++++++++- e2e/helpers_test.go | 8 ++++---- outside.go | 16 +--------------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/e2e/handshakes_test.go b/e2e/handshakes_test.go index 757cfd1..67b166b 100644 --- a/e2e/handshakes_test.go +++ b/e2e/handshakes_test.go @@ -25,11 +25,12 @@ import ( func BenchmarkHotPath(b *testing.B) { ca, _, caKey, _ := cert_test.NewTestCaCert(cert.Version1, cert.Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{}) - myControl, myVpnIpNet, _, _ := newSimpleServer(cert.Version1, ca, caKey, "me", "10.128.0.1/24", nil) + myControl, myVpnIpNet, myUdpAddr, _ := newSimpleServer(cert.Version1, ca, caKey, "me", "10.128.0.1/24", nil) theirControl, theirVpnIpNet, theirUdpAddr, _ := newSimpleServer(cert.Version1, ca, caKey, "them", "10.128.0.2/24", nil) // Put their info in our lighthouse myControl.InjectLightHouseAddr(theirVpnIpNet[0].Addr(), theirUdpAddr) + theirControl.InjectLightHouseAddr(myVpnIpNet[0].Addr(), myUdpAddr) // Start the servers myControl.Start() @@ -38,6 +39,9 @@ func BenchmarkHotPath(b *testing.B) { r := router.NewR(b, myControl, theirControl) r.CancelFlowLogs() + assertTunnel(b, myVpnIpNet[0].Addr(), theirVpnIpNet[0].Addr(), myControl, theirControl, r) + b.ResetTimer() + for n := 0; n < b.N; n++ { myControl.InjectTunUDPPacket(theirVpnIpNet[0].Addr(), 80, myVpnIpNet[0].Addr(), 80, []byte("Hi from me")) _ = r.RouteForAllUntilTxTun(theirControl) @@ -47,6 +51,39 @@ func BenchmarkHotPath(b *testing.B) { theirControl.Stop() } +func BenchmarkHotPathRelay(b *testing.B) { + ca, _, caKey, _ := cert_test.NewTestCaCert(cert.Version1, cert.Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{}) + myControl, myVpnIpNet, _, _ := newSimpleServer(cert.Version1, ca, caKey, "me ", "10.128.0.1/24", m{"relay": m{"use_relays": true}}) + relayControl, relayVpnIpNet, relayUdpAddr, _ := newSimpleServer(cert.Version1, ca, caKey, "relay ", "10.128.0.128/24", m{"relay": m{"am_relay": true}}) + theirControl, theirVpnIpNet, theirUdpAddr, _ := newSimpleServer(cert.Version1, ca, caKey, "them ", "10.128.0.2/24", m{"relay": m{"use_relays": true}}) + + // Teach my how to get to the relay and that their can be reached via the relay + myControl.InjectLightHouseAddr(relayVpnIpNet[0].Addr(), relayUdpAddr) + myControl.InjectRelays(theirVpnIpNet[0].Addr(), []netip.Addr{relayVpnIpNet[0].Addr()}) + relayControl.InjectLightHouseAddr(theirVpnIpNet[0].Addr(), theirUdpAddr) + + // Build a router so we don't have to reason who gets which packet + r := router.NewR(b, myControl, relayControl, theirControl) + r.CancelFlowLogs() + + // Start the servers + myControl.Start() + relayControl.Start() + theirControl.Start() + + assertTunnel(b, theirVpnIpNet[0].Addr(), myVpnIpNet[0].Addr(), theirControl, myControl, r) + b.ResetTimer() + + for n := 0; n < b.N; n++ { + myControl.InjectTunUDPPacket(theirVpnIpNet[0].Addr(), 80, myVpnIpNet[0].Addr(), 80, []byte("Hi from me")) + _ = r.RouteForAllUntilTxTun(theirControl) + } + + myControl.Stop() + theirControl.Stop() + relayControl.Stop() +} + func TestGoodHandshake(t *testing.T) { ca, _, caKey, _ := cert_test.NewTestCaCert(cert.Version1, cert.Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{}) myControl, myVpnIpNet, myUdpAddr, _ := newSimpleServer(cert.Version1, ca, caKey, "me", "10.128.0.1/24", nil) diff --git a/e2e/helpers_test.go b/e2e/helpers_test.go index cb9fc37..7a802c9 100644 --- a/e2e/helpers_test.go +++ b/e2e/helpers_test.go @@ -292,7 +292,7 @@ func deadline(t *testing.T, seconds time.Duration) doneCb { } } -func assertTunnel(t *testing.T, vpnIpA, vpnIpB netip.Addr, controlA, controlB *nebula.Control, r *router.R) { +func assertTunnel(t testing.TB, vpnIpA, vpnIpB netip.Addr, controlA, controlB *nebula.Control, r *router.R) { // Send a packet from them to me controlB.InjectTunUDPPacket(vpnIpA, 80, vpnIpB, 90, []byte("Hi from B")) bPacket := r.RouteForAllUntilTxTun(controlA) @@ -325,7 +325,7 @@ func assertHostInfoPair(t *testing.T, addrA, addrB netip.AddrPort, vpnNetsA, vpn assert.Equal(t, hBinA.RemoteIndex, hAinB.LocalIndex, "Host B remote index does not match host A local index") } -func assertUdpPacket(t *testing.T, expected, b []byte, fromIp, toIp netip.Addr, fromPort, toPort uint16) { +func assertUdpPacket(t testing.TB, expected, b []byte, fromIp, toIp netip.Addr, fromPort, toPort uint16) { if toIp.Is6() { assertUdpPacket6(t, expected, b, fromIp, toIp, fromPort, toPort) } else { @@ -333,7 +333,7 @@ func assertUdpPacket(t *testing.T, expected, b []byte, fromIp, toIp netip.Addr, } } -func assertUdpPacket6(t *testing.T, expected, b []byte, fromIp, toIp netip.Addr, fromPort, toPort uint16) { +func assertUdpPacket6(t testing.TB, expected, b []byte, fromIp, toIp netip.Addr, fromPort, toPort uint16) { packet := gopacket.NewPacket(b, layers.LayerTypeIPv6, gopacket.Lazy) v6 := packet.Layer(layers.LayerTypeIPv6).(*layers.IPv6) assert.NotNil(t, v6, "No ipv6 data found") @@ -352,7 +352,7 @@ func assertUdpPacket6(t *testing.T, expected, b []byte, fromIp, toIp netip.Addr, assert.Equal(t, expected, data.Payload(), "Data was incorrect") } -func assertUdpPacket4(t *testing.T, expected, b []byte, fromIp, toIp netip.Addr, fromPort, toPort uint16) { +func assertUdpPacket4(t testing.TB, expected, b []byte, fromIp, toIp netip.Addr, fromPort, toPort uint16) { packet := gopacket.NewPacket(b, layers.LayerTypeIPv4, gopacket.Lazy) v4 := packet.Layer(layers.LayerTypeIPv4).(*layers.IPv4) assert.NotNil(t, v4, "No ipv4 data found") diff --git a/outside.go b/outside.go index ac7fa6d..b1a28e5 100644 --- a/outside.go +++ b/outside.go @@ -54,8 +54,6 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte, switch h.Type { case header.Message: - // TODO handleEncrypted sends directly to addr on error. Handle this in the tunneling case. - //TODO: RELAY-WORK ip could be relayed here if !f.handleEncrypted(ci, via, h) { return } @@ -146,21 +144,19 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte, return } - //NOTE: via should never be a relayed from here + //TODO: assert via is not relayed lhf.HandleRequest(via.UdpAddr, hostinfo.vpnAddrs, d, f) // Fallthrough to the bottom to record incoming traffic case header.Test: f.messageMetrics.Rx(h.Type, h.Subtype, 1) - //TODO: RELAY-WORK ip could be relayed here if !f.handleEncrypted(ci, via, h) { return } d, err := f.decrypt(hostinfo, h.MessageCounter, out, packet, h, nb) if err != nil { - //TODO: RELAY-WORK ip could be relayed here hostinfo.logger(f.l).WithError(err).WithField("from", via). WithField("packet", packet). Error("Failed to decrypt test packet") @@ -170,9 +166,7 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte, if h.Subtype == header.TestRequest { // This testRequest might be from TryPromoteBest, so we should roam // to the new IP address before responding - //TODO: RELAY-WORK ip could be relayed here f.handleHostRoaming(hostinfo, via) - //TODO: RELAY-WORK ip could be relayed here f.send(header.Test, header.TestReply, ci, hostinfo, d, nb, out) } @@ -183,24 +177,20 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte, case header.Handshake: f.messageMetrics.Rx(h.Type, h.Subtype, 1) - //TODO: RELAY-WORK ip could be relayed here f.handshakeManager.HandleIncoming(via, packet, h) return case header.RecvError: f.messageMetrics.Rx(h.Type, h.Subtype, 1) - //TODO: RELAY-WORK we should probably support recv_error better in the relays, pass via directly to handleRecvError f.handleRecvError(via.UdpAddr, h) return case header.CloseTunnel: f.messageMetrics.Rx(h.Type, h.Subtype, 1) - //TODO: RELAY-WORK ip could be relayed here if !f.handleEncrypted(ci, via, h) { return } - //TODO: RELAY-WORK ip could be relayed here hostinfo.logger(f.l).WithField("from", via). Info("Close tunnel received, tearing down.") @@ -208,15 +198,12 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte, return case header.Control: - //TODO: RELAY-WORK ip could be relayed here if !f.handleEncrypted(ci, via, h) { return } d, err := f.decrypt(hostinfo, h.MessageCounter, out, packet, h, nb) if err != nil { - - //TODO: RELAY-WORK ip could be relayed here hostinfo.logger(f.l).WithError(err).WithField("from", via). WithField("packet", packet). Error("Failed to decrypt Control packet") @@ -227,7 +214,6 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte, default: f.messageMetrics.Rx(h.Type, h.Subtype, 1) - //TODO: RELAY-WORK ip could be relayed here hostinfo.logger(f.l).Debugf("Unexpected packet received from %s", via) return }