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:
parent
f5c1c78179
commit
4ceec05f1b
5 changed files with 72 additions and 24 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue