Skip to content

Commit a55e052

Browse files
authored
Merge pull request #3724 from stek29/fix-udp-fwd
portfwd: create separate gRPC streams for each UDP client
2 parents b1216d8 + a04f244 commit a55e052

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

pkg/portfwd/client.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"fmt"
99
"net"
10+
"sync/atomic"
1011
"time"
1112

1213
"github.com/containers/gvisor-tap-vsock/pkg/services/forwarder"
@@ -40,33 +41,35 @@ func HandleTCPConnection(ctx context.Context, client *guestagentclient.GuestAgen
4041
}
4142

4243
func HandleUDPConnection(ctx context.Context, client *guestagentclient.GuestAgentClient, conn net.PacketConn, guestAddr string) {
43-
id := fmt.Sprintf("udp-%s", conn.LocalAddr().String())
44-
45-
stream, err := client.Tunnel(ctx)
46-
if err != nil {
47-
logrus.Errorf("could not open udp tunnel for id: %s error:%v", id, err)
48-
return
49-
}
50-
51-
// Handshake message to start tunnel
52-
if err := stream.Send(&api.TunnelMessage{Id: id, Protocol: "udp", GuestAddr: guestAddr}); err != nil {
53-
logrus.Errorf("could not start udp tunnel for id: %s error:%v", id, err)
54-
return
55-
}
44+
var udpConnectionCounter atomic.Uint32
45+
initialID := fmt.Sprintf("udp-%s", conn.LocalAddr().String())
5646

47+
// gvisor-tap-vsock's UDPProxy demultiplexes client connections internally based on their source address.
48+
// It calls this dialer function only when it receives a datagram from a new, unrecognized client.
49+
// For each new client, we must return a new net.Conn, which in our case is a new gRPC stream.
50+
// The atomic counter ensures that each stream has a unique ID to distinguish them on the server side.
5751
proxy, err := forwarder.NewUDPProxy(conn, func() (net.Conn, error) {
52+
id := fmt.Sprintf("%s-%d", initialID, udpConnectionCounter.Add(1))
53+
stream, err := client.Tunnel(ctx)
54+
if err != nil {
55+
return nil, fmt.Errorf("could not open udp tunnel for id: %s error:%w", id, err)
56+
}
57+
// Handshake message to start tunnel
58+
if err := stream.Send(&api.TunnelMessage{Id: id, Protocol: "udp", GuestAddr: guestAddr}); err != nil {
59+
return nil, fmt.Errorf("could not start udp tunnel for id: %s error:%w", id, err)
60+
}
5861
rw := &GrpcClientRW{stream: stream, id: id, addr: guestAddr, protocol: "udp"}
5962
return rw, nil
6063
})
6164
if err != nil {
62-
logrus.Errorf("error in udp tunnel proxy for id: %s error:%v", id, err)
65+
logrus.Errorf("error in udp tunnel proxy for id: %s error:%v", initialID, err)
6366
return
6467
}
6568

6669
defer func() {
6770
err := proxy.Close()
6871
if err != nil {
69-
logrus.Errorf("error in closing udp tunnel proxy for id: %s error:%v", id, err)
72+
logrus.Errorf("error in closing udp tunnel proxy for id: %s error:%v", initialID, err)
7073
}
7174
}()
7275
proxy.Run()

0 commit comments

Comments
 (0)