github.com/gopacket/gopacket@v1.1.0/afpacket/options.go (about) 1 // Copyright 2012 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 7 //go:build linux 8 // +build linux 9 10 package afpacket 11 12 import ( 13 "errors" 14 "fmt" 15 "time" 16 17 "golang.org/x/sys/unix" 18 ) 19 20 // OptTPacketVersion is the version of TPacket to use. 21 // It can be passed into NewTPacket. 22 type OptTPacketVersion int 23 24 // String returns a string representation of the version, generally of the form V#. 25 func (t OptTPacketVersion) String() string { 26 switch t { 27 case TPacketVersion1: 28 return "V1" 29 case TPacketVersion2: 30 return "V2" 31 case TPacketVersion3: 32 return "V3" 33 case TPacketVersionHighestAvailable: 34 return "HighestAvailable" 35 } 36 return "InvalidVersion" 37 } 38 39 // OptSocketType is the socket type used to open the TPacket socket. 40 type OptSocketType int 41 42 func (t OptSocketType) String() string { 43 switch t { 44 case SocketRaw: 45 return "SOCK_RAW" 46 case SocketDgram: 47 return "SOCK_DGRAM" 48 } 49 return "UnknownSocketType" 50 } 51 52 // TPacket version numbers for use with NewHandle. 53 const ( 54 // TPacketVersionHighestAvailable tells NewHandle to use the highest available version of tpacket the kernel has available. 55 // This is the default, should a version number not be given in NewHandle's options. 56 TPacketVersionHighestAvailable = OptTPacketVersion(-1) 57 TPacketVersion1 = OptTPacketVersion(unix.TPACKET_V1) 58 TPacketVersion2 = OptTPacketVersion(unix.TPACKET_V2) 59 TPacketVersion3 = OptTPacketVersion(unix.TPACKET_V3) 60 tpacketVersionMax = TPacketVersion3 61 tpacketVersionMin = -1 62 // SocketRaw is the default socket type. It returns packet data 63 // including the link layer (ethernet headers, etc). 64 SocketRaw = OptSocketType(unix.SOCK_RAW) 65 // SocketDgram strips off the link layer when reading packets, and adds 66 // the link layer back automatically on packet writes (coming soon...) 67 SocketDgram = OptSocketType(unix.SOCK_DGRAM) 68 ) 69 70 // OptInterface is the specific interface to bind to. 71 // It can be passed into NewTPacket. 72 type OptInterface string 73 74 // OptFrameSize is TPacket's tp_frame_size 75 // It can be passed into NewTPacket. 76 type OptFrameSize int 77 78 // OptBlockSize is TPacket's tp_block_size 79 // It can be passed into NewTPacket. 80 type OptBlockSize int 81 82 // OptNumBlocks is TPacket's tp_block_nr 83 // It can be passed into NewTPacket. 84 type OptNumBlocks int 85 86 // OptBlockTimeout is TPacket v3's tp_retire_blk_tov. Note that it has only millisecond granularity, so must be >= 1 ms. 87 // It can be passed into NewTPacket. 88 type OptBlockTimeout time.Duration 89 90 // OptPollTimeout is the number of milliseconds that poll() should block waiting for a file 91 // descriptor to become ready. Specifying a negative value in timeāout means an infinite timeout. 92 type OptPollTimeout time.Duration 93 94 // OptAddVLANHeader modifies the packet data that comes back from the 95 // kernel by adding in the VLAN header that the NIC stripped. AF_PACKET by 96 // default uses VLAN offloading, in which the NIC strips the VLAN header off of 97 // the packet before handing it to the kernel. This means that, even if a 98 // packet has an 802.1q header on the wire, it'll show up without one by the 99 // time it goes through AF_PACKET. If this option is true, the VLAN header is 100 // added back in before the packet is returned. Note that this potentially has 101 // a large performance hit, especially in otherwise zero-copy operation. 102 // 103 // Note that if you do not need to have a "real" VLAN layer, it may be 104 // preferable to use the VLAN ID provided by the AncillaryVLAN struct 105 // in CaptureInfo.AncillaryData, which is populated out-of-band and has 106 // negligible performance impact. Such ancillary data will automatically 107 // be provided if available. 108 type OptAddVLANHeader bool 109 110 // Default constants used by options. 111 const ( 112 DefaultFrameSize = 4096 // Default value for OptFrameSize. 113 DefaultBlockSize = DefaultFrameSize * 128 // Default value for OptBlockSize. 114 DefaultNumBlocks = 128 // Default value for OptNumBlocks. 115 DefaultBlockTimeout = 64 * time.Millisecond // Default value for OptBlockTimeout. 116 DefaultPollTimeout = -1 * time.Millisecond // Default value for OptPollTimeout. This blocks forever. 117 ) 118 119 type options struct { 120 frameSize int 121 framesPerBlock int 122 blockSize int 123 numBlocks int 124 addVLANHeader bool 125 blockTimeout time.Duration 126 pollTimeout time.Duration 127 version OptTPacketVersion 128 socktype OptSocketType 129 iface string 130 } 131 132 var defaultOpts = options{ 133 frameSize: DefaultFrameSize, 134 blockSize: DefaultBlockSize, 135 numBlocks: DefaultNumBlocks, 136 blockTimeout: DefaultBlockTimeout, 137 pollTimeout: DefaultPollTimeout, 138 version: TPacketVersionHighestAvailable, 139 socktype: SocketRaw, 140 } 141 142 func parseOptions(opts ...interface{}) (ret options, err error) { 143 ret = defaultOpts 144 for _, opt := range opts { 145 switch v := opt.(type) { 146 case OptFrameSize: 147 ret.frameSize = int(v) 148 case OptBlockSize: 149 ret.blockSize = int(v) 150 case OptNumBlocks: 151 ret.numBlocks = int(v) 152 case OptBlockTimeout: 153 ret.blockTimeout = time.Duration(v) 154 case OptPollTimeout: 155 ret.pollTimeout = time.Duration(v) 156 case OptTPacketVersion: 157 ret.version = v 158 case OptInterface: 159 ret.iface = string(v) 160 case OptSocketType: 161 ret.socktype = v 162 case OptAddVLANHeader: 163 ret.addVLANHeader = bool(v) 164 default: 165 err = errors.New("unknown type in options") 166 return 167 } 168 } 169 if err = ret.check(); err != nil { 170 return 171 } 172 ret.framesPerBlock = ret.blockSize / ret.frameSize 173 return 174 } 175 func (o options) check() error { 176 switch { 177 case o.blockSize%pageSize != 0: 178 return fmt.Errorf("block size %d must be divisible by page size %d", o.blockSize, pageSize) 179 case o.blockSize%o.frameSize != 0: 180 return fmt.Errorf("block size %d must be divisible by frame size %d", o.blockSize, o.frameSize) 181 case o.numBlocks < 1: 182 return fmt.Errorf("num blocks %d must be >= 1", o.numBlocks) 183 case o.blockTimeout < time.Millisecond: 184 return fmt.Errorf("block timeout %v must be > %v", o.blockTimeout, time.Millisecond) 185 case o.version < tpacketVersionMin || o.version > tpacketVersionMax: 186 return fmt.Errorf("tpacket version %v is invalid", o.version) 187 } 188 return nil 189 }