github.com/database64128/shadowsocks-go@v1.7.0/service/udp_nat_mmsg.go (about)

     1  //go:build linux || netbsd
     2  
     3  package service
     4  
     5  import (
     6  	"bytes"
     7  	"errors"
     8  	"net/netip"
     9  	"os"
    10  	"sync/atomic"
    11  	"time"
    12  	"unsafe"
    13  
    14  	"github.com/database64128/shadowsocks-go/conn"
    15  	"github.com/database64128/shadowsocks-go/router"
    16  	"github.com/database64128/shadowsocks-go/zerocopy"
    17  	"go.uber.org/zap"
    18  	"golang.org/x/sys/unix"
    19  )
    20  
    21  // natUplinkMmsg is used for passing information about relay uplink to the relay goroutine.
    22  type natUplinkMmsg struct {
    23  	clientAddrPort netip.AddrPort
    24  	natConn        *conn.MmsgWConn
    25  	natConnSendCh  <-chan *natQueuedPacket
    26  	natConnPacker  zerocopy.ClientPacker
    27  }
    28  
    29  // natDownlinkMmsg is used for passing information about relay downlink to the relay goroutine.
    30  type natDownlinkMmsg struct {
    31  	clientAddrPort     netip.AddrPort
    32  	clientPktinfop     *[]byte
    33  	clientPktinfo      *atomic.Pointer[[]byte]
    34  	natConn            *conn.MmsgRConn
    35  	natConnRecvBufSize int
    36  	natConnUnpacker    zerocopy.ClientUnpacker
    37  	serverConn         *conn.MmsgWConn
    38  	serverConnPacker   zerocopy.ServerPacker
    39  }
    40  
    41  func (s *UDPNATRelay) setStartFunc(batchMode string) {
    42  	switch batchMode {
    43  	case "sendmmsg", "":
    44  		s.startFunc = s.startMmsg
    45  	default:
    46  		s.startFunc = s.startGeneric
    47  	}
    48  }
    49  
    50  func (s *UDPNATRelay) startMmsg() error {
    51  	serverConn, err := conn.ListenUDPRawConn(s.serverConnListenConfig, "udp", s.listenAddress)
    52  	if err != nil {
    53  		return err
    54  	}
    55  	s.serverConn = serverConn.UDPConn
    56  
    57  	s.mwg.Add(1)
    58  
    59  	go func() {
    60  		s.recvFromServerConnRecvmmsg(serverConn.RConn())
    61  		s.mwg.Done()
    62  	}()
    63  
    64  	s.logger.Info("Started UDP NAT relay service",
    65  		zap.String("server", s.serverName),
    66  		zap.String("listenAddress", s.listenAddress),
    67  	)
    68  
    69  	return nil
    70  }
    71  
    72  func (s *UDPNATRelay) recvFromServerConnRecvmmsg(serverConn *conn.MmsgRConn) {
    73  	n := s.serverRecvBatchSize
    74  	qpvec := make([]*natQueuedPacket, n)
    75  	namevec := make([]unix.RawSockaddrInet6, n)
    76  	iovec := make([]unix.Iovec, n)
    77  	cmsgvec := make([][]byte, n)
    78  	msgvec := make([]conn.Mmsghdr, n)
    79  
    80  	for i := range msgvec {
    81  		cmsgBuf := make([]byte, conn.SocketControlMessageBufferSize)
    82  		cmsgvec[i] = cmsgBuf
    83  		msgvec[i].Msghdr.Name = (*byte)(unsafe.Pointer(&namevec[i]))
    84  		msgvec[i].Msghdr.Namelen = unix.SizeofSockaddrInet6
    85  		msgvec[i].Msghdr.Iov = &iovec[i]
    86  		msgvec[i].Msghdr.SetIovlen(1)
    87  		msgvec[i].Msghdr.Control = &cmsgBuf[0]
    88  	}
    89  
    90  	var (
    91  		err                  error
    92  		recvmmsgCount        uint64
    93  		packetsReceived      uint64
    94  		payloadBytesReceived uint64
    95  		burstBatchSize       int
    96  	)
    97  
    98  	for {
    99  		for i := range iovec[:n] {
   100  			queuedPacket := s.getQueuedPacket()
   101  			qpvec[i] = queuedPacket
   102  			iovec[i].Base = &queuedPacket.buf[s.packetBufFrontHeadroom]
   103  			iovec[i].SetLen(s.packetBufRecvSize)
   104  			msgvec[i].Msghdr.SetControllen(conn.SocketControlMessageBufferSize)
   105  		}
   106  
   107  		n, err = serverConn.ReadMsgs(msgvec, 0)
   108  		if err != nil {
   109  			if errors.Is(err, os.ErrDeadlineExceeded) {
   110  				break
   111  			}
   112  
   113  			s.logger.Warn("Failed to batch read packets from serverConn",
   114  				zap.String("server", s.serverName),
   115  				zap.String("listenAddress", s.listenAddress),
   116  				zap.Error(err),
   117  			)
   118  
   119  			n = 1
   120  			s.putQueuedPacket(qpvec[0])
   121  			continue
   122  		}
   123  
   124  		recvmmsgCount++
   125  		packetsReceived += uint64(n)
   126  		if burstBatchSize < n {
   127  			burstBatchSize = n
   128  		}
   129  
   130  		s.mu.Lock()
   131  
   132  		msgvecn := msgvec[:n]
   133  
   134  		for i := range msgvecn {
   135  			msg := &msgvecn[i]
   136  			queuedPacket := qpvec[i]
   137  
   138  			if msg.Msghdr.Controllen == 0 {
   139  				s.logger.Warn("Skipping packet with no control message from serverConn",
   140  					zap.String("server", s.serverName),
   141  					zap.String("listenAddress", s.listenAddress),
   142  				)
   143  
   144  				s.putQueuedPacket(queuedPacket)
   145  				continue
   146  			}
   147  
   148  			clientAddrPort, err := conn.SockaddrToAddrPort(msg.Msghdr.Name, msg.Msghdr.Namelen)
   149  			if err != nil {
   150  				s.logger.Warn("Failed to parse sockaddr of packet from serverConn",
   151  					zap.String("server", s.serverName),
   152  					zap.String("listenAddress", s.listenAddress),
   153  					zap.Error(err),
   154  				)
   155  
   156  				s.putQueuedPacket(queuedPacket)
   157  				continue
   158  			}
   159  
   160  			err = conn.ParseFlagsForError(int(msg.Msghdr.Flags))
   161  			if err != nil {
   162  				s.logger.Warn("Packet from serverConn discarded",
   163  					zap.String("server", s.serverName),
   164  					zap.String("listenAddress", s.listenAddress),
   165  					zap.Stringer("clientAddress", clientAddrPort),
   166  					zap.Uint32("packetLength", msg.Msglen),
   167  					zap.Error(err),
   168  				)
   169  
   170  				s.putQueuedPacket(queuedPacket)
   171  				continue
   172  			}
   173  
   174  			var serverConnPacker zerocopy.ServerPacker
   175  
   176  			entry, ok := s.table[clientAddrPort]
   177  			if !ok {
   178  				entry = &natEntry{}
   179  
   180  				serverConnPacker, entry.serverConnUnpacker, err = s.server.NewSession()
   181  				if err != nil {
   182  					s.logger.Warn("Failed to create new session for serverConn",
   183  						zap.String("server", s.serverName),
   184  						zap.String("listenAddress", s.listenAddress),
   185  						zap.Stringer("clientAddress", clientAddrPort),
   186  						zap.Error(err),
   187  					)
   188  
   189  					s.putQueuedPacket(queuedPacket)
   190  					continue
   191  				}
   192  			}
   193  
   194  			queuedPacket.targetAddr, queuedPacket.start, queuedPacket.length, err = entry.serverConnUnpacker.UnpackInPlace(queuedPacket.buf, clientAddrPort, s.packetBufFrontHeadroom, int(msg.Msglen))
   195  			if err != nil {
   196  				s.logger.Warn("Failed to unpack packet from serverConn",
   197  					zap.String("server", s.serverName),
   198  					zap.String("listenAddress", s.listenAddress),
   199  					zap.Stringer("clientAddress", clientAddrPort),
   200  					zap.Uint32("packetLength", msg.Msglen),
   201  					zap.Error(err),
   202  				)
   203  
   204  				s.putQueuedPacket(queuedPacket)
   205  				continue
   206  			}
   207  
   208  			payloadBytesReceived += uint64(queuedPacket.length)
   209  
   210  			var clientPktinfop *[]byte
   211  			cmsg := cmsgvec[i][:msg.Msghdr.Controllen]
   212  
   213  			if !bytes.Equal(entry.clientPktinfoCache, cmsg) {
   214  				clientPktinfoAddr, clientPktinfoIfindex, err := conn.ParsePktinfoCmsg(cmsg)
   215  				if err != nil {
   216  					s.logger.Warn("Failed to parse pktinfo control message from serverConn",
   217  						zap.String("server", s.serverName),
   218  						zap.String("listenAddress", s.listenAddress),
   219  						zap.Stringer("clientAddress", clientAddrPort),
   220  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   221  						zap.Error(err),
   222  					)
   223  
   224  					s.putQueuedPacket(queuedPacket)
   225  					continue
   226  				}
   227  
   228  				clientPktinfoCache := make([]byte, len(cmsg))
   229  				copy(clientPktinfoCache, cmsg)
   230  				clientPktinfop = &clientPktinfoCache
   231  				entry.clientPktinfo.Store(clientPktinfop)
   232  				entry.clientPktinfoCache = clientPktinfoCache
   233  
   234  				if ce := s.logger.Check(zap.DebugLevel, "Updated client pktinfo"); ce != nil {
   235  					ce.Write(
   236  						zap.String("server", s.serverName),
   237  						zap.String("listenAddress", s.listenAddress),
   238  						zap.Stringer("clientAddress", clientAddrPort),
   239  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   240  						zap.Stringer("clientPktinfoAddr", clientPktinfoAddr),
   241  						zap.Uint32("clientPktinfoIfindex", clientPktinfoIfindex),
   242  					)
   243  				}
   244  			}
   245  
   246  			if !ok {
   247  				natConnSendCh := make(chan *natQueuedPacket, s.sendChannelCapacity)
   248  				entry.natConnSendCh = natConnSendCh
   249  				s.table[clientAddrPort] = entry
   250  
   251  				go func() {
   252  					var sendChClean bool
   253  
   254  					defer func() {
   255  						s.mu.Lock()
   256  						close(natConnSendCh)
   257  						delete(s.table, clientAddrPort)
   258  						s.mu.Unlock()
   259  
   260  						if !sendChClean {
   261  							for queuedPacket := range natConnSendCh {
   262  								s.putQueuedPacket(queuedPacket)
   263  							}
   264  						}
   265  					}()
   266  
   267  					c, err := s.router.GetUDPClient(router.RequestInfo{
   268  						ServerIndex:    s.serverIndex,
   269  						SourceAddrPort: clientAddrPort,
   270  						TargetAddr:     queuedPacket.targetAddr,
   271  					})
   272  					if err != nil {
   273  						s.logger.Warn("Failed to get UDP client for new NAT session",
   274  							zap.String("server", s.serverName),
   275  							zap.String("listenAddress", s.listenAddress),
   276  							zap.Stringer("clientAddress", clientAddrPort),
   277  							zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   278  							zap.Error(err),
   279  						)
   280  						return
   281  					}
   282  
   283  					// Only add for the current goroutine here, since we don't want the router to block exiting.
   284  					s.wg.Add(1)
   285  					defer s.wg.Done()
   286  
   287  					clientInfo, natConnPacker, natConnUnpacker, err := c.NewSession()
   288  					if err != nil {
   289  						s.logger.Warn("Failed to create new UDP client session",
   290  							zap.String("server", s.serverName),
   291  							zap.String("client", clientInfo.Name),
   292  							zap.String("listenAddress", s.listenAddress),
   293  							zap.Stringer("clientAddress", clientAddrPort),
   294  							zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   295  							zap.Error(err),
   296  						)
   297  						return
   298  					}
   299  
   300  					natConn, err := conn.ListenUDPRawConn(clientInfo.ListenConfig, "udp", "")
   301  					if err != nil {
   302  						s.logger.Warn("Failed to create UDP socket for new NAT session",
   303  							zap.String("server", s.serverName),
   304  							zap.String("client", clientInfo.Name),
   305  							zap.String("listenAddress", s.listenAddress),
   306  							zap.Stringer("clientAddress", clientAddrPort),
   307  							zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   308  							zap.Error(err),
   309  						)
   310  						return
   311  					}
   312  
   313  					err = natConn.SetReadDeadline(time.Now().Add(s.natTimeout))
   314  					if err != nil {
   315  						s.logger.Warn("Failed to set read deadline on natConn",
   316  							zap.String("server", s.serverName),
   317  							zap.String("client", clientInfo.Name),
   318  							zap.String("listenAddress", s.listenAddress),
   319  							zap.Stringer("clientAddress", clientAddrPort),
   320  							zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   321  							zap.Duration("natTimeout", s.natTimeout),
   322  							zap.Error(err),
   323  						)
   324  						natConn.Close()
   325  						return
   326  					}
   327  
   328  					oldState := entry.state.Swap(natConn.UDPConn)
   329  					if oldState != nil {
   330  						natConn.Close()
   331  						return
   332  					}
   333  
   334  					// No more early returns!
   335  					sendChClean = true
   336  
   337  					s.logger.Info("UDP NAT relay started",
   338  						zap.String("server", s.serverName),
   339  						zap.String("client", clientInfo.Name),
   340  						zap.String("listenAddress", s.listenAddress),
   341  						zap.Stringer("clientAddress", clientAddrPort),
   342  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   343  					)
   344  
   345  					s.wg.Add(1)
   346  
   347  					go func() {
   348  						s.relayServerConnToNatConnSendmmsg(natUplinkMmsg{
   349  							clientAddrPort: clientAddrPort,
   350  							natConn:        natConn.WConn(),
   351  							natConnSendCh:  natConnSendCh,
   352  							natConnPacker:  natConnPacker,
   353  						})
   354  						natConn.Close()
   355  						s.wg.Done()
   356  					}()
   357  
   358  					s.relayNatConnToServerConnSendmmsg(natDownlinkMmsg{
   359  						clientAddrPort:     clientAddrPort,
   360  						clientPktinfop:     clientPktinfop,
   361  						clientPktinfo:      &entry.clientPktinfo,
   362  						natConn:            natConn.RConn(),
   363  						natConnRecvBufSize: clientInfo.MaxPacketSize,
   364  						natConnUnpacker:    natConnUnpacker,
   365  						serverConn:         serverConn.WConn(),
   366  						serverConnPacker:   serverConnPacker,
   367  					})
   368  				}()
   369  
   370  				if ce := s.logger.Check(zap.DebugLevel, "New UDP NAT session"); ce != nil {
   371  					ce.Write(
   372  						zap.String("server", s.serverName),
   373  						zap.String("listenAddress", s.listenAddress),
   374  						zap.Stringer("clientAddress", clientAddrPort),
   375  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   376  					)
   377  				}
   378  			}
   379  
   380  			select {
   381  			case entry.natConnSendCh <- queuedPacket:
   382  			default:
   383  				if ce := s.logger.Check(zap.DebugLevel, "Dropping packet due to full send channel"); ce != nil {
   384  					ce.Write(
   385  						zap.String("server", s.serverName),
   386  						zap.String("listenAddress", s.listenAddress),
   387  						zap.Stringer("clientAddress", clientAddrPort),
   388  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   389  					)
   390  				}
   391  
   392  				s.putQueuedPacket(queuedPacket)
   393  			}
   394  		}
   395  
   396  		s.mu.Unlock()
   397  	}
   398  
   399  	for i := range qpvec {
   400  		s.putQueuedPacket(qpvec[i])
   401  	}
   402  
   403  	s.logger.Info("Finished receiving from serverConn",
   404  		zap.String("server", s.serverName),
   405  		zap.String("listenAddress", s.listenAddress),
   406  		zap.Uint64("recvmmsgCount", recvmmsgCount),
   407  		zap.Uint64("packetsReceived", packetsReceived),
   408  		zap.Uint64("payloadBytesReceived", payloadBytesReceived),
   409  		zap.Int("burstBatchSize", burstBatchSize),
   410  	)
   411  }
   412  
   413  func (s *UDPNATRelay) relayServerConnToNatConnSendmmsg(uplink natUplinkMmsg) {
   414  	var (
   415  		destAddrPort     netip.AddrPort
   416  		packetStart      int
   417  		packetLength     int
   418  		err              error
   419  		sendmmsgCount    uint64
   420  		packetsSent      uint64
   421  		payloadBytesSent uint64
   422  		burstBatchSize   int
   423  	)
   424  
   425  	qpvec := make([]*natQueuedPacket, s.relayBatchSize)
   426  	namevec := make([]unix.RawSockaddrInet6, s.relayBatchSize)
   427  	iovec := make([]unix.Iovec, s.relayBatchSize)
   428  	msgvec := make([]conn.Mmsghdr, s.relayBatchSize)
   429  
   430  	for i := range msgvec {
   431  		msgvec[i].Msghdr.Name = (*byte)(unsafe.Pointer(&namevec[i]))
   432  		msgvec[i].Msghdr.Namelen = unix.SizeofSockaddrInet6
   433  		msgvec[i].Msghdr.Iov = &iovec[i]
   434  		msgvec[i].Msghdr.SetIovlen(1)
   435  	}
   436  
   437  main:
   438  	for {
   439  		var count int
   440  
   441  		// Block on first dequeue op.
   442  		queuedPacket, ok := <-uplink.natConnSendCh
   443  		if !ok {
   444  			break
   445  		}
   446  
   447  	dequeue:
   448  		for {
   449  			destAddrPort, packetStart, packetLength, err = uplink.natConnPacker.PackInPlace(queuedPacket.buf, queuedPacket.targetAddr, queuedPacket.start, queuedPacket.length)
   450  			if err != nil {
   451  				s.logger.Warn("Failed to pack packet for natConn",
   452  					zap.String("server", s.serverName),
   453  					zap.String("listenAddress", s.listenAddress),
   454  					zap.Stringer("clientAddress", uplink.clientAddrPort),
   455  					zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   456  					zap.Int("payloadLength", queuedPacket.length),
   457  					zap.Error(err),
   458  				)
   459  
   460  				s.putQueuedPacket(queuedPacket)
   461  
   462  				if count == 0 {
   463  					continue main
   464  				}
   465  				goto next
   466  			}
   467  
   468  			qpvec[count] = queuedPacket
   469  			namevec[count] = conn.AddrPortToSockaddrInet6(destAddrPort)
   470  			iovec[count].Base = &queuedPacket.buf[packetStart]
   471  			iovec[count].SetLen(packetLength)
   472  			count++
   473  			payloadBytesSent += uint64(queuedPacket.length)
   474  
   475  			if count == s.relayBatchSize {
   476  				break
   477  			}
   478  
   479  		next:
   480  			select {
   481  			case queuedPacket, ok = <-uplink.natConnSendCh:
   482  				if !ok {
   483  					break dequeue
   484  				}
   485  			default:
   486  				break dequeue
   487  			}
   488  		}
   489  
   490  		if err := uplink.natConn.WriteMsgs(msgvec[:count], 0); err != nil {
   491  			s.logger.Warn("Failed to batch write packets to natConn",
   492  				zap.String("server", s.serverName),
   493  				zap.String("listenAddress", s.listenAddress),
   494  				zap.Stringer("clientAddress", uplink.clientAddrPort),
   495  				zap.Stringer("lastTargetAddress", &qpvec[count-1].targetAddr),
   496  				zap.Stringer("lastWriteDestAddress", destAddrPort),
   497  				zap.Error(err),
   498  			)
   499  		}
   500  
   501  		if err := uplink.natConn.SetReadDeadline(time.Now().Add(s.natTimeout)); err != nil {
   502  			s.logger.Warn("Failed to set read deadline on natConn",
   503  				zap.String("server", s.serverName),
   504  				zap.String("listenAddress", s.listenAddress),
   505  				zap.Stringer("clientAddress", uplink.clientAddrPort),
   506  				zap.Duration("natTimeout", s.natTimeout),
   507  				zap.Error(err),
   508  			)
   509  		}
   510  
   511  		sendmmsgCount++
   512  		packetsSent += uint64(count)
   513  		if burstBatchSize < count {
   514  			burstBatchSize = count
   515  		}
   516  
   517  		qpvecn := qpvec[:count]
   518  
   519  		for i := range qpvecn {
   520  			s.putQueuedPacket(qpvecn[i])
   521  		}
   522  
   523  		if !ok {
   524  			break
   525  		}
   526  	}
   527  
   528  	s.logger.Info("Finished relay serverConn -> natConn",
   529  		zap.String("server", s.serverName),
   530  		zap.String("listenAddress", s.listenAddress),
   531  		zap.Stringer("clientAddress", uplink.clientAddrPort),
   532  		zap.Stringer("lastWriteDestAddress", destAddrPort),
   533  		zap.Uint64("sendmmsgCount", sendmmsgCount),
   534  		zap.Uint64("packetsSent", packetsSent),
   535  		zap.Uint64("payloadBytesSent", payloadBytesSent),
   536  		zap.Int("burstBatchSize", burstBatchSize),
   537  	)
   538  
   539  	s.collector.CollectUDPSessionUplink("", packetsSent, payloadBytesSent)
   540  }
   541  
   542  func (s *UDPNATRelay) relayNatConnToServerConnSendmmsg(downlink natDownlinkMmsg) {
   543  	clientPktinfop := downlink.clientPktinfop
   544  	clientPktinfo := *clientPktinfop
   545  	maxClientPacketSize := zerocopy.MaxPacketSizeForAddr(s.mtu, downlink.clientAddrPort.Addr())
   546  
   547  	serverConnPackerInfo := downlink.serverConnPacker.ServerPackerInfo()
   548  	natConnUnpackerInfo := downlink.natConnUnpacker.ClientUnpackerInfo()
   549  	headroom := zerocopy.UDPRelayHeadroom(serverConnPackerInfo.Headroom, natConnUnpackerInfo.Headroom)
   550  
   551  	var (
   552  		sendmmsgCount    uint64
   553  		packetsSent      uint64
   554  		payloadBytesSent uint64
   555  		burstBatchSize   int
   556  	)
   557  
   558  	name, namelen := conn.AddrPortToSockaddr(downlink.clientAddrPort)
   559  	savec := make([]unix.RawSockaddrInet6, s.relayBatchSize)
   560  	bufvec := make([][]byte, s.relayBatchSize)
   561  	riovec := make([]unix.Iovec, s.relayBatchSize)
   562  	siovec := make([]unix.Iovec, s.relayBatchSize)
   563  	rmsgvec := make([]conn.Mmsghdr, s.relayBatchSize)
   564  	smsgvec := make([]conn.Mmsghdr, s.relayBatchSize)
   565  
   566  	for i := 0; i < s.relayBatchSize; i++ {
   567  		packetBuf := make([]byte, headroom.Front+downlink.natConnRecvBufSize+headroom.Rear)
   568  		bufvec[i] = packetBuf
   569  
   570  		riovec[i].Base = &packetBuf[headroom.Front]
   571  		riovec[i].SetLen(downlink.natConnRecvBufSize)
   572  
   573  		rmsgvec[i].Msghdr.Name = (*byte)(unsafe.Pointer(&savec[i]))
   574  		rmsgvec[i].Msghdr.Namelen = unix.SizeofSockaddrInet6
   575  		rmsgvec[i].Msghdr.Iov = &riovec[i]
   576  		rmsgvec[i].Msghdr.SetIovlen(1)
   577  
   578  		smsgvec[i].Msghdr.Name = name
   579  		smsgvec[i].Msghdr.Namelen = namelen
   580  		smsgvec[i].Msghdr.Iov = &siovec[i]
   581  		smsgvec[i].Msghdr.SetIovlen(1)
   582  		smsgvec[i].Msghdr.Control = &clientPktinfo[0]
   583  		smsgvec[i].Msghdr.SetControllen(len(clientPktinfo))
   584  	}
   585  
   586  	for {
   587  		nr, err := downlink.natConn.ReadMsgs(rmsgvec, 0)
   588  		if err != nil {
   589  			if errors.Is(err, os.ErrDeadlineExceeded) {
   590  				break
   591  			}
   592  
   593  			s.logger.Warn("Failed to batch read packets from natConn",
   594  				zap.String("server", s.serverName),
   595  				zap.String("listenAddress", s.listenAddress),
   596  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   597  				zap.Error(err),
   598  			)
   599  			continue
   600  		}
   601  
   602  		var ns int
   603  		rmsgvecn := rmsgvec[:nr]
   604  
   605  		for i := range rmsgvecn {
   606  			msg := &rmsgvecn[i]
   607  
   608  			packetSourceAddrPort, err := conn.SockaddrToAddrPort(msg.Msghdr.Name, msg.Msghdr.Namelen)
   609  			if err != nil {
   610  				s.logger.Warn("Failed to parse sockaddr of packet from natConn",
   611  					zap.String("server", s.serverName),
   612  					zap.String("listenAddress", s.listenAddress),
   613  					zap.Stringer("clientAddress", downlink.clientAddrPort),
   614  					zap.Error(err),
   615  				)
   616  				continue
   617  			}
   618  
   619  			err = conn.ParseFlagsForError(int(msg.Msghdr.Flags))
   620  			if err != nil {
   621  				s.logger.Warn("Packet from natConn discarded",
   622  					zap.String("server", s.serverName),
   623  					zap.String("listenAddress", s.listenAddress),
   624  					zap.Stringer("clientAddress", downlink.clientAddrPort),
   625  					zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   626  					zap.Uint32("packetLength", msg.Msglen),
   627  					zap.Error(err),
   628  				)
   629  				continue
   630  			}
   631  
   632  			packetBuf := bufvec[i]
   633  
   634  			payloadSourceAddrPort, payloadStart, payloadLength, err := downlink.natConnUnpacker.UnpackInPlace(packetBuf, packetSourceAddrPort, headroom.Front, int(msg.Msglen))
   635  			if err != nil {
   636  				s.logger.Warn("Failed to unpack packet from natConn",
   637  					zap.String("server", s.serverName),
   638  					zap.String("listenAddress", s.listenAddress),
   639  					zap.Stringer("clientAddress", downlink.clientAddrPort),
   640  					zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   641  					zap.Uint32("packetLength", msg.Msglen),
   642  					zap.Error(err),
   643  				)
   644  				continue
   645  			}
   646  
   647  			packetStart, packetLength, err := downlink.serverConnPacker.PackInPlace(packetBuf, payloadSourceAddrPort, payloadStart, payloadLength, maxClientPacketSize)
   648  			if err != nil {
   649  				s.logger.Warn("Failed to pack packet for serverConn",
   650  					zap.String("server", s.serverName),
   651  					zap.String("listenAddress", s.listenAddress),
   652  					zap.Stringer("clientAddress", downlink.clientAddrPort),
   653  					zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   654  					zap.Stringer("payloadSourceAddress", payloadSourceAddrPort),
   655  					zap.Int("payloadLength", payloadLength),
   656  					zap.Int("maxClientPacketSize", maxClientPacketSize),
   657  					zap.Error(err),
   658  				)
   659  				continue
   660  			}
   661  
   662  			siovec[ns].Base = &packetBuf[packetStart]
   663  			siovec[ns].SetLen(packetLength)
   664  			ns++
   665  			payloadBytesSent += uint64(payloadLength)
   666  		}
   667  
   668  		if ns == 0 {
   669  			continue
   670  		}
   671  
   672  		if cpp := downlink.clientPktinfo.Load(); cpp != clientPktinfop {
   673  			clientPktinfo = *cpp
   674  			clientPktinfop = cpp
   675  
   676  			for i := range smsgvec {
   677  				smsgvec[i].Msghdr.Control = &clientPktinfo[0]
   678  				smsgvec[i].Msghdr.SetControllen(len(clientPktinfo))
   679  			}
   680  		}
   681  
   682  		err = downlink.serverConn.WriteMsgs(smsgvec[:ns], 0)
   683  		if err != nil {
   684  			s.logger.Warn("Failed to batch write packets to serverConn",
   685  				zap.String("server", s.serverName),
   686  				zap.String("listenAddress", s.listenAddress),
   687  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   688  				zap.Error(err),
   689  			)
   690  		}
   691  
   692  		sendmmsgCount++
   693  		packetsSent += uint64(ns)
   694  		if burstBatchSize < ns {
   695  			burstBatchSize = ns
   696  		}
   697  	}
   698  
   699  	s.logger.Info("Finished relay serverConn <- natConn",
   700  		zap.String("server", s.serverName),
   701  		zap.String("listenAddress", s.listenAddress),
   702  		zap.Stringer("clientAddress", downlink.clientAddrPort),
   703  		zap.Uint64("sendmmsgCount", sendmmsgCount),
   704  		zap.Uint64("packetsSent", packetsSent),
   705  		zap.Uint64("payloadBytesSent", payloadBytesSent),
   706  		zap.Int("burstBatchSize", burstBatchSize),
   707  	)
   708  
   709  	s.collector.CollectUDPSessionDownlink("", packetsSent, payloadBytesSent)
   710  }