github.com/imran-kn/cilium-fork@v1.6.9/pkg/mac/mac.go (about)

     1  // Copyright 2016-2017 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mac
    16  
    17  import (
    18  	"bytes"
    19  	"crypto/rand"
    20  	"encoding/hex"
    21  	"fmt"
    22  	"net"
    23  )
    24  
    25  // MAC address is an net.HardwareAddr encapsulation to force cilium to only use MAC-48.
    26  type MAC net.HardwareAddr
    27  
    28  // String returns the string representation of m.
    29  func (m MAC) String() string {
    30  	return net.HardwareAddr(m).String()
    31  }
    32  
    33  // ParseMAC parses s only as an IEEE 802 MAC-48.
    34  func ParseMAC(s string) (MAC, error) {
    35  	ha, err := net.ParseMAC(s)
    36  	if err != nil {
    37  		return MAC{}, err
    38  	}
    39  	if len(ha) != 6 {
    40  		return MAC{}, fmt.Errorf("invalid MAC address %s", s)
    41  	}
    42  
    43  	return MAC(ha), nil
    44  }
    45  
    46  // Uint64 returns the MAC in uint64 format. The MAC is represented as little-endian in
    47  // the returned value.
    48  // Example:
    49  //  m := MAC([]{0x11, 0x12, 0x23, 0x34, 0x45, 0x56})
    50  //  v, err := m.Uint64()
    51  //  fmt.Printf("0x%X", v) // 0x564534231211
    52  func (m MAC) Uint64() (uint64, error) {
    53  	if len(m) != 6 {
    54  		return 0, fmt.Errorf("invalid MAC address %s", m.String())
    55  	}
    56  
    57  	return uint64(m[5])<<40 | uint64(m[4])<<32 | uint64(m[3])<<24 |
    58  		uint64(m[2])<<16 | uint64(m[1])<<8 | uint64(m[0]), nil
    59  }
    60  
    61  func (m MAC) MarshalJSON() ([]byte, error) {
    62  	if len(m) == 0 {
    63  		return []byte(`""`), nil
    64  	}
    65  	if len(m) != 6 {
    66  		return nil, fmt.Errorf("invalid MAC address length %s", string(m))
    67  	}
    68  	return []byte(fmt.Sprintf("\"%02x:%02x:%02x:%02x:%02x:%02x\"", m[0], m[1], m[2], m[3], m[4], m[5])), nil
    69  }
    70  
    71  func (m MAC) MarshalIndentJSON(prefix, indent string) ([]byte, error) {
    72  	return m.MarshalJSON()
    73  }
    74  
    75  func (m *MAC) UnmarshalJSON(data []byte) error {
    76  	if len(data) == len([]byte(`""`)) {
    77  		if m == nil {
    78  			m = new(MAC)
    79  		}
    80  		*m = MAC{}
    81  		return nil
    82  	}
    83  	if len(data) != 19 {
    84  		return fmt.Errorf("invalid MAC address length %s", string(data))
    85  	}
    86  	data = data[1 : len(data)-1]
    87  	macStr := bytes.Replace(data, []byte(`:`), []byte(``), -1)
    88  	if len(macStr) != 12 {
    89  		return fmt.Errorf("invalid MAC address format")
    90  	}
    91  	macByte := make([]byte, len(macStr))
    92  	hex.Decode(macByte, macStr)
    93  	*m = MAC{macByte[0], macByte[1], macByte[2], macByte[3], macByte[4], macByte[5]}
    94  	return nil
    95  }
    96  
    97  // GenerateRandMAC generates a random unicast and locally administered MAC address.
    98  func GenerateRandMAC() (MAC, error) {
    99  	buf := make([]byte, 6)
   100  	if _, err := rand.Read(buf); err != nil {
   101  		return nil, fmt.Errorf("Unable to retrieve 6 rnd bytes: %s", err)
   102  	}
   103  
   104  	// Set locally administered addresses bit and reset multicast bit
   105  	buf[0] = (buf[0] | 0x02) & 0xfe
   106  
   107  	return MAC(buf), nil
   108  }