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 }