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