mirror of https://github.com/kubernetes/kops.git
				
				
				
			
		
			
				
	
	
		
			111 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
| // +build peer_name_mac !peer_name_alternative
 | |
| 
 | |
| package mesh
 | |
| 
 | |
| // The !peer_name_alternative effectively makes this the default,
 | |
| // i.e. to choose an alternative, run
 | |
| //
 | |
| //   go build -tags 'peer_name_alternative peer_name_hash'
 | |
| //
 | |
| // Let peer names be MACs...
 | |
| //
 | |
| // MACs need to be unique across our network, or bad things will
 | |
| // happen anyway. So they make pretty good candidates for peer
 | |
| // names. And doing so is pretty efficient both computationally and
 | |
| // network overhead wise.
 | |
| //
 | |
| // Note that we do not mandate *what* MAC should be used as the peer
 | |
| // name. In particular it doesn't actually have to be the MAC of, say,
 | |
| // the network interface the peer is sniffing on.
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| )
 | |
| 
 | |
| // PeerName is used as a map key. Since net.HardwareAddr isn't suitable for
 | |
| // that - it's a slice, and slices can't be map keys - we convert that to/from
 | |
| // uint64.
 | |
| type PeerName uint64
 | |
| 
 | |
| const (
 | |
| 	// PeerNameFlavour is the type of peer names we use.
 | |
| 	PeerNameFlavour = "mac"
 | |
| 
 | |
| 	// NameSize is the number of bytes in a peer name.
 | |
| 	NameSize = 6
 | |
| 
 | |
| 	// UnknownPeerName is used as a sentinel value.
 | |
| 	UnknownPeerName = PeerName(0)
 | |
| )
 | |
| 
 | |
| // PeerNameFromUserInput parses PeerName from a user-provided string.
 | |
| func PeerNameFromUserInput(userInput string) (PeerName, error) {
 | |
| 	return PeerNameFromString(userInput)
 | |
| }
 | |
| 
 | |
| // PeerNameFromString parses PeerName from a generic string.
 | |
| func PeerNameFromString(nameStr string) (PeerName, error) {
 | |
| 	var a, b, c, d, e, f uint64
 | |
| 
 | |
| 	match := func(format string, args ...interface{}) bool {
 | |
| 		a, b, c, d, e, f = 0, 0, 0, 0, 0, 0
 | |
| 		n, err := fmt.Sscanf(nameStr+"\000", format+"\000", args...)
 | |
| 		return err == nil && n == len(args)
 | |
| 	}
 | |
| 
 | |
| 	switch {
 | |
| 	case match("%2x:%2x:%2x:%2x:%2x:%2x", &a, &b, &c, &d, &e, &f):
 | |
| 	case match("::%2x:%2x:%2x:%2x", &c, &d, &e, &f):
 | |
| 	case match("%2x::%2x:%2x:%2x", &a, &d, &e, &f):
 | |
| 	case match("%2x:%2x::%2x:%2x", &a, &b, &e, &f):
 | |
| 	case match("%2x:%2x:%2x::%2x", &a, &b, &c, &f):
 | |
| 	case match("%2x:%2x:%2x:%2x::", &a, &b, &c, &d):
 | |
| 	case match("::%2x:%2x:%2x", &d, &e, &f):
 | |
| 	case match("%2x::%2x:%2x", &a, &e, &f):
 | |
| 	case match("%2x:%2x::%2x", &a, &b, &f):
 | |
| 	case match("%2x:%2x:%2x::", &a, &b, &c):
 | |
| 	case match("::%2x:%2x", &e, &f):
 | |
| 	case match("%2x::%2x", &a, &f):
 | |
| 	case match("%2x:%2x::", &a, &b):
 | |
| 	case match("::%2x", &f):
 | |
| 	case match("%2x::", &a):
 | |
| 	default:
 | |
| 		return UnknownPeerName, fmt.Errorf("invalid peer name format: %q", nameStr)
 | |
| 	}
 | |
| 
 | |
| 	return PeerName(a<<40 | b<<32 | c<<24 | d<<16 | e<<8 | f), nil
 | |
| }
 | |
| 
 | |
| // PeerNameFromBin parses PeerName from a byte slice.
 | |
| func PeerNameFromBin(nameByte []byte) PeerName {
 | |
| 	return PeerName(macint(net.HardwareAddr(nameByte)))
 | |
| }
 | |
| 
 | |
| // bytes encodes PeerName as a byte slice.
 | |
| func (name PeerName) bytes() []byte {
 | |
| 	return intmac(uint64(name))
 | |
| }
 | |
| 
 | |
| // String encodes PeerName as a string.
 | |
| func (name PeerName) String() string {
 | |
| 	return intmac(uint64(name)).String()
 | |
| }
 | |
| 
 | |
| func macint(mac net.HardwareAddr) (r uint64) {
 | |
| 	for _, b := range mac {
 | |
| 		r <<= 8
 | |
| 		r |= uint64(b)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func intmac(key uint64) (r net.HardwareAddr) {
 | |
| 	r = make([]byte, 6)
 | |
| 	for i := 5; i >= 0; i-- {
 | |
| 		r[i] = byte(key)
 | |
| 		key >>= 8
 | |
| 	}
 | |
| 	return
 | |
| }
 |