mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
commit
d4270c1764
23 changed files with 486 additions and 81 deletions
|
@ -16,7 +16,6 @@ network. Docker Engine supports multi-host networking out-of-the-box through the
|
|||
`overlay` network driver. Unlike `bridge` networks, overlay networks require
|
||||
some pre-existing conditions before you can create one. These conditions are:
|
||||
|
||||
* A host with a 3.16 kernel version or higher.
|
||||
* Access to a key-value store. Docker supports Consul, Etcd, and ZooKeeper (Distributed store) key-value stores.
|
||||
* A cluster of hosts with connectivity to the key-value store.
|
||||
* A properly configured Engine `daemon` on each host in the cluster.
|
||||
|
|
|
@ -24,7 +24,7 @@ clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
|
|||
clone git github.com/docker/go-connections 4e42727957c146776e5de9cec8c39e4059ed9f20
|
||||
|
||||
#get libnetwork packages
|
||||
clone git github.com/docker/libnetwork bbd6e6d8ca1e7c9b42f6f53277b0bde72847ff90
|
||||
clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436
|
||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||
|
|
|
@ -121,7 +121,8 @@ type driverData struct {
|
|||
}
|
||||
|
||||
type ipamData struct {
|
||||
driver ipamapi.Ipam
|
||||
driver ipamapi.Ipam
|
||||
capability *ipamapi.Capability
|
||||
// default address spaces are provided by ipam driver at registration time
|
||||
defaultLocalAddressSpace, defaultGlobalAddressSpace string
|
||||
}
|
||||
|
@ -306,7 +307,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
|
||||
func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
||||
if !config.IsValidName(name) {
|
||||
return ErrInvalidName(name)
|
||||
}
|
||||
|
@ -322,7 +323,7 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error
|
|||
return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
|
||||
}
|
||||
c.Lock()
|
||||
c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
|
||||
c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps}
|
||||
c.Unlock()
|
||||
|
||||
log.Debugf("Registering ipam driver: %q", name)
|
||||
|
@ -330,6 +331,14 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
|
||||
return c.registerIpamDriver(name, driver, &ipamapi.Capability{})
|
||||
}
|
||||
|
||||
func (c *controller) RegisterIpamDriverWithCapabilities(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
||||
return c.registerIpamDriver(name, driver, caps)
|
||||
}
|
||||
|
||||
// NewNetwork creates a new network of the specified network type. The options
|
||||
// are network specific and modeled in a generic way.
|
||||
func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
|
||||
|
|
|
@ -103,6 +103,9 @@ func (sb *sandbox) needDefaultGW() bool {
|
|||
if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
|
||||
continue
|
||||
}
|
||||
if ep.getNetwork().Internal() {
|
||||
return false
|
||||
}
|
||||
if ep.joinInfo.disableGatewayService {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -490,6 +490,12 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
|
|||
config.EnableIPv6 = val.(bool)
|
||||
}
|
||||
|
||||
if val, ok := option[netlabel.Internal]; ok {
|
||||
if internal, ok := val.(bool); ok && internal {
|
||||
return nil, &driverapi.ErrNotImplemented{}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally validate the configuration
|
||||
if err = config.Validate(); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -157,6 +157,6 @@ func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) {
|
|||
}
|
||||
|
||||
func isRunningInContainer() bool {
|
||||
_, err := os.Stat("/.dockerinit")
|
||||
_, err := os.Stat("/.dockerenv")
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
|
|
|
@ -62,6 +62,13 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Store and program user specified bridge network and network gateway
|
||||
i.bridgeIPv6 = config.AddressIPv6
|
||||
i.gatewayIPv6 = config.AddressIPv6.IP
|
||||
if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: i.bridgeIPv6}); err != nil {
|
||||
return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
|
||||
}
|
||||
|
||||
// Setting route to global IPv6 subnet
|
||||
logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
|
||||
err = netlink.RouteAdd(&netlink.Route{
|
||||
|
|
131
vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go
vendored
Normal file
131
vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
)
|
||||
|
||||
const globalChain = "DOCKER-OVERLAY"
|
||||
|
||||
var filterOnce sync.Once
|
||||
|
||||
func rawIPTables(args ...string) error {
|
||||
if output, err := iptables.Raw(args...); err != nil {
|
||||
return fmt.Errorf("unable to add overlay filter: %v", err)
|
||||
} else if len(output) != 0 {
|
||||
return fmt.Errorf("unable to add overlay filter: %s", string(output))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func chainExists(cname string) bool {
|
||||
if _, err := iptables.Raw("-L", cname); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func setupGlobalChain() {
|
||||
if err := rawIPTables("-N", globalChain); err != nil {
|
||||
logrus.Debugf("could not create global overlay chain: %v", err)
|
||||
}
|
||||
|
||||
if err := rawIPTables("-A", globalChain, "-j", "RETURN"); err != nil {
|
||||
logrus.Debugf("could not install default return chain in the overlay global chain: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func setNetworkChain(cname string, remove bool) error {
|
||||
// Initialize the onetime global overlay chain
|
||||
filterOnce.Do(setupGlobalChain)
|
||||
|
||||
exists := chainExists(cname)
|
||||
|
||||
opt := "-N"
|
||||
// In case of remove, make sure to flush the rules in the chain
|
||||
if remove && exists {
|
||||
if err := rawIPTables("-F", cname); err != nil {
|
||||
return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
|
||||
}
|
||||
opt = "-X"
|
||||
}
|
||||
|
||||
if (!remove && !exists) || (remove && exists) {
|
||||
if err := rawIPTables(opt, cname); err != nil {
|
||||
return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !remove {
|
||||
if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") {
|
||||
if err := rawIPTables("-A", cname, "-j", "DROP"); err != nil {
|
||||
return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addNetworkChain(cname string) error {
|
||||
return setNetworkChain(cname, false)
|
||||
}
|
||||
|
||||
func removeNetworkChain(cname string) error {
|
||||
return setNetworkChain(cname, true)
|
||||
}
|
||||
|
||||
func setFilters(cname, brName string, remove bool) error {
|
||||
opt := "-I"
|
||||
if remove {
|
||||
opt = "-D"
|
||||
}
|
||||
|
||||
// Everytime we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
|
||||
if !remove {
|
||||
for _, chain := range []string{"OUTPUT", "FORWARD"} {
|
||||
exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain)
|
||||
if exists {
|
||||
if err := rawIPTables("-D", chain, "-j", globalChain); err != nil {
|
||||
return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := rawIPTables("-I", chain, "-j", globalChain); err != nil {
|
||||
return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert/Delete the rule to jump to per-bridge chain
|
||||
exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
|
||||
if (!remove && !exists) || (remove && exists) {
|
||||
if err := rawIPTables(opt, globalChain, "-o", brName, "-j", cname); err != nil {
|
||||
return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
|
||||
}
|
||||
}
|
||||
|
||||
exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
|
||||
if (!remove && exists) || (remove && !exists) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := rawIPTables(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
|
||||
return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addFilters(cname, brName string) error {
|
||||
return setFilters(cname, brName, false)
|
||||
}
|
||||
|
||||
func removeFilters(cname, brName string) error {
|
||||
return setFilters(cname, brName, true)
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
|
@ -12,11 +13,17 @@ import (
|
|||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/docker/libnetwork/resolvconf"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
var (
|
||||
hostMode bool
|
||||
hostModeOnce sync.Once
|
||||
)
|
||||
|
||||
type networkTable map[string]*network
|
||||
|
||||
type subnet struct {
|
||||
|
@ -87,22 +94,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
|
|||
return nil
|
||||
}
|
||||
|
||||
/* func (d *driver) createNetworkfromStore(nid string) (*network, error) {
|
||||
n := &network{
|
||||
id: nid,
|
||||
driver: d,
|
||||
endpoints: endpointTable{},
|
||||
once: &sync.Once{},
|
||||
subnets: []*subnet{},
|
||||
}
|
||||
|
||||
err := d.store.GetObject(datastore.Key(n.Key()...), n)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get network %q from data store, %v", nid, err)
|
||||
}
|
||||
return n, nil
|
||||
}*/
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
if nid == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
|
@ -171,24 +162,110 @@ func (n *network) destroySandbox() {
|
|||
}
|
||||
|
||||
for _, s := range n.subnets {
|
||||
if hostMode {
|
||||
if err := removeFilters(n.id[:12], s.brName); err != nil {
|
||||
logrus.Warnf("Could not remove overlay filters: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.vxlanName != "" {
|
||||
err := deleteVxlan(s.vxlanName)
|
||||
err := deleteInterface(s.vxlanName)
|
||||
if err != nil {
|
||||
logrus.Warnf("could not cleanup sandbox properly: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hostMode {
|
||||
if err := removeNetworkChain(n.id[:12]); err != nil {
|
||||
logrus.Warnf("could not remove network chain: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
sbox.Destroy()
|
||||
n.setSandbox(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *network) initSubnetSandbox(s *subnet) error {
|
||||
// create a bridge and vxlan device for this subnet and move it to the sandbox
|
||||
brName, err := netutils.GenerateIfaceName("bridge", 7)
|
||||
if err != nil {
|
||||
return err
|
||||
func setHostMode() {
|
||||
if os.Getenv("_OVERLAY_HOST_MODE") != "" {
|
||||
hostMode = true
|
||||
return
|
||||
}
|
||||
|
||||
err := createVxlan("testvxlan", 1)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to create testvxlan interface: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer deleteInterface("testvxlan")
|
||||
|
||||
path := "/proc/self/ns/net"
|
||||
f, err := os.OpenFile(path, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to open path %s for network namespace for setting host mode: %v", path, err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
nsFD := f.Fd()
|
||||
|
||||
iface, err := netlink.LinkByName("testvxlan")
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get link testvxlan: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// If we are not able to move the vxlan interface to a namespace
|
||||
// then fallback to host mode
|
||||
if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
|
||||
hostMode = true
|
||||
}
|
||||
}
|
||||
|
||||
func (n *network) generateVxlanName(s *subnet) string {
|
||||
return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
|
||||
}
|
||||
|
||||
func (n *network) generateBridgeName(s *subnet) string {
|
||||
return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
|
||||
}
|
||||
|
||||
func isOverlap(nw *net.IPNet) bool {
|
||||
var nameservers []string
|
||||
|
||||
if rc, err := resolvconf.Get(); err == nil {
|
||||
nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
|
||||
}
|
||||
|
||||
if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if err := netutils.CheckRouteOverlaps(nw); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *network) initSubnetSandbox(s *subnet) error {
|
||||
brName := n.generateBridgeName(s)
|
||||
vxlanName := n.generateVxlanName(s)
|
||||
|
||||
if hostMode {
|
||||
// Try to delete stale bridge interface if it exists
|
||||
deleteInterface(brName)
|
||||
// Try to delete the vxlan interface by vni if already present
|
||||
deleteVxlanByVNI(n.vxlanID(s))
|
||||
|
||||
if isOverlap(s.subnetIP) {
|
||||
return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String())
|
||||
}
|
||||
}
|
||||
|
||||
// create a bridge and vxlan device for this subnet and move it to the sandbox
|
||||
sbox := n.sandbox()
|
||||
|
||||
if err := sbox.AddInterface(brName, "br",
|
||||
|
@ -197,7 +274,7 @@ func (n *network) initSubnetSandbox(s *subnet) error {
|
|||
return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
vxlanName, err := createVxlan(n.vxlanID(s))
|
||||
err := createVxlan(vxlanName, n.vxlanID(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -207,6 +284,12 @@ func (n *network) initSubnetSandbox(s *subnet) error {
|
|||
return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
if hostMode {
|
||||
if err := addFilters(n.id[:12], brName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
s.vxlanName = vxlanName
|
||||
s.brName = brName
|
||||
|
@ -220,8 +303,16 @@ func (n *network) initSandbox() error {
|
|||
n.initEpoch++
|
||||
n.Unlock()
|
||||
|
||||
hostModeOnce.Do(setHostMode)
|
||||
|
||||
if hostMode {
|
||||
if err := addNetworkChain(n.id[:12]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sbox, err := osl.NewSandbox(
|
||||
osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true)
|
||||
osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), !hostMode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create network sandbox: %v", err)
|
||||
}
|
||||
|
|
|
@ -47,14 +47,9 @@ func createVethPair() (string, string, error) {
|
|||
return name1, name2, nil
|
||||
}
|
||||
|
||||
func createVxlan(vni uint32) (string, error) {
|
||||
func createVxlan(name string, vni uint32) error {
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
name, err := netutils.GenerateIfaceName("vxlan", 7)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error generating vxlan name: %v", err)
|
||||
}
|
||||
|
||||
vxlan := &netlink.Vxlan{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: name},
|
||||
VxlanId: int(vni),
|
||||
|
@ -66,23 +61,45 @@ func createVxlan(vni uint32) (string, error) {
|
|||
}
|
||||
|
||||
if err := netlink.LinkAdd(vxlan); err != nil {
|
||||
return "", fmt.Errorf("error creating vxlan interface: %v", err)
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func deleteVxlan(name string) error {
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
link, err := netlink.LinkByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)
|
||||
}
|
||||
|
||||
if err := netlink.LinkDel(link); err != nil {
|
||||
return fmt.Errorf("error deleting vxlan interface: %v", err)
|
||||
return fmt.Errorf("error creating vxlan interface: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteInterface(name string) error {
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
link, err := netlink.LinkByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find interface with name %s: %v", name, err)
|
||||
}
|
||||
|
||||
if err := netlink.LinkDel(link); err != nil {
|
||||
return fmt.Errorf("error deleting interface with name %s: %v", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteVxlanByVNI(vni uint32) error {
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
links, err := netlink.LinkList()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list interfaces while deleting vxlan interface by vni: %v", err)
|
||||
}
|
||||
|
||||
for _, l := range links {
|
||||
if l.Type() == "vxlan" && l.(*netlink.Vxlan).VxlanId == int(vni) {
|
||||
err = netlink.LinkDel(l)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("could not find a vxlan interface to delete with id %d", vni)
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
|||
d := &driver{
|
||||
networks: networkTable{},
|
||||
peerDb: peerNetworkMap{
|
||||
mp: map[string]peerMap{},
|
||||
mp: map[string]*peerMap{},
|
||||
},
|
||||
config: config,
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ type peerMap struct {
|
|||
}
|
||||
|
||||
type peerNetworkMap struct {
|
||||
mp map[string]peerMap
|
||||
mp map[string]*peerMap
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
|
|||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
d.peerDb.mp[nid] = peerMap{
|
||||
d.peerDb.mp[nid] = &peerMap{
|
||||
mp: make(map[string]peerEntry),
|
||||
}
|
||||
|
||||
|
|
|
@ -748,11 +748,8 @@ func (ep *endpoint) DataScope() string {
|
|||
return ep.getNetwork().DataScope()
|
||||
}
|
||||
|
||||
func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
|
||||
var (
|
||||
ipam ipamapi.Ipam
|
||||
err error
|
||||
)
|
||||
func (ep *endpoint) assignAddress(ipam ipamapi.Ipam, assignIPv4, assignIPv6 bool) error {
|
||||
var err error
|
||||
|
||||
n := ep.getNetwork()
|
||||
if n.Type() == "host" || n.Type() == "null" {
|
||||
|
@ -761,11 +758,6 @@ func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
|
|||
|
||||
log.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
|
||||
|
||||
ipam, err = n.getController().getIpamDriver(n.ipamType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if assignIPv4 {
|
||||
if err = ep.assignAddressVersion(4, ipam); err != nil {
|
||||
return err
|
||||
|
|
|
@ -486,21 +486,28 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
|
|||
// DumpDatabase dumps the internal info
|
||||
func (a *Allocator) DumpDatabase() string {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
aspaces := make(map[string]*addrSpace, len(a.addrSpaces))
|
||||
for as, aSpace := range a.addrSpaces {
|
||||
aspaces[as] = aSpace
|
||||
}
|
||||
a.Unlock()
|
||||
|
||||
var s string
|
||||
for as, aSpace := range a.addrSpaces {
|
||||
for as, aSpace := range aspaces {
|
||||
s = fmt.Sprintf("\n\n%s Config", as)
|
||||
aSpace.Lock()
|
||||
for k, config := range aSpace.subnets {
|
||||
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
||||
if config.Range == nil {
|
||||
a.retrieveBitmask(k, config.Pool)
|
||||
}
|
||||
}
|
||||
aSpace.Unlock()
|
||||
}
|
||||
|
||||
s = fmt.Sprintf("%s\n\nBitmasks", s)
|
||||
for k, bm := range a.addresses {
|
||||
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
|
||||
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%s: %s", k, bm))
|
||||
}
|
||||
|
||||
return s
|
||||
|
|
|
@ -22,8 +22,10 @@ const (
|
|||
|
||||
// Callback provides a Callback interface for registering an IPAM instance into LibNetwork
|
||||
type Callback interface {
|
||||
// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a ipam instance
|
||||
// RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork
|
||||
RegisterIpamDriver(name string, driver Ipam) error
|
||||
// RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify cpaabilities
|
||||
RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error
|
||||
}
|
||||
|
||||
/**************
|
||||
|
@ -70,3 +72,8 @@ type Ipam interface {
|
|||
// Release the address from the specified pool ID
|
||||
ReleaseAddress(string, net.IP) error
|
||||
}
|
||||
|
||||
// Capability represents the requirements and capabilities of the IPAM driver
|
||||
type Capability struct {
|
||||
RequiresMACAddress bool
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// messages between libnetwork and the remote ipam plugin
|
||||
package api
|
||||
|
||||
import "github.com/docker/libnetwork/ipamapi"
|
||||
|
||||
// Response is the basic response structure used in all responses
|
||||
type Response struct {
|
||||
Error string
|
||||
|
@ -17,6 +19,17 @@ func (r *Response) GetError() string {
|
|||
return r.Error
|
||||
}
|
||||
|
||||
// GetCapabilityResponse is the response of GetCapability request
|
||||
type GetCapabilityResponse struct {
|
||||
Response
|
||||
RequiresMACAddress bool
|
||||
}
|
||||
|
||||
// ToCapability converts the capability response into the internal ipam driver capaility structure
|
||||
func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability {
|
||||
return &ipamapi.Capability{RequiresMACAddress: capRes.RequiresMACAddress}
|
||||
}
|
||||
|
||||
// GetAddressSpacesResponse is the response to the ``get default address spaces`` request message
|
||||
type GetAddressSpacesResponse struct {
|
||||
Response
|
||||
|
|
|
@ -30,8 +30,17 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
|
|||
// Init registers a remote ipam when its plugin is activated
|
||||
func Init(cb ipamapi.Callback, l, g interface{}) error {
|
||||
plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) {
|
||||
if err := cb.RegisterIpamDriver(name, newAllocator(name, client)); err != nil {
|
||||
log.Errorf("error registering remote ipam %s due to %v", name, err)
|
||||
a := newAllocator(name, client)
|
||||
if cps, err := a.(*allocator).getCapabilities(); err == nil {
|
||||
if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
|
||||
log.Errorf("error registering remote ipam driver %s due to %v", name, err)
|
||||
}
|
||||
} else {
|
||||
log.Infof("remote ipam driver %s does not support capabilities", name)
|
||||
log.Debug(err)
|
||||
if err := cb.RegisterIpamDriver(name, a); err != nil {
|
||||
log.Errorf("error registering remote ipam driver %s due to %v", name, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
return nil
|
||||
|
@ -49,6 +58,14 @@ func (a *allocator) call(methodName string, arg interface{}, retVal PluginRespon
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
|
||||
var res api.GetCapabilityResponse
|
||||
if err := a.call("GetCapabilities", nil, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.ToCapability(), nil
|
||||
}
|
||||
|
||||
// GetDefaultAddressSpaces returns the local and global default address spaces
|
||||
func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
|
||||
res := &api.GetAddressSpacesResponse{}
|
||||
|
|
22
vendor/src/github.com/docker/libnetwork/ipamutils/utils_freebsd.go
vendored
Normal file
22
vendor/src/github.com/docker/libnetwork/ipamutils/utils_freebsd.go
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Package ipamutils provides utililty functions for ipam management
|
||||
package ipamutils
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
// ElectInterfaceAddresses looks for an interface on the OS with the specified name
|
||||
// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
|
||||
// it chooses from a predifined list the first IPv4 address which does not conflict
|
||||
// with other interfaces on the system.
|
||||
func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
|
||||
return nil, nil, types.NotImplementedErrorf("not supported on freebsd")
|
||||
}
|
||||
|
||||
// FindAvailableNetwork returns a network from the passed list which does not
|
||||
// overlap with existing interfaces in the system
|
||||
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
||||
return nil, types.NotImplementedErrorf("not supported on freebsd")
|
||||
}
|
|
@ -41,6 +41,9 @@ const (
|
|||
|
||||
// Gateway represents the gateway for the network
|
||||
Gateway = Prefix + ".gateway"
|
||||
|
||||
// Internal constant represents that the network is internal which disables default gateway service
|
||||
Internal = Prefix + ".internal"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/docker/libnetwork/etchosts"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
@ -58,6 +59,7 @@ type Network interface {
|
|||
// NetworkInfo returns some configuration and operational information about the network
|
||||
type NetworkInfo interface {
|
||||
IpamConfig() (string, []*IpamConf, []*IpamConf)
|
||||
IpamInfo() ([]*IpamInfo, []*IpamInfo)
|
||||
DriverOptions() map[string]string
|
||||
Scope() string
|
||||
}
|
||||
|
@ -161,6 +163,7 @@ type network struct {
|
|||
persist bool
|
||||
stopWatchCh chan struct{}
|
||||
drvOnce *sync.Once
|
||||
internal bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -303,6 +306,7 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
|||
dstN.dbIndex = n.dbIndex
|
||||
dstN.dbExists = n.dbExists
|
||||
dstN.drvOnce = n.drvOnce
|
||||
dstN.internal = n.internal
|
||||
|
||||
for _, v4conf := range n.ipamV4Config {
|
||||
dstV4Conf := &IpamConf{}
|
||||
|
@ -389,6 +393,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
netMap["ipamV6Info"] = string(iis)
|
||||
}
|
||||
netMap["internal"] = n.internal
|
||||
return json.Marshal(netMap)
|
||||
}
|
||||
|
||||
|
@ -452,6 +457,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if v, ok := netMap["internal"]; ok {
|
||||
n.internal = v.(bool)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -478,6 +486,18 @@ func NetworkOptionPersist(persist bool) NetworkOption {
|
|||
}
|
||||
}
|
||||
|
||||
// NetworkOptionInternalNetwork returns an option setter to config the network
|
||||
// to be internal which disables default gateway service
|
||||
func NetworkOptionInternalNetwork() NetworkOption {
|
||||
return func(n *network) {
|
||||
n.internal = true
|
||||
if n.generic == nil {
|
||||
n.generic = make(map[string]interface{})
|
||||
}
|
||||
n.generic[netlabel.Internal] = true
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkOptionIpam function returns an option setter for the ipam configuration for this network
|
||||
func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf) NetworkOption {
|
||||
return func(n *network) {
|
||||
|
@ -678,7 +698,22 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
}
|
||||
}
|
||||
|
||||
if err = ep.assignAddress(true, !n.postIPv6); err != nil {
|
||||
ipam, err := n.getController().getIPAM(n.ipamType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ipam.capability.RequiresMACAddress {
|
||||
if ep.iface.mac == nil {
|
||||
ep.iface.mac = netutils.GenerateRandomMAC()
|
||||
}
|
||||
if ep.ipamOptions == nil {
|
||||
ep.ipamOptions = make(map[string]string)
|
||||
}
|
||||
ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String()
|
||||
}
|
||||
|
||||
if err = ep.assignAddress(ipam.driver, true, !n.postIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
|
@ -698,7 +733,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
}
|
||||
}()
|
||||
|
||||
if err = ep.assignAddress(false, n.postIPv6); err != nil {
|
||||
if err = ep.assignAddress(ipam.driver, false, n.postIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -1148,3 +1183,32 @@ func (n *network) IpamConfig() (string, []*IpamConf, []*IpamConf) {
|
|||
|
||||
return n.ipamType, v4L, v6L
|
||||
}
|
||||
|
||||
func (n *network) IpamInfo() ([]*IpamInfo, []*IpamInfo) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
v4Info := make([]*IpamInfo, len(n.ipamV4Info))
|
||||
v6Info := make([]*IpamInfo, len(n.ipamV6Info))
|
||||
|
||||
for i, info := range n.ipamV4Info {
|
||||
ic := &IpamInfo{}
|
||||
info.CopyTo(ic)
|
||||
v4Info[i] = ic
|
||||
}
|
||||
|
||||
for i, info := range n.ipamV6Info {
|
||||
ic := &IpamInfo{}
|
||||
info.CopyTo(ic)
|
||||
v6Info[i] = ic
|
||||
}
|
||||
|
||||
return v4Info, v6Info
|
||||
}
|
||||
|
||||
func (n *network) Internal() bool {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.internal
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ func (i *nwIface) Remove() error {
|
|||
|
||||
n.Lock()
|
||||
path := n.path
|
||||
isDefault := n.isDefault
|
||||
n.Unlock()
|
||||
|
||||
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
|
||||
|
@ -134,7 +135,7 @@ func (i *nwIface) Remove() error {
|
|||
if err := netlink.LinkDel(iface); err != nil {
|
||||
return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
|
||||
}
|
||||
} else {
|
||||
} else if !isDefault {
|
||||
// Move the network interface to caller namespace.
|
||||
if err := netlink.LinkSetNsFd(iface, callerFD); err != nil {
|
||||
fmt.Println("LinkSetNsPid failed: ", err)
|
||||
|
@ -213,9 +214,15 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
|
|||
}
|
||||
|
||||
n.Lock()
|
||||
i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
|
||||
n.nextIfIndex++
|
||||
if n.isDefault {
|
||||
i.dstName = i.srcName
|
||||
} else {
|
||||
i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
|
||||
n.nextIfIndex++
|
||||
}
|
||||
|
||||
path := n.path
|
||||
isDefault := n.isDefault
|
||||
n.Unlock()
|
||||
|
||||
return nsInvoke(path, func(nsFD int) error {
|
||||
|
@ -231,9 +238,13 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
|
|||
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
|
||||
}
|
||||
|
||||
// Move the network interface to the destination namespace.
|
||||
if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
|
||||
return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
|
||||
// Move the network interface to the destination
|
||||
// namespace only if the namespace is not a default
|
||||
// type
|
||||
if !isDefault {
|
||||
if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
|
||||
return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -41,6 +41,7 @@ type networkNamespace struct {
|
|||
staticRoutes []*types.StaticRoute
|
||||
neighbors []*neigh
|
||||
nextIfIndex int
|
||||
isDefault bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -146,7 +147,7 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &networkNamespace{path: key}, nil
|
||||
return &networkNamespace{path: key, isDefault: !osCreate}, nil
|
||||
}
|
||||
|
||||
func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter {
|
||||
|
|
|
@ -19,6 +19,11 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// GetSandboxForExternalKey returns sandbox object for the supplied path
|
||||
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
|
|
Loading…
Reference in a new issue