|
@@ -62,6 +62,7 @@ func (r *tunFile) newFriend(fd int) (*tunFile, error) {
|
|
|
fd: fd,
|
|
fd: fd,
|
|
|
shutdownFd: r.shutdownFd,
|
|
shutdownFd: r.shutdownFd,
|
|
|
vnetHdr: r.vnetHdr,
|
|
vnetHdr: r.vnetHdr,
|
|
|
|
|
+ readBuf: make([]byte, tunReadBufSize),
|
|
|
readPoll: [2]unix.PollFd{
|
|
readPoll: [2]unix.PollFd{
|
|
|
{Fd: int32(fd), Events: unix.POLLIN},
|
|
{Fd: int32(fd), Events: unix.POLLIN},
|
|
|
{Fd: int32(r.shutdownFd), Events: unix.POLLIN},
|
|
{Fd: int32(r.shutdownFd), Events: unix.POLLIN},
|
|
@@ -72,7 +73,6 @@ func (r *tunFile) newFriend(fd int) (*tunFile, error) {
|
|
|
},
|
|
},
|
|
|
}
|
|
}
|
|
|
if r.vnetHdr {
|
|
if r.vnetHdr {
|
|
|
- out.readBuf = make([]byte, tunReadBufSize)
|
|
|
|
|
out.segBuf = make([]byte, tunSegBufSize)
|
|
out.segBuf = make([]byte, tunSegBufSize)
|
|
|
out.writeIovs[0].Base = &zeroVnetHdr[0]
|
|
out.writeIovs[0].Base = &zeroVnetHdr[0]
|
|
|
out.writeIovs[0].SetLen(virtioNetHdrLen)
|
|
out.writeIovs[0].SetLen(virtioNetHdrLen)
|
|
@@ -95,6 +95,7 @@ func newTunFd(fd int, vnetHdr bool) (*tunFile, error) {
|
|
|
shutdownFd: shutdownFd,
|
|
shutdownFd: shutdownFd,
|
|
|
lastOne: true,
|
|
lastOne: true,
|
|
|
vnetHdr: vnetHdr,
|
|
vnetHdr: vnetHdr,
|
|
|
|
|
+ readBuf: make([]byte, tunReadBufSize),
|
|
|
readPoll: [2]unix.PollFd{
|
|
readPoll: [2]unix.PollFd{
|
|
|
{Fd: int32(fd), Events: unix.POLLIN},
|
|
{Fd: int32(fd), Events: unix.POLLIN},
|
|
|
{Fd: int32(shutdownFd), Events: unix.POLLIN},
|
|
{Fd: int32(shutdownFd), Events: unix.POLLIN},
|
|
@@ -105,7 +106,6 @@ func newTunFd(fd int, vnetHdr bool) (*tunFile, error) {
|
|
|
},
|
|
},
|
|
|
}
|
|
}
|
|
|
if vnetHdr {
|
|
if vnetHdr {
|
|
|
- out.readBuf = make([]byte, tunReadBufSize)
|
|
|
|
|
out.segBuf = make([]byte, tunSegBufSize)
|
|
out.segBuf = make([]byte, tunSegBufSize)
|
|
|
out.writeIovs[0].Base = &zeroVnetHdr[0]
|
|
out.writeIovs[0].Base = &zeroVnetHdr[0]
|
|
|
out.writeIovs[0].SetLen(virtioNetHdrLen)
|
|
out.writeIovs[0].SetLen(virtioNetHdrLen)
|
|
@@ -181,29 +181,24 @@ func (r *tunFile) readRaw(buf []byte) (int, error) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (r *tunFile) Read(buf []byte) (int, error) {
|
|
|
|
|
- if !r.vnetHdr {
|
|
|
|
|
- return r.readRaw(buf)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+// ReadBatch reads one superpacket from the tun and returns the resulting
|
|
|
|
|
+// packets. Slices point into the tunFile's internal buffers and are only
|
|
|
|
|
+// valid until the next ReadBatch / Read / Close on this Queue.
|
|
|
|
|
+func (r *tunFile) ReadBatch() ([][]byte, error) {
|
|
|
|
|
+ r.pending = r.pending[:0]
|
|
|
|
|
+ r.pendingIdx = 0
|
|
|
|
|
|
|
|
for {
|
|
for {
|
|
|
- if r.pendingIdx < len(r.pending) {
|
|
|
|
|
- seg := r.pending[r.pendingIdx]
|
|
|
|
|
- r.pendingIdx++
|
|
|
|
|
- if len(seg) > len(buf) {
|
|
|
|
|
- return 0, io.ErrShortBuffer
|
|
|
|
|
- }
|
|
|
|
|
- return copy(buf, seg), nil
|
|
|
|
|
- }
|
|
|
|
|
- r.pending = r.pending[:0]
|
|
|
|
|
- r.pendingIdx = 0
|
|
|
|
|
-
|
|
|
|
|
n, err := r.readRaw(r.readBuf)
|
|
n, err := r.readRaw(r.readBuf)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return 0, err
|
|
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !r.vnetHdr {
|
|
|
|
|
+ r.pending = append(r.pending, r.readBuf[:n])
|
|
|
|
|
+ return r.pending, nil
|
|
|
}
|
|
}
|
|
|
if n < virtioNetHdrLen {
|
|
if n < virtioNetHdrLen {
|
|
|
- return 0, fmt.Errorf("short tun read: %d < %d", n, virtioNetHdrLen)
|
|
|
|
|
|
|
+ return nil, fmt.Errorf("short tun read: %d < %d", n, virtioNetHdrLen)
|
|
|
}
|
|
}
|
|
|
var hdr virtioNetHdr
|
|
var hdr virtioNetHdr
|
|
|
hdr.decode(r.readBuf[:virtioNetHdrLen])
|
|
hdr.decode(r.readBuf[:virtioNetHdrLen])
|
|
@@ -211,6 +206,26 @@ func (r *tunFile) Read(buf []byte) (int, error) {
|
|
|
// Drop and read again — a bad packet should not kill the reader.
|
|
// Drop and read again — a bad packet should not kill the reader.
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
|
|
+ return r.pending, nil
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Read drains segments produced by the last ReadBatch one at a time; when the
|
|
|
|
|
+// batch is exhausted it fetches a fresh one. Kept for io.Reader compatibility;
|
|
|
|
|
+// batch-aware callers should use ReadBatch directly.
|
|
|
|
|
+func (r *tunFile) Read(buf []byte) (int, error) {
|
|
|
|
|
+ for {
|
|
|
|
|
+ if r.pendingIdx < len(r.pending) {
|
|
|
|
|
+ seg := r.pending[r.pendingIdx]
|
|
|
|
|
+ r.pendingIdx++
|
|
|
|
|
+ if len(seg) > len(buf) {
|
|
|
|
|
+ return 0, io.ErrShortBuffer
|
|
|
|
|
+ }
|
|
|
|
|
+ return copy(buf, seg), nil
|
|
|
|
|
+ }
|
|
|
|
|
+ if _, err := r.ReadBatch(); err != nil {
|
|
|
|
|
+ return 0, err
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -540,7 +555,7 @@ func (t *tun) SupportsMultiqueue() bool {
|
|
|
return true
|
|
return true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
|
|
|
|
|
|
|
+func (t *tun) NewMultiQueueReader() (Queue, error) {
|
|
|
t.closeLock.Lock()
|
|
t.closeLock.Lock()
|
|
|
defer t.closeLock.Unlock()
|
|
defer t.closeLock.Unlock()
|
|
|
|
|
|