github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/link/rawfile/rawfile_unsafe.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build linux darwin
    16  
    17  // Package rawfile contains utilities for using the netstack with raw host
    18  // files on Linux hosts.
    19  package rawfile
    20  
    21  import (
    22  	"syscall"
    23  	"unsafe"
    24  
    25  	"github.com/FlowerWrong/netstack/tcpip"
    26  )
    27  
    28  // GetMTU determines the MTU of a network interface device.
    29  func GetMTU(name string) (uint32, error) {
    30  	fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
    31  	if err != nil {
    32  		return 0, err
    33  	}
    34  
    35  	defer syscall.Close(fd)
    36  
    37  	var ifreq struct {
    38  		name [16]byte
    39  		mtu  int32
    40  		_    [20]byte
    41  	}
    42  
    43  	copy(ifreq.name[:], name)
    44  	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCGIFMTU, uintptr(unsafe.Pointer(&ifreq)))
    45  	if errno != 0 {
    46  		return 0, errno
    47  	}
    48  
    49  	return uint32(ifreq.mtu), nil
    50  }
    51  
    52  // NonBlockingWrite writes the given buffer to a file descriptor. It fails if
    53  // partial data is written.
    54  func NonBlockingWrite(fd int, buf []byte) *tcpip.Error {
    55  	var ptr unsafe.Pointer
    56  	if len(buf) > 0 {
    57  		ptr = unsafe.Pointer(&buf[0])
    58  	}
    59  
    60  	_, _, e := syscall.RawSyscall(syscall.SYS_WRITE, uintptr(fd), uintptr(ptr), uintptr(len(buf)))
    61  	if e != 0 {
    62  		return TranslateErrno(e)
    63  	}
    64  
    65  	return nil
    66  }
    67  
    68  // NonBlockingWrite3 writes up to three byte slices to a file descriptor in a
    69  // single syscall. It fails if partial data is written.
    70  func NonBlockingWrite3(fd int, b1, b2, b3 []byte) *tcpip.Error {
    71  	// If the is no second buffer, issue a regular write.
    72  	if len(b2) == 0 {
    73  		return NonBlockingWrite(fd, b1)
    74  	}
    75  
    76  	// We have two buffers. Build the iovec that represents them and issue
    77  	// a writev syscall.
    78  	iovec := [3]syscall.Iovec{
    79  		{
    80  			Base: &b1[0],
    81  			Len:  uint64(len(b1)),
    82  		},
    83  		{
    84  			Base: &b2[0],
    85  			Len:  uint64(len(b2)),
    86  		},
    87  	}
    88  	iovecLen := uintptr(2)
    89  
    90  	if len(b3) > 0 {
    91  		iovecLen++
    92  		iovec[2].Base = &b3[0]
    93  		iovec[2].Len = uint64(len(b3))
    94  	}
    95  
    96  	_, _, e := syscall.RawSyscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovec[0])), iovecLen)
    97  	if e != 0 {
    98  		return TranslateErrno(e)
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  // PollEvent represents the pollfd structure passed to a poll() system call.
   105  type PollEvent struct {
   106  	FD      int32
   107  	Events  int16
   108  	Revents int16
   109  }
   110  
   111  // BlockingRead reads from a file descriptor that is set up as non-blocking. If
   112  // no data is available, it will block in a poll() syscall until the file
   113  // descriptor becomes readable.
   114  func BlockingRead(fd int, b []byte) (int, *tcpip.Error) {
   115  	for {
   116  		n, _, e := syscall.RawSyscall(syscall.SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)))
   117  		if e == 0 {
   118  			return int(n), nil
   119  		}
   120  
   121  		event := PollEvent{
   122  			FD:     int32(fd),
   123  			Events: 1, // POLLIN
   124  		}
   125  
   126  		_, e = BlockingPoll(&event, 1, nil)
   127  		if e != 0 && e != syscall.EINTR {
   128  			return 0, TranslateErrno(e)
   129  		}
   130  	}
   131  }
   132  
   133  // BlockingReadv reads from a file descriptor that is set up as non-blocking and
   134  // stores the data in a list of iovecs buffers. If no data is available, it will
   135  // block in a poll() syscall until the file descriptor becomes readable.
   136  func BlockingReadv(fd int, iovecs []syscall.Iovec) (int, *tcpip.Error) {
   137  	for {
   138  		n, _, e := syscall.RawSyscall(syscall.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
   139  		if e == 0 {
   140  			return int(n), nil
   141  		}
   142  
   143  		event := PollEvent{
   144  			FD:     int32(fd),
   145  			Events: 1, // POLLIN
   146  		}
   147  
   148  		_, e = BlockingPoll(&event, 1, nil)
   149  		if e != 0 && e != syscall.EINTR {
   150  			return 0, TranslateErrno(e)
   151  		}
   152  	}
   153  }
   154  
   155  // MMsgHdr represents the mmsg_hdr structure required by recvmmsg() on linux.
   156  type MMsgHdr struct {
   157  	Msg syscall.Msghdr
   158  	Len uint32
   159  	_   [4]byte
   160  }
   161  
   162  // BlockingRecvMMsg reads from a file descriptor that is set up as non-blocking
   163  // and stores the received messages in a slice of MMsgHdr structures. If no data
   164  // is available, it will block in a poll() syscall until the file descriptor
   165  // becomes readable.
   166  func BlockingRecvMMsg(fd int, msgHdrs []MMsgHdr) (int, *tcpip.Error) {
   167  	//for {
   168  	//	n, _, e := syscall.RawSyscall6(syscall.SYS_RECVMMSG, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), syscall.MSG_DONTWAIT, 0, 0)
   169  	//	if e == 0 {
   170  	//		return int(n), nil
   171  	//	}
   172  	//
   173  	//	event := PollEvent{
   174  	//		FD:     int32(fd),
   175  	//		Events: 1, // POLLIN
   176  	//	}
   177  	//
   178  	//	if _, e := BlockingPoll(&event, 1, nil); e != 0 && e != syscall.EINTR {
   179  	//		return 0, TranslateErrno(e)
   180  	//	}
   181  	//}
   182  	return 0, tcpip.ErrInvalidOptionValue
   183  }