github.com/contiv/libOpenflow@v0.0.0-20210609050114-d967b14cc688/protocol/ethernet.go (about)

     1  package protocol
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"net"
     7  
     8  	"github.com/contiv/libOpenflow/util"
     9  )
    10  
    11  // see http://en.wikipedia.org/wiki/EtherType
    12  const (
    13  	IPv4_MSG = 0x0800
    14  	ARP_MSG  = 0x0806
    15  	LLDP_MSG = 0x88cc
    16  	WOL_MSG  = 0x0842
    17  	RARP_MSG = 0x8035
    18  	VLAN_MSG = 0x8100
    19  
    20  	IPv6_MSG     = 0x86DD
    21  	STP_MSG      = 0x4242
    22  	STP_BPDU_MSG = 0xAAAA
    23  )
    24  
    25  type Ethernet struct {
    26  	Delimiter uint8
    27  	HWDst     net.HardwareAddr
    28  	HWSrc     net.HardwareAddr
    29  	VLANID    VLAN
    30  	Ethertype uint16
    31  	Data      util.Message
    32  }
    33  
    34  func NewEthernet() *Ethernet {
    35  	eth := new(Ethernet)
    36  	eth.HWDst = net.HardwareAddr(make([]byte, 6))
    37  	eth.HWSrc = net.HardwareAddr(make([]byte, 6))
    38  	eth.VLANID = *NewVLAN()
    39  	eth.Ethertype = 0x800
    40  	eth.Data = nil
    41  	return eth
    42  }
    43  
    44  func (e *Ethernet) Len() (n uint16) {
    45  	n = 0
    46  	n += 12
    47  	if e.VLANID.VID != 0 {
    48  		n += 4
    49  	}
    50  	n += 2
    51  	if e.Data != nil {
    52  		n += e.Data.Len()
    53  	}
    54  	return
    55  }
    56  
    57  func (e *Ethernet) MarshalBinary() (data []byte, err error) {
    58  	data = make([]byte, int(e.Len()))
    59  	bytes := make([]byte, 0)
    60  	n := 0
    61  	copy(data[n:], e.HWDst)
    62  	n += len(e.HWDst)
    63  	copy(data[n:], e.HWSrc)
    64  	n += len(e.HWSrc)
    65  
    66  	if e.VLANID.VID != 0 {
    67  		bytes, err = e.VLANID.MarshalBinary()
    68  		if err != nil {
    69  			return
    70  		}
    71  		copy(data[n:], bytes)
    72  		n += len(bytes)
    73  	}
    74  
    75  	binary.BigEndian.PutUint16(data[n:n+2], e.Ethertype)
    76  	n += 2
    77  
    78  	if e.Data != nil {
    79  		bytes, err = e.Data.MarshalBinary()
    80  		if err != nil {
    81  			return
    82  		}
    83  		copy(data[n:n+len(bytes)], bytes)
    84  	}
    85  	return
    86  }
    87  
    88  func (e *Ethernet) UnmarshalBinary(data []byte) error {
    89  	if len(data) < 14 {
    90  		return errors.New("The []byte is too short to unmarshal a full Ethernet message.")
    91  	}
    92  	n := 0
    93  	e.HWDst = net.HardwareAddr(make([]byte, 6))
    94  	copy(e.HWDst, data[n:n+6])
    95  	n += 6
    96  	e.HWSrc = net.HardwareAddr(make([]byte, 6))
    97  	copy(e.HWSrc, data[n:n+6])
    98  	n += 6
    99  
   100  	e.Ethertype = binary.BigEndian.Uint16(data[n:])
   101  	if e.Ethertype == VLAN_MSG {
   102  		e.VLANID = *new(VLAN)
   103  		err := e.VLANID.UnmarshalBinary(data[n:])
   104  		if err != nil {
   105  			return err
   106  		}
   107  		n += int(e.VLANID.Len())
   108  
   109  		e.Ethertype = binary.BigEndian.Uint16(data[n:])
   110  	} else {
   111  		e.VLANID = *new(VLAN)
   112  		e.VLANID.VID = 0
   113  	}
   114  	n += 2
   115  
   116  	switch e.Ethertype {
   117  	case IPv4_MSG:
   118  		e.Data = new(IPv4)
   119  	case IPv6_MSG:
   120  		e.Data = new(IPv6)
   121  	case ARP_MSG:
   122  		e.Data = new(ARP)
   123  	default:
   124  		e.Data = new(util.Buffer)
   125  	}
   126  	return e.Data.UnmarshalBinary(data[n:])
   127  }
   128  
   129  const (
   130  	PCP_MASK = 0xe000
   131  	DEI_MASK = 0x1000
   132  	VID_MASK = 0x0fff
   133  )
   134  
   135  type VLAN struct {
   136  	TPID uint16
   137  	PCP  uint8
   138  	DEI  uint8
   139  	VID  uint16
   140  }
   141  
   142  func NewVLAN() *VLAN {
   143  	v := new(VLAN)
   144  	v.TPID = 0x8100
   145  	v.VID = 0
   146  	return v
   147  }
   148  
   149  func (v *VLAN) Len() (n uint16) {
   150  	return 4
   151  }
   152  
   153  func (v *VLAN) MarshalBinary() (data []byte, err error) {
   154  	data = make([]byte, v.Len())
   155  	binary.BigEndian.PutUint16(data[:2], v.TPID)
   156  	var tci uint16
   157  	tci = (tci | uint16(v.PCP)<<13) + (tci | uint16(v.DEI)<<12) + (tci | v.VID)
   158  	binary.BigEndian.PutUint16(data[2:], tci)
   159  	return
   160  }
   161  
   162  func (v *VLAN) UnmarshalBinary(data []byte) error {
   163  	if len(data) < 4 {
   164  		return errors.New("The []byte is too short to unmarshal a full VLAN header.")
   165  	}
   166  	v.TPID = binary.BigEndian.Uint16(data[:2])
   167  	var tci uint16
   168  	tci = binary.BigEndian.Uint16(data[2:])
   169  	v.PCP = uint8(PCP_MASK & tci >> 13)
   170  	v.DEI = uint8(DEI_MASK & tci >> 12)
   171  	v.VID = VID_MASK & tci
   172  	return nil
   173  }