소스 검색

Add support to add bridge to the sandbox.

Added support to add a bridge the same way as any other
interface into the namespace. The only difference is linux
does not support creating the bridge in one namespace and
moving it into another namespace. So for a bridge the sandbox
code also does the creation of the bridge inside the sandbox.
Also added an optional argument to interface which can now
select one of the already existing interfaces as it's master.
For this option to succeed the master interface should be of type
bridge.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
Jana Radhakrishnan 10 년 전
부모
커밋
4ceec05f1b

+ 29 - 0
libnetwork/sandbox/interface_linux.go

@@ -15,9 +15,12 @@ type IfaceOption func(i *nwIface)
 type nwIface struct {
 type nwIface struct {
 	srcName     string
 	srcName     string
 	dstName     string
 	dstName     string
+	master      string
+	dstMaster   string
 	address     *net.IPNet
 	address     *net.IPNet
 	addressIPv6 *net.IPNet
 	addressIPv6 *net.IPNet
 	routes      []*net.IPNet
 	routes      []*net.IPNet
+	bridge      bool
 	ns          *networkNamespace
 	ns          *networkNamespace
 	sync.Mutex
 	sync.Mutex
 }
 }
@@ -169,6 +172,14 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
 	i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
 	i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
 	i.processInterfaceOptions(options...)
 	i.processInterfaceOptions(options...)
 
 
+	if i.master != "" {
+		i.dstMaster = n.findDstMaster(i.master)
+		if i.dstMaster == "" {
+			return fmt.Errorf("could not find an appropriate master %q for %q",
+				i.master, i.srcName)
+		}
+	}
+
 	n.Lock()
 	n.Lock()
 	i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
 	i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
 	n.nextIfIndex++
 	n.nextIfIndex++
