VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
This commit is contained in:
1356
vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go
generated
vendored
Normal file
1356
vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
211
vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go
generated
vendored
Normal file
211
vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libkv/store"
|
||||
"github.com/docker/libkv/store/boltdb"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const bridgePrefix = "bridge"
|
||||
|
||||
func (d *driver) initStore(option map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
provider, provOk := option[netlabel.LocalKVProvider]
|
||||
provURL, urlOk := option[netlabel.LocalKVProviderURL]
|
||||
|
||||
if provOk && urlOk {
|
||||
cfg := &datastore.ScopeCfg{
|
||||
Client: datastore.ScopeClientCfg{
|
||||
Provider: provider.(string),
|
||||
Address: provURL.(string),
|
||||
},
|
||||
}
|
||||
|
||||
provConfig, confOk := option[netlabel.LocalKVProviderConfig]
|
||||
if confOk {
|
||||
cfg.Client.Config = provConfig.(*store.Config)
|
||||
}
|
||||
|
||||
d.store, err = datastore.NewDataStore(datastore.LocalScope, cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bridge driver failed to initialize data store: %v", err)
|
||||
}
|
||||
|
||||
return d.populateNetworks()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) populateNetworks() error {
|
||||
kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{})
|
||||
if err != nil && err != datastore.ErrKeyNotFound && err != boltdb.ErrBoltBucketNotFound {
|
||||
return fmt.Errorf("failed to get bridge network configurations from store: %v", err)
|
||||
}
|
||||
|
||||
// It's normal for network configuration state to be empty. Just return.
|
||||
if err == datastore.ErrKeyNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, kvo := range kvol {
|
||||
ncfg := kvo.(*networkConfiguration)
|
||||
if err = d.createNetwork(ncfg); err != nil {
|
||||
logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state", ncfg.ID, ncfg.BridgeName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
|
||||
if d.store == nil {
|
||||
logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.store.PutObjectAtomic(kvObject); err != nil {
|
||||
return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) storeDelete(kvObject datastore.KVObject) error {
|
||||
if d.store == nil {
|
||||
logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...))
|
||||
return nil
|
||||
}
|
||||
|
||||
retry:
|
||||
if err := d.store.DeleteObjectAtomic(kvObject); err != nil {
|
||||
if err == datastore.ErrKeyModified {
|
||||
if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
|
||||
return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
|
||||
}
|
||||
goto retry
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
|
||||
nMap := make(map[string]interface{})
|
||||
nMap["ID"] = ncfg.ID
|
||||
nMap["BridgeName"] = ncfg.BridgeName
|
||||
nMap["EnableIPv6"] = ncfg.EnableIPv6
|
||||
nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade
|
||||
nMap["EnableICC"] = ncfg.EnableICC
|
||||
nMap["Mtu"] = ncfg.Mtu
|
||||
nMap["DefaultBridge"] = ncfg.DefaultBridge
|
||||
nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String()
|
||||
nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String()
|
||||
nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String()
|
||||
|
||||
if ncfg.AddressIPv4 != nil {
|
||||
nMap["AddressIPv4"] = ncfg.AddressIPv4.String()
|
||||
}
|
||||
|
||||
if ncfg.AddressIPv6 != nil {
|
||||
nMap["AddressIPv6"] = ncfg.AddressIPv6.String()
|
||||
}
|
||||
|
||||
return json.Marshal(nMap)
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
|
||||
var (
|
||||
err error
|
||||
nMap map[string]interface{}
|
||||
)
|
||||
|
||||
if err = json.Unmarshal(b, &nMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v, ok := nMap["AddressIPv4"]; ok {
|
||||
if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := nMap["AddressIPv6"]; ok {
|
||||
if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil {
|
||||
return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
ncfg.DefaultBridge = nMap["DefaultBridge"].(bool)
|
||||
ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string))
|
||||
ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string))
|
||||
ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string))
|
||||
ncfg.ID = nMap["ID"].(string)
|
||||
ncfg.BridgeName = nMap["BridgeName"].(string)
|
||||
ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool)
|
||||
ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool)
|
||||
ncfg.EnableICC = nMap["EnableICC"].(bool)
|
||||
ncfg.Mtu = int(nMap["Mtu"].(float64))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Key() []string {
|
||||
return []string{bridgePrefix, ncfg.ID}
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) KeyPrefix() []string {
|
||||
return []string{bridgePrefix}
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Value() []byte {
|
||||
b, err := json.Marshal(ncfg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) SetValue(value []byte) error {
|
||||
return json.Unmarshal(value, ncfg)
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Index() uint64 {
|
||||
return ncfg.dbIndex
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) SetIndex(index uint64) {
|
||||
ncfg.dbIndex = index
|
||||
ncfg.dbExists = true
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Exists() bool {
|
||||
return ncfg.dbExists
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) Skip() bool {
|
||||
return ncfg.DefaultBridge
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) New() datastore.KVObject {
|
||||
return &networkConfiguration{}
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error {
|
||||
dstNcfg := o.(*networkConfiguration)
|
||||
*dstNcfg = *ncfg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ncfg *networkConfiguration) DataScope() string {
|
||||
return datastore.LocalScope
|
||||
}
|
||||
841
vendor/github.com/docker/libnetwork/drivers/bridge/bridge_test.go
generated
vendored
Normal file
841
vendor/github.com/docker/libnetwork/drivers/bridge/bridge_test.go
generated
vendored
Normal file
@@ -0,0 +1,841 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipamutils"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func getIPv4Data(t *testing.T) []driverapi.IPAMData {
|
||||
ipd := driverapi.IPAMData{AddressSpace: "full"}
|
||||
nw, _, err := ipamutils.ElectInterfaceAddresses("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipd.Pool = nw
|
||||
// Set network gateway to X.X.X.1
|
||||
ipd.Gateway = types.GetIPNetCopy(nw)
|
||||
ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
|
||||
return []driverapi.IPAMData{ipd}
|
||||
}
|
||||
|
||||
func TestCreateFullOptions(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPForwarding: true,
|
||||
EnableIPTables: true,
|
||||
}
|
||||
|
||||
// Test this scenario: Default gw address does not belong to
|
||||
// container network and it's greater than bridge address
|
||||
cnw, _ := types.ParseCIDR("172.16.122.0/24")
|
||||
bnw, _ := types.ParseCIDR("172.16.0.0/24")
|
||||
br, _ := types.ParseCIDR("172.16.0.1/16")
|
||||
defgw, _ := types.ParseCIDR("172.16.0.100/16")
|
||||
|
||||
netConfig := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netOption := make(map[string]interface{})
|
||||
netOption[netlabel.GenericData] = netConfig
|
||||
|
||||
ipdList := []driverapi.IPAMData{
|
||||
driverapi.IPAMData{
|
||||
Pool: bnw,
|
||||
Gateway: br,
|
||||
AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
|
||||
},
|
||||
}
|
||||
err := d.CreateNetwork("dummy", netOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
// Verify the IP address allocated for the endpoint belongs to the container network
|
||||
epOptions := make(map[string]interface{})
|
||||
te := newTestEndpoint(cnw, 10)
|
||||
err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||
}
|
||||
|
||||
if !cnw.Contains(te.Interface().Address().IP) {
|
||||
t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateNoConfig(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFullOptionsLabels(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPForwarding: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
bndIPs := "127.0.0.1"
|
||||
nwV6s := "2100:2400:2600:2700:2800::/80"
|
||||
gwV6s := "2100:2400:2600:2700:2800::25/80"
|
||||
nwV6, _ := types.ParseCIDR(nwV6s)
|
||||
gwV6, _ := types.ParseCIDR(gwV6s)
|
||||
|
||||
labels := map[string]string{
|
||||
BridgeName: DefaultBridgeName,
|
||||
DefaultBridge: "true",
|
||||
netlabel.EnableIPv6: "true",
|
||||
EnableICC: "true",
|
||||
EnableIPMasquerade: "true",
|
||||
DefaultBindingIP: bndIPs,
|
||||
}
|
||||
|
||||
netOption := make(map[string]interface{})
|
||||
netOption[netlabel.GenericData] = labels
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
ipd6List := []driverapi.IPAMData{
|
||||
driverapi.IPAMData{
|
||||
Pool: nwV6,
|
||||
AuxAddresses: map[string]*net.IPNet{
|
||||
DefaultGatewayV6AuxKey: gwV6,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("dummy", netOption, ipdList, ipd6List)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
nw, ok := d.networks["dummy"]
|
||||
if !ok {
|
||||
t.Fatalf("Cannot find dummy network in bridge driver")
|
||||
}
|
||||
|
||||
if nw.config.BridgeName != DefaultBridgeName {
|
||||
t.Fatalf("incongruent name in bridge network")
|
||||
}
|
||||
|
||||
if !nw.config.EnableIPv6 {
|
||||
t.Fatalf("incongruent EnableIPv6 in bridge network")
|
||||
}
|
||||
|
||||
if !nw.config.EnableICC {
|
||||
t.Fatalf("incongruent EnableICC in bridge network")
|
||||
}
|
||||
|
||||
if !nw.config.EnableIPMasquerade {
|
||||
t.Fatalf("incongruent EnableIPMasquerade in bridge network")
|
||||
}
|
||||
|
||||
bndIP := net.ParseIP(bndIPs)
|
||||
if !bndIP.Equal(nw.config.DefaultBindingIP) {
|
||||
t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
|
||||
}
|
||||
|
||||
if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) {
|
||||
t.Fatalf("Unexpected: %v", nw.config.AddressIPv6)
|
||||
}
|
||||
|
||||
if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) {
|
||||
t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6)
|
||||
}
|
||||
|
||||
// In short here we are testing --fixed-cidr-v6 daemon option
|
||||
// plus --mac-address run option
|
||||
mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff")
|
||||
epOptions := map[string]interface{}{netlabel.MacAddress: mac}
|
||||
te := newTestEndpoint(ipdList[0].Pool, 20)
|
||||
err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !nwV6.Contains(te.Interface().AddressIPv6().IP) {
|
||||
t.Fatalf("endpoint got assigned address outside of container network(%s): %s", nwV6.String(), te.Interface().AddressIPv6())
|
||||
}
|
||||
if te.Interface().AddressIPv6().IP.String() != "2100:2400:2600:2700:2800:aabb:ccdd:eeff" {
|
||||
t.Fatalf("Unexpected endpoint IPv6 address: %v", te.Interface().AddressIPv6().IP)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Creation of second network with default name failed with unexpected error type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFail(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err == nil {
|
||||
t.Fatal("Bridge creation was expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMultipleNetworks(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPTables: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
config1 := &networkConfiguration{BridgeName: "net_test_1"}
|
||||
genericOption = make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config1
|
||||
if err := d.CreateNetwork("1", genericOption, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
config2 := &networkConfiguration{BridgeName: "net_test_2"}
|
||||
genericOption[netlabel.GenericData] = config2
|
||||
if err := d.CreateNetwork("2", genericOption, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
// Verify the network isolation rules are installed, each network subnet should appear 2 times
|
||||
verifyV4INCEntries(d.networks, 2, t)
|
||||
|
||||
config3 := &networkConfiguration{BridgeName: "net_test_3"}
|
||||
genericOption[netlabel.GenericData] = config3
|
||||
if err := d.CreateNetwork("3", genericOption, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
// Verify the network isolation rules are installed, each network subnet should appear 4 times
|
||||
verifyV4INCEntries(d.networks, 6, t)
|
||||
|
||||
config4 := &networkConfiguration{BridgeName: "net_test_4"}
|
||||
genericOption[netlabel.GenericData] = config4
|
||||
if err := d.CreateNetwork("4", genericOption, getIPv4Data(t), nil); err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
// Now 6 times
|
||||
verifyV4INCEntries(d.networks, 12, t)
|
||||
|
||||
d.DeleteNetwork("1")
|
||||
verifyV4INCEntries(d.networks, 6, t)
|
||||
|
||||
d.DeleteNetwork("2")
|
||||
verifyV4INCEntries(d.networks, 2, t)
|
||||
|
||||
d.DeleteNetwork("3")
|
||||
verifyV4INCEntries(d.networks, 0, t)
|
||||
|
||||
d.DeleteNetwork("4")
|
||||
verifyV4INCEntries(d.networks, 0, t)
|
||||
}
|
||||
|
||||
func verifyV4INCEntries(networks map[string]*bridgeNetwork, numEntries int, t *testing.T) {
|
||||
out, err := iptables.Raw("-nvL", IsolationChain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found := 0
|
||||
for _, x := range networks {
|
||||
for _, y := range networks {
|
||||
if x == y {
|
||||
continue
|
||||
}
|
||||
re := regexp.MustCompile(fmt.Sprintf("%s %s", x.config.BridgeName, y.config.BridgeName))
|
||||
matches := re.FindAllString(string(out[:]), -1)
|
||||
if len(matches) != 1 {
|
||||
t.Fatalf("Cannot find expected inter-network isolation rules in IP Tables:\n%s", string(out[:]))
|
||||
}
|
||||
found++
|
||||
}
|
||||
}
|
||||
|
||||
if found != numEntries {
|
||||
t.Fatalf("Cannot find expected number (%d) of inter-network isolation rules in IP Tables:\n%s\nFound %d", numEntries, string(out[:]), found)
|
||||
}
|
||||
}
|
||||
|
||||
type testInterface struct {
|
||||
mac net.HardwareAddr
|
||||
addr *net.IPNet
|
||||
addrv6 *net.IPNet
|
||||
srcName string
|
||||
dstName string
|
||||
}
|
||||
|
||||
type testEndpoint struct {
|
||||
iface *testInterface
|
||||
gw net.IP
|
||||
gw6 net.IP
|
||||
hostsPath string
|
||||
resolvConfPath string
|
||||
routes []types.StaticRoute
|
||||
}
|
||||
|
||||
func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
|
||||
addr := types.GetIPNetCopy(nw)
|
||||
addr.IP[len(addr.IP)-1] = ordinal
|
||||
return &testEndpoint{iface: &testInterface{addr: addr}}
|
||||
}
|
||||
|
||||
func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
|
||||
if te.iface != nil {
|
||||
return te.iface
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *testInterface) MacAddress() net.HardwareAddr {
|
||||
return i.mac
|
||||
}
|
||||
|
||||
func (i *testInterface) Address() *net.IPNet {
|
||||
return i.addr
|
||||
}
|
||||
|
||||
func (i *testInterface) AddressIPv6() *net.IPNet {
|
||||
return i.addrv6
|
||||
}
|
||||
|
||||
func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error {
|
||||
if i.mac != nil {
|
||||
return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac)
|
||||
}
|
||||
if mac == nil {
|
||||
return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
|
||||
}
|
||||
i.mac = types.GetMacCopy(mac)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *testInterface) SetIPAddress(address *net.IPNet) error {
|
||||
if address.IP == nil {
|
||||
return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
|
||||
}
|
||||
if address.IP.To4() == nil {
|
||||
return setAddress(&i.addrv6, address)
|
||||
}
|
||||
return setAddress(&i.addr, address)
|
||||
}
|
||||
|
||||
func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
|
||||
if *ifaceAddr != nil {
|
||||
return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
|
||||
}
|
||||
*ifaceAddr = types.GetIPNetCopy(address)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *testInterface) SetNames(srcName string, dstName string) error {
|
||||
i.srcName = srcName
|
||||
i.dstName = dstName
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
|
||||
if te.iface != nil {
|
||||
return te.iface
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) SetGateway(gw net.IP) error {
|
||||
te.gw = gw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
|
||||
te.gw6 = gw6
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
|
||||
te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) DisableGatewayService() {}
|
||||
|
||||
func TestQueryEndpointInfo(t *testing.T) {
|
||||
testQueryEndpointInfo(t, true)
|
||||
}
|
||||
|
||||
func TestQueryEndpointInfoHairpin(t *testing.T) {
|
||||
testQueryEndpointInfo(t, false)
|
||||
}
|
||||
|
||||
func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPTables: true,
|
||||
EnableUserlandProxy: ulPxyEnabled,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableICC: false,
|
||||
}
|
||||
genericOption = make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("net1", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
portMappings := getPortMapping()
|
||||
epOptions := make(map[string]interface{})
|
||||
epOptions[netlabel.PortMap] = portMappings
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("net1", "ep1", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||
}
|
||||
|
||||
network, ok := d.networks["net1"]
|
||||
if !ok {
|
||||
t.Fatalf("Cannot find network %s inside driver", "net1")
|
||||
}
|
||||
ep, _ := network.endpoints["ep1"]
|
||||
data, err := d.EndpointOperInfo(network.id, ep.id)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to ask for endpoint operational data: %v", err)
|
||||
}
|
||||
pmd, ok := data[netlabel.PortMap]
|
||||
if !ok {
|
||||
t.Fatalf("Endpoint operational data does not contain port mapping data")
|
||||
}
|
||||
pm, ok := pmd.([]types.PortBinding)
|
||||
if !ok {
|
||||
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
||||
}
|
||||
if len(ep.portMapping) != len(pm) {
|
||||
t.Fatalf("Incomplete data for port mapping in endpoint operational data")
|
||||
}
|
||||
for i, pb := range ep.portMapping {
|
||||
if !pb.Equal(&pm[i]) {
|
||||
t.Fatalf("Unexpected data for port mapping in endpoint operational data")
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup as host ports are there
|
||||
err = network.releasePorts(ep)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to release mapped ports: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateLinkWithOptions(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
netOptions := make(map[string]interface{})
|
||||
netOptions[netlabel.GenericData] = netconfig
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("net1", netOptions, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
|
||||
epOptions := make(map[string]interface{})
|
||||
epOptions[netlabel.MacAddress] = mac
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("net1", "ep", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint: %s", err.Error())
|
||||
}
|
||||
|
||||
err = d.Join("net1", "ep", "sbox", te, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to join the endpoint: %v", err)
|
||||
}
|
||||
|
||||
ifaceName := te.iface.srcName
|
||||
veth, err := netlink.LinkByName(ifaceName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(mac, veth.Attrs().HardwareAddr) {
|
||||
t.Fatalf("Failed to parse and program endpoint configuration")
|
||||
}
|
||||
}
|
||||
|
||||
func getExposedPorts() []types.TransportPort {
|
||||
return []types.TransportPort{
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
||||
types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
||||
}
|
||||
}
|
||||
|
||||
func getPortMapping() []types.PortBinding {
|
||||
return []types.PortBinding{
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
||||
types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
||||
types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkContainers(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPTables: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
netconfig := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableICC: false,
|
||||
}
|
||||
genericOption = make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = netconfig
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("net1", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
exposedPorts := getExposedPorts()
|
||||
epOptions := make(map[string]interface{})
|
||||
epOptions[netlabel.ExposedPorts] = exposedPorts
|
||||
|
||||
te1 := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("net1", "ep1", te1.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||
}
|
||||
|
||||
addr1 := te1.iface.addr
|
||||
if addr1.IP.To4() == nil {
|
||||
t.Fatalf("No Ipv4 address assigned to the endpoint: ep1")
|
||||
}
|
||||
|
||||
te2 := newTestEndpoint(ipdList[0].Pool, 22)
|
||||
err = d.CreateEndpoint("net1", "ep2", te2.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||
}
|
||||
|
||||
addr2 := te2.iface.addr
|
||||
if addr2.IP.To4() == nil {
|
||||
t.Fatalf("No Ipv4 address assigned to the endpoint: ep2")
|
||||
}
|
||||
|
||||
ce := []string{"ep1"}
|
||||
cConfig := &containerConfiguration{ChildEndpoints: ce}
|
||||
genericOption = make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = cConfig
|
||||
|
||||
err = d.Join("net1", "ep2", "", te2, genericOption)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to link ep1 and ep2")
|
||||
}
|
||||
|
||||
out, err := iptables.Raw("-L", DockerChain)
|
||||
for _, pm := range exposedPorts {
|
||||
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
||||
re := regexp.MustCompile(regex)
|
||||
matches := re.FindAllString(string(out[:]), -1)
|
||||
if len(matches) != 1 {
|
||||
t.Fatalf("IP Tables programming failed %s", string(out[:]))
|
||||
}
|
||||
|
||||
regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
|
||||
matched, _ := regexp.MatchString(regex, string(out[:]))
|
||||
if !matched {
|
||||
t.Fatalf("IP Tables programming failed %s", string(out[:]))
|
||||
}
|
||||
}
|
||||
|
||||
err = d.Leave("net1", "ep2")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to unlink ep1 and ep2")
|
||||
}
|
||||
|
||||
out, err = iptables.Raw("-L", DockerChain)
|
||||
for _, pm := range exposedPorts {
|
||||
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
||||
re := regexp.MustCompile(regex)
|
||||
matches := re.FindAllString(string(out[:]), -1)
|
||||
if len(matches) != 0 {
|
||||
t.Fatalf("Leave should have deleted relevant IPTables rules %s", string(out[:]))
|
||||
}
|
||||
|
||||
regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
|
||||
matched, _ := regexp.MatchString(regex, string(out[:]))
|
||||
if matched {
|
||||
t.Fatalf("Leave should have deleted relevant IPTables rules %s", string(out[:]))
|
||||
}
|
||||
}
|
||||
|
||||
// Error condition test with an invalid endpoint-id "ep4"
|
||||
ce = []string{"ep1", "ep4"}
|
||||
cConfig = &containerConfiguration{ChildEndpoints: ce}
|
||||
genericOption = make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = cConfig
|
||||
|
||||
err = d.Join("net1", "ep2", "", te2, genericOption)
|
||||
if err != nil {
|
||||
out, err = iptables.Raw("-L", DockerChain)
|
||||
for _, pm := range exposedPorts {
|
||||
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
||||
re := regexp.MustCompile(regex)
|
||||
matches := re.FindAllString(string(out[:]), -1)
|
||||
if len(matches) != 0 {
|
||||
t.Fatalf("Error handling should rollback relevant IPTables rules %s", string(out[:]))
|
||||
}
|
||||
|
||||
regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
|
||||
matched, _ := regexp.MatchString(regex, string(out[:]))
|
||||
if matched {
|
||||
t.Fatalf("Error handling should rollback relevant IPTables rules %s", string(out[:]))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("Expected Join to fail given link conditions are not satisfied")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateConfig(t *testing.T) {
|
||||
|
||||
// Test mtu
|
||||
c := networkConfiguration{Mtu: -2}
|
||||
err := c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid MTU number")
|
||||
}
|
||||
|
||||
c.Mtu = 9000
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected validation error on MTU number")
|
||||
}
|
||||
|
||||
// Bridge network
|
||||
_, network, _ := net.ParseCIDR("172.28.0.0/16")
|
||||
c = networkConfiguration{
|
||||
AddressIPv4: network,
|
||||
}
|
||||
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test v4 gw
|
||||
c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid default gateway")
|
||||
}
|
||||
|
||||
c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234")
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected validation error on default gateway")
|
||||
}
|
||||
|
||||
// Test v6 gw
|
||||
_, v6nw, _ := net.ParseCIDR("2001:1234:ae:b004::/64")
|
||||
c = networkConfiguration{
|
||||
EnableIPv6: true,
|
||||
AddressIPv6: v6nw,
|
||||
DefaultGatewayIPv6: net.ParseIP("2001:1234:ac:b004::bad:a55"),
|
||||
}
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid v6 default gateway")
|
||||
}
|
||||
|
||||
c.DefaultGatewayIPv6 = net.ParseIP("2001:1234:ae:b004::bad:a55")
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected validation error on v6 default gateway")
|
||||
}
|
||||
|
||||
c.AddressIPv6 = nil
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid v6 default gateway")
|
||||
}
|
||||
|
||||
c.AddressIPv6 = nil
|
||||
err = c.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect invalid v6 default gateway")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultGw(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
_, subnetv6, _ := net.ParseCIDR("2001:db8:ea9:9abc:b0c4::/80")
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
gw4 := types.GetIPCopy(ipdList[0].Pool.IP).To4()
|
||||
gw4[3] = 254
|
||||
gw6 := net.ParseIP("2001:db8:ea9:9abc:b0c4::254")
|
||||
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true,
|
||||
AddressIPv6: subnetv6,
|
||||
DefaultGatewayIPv4: gw4,
|
||||
DefaultGatewayIPv6: gw6,
|
||||
}
|
||||
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 10)
|
||||
err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create endpoint: %v", err)
|
||||
}
|
||||
|
||||
err = d.Join("dummy", "ep", "sbox", te, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to join endpoint: %v", err)
|
||||
}
|
||||
|
||||
if !gw4.Equal(te.gw) {
|
||||
t.Fatalf("Failed to configure default gateway. Expected %v. Found %v", gw4, te.gw)
|
||||
}
|
||||
|
||||
if !gw6.Equal(te.gw6) {
|
||||
t.Fatalf("Failed to configure default gateway. Expected %v. Found %v", gw6, te.gw6)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanupIptableRules(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
bridgeChain := []iptables.ChainInfo{
|
||||
iptables.ChainInfo{Name: DockerChain, Table: iptables.Nat},
|
||||
iptables.ChainInfo{Name: DockerChain, Table: iptables.Filter},
|
||||
iptables.ChainInfo{Name: IsolationChain, Table: iptables.Filter},
|
||||
}
|
||||
if _, _, _, err := setupIPChains(&configuration{EnableIPTables: true}); err != nil {
|
||||
t.Fatalf("Error setting up ip chains: %v", err)
|
||||
}
|
||||
for _, chainInfo := range bridgeChain {
|
||||
if !iptables.ExistChain(chainInfo.Name, chainInfo.Table) {
|
||||
t.Fatalf("iptables chain %s of %s table should have been created", chainInfo.Name, chainInfo.Table)
|
||||
}
|
||||
}
|
||||
removeIPChains()
|
||||
for _, chainInfo := range bridgeChain {
|
||||
if iptables.ExistChain(chainInfo.Name, chainInfo.Table) {
|
||||
t.Fatalf("iptables chain %s of %s table should have been deleted", chainInfo.Name, chainInfo.Table)
|
||||
}
|
||||
}
|
||||
}
|
||||
341
vendor/github.com/docker/libnetwork/drivers/bridge/errors.go
generated
vendored
Normal file
341
vendor/github.com/docker/libnetwork/drivers/bridge/errors.go
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// ErrConfigExists error is returned when driver already has a config applied.
|
||||
type ErrConfigExists struct{}
|
||||
|
||||
func (ece *ErrConfigExists) Error() string {
|
||||
return "configuration already exists, bridge configuration can be applied only once"
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (ece *ErrConfigExists) Forbidden() {}
|
||||
|
||||
// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
|
||||
type ErrInvalidDriverConfig struct{}
|
||||
|
||||
func (eidc *ErrInvalidDriverConfig) Error() string {
|
||||
return "Invalid configuration passed to Bridge Driver"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eidc *ErrInvalidDriverConfig) BadRequest() {}
|
||||
|
||||
// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
|
||||
type ErrInvalidNetworkConfig struct{}
|
||||
|
||||
func (einc *ErrInvalidNetworkConfig) Error() string {
|
||||
return "trying to create a network on a driver without valid config"
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (einc *ErrInvalidNetworkConfig) Forbidden() {}
|
||||
|
||||
// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
|
||||
type ErrInvalidContainerConfig struct{}
|
||||
|
||||
func (eicc *ErrInvalidContainerConfig) Error() string {
|
||||
return "Error in joining a container due to invalid configuration"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eicc *ErrInvalidContainerConfig) BadRequest() {}
|
||||
|
||||
// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
|
||||
type ErrInvalidEndpointConfig struct{}
|
||||
|
||||
func (eiec *ErrInvalidEndpointConfig) Error() string {
|
||||
return "trying to create an endpoint with an invalid endpoint configuration"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
|
||||
|
||||
// ErrNetworkExists error is returned when a network already exists and another network is created.
|
||||
type ErrNetworkExists struct{}
|
||||
|
||||
func (ene *ErrNetworkExists) Error() string {
|
||||
return "network already exists, bridge can only have one network"
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (ene *ErrNetworkExists) Forbidden() {}
|
||||
|
||||
// ErrIfaceName error is returned when a new name could not be generated.
|
||||
type ErrIfaceName struct{}
|
||||
|
||||
func (ein *ErrIfaceName) Error() string {
|
||||
return "failed to find name for new interface"
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (ein *ErrIfaceName) InternalError() {}
|
||||
|
||||
// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
|
||||
type ErrNoIPAddr struct{}
|
||||
|
||||
func (enip *ErrNoIPAddr) Error() string {
|
||||
return "bridge has no IPv4 address configured"
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (enip *ErrNoIPAddr) InternalError() {}
|
||||
|
||||
// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
|
||||
type ErrInvalidGateway struct{}
|
||||
|
||||
func (eig *ErrInvalidGateway) Error() string {
|
||||
return "default gateway ip must be part of the network"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eig *ErrInvalidGateway) BadRequest() {}
|
||||
|
||||
// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
|
||||
type ErrInvalidContainerSubnet struct{}
|
||||
|
||||
func (eis *ErrInvalidContainerSubnet) Error() string {
|
||||
return "container subnet must be a subset of bridge network"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eis *ErrInvalidContainerSubnet) BadRequest() {}
|
||||
|
||||
// ErrInvalidMtu is returned when the user provided MTU is not valid.
|
||||
type ErrInvalidMtu int
|
||||
|
||||
func (eim ErrInvalidMtu) Error() string {
|
||||
return fmt.Sprintf("invalid MTU number: %d", int(eim))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eim ErrInvalidMtu) BadRequest() {}
|
||||
|
||||
// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
|
||||
type ErrInvalidPort string
|
||||
|
||||
func (ip ErrInvalidPort) Error() string {
|
||||
return fmt.Sprintf("invalid transport port: %s", string(ip))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (ip ErrInvalidPort) BadRequest() {}
|
||||
|
||||
// ErrUnsupportedAddressType is returned when the specified address type is not supported.
|
||||
type ErrUnsupportedAddressType string
|
||||
|
||||
func (uat ErrUnsupportedAddressType) Error() string {
|
||||
return fmt.Sprintf("unsupported address type: %s", string(uat))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (uat ErrUnsupportedAddressType) BadRequest() {}
|
||||
|
||||
// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
|
||||
type ErrInvalidAddressBinding string
|
||||
|
||||
func (iab ErrInvalidAddressBinding) Error() string {
|
||||
return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (iab ErrInvalidAddressBinding) BadRequest() {}
|
||||
|
||||
// ActiveEndpointsError is returned when there are
|
||||
// still active endpoints in the network being deleted.
|
||||
type ActiveEndpointsError string
|
||||
|
||||
func (aee ActiveEndpointsError) Error() string {
|
||||
return fmt.Sprintf("network %s has active endpoint", string(aee))
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (aee ActiveEndpointsError) Forbidden() {}
|
||||
|
||||
// InvalidNetworkIDError is returned when the passed
|
||||
// network id for an existing network is not a known id.
|
||||
type InvalidNetworkIDError string
|
||||
|
||||
func (inie InvalidNetworkIDError) Error() string {
|
||||
return fmt.Sprintf("invalid network id %s", string(inie))
|
||||
}
|
||||
|
||||
// NotFound denotes the type of this error
|
||||
func (inie InvalidNetworkIDError) NotFound() {}
|
||||
|
||||
// InvalidEndpointIDError is returned when the passed
|
||||
// endpoint id is not valid.
|
||||
type InvalidEndpointIDError string
|
||||
|
||||
func (ieie InvalidEndpointIDError) Error() string {
|
||||
return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (ieie InvalidEndpointIDError) BadRequest() {}
|
||||
|
||||
// InvalidSandboxIDError is returned when the passed
|
||||
// sandbox id is not valid.
|
||||
type InvalidSandboxIDError string
|
||||
|
||||
func (isie InvalidSandboxIDError) Error() string {
|
||||
return fmt.Sprintf("invalid sanbox id: %s", string(isie))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (isie InvalidSandboxIDError) BadRequest() {}
|
||||
|
||||
// EndpointNotFoundError is returned when the no endpoint
|
||||
// with the passed endpoint id is found.
|
||||
type EndpointNotFoundError string
|
||||
|
||||
func (enfe EndpointNotFoundError) Error() string {
|
||||
return fmt.Sprintf("endpoint not found: %s", string(enfe))
|
||||
}
|
||||
|
||||
// NotFound denotes the type of this error
|
||||
func (enfe EndpointNotFoundError) NotFound() {}
|
||||
|
||||
// NonDefaultBridgeExistError is returned when a non-default
|
||||
// bridge config is passed but it does not already exist.
|
||||
type NonDefaultBridgeExistError string
|
||||
|
||||
func (ndbee NonDefaultBridgeExistError) Error() string {
|
||||
return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (ndbee NonDefaultBridgeExistError) Forbidden() {}
|
||||
|
||||
// NonDefaultBridgeNeedsIPError is returned when a non-default
|
||||
// bridge config is passed but it has no ip configured
|
||||
type NonDefaultBridgeNeedsIPError string
|
||||
|
||||
func (ndbee NonDefaultBridgeNeedsIPError) Error() string {
|
||||
return fmt.Sprintf("bridge device with non default name %s must have a valid IP address", string(ndbee))
|
||||
}
|
||||
|
||||
// Forbidden denotes the type of this error
|
||||
func (ndbee NonDefaultBridgeNeedsIPError) Forbidden() {}
|
||||
|
||||
// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
|
||||
// failed.
|
||||
type FixedCIDRv4Error struct {
|
||||
Net *net.IPNet
|
||||
Subnet *net.IPNet
|
||||
Err error
|
||||
}
|
||||
|
||||
func (fcv4 *FixedCIDRv4Error) Error() string {
|
||||
return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.Subnet, fcv4.Net, fcv4.Err)
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (fcv4 *FixedCIDRv4Error) InternalError() {}
|
||||
|
||||
// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
|
||||
// failed.
|
||||
type FixedCIDRv6Error struct {
|
||||
Net *net.IPNet
|
||||
Err error
|
||||
}
|
||||
|
||||
func (fcv6 *FixedCIDRv6Error) Error() string {
|
||||
return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.Net, fcv6.Net, fcv6.Err)
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (fcv6 *FixedCIDRv6Error) InternalError() {}
|
||||
|
||||
// IPTableCfgError is returned when an unexpected ip tables configuration is entered
|
||||
type IPTableCfgError string
|
||||
|
||||
func (name IPTableCfgError) Error() string {
|
||||
return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (name IPTableCfgError) BadRequest() {}
|
||||
|
||||
// InvalidIPTablesCfgError is returned when an invalid ip tables configuration is entered
|
||||
type InvalidIPTablesCfgError string
|
||||
|
||||
func (action InvalidIPTablesCfgError) Error() string {
|
||||
return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (action InvalidIPTablesCfgError) BadRequest() {}
|
||||
|
||||
// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
|
||||
type IPv4AddrRangeError string
|
||||
|
||||
func (name IPv4AddrRangeError) Error() string {
|
||||
return fmt.Sprintf("can't find an address range for interface %q", string(name))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (name IPv4AddrRangeError) BadRequest() {}
|
||||
|
||||
// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
|
||||
type IPv4AddrAddError struct {
|
||||
IP *net.IPNet
|
||||
Err error
|
||||
}
|
||||
|
||||
func (ipv4 *IPv4AddrAddError) Error() string {
|
||||
return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.IP, ipv4.Err)
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (ipv4 *IPv4AddrAddError) InternalError() {}
|
||||
|
||||
// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
|
||||
type IPv6AddrAddError struct {
|
||||
IP *net.IPNet
|
||||
Err error
|
||||
}
|
||||
|
||||
func (ipv6 *IPv6AddrAddError) Error() string {
|
||||
return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.IP, ipv6.Err)
|
||||
}
|
||||
|
||||
// InternalError denotes the type of this error
|
||||
func (ipv6 *IPv6AddrAddError) InternalError() {}
|
||||
|
||||
// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
|
||||
type IPv4AddrNoMatchError struct {
|
||||
IP net.IP
|
||||
CfgIP net.IP
|
||||
}
|
||||
|
||||
func (ipv4 *IPv4AddrNoMatchError) Error() string {
|
||||
return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.IP, ipv4.CfgIP)
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (ipv4 *IPv4AddrNoMatchError) BadRequest() {}
|
||||
|
||||
// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
|
||||
type IPv6AddrNoMatchError net.IPNet
|
||||
|
||||
func (ipv6 *IPv6AddrNoMatchError) Error() string {
|
||||
return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (ipv6 *IPv6AddrNoMatchError) BadRequest() {}
|
||||
|
||||
// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
|
||||
type InvalidLinkIPAddrError string
|
||||
|
||||
func (address InvalidLinkIPAddrError) Error() string {
|
||||
return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (address InvalidLinkIPAddrError) BadRequest() {}
|
||||
79
vendor/github.com/docker/libnetwork/drivers/bridge/interface.go
generated
vendored
Normal file
79
vendor/github.com/docker/libnetwork/drivers/bridge/interface.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultBridgeName is the default name for the bridge interface managed
|
||||
// by the driver when unspecified by the caller.
|
||||
DefaultBridgeName = "docker0"
|
||||
)
|
||||
|
||||
// Interface models the bridge network device.
|
||||
type bridgeInterface struct {
|
||||
Link netlink.Link
|
||||
bridgeIPv4 *net.IPNet
|
||||
bridgeIPv6 *net.IPNet
|
||||
gatewayIPv4 net.IP
|
||||
gatewayIPv6 net.IP
|
||||
}
|
||||
|
||||
// newInterface creates a new bridge interface structure. It attempts to find
|
||||
// an already existing device identified by the configuration BridgeName field,
|
||||
// or the default bridge name when unspecified), but doesn't attempt to create
|
||||
// one when missing
|
||||
func newInterface(config *networkConfiguration) *bridgeInterface {
|
||||
i := &bridgeInterface{}
|
||||
|
||||
// Initialize the bridge name to the default if unspecified.
|
||||
if config.BridgeName == "" {
|
||||
config.BridgeName = DefaultBridgeName
|
||||
}
|
||||
|
||||
// Attempt to find an existing bridge named with the specified name.
|
||||
i.Link, _ = netlink.LinkByName(config.BridgeName)
|
||||
return i
|
||||
}
|
||||
|
||||
// exists indicates if the existing bridge interface exists on the system.
|
||||
func (i *bridgeInterface) exists() bool {
|
||||
return i.Link != nil
|
||||
}
|
||||
|
||||
// addresses returns a single IPv4 address and all IPv6 addresses for the
|
||||
// bridge interface.
|
||||
func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) {
|
||||
v4addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return netlink.Addr{}, nil, err
|
||||
}
|
||||
|
||||
v6addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V6)
|
||||
if err != nil {
|
||||
return netlink.Addr{}, nil, err
|
||||
}
|
||||
|
||||
if len(v4addr) == 0 {
|
||||
return netlink.Addr{}, v6addr, nil
|
||||
}
|
||||
return v4addr[0], v6addr, nil
|
||||
}
|
||||
|
||||
func (i *bridgeInterface) programIPv6Address() error {
|
||||
_, nlAddressList, err := i.addresses()
|
||||
if err != nil {
|
||||
return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: fmt.Errorf("failed to retrieve address list: %v", err)}
|
||||
}
|
||||
nlAddr := netlink.Addr{IPNet: i.bridgeIPv6}
|
||||
if findIPv6Address(nlAddr, nlAddressList) {
|
||||
return nil
|
||||
}
|
||||
if err := netlink.AddrAdd(i.Link, &nlAddr); err != nil {
|
||||
return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
33
vendor/github.com/docker/libnetwork/drivers/bridge/interface_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/libnetwork/drivers/bridge/interface_test.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestInterfaceDefaultName(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
config := &networkConfiguration{}
|
||||
if _ = newInterface(config); config.BridgeName != DefaultBridgeName {
|
||||
t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddressesEmptyInterface(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
inf := newInterface(&networkConfiguration{})
|
||||
addrv4, addrsv6, err := inf.addresses()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get addresses of default interface: %v", err)
|
||||
}
|
||||
if expected := (netlink.Addr{}); addrv4 != expected {
|
||||
t.Fatalf("Default interface has unexpected IPv4: %s", addrv4)
|
||||
}
|
||||
if len(addrsv6) != 0 {
|
||||
t.Fatalf("Default interface has unexpected IPv6: %v", addrsv6)
|
||||
}
|
||||
}
|
||||
18
vendor/github.com/docker/libnetwork/drivers/bridge/labels.go
generated
vendored
Normal file
18
vendor/github.com/docker/libnetwork/drivers/bridge/labels.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package bridge
|
||||
|
||||
const (
|
||||
// BridgeName label for bridge driver
|
||||
BridgeName = "com.docker.network.bridge.name"
|
||||
|
||||
// EnableIPMasquerade label for bridge driver
|
||||
EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade"
|
||||
|
||||
// EnableICC label
|
||||
EnableICC = "com.docker.network.bridge.enable_icc"
|
||||
|
||||
// DefaultBindingIP label
|
||||
DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4"
|
||||
|
||||
// DefaultBridge label
|
||||
DefaultBridge = "com.docker.network.bridge.default_bridge"
|
||||
)
|
||||
85
vendor/github.com/docker/libnetwork/drivers/bridge/link.go
generated
vendored
Normal file
85
vendor/github.com/docker/libnetwork/drivers/bridge/link.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
type link struct {
|
||||
parentIP string
|
||||
childIP string
|
||||
ports []types.TransportPort
|
||||
bridge string
|
||||
}
|
||||
|
||||
func (l *link) String() string {
|
||||
return fmt.Sprintf("%s <-> %s [%v] on %s", l.parentIP, l.childIP, l.ports, l.bridge)
|
||||
}
|
||||
|
||||
func newLink(parentIP, childIP string, ports []types.TransportPort, bridge string) *link {
|
||||
return &link{
|
||||
childIP: childIP,
|
||||
parentIP: parentIP,
|
||||
ports: ports,
|
||||
bridge: bridge,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (l *link) Enable() error {
|
||||
// -A == iptables append flag
|
||||
linkFunction := func() error {
|
||||
return linkContainers("-A", l.parentIP, l.childIP, l.ports, l.bridge, false)
|
||||
}
|
||||
|
||||
iptables.OnReloaded(func() { linkFunction() })
|
||||
return linkFunction()
|
||||
}
|
||||
|
||||
func (l *link) Disable() {
|
||||
// -D == iptables delete flag
|
||||
err := linkContainers("-D", l.parentIP, l.childIP, l.ports, l.bridge, true)
|
||||
if err != nil {
|
||||
log.Errorf("Error removing IPTables rules for a link %s due to %s", l.String(), err.Error())
|
||||
}
|
||||
// Return proper error once we move to use a proper iptables package
|
||||
// that returns typed errors
|
||||
}
|
||||
|
||||
func linkContainers(action, parentIP, childIP string, ports []types.TransportPort, bridge string,
|
||||
ignoreErrors bool) error {
|
||||
var nfAction iptables.Action
|
||||
|
||||
switch action {
|
||||
case "-A":
|
||||
nfAction = iptables.Append
|
||||
case "-I":
|
||||
nfAction = iptables.Insert
|
||||
case "-D":
|
||||
nfAction = iptables.Delete
|
||||
default:
|
||||
return InvalidIPTablesCfgError(action)
|
||||
}
|
||||
|
||||
ip1 := net.ParseIP(parentIP)
|
||||
if ip1 == nil {
|
||||
return InvalidLinkIPAddrError(parentIP)
|
||||
}
|
||||
ip2 := net.ParseIP(childIP)
|
||||
if ip2 == nil {
|
||||
return InvalidLinkIPAddrError(childIP)
|
||||
}
|
||||
|
||||
chain := iptables.ChainInfo{Name: DockerChain}
|
||||
for _, port := range ports {
|
||||
err := chain.Link(nfAction, ip1, ip2, int(port.Port), port.Proto.String(), bridge)
|
||||
if !ignoreErrors && err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
39
vendor/github.com/docker/libnetwork/drivers/bridge/link_test.go
generated
vendored
Normal file
39
vendor/github.com/docker/libnetwork/drivers/bridge/link_test.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func getPorts() []types.TransportPort {
|
||||
return []types.TransportPort{
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
||||
types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
||||
types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkNew(t *testing.T) {
|
||||
ports := getPorts()
|
||||
|
||||
link := newLink("172.0.17.3", "172.0.17.2", ports, "docker0")
|
||||
|
||||
if link == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if link.parentIP != "172.0.17.3" {
|
||||
t.Fail()
|
||||
}
|
||||
if link.childIP != "172.0.17.2" {
|
||||
t.Fail()
|
||||
}
|
||||
for i, p := range link.ports {
|
||||
if p != ports[i] {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
if link.bridge != "docker0" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
131
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux.go
generated
vendored
Normal file
131
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
const (
|
||||
ifNameSize = 16
|
||||
ioctlBrAdd = 0x89a0
|
||||
ioctlBrAddIf = 0x89a2
|
||||
)
|
||||
|
||||
type ifreqIndex struct {
|
||||
IfrnName [ifNameSize]byte
|
||||
IfruIndex int32
|
||||
}
|
||||
|
||||
type ifreqHwaddr struct {
|
||||
IfrnName [ifNameSize]byte
|
||||
IfruHwaddr syscall.RawSockaddr
|
||||
}
|
||||
|
||||
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
// THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
|
||||
// IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
|
||||
// WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
|
||||
func getIfSocket() (fd int, err error) {
|
||||
for _, socket := range []int{
|
||||
syscall.AF_INET,
|
||||
syscall.AF_PACKET,
|
||||
syscall.AF_INET6,
|
||||
} {
|
||||
if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
return fd, nil
|
||||
}
|
||||
return -1, err
|
||||
}
|
||||
|
||||
func ifIoctBridge(iface, master *net.Interface, op uintptr) error {
|
||||
if len(master.Name) >= ifNameSize {
|
||||
return fmt.Errorf("Interface name %s too long", master.Name)
|
||||
}
|
||||
|
||||
s, err := getIfSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(s)
|
||||
|
||||
ifr := ifreqIndex{}
|
||||
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
|
||||
ifr.IfruIndex = int32(iface.Index)
|
||||
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), op, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add a slave to a bridge device. This is more backward-compatible than
|
||||
// netlink.NetworkSetMaster and works on RHEL 6.
|
||||
func ioctlAddToBridge(iface, master *net.Interface) error {
|
||||
return ifIoctBridge(iface, master, ioctlBrAddIf)
|
||||
}
|
||||
|
||||
func ioctlSetMacAddress(name, addr string) error {
|
||||
if len(name) >= ifNameSize {
|
||||
return fmt.Errorf("Interface name %s too long", name)
|
||||
}
|
||||
|
||||
hw, err := net.ParseMAC(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := getIfSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(s)
|
||||
|
||||
ifr := ifreqHwaddr{}
|
||||
ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
|
||||
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
|
||||
}
|
||||
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ioctlCreateBridge(name string, setMacAddr bool) error {
|
||||
if len(name) >= ifNameSize {
|
||||
return fmt.Errorf("Interface name %s too long", name)
|
||||
}
|
||||
|
||||
s, err := getIfSocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(s)
|
||||
|
||||
nameBytePtr, err := syscall.BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), ioctlBrAdd, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
|
||||
return err
|
||||
}
|
||||
if setMacAddr {
|
||||
return ioctlSetMacAddress(name, netutils.GenerateRandomMAC().String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
7
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go
generated
vendored
Normal file
7
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build arm ppc64 ppc64le
|
||||
|
||||
package bridge
|
||||
|
||||
func ifrDataByte(b byte) uint8 {
|
||||
return uint8(b)
|
||||
}
|
||||
7
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go
generated
vendored
Normal file
7
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build !arm,!ppc64,!ppc64le
|
||||
|
||||
package bridge
|
||||
|
||||
func ifrDataByte(b byte) int8 {
|
||||
return int8(b)
|
||||
}
|
||||
18
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_unsupported.go
generated
vendored
Normal file
18
vendor/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// +build !linux
|
||||
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Add a slave to a bridge device. This is more backward-compatible than
|
||||
// netlink.NetworkSetMaster and works on RHEL 6.
|
||||
func ioctlAddToBridge(iface, master *net.Interface) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func ioctlCreateBridge(name string, setMacAddr bool) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
217
vendor/github.com/docker/libnetwork/drivers/bridge/network_test.go
generated
vendored
Normal file
217
vendor/github.com/docker/libnetwork/drivers/bridge/network_test.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestLinkCreate(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
mtu := 1490
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
Mtu: mtu,
|
||||
EnableIPv6: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 10)
|
||||
err = d.CreateEndpoint("dummy", "", te.Interface(), nil)
|
||||
if err != nil {
|
||||
if _, ok := err.(InvalidEndpointIDError); !ok {
|
||||
t.Fatalf("Failed with a wrong error :%s", err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("Failed to detect invalid config")
|
||||
}
|
||||
|
||||
// Good endpoint creation
|
||||
err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||
}
|
||||
|
||||
err = d.Join("dummy", "ep", "sbox", te, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||
}
|
||||
|
||||
// Verify sbox endoint interface inherited MTU value from bridge config
|
||||
sboxLnk, err := netlink.LinkByName(te.iface.srcName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mtu != sboxLnk.Attrs().MTU {
|
||||
t.Fatalf("Sandbox endpoint interface did not inherit bridge interface MTU config")
|
||||
}
|
||||
// TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName
|
||||
// then we could check the MTU on hostLnk as well.
|
||||
|
||||
te1 := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to detect duplicate endpoint id on same network")
|
||||
}
|
||||
|
||||
if te.iface.dstName == "" {
|
||||
t.Fatal("Invalid Dstname returned")
|
||||
}
|
||||
|
||||
_, err = netlink.LinkByName(te.iface.srcName)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find source link %s: %v", te.iface.srcName, err)
|
||||
}
|
||||
|
||||
n, ok := d.networks["dummy"]
|
||||
if !ok {
|
||||
t.Fatalf("Cannot find network %s inside driver", "dummy")
|
||||
}
|
||||
ip := te.iface.addr.IP
|
||||
if !n.bridge.bridgeIPv4.Contains(ip) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), n.bridge.bridgeIPv4.String())
|
||||
}
|
||||
|
||||
ip6 := te.iface.addrv6.IP
|
||||
if !n.bridge.bridgeIPv6.Contains(ip6) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip6.String(), bridgeIPv6.String())
|
||||
}
|
||||
|
||||
if !te.gw.Equal(n.bridge.bridgeIPv4.IP) {
|
||||
t.Fatalf("Invalid default gateway. Expected %s. Got %s", n.bridge.bridgeIPv4.IP.String(),
|
||||
te.gw.String())
|
||||
}
|
||||
|
||||
if !te.gw6.Equal(n.bridge.bridgeIPv6.IP) {
|
||||
t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", n.bridge.bridgeIPv6.IP.String(),
|
||||
te.gw6.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkCreateTwo(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
te1 := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||
}
|
||||
|
||||
te2 := newTestEndpoint(ipdList[0].Pool, 12)
|
||||
err = d.CreateEndpoint("dummy", "ep", te2.Interface(), nil)
|
||||
if err != nil {
|
||||
if _, ok := err.(driverapi.ErrEndpointExists); !ok {
|
||||
t.Fatalf("Failed with a wrong error: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("Expected to fail while trying to add same endpoint twice")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkCreateNoEnableIPv6(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
te := newTestEndpoint(ipdList[0].Pool, 30)
|
||||
err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||
}
|
||||
|
||||
iface := te.iface
|
||||
if iface.addrv6 != nil && iface.addrv6.IP.To16() != nil {
|
||||
t.Fatalf("Expectd IPv6 address to be nil when IPv6 is not enabled. Got IPv6 = %s", iface.addrv6.String())
|
||||
}
|
||||
|
||||
if te.gw6.To16() != nil {
|
||||
t.Fatalf("Expected GatewayIPv6 to be nil when IPv6 is not enabled. Got GatewayIPv6 = %s", te.gw6.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkDelete(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
if err := d.configure(nil); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 30)
|
||||
err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||
}
|
||||
|
||||
err = d.DeleteEndpoint("dummy", "")
|
||||
if err != nil {
|
||||
if _, ok := err.(InvalidEndpointIDError); !ok {
|
||||
t.Fatalf("Failed with a wrong error :%s", err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("Failed to detect invalid config")
|
||||
}
|
||||
|
||||
err = d.DeleteEndpoint("dummy", "ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
128
vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
generated
vendored
Normal file
128
vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||
if epConfig == nil || epConfig.PortBindings == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
defHostIP := defaultBindingIP
|
||||
if reqDefBindIP != nil {
|
||||
defHostIP = reqDefBindIP
|
||||
}
|
||||
|
||||
return n.allocatePortsInternal(epConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||
bs := make([]types.PortBinding, 0, len(bindings))
|
||||
for _, c := range bindings {
|
||||
b := c.GetCopy()
|
||||
if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
||||
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
|
||||
if cuErr := n.releasePortsInternal(bs); cuErr != nil {
|
||||
logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
bs = append(bs, b)
|
||||
}
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
|
||||
var (
|
||||
host net.Addr
|
||||
err error
|
||||
)
|
||||
|
||||
// Store the container interface address in the operational binding
|
||||
bnd.IP = containerIP
|
||||
|
||||
// Adjust the host address in the operational binding
|
||||
if len(bnd.HostIP) == 0 {
|
||||
bnd.HostIP = defHostIP
|
||||
}
|
||||
|
||||
// Adjust HostPortEnd if this is not a range.
|
||||
if bnd.HostPortEnd == 0 {
|
||||
bnd.HostPortEnd = bnd.HostPort
|
||||
}
|
||||
|
||||
// Construct the container side transport address
|
||||
container, err := bnd.ContainerAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
||||
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||
if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
|
||||
break
|
||||
}
|
||||
// There is no point in immediately retrying to map an explicitly chosen port.
|
||||
if bnd.HostPort != 0 {
|
||||
logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
|
||||
break
|
||||
}
|
||||
logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the host port (regardless it was or not specified in the binding)
|
||||
switch netAddr := host.(type) {
|
||||
case *net.TCPAddr:
|
||||
bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
|
||||
return nil
|
||||
case *net.UDPAddr:
|
||||
bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
|
||||
return nil
|
||||
default:
|
||||
// For completeness
|
||||
return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
|
||||
}
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
|
||||
return n.releasePortsInternal(ep.portMapping)
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
|
||||
var errorBuf bytes.Buffer
|
||||
|
||||
// Attempt to release all port bindings, do not stop on failure
|
||||
for _, m := range bindings {
|
||||
if err := n.releasePort(m); err != nil {
|
||||
errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
|
||||
}
|
||||
}
|
||||
|
||||
if errorBuf.Len() != 0 {
|
||||
return errors.New(errorBuf.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
|
||||
// Construct the host side transport address
|
||||
host, err := bnd.HostAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.portMapper.Unmap(host)
|
||||
}
|
||||
80
vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go
generated
vendored
Normal file
80
vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
if reexec.Init() {
|
||||
return
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestPortMappingConfig(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
d := newDriver()
|
||||
|
||||
config := &configuration{
|
||||
EnableIPTables: true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = config
|
||||
|
||||
if err := d.configure(genericOption); err != nil {
|
||||
t.Fatalf("Failed to setup driver config: %v", err)
|
||||
}
|
||||
|
||||
binding1 := types.PortBinding{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)}
|
||||
binding2 := types.PortBinding{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)}
|
||||
portBindings := []types.PortBinding{binding1, binding2}
|
||||
|
||||
epOptions := make(map[string]interface{})
|
||||
epOptions[netlabel.PortMap] = portBindings
|
||||
|
||||
netConfig := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
}
|
||||
netOptions := make(map[string]interface{})
|
||||
netOptions[netlabel.GenericData] = netConfig
|
||||
|
||||
ipdList := getIPv4Data(t)
|
||||
err := d.CreateNetwork("dummy", netOptions, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
te := newTestEndpoint(ipdList[0].Pool, 11)
|
||||
err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create the endpoint: %s", err.Error())
|
||||
}
|
||||
|
||||
network, ok := d.networks["dummy"]
|
||||
if !ok {
|
||||
t.Fatalf("Cannot find network %s inside driver", "dummy")
|
||||
}
|
||||
ep, _ := network.endpoints["ep1"]
|
||||
if len(ep.portMapping) != 2 {
|
||||
t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
|
||||
}
|
||||
if ep.portMapping[0].Proto != binding1.Proto || ep.portMapping[0].Port != binding1.Port ||
|
||||
ep.portMapping[1].Proto != binding2.Proto || ep.portMapping[1].Port != binding2.Port {
|
||||
t.Fatalf("bridgeEndpoint has incorrect port mapping values")
|
||||
}
|
||||
if ep.portMapping[0].HostIP == nil || ep.portMapping[0].HostPort == 0 ||
|
||||
ep.portMapping[1].HostIP == nil || ep.portMapping[1].HostPort == 0 {
|
||||
t.Fatalf("operational port mapping data not found on bridgeEndpoint")
|
||||
}
|
||||
|
||||
err = network.releasePorts(ep)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to release mapped ports: %v", err)
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/docker/libnetwork/drivers/bridge/resolvconf.go
generated
vendored
Normal file
67
vendor/github.com/docker/libnetwork/drivers/bridge/resolvconf.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
ipv4NumBlock = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)`
|
||||
ipv4Address = `(` + ipv4NumBlock + `\.){3}` + ipv4NumBlock
|
||||
|
||||
// This is not an IPv6 address verifier as it will accept a super-set of IPv6, and also
|
||||
// will *not match* IPv4-Embedded IPv6 Addresses (RFC6052), but that and other variants
|
||||
// -- e.g. other link-local types -- either won't work in containers or are unnecessary.
|
||||
// For readability and sufficiency for Docker purposes this seemed more reasonable than a
|
||||
// 1000+ character regexp with exact and complete IPv6 validation
|
||||
ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})`
|
||||
)
|
||||
|
||||
var nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
|
||||
|
||||
func readResolvConf() ([]byte, error) {
|
||||
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resolv, nil
|
||||
}
|
||||
|
||||
// getLines parses input into lines and strips away comments.
|
||||
func getLines(input []byte, commentMarker []byte) [][]byte {
|
||||
lines := bytes.Split(input, []byte("\n"))
|
||||
var output [][]byte
|
||||
for _, currentLine := range lines {
|
||||
var commentIndex = bytes.Index(currentLine, commentMarker)
|
||||
if commentIndex == -1 {
|
||||
output = append(output, currentLine)
|
||||
} else {
|
||||
output = append(output, currentLine[:commentIndex])
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// GetNameserversAsCIDR returns nameservers (if any) listed in
|
||||
// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32")
|
||||
// This function's output is intended for net.ParseCIDR
|
||||
func getNameserversAsCIDR(resolvConf []byte) []string {
|
||||
nameservers := []string{}
|
||||
for _, nameserver := range getNameservers(resolvConf) {
|
||||
nameservers = append(nameservers, nameserver+"/32")
|
||||
}
|
||||
return nameservers
|
||||
}
|
||||
|
||||
// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf
|
||||
func getNameservers(resolvConf []byte) []string {
|
||||
nameservers := []string{}
|
||||
for _, line := range getLines(resolvConf, []byte("#")) {
|
||||
var ns = nsRegexp.FindSubmatch(line)
|
||||
if len(ns) > 0 {
|
||||
nameservers = append(nameservers, string(ns[1]))
|
||||
}
|
||||
}
|
||||
return nameservers
|
||||
}
|
||||
53
vendor/github.com/docker/libnetwork/drivers/bridge/resolvconf_test.go
generated
vendored
Normal file
53
vendor/github.com/docker/libnetwork/drivers/bridge/resolvconf_test.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResolveConfRead(t *testing.T) {
|
||||
b, err := readResolvConf()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read resolv.conf: %v", err)
|
||||
}
|
||||
|
||||
if b == nil {
|
||||
t.Fatal("Reading resolv.conf returned no content")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveConfReadLines(t *testing.T) {
|
||||
commentChar := []byte("#")
|
||||
|
||||
b, _ := readResolvConf()
|
||||
lines := getLines(b, commentChar)
|
||||
if lines == nil {
|
||||
t.Fatal("Failed to read resolv.conf lines")
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
if bytes.Index(line, commentChar) != -1 {
|
||||
t.Fatal("Returned comment content from resolv.conf")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvConfNameserversAsCIDR(t *testing.T) {
|
||||
resolvConf := `# Commented line
|
||||
nameserver 1.2.3.4
|
||||
|
||||
nameserver 5.6.7.8 # Test
|
||||
`
|
||||
|
||||
cidrs := getNameserversAsCIDR([]byte(resolvConf))
|
||||
if expected := 2; len(cidrs) != expected {
|
||||
t.Fatalf("Expected %d nameservers, got %d", expected, len(cidrs))
|
||||
}
|
||||
|
||||
expected := []string{"1.2.3.4/32", "5.6.7.8/32"}
|
||||
for i, exp := range expected {
|
||||
if cidrs[i] != exp {
|
||||
t.Fatalf("Expected nameservers %s, got %s", exp, cidrs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/docker/libnetwork/drivers/bridge/setup.go
generated
vendored
Normal file
26
vendor/github.com/docker/libnetwork/drivers/bridge/setup.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package bridge
|
||||
|
||||
type setupStep func(*networkConfiguration, *bridgeInterface) error
|
||||
|
||||
type bridgeSetup struct {
|
||||
config *networkConfiguration
|
||||
bridge *bridgeInterface
|
||||
steps []setupStep
|
||||
}
|
||||
|
||||
func newBridgeSetup(c *networkConfiguration, i *bridgeInterface) *bridgeSetup {
|
||||
return &bridgeSetup{config: c, bridge: i}
|
||||
}
|
||||
|
||||
func (b *bridgeSetup) apply() error {
|
||||
for _, fn := range b.steps {
|
||||
if err := fn(b.config, b.bridge); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bridgeSetup) queueStep(step setupStep) {
|
||||
b.steps = append(b.steps, step)
|
||||
}
|
||||
162
vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go
generated
vendored
Normal file
162
vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Enumeration type saying which versions of IP protocol to process.
|
||||
type ipVersion int
|
||||
|
||||
const (
|
||||
ipvnone ipVersion = iota
|
||||
ipv4
|
||||
ipv6
|
||||
ipvboth
|
||||
)
|
||||
|
||||
//Gets the IP version in use ( [ipv4], [ipv6] or [ipv4 and ipv6] )
|
||||
func getIPVersion(config *networkConfiguration) ipVersion {
|
||||
ipVersion := ipv4
|
||||
if config.AddressIPv6 != nil || config.EnableIPv6 {
|
||||
ipVersion |= ipv6
|
||||
}
|
||||
return ipVersion
|
||||
}
|
||||
|
||||
func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error {
|
||||
err := checkBridgeNetFiltering(config, i)
|
||||
if err != nil {
|
||||
if ptherr, ok := err.(*os.PathError); ok {
|
||||
if errno, ok := ptherr.Err.(syscall.Errno); ok && errno == syscall.ENOENT {
|
||||
if isRunningInContainer() {
|
||||
logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err)
|
||||
err = nil
|
||||
} else {
|
||||
err = fmt.Errorf("please ensure that br_netfilter kernel module is loaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot restrict inter-container communication: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//Enable bridge net filtering if ip forwarding is enabled. See github issue #11404
|
||||
func checkBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error {
|
||||
ipVer := getIPVersion(config)
|
||||
iface := config.BridgeName
|
||||
doEnable := func(ipVer ipVersion) error {
|
||||
var ipVerName string
|
||||
if ipVer == ipv4 {
|
||||
ipVerName = "IPv4"
|
||||
} else {
|
||||
ipVerName = "IPv6"
|
||||
}
|
||||
enabled, err := isPacketForwardingEnabled(ipVer, iface)
|
||||
if err != nil {
|
||||
logrus.Warnf("failed to check %s forwarding: %v", ipVerName, err)
|
||||
} else if enabled {
|
||||
enabled, err := getKernelBoolParam(getBridgeNFKernelParam(ipVer))
|
||||
if err != nil || enabled {
|
||||
return err
|
||||
}
|
||||
return setKernelBoolParam(getBridgeNFKernelParam(ipVer), true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
switch ipVer {
|
||||
case ipv4, ipv6:
|
||||
return doEnable(ipVer)
|
||||
case ipvboth:
|
||||
v4err := doEnable(ipv4)
|
||||
v6err := doEnable(ipv6)
|
||||
if v4err == nil {
|
||||
return v6err
|
||||
}
|
||||
return v4err
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Get kernel param path saying whether IPv${ipVer} traffic is being forwarded
|
||||
// on particular interface. Interface may be specified for IPv6 only. If
|
||||
// `iface` is empty, `default` will be assumed, which represents default value
|
||||
// for new interfaces.
|
||||
func getForwardingKernelParam(ipVer ipVersion, iface string) string {
|
||||
switch ipVer {
|
||||
case ipv4:
|
||||
return "/proc/sys/net/ipv4/ip_forward"
|
||||
case ipv6:
|
||||
if iface == "" {
|
||||
iface = "default"
|
||||
}
|
||||
return fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/forwarding", iface)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Get kernel param path saying whether bridged IPv${ipVer} traffic shall be
|
||||
// passed to ip${ipVer}tables' chains.
|
||||
func getBridgeNFKernelParam(ipVer ipVersion) string {
|
||||
switch ipVer {
|
||||
case ipv4:
|
||||
return "/proc/sys/net/bridge/bridge-nf-call-iptables"
|
||||
case ipv6:
|
||||
return "/proc/sys/net/bridge/bridge-nf-call-ip6tables"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
//Gets the value of the kernel parameters located at the given path
|
||||
func getKernelBoolParam(path string) (bool, error) {
|
||||
enabled := false
|
||||
line, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(line) > 0 {
|
||||
enabled = line[0] == '1'
|
||||
}
|
||||
return enabled, err
|
||||
}
|
||||
|
||||
//Sets the value of the kernel parameter located at the given path
|
||||
func setKernelBoolParam(path string, on bool) error {
|
||||
value := byte('0')
|
||||
if on {
|
||||
value = byte('1')
|
||||
}
|
||||
return ioutil.WriteFile(path, []byte{value, '\n'}, 0644)
|
||||
}
|
||||
|
||||
//Checks to see if packet forwarding is enabled
|
||||
func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) {
|
||||
switch ipVer {
|
||||
case ipv4, ipv6:
|
||||
return getKernelBoolParam(getForwardingKernelParam(ipVer, iface))
|
||||
case ipvboth:
|
||||
enabled, err := getKernelBoolParam(getForwardingKernelParam(ipv4, ""))
|
||||
if err != nil || !enabled {
|
||||
return enabled, err
|
||||
}
|
||||
return getKernelBoolParam(getForwardingKernelParam(ipv6, iface))
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func isRunningInContainer() bool {
|
||||
_, err := os.Stat("/.dockerenv")
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
12
vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering_test.go
generated
vendored
Normal file
12
vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering_test.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package bridge
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIPConstantValues(t *testing.T) {
|
||||
if ipv4|ipv6 != ipvboth {
|
||||
t.Fatalf("bitwise or of ipv4(%04b) and ipv6(%04b) must yield ipvboth(%04b)", ipv4, ipv6, ipvboth)
|
||||
}
|
||||
if ipvboth&(^(ipv4 | ipv6)) != ipvnone {
|
||||
t.Fatalf("ipvboth(%04b) with unset ipv4(%04b) and ipv6(%04b) bits shall equal to ipvnone", ipvboth, ipv4, ipv6)
|
||||
}
|
||||
}
|
||||
66
vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go
generated
vendored
Normal file
66
vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// SetupDevice create a new bridge interface/
|
||||
func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
||||
var setMac bool
|
||||
|
||||
// We only attempt to create the bridge when the requested device name is
|
||||
// the default one.
|
||||
if config.BridgeName != DefaultBridgeName && config.DefaultBridge {
|
||||
return NonDefaultBridgeExistError(config.BridgeName)
|
||||
}
|
||||
|
||||
// Set the bridgeInterface netlink.Bridge.
|
||||
i.Link = &netlink.Bridge{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: config.BridgeName,
|
||||
},
|
||||
}
|
||||
|
||||
// Only set the bridge's MAC address if the kernel version is > 3.3, as it
|
||||
// was not supported before that.
|
||||
kv, err := kernel.GetKernelVersion()
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to check kernel versions: %v. Will not assign a MAC address to the bridge interface", err)
|
||||
} else {
|
||||
setMac = kv.Kernel > 3 || (kv.Kernel == 3 && kv.Major >= 3)
|
||||
}
|
||||
|
||||
if err = netlink.LinkAdd(i.Link); err != nil {
|
||||
logrus.Debugf("Failed to create bridge %s via netlink. Trying ioctl", config.BridgeName)
|
||||
return ioctlCreateBridge(config.BridgeName, setMac)
|
||||
}
|
||||
|
||||
if setMac {
|
||||
hwAddr := netutils.GenerateRandomMAC()
|
||||
if err = netlink.LinkSetHardwareAddr(i.Link, hwAddr); err != nil {
|
||||
return fmt.Errorf("failed to set bridge mac-address %s : %s", hwAddr, err.Error())
|
||||
}
|
||||
logrus.Debugf("Setting bridge mac address to %s", hwAddr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SetupDeviceUp ups the given bridge interface.
|
||||
func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
|
||||
err := netlink.LinkSetUp(i.Link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Attempt to update the bridge interface to refresh the flags status,
|
||||
// ignoring any failure to do so.
|
||||
if lnk, err := netlink.LinkByName(config.BridgeName); err == nil {
|
||||
i.Link = lnk
|
||||
}
|
||||
return nil
|
||||
}
|
||||
76
vendor/github.com/docker/libnetwork/drivers/bridge/setup_device_test.go
generated
vendored
Normal file
76
vendor/github.com/docker/libnetwork/drivers/bridge/setup_device_test.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestSetupNewBridge(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
config := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
br := &bridgeInterface{}
|
||||
|
||||
if err := setupDevice(config, br); err != nil {
|
||||
t.Fatalf("Bridge creation failed: %v", err)
|
||||
}
|
||||
if br.Link == nil {
|
||||
t.Fatal("bridgeInterface link is nil (expected valid link)")
|
||||
}
|
||||
if _, err := netlink.LinkByName(DefaultBridgeName); err != nil {
|
||||
t.Fatalf("Failed to retrieve bridge device: %v", err)
|
||||
}
|
||||
if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp {
|
||||
t.Fatalf("bridgeInterface should be created down")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupNewNonDefaultBridge(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true}
|
||||
br := &bridgeInterface{}
|
||||
|
||||
err := setupDevice(config, br)
|
||||
if err == nil {
|
||||
t.Fatal("Expected bridge creation failure with \"non default name\", succeeded")
|
||||
}
|
||||
|
||||
if _, ok := err.(NonDefaultBridgeExistError); !ok {
|
||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDeviceUp(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
config := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||
br := &bridgeInterface{}
|
||||
|
||||
if err := setupDevice(config, br); err != nil {
|
||||
t.Fatalf("Bridge creation failed: %v", err)
|
||||
}
|
||||
if err := setupDeviceUp(config, br); err != nil {
|
||||
t.Fatalf("Failed to up bridge device: %v", err)
|
||||
}
|
||||
|
||||
lnk, _ := netlink.LinkByName(DefaultBridgeName)
|
||||
if lnk.Attrs().Flags&net.FlagUp != net.FlagUp {
|
||||
t.Fatalf("bridgeInterface should be up")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateRandomMAC(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
mac1 := netutils.GenerateRandomMAC()
|
||||
mac2 := netutils.GenerateRandomMAC()
|
||||
if bytes.Compare(mac1, mac2) == 0 {
|
||||
t.Fatalf("Generated twice the same MAC address %v", mac1)
|
||||
}
|
||||
}
|
||||
20
vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go
generated
vendored
Normal file
20
vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package bridge
|
||||
|
||||
import "github.com/docker/libnetwork/iptables"
|
||||
|
||||
func (n *bridgeNetwork) setupFirewalld(config *networkConfiguration, i *bridgeInterface) error {
|
||||
d := n.driver
|
||||
d.Lock()
|
||||
driverConfig := d.config
|
||||
d.Unlock()
|
||||
|
||||
// Sanity check.
|
||||
if driverConfig.EnableIPTables == false {
|
||||
return IPTableCfgError(config.BridgeName)
|
||||
}
|
||||
|
||||
iptables.OnReloaded(func() { n.setupIPTables(config, i) })
|
||||
iptables.OnReloaded(n.portMapper.ReMapAll)
|
||||
|
||||
return nil
|
||||
}
|
||||
29
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go
generated
vendored
Normal file
29
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const (
|
||||
ipv4ForwardConf = "/proc/sys/net/ipv4/ip_forward"
|
||||
ipv4ForwardConfPerm = 0644
|
||||
)
|
||||
|
||||
func setupIPForwarding() error {
|
||||
// Get current IPv4 forward setup
|
||||
ipv4ForwardData, err := ioutil.ReadFile(ipv4ForwardConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IP forwarding setup: %v", err)
|
||||
}
|
||||
|
||||
// Enable IPv4 forwarding only if it is not already enabled
|
||||
if ipv4ForwardData[0] != '1' {
|
||||
// Enable IPv4 forwarding
|
||||
if err := ioutil.WriteFile(ipv4ForwardConf, []byte{'1', '\n'}, ipv4ForwardConfPerm); err != nil {
|
||||
return fmt.Errorf("Setup IP forwarding failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
51
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go
generated
vendored
Normal file
51
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetupIPForwarding(t *testing.T) {
|
||||
// Read current setting and ensure the original value gets restored
|
||||
procSetting := readCurrentIPForwardingSetting(t)
|
||||
defer reconcileIPForwardingSetting(t, procSetting)
|
||||
|
||||
// Disable IP Forwarding if enabled
|
||||
if bytes.Compare(procSetting, []byte("1\n")) == 0 {
|
||||
writeIPForwardingSetting(t, []byte{'0', '\n'})
|
||||
}
|
||||
|
||||
// Set IP Forwarding
|
||||
if err := setupIPForwarding(); err != nil {
|
||||
t.Fatalf("Failed to setup IP forwarding: %v", err)
|
||||
}
|
||||
|
||||
// Read new setting
|
||||
procSetting = readCurrentIPForwardingSetting(t)
|
||||
if bytes.Compare(procSetting, []byte("1\n")) != 0 {
|
||||
t.Fatalf("Failed to effectively setup IP forwarding")
|
||||
}
|
||||
}
|
||||
|
||||
func readCurrentIPForwardingSetting(t *testing.T) []byte {
|
||||
procSetting, err := ioutil.ReadFile(ipv4ForwardConf)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't execute test: Failed to read current IP forwarding setting: %v", err)
|
||||
}
|
||||
return procSetting
|
||||
}
|
||||
|
||||
func writeIPForwardingSetting(t *testing.T, chars []byte) {
|
||||
err := ioutil.WriteFile(ipv4ForwardConf, chars, ipv4ForwardConfPerm)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't execute or cleanup after test: Failed to reset IP forwarding: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func reconcileIPForwardingSetting(t *testing.T, original []byte) {
|
||||
current := readCurrentIPForwardingSetting(t)
|
||||
if bytes.Compare(original, current) != 0 {
|
||||
writeIPForwardingSetting(t, original)
|
||||
}
|
||||
}
|
||||
345
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
generated
vendored
Normal file
345
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
generated
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
// DockerChain: DOCKER iptable chain name
|
||||
const (
|
||||
DockerChain = "DOCKER"
|
||||
IsolationChain = "DOCKER-ISOLATION"
|
||||
)
|
||||
|
||||
func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
|
||||
// Sanity check.
|
||||
if config.EnableIPTables == false {
|
||||
return nil, nil, nil, fmt.Errorf("cannot create new chains, EnableIPTable is disabled")
|
||||
}
|
||||
|
||||
hairpinMode := !config.EnableUserlandProxy
|
||||
|
||||
natChain, err := iptables.NewChain(DockerChain, iptables.Nat, hairpinMode)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to create NAT chain: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
|
||||
logrus.Warnf("failed on removing iptables NAT chain on cleanup: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, false)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to create FILTER chain: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err := iptables.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
|
||||
logrus.Warnf("failed on removing iptables FILTER chain on cleanup: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
isolationChain, err := iptables.NewChain(IsolationChain, iptables.Filter, false)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
|
||||
}
|
||||
|
||||
if err := addReturnRule(IsolationChain); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return natChain, filterChain, isolationChain, nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error {
|
||||
d := n.driver
|
||||
d.Lock()
|
||||
driverConfig := d.config
|
||||
d.Unlock()
|
||||
|
||||
// Sanity check.
|
||||
if driverConfig.EnableIPTables == false {
|
||||
return fmt.Errorf("Cannot program chains, EnableIPTable is disabled")
|
||||
}
|
||||
|
||||
// Pickup this configuraton option from driver
|
||||
hairpinMode := !driverConfig.EnableUserlandProxy
|
||||
|
||||
addrv4, _, err := netutils.GetIfaceAddr(config.BridgeName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire Interface address: %s", err.Error())
|
||||
}
|
||||
ipnet := addrv4.(*net.IPNet)
|
||||
maskedAddrv4 := &net.IPNet{
|
||||
IP: ipnet.IP.Mask(ipnet.Mask),
|
||||
Mask: ipnet.Mask,
|
||||
}
|
||||
if config.Internal {
|
||||
if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, true); err != nil {
|
||||
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
||||
}
|
||||
n.registerIptCleanFunc(func() error {
|
||||
return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, false)
|
||||
})
|
||||
} else {
|
||||
if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
||||
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
||||
}
|
||||
n.registerIptCleanFunc(func() error {
|
||||
return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
|
||||
})
|
||||
natChain, filterChain, _, err := n.getDriverChains()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
||||
}
|
||||
|
||||
err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
||||
}
|
||||
|
||||
err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
||||
}
|
||||
|
||||
n.registerIptCleanFunc(func() error {
|
||||
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
|
||||
})
|
||||
|
||||
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
|
||||
}
|
||||
|
||||
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type iptRule struct {
|
||||
table iptables.Table
|
||||
chain string
|
||||
preArgs []string
|
||||
args []string
|
||||
}
|
||||
|
||||
func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairpin, enable bool) error {
|
||||
|
||||
var (
|
||||
address = addr.String()
|
||||
natRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", address, "!", "-o", bridgeIface, "-j", "MASQUERADE"}}
|
||||
hpNatRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}}
|
||||
outRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}}
|
||||
inRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}
|
||||
)
|
||||
|
||||
// Set NAT.
|
||||
if ipmasq {
|
||||
if err := programChainRule(natRule, "NAT", enable); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// In hairpin mode, masquerade traffic from localhost
|
||||
if hairpin {
|
||||
if err := programChainRule(hpNatRule, "MASQ LOCAL HOST", enable); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Set Inter Container Communication.
|
||||
if err := setIcc(bridgeIface, icc, enable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set Accept on all non-intercontainer outgoing packets.
|
||||
if err := programChainRule(outRule, "ACCEPT NON_ICC OUTGOING", enable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set Accept on incoming packets for existing connections.
|
||||
if err := programChainRule(inRule, "ACCEPT INCOMING", enable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
|
||||
var (
|
||||
prefix []string
|
||||
operation string
|
||||
condition bool
|
||||
doesExist = iptables.Exists(rule.table, rule.chain, rule.args...)
|
||||
)
|
||||
|
||||
if insert {
|
||||
condition = !doesExist
|
||||
prefix = []string{"-I", rule.chain}
|
||||
operation = "enable"
|
||||
} else {
|
||||
condition = doesExist
|
||||
prefix = []string{"-D", rule.chain}
|
||||
operation = "disable"
|
||||
}
|
||||
if rule.preArgs != nil {
|
||||
prefix = append(rule.preArgs, prefix...)
|
||||
}
|
||||
|
||||
if condition {
|
||||
if err := iptables.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
|
||||
return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setIcc(bridgeIface string, iccEnable, insert bool) error {
|
||||
var (
|
||||
table = iptables.Filter
|
||||
chain = "FORWARD"
|
||||
args = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"}
|
||||
acceptArgs = append(args, "ACCEPT")
|
||||
dropArgs = append(args, "DROP")
|
||||
)
|
||||
|
||||
if insert {
|
||||
if !iccEnable {
|
||||
iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...)
|
||||
|
||||
if !iptables.Exists(table, chain, dropArgs...) {
|
||||
if err := iptables.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iptables.Raw(append([]string{"-D", chain}, dropArgs...)...)
|
||||
|
||||
if !iptables.Exists(table, chain, acceptArgs...) {
|
||||
if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove any ICC rule.
|
||||
if !iccEnable {
|
||||
if iptables.Exists(table, chain, dropArgs...) {
|
||||
iptables.Raw(append([]string{"-D", chain}, dropArgs...)...)
|
||||
}
|
||||
} else {
|
||||
if iptables.Exists(table, chain, acceptArgs...) {
|
||||
iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Control Inter Network Communication. Install/remove only if it is not/is present.
|
||||
func setINC(iface1, iface2 string, enable bool) error {
|
||||
var (
|
||||
table = iptables.Filter
|
||||
chain = IsolationChain
|
||||
args = [2][]string{{"-i", iface1, "-o", iface2, "-j", "DROP"}, {"-i", iface2, "-o", iface1, "-j", "DROP"}}
|
||||
)
|
||||
|
||||
if enable {
|
||||
for i := 0; i < 2; i++ {
|
||||
if iptables.Exists(table, chain, args[i]...) {
|
||||
continue
|
||||
}
|
||||
if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args[i]...)...); err != nil {
|
||||
return fmt.Errorf("unable to add inter-network communication rule: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 2; i++ {
|
||||
if !iptables.Exists(table, chain, args[i]...) {
|
||||
continue
|
||||
}
|
||||
if err := iptables.RawCombinedOutput(append([]string{"-D", chain}, args[i]...)...); err != nil {
|
||||
return fmt.Errorf("unable to remove inter-network communication rule: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addReturnRule(chain string) error {
|
||||
var (
|
||||
table = iptables.Filter
|
||||
args = []string{"-j", "RETURN"}
|
||||
)
|
||||
|
||||
if iptables.Exists(table, chain, args...) {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args...)...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ensure the jump rule is on top
|
||||
func ensureJumpRule(fromChain, toChain string) error {
|
||||
var (
|
||||
table = iptables.Filter
|
||||
args = []string{"-j", toChain}
|
||||
)
|
||||
|
||||
if iptables.Exists(table, fromChain, args...) {
|
||||
err := iptables.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
err := iptables.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeIPChains() {
|
||||
for _, chainInfo := range []iptables.ChainInfo{
|
||||
{Name: DockerChain, Table: iptables.Nat},
|
||||
{Name: DockerChain, Table: iptables.Filter},
|
||||
{Name: IsolationChain, Table: iptables.Filter},
|
||||
} {
|
||||
if err := chainInfo.Remove(); err != nil {
|
||||
logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) error {
|
||||
var (
|
||||
inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
|
||||
outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
|
||||
)
|
||||
if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
124
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables_test.go
generated
vendored
Normal file
124
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables_test.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
"github.com/docker/libnetwork/portmapper"
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
)
|
||||
|
||||
const (
|
||||
iptablesTestBridgeIP = "192.168.42.1"
|
||||
)
|
||||
|
||||
func TestProgramIPTable(t *testing.T) {
|
||||
// Create a test bridge with a basic bridge configuration (name + IPv4).
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
createTestBridge(getBasicTestConfig(), &bridgeInterface{}, t)
|
||||
|
||||
// Store various iptables chain rules we care for.
|
||||
rules := []struct {
|
||||
rule iptRule
|
||||
descr string
|
||||
}{
|
||||
{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"},
|
||||
{iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"},
|
||||
{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"},
|
||||
{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"},
|
||||
{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"},
|
||||
{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"},
|
||||
}
|
||||
|
||||
// Assert the chain rules' insertion and removal.
|
||||
for _, c := range rules {
|
||||
assertIPTableChainProgramming(c.rule, c.descr, t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupIPChains(t *testing.T) {
|
||||
// Create a test bridge with a basic bridge configuration (name + IPv4).
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
driverconfig := &configuration{
|
||||
EnableIPTables: true,
|
||||
}
|
||||
d := &driver{
|
||||
config: driverconfig,
|
||||
}
|
||||
assertChainConfig(d, t)
|
||||
|
||||
config := getBasicTestConfig()
|
||||
br := &bridgeInterface{}
|
||||
createTestBridge(config, br, t)
|
||||
|
||||
assertBridgeConfig(config, br, d, t)
|
||||
|
||||
config.EnableIPMasquerade = true
|
||||
assertBridgeConfig(config, br, d, t)
|
||||
|
||||
config.EnableICC = true
|
||||
assertBridgeConfig(config, br, d, t)
|
||||
|
||||
config.EnableIPMasquerade = false
|
||||
assertBridgeConfig(config, br, d, t)
|
||||
}
|
||||
|
||||
func getBasicTestConfig() *networkConfiguration {
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)}}
|
||||
return config
|
||||
}
|
||||
|
||||
func createTestBridge(config *networkConfiguration, br *bridgeInterface, t *testing.T) {
|
||||
if err := setupDevice(config, br); err != nil {
|
||||
t.Fatalf("Failed to create the testing Bridge: %s", err.Error())
|
||||
}
|
||||
if err := setupBridgeIPv4(config, br); err != nil {
|
||||
t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Assert base function which pushes iptables chain rules on insertion and removal.
|
||||
func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
|
||||
// Add
|
||||
if err := programChainRule(rule, descr, true); err != nil {
|
||||
t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error())
|
||||
}
|
||||
if iptables.Exists(rule.table, rule.chain, rule.args...) == false {
|
||||
t.Fatalf("Failed to effectively program iptable rule: %s", descr)
|
||||
}
|
||||
|
||||
// Remove
|
||||
if err := programChainRule(rule, descr, false); err != nil {
|
||||
t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error())
|
||||
}
|
||||
if iptables.Exists(rule.table, rule.chain, rule.args...) == true {
|
||||
t.Fatalf("Failed to effectively remove iptable rule: %s", descr)
|
||||
}
|
||||
}
|
||||
|
||||
// Assert function which create chains.
|
||||
func assertChainConfig(d *driver, t *testing.T) {
|
||||
var err error
|
||||
|
||||
d.natChain, d.filterChain, d.isolationChain, err = setupIPChains(d.config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Assert function which pushes chains based on bridge config parameters.
|
||||
func assertBridgeConfig(config *networkConfiguration, br *bridgeInterface, d *driver, t *testing.T) {
|
||||
nw := bridgeNetwork{portMapper: portmapper.New(),
|
||||
config: config}
|
||||
nw.driver = d
|
||||
|
||||
// Attempt programming of ip tables.
|
||||
err := nw.setupIPTables(config, br)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
62
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go
generated
vendored
Normal file
62
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
|
||||
addrv4, _, err := i.addresses()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
|
||||
}
|
||||
|
||||
if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
|
||||
if addrv4.IPNet != nil {
|
||||
if err := netlink.AddrDel(i.Link, &addrv4); err != nil {
|
||||
return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
|
||||
}
|
||||
}
|
||||
log.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
|
||||
if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
|
||||
return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Store bridge network and default gateway
|
||||
i.bridgeIPv4 = config.AddressIPv4
|
||||
i.gatewayIPv4 = config.AddressIPv4.IP
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupGatewayIPv4(config *networkConfiguration, i *bridgeInterface) error {
|
||||
if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
|
||||
return &ErrInvalidGateway{}
|
||||
}
|
||||
|
||||
// Store requested default gateway
|
||||
i.gatewayIPv4 = config.DefaultGatewayIPv4
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupLoopbackAdressesRouting(config *networkConfiguration, i *bridgeInterface) error {
|
||||
sysPath := filepath.Join("/proc/sys/net/ipv4/conf", config.BridgeName, "route_localnet")
|
||||
ipv4LoRoutingData, err := ioutil.ReadFile(sysPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv4 local routing setup: %v", err)
|
||||
}
|
||||
// Enable loopback adresses routing only if it isn't already enabled
|
||||
if ipv4LoRoutingData[0] != '1' {
|
||||
if err := ioutil.WriteFile(sysPath, []byte{'1', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("Unable to enable local routing for hairpin mode: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
74
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4_test.go
generated
vendored
Normal file
74
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4_test.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func setupTestInterface(t *testing.T) (*networkConfiguration, *bridgeInterface) {
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName}
|
||||
br := &bridgeInterface{}
|
||||
|
||||
if err := setupDevice(config, br); err != nil {
|
||||
t.Fatalf("Bridge creation failed: %v", err)
|
||||
}
|
||||
return config, br
|
||||
}
|
||||
|
||||
func TestSetupBridgeIPv4Fixed(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
ip, netw, err := net.ParseCIDR("192.168.1.1/24")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bridge IPv4: %v", err)
|
||||
}
|
||||
|
||||
config, br := setupTestInterface(t)
|
||||
config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
|
||||
if err := setupBridgeIPv4(config, br); err != nil {
|
||||
t.Fatalf("Failed to setup bridge IPv4: %v", err)
|
||||
}
|
||||
|
||||
addrsv4, err := netlink.AddrList(br.Link, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to list device IPv4 addresses: %v", err)
|
||||
}
|
||||
|
||||
var found bool
|
||||
for _, addr := range addrsv4 {
|
||||
if config.AddressIPv4.String() == addr.IPNet.String() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("Bridge device does not have requested IPv4 address %v", config.AddressIPv4)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupGatewayIPv4(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
ip, nw, _ := net.ParseCIDR("192.168.0.24/16")
|
||||
nw.IP = ip
|
||||
gw := net.ParseIP("192.168.2.254")
|
||||
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
DefaultGatewayIPv4: gw}
|
||||
|
||||
br := &bridgeInterface{bridgeIPv4: nw}
|
||||
|
||||
if err := setupGatewayIPv4(config, br); err != nil {
|
||||
t.Fatalf("Set Default Gateway failed: %v", err)
|
||||
}
|
||||
|
||||
if !gw.Equal(br.gatewayIPv4) {
|
||||
t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv4)
|
||||
}
|
||||
}
|
||||
119
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go
generated
vendored
Normal file
119
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
var bridgeIPv6 *net.IPNet
|
||||
|
||||
const (
|
||||
bridgeIPv6Str = "fe80::1/64"
|
||||
ipv6ForwardConfPerm = 0644
|
||||
ipv6ForwardConfDefault = "/proc/sys/net/ipv6/conf/default/forwarding"
|
||||
ipv6ForwardConfAll = "/proc/sys/net/ipv6/conf/all/forwarding"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We allow ourselves to panic in this special case because we indicate a
|
||||
// failure to parse a compile-time define constant.
|
||||
var err error
|
||||
if bridgeIPv6, err = types.ParseCIDR(bridgeIPv6Str); err != nil {
|
||||
panic(fmt.Sprintf("Cannot parse default bridge IPv6 address %q: %v", bridgeIPv6Str, err))
|
||||
}
|
||||
}
|
||||
|
||||
func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
|
||||
procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6"
|
||||
ipv6BridgeData, err := ioutil.ReadFile(procFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv6 setup for bridge %v: %v", config.BridgeName, err)
|
||||
}
|
||||
// Enable IPv6 on the bridge only if it isn't already enabled
|
||||
if ipv6BridgeData[0] != '0' {
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Store bridge network and default gateway
|
||||
i.bridgeIPv6 = bridgeIPv6
|
||||
i.gatewayIPv6 = i.bridgeIPv6.IP
|
||||
|
||||
if err := i.programIPv6Address(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.AddressIPv6 == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Store the user specified bridge network and network gateway and program it
|
||||
i.bridgeIPv6 = config.AddressIPv6
|
||||
i.gatewayIPv6 = config.AddressIPv6.IP
|
||||
|
||||
if err := i.programIPv6Address(); err != nil {
|
||||
return 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{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
LinkIndex: i.Link.Attrs().Index,
|
||||
Dst: config.AddressIPv6,
|
||||
})
|
||||
if err != nil && !os.IsExist(err) {
|
||||
logrus.Errorf("Could not add route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
|
||||
if config.AddressIPv6 == nil {
|
||||
return &ErrInvalidContainerSubnet{}
|
||||
}
|
||||
if !config.AddressIPv6.Contains(config.DefaultGatewayIPv6) {
|
||||
return &ErrInvalidGateway{}
|
||||
}
|
||||
|
||||
// Store requested default gateway
|
||||
i.gatewayIPv6 = config.DefaultGatewayIPv6
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error {
|
||||
// Get current IPv6 default forwarding setup
|
||||
ipv6ForwardDataDefault, err := ioutil.ReadFile(ipv6ForwardConfDefault)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv6 default forwarding setup: %v", err)
|
||||
}
|
||||
// Enable IPv6 default forwarding only if it is not already enabled
|
||||
if ipv6ForwardDataDefault[0] != '1' {
|
||||
if err := ioutil.WriteFile(ipv6ForwardConfDefault, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
logrus.Warnf("Unable to enable IPv6 default forwarding: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get current IPv6 all forwarding setup
|
||||
ipv6ForwardDataAll, err := ioutil.ReadFile(ipv6ForwardConfAll)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv6 all forwarding setup: %v", err)
|
||||
}
|
||||
// Enable IPv6 all forwarding only if it is not already enabled
|
||||
if ipv6ForwardDataAll[0] != '1' {
|
||||
if err := ioutil.WriteFile(ipv6ForwardConfAll, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
logrus.Warnf("Unable to enable IPv6 all forwarding: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
70
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6_test.go
generated
vendored
Normal file
70
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6_test.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestSetupIPv6(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
config, br := setupTestInterface(t)
|
||||
if err := setupBridgeIPv6(config, br); err != nil {
|
||||
t.Fatalf("Failed to setup bridge IPv6: %v", err)
|
||||
}
|
||||
|
||||
procSetting, err := ioutil.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", config.BridgeName))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read disable_ipv6 kernel setting: %v", err)
|
||||
}
|
||||
|
||||
if expected := []byte("0\n"); bytes.Compare(expected, procSetting) != 0 {
|
||||
t.Fatalf("Invalid kernel setting disable_ipv6: expected %q, got %q", string(expected), string(procSetting))
|
||||
}
|
||||
|
||||
addrsv6, err := netlink.AddrList(br.Link, netlink.FAMILY_V6)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to list device IPv6 addresses: %v", err)
|
||||
}
|
||||
|
||||
var found bool
|
||||
for _, addr := range addrsv6 {
|
||||
if bridgeIPv6Str == addr.IPNet.String() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("Bridge device does not have requested IPv6 address %v", bridgeIPv6Str)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSetupGatewayIPv6(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
_, nw, _ := net.ParseCIDR("2001:db8:ea9:9abc:ffff::/80")
|
||||
gw := net.ParseIP("2001:db8:ea9:9abc:ffff::254")
|
||||
|
||||
config := &networkConfiguration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
AddressIPv6: nw,
|
||||
DefaultGatewayIPv6: gw}
|
||||
|
||||
br := &bridgeInterface{}
|
||||
|
||||
if err := setupGatewayIPv6(config, br); err != nil {
|
||||
t.Fatalf("Set Default Gateway failed: %v", err)
|
||||
}
|
||||
|
||||
if !gw.Equal(br.gatewayIPv6) {
|
||||
t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv6)
|
||||
}
|
||||
}
|
||||
51
vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go
generated
vendored
Normal file
51
vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) error {
|
||||
// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
|
||||
addrv4, addrsv6, err := i.addresses()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify that the bridge does have an IPv4 address.
|
||||
if addrv4.IPNet == nil {
|
||||
return &ErrNoIPAddr{}
|
||||
}
|
||||
|
||||
// Verify that the bridge IPv4 address matches the requested configuration.
|
||||
if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
|
||||
return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
|
||||
}
|
||||
|
||||
// Verify that one of the bridge IPv6 addresses matches the requested
|
||||
// configuration.
|
||||
if config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
|
||||
return (*IPv6AddrNoMatchError)(bridgeIPv6)
|
||||
}
|
||||
|
||||
// Release any residual IPv6 address that might be there because of older daemon instances
|
||||
for _, addrv6 := range addrsv6 {
|
||||
if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) {
|
||||
if err := netlink.AddrDel(i.Link, &addrv6); err != nil {
|
||||
log.Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findIPv6Address(addr netlink.Addr, addresses []netlink.Addr) bool {
|
||||
for _, addrv6 := range addresses {
|
||||
if addrv6.String() == addr.String() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
110
vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify_test.go
generated
vendored
Normal file
110
vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify_test.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/testutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func setupVerifyTest(t *testing.T) *bridgeInterface {
|
||||
inf := &bridgeInterface{}
|
||||
|
||||
br := netlink.Bridge{}
|
||||
br.LinkAttrs.Name = "default0"
|
||||
if err := netlink.LinkAdd(&br); err == nil {
|
||||
inf.Link = &br
|
||||
} else {
|
||||
t.Fatalf("Failed to create bridge interface: %v", err)
|
||||
}
|
||||
|
||||
return inf
|
||||
}
|
||||
|
||||
func TestSetupVerify(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
config := &networkConfiguration{}
|
||||
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
||||
|
||||
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
|
||||
t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
|
||||
}
|
||||
|
||||
if err := setupVerifyAndReconcile(config, inf); err != nil {
|
||||
t.Fatalf("Address verification failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupVerifyBad(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
config := &networkConfiguration{}
|
||||
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
||||
|
||||
ipnet := &net.IPNet{IP: net.IPv4(192, 168, 1, 2), Mask: addrv4.DefaultMask()}
|
||||
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: ipnet}); err != nil {
|
||||
t.Fatalf("Failed to assign IPv4 %s to interface: %v", ipnet, err)
|
||||
}
|
||||
|
||||
if err := setupVerifyAndReconcile(config, inf); err == nil {
|
||||
t.Fatal("Address verification was expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupVerifyMissing(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
config := &networkConfiguration{}
|
||||
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
||||
|
||||
if err := setupVerifyAndReconcile(config, inf); err == nil {
|
||||
t.Fatal("Address verification was expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupVerifyIPv6(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
config := &networkConfiguration{}
|
||||
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
||||
config.EnableIPv6 = true
|
||||
|
||||
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
|
||||
t.Fatalf("Failed to assign IPv6 %s to interface: %v", bridgeIPv6, err)
|
||||
}
|
||||
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
|
||||
t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
|
||||
}
|
||||
|
||||
if err := setupVerifyAndReconcile(config, inf); err != nil {
|
||||
t.Fatalf("Address verification failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupVerifyIPv6Missing(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
config := &networkConfiguration{}
|
||||
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
||||
config.EnableIPv6 = true
|
||||
|
||||
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
|
||||
t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
|
||||
}
|
||||
|
||||
if err := setupVerifyAndReconcile(config, inf); err == nil {
|
||||
t.Fatal("Address verification was expected to fail")
|
||||
}
|
||||
}
|
||||
77
vendor/github.com/docker/libnetwork/drivers/host/host.go
generated
vendored
Normal file
77
vendor/github.com/docker/libnetwork/drivers/host/host.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const networkType = "host"
|
||||
|
||||
type driver struct {
|
||||
network string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// Init registers a new instance of host driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if d.network != "" {
|
||||
return types.ForbiddenErrorf("only one instance of \"%s\" network is allowed", networkType)
|
||||
}
|
||||
|
||||
d.network = id
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
|
||||
func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
||||
func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
50
vendor/github.com/docker/libnetwork/drivers/host/host_test.go
generated
vendored
Normal file
50
vendor/github.com/docker/libnetwork/drivers/host/host_test.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func TestDriver(t *testing.T) {
|
||||
d := &driver{}
|
||||
|
||||
if d.Type() != networkType {
|
||||
t.Fatalf("Unexpected network type returned by driver")
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("first", nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if d.network != "first" {
|
||||
t.Fatalf("Unexpected network id stored")
|
||||
}
|
||||
|
||||
err = d.CreateNetwork("second", nil, nil, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Second network creation should fail on this driver")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Second network creation failed with unexpected error type")
|
||||
}
|
||||
|
||||
err = d.DeleteNetwork("first")
|
||||
if err == nil {
|
||||
t.Fatalf("network deletion should fail on this driver")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("network deletion failed with unexpected error type")
|
||||
}
|
||||
|
||||
// we don't really check if it is there or not, delete is not allowed for this driver, period.
|
||||
err = d.DeleteNetwork("unknown")
|
||||
if err == nil {
|
||||
t.Fatalf("any network deletion should fail on this driver")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("any network deletion failed with unexpected error type")
|
||||
}
|
||||
}
|
||||
77
vendor/github.com/docker/libnetwork/drivers/null/null.go
generated
vendored
Normal file
77
vendor/github.com/docker/libnetwork/drivers/null/null.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package null
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const networkType = "null"
|
||||
|
||||
type driver struct {
|
||||
network string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// Init registers a new instance of null driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if d.network != "" {
|
||||
return types.ForbiddenErrorf("only one instance of \"%s\" network is allowed", networkType)
|
||||
}
|
||||
|
||||
d.network = id
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
|
||||
func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
||||
func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
50
vendor/github.com/docker/libnetwork/drivers/null/null_test.go
generated
vendored
Normal file
50
vendor/github.com/docker/libnetwork/drivers/null/null_test.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package null
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func TestDriver(t *testing.T) {
|
||||
d := &driver{}
|
||||
|
||||
if d.Type() != networkType {
|
||||
t.Fatalf("Unexpected network type returned by driver")
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("first", nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if d.network != "first" {
|
||||
t.Fatalf("Unexpected network id stored")
|
||||
}
|
||||
|
||||
err = d.CreateNetwork("second", nil, nil, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Second network creation should fail on this driver")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Second network creation failed with unexpected error type")
|
||||
}
|
||||
|
||||
err = d.DeleteNetwork("first")
|
||||
if err == nil {
|
||||
t.Fatalf("network deletion should fail on this driver")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("network deletion failed with unexpected error type")
|
||||
}
|
||||
|
||||
// we don't really check if it is there or not, delete is not allowed for this driver, period.
|
||||
err = d.DeleteNetwork("unknown")
|
||||
if err == nil {
|
||||
t.Fatalf("any network deletion should fail on this driver")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("any network deletion failed with unexpected error type")
|
||||
}
|
||||
}
|
||||
123
vendor/github.com/docker/libnetwork/drivers/overlay/filter.go
generated
vendored
Normal file
123
vendor/github.com/docker/libnetwork/drivers/overlay/filter.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
)
|
||||
|
||||
const globalChain = "DOCKER-OVERLAY"
|
||||
|
||||
var filterOnce sync.Once
|
||||
|
||||
func chainExists(cname string) bool {
|
||||
if _, err := iptables.Raw("-L", cname); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func setupGlobalChain() {
|
||||
if err := iptables.RawCombinedOutput("-N", globalChain); err != nil {
|
||||
logrus.Errorf("could not create global overlay chain: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := iptables.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil {
|
||||
logrus.Errorf("could not install default return chain in the overlay global chain: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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 := iptables.RawCombinedOutput("-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 := iptables.RawCombinedOutput(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 := iptables.RawCombinedOutput("-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 := iptables.RawCombinedOutput("-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 := iptables.RawCombinedOutput("-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 := iptables.RawCombinedOutput(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 := iptables.RawCombinedOutput(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)
|
||||
}
|
||||
149
vendor/github.com/docker/libnetwork/drivers/overlay/joinleave.go
generated
vendored
Normal file
149
vendor/github.com/docker/libnetwork/drivers/overlay/joinleave.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return fmt.Errorf("could not find network with id %s", nid)
|
||||
}
|
||||
|
||||
ep := n.endpoint(eid)
|
||||
if ep == nil {
|
||||
return fmt.Errorf("could not find endpoint with id %s", eid)
|
||||
}
|
||||
|
||||
s := n.getSubnetforIP(ep.addr)
|
||||
if s == nil {
|
||||
return fmt.Errorf("could not find subnet for endpoint %s", eid)
|
||||
}
|
||||
|
||||
if err := n.obtainVxlanID(s); err != nil {
|
||||
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
if err := n.joinSandbox(); err != nil {
|
||||
return fmt.Errorf("network sandbox join failed: %v", err)
|
||||
}
|
||||
|
||||
if err := n.joinSubnetSandbox(s); err != nil {
|
||||
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
// joinSubnetSandbox gets called when an endpoint comes up on a new subnet in the
|
||||
// overlay network. Hence the Endpoint count should be updated outside joinSubnetSandbox
|
||||
n.incEndpointCount()
|
||||
|
||||
sbox := n.sandbox()
|
||||
|
||||
name1, name2, err := createVethPair()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ep.ifName = name2
|
||||
|
||||
// Set the container interface and its peer MTU to 1450 to allow
|
||||
// for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) +
|
||||
// outer UDP(8) + vxlan header(8))
|
||||
veth, err := netlink.LinkByName(name1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cound not find link by name %s: %v", name1, err)
|
||||
}
|
||||
err = netlink.LinkSetMTU(veth, vxlanVethMTU)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sbox.AddInterface(name1, "veth",
|
||||
sbox.InterfaceOptions().Master(s.brName)); err != nil {
|
||||
return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err)
|
||||
}
|
||||
|
||||
veth, err = netlink.LinkByName(name2)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find link by name %s: %v", name2, err)
|
||||
}
|
||||
err = netlink.LinkSetMTU(veth, vxlanVethMTU)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := netlink.LinkSetHardwareAddr(veth, ep.mac); err != nil {
|
||||
return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err)
|
||||
}
|
||||
|
||||
for _, sub := range n.subnets {
|
||||
if sub == s {
|
||||
continue
|
||||
}
|
||||
if err := jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil {
|
||||
log.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id)
|
||||
}
|
||||
}
|
||||
|
||||
if iNames := jinfo.InterfaceName(); iNames != nil {
|
||||
err = iNames.SetNames(name2, "eth")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.peerDbAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac,
|
||||
net.ParseIP(d.bindAddress), true)
|
||||
d.pushLocalEndpointEvent("join", nid, eid)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return fmt.Errorf("could not find network with id %s", nid)
|
||||
}
|
||||
|
||||
ep := n.endpoint(eid)
|
||||
|
||||
if ep == nil {
|
||||
return types.InternalMaskableErrorf("could not find endpoint with id %s", eid)
|
||||
}
|
||||
|
||||
if d.notifyCh != nil {
|
||||
d.notifyCh <- ovNotify{
|
||||
action: "leave",
|
||||
nid: nid,
|
||||
eid: eid,
|
||||
}
|
||||
}
|
||||
|
||||
n.leaveSandbox()
|
||||
|
||||
link, err := netlink.LinkByName(ep.ifName)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to retrieve interface link for interface removal on endpoint leave: %v", err)
|
||||
return nil
|
||||
}
|
||||
if err := netlink.LinkDel(link); err != nil {
|
||||
log.Warnf("Failed to delete interface link on endpoint leave: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
105
vendor/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go
generated
vendored
Normal file
105
vendor/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
type endpointTable map[string]*endpoint
|
||||
|
||||
type endpoint struct {
|
||||
id string
|
||||
ifName string
|
||||
mac net.HardwareAddr
|
||||
addr *net.IPNet
|
||||
}
|
||||
|
||||
func (n *network) endpoint(eid string) *endpoint {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.endpoints[eid]
|
||||
}
|
||||
|
||||
func (n *network) addEndpoint(ep *endpoint) {
|
||||
n.Lock()
|
||||
n.endpoints[ep.id] = ep
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (n *network) deleteEndpoint(eid string) {
|
||||
n.Lock()
|
||||
delete(n.endpoints, eid)
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
|
||||
epOptions map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
if err = validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since we perform lazy configuration make sure we try
|
||||
// configuring the driver when we enter CreateEndpoint since
|
||||
// CreateNetwork may not be called in every node.
|
||||
if err := d.configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return fmt.Errorf("network id %q not found", nid)
|
||||
}
|
||||
|
||||
ep := &endpoint{
|
||||
id: eid,
|
||||
addr: ifInfo.Address(),
|
||||
mac: ifInfo.MacAddress(),
|
||||
}
|
||||
if ep.addr == nil {
|
||||
return fmt.Errorf("create endpoint was not passed interface IP address")
|
||||
}
|
||||
|
||||
if s := n.getSubnetforIP(ep.addr); s == nil {
|
||||
return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid)
|
||||
}
|
||||
|
||||
if ep.mac == nil {
|
||||
ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
|
||||
if err := ifInfo.SetMacAddress(ep.mac); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
n.addEndpoint(ep)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return fmt.Errorf("network id %q not found", nid)
|
||||
}
|
||||
|
||||
ep := n.endpoint(eid)
|
||||
if ep == nil {
|
||||
return fmt.Errorf("endpoint id %q not found", eid)
|
||||
}
|
||||
|
||||
n.deleteEndpoint(eid)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
633
vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go
generated
vendored
Normal file
633
vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go
generated
vendored
Normal file
@@ -0,0 +1,633 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"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 {
|
||||
once *sync.Once
|
||||
vxlanName string
|
||||
brName string
|
||||
vni uint32
|
||||
initErr error
|
||||
subnetIP *net.IPNet
|
||||
gwIP *net.IPNet
|
||||
}
|
||||
|
||||
type subnetJSON struct {
|
||||
SubnetIP string
|
||||
GwIP string
|
||||
Vni uint32
|
||||
}
|
||||
|
||||
type network struct {
|
||||
id string
|
||||
dbIndex uint64
|
||||
dbExists bool
|
||||
sbox osl.Sandbox
|
||||
endpoints endpointTable
|
||||
driver *driver
|
||||
joinCnt int
|
||||
once *sync.Once
|
||||
initEpoch int
|
||||
initErr error
|
||||
subnets []*subnet
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
}
|
||||
|
||||
// Since we perform lazy configuration make sure we try
|
||||
// configuring the driver when we enter CreateNetwork
|
||||
if err := d.configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := &network{
|
||||
id: id,
|
||||
driver: d,
|
||||
endpoints: endpointTable{},
|
||||
once: &sync.Once{},
|
||||
subnets: []*subnet{},
|
||||
}
|
||||
|
||||
for _, ipd := range ipV4Data {
|
||||
s := &subnet{
|
||||
subnetIP: ipd.Pool,
|
||||
gwIP: ipd.Gateway,
|
||||
once: &sync.Once{},
|
||||
}
|
||||
n.subnets = append(n.subnets, s)
|
||||
}
|
||||
|
||||
if err := n.writeToStore(); err != nil {
|
||||
return fmt.Errorf("failed to update data store for network %v: %v", n.id, err)
|
||||
}
|
||||
|
||||
d.addNetwork(n)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
if nid == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return fmt.Errorf("could not find network with id %s", nid)
|
||||
}
|
||||
|
||||
d.deleteNetwork(nid)
|
||||
|
||||
return n.releaseVxlanID()
|
||||
}
|
||||
|
||||
func (n *network) incEndpointCount() {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
n.joinCnt++
|
||||
}
|
||||
|
||||
func (n *network) joinSandbox() error {
|
||||
// If there is a race between two go routines here only one will win
|
||||
// the other will wait.
|
||||
n.once.Do(func() {
|
||||
// save the error status of initSandbox in n.initErr so that
|
||||
// all the racing go routines are able to know the status.
|
||||
n.initErr = n.initSandbox()
|
||||
})
|
||||
|
||||
return n.initErr
|
||||
}
|
||||
|
||||
func (n *network) joinSubnetSandbox(s *subnet) error {
|
||||
s.once.Do(func() {
|
||||
s.initErr = n.initSubnetSandbox(s)
|
||||
})
|
||||
return s.initErr
|
||||
}
|
||||
|
||||
func (n *network) leaveSandbox() {
|
||||
n.Lock()
|
||||
n.joinCnt--
|
||||
if n.joinCnt != 0 {
|
||||
n.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// We are about to destroy sandbox since the container is leaving the network
|
||||
// Reinitialize the once variable so that we will be able to trigger one time
|
||||
// sandbox initialization(again) when another container joins subsequently.
|
||||
n.once = &sync.Once{}
|
||||
for _, s := range n.subnets {
|
||||
s.once = &sync.Once{}
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
n.destroySandbox()
|
||||
}
|
||||
|
||||
func (n *network) destroySandbox() {
|
||||
sbox := n.sandbox()
|
||||
if sbox != nil {
|
||||
for _, iface := range sbox.Info().Interfaces() {
|
||||
iface.Remove()
|
||||
}
|
||||
|
||||
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 := 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 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",
|
||||
sbox.InterfaceOptions().Address(s.gwIP),
|
||||
sbox.InterfaceOptions().Bridge(true)); err != nil {
|
||||
return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
err := createVxlan(vxlanName, n.vxlanID(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sbox.AddInterface(vxlanName, "vxlan",
|
||||
sbox.InterfaceOptions().Master(brName)); err != nil {
|
||||
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
|
||||
n.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *network) initSandbox() error {
|
||||
n.Lock()
|
||||
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), !hostMode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create network sandbox: %v", err)
|
||||
}
|
||||
|
||||
n.setSandbox(sbox)
|
||||
|
||||
n.driver.peerDbUpdateSandbox(n.id)
|
||||
|
||||
var nlSock *nl.NetlinkSocket
|
||||
sbox.InvokeFunc(func() {
|
||||
nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to subscribe to neighbor group netlink messages")
|
||||
}
|
||||
})
|
||||
|
||||
go n.watchMiss(nlSock)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
|
||||
for {
|
||||
msgs, err := nlSock.Receive()
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to receive from netlink: %v ", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
if msg.Header.Type != syscall.RTM_GETNEIGH && msg.Header.Type != syscall.RTM_NEWNEIGH {
|
||||
continue
|
||||
}
|
||||
|
||||
neigh, err := netlink.NeighDeserialize(msg.Data)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to deserialize netlink ndmsg: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if neigh.IP.To16() != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if neigh.State&(netlink.NUD_STALE|netlink.NUD_INCOMPLETE) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
mac, IPmask, vtep, err := n.driver.resolvePeer(n.id, neigh.IP)
|
||||
if err != nil {
|
||||
logrus.Errorf("could not resolve peer %q: %v", neigh.IP, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, IPmask, mac, vtep, true); err != nil {
|
||||
logrus.Errorf("could not add neighbor entry for missed peer %q: %v", neigh.IP, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
networks := d.networks
|
||||
d.Unlock()
|
||||
|
||||
n, ok := networks[nid]
|
||||
if !ok {
|
||||
n = d.getNetworkFromStore(nid)
|
||||
if n != nil {
|
||||
n.driver = d
|
||||
n.endpoints = endpointTable{}
|
||||
n.once = &sync.Once{}
|
||||
networks[nid] = n
|
||||
}
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (d *driver) getNetworkFromStore(nid string) *network {
|
||||
if d.store == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := &network{id: nid}
|
||||
if err := d.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *network) sandbox() osl.Sandbox {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.sbox
|
||||
}
|
||||
|
||||
func (n *network) setSandbox(sbox osl.Sandbox) {
|
||||
n.Lock()
|
||||
n.sbox = sbox
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (n *network) vxlanID(s *subnet) uint32 {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return s.vni
|
||||
}
|
||||
|
||||
func (n *network) setVxlanID(s *subnet, vni uint32) {
|
||||
n.Lock()
|
||||
s.vni = vni
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (n *network) Key() []string {
|
||||
return []string{"overlay", "network", n.id}
|
||||
}
|
||||
|
||||
func (n *network) KeyPrefix() []string {
|
||||
return []string{"overlay", "network"}
|
||||
}
|
||||
|
||||
func (n *network) Value() []byte {
|
||||
netJSON := []*subnetJSON{}
|
||||
|
||||
for _, s := range n.subnets {
|
||||
sj := &subnetJSON{
|
||||
SubnetIP: s.subnetIP.String(),
|
||||
GwIP: s.gwIP.String(),
|
||||
Vni: s.vni,
|
||||
}
|
||||
netJSON = append(netJSON, sj)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(netJSON)
|
||||
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (n *network) Index() uint64 {
|
||||
return n.dbIndex
|
||||
}
|
||||
|
||||
func (n *network) SetIndex(index uint64) {
|
||||
n.dbIndex = index
|
||||
n.dbExists = true
|
||||
}
|
||||
|
||||
func (n *network) Exists() bool {
|
||||
return n.dbExists
|
||||
}
|
||||
|
||||
func (n *network) Skip() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *network) SetValue(value []byte) error {
|
||||
var newNet bool
|
||||
netJSON := []*subnetJSON{}
|
||||
|
||||
err := json.Unmarshal(value, &netJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(n.subnets) == 0 {
|
||||
newNet = true
|
||||
}
|
||||
|
||||
for _, sj := range netJSON {
|
||||
subnetIPstr := sj.SubnetIP
|
||||
gwIPstr := sj.GwIP
|
||||
vni := sj.Vni
|
||||
|
||||
subnetIP, _ := types.ParseCIDR(subnetIPstr)
|
||||
gwIP, _ := types.ParseCIDR(gwIPstr)
|
||||
|
||||
if newNet {
|
||||
s := &subnet{
|
||||
subnetIP: subnetIP,
|
||||
gwIP: gwIP,
|
||||
vni: vni,
|
||||
once: &sync.Once{},
|
||||
}
|
||||
n.subnets = append(n.subnets, s)
|
||||
} else {
|
||||
sNet := n.getMatchingSubnet(subnetIP)
|
||||
if sNet != nil {
|
||||
sNet.vni = vni
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *network) DataScope() string {
|
||||
return datastore.GlobalScope
|
||||
}
|
||||
|
||||
func (n *network) writeToStore() error {
|
||||
return n.driver.store.PutObjectAtomic(n)
|
||||
}
|
||||
|
||||
func (n *network) releaseVxlanID() error {
|
||||
if n.driver.store == nil {
|
||||
return fmt.Errorf("no datastore configured. cannot release vxlan id")
|
||||
}
|
||||
|
||||
if len(n.subnets) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := n.driver.store.DeleteObjectAtomic(n); err != nil {
|
||||
if err == datastore.ErrKeyModified || err == datastore.ErrKeyNotFound {
|
||||
// In both the above cases we can safely assume that the key has been removed by some other
|
||||
// instance and so simply get out of here
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to delete network to vxlan id map: %v", err)
|
||||
}
|
||||
|
||||
for _, s := range n.subnets {
|
||||
n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
|
||||
n.setVxlanID(s, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *network) obtainVxlanID(s *subnet) error {
|
||||
//return if the subnet already has a vxlan id assigned
|
||||
if s.vni != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if n.driver.store == nil {
|
||||
return fmt.Errorf("no datastore configured. cannot obtain vxlan id")
|
||||
}
|
||||
|
||||
for {
|
||||
if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
|
||||
return fmt.Errorf("getting network %q from datastore failed %v", n.id, err)
|
||||
}
|
||||
|
||||
if s.vni == 0 {
|
||||
vxlanID, err := n.driver.vxlanIdm.GetID()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to allocate vxlan id: %v", err)
|
||||
}
|
||||
|
||||
n.setVxlanID(s, uint32(vxlanID))
|
||||
if err := n.writeToStore(); err != nil {
|
||||
n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
|
||||
n.setVxlanID(s, 0)
|
||||
if err == datastore.ErrKeyModified {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("network %q failed to update data store: %v", n.id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
234
vendor/github.com/docker/libnetwork/drivers/overlay/ov_serf.go
generated
vendored
Normal file
234
vendor/github.com/docker/libnetwork/drivers/overlay/ov_serf.go
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
)
|
||||
|
||||
type ovNotify struct {
|
||||
action string
|
||||
eid string
|
||||
nid string
|
||||
}
|
||||
|
||||
type logWriter struct{}
|
||||
|
||||
func (l *logWriter) Write(p []byte) (int, error) {
|
||||
str := string(p)
|
||||
|
||||
switch {
|
||||
case strings.Contains(str, "[WARN]"):
|
||||
logrus.Warn(str)
|
||||
case strings.Contains(str, "[DEBUG]"):
|
||||
logrus.Debug(str)
|
||||
case strings.Contains(str, "[INFO]"):
|
||||
logrus.Info(str)
|
||||
case strings.Contains(str, "[ERR]"):
|
||||
logrus.Error(str)
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *driver) serfInit() error {
|
||||
var err error
|
||||
|
||||
config := serf.DefaultConfig()
|
||||
config.Init()
|
||||
config.MemberlistConfig.BindAddr = d.bindAddress
|
||||
|
||||
d.eventCh = make(chan serf.Event, 4)
|
||||
config.EventCh = d.eventCh
|
||||
config.UserCoalescePeriod = 1 * time.Second
|
||||
config.UserQuiescentPeriod = 50 * time.Millisecond
|
||||
|
||||
config.LogOutput = &logWriter{}
|
||||
config.MemberlistConfig.LogOutput = config.LogOutput
|
||||
|
||||
s, err := serf.Create(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create cluster node: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
s.Shutdown()
|
||||
}
|
||||
}()
|
||||
|
||||
d.serfInstance = s
|
||||
|
||||
d.notifyCh = make(chan ovNotify)
|
||||
d.exitCh = make(chan chan struct{})
|
||||
|
||||
go d.startSerfLoop(d.eventCh, d.notifyCh, d.exitCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) serfJoin(neighIP string) error {
|
||||
if neighIP == "" {
|
||||
return fmt.Errorf("no neighbor to join")
|
||||
}
|
||||
if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil {
|
||||
return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v",
|
||||
neighIP, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) notifyEvent(event ovNotify) {
|
||||
n := d.network(event.nid)
|
||||
ep := n.endpoint(event.eid)
|
||||
|
||||
ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(),
|
||||
net.IP(ep.addr.Mask).String(), ep.mac.String())
|
||||
eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(),
|
||||
event.nid, event.eid)
|
||||
|
||||
if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil {
|
||||
logrus.Errorf("Sending user event failed: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) processEvent(u serf.UserEvent) {
|
||||
logrus.Debugf("Received user event name:%s, payload:%s\n", u.Name,
|
||||
string(u.Payload))
|
||||
|
||||
var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string
|
||||
if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil {
|
||||
fmt.Printf("Failed to scan name string: %v\n", err)
|
||||
}
|
||||
|
||||
if _, err := fmt.Sscan(string(u.Payload), &action,
|
||||
&ipStr, &maskStr, &macStr); err != nil {
|
||||
fmt.Printf("Failed to scan value string: %v\n", err)
|
||||
}
|
||||
|
||||
logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr)
|
||||
|
||||
mac, err := net.ParseMAC(macStr)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to parse mac: %v\n", err)
|
||||
}
|
||||
|
||||
if d.serfInstance.LocalMember().Addr.String() == vtepStr {
|
||||
return
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "join":
|
||||
if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
|
||||
net.ParseIP(vtepStr), true); err != nil {
|
||||
logrus.Errorf("Peer add failed in the driver: %v\n", err)
|
||||
}
|
||||
case "leave":
|
||||
if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
|
||||
net.ParseIP(vtepStr), true); err != nil {
|
||||
logrus.Errorf("Peer delete failed in the driver: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) processQuery(q *serf.Query) {
|
||||
logrus.Debugf("Received query name:%s, payload:%s\n", q.Name,
|
||||
string(q.Payload))
|
||||
|
||||
var nid, ipStr string
|
||||
if _, err := fmt.Sscan(string(q.Payload), &nid, &ipStr); err != nil {
|
||||
fmt.Printf("Failed to scan query payload string: %v\n", err)
|
||||
}
|
||||
|
||||
peerMac, peerIPMask, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
q.Respond([]byte(fmt.Sprintf("%s %s %s", peerMac.String(), net.IP(peerIPMask).String(), vtep.String())))
|
||||
}
|
||||
|
||||
func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
|
||||
if d.serfInstance == nil {
|
||||
return nil, nil, nil, fmt.Errorf("could not resolve peer: serf instance not initialized")
|
||||
}
|
||||
|
||||
qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
|
||||
resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
|
||||
}
|
||||
|
||||
respCh := resp.ResponseCh()
|
||||
select {
|
||||
case r := <-respCh:
|
||||
var macStr, maskStr, vtepStr string
|
||||
if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
|
||||
}
|
||||
|
||||
mac, err := net.ParseMAC(macStr)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err)
|
||||
}
|
||||
|
||||
return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil
|
||||
|
||||
case <-time.After(time.Second):
|
||||
return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify,
|
||||
exitCh chan chan struct{}) {
|
||||
|
||||
for {
|
||||
select {
|
||||
case notify, ok := <-notifyCh:
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
d.notifyEvent(notify)
|
||||
case ch, ok := <-exitCh:
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if err := d.serfInstance.Leave(); err != nil {
|
||||
logrus.Errorf("failed leaving the cluster: %v\n", err)
|
||||
}
|
||||
|
||||
d.serfInstance.Shutdown()
|
||||
close(ch)
|
||||
return
|
||||
case e, ok := <-eventCh:
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if e.EventType() == serf.EventQuery {
|
||||
d.processQuery(e.(*serf.Query))
|
||||
break
|
||||
}
|
||||
|
||||
u, ok := e.(serf.UserEvent)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
d.processEvent(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) isSerfAlive() bool {
|
||||
d.Lock()
|
||||
serfInstance := d.serfInstance
|
||||
d.Unlock()
|
||||
if serfInstance == nil || serfInstance.State() != serf.SerfAlive {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
105
vendor/github.com/docker/libnetwork/drivers/overlay/ov_utils.go
generated
vendored
Normal file
105
vendor/github.com/docker/libnetwork/drivers/overlay/ov_utils.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
func validateID(nid, eid string) error {
|
||||
if nid == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
}
|
||||
|
||||
if eid == "" {
|
||||
return fmt.Errorf("invalid endpoint id")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createVethPair() (string, string, error) {
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
// Generate a name for what will be the host side pipe interface
|
||||
name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("error generating veth name1: %v", err)
|
||||
}
|
||||
|
||||
// Generate a name for what will be the sandbox side pipe interface
|
||||
name2, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("error generating veth name2: %v", err)
|
||||
}
|
||||
|
||||
// Generate and add the interface pipe host <-> sandbox
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
||||
PeerName: name2}
|
||||
if err := netlink.LinkAdd(veth); err != nil {
|
||||
return "", "", fmt.Errorf("error creating veth pair: %v", err)
|
||||
}
|
||||
|
||||
return name1, name2, nil
|
||||
}
|
||||
|
||||
func createVxlan(name string, vni uint32) error {
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
vxlan := &netlink.Vxlan{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: name},
|
||||
VxlanId: int(vni),
|
||||
Learning: true,
|
||||
Port: int(nl.Swap16(vxlanPort)), //network endian order
|
||||
Proxy: true,
|
||||
L3miss: true,
|
||||
L2miss: true,
|
||||
}
|
||||
|
||||
if err := netlink.LinkAdd(vxlan); err != nil {
|
||||
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)
|
||||
}
|
||||
209
vendor/github.com/docker/libnetwork/drivers/overlay/overlay.go
generated
vendored
Normal file
209
vendor/github.com/docker/libnetwork/drivers/overlay/overlay.go
generated
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libkv/store"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/idm"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
)
|
||||
|
||||
const (
|
||||
networkType = "overlay"
|
||||
vethPrefix = "veth"
|
||||
vethLen = 7
|
||||
vxlanIDStart = 256
|
||||
vxlanIDEnd = 1000
|
||||
vxlanPort = 4789
|
||||
vxlanVethMTU = 1450
|
||||
)
|
||||
|
||||
type driver struct {
|
||||
eventCh chan serf.Event
|
||||
notifyCh chan ovNotify
|
||||
exitCh chan chan struct{}
|
||||
bindAddress string
|
||||
neighIP string
|
||||
config map[string]interface{}
|
||||
peerDb peerNetworkMap
|
||||
serfInstance *serf.Serf
|
||||
networks networkTable
|
||||
store datastore.DataStore
|
||||
ipAllocator *idm.Idm
|
||||
vxlanIdm *idm.Idm
|
||||
once sync.Once
|
||||
joinOnce sync.Once
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// Init registers a new instance of overlay driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.GlobalScope,
|
||||
}
|
||||
|
||||
d := &driver{
|
||||
networks: networkTable{},
|
||||
peerDb: peerNetworkMap{
|
||||
mp: map[string]*peerMap{},
|
||||
},
|
||||
config: config,
|
||||
}
|
||||
|
||||
return dc.RegisterDriver(networkType, d, c)
|
||||
}
|
||||
|
||||
// Fini cleans up the driver resources
|
||||
func Fini(drv driverapi.Driver) {
|
||||
d := drv.(*driver)
|
||||
|
||||
if d.exitCh != nil {
|
||||
waitCh := make(chan struct{})
|
||||
|
||||
d.exitCh <- waitCh
|
||||
|
||||
<-waitCh
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) configure() error {
|
||||
var err error
|
||||
|
||||
if len(d.config) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
d.once.Do(func() {
|
||||
provider, provOk := d.config[netlabel.GlobalKVProvider]
|
||||
provURL, urlOk := d.config[netlabel.GlobalKVProviderURL]
|
||||
|
||||
if provOk && urlOk {
|
||||
cfg := &datastore.ScopeCfg{
|
||||
Client: datastore.ScopeClientCfg{
|
||||
Provider: provider.(string),
|
||||
Address: provURL.(string),
|
||||
},
|
||||
}
|
||||
provConfig, confOk := d.config[netlabel.GlobalKVProviderConfig]
|
||||
if confOk {
|
||||
cfg.Client.Config = provConfig.(*store.Config)
|
||||
}
|
||||
d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to initialize data store: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to initialize vxlan id manager: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
d.ipAllocator, err = idm.New(d.store, "ipam-id", 1, 0xFFFF-2)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to initalize ipam id manager: %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
func validateSelf(node string) error {
|
||||
advIP := net.ParseIP(node)
|
||||
if advIP == nil {
|
||||
return fmt.Errorf("invalid self address (%s)", node)
|
||||
}
|
||||
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to get interface addresses %v", err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
ip, _, err := net.ParseCIDR(addr.String())
|
||||
if err == nil && ip.Equal(advIP) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Multi-Host overlay networking requires cluster-advertise(%s) to be configured with a local ip-address that is reachable within the cluster", advIP.String())
|
||||
}
|
||||
|
||||
func (d *driver) nodeJoin(node string, self bool) {
|
||||
if self && !d.isSerfAlive() {
|
||||
if err := validateSelf(node); err != nil {
|
||||
logrus.Errorf("%s", err.Error())
|
||||
}
|
||||
d.Lock()
|
||||
d.bindAddress = node
|
||||
d.Unlock()
|
||||
err := d.serfInit()
|
||||
if err != nil {
|
||||
logrus.Errorf("initializing serf instance failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
d.Lock()
|
||||
if !self {
|
||||
d.neighIP = node
|
||||
}
|
||||
neighIP := d.neighIP
|
||||
d.Unlock()
|
||||
|
||||
if d.serfInstance != nil && neighIP != "" {
|
||||
var err error
|
||||
d.joinOnce.Do(func() {
|
||||
err = d.serfJoin(neighIP)
|
||||
if err == nil {
|
||||
d.pushLocalDb()
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Errorf("joining serf neighbor %s failed: %v", node, err)
|
||||
d.Lock()
|
||||
d.joinOnce = sync.Once{}
|
||||
d.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
|
||||
if !d.isSerfAlive() {
|
||||
return
|
||||
}
|
||||
d.notifyCh <- ovNotify{
|
||||
action: "join",
|
||||
nid: nid,
|
||||
eid: eid,
|
||||
}
|
||||
}
|
||||
|
||||
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
|
||||
func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
if dType == driverapi.NodeDiscovery {
|
||||
nodeData, ok := data.(driverapi.NodeDiscoveryData)
|
||||
if !ok || nodeData.Address == "" {
|
||||
return fmt.Errorf("invalid discovery data")
|
||||
}
|
||||
d.nodeJoin(nodeData.Address, nodeData.Self)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
||||
func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
134
vendor/github.com/docker/libnetwork/drivers/overlay/overlay_test.go
generated
vendored
Normal file
134
vendor/github.com/docker/libnetwork/drivers/overlay/overlay_test.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
_ "github.com/docker/libnetwork/testutils"
|
||||
)
|
||||
|
||||
type driverTester struct {
|
||||
t *testing.T
|
||||
d *driver
|
||||
}
|
||||
|
||||
const testNetworkType = "overlay"
|
||||
|
||||
func setupDriver(t *testing.T) *driverTester {
|
||||
dt := &driverTester{t: t}
|
||||
if err := Init(dt, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := dt.d.configure(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName("eth0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil || len(addrs) == 0 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data := driverapi.NodeDiscoveryData{
|
||||
Address: addrs[0].String(),
|
||||
Self: true,
|
||||
}
|
||||
dt.d.DiscoverNew(driverapi.NodeDiscovery, data)
|
||||
return dt
|
||||
}
|
||||
|
||||
func cleanupDriver(t *testing.T, dt *driverTester) {
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
Fini(dt.d)
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("test timed out because Fini() did not return on time")
|
||||
}
|
||||
}
|
||||
|
||||
func (dt *driverTester) RegisterDriver(name string, drv driverapi.Driver,
|
||||
cap driverapi.Capability) error {
|
||||
if name != testNetworkType {
|
||||
dt.t.Fatalf("Expected driver register name to be %q. Instead got %q",
|
||||
testNetworkType, name)
|
||||
}
|
||||
|
||||
if _, ok := drv.(*driver); !ok {
|
||||
dt.t.Fatalf("Expected driver type to be %T. Instead got %T",
|
||||
&driver{}, drv)
|
||||
}
|
||||
|
||||
dt.d = drv.(*driver)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestOverlayInit(t *testing.T) {
|
||||
if err := Init(&driverTester{t: t}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlayFiniWithoutConfig(t *testing.T) {
|
||||
dt := &driverTester{t: t}
|
||||
if err := Init(dt, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cleanupDriver(t, dt)
|
||||
}
|
||||
|
||||
func TestOverlayNilConfig(t *testing.T) {
|
||||
dt := &driverTester{t: t}
|
||||
if err := Init(dt, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := dt.d.configure(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cleanupDriver(t, dt)
|
||||
}
|
||||
|
||||
func TestOverlayConfig(t *testing.T) {
|
||||
dt := setupDriver(t)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
d := dt.d
|
||||
if d.notifyCh == nil {
|
||||
t.Fatal("Driver notify channel wasn't initialzed after Config method")
|
||||
}
|
||||
|
||||
if d.exitCh == nil {
|
||||
t.Fatal("Driver serfloop exit channel wasn't initialzed after Config method")
|
||||
}
|
||||
|
||||
if d.serfInstance == nil {
|
||||
t.Fatal("Driver serfinstance hasn't been initialized after Config method")
|
||||
}
|
||||
|
||||
cleanupDriver(t, dt)
|
||||
}
|
||||
|
||||
func TestOverlayType(t *testing.T) {
|
||||
dt := &driverTester{t: t}
|
||||
if err := Init(dt, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if dt.d.Type() != testNetworkType {
|
||||
t.Fatalf("Expected Type() to return %q. Instead got %q", testNetworkType,
|
||||
dt.d.Type())
|
||||
}
|
||||
}
|
||||
329
vendor/github.com/docker/libnetwork/drivers/overlay/peerdb.go
generated
vendored
Normal file
329
vendor/github.com/docker/libnetwork/drivers/overlay/peerdb.go
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type peerKey struct {
|
||||
peerIP net.IP
|
||||
peerMac net.HardwareAddr
|
||||
}
|
||||
|
||||
type peerEntry struct {
|
||||
eid string
|
||||
vtep net.IP
|
||||
peerIPMask net.IPMask
|
||||
inSandbox bool
|
||||
isLocal bool
|
||||
}
|
||||
|
||||
type peerMap struct {
|
||||
mp map[string]peerEntry
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type peerNetworkMap struct {
|
||||
mp map[string]*peerMap
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (pKey peerKey) String() string {
|
||||
return fmt.Sprintf("%s %s", pKey.peerIP, pKey.peerMac)
|
||||
}
|
||||
|
||||
func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
|
||||
ipB, err := state.Token(true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pKey.peerIP = net.ParseIP(string(ipB))
|
||||
|
||||
macB, err := state.Token(true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pKey.peerMac, err = net.ParseMAC(string(macB))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var peerDbWg sync.WaitGroup
|
||||
|
||||
func (d *driver) peerDbWalk(f func(string, *peerKey, *peerEntry) bool) error {
|
||||
d.peerDb.Lock()
|
||||
nids := []string{}
|
||||
for nid := range d.peerDb.mp {
|
||||
nids = append(nids, nid)
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
for _, nid := range nids {
|
||||
d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
||||
return f(nid, pKey, pEntry)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool) error {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
d.peerDb.Unlock()
|
||||
return nil
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
pMap.Lock()
|
||||
for pKeyStr, pEntry := range pMap.mp {
|
||||
var pKey peerKey
|
||||
if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil {
|
||||
fmt.Printf("peer key scan failed: %v", err)
|
||||
}
|
||||
|
||||
if f(&pKey, &pEntry) {
|
||||
pMap.Unlock()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
pMap.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
|
||||
var (
|
||||
peerMac net.HardwareAddr
|
||||
vtep net.IP
|
||||
peerIPMask net.IPMask
|
||||
found bool
|
||||
)
|
||||
|
||||
err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
||||
if pKey.peerIP.Equal(peerIP) {
|
||||
peerMac = pKey.peerMac
|
||||
peerIPMask = pEntry.peerIPMask
|
||||
vtep = pEntry.vtep
|
||||
found = true
|
||||
return found
|
||||
}
|
||||
|
||||
return found
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
|
||||
}
|
||||
|
||||
return peerMac, peerIPMask, vtep, nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
|
||||
peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
|
||||
|
||||
peerDbWg.Wait()
|
||||
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
d.peerDb.mp[nid] = &peerMap{
|
||||
mp: make(map[string]peerEntry),
|
||||
}
|
||||
|
||||
pMap = d.peerDb.mp[nid]
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
pKey := peerKey{
|
||||
peerIP: peerIP,
|
||||
peerMac: peerMac,
|
||||
}
|
||||
|
||||
pEntry := peerEntry{
|
||||
eid: eid,
|
||||
vtep: vtep,
|
||||
peerIPMask: peerIPMask,
|
||||
isLocal: isLocal,
|
||||
}
|
||||
|
||||
pMap.Lock()
|
||||
pMap.mp[pKey.String()] = pEntry
|
||||
pMap.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
|
||||
peerMac net.HardwareAddr, vtep net.IP) {
|
||||
peerDbWg.Wait()
|
||||
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
d.peerDb.Unlock()
|
||||
return
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
pKey := peerKey{
|
||||
peerIP: peerIP,
|
||||
peerMac: peerMac,
|
||||
}
|
||||
|
||||
pMap.Lock()
|
||||
delete(pMap.mp, pKey.String())
|
||||
pMap.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) peerDbUpdateSandbox(nid string) {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
d.peerDb.Unlock()
|
||||
return
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
peerDbWg.Add(1)
|
||||
|
||||
var peerOps []func()
|
||||
pMap.Lock()
|
||||
for pKeyStr, pEntry := range pMap.mp {
|
||||
var pKey peerKey
|
||||
if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil {
|
||||
fmt.Printf("peer key scan failed: %v", err)
|
||||
}
|
||||
|
||||
if pEntry.isLocal {
|
||||
continue
|
||||
}
|
||||
|
||||
// Go captures variables by reference. The pEntry could be
|
||||
// pointing to the same memory location for every iteration. Make
|
||||
// a copy of pEntry before capturing it in the following closure.
|
||||
entry := pEntry
|
||||
op := func() {
|
||||
if err := d.peerAdd(nid, entry.eid, pKey.peerIP, entry.peerIPMask,
|
||||
pKey.peerMac, entry.vtep,
|
||||
false); err != nil {
|
||||
fmt.Printf("peerdbupdate in sandbox failed for ip %s and mac %s: %v",
|
||||
pKey.peerIP, pKey.peerMac, err)
|
||||
}
|
||||
}
|
||||
|
||||
peerOps = append(peerOps, op)
|
||||
}
|
||||
pMap.Unlock()
|
||||
|
||||
for _, op := range peerOps {
|
||||
op()
|
||||
}
|
||||
|
||||
peerDbWg.Done()
|
||||
}
|
||||
|
||||
func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
|
||||
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
||||
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updateDb {
|
||||
d.peerDbAdd(nid, eid, peerIP, peerIPMask, peerMac, vtep, false)
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
sbox := n.sandbox()
|
||||
if sbox == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
IP := &net.IPNet{
|
||||
IP: peerIP,
|
||||
Mask: peerIPMask,
|
||||
}
|
||||
|
||||
s := n.getSubnetforIP(IP)
|
||||
if s == nil {
|
||||
return fmt.Errorf("couldn't find the subnet %q in network %q\n", IP.String(), n.id)
|
||||
}
|
||||
|
||||
if err := n.obtainVxlanID(s); err != nil {
|
||||
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
if err := n.joinSubnetSandbox(s); err != nil {
|
||||
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
// Add neighbor entry for the peer IP
|
||||
if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName)); err != nil {
|
||||
return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err)
|
||||
}
|
||||
|
||||
// Add fdb entry to the bridge for the peer mac
|
||||
if err := sbox.AddNeighbor(vtep, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName),
|
||||
sbox.NeighborOptions().Family(syscall.AF_BRIDGE)); err != nil {
|
||||
return fmt.Errorf("could not add fdb entry into the sandbox: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
|
||||
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
||||
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updateDb {
|
||||
d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep)
|
||||
}
|
||||
|
||||
n := d.network(nid)
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
sbox := n.sandbox()
|
||||
if sbox == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete fdb entry to the bridge for the peer mac
|
||||
if err := sbox.DeleteNeighbor(vtep, peerMac); err != nil {
|
||||
return fmt.Errorf("could not delete fdb entry into the sandbox: %v", err)
|
||||
}
|
||||
|
||||
// Delete neighbor entry for the peer IP
|
||||
if err := sbox.DeleteNeighbor(peerIP, peerMac); err != nil {
|
||||
return fmt.Errorf("could not delete neigbor entry into the sandbox: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) pushLocalDb() {
|
||||
d.peerDbWalk(func(nid string, pKey *peerKey, pEntry *peerEntry) bool {
|
||||
if pEntry.isLocal {
|
||||
d.pushLocalEndpointEvent("join", nid, pEntry.eid)
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
164
vendor/github.com/docker/libnetwork/drivers/remote/api/api.go
generated
vendored
Normal file
164
vendor/github.com/docker/libnetwork/drivers/remote/api/api.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
Package api represents all requests and responses suitable for conversation
|
||||
with a remote driver.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
)
|
||||
|
||||
// Response is the basic response structure used in all responses.
|
||||
type Response struct {
|
||||
Err string
|
||||
}
|
||||
|
||||
// GetError returns the error from the response, if any.
|
||||
func (r *Response) GetError() string {
|
||||
return r.Err
|
||||
}
|
||||
|
||||
// GetCapabilityResponse is the response of GetCapability request
|
||||
type GetCapabilityResponse struct {
|
||||
Response
|
||||
Scope string
|
||||
}
|
||||
|
||||
// CreateNetworkRequest requests a new network.
|
||||
type CreateNetworkRequest struct {
|
||||
// A network ID that remote plugins are expected to store for future
|
||||
// reference.
|
||||
NetworkID string
|
||||
|
||||
// A free form map->object interface for communication of options.
|
||||
Options map[string]interface{}
|
||||
|
||||
// IPAMData contains the address pool information for this network
|
||||
IPv4Data, IPv6Data []driverapi.IPAMData
|
||||
}
|
||||
|
||||
// CreateNetworkResponse is the response to the CreateNetworkRequest.
|
||||
type CreateNetworkResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// DeleteNetworkRequest is the request to delete an existing network.
|
||||
type DeleteNetworkRequest struct {
|
||||
// The ID of the network to delete.
|
||||
NetworkID string
|
||||
}
|
||||
|
||||
// DeleteNetworkResponse is the response to a request for deleting a network.
|
||||
type DeleteNetworkResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// CreateEndpointRequest is the request to create an endpoint within a network.
|
||||
type CreateEndpointRequest struct {
|
||||
// Provided at create time, this will be the network id referenced.
|
||||
NetworkID string
|
||||
// The ID of the endpoint for later reference.
|
||||
EndpointID string
|
||||
Interface *EndpointInterface
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
// EndpointInterface represents an interface endpoint.
|
||||
type EndpointInterface struct {
|
||||
Address string
|
||||
AddressIPv6 string
|
||||
MacAddress string
|
||||
}
|
||||
|
||||
// CreateEndpointResponse is the response to the CreateEndpoint action.
|
||||
type CreateEndpointResponse struct {
|
||||
Response
|
||||
Interface *EndpointInterface
|
||||
}
|
||||
|
||||
// Interface is the representation of a linux interface.
|
||||
type Interface struct {
|
||||
Address *net.IPNet
|
||||
AddressIPv6 *net.IPNet
|
||||
MacAddress net.HardwareAddr
|
||||
}
|
||||
|
||||
// DeleteEndpointRequest describes the API for deleting an endpoint.
|
||||
type DeleteEndpointRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
// DeleteEndpointResponse is the response to the DeleteEndpoint action.
|
||||
type DeleteEndpointResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// EndpointInfoRequest retrieves information about the endpoint from the network driver.
|
||||
type EndpointInfoRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
// EndpointInfoResponse is the response to an EndpointInfoRequest.
|
||||
type EndpointInfoResponse struct {
|
||||
Response
|
||||
Value map[string]interface{}
|
||||
}
|
||||
|
||||
// JoinRequest describes the API for joining an endpoint to a sandbox.
|
||||
type JoinRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
SandboxKey string
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
// InterfaceName is the struct represetation of a pair of devices with source
|
||||
// and destination, for the purposes of putting an endpoint into a container.
|
||||
type InterfaceName struct {
|
||||
SrcName string
|
||||
DstName string
|
||||
DstPrefix string
|
||||
}
|
||||
|
||||
// StaticRoute is the plain JSON representation of a static route.
|
||||
type StaticRoute struct {
|
||||
Destination string
|
||||
RouteType int
|
||||
NextHop string
|
||||
}
|
||||
|
||||
// JoinResponse is the response to a JoinRequest.
|
||||
type JoinResponse struct {
|
||||
Response
|
||||
InterfaceName *InterfaceName
|
||||
Gateway string
|
||||
GatewayIPv6 string
|
||||
StaticRoutes []StaticRoute
|
||||
DisableGatewayService bool
|
||||
}
|
||||
|
||||
// LeaveRequest describes the API for detaching an endpoint from a sandbox.
|
||||
type LeaveRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
// LeaveResponse is the answer to LeaveRequest.
|
||||
type LeaveResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// DiscoveryNotification represents a discovery notification
|
||||
type DiscoveryNotification struct {
|
||||
DiscoveryType driverapi.DiscoveryType
|
||||
DiscoveryData interface{}
|
||||
}
|
||||
|
||||
// DiscoveryResponse is used by libnetwork to log any plugin error processing the discovery notifications
|
||||
type DiscoveryResponse struct {
|
||||
Response
|
||||
}
|
||||
327
vendor/github.com/docker/libnetwork/drivers/remote/driver.go
generated
vendored
Normal file
327
vendor/github.com/docker/libnetwork/drivers/remote/driver.go
generated
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/drivers/remote/api"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
type driver struct {
|
||||
endpoint *plugins.Client
|
||||
networkType string
|
||||
}
|
||||
|
||||
type maybeError interface {
|
||||
GetError() string
|
||||
}
|
||||
|
||||
func newDriver(name string, client *plugins.Client) driverapi.Driver {
|
||||
return &driver{networkType: name, endpoint: client}
|
||||
}
|
||||
|
||||
// Init makes sure a remote driver is registered when a network driver
|
||||
// plugin is activated.
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
|
||||
// negotiate driver capability with client
|
||||
d := newDriver(name, client)
|
||||
c, err := d.(*driver).getCapabilities()
|
||||
if err != nil {
|
||||
log.Errorf("error getting capability for %s due to %v", name, err)
|
||||
return
|
||||
}
|
||||
if err = dc.RegisterDriver(name, d, *c); err != nil {
|
||||
log.Errorf("error registering driver for %s due to %v", name, err)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get capability from client
|
||||
func (d *driver) getCapabilities() (*driverapi.Capability, error) {
|
||||
var capResp api.GetCapabilityResponse
|
||||
if err := d.call("GetCapabilities", nil, &capResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &driverapi.Capability{}
|
||||
switch capResp.Scope {
|
||||
case "global":
|
||||
c.DataScope = datastore.GlobalScope
|
||||
case "local":
|
||||
c.DataScope = datastore.LocalScope
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Config is not implemented for remote drivers, since it is assumed
|
||||
// to be supplied to the remote process out-of-band (e.g., as command
|
||||
// line arguments).
|
||||
func (d *driver) Config(option map[string]interface{}) error {
|
||||
return &driverapi.ErrNotImplemented{}
|
||||
}
|
||||
|
||||
func (d *driver) call(methodName string, arg interface{}, retVal maybeError) error {
|
||||
method := driverapi.NetworkPluginEndpointType + "." + methodName
|
||||
err := d.endpoint.Call(method, arg, retVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e := retVal.GetError(); e != "" {
|
||||
return fmt.Errorf("remote: %s", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
create := &api.CreateNetworkRequest{
|
||||
NetworkID: id,
|
||||
Options: options,
|
||||
IPv4Data: ipV4Data,
|
||||
IPv6Data: ipV6Data,
|
||||
}
|
||||
return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
delete := &api.DeleteNetworkRequest{NetworkID: nid}
|
||||
return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
if ifInfo == nil {
|
||||
return fmt.Errorf("must not be called with nil InterfaceInfo")
|
||||
}
|
||||
|
||||
reqIface := &api.EndpointInterface{}
|
||||
if ifInfo.Address() != nil {
|
||||
reqIface.Address = ifInfo.Address().String()
|
||||
}
|
||||
if ifInfo.AddressIPv6() != nil {
|
||||
reqIface.AddressIPv6 = ifInfo.AddressIPv6().String()
|
||||
}
|
||||
if ifInfo.MacAddress() != nil {
|
||||
reqIface.MacAddress = ifInfo.MacAddress().String()
|
||||
}
|
||||
|
||||
create := &api.CreateEndpointRequest{
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
Interface: reqIface,
|
||||
Options: epOptions,
|
||||
}
|
||||
var res api.CreateEndpointResponse
|
||||
if err := d.call("CreateEndpoint", create, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inIface, err := parseInterface(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if inIface == nil {
|
||||
// Remote driver did not set any field
|
||||
return nil
|
||||
}
|
||||
|
||||
if inIface.MacAddress != nil {
|
||||
if err := ifInfo.SetMacAddress(inIface.MacAddress); err != nil {
|
||||
return errorWithRollback(fmt.Sprintf("driver modified interface MAC address: %v", err), d.DeleteEndpoint(nid, eid))
|
||||
}
|
||||
}
|
||||
if inIface.Address != nil {
|
||||
if err := ifInfo.SetIPAddress(inIface.Address); err != nil {
|
||||
return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid))
|
||||
}
|
||||
}
|
||||
if inIface.AddressIPv6 != nil {
|
||||
if err := ifInfo.SetIPAddress(inIface.AddressIPv6); err != nil {
|
||||
return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func errorWithRollback(msg string, err error) error {
|
||||
rollback := "rolled back"
|
||||
if err != nil {
|
||||
rollback = "failed to roll back: " + err.Error()
|
||||
}
|
||||
return fmt.Errorf("%s; %s", msg, rollback)
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
delete := &api.DeleteEndpointRequest{
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
}
|
||||
return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
info := &api.EndpointInfoRequest{
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
}
|
||||
var res api.EndpointInfoResponse
|
||||
if err := d.call("EndpointOperInfo", info, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.Value, nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
join := &api.JoinRequest{
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
SandboxKey: sboxKey,
|
||||
Options: options,
|
||||
}
|
||||
var (
|
||||
res api.JoinResponse
|
||||
err error
|
||||
)
|
||||
if err = d.call("Join", join, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ifaceName := res.InterfaceName
|
||||
if iface := jinfo.InterfaceName(); iface != nil && ifaceName != nil {
|
||||
if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil {
|
||||
return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
|
||||
}
|
||||
}
|
||||
|
||||
var addr net.IP
|
||||
if res.Gateway != "" {
|
||||
if addr = net.ParseIP(res.Gateway); addr == nil {
|
||||
return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway)
|
||||
}
|
||||
if jinfo.SetGateway(addr) != nil {
|
||||
return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid))
|
||||
}
|
||||
}
|
||||
if res.GatewayIPv6 != "" {
|
||||
if addr = net.ParseIP(res.GatewayIPv6); addr == nil {
|
||||
return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6)
|
||||
}
|
||||
if jinfo.SetGatewayIPv6(addr) != nil {
|
||||
return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid))
|
||||
}
|
||||
}
|
||||
if len(res.StaticRoutes) > 0 {
|
||||
routes, err := parseStaticRoutes(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, route := range routes {
|
||||
if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop) != nil {
|
||||
return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid))
|
||||
}
|
||||
}
|
||||
}
|
||||
if res.DisableGatewayService {
|
||||
jinfo.DisableGatewayService()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
leave := &api.LeaveRequest{
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
}
|
||||
return d.call("Leave", leave, &api.LeaveResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return d.networkType
|
||||
}
|
||||
|
||||
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
|
||||
func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
if dType != driverapi.NodeDiscovery {
|
||||
return fmt.Errorf("Unknown discovery type : %v", dType)
|
||||
}
|
||||
notif := &api.DiscoveryNotification{
|
||||
DiscoveryType: dType,
|
||||
DiscoveryData: data,
|
||||
}
|
||||
return d.call("DiscoverNew", notif, &api.DiscoveryResponse{})
|
||||
}
|
||||
|
||||
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
||||
func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
if dType != driverapi.NodeDiscovery {
|
||||
return fmt.Errorf("Unknown discovery type : %v", dType)
|
||||
}
|
||||
notif := &api.DiscoveryNotification{
|
||||
DiscoveryType: dType,
|
||||
DiscoveryData: data,
|
||||
}
|
||||
return d.call("DiscoverDelete", notif, &api.DiscoveryResponse{})
|
||||
}
|
||||
|
||||
func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
|
||||
var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
|
||||
for i, inRoute := range r.StaticRoutes {
|
||||
var err error
|
||||
outRoute := &types.StaticRoute{RouteType: inRoute.RouteType}
|
||||
|
||||
if inRoute.Destination != "" {
|
||||
if outRoute.Destination, err = types.ParseCIDR(inRoute.Destination); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if inRoute.NextHop != "" {
|
||||
outRoute.NextHop = net.ParseIP(inRoute.NextHop)
|
||||
if outRoute.NextHop == nil {
|
||||
return nil, fmt.Errorf("failed to parse nexthop IP %s", inRoute.NextHop)
|
||||
}
|
||||
}
|
||||
|
||||
routes[i] = outRoute
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// parseInterfaces validates all the parameters of an Interface and returns them.
|
||||
func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
|
||||
var outIf *api.Interface
|
||||
|
||||
inIf := r.Interface
|
||||
if inIf != nil {
|
||||
var err error
|
||||
outIf = &api.Interface{}
|
||||
if inIf.Address != "" {
|
||||
if outIf.Address, err = types.ParseCIDR(inIf.Address); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if inIf.AddressIPv6 != "" {
|
||||
if outIf.AddressIPv6, err = types.ParseCIDR(inIf.AddressIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if inIf.MacAddress != "" {
|
||||
if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outIf, nil
|
||||
}
|
||||
559
vendor/github.com/docker/libnetwork/drivers/remote/driver_test.go
generated
vendored
Normal file
559
vendor/github.com/docker/libnetwork/drivers/remote/driver_test.go
generated
vendored
Normal file
@@ -0,0 +1,559 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
_ "github.com/docker/libnetwork/testutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func decodeToMap(r *http.Request) (res map[string]interface{}, err error) {
|
||||
err = json.NewDecoder(r.Body).Decode(&res)
|
||||
return
|
||||
}
|
||||
|
||||
func handle(t *testing.T, mux *http.ServeMux, method string, h func(map[string]interface{}) interface{}) {
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.%s", driverapi.NetworkPluginEndpointType, method), func(w http.ResponseWriter, r *http.Request) {
|
||||
ask, err := decodeToMap(r)
|
||||
if err != nil && err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
answer := h(ask)
|
||||
err = json.NewEncoder(w).Encode(&answer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() {
|
||||
if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
server := httptest.NewServer(mux)
|
||||
if server == nil {
|
||||
t.Fatal("Failed to start a HTTP Server")
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(fmt.Sprintf("/etc/docker/plugins/%s.spec", name), []byte(server.URL), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
||||
fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
|
||||
})
|
||||
|
||||
return func() {
|
||||
if err := os.RemoveAll("/etc/docker/plugins"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server.Close()
|
||||
}
|
||||
}
|
||||
|
||||
type testEndpoint struct {
|
||||
t *testing.T
|
||||
src string
|
||||
dst string
|
||||
address string
|
||||
addressIPv6 string
|
||||
macAddress string
|
||||
gateway string
|
||||
gatewayIPv6 string
|
||||
resolvConfPath string
|
||||
hostsPath string
|
||||
nextHop string
|
||||
destination string
|
||||
routeType int
|
||||
disableGatewayService bool
|
||||
}
|
||||
|
||||
func (test *testEndpoint) Interface() driverapi.InterfaceInfo {
|
||||
return test
|
||||
}
|
||||
|
||||
func (test *testEndpoint) Address() *net.IPNet {
|
||||
if test.address == "" {
|
||||
return nil
|
||||
}
|
||||
nw, _ := types.ParseCIDR(test.address)
|
||||
return nw
|
||||
}
|
||||
|
||||
func (test *testEndpoint) AddressIPv6() *net.IPNet {
|
||||
if test.addressIPv6 == "" {
|
||||
return nil
|
||||
}
|
||||
nw, _ := types.ParseCIDR(test.addressIPv6)
|
||||
return nw
|
||||
}
|
||||
|
||||
func (test *testEndpoint) MacAddress() net.HardwareAddr {
|
||||
if test.macAddress == "" {
|
||||
return nil
|
||||
}
|
||||
mac, _ := net.ParseMAC(test.macAddress)
|
||||
return mac
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetMacAddress(mac net.HardwareAddr) error {
|
||||
if test.macAddress != "" {
|
||||
return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", test.macAddress, mac)
|
||||
}
|
||||
if mac == nil {
|
||||
return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
|
||||
}
|
||||
test.macAddress = mac.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetIPAddress(address *net.IPNet) error {
|
||||
if address.IP == nil {
|
||||
return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
|
||||
}
|
||||
if address.IP.To4() == nil {
|
||||
return setAddress(&test.addressIPv6, address)
|
||||
}
|
||||
return setAddress(&test.address, address)
|
||||
}
|
||||
|
||||
func setAddress(ifaceAddr *string, address *net.IPNet) error {
|
||||
if *ifaceAddr != "" {
|
||||
return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
|
||||
}
|
||||
*ifaceAddr = address.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
|
||||
return test
|
||||
}
|
||||
|
||||
func compareIPs(t *testing.T, kind string, shouldBe string, supplied net.IP) {
|
||||
ip := net.ParseIP(shouldBe)
|
||||
if ip == nil {
|
||||
t.Fatalf(`Invalid IP to test against: "%s"`, shouldBe)
|
||||
}
|
||||
if !ip.Equal(supplied) {
|
||||
t.Fatalf(`%s IPs are not equal: expected "%s", got %v`, kind, shouldBe, supplied)
|
||||
}
|
||||
}
|
||||
|
||||
func compareIPNets(t *testing.T, kind string, shouldBe string, supplied net.IPNet) {
|
||||
_, net, _ := net.ParseCIDR(shouldBe)
|
||||
if net == nil {
|
||||
t.Fatalf(`Invalid IP network to test against: "%s"`, shouldBe)
|
||||
}
|
||||
if !types.CompareIPNet(net, &supplied) {
|
||||
t.Fatalf(`%s IP networks are not equal: expected "%s", got %v`, kind, shouldBe, supplied)
|
||||
}
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetGateway(ipv4 net.IP) error {
|
||||
compareIPs(test.t, "Gateway", test.gateway, ipv4)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error {
|
||||
compareIPs(test.t, "GatewayIPv6", test.gatewayIPv6, ipv6)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetNames(src string, dst string) error {
|
||||
if test.src != src {
|
||||
test.t.Fatalf(`Wrong SrcName; expected "%s", got "%s"`, test.src, src)
|
||||
}
|
||||
if test.dst != dst {
|
||||
test.t.Fatalf(`Wrong DstPrefix; expected "%s", got "%s"`, test.dst, dst)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
|
||||
compareIPNets(test.t, "Destination", test.destination, *destination)
|
||||
compareIPs(test.t, "NextHop", test.nextHop, nextHop)
|
||||
|
||||
if test.routeType != routeType {
|
||||
test.t.Fatalf(`Wrong RouteType; expected "%d", got "%d"`, test.routeType, routeType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) DisableGatewayService() {
|
||||
test.disableGatewayService = true
|
||||
}
|
||||
|
||||
func TestGetEmptyCapabilities(t *testing.T) {
|
||||
var plugin = "test-net-driver-empty-cap"
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := newDriver(plugin, p.Client)
|
||||
if d.Type() != plugin {
|
||||
t.Fatal("Driver type does not match that given")
|
||||
}
|
||||
|
||||
_, err = d.(*driver).getCapabilities()
|
||||
if err == nil {
|
||||
t.Fatal("There should be error reported when get empty capability")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExtraCapabilities(t *testing.T) {
|
||||
var plugin = "test-net-driver-extra-cap"
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{
|
||||
"Scope": "local",
|
||||
"foo": "bar",
|
||||
}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := newDriver(plugin, p.Client)
|
||||
if d.Type() != plugin {
|
||||
t.Fatal("Driver type does not match that given")
|
||||
}
|
||||
|
||||
c, err := d.(*driver).getCapabilities()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if c.DataScope != datastore.LocalScope {
|
||||
t.Fatalf("get capability '%s', expecting 'local'", c.DataScope)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInvalidCapabilities(t *testing.T) {
|
||||
var plugin = "test-net-driver-invalid-cap"
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{
|
||||
"Scope": "fake",
|
||||
}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := newDriver(plugin, p.Client)
|
||||
if d.Type() != plugin {
|
||||
t.Fatal("Driver type does not match that given")
|
||||
}
|
||||
|
||||
_, err = d.(*driver).getCapabilities()
|
||||
if err == nil {
|
||||
t.Fatal("There should be error reported when get invalid capability")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteDriver(t *testing.T) {
|
||||
var plugin = "test-net-driver"
|
||||
|
||||
ep := &testEndpoint{
|
||||
t: t,
|
||||
src: "vethsrc",
|
||||
dst: "vethdst",
|
||||
address: "192.168.5.7/16",
|
||||
addressIPv6: "2001:DB8::5:7/48",
|
||||
macAddress: "",
|
||||
gateway: "192.168.0.1",
|
||||
gatewayIPv6: "2001:DB8::1",
|
||||
hostsPath: "/here/comes/the/host/path",
|
||||
resolvConfPath: "/there/goes/the/resolv/conf",
|
||||
destination: "10.0.0.0/8",
|
||||
nextHop: "10.0.0.1",
|
||||
routeType: 1,
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
var networkID string
|
||||
|
||||
handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{
|
||||
"Scope": "global",
|
||||
}
|
||||
})
|
||||
handle(t, mux, "CreateNetwork", func(msg map[string]interface{}) interface{} {
|
||||
nid := msg["NetworkID"]
|
||||
var ok bool
|
||||
if networkID, ok = nid.(string); !ok {
|
||||
t.Fatal("RPC did not include network ID string")
|
||||
}
|
||||
return map[string]interface{}{}
|
||||
})
|
||||
handle(t, mux, "DeleteNetwork", func(msg map[string]interface{}) interface{} {
|
||||
if nid, ok := msg["NetworkID"]; !ok || nid != networkID {
|
||||
t.Fatal("Network ID missing or does not match that created")
|
||||
}
|
||||
return map[string]interface{}{}
|
||||
})
|
||||
handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
||||
iface := map[string]interface{}{
|
||||
"MacAddress": ep.macAddress,
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"Interface": iface,
|
||||
}
|
||||
})
|
||||
handle(t, mux, "Join", func(msg map[string]interface{}) interface{} {
|
||||
options := msg["Options"].(map[string]interface{})
|
||||
foo, ok := options["foo"].(string)
|
||||
if !ok || foo != "fooValue" {
|
||||
t.Fatalf("Did not receive expected foo string in request options: %+v", msg)
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"Gateway": ep.gateway,
|
||||
"GatewayIPv6": ep.gatewayIPv6,
|
||||
"HostsPath": ep.hostsPath,
|
||||
"ResolvConfPath": ep.resolvConfPath,
|
||||
"InterfaceName": map[string]interface{}{
|
||||
"SrcName": ep.src,
|
||||
"DstPrefix": ep.dst,
|
||||
},
|
||||
"StaticRoutes": []map[string]interface{}{
|
||||
{
|
||||
"Destination": ep.destination,
|
||||
"RouteType": ep.routeType,
|
||||
"NextHop": ep.nextHop,
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
handle(t, mux, "Leave", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]string{}
|
||||
})
|
||||
handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{}
|
||||
})
|
||||
handle(t, mux, "EndpointOperInfo", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{
|
||||
"Value": map[string]string{
|
||||
"Arbitrary": "key",
|
||||
"Value": "pairs?",
|
||||
},
|
||||
}
|
||||
})
|
||||
handle(t, mux, "DiscoverNew", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]string{}
|
||||
})
|
||||
handle(t, mux, "DiscoverDelete", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := newDriver(plugin, p.Client)
|
||||
if d.Type() != plugin {
|
||||
t.Fatal("Driver type does not match that given")
|
||||
}
|
||||
|
||||
c, err := d.(*driver).getCapabilities()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if c.DataScope != datastore.GlobalScope {
|
||||
t.Fatalf("get capability '%s', expecting 'global'", c.DataScope)
|
||||
}
|
||||
|
||||
netID := "dummy-network"
|
||||
err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
endID := "dummy-endpoint"
|
||||
err = d.CreateEndpoint(netID, endID, ep, map[string]interface{}{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
joinOpts := map[string]interface{}{"foo": "fooValue"}
|
||||
err = d.Join(netID, endID, "sandbox-key", ep, joinOpts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = d.EndpointOperInfo(netID, endID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = d.Leave(netID, endID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = d.DeleteEndpoint(netID, endID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = d.DeleteNetwork(netID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data := driverapi.NodeDiscoveryData{
|
||||
Address: "192.168.1.1",
|
||||
}
|
||||
if err = d.DiscoverNew(driverapi.NodeDiscovery, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = d.DiscoverDelete(driverapi.NodeDiscovery, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDriverError(t *testing.T) {
|
||||
var plugin = "test-net-driver-error"
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{
|
||||
"Err": "this should get raised as an error",
|
||||
}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
driver := newDriver(plugin, p.Client)
|
||||
|
||||
if err := driver.CreateEndpoint("dummy", "dummy", &testEndpoint{t: t}, map[string]interface{}{}); err == nil {
|
||||
t.Fatalf("Expected error from driver")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingValues(t *testing.T) {
|
||||
var plugin = "test-net-driver-missing"
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
ep := &testEndpoint{
|
||||
t: t,
|
||||
}
|
||||
|
||||
handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
||||
iface := map[string]interface{}{
|
||||
"Address": ep.address,
|
||||
"AddressIPv6": ep.addressIPv6,
|
||||
"MacAddress": ep.macAddress,
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"Interface": iface,
|
||||
}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
driver := newDriver(plugin, p.Client)
|
||||
|
||||
if err := driver.CreateEndpoint("dummy", "dummy", ep, map[string]interface{}{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type rollbackEndpoint struct {
|
||||
}
|
||||
|
||||
func (r *rollbackEndpoint) Interface() driverapi.InterfaceInfo {
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *rollbackEndpoint) MacAddress() net.HardwareAddr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rollbackEndpoint) Address() *net.IPNet {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rollbackEndpoint) AddressIPv6() *net.IPNet {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rollbackEndpoint) SetMacAddress(mac net.HardwareAddr) error {
|
||||
return fmt.Errorf("invalid mac")
|
||||
}
|
||||
|
||||
func (r *rollbackEndpoint) SetIPAddress(ip *net.IPNet) error {
|
||||
return fmt.Errorf("invalid ip")
|
||||
}
|
||||
|
||||
func TestRollback(t *testing.T) {
|
||||
var plugin = "test-net-driver-rollback"
|
||||
|
||||
mux := http.NewServeMux()
|
||||
defer setupPlugin(t, plugin, mux)()
|
||||
|
||||
rolledback := false
|
||||
|
||||
handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
||||
iface := map[string]interface{}{
|
||||
"Address": "192.168.4.5/16",
|
||||
"AddressIPv6": "",
|
||||
"MacAddress": "7a:12:34:56:78:90",
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"Interface": interface{}(iface),
|
||||
}
|
||||
})
|
||||
handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} {
|
||||
rolledback = true
|
||||
return map[string]interface{}{}
|
||||
})
|
||||
|
||||
p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
driver := newDriver(plugin, p.Client)
|
||||
|
||||
ep := &rollbackEndpoint{}
|
||||
|
||||
if err := driver.CreateEndpoint("dummy", "dummy", ep.Interface(), map[string]interface{}{}); err == nil {
|
||||
t.Fatalf("Expected error from driver")
|
||||
}
|
||||
if !rolledback {
|
||||
t.Fatalf("Expected to have had DeleteEndpoint called")
|
||||
}
|
||||
}
|
||||
64
vendor/github.com/docker/libnetwork/drivers/windows/windows.go
generated
vendored
Normal file
64
vendor/github.com/docker/libnetwork/drivers/windows/windows.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package windows
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
)
|
||||
|
||||
const networkType = "windows"
|
||||
|
||||
// TODO Windows. This is a placeholder for now
|
||||
|
||||
type driver struct{}
|
||||
|
||||
// Init registers a new instance of null driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
|
||||
func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
||||
func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user