@@ -22,8 +22,7 @@ type System struct {
2222 ctx context.Context
2323 tun Tun
2424 tunName string
25- mtu uint32
26- bufferSize int
25+ mtu int
2726 handler Handler
2827 logger logger.Logger
2928 inet4Prefixes []netip.Prefix
@@ -57,8 +56,7 @@ func NewSystem(options StackOptions) (Stack, error) {
5756 ctx : options .Context ,
5857 tun : options .Tun ,
5958 tunName : options .TunOptions .Name ,
60- mtu : options .TunOptions .MTU ,
61- bufferSize : int (options .BufferSize ()),
59+ mtu : int (options .TunOptions .MTU ),
6260 udpTimeout : options .UDPTimeout ,
6361 handler : options .Handler ,
6462 logger : options .Logger ,
@@ -147,8 +145,15 @@ func (s *System) tunLoop() {
147145 s .wintunLoop (winTun )
148146 return
149147 }
148+ if batchTUN , isBatchTUN := s .tun .(BatchTUN ); isBatchTUN {
149+ batchSize := batchTUN .BatchSize ()
150+ if batchSize > 1 {
151+ s .batchLoop (batchTUN , batchSize )
152+ return
153+ }
154+ }
150155 frontHeadroom := s .tun .FrontHeadroom ()
151- packetBuffer := make ([]byte , s .bufferSize + frontHeadroom + PacketOffset )
156+ packetBuffer := make ([]byte , s .mtu + frontHeadroom + PacketOffset )
152157 for {
153158 n , err := s .tun .Read (packetBuffer [frontHeadroom :])
154159 if err != nil {
@@ -162,17 +167,7 @@ func (s *System) tunLoop() {
162167 }
163168 rawPacket := packetBuffer [:frontHeadroom + n ]
164169 packet := packetBuffer [frontHeadroom + PacketOffset : frontHeadroom + n ]
165- switch ipVersion := packet [0 ] >> 4 ; ipVersion {
166- case 4 :
167- err = s .processIPv4 (rawPacket , packet )
168- case 6 :
169- err = s .processIPv6 (rawPacket , packet )
170- default :
171- err = E .New ("ip: unknown version: " , ipVersion )
172- }
173- if err != nil {
174- s .logger .Trace (err )
175- }
170+ s .processPacket (rawPacket , packet )
176171 }
177172}
178173
@@ -186,18 +181,53 @@ func (s *System) wintunLoop(winTun WinTun) {
186181 release ()
187182 continue
188183 }
189- switch ipVersion := packet [0 ] >> 4 ; ipVersion {
190- case 4 :
191- err = s .processIPv4 (packet , packet )
192- case 6 :
193- err = s .processIPv6 (packet , packet )
194- default :
195- err = E .New ("ip: unknown version: " , ipVersion )
196- }
184+ s .processPacket (packet , packet )
185+ release ()
186+ }
187+ }
188+
189+ func (s * System ) batchLoop (linuxTUN BatchTUN , batchSize int ) {
190+ frontHeadroom := s .tun .FrontHeadroom ()
191+ packetBuffers := make ([][]byte , batchSize )
192+ for i := range packetBuffers {
193+ packetBuffers [i ] = make ([]byte , s .mtu + frontHeadroom + PacketOffset )
194+ }
195+ packetSizes := make ([]int , batchSize )
196+ for {
197+ n , err := linuxTUN .BatchRead (packetBuffers , packetSizes )
197198 if err != nil {
198- s .logger .Trace (err )
199+ if E .IsClosed (err ) {
200+ return
201+ }
202+ s .logger .Error (E .Cause (err , "batch read packet" ))
199203 }
200- release ()
204+ if n == 0 {
205+ continue
206+ }
207+ for i := 0 ; i < n ; i ++ {
208+ packetBuffer := packetBuffers [i ][:packetSizes [i ]]
209+ if n < clashtcpip .IPv4PacketMinLength {
210+ continue
211+ }
212+ rawPacket := packetBuffer [:frontHeadroom + n ]
213+ packet := packetBuffer [frontHeadroom + PacketOffset : frontHeadroom + n ]
214+ s .processPacket (rawPacket , packet )
215+ }
216+ }
217+ }
218+
219+ func (s * System ) processPacket (rawPacket []byte , packet []byte ) {
220+ var err error
221+ switch ipVersion := packet [0 ] >> 4 ; ipVersion {
222+ case 4 :
223+ err = s .processIPv4 (rawPacket , packet )
224+ case 6 :
225+ err = s .processIPv6 (rawPacket , packet )
226+ default :
227+ err = E .New ("ip: unknown version: " , ipVersion )
228+ }
229+ if err != nil {
230+ s .logger .Trace (err )
201231 }
202232}
203233
@@ -354,7 +384,7 @@ func (s *System) processIPv4UDP(rawPacket []byte, packet clashtcpip.IPv4Packet,
354384 headerLen := packet .HeaderLen () + clashtcpip .UDPHeaderSize
355385 headerCopy := make ([]byte , headerLen )
356386 copy (headerCopy , packet [:headerLen ])
357- return & systemUDPPacketWriter4 {s .tun , s .tun .FrontHeadroom (), headerCopy , source }
387+ return & systemUDPPacketWriter4 {s .tun , s .tun .FrontHeadroom () + PacketOffset , headerCopy , source }
358388 })
359389 return nil
360390}
@@ -380,7 +410,7 @@ func (s *System) processIPv6UDP(rawPacket []byte, packet clashtcpip.IPv6Packet,
380410 headerLen := len (packet ) - int (header .Length ()) + clashtcpip .UDPHeaderSize
381411 headerCopy := make ([]byte , headerLen )
382412 copy (headerCopy , packet [:headerLen ])
383- return & systemUDPPacketWriter6 {s .tun , s .tun .FrontHeadroom (), headerCopy , source }
413+ return & systemUDPPacketWriter6 {s .tun , s .tun .FrontHeadroom () + PacketOffset , headerCopy , source }
384414 })
385415 return nil
386416}
@@ -421,8 +451,7 @@ type systemUDPPacketWriter4 struct {
421451func (w * systemUDPPacketWriter4 ) WritePacket (buffer * buf.Buffer , destination M.Socksaddr ) error {
422452 newPacket := buf .NewSize (w .frontHeadroom + len (w .header ) + buffer .Len ())
423453 defer newPacket .Release ()
424- newPacket .WriteZeroN (w .frontHeadroom )
425- newPacket .Advance (w .frontHeadroom )
454+ newPacket .Resize (w .frontHeadroom , 0 )
426455 newPacket .Write (w .header )
427456 newPacket .Write (buffer .Bytes ())
428457 ipHdr := clashtcpip .IPv4Packet (newPacket .Bytes ())
@@ -435,7 +464,11 @@ func (w *systemUDPPacketWriter4) WritePacket(buffer *buf.Buffer, destination M.S
435464 udpHdr .SetLength (uint16 (buffer .Len () + clashtcpip .UDPHeaderSize ))
436465 udpHdr .ResetChecksum (ipHdr .PseudoSum ())
437466 ipHdr .ResetChecksum ()
438- newPacket .Advance (- w .frontHeadroom )
467+ if PacketOffset > 0 {
468+ newPacket .ExtendHeader (PacketOffset )[3 ] = syscall .AF_INET
469+ } else {
470+ newPacket .Advance (- w .frontHeadroom )
471+ }
439472 return common .Error (w .tun .Write (newPacket .Bytes ()))
440473}
441474
@@ -449,8 +482,7 @@ type systemUDPPacketWriter6 struct {
449482func (w * systemUDPPacketWriter6 ) WritePacket (buffer * buf.Buffer , destination M.Socksaddr ) error {
450483 newPacket := buf .NewSize (w .frontHeadroom + len (w .header ) + buffer .Len ())
451484 defer newPacket .Release ()
452- newPacket .WriteZeroN (w .frontHeadroom )
453- newPacket .Advance (w .frontHeadroom )
485+ newPacket .Resize (w .frontHeadroom , 0 )
454486 newPacket .Write (w .header )
455487 newPacket .Write (buffer .Bytes ())
456488 ipHdr := clashtcpip .IPv6Packet (newPacket .Bytes ())
@@ -463,6 +495,10 @@ func (w *systemUDPPacketWriter6) WritePacket(buffer *buf.Buffer, destination M.S
463495 udpHdr .SetSourcePort (destination .Port )
464496 udpHdr .SetLength (udpLen )
465497 udpHdr .ResetChecksum (ipHdr .PseudoSum ())
466- newPacket .Advance (- w .frontHeadroom )
498+ if PacketOffset > 0 {
499+ newPacket .ExtendHeader (PacketOffset )[3 ] = syscall .AF_INET6
500+ } else {
501+ newPacket .Advance (- w .frontHeadroom )
502+ }
467503 return common .Error (w .tun .Write (newPacket .Bytes ()))
468504}
0 commit comments