@@ -176,6 +187,12 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
 	n.Unlock()
 	n.Unlock()
 
 
 	return nsInvoke(path, func(nsFD int) error {
 	return nsInvoke(path, func(nsFD int) error {
+		// If it is a bridge interface we have to create the bridge inside
+		// the namespace so don't try to lookup the interface using srcName
+		if i.bridge {
+			return nil
+		}
+
 		// Find the network interface identified by the SrcName attribute.
 		// Find the network interface identified by the SrcName attribute.
 		iface, err := netlink.LinkByName(i.srcName)
 		iface, err := netlink.LinkByName(i.srcName)
 		if err != nil {
 		if err != nil {
@@ -189,6 +206,18 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
 
 
 		return nil
 		return nil
 	}, func(callerFD int) error {
 	}, func(callerFD int) error {
+		if i.bridge {
+			link := &netlink.Bridge{
+				LinkAttrs: netlink.LinkAttrs{
+					Name: i.srcName,
+				},
+			}
+
+			if err := netlink.LinkAdd(link); err != nil {
+				return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
+			}
+		}
+
 		// Find the network interface identified by the SrcName attribute.
 		// Find the network interface identified by the SrcName attribute.
 		iface, err := netlink.LinkByName(i.srcName)
 		iface, err := netlink.LinkByName(i.srcName)
 		if err != nil {
 		if err != nil {

+ 12 - 0
libnetwork/sandbox/options_linux.go

@@ -10,6 +10,18 @@ func (i *nwIface) processInterfaceOptions(options ...IfaceOption) {
 	}
 	}
 }
 }
 
 
+func (n *networkNamespace) Bridge(isBridge bool) IfaceOption {
+	return func(i *nwIface) {
+		i.bridge = isBridge
+	}
+}
+
+func (n *networkNamespace) Master(name string) IfaceOption {
+	return func(i *nwIface) {
+		i.master = name
+	}
+}
+
 func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
 func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
 	return func(i *nwIface) {
 	return func(i *nwIface) {
 		i.address = addr
 		i.address = addr

+ 14 - 0
libnetwork/sandbox/sandbox.go

@@ -49,12 +49,20 @@ type Sandbox interface {
 
 
 // IfaceOptionSetter interface defines the option setter methods for interface options.
 // IfaceOptionSetter interface defines the option setter methods for interface options.
 type IfaceOptionSetter interface {
 type IfaceOptionSetter interface {
+	// Bridge returns an option setter to set if the interface is a bridge.
+	Bridge(bool) IfaceOption
+
 	// Address returns an option setter to set IPv4 address.
 	// Address returns an option setter to set IPv4 address.
 	Address(*net.IPNet) IfaceOption
 	Address(*net.IPNet) IfaceOption
 
 
 	// Address returns an option setter to set IPv6 address.
 	// Address returns an option setter to set IPv6 address.
 	AddressIPv6(*net.IPNet) IfaceOption
 	AddressIPv6(*net.IPNet) IfaceOption
 
 
+	// Master returns an option setter to set the master interface if any for this
+	// interface. The master interface name should refer to the srcname of a
+	// previously added interface of type bridge.
+	Master(string) IfaceOption
+
 	// Address returns an option setter to set interface routes.
 	// Address returns an option setter to set interface routes.
 	Routes([]*net.IPNet) IfaceOption
 	Routes([]*net.IPNet) IfaceOption
 }
 }
@@ -106,6 +114,12 @@ type Interface interface {
 	// IP routes for the interface.
 	// IP routes for the interface.
 	Routes() []*net.IPNet
 	Routes() []*net.IPNet
 
 
+	// Bridge returns true if the interface is a bridge
+	Bridge() bool
+
+	// Master returns the srcname of the master interface for this interface.
+	Master() string
+
 	// Remove an interface from the sandbox by renaming to original name
 	// Remove an interface from the sandbox by renaming to original name
 	// and moving it out of the sandbox.
 	// and moving it out of the sandbox.
 	Remove() error
 	Remove() error

+ 10 - 20
libnetwork/sandbox/sandbox_linux_test.go

@@ -76,6 +76,11 @@ func newInfo(t *testing.T) (Sandbox, error) {
 
 
 	intf1.routes = []*net.IPNet{route}
 	intf1.routes = []*net.IPNet{route}
 
 
+	intf2 := &nwIface{}
+	intf2.srcName = "testbridge"
+	intf2.dstName = sboxIfaceName
+	intf2.bridge = true
+
 	veth = &netlink.Veth{
 	veth = &netlink.Veth{
 		LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
 		LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
 		PeerName:  vethName4}
 		PeerName:  vethName4}
@@ -84,27 +89,12 @@ func newInfo(t *testing.T) (Sandbox, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	intf2 := &nwIface{}
-	intf2.srcName = vethName4
-	intf2.dstName = sboxIfaceName
-
-	ip4, addr, err = net.ParseCIDR("192.168.2.100/24")
-	if err != nil {
-		return nil, err
-	}
-	intf2.address = addr
-	intf2.address.IP = ip4
-
-	// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
-	ip6, addrv6, err = net.ParseCIDR("fe80::3/64")
-
-	if err != nil {
-		return nil, err
-	}
-	intf2.addressIPv6 = addrv6
-	intf2.addressIPv6.IP = ip6
+	intf3 := &nwIface{}
+	intf3.srcName = vethName4
+	intf3.dstName = sboxIfaceName
+	intf3.master = "testbridge"
 
 
-	info := &networkNamespace{iFaces: []*nwIface{intf1, intf2}}
+	info := &networkNamespace{iFaces: []*nwIface{intf1, intf2, intf3}}
 
 
 	info.gw = net.ParseIP("192.168.1.1")
 	info.gw = net.ParseIP("192.168.1.1")
 	// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
 	// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")

+ 7 - 4
libnetwork/sandbox/sandbox_test.go

@@ -41,6 +41,7 @@ func TestSandboxCreate(t *testing.T) {
 
 
 	for _, i := range tbox.Info().Interfaces() {
 	for _, i := range tbox.Info().Interfaces() {
 		err = s.AddInterface(i.SrcName(), i.DstName(),
 		err = s.AddInterface(i.SrcName(), i.DstName(),
+			tbox.InterfaceOptions().Bridge(i.Bridge()),
 			tbox.InterfaceOptions().Address(i.Address()),
 			tbox.InterfaceOptions().Address(i.Address()),
 			tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6()))
 			tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6()))
 		if err != nil {
 		if err != nil {
@@ -61,7 +62,7 @@ func TestSandboxCreate(t *testing.T) {
 	}
 	}
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
-	verifySandbox(t, s, []string{"0", "1"})
+	verifySandbox(t, s, []string{"0", "1", "2"})
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
 	s.Destroy()
 	s.Destroy()
@@ -134,6 +135,7 @@ func TestAddRemoveInterface(t *testing.T) {
 
 
 	for _, i := range tbox.Info().Interfaces() {
 	for _, i := range tbox.Info().Interfaces() {
 		err = s.AddInterface(i.SrcName(), i.DstName(),
 		err = s.AddInterface(i.SrcName(), i.DstName(),
+			tbox.InterfaceOptions().Bridge(i.Bridge()),
 			tbox.InterfaceOptions().Address(i.Address()),
 			tbox.InterfaceOptions().Address(i.Address()),
 			tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6()))
 			tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6()))
 		if err != nil {
 		if err != nil {
@@ -142,7 +144,7 @@ func TestAddRemoveInterface(t *testing.T) {
 		runtime.LockOSThread()
 		runtime.LockOSThread()
 	}
 	}
 
 
-	verifySandbox(t, s, []string{"0", "1"})
+	verifySandbox(t, s, []string{"0", "1", "2"})
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
 	interfaces := s.Info().Interfaces()
 	interfaces := s.Info().Interfaces()
@@ -151,18 +153,19 @@ func TestAddRemoveInterface(t *testing.T) {
 	}
 	}
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
-	verifySandbox(t, s, []string{"1"})
+	verifySandbox(t, s, []string{"1", "2"})
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
 	i := tbox.Info().Interfaces()[0]
 	i := tbox.Info().Interfaces()[0]
 	if err := s.AddInterface(i.SrcName(), i.DstName(),
 	if err := s.AddInterface(i.SrcName(), i.DstName(),
+		tbox.InterfaceOptions().Bridge(i.Bridge()),
 		tbox.InterfaceOptions().Address(i.Address()),
 		tbox.InterfaceOptions().Address(i.Address()),
 		tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6())); err != nil {
 		tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6())); err != nil {
 		t.Fatalf("Failed to add interfaces to sandbox: %v", err)
 		t.Fatalf("Failed to add interfaces to sandbox: %v", err)
 	}
 	}
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
-	verifySandbox(t, s, []string{"1", "2"})
+	verifySandbox(t, s, []string{"1", "2", "3"})
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
 	s.Destroy()
 	s.Destroy()