Check subnet overlap when programming of sandbox interface
Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
734f4ec86d
commit
0d32a1924e
6 changed files with 161 additions and 41 deletions
|
@ -495,10 +495,6 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err = n.getController().updateToStore(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Current endpoint providing external connectivity for the sandbox
|
||||
extEp := sb.getGatewayEndpoint()
|
||||
|
||||
|
@ -515,6 +511,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err = n.getController().updateToStore(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil {
|
||||
return sb.setupDefaultGW()
|
||||
}
|
||||
|
|
|
@ -402,6 +402,20 @@ func externalKeyTest(t *testing.T, reexec bool) {
|
|||
}
|
||||
}()
|
||||
|
||||
n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork2",
|
||||
},
|
||||
}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep, err := n.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -413,7 +427,7 @@ func externalKeyTest(t *testing.T, reexec bool) {
|
|||
}
|
||||
}()
|
||||
|
||||
ep2, err := n.CreateEndpoint("ep2")
|
||||
ep2, err := n2.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -882,6 +882,20 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork2",
|
||||
},
|
||||
}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep, err := n.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1012,12 +1026,26 @@ func TestLeaveAll(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork2",
|
||||
},
|
||||
}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep1, err := n.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep2, err := n.CreateEndpoint("ep2")
|
||||
ep2, err := n2.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -377,7 +377,9 @@ func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
|||
if i.Address() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil {
|
||||
return err
|
||||
}
|
||||
ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
|
||||
return nlh.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
@ -386,6 +388,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error
|
|||
if i.AddressIPv6() == nil {
|
||||
return nil
|
||||
}
|
||||
if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
|
||||
return err
|
||||
}
|
||||
ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
|
||||
return nlh.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
@ -442,3 +447,19 @@ func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error
|
|||
|
||||
return err
|
||||
}
|
||||
|
||||
func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error {
|
||||
routes, err := nlh.RouteList(nil, family)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, route := range routes {
|
||||
if route.Dst != nil {
|
||||
if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) {
|
||||
return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s",
|
||||
address, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -74,8 +75,7 @@ func newInfo(hnd *netlink.Handle, t *testing.T) (Sandbox, error) {
|
|||
intf1.address = addr
|
||||
intf1.address.IP = ip4
|
||||
|
||||
// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
|
||||
ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
|
||||
ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -225,3 +225,65 @@ func TestDisableIPv6DAD(t *testing.T) {
|
|||
t.Fatalf("Unexpected interface flags: 0x%x. Expected to contain 0x%x", addrList[0].Flags, syscall.IFA_F_NODAD)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetInterfaceIP(t *testing.T) {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
||||
ipv4, _ := types.ParseCIDR("172.30.0.33/24")
|
||||
ipv6, _ := types.ParseCIDR("2001:db8::44/64")
|
||||
iface := &nwIface{address: ipv4, addressIPv6: ipv6}
|
||||
|
||||
nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := nlh.LinkAdd(&netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
|
||||
PeerName: "sideB",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
linkA, err := nlh.LinkByName("sideA")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
linkB, err := nlh.LinkByName("sideB")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := nlh.LinkSetUp(linkA); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := nlh.LinkSetUp(linkB); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := setInterfaceIP(nlh, linkA, iface); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := setInterfaceIPv6(nlh, linkA, iface); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = setInterfaceIP(nlh, linkB, iface)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected route conflict error, but succeeded")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "conflicts with existing route") {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = setInterfaceIPv6(nlh, linkB, iface)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected route conflict error, but succeeded")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "conflicts with existing route") {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/config"
|
||||
|
@ -10,7 +11,7 @@ import (
|
|||
"github.com/docker/libnetwork/testutils"
|
||||
)
|
||||
|
||||
func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network) {
|
||||
func getTestEnv(t *testing.T, numNetworks int) (NetworkController, []Network) {
|
||||
netType := "bridge"
|
||||
|
||||
option := options.Generic{
|
||||
|
@ -28,37 +29,31 @@ func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network)
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if empty {
|
||||
return c, nil, nil
|
||||
if numNetworks == 0 {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
name1 := "test_nw_1"
|
||||
netOption1 := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": name1,
|
||||
},
|
||||
}
|
||||
n1, err := c.NewNetwork(netType, name1, "", NetworkOptionGeneric(netOption1))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
nwList := make([]Network, 0, numNetworks)
|
||||
for i := 0; i < numNetworks; i++ {
|
||||
name := fmt.Sprintf("test_nw_%d", i)
|
||||
netOption := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": name,
|
||||
},
|
||||
}
|
||||
n, err := c.NewNetwork(netType, name, "", NetworkOptionGeneric(netOption))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nwList = append(nwList, n)
|
||||
}
|
||||
|
||||
name2 := "test_nw_2"
|
||||
netOption2 := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": name2,
|
||||
},
|
||||
}
|
||||
n2, err := c.NewNetwork(netType, name2, "", NetworkOptionGeneric(netOption2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return c, n1, n2
|
||||
return c, nwList
|
||||
}
|
||||
|
||||
func TestSandboxAddEmpty(t *testing.T) {
|
||||
c, _, _ := getTestEnv(t, true)
|
||||
c, _ := getTestEnv(t, 0)
|
||||
ctrlr := c.(*controller)
|
||||
|
||||
sbx, err := ctrlr.NewSandbox("sandbox0")
|
||||
|
@ -82,7 +77,7 @@ func TestSandboxAddMultiPrio(t *testing.T) {
|
|||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
c, nw, _ := getTestEnv(t, false)
|
||||
c, nws := getTestEnv(t, 3)
|
||||
ctrlr := c.(*controller)
|
||||
|
||||
sbx, err := ctrlr.NewSandbox("sandbox1")
|
||||
|
@ -91,15 +86,15 @@ func TestSandboxAddMultiPrio(t *testing.T) {
|
|||
}
|
||||
sid := sbx.ID()
|
||||
|
||||
ep1, err := nw.CreateEndpoint("ep1")
|
||||
ep1, err := nws[0].CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep2, err := nw.CreateEndpoint("ep2")
|
||||
ep2, err := nws[1].CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep3, err := nw.CreateEndpoint("ep3")
|
||||
ep3, err := nws[2].CreateEndpoint("ep3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -163,7 +158,7 @@ func TestSandboxAddSamePrio(t *testing.T) {
|
|||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
c, nw1, nw2 := getTestEnv(t, false)
|
||||
c, nws := getTestEnv(t, 2)
|
||||
|
||||
ctrlr := c.(*controller)
|
||||
|
||||
|
@ -173,11 +168,11 @@ func TestSandboxAddSamePrio(t *testing.T) {
|
|||
}
|
||||
sid := sbx.ID()
|
||||
|
||||
ep1, err := nw1.CreateEndpoint("ep1")
|
||||
ep1, err := nws[0].CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep2, err := nw2.CreateEndpoint("ep2")
|
||||
ep2, err := nws[1].CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue