commit
d48f2c1a8e
11 changed files with 290 additions and 24 deletions
|
@ -48,13 +48,15 @@ There are many networking solutions available to suit a broad range of use-cases
|
|||
|
||||
// For each new container: allocate IP and interfaces. The returned network
|
||||
// settings will be used for container infos (inspect and such), as well as
|
||||
// iptables rules for port publishing.
|
||||
_, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
||||
// iptables rules for port publishing. This info is contained or accessible
|
||||
// from the returned endpoint.
|
||||
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Add interfaces to the namespace.
|
||||
sinfo := ep.SandboxInfo()
|
||||
for _, iface := range sinfo.Interfaces {
|
||||
if err := networkNamespace.AddInterface(iface); err != nil {
|
||||
return
|
||||
|
|
|
@ -33,13 +33,15 @@ func main() {
|
|||
|
||||
// For each new container: allocate IP and interfaces. The returned network
|
||||
// settings will be used for container infos (inspect and such), as well as
|
||||
// iptables rules for port publishing.
|
||||
_, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
||||
// iptables rules for port publishing. This info is contained or accessible
|
||||
// from the returned endpoint.
|
||||
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Add interfaces to the namespace.
|
||||
sinfo := ep.SandboxInfo()
|
||||
for _, iface := range sinfo.Interfaces {
|
||||
if err := networkNamespace.AddInterface(iface); err != nil {
|
||||
return
|
||||
|
|
|
@ -3,6 +3,8 @@ package driverapi
|
|||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -56,10 +58,10 @@ type Interface struct {
|
|||
DstName string
|
||||
|
||||
// IPv4 address for the interface.
|
||||
Address net.IPNet
|
||||
Address *net.IPNet
|
||||
|
||||
// IPv6 address for the interface.
|
||||
AddressIPv6 net.IPNet
|
||||
AddressIPv6 *net.IPNet
|
||||
}
|
||||
|
||||
// SandboxInfo represents all possible information that
|
||||
|
@ -76,3 +78,85 @@ type SandboxInfo struct {
|
|||
|
||||
// TODO: Add routes and ip tables etc.
|
||||
}
|
||||
|
||||
// GetCopy returns a copy of this Interface structure
|
||||
func (i *Interface) GetCopy() *Interface {
|
||||
return &Interface{
|
||||
SrcName: i.SrcName,
|
||||
DstName: i.DstName,
|
||||
Address: netutils.GetIPNetCopy(i.Address),
|
||||
AddressIPv6: netutils.GetIPNetCopy(i.AddressIPv6),
|
||||
}
|
||||
}
|
||||
|
||||
// Equal checks if this instance of Interface is equal to the passed one
|
||||
func (i *Interface) Equal(o *Interface) bool {
|
||||
if i == o {
|
||||
return true
|
||||
}
|
||||
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if i.SrcName != o.SrcName || i.DstName != o.DstName {
|
||||
return false
|
||||
}
|
||||
|
||||
if !netutils.CompareIPNet(i.Address, o.Address) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !netutils.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetCopy returns a copy of this SandboxInfo structure
|
||||
func (s *SandboxInfo) GetCopy() *SandboxInfo {
|
||||
list := make([]*Interface, len(s.Interfaces))
|
||||
for i, iface := range s.Interfaces {
|
||||
list[i] = iface.GetCopy()
|
||||
}
|
||||
gw := netutils.GetIPCopy(s.Gateway)
|
||||
gw6 := netutils.GetIPCopy(s.GatewayIPv6)
|
||||
|
||||
return &SandboxInfo{Interfaces: list, Gateway: gw, GatewayIPv6: gw6}
|
||||
}
|
||||
|
||||
// Equal checks if this instance of SandboxInfo is equal to the passed one
|
||||
func (s *SandboxInfo) Equal(o *SandboxInfo) bool {
|
||||
if s == o {
|
||||
return true
|
||||
}
|
||||
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if !s.Gateway.Equal(o.Gateway) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !s.GatewayIPv6.Equal(o.GatewayIPv6) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (s.Interfaces == nil && o.Interfaces != nil) ||
|
||||
(s.Interfaces != nil && o.Interfaces == nil) ||
|
||||
(len(s.Interfaces) != len(o.Interfaces)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Note: At the moment, the two lists must be in the same order
|
||||
for i := 0; i < len(s.Interfaces); i++ {
|
||||
if !s.Interfaces[i].Equal(o.Interfaces[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
|
71
libnetwork/driverapi/driverapi_test.go
Normal file
71
libnetwork/driverapi/driverapi_test.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package driverapi
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInterfaceEqual(t *testing.T) {
|
||||
list := getInterfaceList()
|
||||
|
||||
if !list[0].Equal(list[0]) {
|
||||
t.Fatalf("Interface.Equal() returned false negative")
|
||||
}
|
||||
|
||||
if list[0].Equal(list[1]) {
|
||||
t.Fatalf("Interface.Equal() returned false positive")
|
||||
}
|
||||
|
||||
if list[0].Equal(list[1]) != list[1].Equal(list[0]) {
|
||||
t.Fatalf("Interface.Equal() failed commutative check")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterfaceCopy(t *testing.T) {
|
||||
for _, iface := range getInterfaceList() {
|
||||
cp := iface.GetCopy()
|
||||
|
||||
if !iface.Equal(cp) {
|
||||
t.Fatalf("Failed to return a copy of Interface")
|
||||
}
|
||||
|
||||
if iface == cp {
|
||||
t.Fatalf("Failed to return a true copy of Interface")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSandboxInfoCopy(t *testing.T) {
|
||||
si := SandboxInfo{Interfaces: getInterfaceList(), Gateway: net.ParseIP("192.168.1.254"), GatewayIPv6: net.ParseIP("2001:2345::abcd:8889")}
|
||||
cp := si.GetCopy()
|
||||
|
||||
if !si.Equal(cp) {
|
||||
t.Fatalf("Failed to return a copy of SandboxInfo")
|
||||
}
|
||||
|
||||
if &si == cp {
|
||||
t.Fatalf("Failed to return a true copy of SanboxInfo")
|
||||
}
|
||||
}
|
||||
|
||||
func getInterfaceList() []*Interface {
|
||||
_, netv4a, _ := net.ParseCIDR("192.168.30.1/24")
|
||||
_, netv4b, _ := net.ParseCIDR("172.18.255.2/23")
|
||||
_, netv6a, _ := net.ParseCIDR("2001:2345::abcd:8888/80")
|
||||
_, netv6b, _ := net.ParseCIDR("2001:2345::abcd:8889/80")
|
||||
|
||||
return []*Interface{
|
||||
&Interface{
|
||||
SrcName: "veth1234567",
|
||||
DstName: "eth0",
|
||||
Address: netv4a,
|
||||
AddressIPv6: netv6a,
|
||||
},
|
||||
&Interface{
|
||||
SrcName: "veth7654321",
|
||||
DstName: "eth1",
|
||||
Address: netv4b,
|
||||
AddressIPv6: netv6b,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -213,7 +213,8 @@ func (d *driver) DeleteNetwork(nid driverapi.UUID) error {
|
|||
|
||||
func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOption interface{}) (*driverapi.SandboxInfo, error) {
|
||||
var (
|
||||
ipv6Addr net.IPNet
|
||||
ipv6Addr *net.IPNet
|
||||
ip6 net.IP
|
||||
err error
|
||||
)
|
||||
|
||||
|
@ -292,14 +293,14 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOptio
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv4Addr := net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
||||
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
||||
|
||||
if config.EnableIPv6 {
|
||||
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6Addr = net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
|
||||
ipv6Addr = &net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
|
||||
}
|
||||
|
||||
var interfaces []*driverapi.Interface
|
||||
|
@ -316,7 +317,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOptio
|
|||
}
|
||||
|
||||
n.endpoint.addressIPv4 = ip4
|
||||
n.endpoint.addressIPv6 = ipv6Addr.IP
|
||||
n.endpoint.addressIPv6 = ip6
|
||||
interfaces = append(interfaces, intf)
|
||||
sinfo.Interfaces = interfaces
|
||||
return sinfo, nil
|
||||
|
|
|
@ -118,7 +118,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
|
|||
}
|
||||
|
||||
interfaces := sinfo.Interfaces
|
||||
if len(interfaces[0].AddressIPv6.IP) != 0 {
|
||||
if interfaces[0].AddressIPv6 != nil {
|
||||
t.Fatalf("Expectd IPv6 address to be nil when IPv6 is not enabled. Got IPv6 = %s", interfaces[0].AddressIPv6.String())
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ func TestSimplebridge(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep, _, err := network.CreateEndpoint("testep", "", "")
|
||||
ep, err := network.CreateEndpoint("testep", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep, _, err := network.CreateEndpoint("testep", "", "")
|
||||
ep, err := network.CreateEndpoint("testep", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ func TestUnknownEndpoint(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep, _, err := network.CreateEndpoint("testep", "", "")
|
||||
ep, err := network.CreateEndpoint("testep", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package netutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
@ -145,3 +146,31 @@ func GenerateRandomName(prefix string, size int) (string, error) {
|
|||
}
|
||||
return prefix + hex.EncodeToString(id)[:size], nil
|
||||
}
|
||||
|
||||
// GetIPCopy returns a copy of the passed IP address
|
||||
func GetIPCopy(from net.IP) net.IP {
|
||||
to := make(net.IP, len(from))
|
||||
copy(to, from)
|
||||
return to
|
||||
}
|
||||
|
||||
// GetIPNetCopy returns a copy of the passed IP Network
|
||||
func GetIPNetCopy(from *net.IPNet) *net.IPNet {
|
||||
if from == nil {
|
||||
return nil
|
||||
}
|
||||
bm := make(net.IPMask, len(from.Mask))
|
||||
copy(bm, from.Mask)
|
||||
return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
|
||||
}
|
||||
|
||||
// CompareIPNet returns equal if the two IP Networks are equal
|
||||
func CompareIPNet(a, b *net.IPNet) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
|
||||
}
|
||||
|
|
|
@ -209,3 +209,55 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
|
|||
t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareIPNet(t *testing.T) {
|
||||
if CompareIPNet(nil, nil) == false {
|
||||
t.Fatalf("Failed to detect two nil net.IPNets are equal")
|
||||
}
|
||||
|
||||
_, net1, _ := net.ParseCIDR("192.168.30.22/24")
|
||||
if CompareIPNet(net1, net1) == false {
|
||||
t.Fatalf("Failed to detect same net.IPNet pointers equality")
|
||||
}
|
||||
|
||||
_, net2, _ := net.ParseCIDR("192.168.30.22/24")
|
||||
if CompareIPNet(net1, net2) == false {
|
||||
t.Fatalf("Failed to detect same net.IPNet object equality")
|
||||
}
|
||||
|
||||
_, net3, _ := net.ParseCIDR("192.168.30.33/24")
|
||||
if CompareIPNet(net1, net3) == false {
|
||||
t.Fatalf("Failed to detect semantically equivalent net.IPNets")
|
||||
}
|
||||
|
||||
_, net3, _ = net.ParseCIDR("192.168.31.33/24")
|
||||
if CompareIPNet(net2, net3) == true {
|
||||
t.Fatalf("Failed to detect different net.IPNets")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPCopyFunctions(t *testing.T) {
|
||||
ip := net.ParseIP("172.28.30.134")
|
||||
cp := GetIPCopy(ip)
|
||||
|
||||
if !ip.Equal(cp) {
|
||||
t.Fatalf("Failed to return a copy of net.IP")
|
||||
}
|
||||
|
||||
if &ip == &cp {
|
||||
t.Fatalf("Failed to return a true copy of net.IP")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetIPCopyFunctions(t *testing.T) {
|
||||
_, net, _ := net.ParseCIDR("192.168.30.23/24")
|
||||
cp := GetIPNetCopy(net)
|
||||
|
||||
if CompareIPNet(net, cp) == false {
|
||||
t.Fatalf("Failed to return a copy of net.IPNet")
|
||||
}
|
||||
|
||||
if net == cp {
|
||||
t.Fatalf("Failed to return a true copy of net.IPNet")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,8 +48,9 @@ import (
|
|||
// NetworkController provides the interface for controller instance which manages
|
||||
// networks.
|
||||
type NetworkController interface {
|
||||
// NOTE: This method will go away when moving to plugin infrastructure
|
||||
NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error)
|
||||
// Create a new network. The options parameter carry driver specific options.
|
||||
// Create a new network. The options parameter carries network specific options.
|
||||
// Labels support will be added in the near future.
|
||||
NewNetwork(d *NetworkDriver, name string, options interface{}) (Network, error)
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ type Network interface {
|
|||
// Create a new endpoint to this network symbolically identified by the
|
||||
// specified unique name. The options parameter carry driver specific options.
|
||||
// Labels support will be added in the near future.
|
||||
CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, *driverapi.SandboxInfo, error)
|
||||
CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, error)
|
||||
|
||||
// Delete the network.
|
||||
Delete() error
|
||||
|
@ -77,10 +78,19 @@ type Network interface {
|
|||
|
||||
// Endpoint represents a logical connection between a network and a sandbox.
|
||||
type Endpoint interface {
|
||||
// A system generated id for this network.
|
||||
// A system generated id for this endpoint.
|
||||
ID() string
|
||||
|
||||
// Delete endpoint.
|
||||
// Name returns the name of this endpoint.
|
||||
Name() string
|
||||
|
||||
// Network returns the name of the network to which this endpoint is attached.
|
||||
Network() string
|
||||
|
||||
// SandboxInfo returns the sandbox information for this endpoint.
|
||||
SandboxInfo() *driverapi.SandboxInfo
|
||||
|
||||
// Delete and detaches this endpoint from the network.
|
||||
Delete() error
|
||||
}
|
||||
|
||||
|
@ -222,7 +232,7 @@ func (n *network) Delete() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (n *network) CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, *driverapi.SandboxInfo, error) {
|
||||
func (n *network) CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, error) {
|
||||
ep := &endpoint{name: name}
|
||||
ep.id = driverapi.UUID(stringid.GenerateRandomID())
|
||||
ep.network = n
|
||||
|
@ -230,20 +240,35 @@ func (n *network) CreateEndpoint(name string, sboxKey string, options interface{
|
|||
d := n.driver.internalDriver
|
||||
sinfo, err := d.CreateEndpoint(n.id, ep.id, sboxKey, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ep.sandboxInfo = sinfo
|
||||
n.Lock()
|
||||
n.endpoints[ep.id] = ep
|
||||
n.Unlock()
|
||||
return ep, sinfo, nil
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) ID() string {
|
||||
return string(ep.id)
|
||||
}
|
||||
|
||||
func (ep *endpoint) Name() string {
|
||||
return ep.name
|
||||
}
|
||||
|
||||
func (ep *endpoint) Network() string {
|
||||
return ep.network.name
|
||||
}
|
||||
|
||||
func (ep *endpoint) SandboxInfo() *driverapi.SandboxInfo {
|
||||
if ep.sandboxInfo == nil {
|
||||
return nil
|
||||
}
|
||||
return ep.sandboxInfo.GetCopy()
|
||||
}
|
||||
|
||||
func (ep *endpoint) Delete() error {
|
||||
var err error
|
||||
|
||||
|
|
|
@ -35,12 +35,12 @@ func setGatewayIP(gw net.IP) error {
|
|||
}
|
||||
|
||||
func setInterfaceIP(iface netlink.Link, settings *driverapi.Interface) error {
|
||||
ipAddr := &netlink.Addr{IPNet: &settings.Address, Label: ""}
|
||||
ipAddr := &netlink.Addr{IPNet: settings.Address, Label: ""}
|
||||
return netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
||||
func setInterfaceIPv6(iface netlink.Link, settings *driverapi.Interface) error {
|
||||
ipAddr := &netlink.Addr{IPNet: &settings.Address, Label: ""}
|
||||
ipAddr := &netlink.Addr{IPNet: settings.Address, Label: ""}
|
||||
return netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue