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>
This commit is contained in:
Jana Radhakrishnan 2015-06-04 23:45:04 -07:00
parent f5c1c78179
commit 4ceec05f1b
5 changed files with 72 additions and 24 deletions

View file

@ -15,9 +15,12 @@ type IfaceOption func(i *nwIface)
type nwIface struct {
srcName string
dstName string
master string
dstMaster string
address *net.IPNet
addressIPv6 *net.IPNet
routes []*net.IPNet
bridge bool
ns *networkNamespace
sync.Mutex
}
@ -169,6 +172,14 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
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()
i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
n.nextIfIndex++
@ -176,6 +187,12 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
n.Unlock()
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.
iface, err := netlink.LinkByName(i.srcName)
if err != nil {
@ -189,6 +206,18 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
return nil
}, 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.
iface, err := netlink.LinkByName(i.srcName)
if err != nil {

View file

@ -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 {
return func(i *nwIface) {
i.address = addr

View file

@ -49,12 +49,20 @@ type Sandbox interface {
// IfaceOptionSetter interface defines the option setter methods for interface options.
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(*net.IPNet) IfaceOption
// Address returns an option setter to set IPv6 address.
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.
Routes([]*net.IPNet) IfaceOption
}
@ -106,6 +114,12 @@ type Interface interface {
// IP routes for the interface.
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
// and moving it out of the sandbox.
Remove() error

View file

@ -76,6 +76,11 @@ func newInfo(t *testing.T) (Sandbox, error) {
intf1.routes = []*net.IPNet{route}
intf2 := &nwIface{}
intf2.srcName = "testbridge"
intf2.dstName = sboxIfaceName
intf2.bridge = true
veth = &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
PeerName: vethName4}
@ -84,27 +89,12 @@ func newInfo(t *testing.T) (Sandbox, error) {
return nil, err
}
intf2 := &nwIface{}
intf2.srcName = vethName4
intf2.dstName = sboxIfaceName
intf3 := &nwIface{}
intf3.srcName = vethName4
intf3.dstName = sboxIfaceName
intf3.master = "testbridge"
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
info := &networkNamespace{iFaces: []*nwIface{intf1, intf2}}
info := &networkNamespace{iFaces: []*nwIface{intf1, intf2, intf3}}
info.gw = net.ParseIP("192.168.1.1")
// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")

View file

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