Files
zeromesh/internal/vl2/frame.go

93 lines
1.7 KiB
Go

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)
}