• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stillya / wg-relay / 20759018163

06 Jan 2026 07:04PM UTC coverage: 28.278% (-0.1%) from 28.375%
20759018163

push

github

stillya
feat(dataplane): Add offload mode to xdp path

0 of 5 new or added lines in 2 files covered. (0.0%)

1 existing line in 1 file now uncovered.

248 of 877 relevant lines covered (28.28%)

0.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pkg/dataplane/proxy/forward.go
1
package proxy
2

3
import (
4
        "context"
5
        "net"
6

7
        log "log/slog"
8

9
        "github.com/cilium/ebpf"
10
        "github.com/cilium/ebpf/link"
11
        "github.com/pkg/errors"
12
        "github.com/stillya/wg-relay/pkg/dataplane/config"
13

14
        wgebpf "github.com/stillya/wg-relay/ebpf"
15
        "github.com/stillya/wg-relay/pkg/dataplane/maps"
16
)
17

18
// ForwardLoader manages XDP-based forward proxy
19
type ForwardLoader struct {
20
        cfg   config.ProxyConfig
21
        objs  *wgebpf.WgForwardProxyObjects
22
        links []link.Link
23
}
24

25
// NewForwardLoader creates a new forward proxy loader
26
func NewForwardLoader() (*ForwardLoader, error) {
×
27
        return &ForwardLoader{}, nil
×
28
}
×
29

30
// LoadAndAttach loads the forward proxy program and attaches it to interfaces
31
func (fp *ForwardLoader) LoadAndAttach(ctx context.Context, cfg config.ProxyConfig) error {
×
32
        fp.cfg = cfg
×
33

×
34
        if err := fp.loadEBPF(); err != nil {
×
35
                return errors.Wrap(err, "failed to load eBPF objects")
×
36
        }
×
37

38
        if err := fp.configure(cfg); err != nil {
×
39
                return errors.Wrap(err, "failed to configure eBPF maps")
×
40
        }
×
41

42
        if err := fp.attachToInterfaces(); err != nil {
×
43
                fp.Close()
×
44
                return errors.Wrap(err, "failed to attach to interfaces")
×
45
        }
×
46

47
        log.Info("Forward proxy loaded and attached",
×
48
                "enabled", cfg.Enabled,
×
49
                "method", cfg.Method,
×
50
                "target_server_ip", cfg.Forward.TargetServerIP)
×
51

×
52
        return nil
×
53
}
54

55
// configure configures the eBPF maps with the provided configuration
56
func (fp *ForwardLoader) configure(cfg config.ProxyConfig) error {
×
57
        if fp.objs == nil || fp.objs.ObfuscationConfigMap == nil {
×
58
                return errors.New("eBPF objects not loaded")
×
59
        }
×
60

61
        targetServerIP, err := cfg.GetTargetServerIP()
×
62
        if err != nil {
×
63
                return errors.Wrap(err, "failed to get target server IP")
×
64
        }
×
65

66
        keyBytes := cfg.GetKeyBytes()
×
67
        epbfConfig := wgebpf.WgForwardProxyObfuscationConfig{
×
68
                Enabled:        true,
×
69
                Method:         uint8(cfg.GetMethod()),
×
70
                KeyLen:         uint8(len(keyBytes)),
×
71
                TargetServerIp: targetServerIP,
×
72
        }
×
73

×
74
        if !cfg.Enabled {
×
75
                epbfConfig.Enabled = false
×
76
        }
×
77

78
        if len(keyBytes) > len(epbfConfig.Key) {
×
79
                return errors.Errorf("key too long: %d bytes, max %d", len(keyBytes), len(epbfConfig.Key))
×
80
        }
×
81
        copy(epbfConfig.Key[:], keyBytes)
×
82

×
83
        configKey := uint32(0)
×
84
        if err := fp.objs.ObfuscationConfigMap.Put(&configKey, &epbfConfig); err != nil {
×
85
                return errors.Wrap(err, "failed to update forward epbfConfig map")
×
86
        }
×
87

88
        return nil
×
89
}
90

91
// loadEBPF loads the forward proxy eBPF program
92
func (fp *ForwardLoader) loadEBPF() error {
×
93
        fp.objs = &wgebpf.WgForwardProxyObjects{}
×
94

×
95
        opts := &ebpf.CollectionOptions{
×
96
                Programs: ebpf.ProgramOptions{
×
97
                        LogLevel:     2,
×
98
                        LogSizeStart: 16777216, // 16 MB log size
×
99
                },
×
100
        }
×
101

×
102
        if err := wgebpf.LoadWgForwardProxyObjects(fp.objs, opts); err != nil {
×
103
                return errors.Wrap(err, "failed to load forward proxy eBPF objects")
×
104
        }
×
105

106
        log.Info("Forward proxy eBPF program loaded")
×
107
        return nil
×
108
}
109

