Skip to content

Commit 307b151

Browse files
committed
netstack/seamless: attach/detach network dispatcher as approp
1 parent af7da3a commit 307b151

2 files changed

Lines changed: 154 additions & 134 deletions

File tree

intra/netstack/fdbased.go

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ import (
4848

4949
var _ stack.InjectableLinkEndpoint = (*endpoint)(nil)
5050
var _ stack.LinkEndpoint = (*endpoint)(nil)
51-
var _ stack.LinkEndpoint = (*linkSwap)(nil)
52-
var _ FdSwapper = (*linkSwap)(nil)
5351

5452
// placeholder FD for whenever existing FD wrapped in struct fds is closed.
5553
const invalidfd int = -1
@@ -62,51 +60,6 @@ const waitttl = wrapttl
6260

6361
var errNeedsNewEndpoint = errors.New("ns: needs new endpoint")
6462

65-
type FdSwapper interface {
66-
// Swap closes existing FDs; uses new fd.
67-
Swap(fd int) error
68-
// Dispose closes all existing FDs.
69-
Dispose() error
70-
// Stat returns EpStat (fd, age, read, written, lastRead, lastWrite).
71-
Stat() EpStat
72-
}
73-
74-
type EpStat struct {
75-
// Fd is the file descriptor of the endpoint.
76-
Fd int
77-
// Alive indicates whether the endpoint is alive.
78-
Alive bool
79-
// Age is the age of the endpoint.
80-
Age string
81-
// Read is the number of bytes read from the endpoint.
82-
Read string
83-
// Written is the number of bytes written to the endpoint.
84-
Written string
85-
// LastRead is the last time the endpoint was read from.
86-
LastRead string
87-
// LastWrite is the last time the endpoint was written to.
88-
LastWrite string
89-
}
90-
91-
func (s EpStat) String() string {
92-
if s.Fd == 0 {
93-
return "<nil>"
94-
}
95-
return fmt.Sprintf("Fd: %d,Alive: %t,Age: %s,R: %s,W: %s,LastRead: %s,LastWrite: %s",
96-
s.Fd,
97-
s.Alive,
98-
s.Age,
99-
s.Read,
100-
s.Written,
101-
s.LastRead,
102-
s.LastWrite)
103-
}
104-
105-
type SeamlessEndpoint interface {
106-
stack.LinkEndpoint
107-
FdSwapper
108-
}
109-
11063
// linkDispatcher reads packets from the link FD and dispatches them to the
11164
// NetworkDispatcher.
11265
type linkDispatcher interface {

intra/netstack/seamless.go

Lines changed: 154 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package netstack
22

33
import (
44
"errors"
5+
"fmt"
56
"io"
67
"strconv"
78
"strings"
8-
"sync"
99
"syscall"
1010

1111
"github.com/celzero/firestack/intra/core"
@@ -21,15 +21,64 @@ import (
2121
const SnapLen uint32 = 2048 // in bytes; some sufficient value
2222

2323
var (
24-
errNoFdSwapper = errors.New("linkFdSwap: no FdSwapper")
24+
errNoFdSwapper = errors.New("magiclink: no FdSwapper")
2525
)
2626

27-
type linkSwap struct {
28-
sync.Mutex
29-
e stack.LinkEndpoint
27+
type FdSwapper interface {
28+
// Swap closes existing FDs; uses new fd.
29+
Swap(fd int) error
30+
// Dispose closes all existing FDs.
31+
Dispose() error
32+
// Stat returns EpStat (fd, age, read, written, lastRead, lastWrite).
33+
Stat() EpStat
34+
}
35+
36+
type EpStat struct {
37+
// Fd is the file descriptor of the endpoint.
38+
Fd int
39+
// Alive indicates whether the endpoint is alive.
40+
Alive bool
41+
// Age is the age of the endpoint.
42+
Age string
43+
// Read is the number of bytes read from the endpoint.
44+
Read string
45+
// Written is the number of bytes written to the endpoint.
46+
Written string
47+
// LastRead is the last time the endpoint was read from.
48+
LastRead string
49+
// LastWrite is the last time the endpoint was written to.
50+
LastWrite string
51+
}
52+
53+
func (s EpStat) String() string {
54+
if s.Fd == 0 {
55+
return "<nil>"
56+
}
57+
return fmt.Sprintf("Fd: %d,Alive: %t,Age: %s,R: %s,W: %s,LastRead: %s,LastWrite: %s",
58+
s.Fd,
59+
s.Alive,
60+
s.Age,
61+
s.Read,
62+
s.Written,
63+
s.LastRead,
64+
s.LastWrite)
65+
}
66+
67+
type SeamlessEndpoint interface {
68+
stack.LinkEndpoint
3069
FdSwapper
3170
}
3271

72+
type magiclink struct {
73+
e *core.Volatile[stack.LinkEndpoint]
74+
d *core.Volatile[stack.NetworkDispatcher]
75+
FdSwapper
76+
}
77+
78+
var _ stack.LinkEndpoint = (*magiclink)(nil)
79+
var _ stack.NetworkDispatcher = (*magiclink)(nil)
80+
var _ FdSwapper = (*magiclink)(nil)
81+
3382
// ref: github.com/google/gvisor/blob/91f58d2cc/pkg/tcpip/sample/tun_tcp_echo/main.go#L102
3483
func NewEndpoint(dev, mtu int, sink io.WriteCloser) (ep SeamlessEndpoint, err error) {
3584
defer func() {
@@ -60,7 +109,9 @@ func snoop(ep SeamlessEndpoint, sink io.WriteCloser) (SeamlessEndpoint, error) {
60109
if link, err := NewSnoopyEndpoint(ep, sink); err != nil {
61110
return nil, err
62111
} else {
63-
return &linkSwap{sync.Mutex{}, link, ep}, nil
112+
v := core.NewVolatile[stack.LinkEndpoint](link)
113+
d := core.NewZeroVolatile[stack.NetworkDispatcher]()
114+
return &magiclink{v, d, ep}, nil
64115
}
65116
}
66117

@@ -103,7 +154,7 @@ func PcapModes() string {
103154
}
104155

105156
// Swap implements FdSwapper.
106-
func (l *linkSwap) Swap(fd int) error {
157+
func (l *magiclink) Swap(fd int) error {
107158
if l.FdSwapper == nil {
108159
return errNoFdSwapper
109160
}
@@ -116,120 +167,136 @@ func (l *linkSwap) Swap(fd int) error {
116167
MTU: umtu,
117168
}
118169
if ep, err := newFdbasedInjectableEndpoint(&opt); err == nil {
119-
l.Lock()
120-
core.Go("linkFdSwap."+strconv.Itoa(fd), l.e.Close)
121-
l.e = ep
122-
l.Unlock()
170+
if old := l.e.Swap(ep); old != nil {
171+
core.Go("magic."+strconv.Itoa(fd), old.Close)
172+
}
173+
if l.d.Load() == nil {
174+
log.W("netstack: %d magic(mtu: %d); new ep but no dispatcher", fd, umtu)
175+
ep.Attach(nil) // attach the new endpoint to the dispatcher
176+
} else {
177+
log.I("netstack: %d magic(mtu: %d); new ep, attaching dispatcher", fd, umtu)
178+
ep.Attach(l) // attach the new endpoint to the existing dispatcher
179+
}
123180
} else {
124-
log.E("netstack: linkFdSwap(%d); err %v", fd, err)
181+
log.E("netstack: magic(%d); err %v", fd, err)
125182
return err
126183
}
127184
}
128185

129186
return err
130187
}
131188

132-
func (l *linkSwap) MTU() uint32 {
133-
l.Lock()
134-
e := l.e
135-
l.Unlock()
136-
return e.MTU()
189+
func (l *magiclink) MTU() uint32 {
190+
if e := l.e.Load(); e != nil {
191+
return e.MTU()
192+
}
193+
return 0
194+
}
195+
196+
func (l *magiclink) SetMTU(mtu uint32) {
197+
if e := l.e.Load(); e != nil {
198+
e.SetMTU(mtu)
199+
}
200+
}
201+
202+
func (l *magiclink) MaxHeaderLength() uint16 {
203+
if e := l.e.Load(); e != nil {
204+
return e.MaxHeaderLength()
205+
}
206+
return 0
137207
}
138208

139-
func (l *linkSwap) SetMTU(mtu uint32) {
140-
l.Lock()
141-
e := l.e
142-
l.Unlock()
143-
e.SetMTU(mtu)
209+
func (l *magiclink) LinkAddress() tcpip.LinkAddress {
210+
if e := l.e.Load(); e != nil {
211+
return e.LinkAddress()
212+
}
213+
return ""
144214
}
145215

146-
func (l *linkSwap) MaxHeaderLength() uint16 {
147-
l.Lock()
148-
e := l.e
149-
l.Unlock()
150-
return e.MaxHeaderLength()
216+
func (l *magiclink) SetLinkAddress(addr tcpip.LinkAddress) {
217+
if e := l.e.Load(); e != nil {
218+
e.SetLinkAddress(addr)
219+
}
151220
}
152221

153-
func (l *linkSwap) LinkAddress() tcpip.LinkAddress {
154-
l.Lock()
155-
e := l.e
156-
l.Unlock()
157-
return e.LinkAddress()
222+
func (l *magiclink) Capabilities() stack.LinkEndpointCapabilities {
223+
if e := l.e.Load(); e != nil {
224+
return e.Capabilities()
225+
}
226+
return 0
158227
}
159228

160-
func (l *linkSwap) SetLinkAddress(addr tcpip.LinkAddress) {
161-
l.Lock()
162-
e := l.e
163-
l.Unlock()
164-
e.SetLinkAddress(addr)
229+
func (l *magiclink) Attach(dispatcher stack.NetworkDispatcher) {
230+
l.d.Store(dispatcher) // update the dispatcher
231+
if e := l.e.Load(); e != nil {
232+
if dispatcher == nil {
233+
e.Attach(nil) // detach
234+
} else {
235+
e.Attach(l)
236+
}
237+
}
165238
}
166239

167-
func (l *linkSwap) Capabilities() stack.LinkEndpointCapabilities {
168-
l.Lock()
169-
e := l.e
170-
l.Unlock()
171-
return e.Capabilities()
240+
func (l *magiclink) IsAttached() bool {
241+
if e := l.e.Load(); e != nil {
242+
return e.IsAttached()
243+
}
244+
return false
172245
}
173246

174-
func (l *linkSwap) Attach(dispatcher stack.NetworkDispatcher) {
175-
l.Lock()
176-
e := l.e
177-
l.Unlock()
178-
e.Attach(dispatcher)
247+
func (l *magiclink) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
248+
if d := l.d.Load(); d != nil {
249+
d.DeliverNetworkPacket(protocol, pkt)
250+
}
179251
}
180252

181-
func (l *linkSwap) IsAttached() bool {
182-
l.Lock()
183-
e := l.e
184-
l.Unlock()
185-
return e.IsAttached()
253+
func (l *magiclink) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
254+
if d := l.d.Load(); d != nil {
255+
d.DeliverLinkPacket(protocol, pkt)
256+
}
186257
}
187258

188-
func (l *linkSwap) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
189-
l.Lock()
190-
e := l.e
191-
l.Unlock()
192-
return e.WritePackets(pkts)
259+
func (l *magiclink) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
260+
if e := l.e.Load(); e != nil {
261+
return e.WritePackets(pkts)
262+
}
263+
return 0, &tcpip.ErrInvalidEndpointState{}
193264
}
194265

195-
func (l *linkSwap) Wait() {
196-
l.Lock()
197-
e := l.e
198-
l.Unlock()
199-
e.Wait()
266+
func (l *magiclink) Wait() {
267+
if e := l.e.Load(); e != nil {
268+
e.Wait()
269+
}
200270
}
201271

202-
func (l *linkSwap) ARPHardwareType() header.ARPHardwareType {
203-
l.Lock()
204-
e := l.e
205-
l.Unlock()
206-
return e.ARPHardwareType()
272+
func (l *magiclink) ARPHardwareType() header.ARPHardwareType {
273+
if e := l.e.Load(); e != nil {
274+
return e.ARPHardwareType()
275+
}
276+
return 0
207277
}
208278

209-
func (l *linkSwap) AddHeader(pkt *stack.PacketBuffer) {
210-
l.Lock()
211-
e := l.e
212-
l.Unlock()
213-
e.AddHeader(pkt)
279+
func (l *magiclink) AddHeader(pkt *stack.PacketBuffer) {
280+
if e := l.e.Load(); e != nil {
281+
e.AddHeader(pkt)
282+
}
214283
}
215284

216-
func (l *linkSwap) ParseHeader(pkt *stack.PacketBuffer) bool {
217-
l.Lock()
218-
e := l.e
219-
l.Unlock()
220-
return e.ParseHeader(pkt)
285+
func (l *magiclink) ParseHeader(pkt *stack.PacketBuffer) bool {
286+
if e := l.e.Load(); e != nil {
287+
return e.ParseHeader(pkt)
288+
}
289+
return false
221290
}
222291

223-
func (l *linkSwap) Close() {
224-
l.Lock()
225-
e := l.e
226-
l.Unlock()
227-
e.Close()
292+
func (l *magiclink) Close() {
293+
if e := l.e.Load(); e != nil {
294+
e.Close()
295+
}
228296
}
229297

230-
func (l *linkSwap) SetOnCloseAction(f func()) {
231-
l.Lock()
232-
e := l.e
233-
l.Unlock()
234-
e.SetOnCloseAction(f)
298+
func (l *magiclink) SetOnCloseAction(f func()) {
299+
if e := l.e.Load(); e != nil {
300+
e.SetOnCloseAction(f)
301+
}
235302
}

0 commit comments

Comments
 (0)