// setUpRing sets up the shared-memory ring buffer between the user process and the kernel. func (h *TPacket) setUpRing() (err error) { totalSize := C.uint(h.opts.framesPerBlock * h.opts.numBlocks * h.opts.frameSize) switch h.tpVersion { case TPacketVersion1, TPacketVersion2: var tp C.struct_tpacket_req tp.tp_block_size = C.uint(h.opts.blockSize) tp.tp_block_nr = C.uint(h.opts.numBlocks) tp.tp_frame_size = C.uint(h.opts.frameSize) tp.tp_frame_nr = C.uint(h.opts.framesPerBlock * h.opts.numBlocks) if _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_RX_RING, unsafe.Pointer(&tp), C.socklen_t(unsafe.Sizeof(tp))); err != nil { return fmt.Errorf("setsockopt packet_rx_ring: %v", err) } case TPacketVersion3: var tp C.struct_tpacket_req3 tp.tp_block_size = C.uint(h.opts.blockSize) tp.tp_block_nr = C.uint(h.opts.numBlocks) tp.tp_frame_size = C.uint(h.opts.frameSize) tp.tp_frame_nr = C.uint(h.opts.framesPerBlock * h.opts.numBlocks) tp.tp_retire_blk_tov = C.uint(h.opts.blockTimeout / time.Millisecond) if _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_RX_RING, unsafe.Pointer(&tp), C.socklen_t(unsafe.Sizeof(tp))); err != nil { return fmt.Errorf("setsockopt packet_rx_ring v3: %v", err) } default: return errors.New("invalid tpVersion") } if h.ring, err = C.mmap(nil, C.size_t(totalSize), C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, C.int(h.fd), 0); err != nil { return } if h.ring == nil { return errors.New("no ring") } return nil }
// SetFanout activates TPacket's fanout ability. // Use of Fanout requires creating multiple TPacket objects and the same id/type to // a SetFanout call on each. Note that this can be done cross-process, so if two // different processes both call SetFanout with the same type/id, they'll share // packets between them. The same should work for multiple TPacket objects within // the same process. func (h *TPacket) SetFanout(t FanoutType, id uint16) error { h.mu.Lock() defer h.mu.Unlock() arg := C.int(t) << 16 arg |= C.int(id) _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_FANOUT, unsafe.Pointer(&arg), C.socklen_t(unsafe.Sizeof(arg))) return err }
// setTPacketVersion asks the kernel to set TPacket to a particular version, and returns an error on failure. func (h *TPacket) setTPacketVersion(version OptTPacketVersion) error { val := C.int(version) _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_VERSION, unsafe.Pointer(&val), C.socklen_t(unsafe.Sizeof(val))) if err != nil { return fmt.Errorf("setsockopt packet_version: %v", err) } return nil }
// SetBPFFilter compiles and sets a BPF filter for the TPacket handle. func (h *TPacket) SetBPFFilter(expr string) (err error) { // Open a dummy pcap handle p, err := pcap.OpenDead(layers.LinkTypeEthernet, int32(h.opts.frameSize)) if err != nil { return fmt.Errorf("OpenDead: %s", err) } bpf, err := p.NewBPF(expr) if err != nil { return fmt.Errorf("NewBPF: %s", err) } program := bpf.BPF() _, err = C.setsockopt(h.fd, C.SOL_SOCKET, C.SO_ATTACH_FILTER, unsafe.Pointer(&program), C.socklen_t(unsafe.Sizeof(program))) if err != nil { return fmt.Errorf("setsockopt: %s", err) } return nil }