110
// attachToInterfaces attaches the XDP program to configured interfaces
111
func (fp *ForwardLoader) attachToInterfaces() error {
×
112
        for _, interfaceName := range fp.cfg.Interfaces {
×
113
                if err := fp.attachToInterface(interfaceName); err != nil {
×
114
                        fp.cleanupLinks()
×
115
                        return errors.Wrapf(err, "failed to attach to interface %s", interfaceName)
×
116
                }
×
117
        }
118
        return nil
×
119
}
120

121
// attachToInterface attaches XDP program to a single interface
122
func (fp *ForwardLoader) attachToInterface(interfaceName string) error {
×
123
        iface, err := net.InterfaceByName(interfaceName)
×
124
        if err != nil {
×
125
                return errors.Wrapf(err, "failed to get interface %s", interfaceName)
×
126
        }
×
127

128
        var flags link.XDPAttachFlags
×
129
        var mode string
×
130
        switch fp.cfg.DriverMode {
×
131
        case "generic":
×
132
                flags = link.XDPGenericMode
×
133
                mode = "generic"
×
134
        case "driver":
×
135
                flags = link.XDPDriverMode
×
136
                mode = "driver"
×
NEW
137
        case "offload":
×
NEW
138
                flags = link.XDPOffloadMode
×
NEW
139
                mode = "offload"
×
140
        default:
×
141
                // Default to driver mode
×
142
                flags = link.XDPDriverMode
×
143
                mode = "driver"
×
144
        }
145

146
        log.Info("Attaching XDP forward proxy", "interface", interfaceName, "index", iface.Index, "mode", mode)
×
147

×
148
        xdpLink, err := link.AttachXDP(link.XDPOptions{
×
149
                Program:   fp.objs.WgForwardProxy,
×
150
                Interface: iface.Index,
×
151
                Flags:     flags,
×
152
        })
×
153
        if err != nil {
×
154
                return errors.Wrapf(err, "failed to attach XDP program to interface %s in %s mode", interfaceName, mode)
×
155
        }
×
156

157
        log.Info("XDP forward proxy attached successfully", "interface", interfaceName, "mode", mode)
×
158
        fp.links = append(fp.links, xdpLink)
×
159
        return nil
×
160
}
161

162
// cleanupLinks cleans up all attached links
163
func (fp *ForwardLoader) cleanupLinks() {
×
164
        for _, l := range fp.links {
×
165
                if l != nil {
×
166
                        err := l.Close()
×
167
                        if err != nil {
×
168
                                log.Error("Failed to close XDP link", "error", err)
×
169
                        } else {
×
170
                                log.Info("XDP link closed successfully")
×
171
                        }
×
172
                }
173
        }
174
        fp.links = nil
×
175
}
176

177
// Close cleans up all resources
178
func (fp *ForwardLoader) Close() error {
×
179
        var errs []error
×
180

×
181
        for i, l := range fp.links {
×
182
                if l != nil {
×
183
                        if err := l.Close(); err != nil {
×
184
                                errs = append(errs, errors.Wrapf(err, "failed to close XDP l %d", i))
×
185
                        }
×
186
                }
187
        }
188

189
        if fp.objs != nil {
×
190
                if err := fp.objs.Close(); err != nil {
×
191
                        errs = append(errs, errors.Wrap(err, "failed to close forward proxy eBPF objects"))
×
192
                }
×
193
        }
194

195
        if len(errs) > 0 {
×
196
                return errs[0]
×
197
        }
×
198

199
        return nil
×
200
}
201

202
// Maps returns all eBPF maps used by the forward proxy
203
func (fp *ForwardLoader) Maps() *maps.Maps {
×
204
        var metricsMap *ebpf.Map
×
205
        if fp.objs != nil {
×
206
                metricsMap = fp.objs.MetricsMap
×
207
        }
×
208

209
        mapsCollection := maps.NewMaps(metricsMap)
×
210

×
211
        if fp.objs != nil {
×
212
                if fp.objs.ConnectionMap != nil {
×
213
                        mapsCollection.AddOtherMap("ConnectionMap", fp.objs.ConnectionMap)
×
214
                }
×
215

216
                if fp.objs.NatReverseMap != nil {
×
217
                        mapsCollection.AddOtherMap("NatReverseMap", fp.objs.NatReverseMap)
×
218
                }
×
219
        }
220

221
        return mapsCollection
×
222
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc