package vl2 import ( "encoding/binary" "fmt" "net" "sync" ) const ( MinFrameSize = 14 MaxFrameSize = 65535 EtherTypeIPv4 = 0x0800 EtherTypeARP = 0x0806 EtherTypeIPv6 = 0x86DD ) type EthernetFrame struct { DstMAC net.HardwareAddr SrcMAC net.HardwareAddr EtherType uint16 Payload []byte } func ParseEthernetFrame(data []byte) (*EthernetFrame, error) { if len(data) < MinFrameSize { return nil, fmt.Errorf("frame too short: %d < %d", len(data), MinFrameSize) } return &EthernetFrame{ DstMAC: net.HardwareAddr(data[0:6]), SrcMAC: net.HardwareAddr(data[6:12]), EtherType: binary.BigEndian.Uint16(data[12:14]), Payload: data[14:], }, nil } func (f *EthernetFrame) Encode() []byte { buf := make([]byte, MinFrameSize+len(f.Payload)) copy(buf[0:6], f.DstMAC) copy(buf[6:12], f.SrcMAC) binary.BigEndian.PutUint16(buf[12:14], f.EtherType) copy(buf[14:], f.Payload) return buf } func (f *EthernetFrame) IsBroadcast() bool { for _, b := range f.DstMAC { if b != 0xff { return false } } return true } func (f *EthernetFrame) IsMulticast() bool { return len(f.DstMAC) > 0 && f.DstMAC[0]&0x01 == 0x01 && !f.IsBroadcast() } func (f *EthernetFrame) IsARP() bool { return f.EtherType == EtherTypeARP } func (f *EthernetFrame) IsIPv4() bool { return f.EtherType == EtherTypeIPv4 } func (f *EthernetFrame) IsIPv6() bool { return f.EtherType == EtherTypeIPv6 } type MACKey [6]byte func MACToKey(mac net.HardwareAddr) MACKey { var key MACKey copy(key[:], mac) return key } var frameBufPool = sync.Pool{ New: func() interface{} { buf := make([]byte, MaxFrameSize) return &buf }, } func GetFrameBuf() *[]byte { return frameBufPool.Get().(*[]byte) } func PutFrameBuf(buf *[]byte) { frameBufPool.Put(buf) }