github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/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 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/google/netstack/tcpip" 26 "golang.org/x/sys/unix" 27 ) 28 29 // GetMTU determines the MTU of a network interface device. 30 func GetMTU(name string) (uint32, error) { 31 fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) 32 if err != nil { 33 return 0, err 34 } 35 36 defer syscall.Close(fd) 37 38 var ifreq struct { 39 name [16]byte 40 mtu int32 41 _ [20]byte 42 } 43 44 copy(ifreq.name[:], name) 45 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCGIFMTU, uintptr(unsafe.Pointer(&ifreq))) 46 if errno != 0 { 47 return 0, errno 48 } 49 50 return uint32(ifreq.mtu), nil 51 } 52 53 // NonBlockingWrite writes the given buffer to a file descriptor. It fails if 54 // partial data is written. 55 func NonBlockingWrite(fd int, buf []byte) *tcpip.Error { 56 var ptr unsafe.Pointer 57 if len(buf) > 0 { 58 ptr = unsafe.Pointer(&buf[0]) 59 } 60 61 _, _, e := syscall.RawSyscall(syscall.SYS_WRITE, uintptr(fd), uintptr(ptr), uintptr(len(buf))) 62 if e != 0 { 63 return TranslateErrno(e) 64 } 65 66 return nil 67 } 68 69 // NonBlockingWrite3 writes up to three byte slices to a file descriptor in a 70 // single syscall. It fails if partial data is written. 71 func NonBlockingWrite3(fd int, b1, b2, b3 []byte) *tcpip.Error { 72 // If the is no second buffer, issue a regular write. 73 if len(b2) == 0 { 74 return NonBlockingWrite(fd, b1) 75 } 76 77 // We have two buffers. Build the iovec that represents them and issue 78 // a writev syscall. 79 iovec := [3]syscall.Iovec{ 80 { 81 Base: &b1[0], 82 Len: uint64(len(b1)), 83 }, 84 { 85 Base: &b2[0], 86 Len: uint64(len(b2)), 87 }, 88 } 89 iovecLen := uintptr(2) 90 91 if len(b3) > 0 { 92 iovecLen++ 93 iovec[2].Base = &b3[0] 94 iovec[2].Len = uint64(len(b3)) 95 } 96 97 _, _, e := syscall.RawSyscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovec[0])), iovecLen) 98 if e != 0 { 99 return TranslateErrno(e) 100 } 101 102 return nil 103 } 104 105 // NonBlockingSendMMsg sends multiple messages on a socket. 106 func NonBlockingSendMMsg(fd int, msgHdrs []MMsgHdr) (int, *tcpip.Error) { 107 n, _, e := syscall.RawSyscall6(unix.SYS_SENDMMSG, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), syscall.MSG_DONTWAIT, 0, 0) 108 if e != 0 { 109 return 0, TranslateErrno(e) 110 } 111 112 return int(n), nil 113 } 114 115 // PollEvent represents the pollfd structure passed to a poll() system call. 116 type PollEvent struct { 117 FD int32 118 Events int16 119 Revents int16 120 } 121 122 // BlockingRead reads from a file descriptor that is set up as non-blocking. If 123 // no data is available, it will block in a poll() syscall until the file 124 // descriptor becomes readable. 125 func BlockingRead(fd int, b []byte) (int, *tcpip.Error) { 126 for { 127 n, _, e := syscall.RawSyscall(syscall.SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))) 128 if e == 0 { 129 return int(n), nil 130 } 131 132 event := PollEvent{ 133 FD: int32(fd), 134 Events: 1, // POLLIN 135 } 136 137 _, e = BlockingPoll(&event, 1, nil) 138 if e != 0 && e != syscall.EINTR { 139 return 0, TranslateErrno(e) 140 } 141 } 142 } 143 144 // BlockingReadv reads from a file descriptor that is set up as non-blocking and 145 // stores the data in a list of iovecs buffers. If no data is available, it will 146 // block in a poll() syscall until the file descriptor becomes readable. 147 func BlockingReadv(fd int, iovecs []syscall.Iovec) (int, *tcpip.Error) { 148 for { 149 n, _, e := syscall.RawSyscall(syscall.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs))) 150 if e == 0 { 151 return int(n), nil 152 } 153 154 event := PollEvent{ 155 FD: int32(fd), 156 Events: 1, // POLLIN 157 } 158 159 _, e = BlockingPoll(&event, 1, nil) 160 if e != 0 && e != syscall.EINTR { 161 return 0, TranslateErrno(e) 162 } 163 } 164 } 165 166 // MMsgHdr represents the mmsg_hdr structure required by recvmmsg() on linux. 167 type MMsgHdr struct { 168 Msg syscall.Msghdr 169 Len uint32 170 _ [4]byte 171 } 172 173 // BlockingRecvMMsg reads from a file descriptor that is set up as non-blocking 174 // and stores the received messages in a slice of MMsgHdr structures. If no data 175 // is available, it will block in a poll() syscall until the file descriptor 176 // becomes readable. 177 func BlockingRecvMMsg(fd int, msgHdrs []MMsgHdr) (int, *tcpip.Error) { 178 for { 179 n, _, e := syscall.RawSyscall6(syscall.SYS_RECVMMSG, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), syscall.MSG_DONTWAIT, 0, 0) 180 if e == 0 { 181 return int(n), nil 182 } 183 184 event := PollEvent{ 185 FD: int32(fd), 186 Events: 1, // POLLIN 187 } 188 189 if _, e := BlockingPoll(&event, 1, nil); e != 0 && e != syscall.EINTR { 190 return 0, TranslateErrno(e) 191 } 192 } 193 }