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  }