mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
a0a473125b
After moving libnetwork to this repo, we need to update all the import paths for libnetwork to point to docker/docker/libnetwork instead of docker/libnetwork. This change implements that. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
384 lines
7.8 KiB
Go
384 lines
7.8 KiB
Go
package overlay
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/Microsoft/hcsshim"
|
|
"github.com/docker/docker/libnetwork/driverapi"
|
|
"github.com/docker/docker/libnetwork/netlabel"
|
|
"github.com/docker/docker/libnetwork/portmapper"
|
|
"github.com/docker/docker/libnetwork/types"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
hostMode bool
|
|
networkMu sync.Mutex
|
|
)
|
|
|
|
type networkTable map[string]*network
|
|
|
|
type subnet struct {
|
|
vni uint32
|
|
subnetIP *net.IPNet
|
|
gwIP *net.IP
|
|
}
|
|
|
|
type subnetJSON struct {
|
|
SubnetIP string
|
|
GwIP string
|
|
Vni uint32
|
|
}
|
|
|
|
type network struct {
|
|
id string
|
|
name string
|
|
hnsID string
|
|
providerAddress string
|
|
interfaceName string
|
|
endpoints endpointTable
|
|
driver *driver
|
|
initEpoch int
|
|
initErr error
|
|
subnets []*subnet
|
|
secure bool
|
|
portMapper *portmapper.PortMapper
|
|
sync.Mutex
|
|
}
|
|
|
|
func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
|
|
return nil, types.NotImplementedErrorf("not implemented")
|
|
}
|
|
|
|
func (d *driver) NetworkFree(id string) error {
|
|
return types.NotImplementedErrorf("not implemented")
|
|
}
|
|
|
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
|
var (
|
|
networkName string
|
|
interfaceName string
|
|
staleNetworks []string
|
|
)
|
|
|
|
if id == "" {
|
|
return fmt.Errorf("invalid network id")
|
|
}
|
|
|
|
if nInfo == nil {
|
|
return fmt.Errorf("invalid network info structure")
|
|
}
|
|
|
|
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
|
return types.BadRequestErrorf("ipv4 pool is empty")
|
|
}
|
|
|
|
staleNetworks = make([]string, 0)
|
|
vnis := make([]uint32, 0, len(ipV4Data))
|
|
|
|
existingNetwork := d.network(id)
|
|
if existingNetwork != nil {
|
|
logrus.Debugf("Network preexists. Deleting %s", id)
|
|
err := d.DeleteNetwork(id)
|
|
if err != nil {
|
|
logrus.Errorf("Error deleting stale network %s", err.Error())
|
|
}
|
|
}
|
|
|
|
n := &network{
|
|
id: id,
|
|
driver: d,
|
|
endpoints: endpointTable{},
|
|
subnets: []*subnet{},
|
|
portMapper: portmapper.New(""),
|
|
}
|
|
|
|
genData, ok := option[netlabel.GenericData].(map[string]string)
|
|
|
|
if !ok {
|
|
return fmt.Errorf("Unknown generic data option")
|
|
}
|
|
|
|
for label, value := range genData {
|
|
switch label {
|
|
case "com.docker.network.windowsshim.networkname":
|
|
networkName = value
|
|
case "com.docker.network.windowsshim.interface":
|
|
interfaceName = value
|
|
case "com.docker.network.windowsshim.hnsid":
|
|
n.hnsID = value
|
|
case netlabel.OverlayVxlanIDList:
|
|
vniStrings := strings.Split(value, ",")
|
|
for _, vniStr := range vniStrings {
|
|
vni, err := strconv.Atoi(vniStr)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid vxlan id value %q passed", vniStr)
|
|
}
|
|
|
|
vnis = append(vnis, uint32(vni))
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we are getting vnis from libnetwork, either we get for
|
|
// all subnets or none.
|
|
if len(vnis) < len(ipV4Data) {
|
|
return fmt.Errorf("insufficient vnis(%d) passed to overlay. Windows driver requires VNIs to be prepopulated", len(vnis))
|
|
}
|
|
|
|
for i, ipd := range ipV4Data {
|
|
s := &subnet{
|
|
subnetIP: ipd.Pool,
|
|
gwIP: &ipd.Gateway.IP,
|
|
}
|
|
|
|
if len(vnis) != 0 {
|
|
s.vni = vnis[i]
|
|
}
|
|
|
|
d.Lock()
|
|
for _, network := range d.networks {
|
|
found := false
|
|
for _, sub := range network.subnets {
|
|
if sub.vni == s.vni {
|
|
staleNetworks = append(staleNetworks, network.id)
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
break
|
|
}
|
|
}
|
|
d.Unlock()
|
|
|
|
n.subnets = append(n.subnets, s)
|
|
}
|
|
|
|
for _, staleNetwork := range staleNetworks {
|
|
d.DeleteNetwork(staleNetwork)
|
|
}
|
|
|
|
n.name = networkName
|
|
if n.name == "" {
|
|
n.name = id
|
|
}
|
|
|
|
n.interfaceName = interfaceName
|
|
|
|
if nInfo != nil {
|
|
if err := nInfo.TableEventRegister(ovPeerTable, driverapi.EndpointObject); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
d.addNetwork(n)
|
|
|
|
err := d.createHnsNetwork(n)
|
|
|
|
if err != nil {
|
|
d.deleteNetwork(id)
|
|
} else {
|
|
genData["com.docker.network.windowsshim.hnsid"] = n.hnsID
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (d *driver) DeleteNetwork(nid string) error {
|
|
if nid == "" {
|
|
return fmt.Errorf("invalid network id")
|
|
}
|
|
|
|
n := d.network(nid)
|
|
if n == nil {
|
|
return types.ForbiddenErrorf("could not find network with id %s", nid)
|
|
}
|
|
|
|
_, err := hcsshim.HNSNetworkRequest("DELETE", n.hnsID, "")
|
|
if err != nil {
|
|
return types.ForbiddenErrorf(err.Error())
|
|
}
|
|
|
|
d.deleteNetwork(nid)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) addNetwork(n *network) {
|
|
d.Lock()
|
|
d.networks[n.id] = n
|
|
d.Unlock()
|
|
}
|
|
|
|
func (d *driver) deleteNetwork(nid string) {
|
|
d.Lock()
|
|
delete(d.networks, nid)
|
|
d.Unlock()
|
|
}
|
|
|
|
func (d *driver) network(nid string) *network {
|
|
d.Lock()
|
|
defer d.Unlock()
|
|
return d.networks[nid]
|
|
}
|
|
|
|
// func (n *network) restoreNetworkEndpoints() error {
|
|
// logrus.Infof("Restoring endpoints for overlay network: %s", n.id)
|
|
|
|
// hnsresponse, err := hcsshim.HNSListEndpointRequest("GET", "", "")
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
|
|
// for _, endpoint := range hnsresponse {
|
|
// if endpoint.VirtualNetwork != n.hnsID {
|
|
// continue
|
|
// }
|
|
|
|
// ep := n.convertToOverlayEndpoint(&endpoint)
|
|
|
|
// if ep != nil {
|
|
// logrus.Debugf("Restored endpoint:%s Remote:%t", ep.id, ep.remote)
|
|
// n.addEndpoint(ep)
|
|
// }
|
|
// }
|
|
|
|
// return nil
|
|
// }
|
|
|
|
func (n *network) convertToOverlayEndpoint(v *hcsshim.HNSEndpoint) *endpoint {
|
|
ep := &endpoint{
|
|
id: v.Name,
|
|
profileID: v.Id,
|
|
nid: n.id,
|
|
remote: v.IsRemoteEndpoint,
|
|
}
|
|
|
|
mac, err := net.ParseMAC(v.MacAddress)
|
|
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
ep.mac = mac
|
|
ep.addr = &net.IPNet{
|
|
IP: v.IPAddress,
|
|
Mask: net.CIDRMask(32, 32),
|
|
}
|
|
|
|
return ep
|
|
}
|
|
|
|
func (d *driver) createHnsNetwork(n *network) error {
|
|
|
|
subnets := []hcsshim.Subnet{}
|
|
|
|
for _, s := range n.subnets {
|
|
subnet := hcsshim.Subnet{
|
|
AddressPrefix: s.subnetIP.String(),
|
|
}
|
|
|
|
if s.gwIP != nil {
|
|
subnet.GatewayAddress = s.gwIP.String()
|
|
}
|
|
|
|
vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
|
|
Type: "VSID",
|
|
VSID: uint(s.vni),
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
subnet.Policies = append(subnet.Policies, vsidPolicy)
|
|
subnets = append(subnets, subnet)
|
|
}
|
|
|
|
network := &hcsshim.HNSNetwork{
|
|
Name: n.name,
|
|
Type: d.Type(),
|
|
Subnets: subnets,
|
|
NetworkAdapterName: n.interfaceName,
|
|
AutomaticDNS: true,
|
|
}
|
|
|
|
configurationb, err := json.Marshal(network)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
configuration := string(configurationb)
|
|
logrus.Infof("HNSNetwork Request =%v", configuration)
|
|
|
|
hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
n.hnsID = hnsresponse.Id
|
|
n.providerAddress = hnsresponse.ManagementIP
|
|
|
|
return nil
|
|
}
|
|
|
|
// contains return true if the passed ip belongs to one the network's
|
|
// subnets
|
|
func (n *network) contains(ip net.IP) bool {
|
|
for _, s := range n.subnets {
|
|
if s.subnetIP.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// getSubnetforIP returns the subnet to which the given IP belongs
|
|
func (n *network) getSubnetforIP(ip *net.IPNet) *subnet {
|
|
for _, s := range n.subnets {
|
|
// first check if the mask lengths are the same
|
|
i, _ := s.subnetIP.Mask.Size()
|
|
j, _ := ip.Mask.Size()
|
|
if i != j {
|
|
continue
|
|
}
|
|
if s.subnetIP.Contains(ip.IP) {
|
|
return s
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// getMatchingSubnet return the network's subnet that matches the input
|
|
func (n *network) getMatchingSubnet(ip *net.IPNet) *subnet {
|
|
if ip == nil {
|
|
return nil
|
|
}
|
|
for _, s := range n.subnets {
|
|
// first check if the mask lengths are the same
|
|
i, _ := s.subnetIP.Mask.Size()
|
|
j, _ := ip.Mask.Size()
|
|
if i != j {
|
|
continue
|
|
}
|
|
if s.subnetIP.IP.Equal(ip.IP) {
|
|
return s
|
|
}
|
|
}
|
|
return nil
|
|
}
|