You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
subgraph-oz/network/daemon.go

201 lines
4.3 KiB

package network
import(
//Builtin
"errors"
"fmt"
//"math"
"net"
"os"
//"os/exec"
"strings"
//Internal
//External
"github.com/milosgajdos83/tenus"
"github.com/op/go-logging"
)
func BridgeInit(log *logging.Logger) (*HostNetwork, error) {
htn := new(HostNetwork)
if os.Getpid() == 1 {
panic(errors.New("Cannot use netinit from child."))
}
// Fetch the bridge interface by ifname
brL, err := net.InterfaceByName(ozDefaultInterfaceBridge)
if err != nil {
log.Info("Bridge not found, attempting to create a new one")
_, err = createNewBridge(log)
if err != nil {
return nil, fmt.Errorf("Unable to create bridge %+v", err)
}
// Load the new interface
brL, _ = net.InterfaceByName(ozDefaultInterfaceBridge)
} else {
log.Info("Bridge already exists attempting to reuse it")
}
// Lookup the bridge ip addresses
addrs, _ := brL.Addrs()
if len(addrs) == 0 {
return nil, errors.New("Host bridge does not have an IP address assigned")
}
// Try to build the network config from the bridge's address
addrIndex := -1
for i, addr := range addrs {
bIP, brIP, _ := net.ParseCIDR(addr.String())
// Discard IPv6 (TODO...)
if bIP.To4() != nil {
addrIndex = i
bMask := []byte(brIP.Mask)
htn.netmask = net.IPv4(bMask[0], bMask[1], bMask[2], bMask[3])
htn.gateway = net.ParseIP(strings.Split(addr.String(), "/")[0])
htn.class = strings.Split(addr.String(), "/")[1]
htn.broadcast = net_getbroadcast(bIP, brIP.Mask)
htn.min = inet_aton(bIP)
htn.min++
htn.max = inet_aton(htn.broadcast)
htn.max--
break
}
}
if addrIndex < 0 {
return nil, errors.New("Could not find IPv4 for bridge interface")
}
return htn, nil
}
// Create a new bridge on the host
// Assign it an unused range
// And bring the interface up
func createNewBridge(log *logging.Logger) (tenus.Bridger, error) {
if os.Getpid() == 1 {
panic(errors.New("Cannot use netinit from child."))
}
// Create the bridge
br, err := tenus.NewBridgeWithName(ozDefaultInterfaceBridge)
if err != nil {
return nil, err
}
// Lookup an empty ip range
brIp, brIpNet, err := findEmptyRange(log)
if err != nil {
return nil, errors.New("Could not find an ip range to assign to the bridge")
}
// Setup the bridge's address
if err := br.SetLinkIp(brIp, brIpNet); err != nil {
return nil, err
}
// Bridge the interface up
if err = br.SetLinkUp(); err != nil {
return nil, fmt.Errorf("Unable to bring bridge '%+v' up: %+v", ozDefaultInterfaceBridge, err)
}
return br, nil
}
// Look at all the assigned IP address and try to find an available range
// Returns a ip range in the CIDR form if found or an empty string
func findEmptyRange(log *logging.Logger) (net.IP, *net.IPNet, error) {
type localNet struct {
min uint64
max uint64
}
var (
localNets []localNet
availableRange string
)
// List all the available interfaces and their addresses
// and calulate their network's min and max values
ifs, _ := net.Interfaces()
for _, netif := range ifs {
// Disable loopback and our bridge
if netif.Name == ozDefaultInterfaceBridge ||
strings.HasPrefix(netif.Name, "lo") {
continue
}
// Go through each address on the interface
addrs, _ := netif.Addrs()
for _, addr := range addrs {
bIP, brIP, _ := net.ParseCIDR(addr.String())
// Discard non IPv4 addresses
if bIP.To4() != nil {
min := inet_aton(brIP.IP)
min++
max := inet_aton(net_getbroadcast(bIP, brIP.Mask))
max--
localNets = append(localNets, localNet{min: min, max: max})
}
}
}
// Go through the list of private network ranges and
// look for one in which we cannot find a local network
for _, ipRange := range privateNetworkRanges {
bIP, brIP, err := net.ParseCIDR(ipRange)
if err != nil {
continue
}
bMin := inet_aton(bIP)
bMax := inet_aton(net_getbroadcast(bIP, brIP.Mask))
alreadyUsed := false
for _, add := range localNets {
if add.min >= bMin && add.min < bMax &&
add.max > bMin && add.max <= bMax {
alreadyUsed = true
break
}
}
// If the range is available, grab a small slice
if alreadyUsed == false {
bRange := bMax - bMin
if bRange > 0xFF {
bMin = bMax - 0xFE
}
availableRange = inet_ntoa(bMin).String() + "/24"
log.Info("Found available range: %+v", availableRange)
return net.ParseCIDR(availableRange)
}
}
return nil, nil, errors.New("Could not find an available range")
}