@@ -12,6 +12,7 @@ import (
1212 "time"
1313
1414 "github.com/dpeckett/network"
15+ "github.com/prometheus/client_golang/prometheus"
1516 "golang.zx2c4.com/wireguard/tun"
1617
1718 "gvisor.dev/gvisor/pkg/buffer"
@@ -30,6 +31,12 @@ import (
3031
3132const IPv6MinMTU = 1280 // IPv6 minimum MTU, required for some PPPoE links.
3233
34+ // TunnelMTU is the MTU used for tunnel TUN devices. Sized to fit in a single
35+ // QUIC datagram after PMTUD on a typical 1500-byte internet path:
36+ // 1500 (Ethernet) - 20 (IP) - 8 (UDP) - ~26 (QUIC framing) - 1 (contextID) ≈ 1445.
37+ // We use 1420 to leave headroom for path variance.
38+ const TunnelMTU = 1420
39+
3340var _ tun.Device = (* TunDevice )(nil )
3441
3542type TunDevice struct {
@@ -80,18 +87,18 @@ func NewTunDevice(pcapPath string) (*TunDevice, error) {
8087
8188 // High-performance TCP buffer settings.
8289 tcpRcvBuf := tcpip.TCPReceiveBufferSizeRangeOption {
83- Min : 64 << 10 , // 64 KiB
84- Default : 2 << 20 , // 2 MiB
85- Max : 16 << 20 , // 16 MiB
90+ Min : 64 << 10 , // 64 KiB
91+ Default : 2 << 20 , // 2 MiB
92+ Max : 16 << 20 , // 16 MiB
8693 }
8794 tcpipErr = ipstack .SetTransportProtocolOption (tcp .ProtocolNumber , & tcpRcvBuf )
8895 if tcpipErr != nil {
8996 return nil , fmt .Errorf ("could not set TCP receive buffer size: %v" , tcpipErr )
9097 }
9198 tcpSndBuf := tcpip.TCPSendBufferSizeRangeOption {
92- Min : 64 << 10 , // 64 KiB
93- Default : 2 << 20 , // 2 MiB
94- Max : 16 << 20 , // 16 MiB
99+ Min : 64 << 10 , // 64 KiB
100+ Default : 2 << 20 , // 2 MiB
101+ Max : 16 << 20 , // 16 MiB
95102 }
96103 tcpipErr = ipstack .SetTransportProtocolOption (tcp .ProtocolNumber , & tcpSndBuf )
97104 if tcpipErr != nil {
@@ -129,7 +136,7 @@ func NewTunDevice(pcapPath string) (*TunDevice, error) {
129136 }
130137
131138 nicID := ipstack .NextNICID ()
132- linkEP := channel .New (4096 , uint32 (IPv6MinMTU ), "" )
139+ linkEP := channel .New (4096 , uint32 (TunnelMTU ), "" )
133140 var nicEP stack.LinkEndpoint = linkEP
134141
135142 var pcapFile * os.File
@@ -361,6 +368,36 @@ func (tun *TunDevice) ListenPacket(addr netip.AddrPort) (net.PacketConn, error)
361368 return gonet .DialUDP (tun .stack , fa , nil , protoNum )
362369}
363370
371+ // RegisterTCPStatsMetrics registers netstack TCP stats as Prometheus gauges
372+ // that are read at push/scrape time. Call once after creating the TunDevice.
373+ func (tun * TunDevice ) RegisterTCPStatsMetrics (reg prometheus.Registerer ) {
374+ s := tun .stack .Stats ().TCP
375+ gauges := []struct {
376+ name string
377+ help string
378+ fn func () float64
379+ }{
380+ {"tunnel_netstack_tcp_segments_sent_total" , "TCP segments sent." , func () float64 { return float64 (s .SegmentsSent .Value ()) }},
381+ {"tunnel_netstack_tcp_segments_received_total" , "TCP segments received." , func () float64 { return float64 (s .ValidSegmentsReceived .Value ()) }},
382+ {"tunnel_netstack_tcp_retransmits_total" , "TCP segments retransmitted." , func () float64 { return float64 (s .Retransmits .Value ()) }},
383+ {"tunnel_netstack_tcp_fast_retransmit_total" , "TCP fast retransmits." , func () float64 { return float64 (s .FastRetransmit .Value ()) }},
384+ {"tunnel_netstack_tcp_slow_start_retransmits_total" , "TCP slow start retransmits." , func () float64 { return float64 (s .SlowStartRetransmits .Value ()) }},
385+ {"tunnel_netstack_tcp_timeouts_total" , "TCP RTO timeouts." , func () float64 { return float64 (s .Timeouts .Value ()) }},
386+ {"tunnel_netstack_tcp_fast_recovery_total" , "TCP fast recovery events." , func () float64 { return float64 (s .FastRecovery .Value ()) }},
387+ {"tunnel_netstack_tcp_sack_recovery_total" , "TCP SACK recovery events." , func () float64 { return float64 (s .SACKRecovery .Value ()) }},
388+ {"tunnel_netstack_tcp_checksum_errors_total" , "TCP checksum errors." , func () float64 { return float64 (s .ChecksumErrors .Value ()) }},
389+ {"tunnel_netstack_tcp_established" , "Current established TCP connections." , func () float64 { return float64 (s .CurrentEstablished .Value ()) }},
390+ {"tunnel_netstack_tcp_resets_sent_total" , "TCP resets sent." , func () float64 { return float64 (s .ResetsSent .Value ()) }},
391+ {"tunnel_netstack_tcp_resets_received_total" , "TCP resets received." , func () float64 { return float64 (s .ResetsReceived .Value ()) }},
392+ }
393+ for _ , g := range gauges {
394+ reg .MustRegister (prometheus .NewGaugeFunc (
395+ prometheus.GaugeOpts {Name : g .name , Help : g .help },
396+ g .fn ,
397+ ))
398+ }
399+ }
400+
364401// ForwardTo forwards all inbound traffic to the upstream network.
365402func (tun * TunDevice ) ForwardTo (ctx context.Context , upstream network.Network ) error {
366403 // Allow outgoing packets to have a source address different from the address
0 commit comments