Modify driver Join api to only allow dst prefix

Currently the driver api allows the driver to specify the
full interface name for the interface inside the container.
This is not appropriate since the driver does not have the full
view of the sandbox to correcly allocate an unambiguous interface
name. Instead with this PR the driver will be allowed to specify
a prefix for the name and libnetwork and sandbox layers will
disambiguate it with an appropriate suffix.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-05-21 18:04:49 +00:00
parent 5dc21d4a3e
commit 89045ca381
8 changed files with 108 additions and 28 deletions

View File

@ -83,8 +83,8 @@ type InterfaceInfo interface {
// InterfaceNameInfo provides a go interface for the drivers to assign names
// to interfaces.
type InterfaceNameInfo interface {
// SetNames method assigns the srcName and dstName for the interface.
SetNames(srcName, dstName string) error
// SetNames method assigns the srcName and dstPrefix for the interface.
SetNames(srcName, dstPrefix string) error
// ID returns the numerical id that was assigned to the interface by the driver
// CreateEndpoint.

View File

@ -21,7 +21,7 @@ const (
networkType = "bridge"
vethPrefix = "veth"
vethLen = 7
containerVeth = "eth0"
containerVethPrefix = "eth"
maxAllocatePortAttempts = 10
ifaceID = 1
)
@ -545,7 +545,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
// Create the sandbox side pipe interface
intf := &sandbox.Interface{}
intf.SrcName = name2
intf.DstName = containerVeth
intf.DstName = containerVethPrefix
intf.Address = ipv4Addr
if config.EnableIPv6 {

View File

@ -291,7 +291,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
for _, i := range ifaces {
iface := &sandbox.Interface{
SrcName: i.srcName,
DstName: i.dstName,
DstName: i.dstPrefix,
Address: &i.addr,
}
if i.addrv6.IP.To16() != nil {

View File

@ -40,12 +40,12 @@ type InterfaceInfo interface {
}
type endpointInterface struct {
id int
mac net.HardwareAddr
addr net.IPNet
addrv6 net.IPNet
srcName string
dstName string
id int
mac net.HardwareAddr
addr net.IPNet
addrv6 net.IPNet
srcName string
dstPrefix string
}
type endpointJoinInfo struct {
@ -130,9 +130,9 @@ func (i *endpointInterface) AddressIPv6() net.IPNet {
return (*types.GetIPNetCopy(&i.addrv6))
}
func (i *endpointInterface) SetNames(srcName string, dstName string) error {
func (i *endpointInterface) SetNames(srcName string, dstPrefix string) error {
i.srcName = srcName
i.dstName = dstName
i.dstPrefix = dstPrefix
return nil
}

View File

@ -23,6 +23,7 @@ import (
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/options"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
@ -730,6 +731,35 @@ func TestNetworkQuery(t *testing.T) {
const containerID = "valid_container"
func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
origns, err := netns.Get()
if err != nil {
t.Fatalf("Could not get the current netns: %v", err)
}
defer origns.Close()
key := info.SandboxKey()
f, err := os.OpenFile(key, os.O_RDONLY, 0)
if err != nil {
t.Fatalf("Failed to open network namespace path %q: %v", key, err)
}
defer f.Close()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
nsFD := f.Fd()
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err)
}
defer netns.Set(origns)
_, err = netlink.LinkByName("eth0")
if err != nil {
t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
}
}
func TestEndpointJoin(t *testing.T) {
if !netutils.IsRunningInContainer() {
defer netutils.SetupTestNetNS(t)()
@ -786,6 +816,8 @@ func TestEndpointJoin(t *testing.T) {
if info.SandboxKey() == "" {
t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
}
checkSandbox(t, info)
}
func TestEndpointJoinInvalidContainerId(t *testing.T) {

View File

@ -20,8 +20,10 @@ var once sync.Once
// interface. It represents a linux network namespace, and moves an interface
// into it when called on method AddInterface or sets the gateway etc.
type networkNamespace struct {
path string
sinfo *Info
path string
sinfo *Info
nextIfIndex int
sync.Mutex
}
func createBasePath() {
@ -167,6 +169,11 @@ func (n *networkNamespace) RemoveInterface(i *Interface) error {
}
func (n *networkNamespace) AddInterface(i *Interface) error {
n.Lock()
i.DstName = fmt.Sprintf("%s%d", i.DstName, n.nextIfIndex)
n.nextIfIndex++
n.Unlock()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@ -214,7 +221,10 @@ func (n *networkNamespace) AddInterface(i *Interface) error {
return err
}
n.Lock()
n.sinfo.Interfaces = append(n.sinfo.Interfaces, i)
n.Unlock()
return nil
}

View File

@ -20,7 +20,9 @@ type Sandbox interface {
// Add an existing Interface to this sandbox. The operation will rename
// from the Interface SrcName to DstName as it moves, and reconfigure the
// interface according to the specified settings.
// interface according to the specified settings. The caller is expected
// to only provide a prefix for DstName. The AddInterface api will auto-generate
// an appropriate suffix for the DstName to disambiguate.
AddInterface(*Interface) error
// Remove an interface from the sandbox by renamin to original name
@ -62,7 +64,9 @@ type Interface struct {
SrcName string
// The name that will be assigned to the interface once moves inside a
// network namespace.
// network namespace. When the caller passes in a DstName, it is only
// expected to pass a prefix. The name will modified with an appropriately
// auto-generated suffix.
DstName string
// IPv4 address for the interface.

View File

@ -15,6 +15,8 @@ import (
const (
vethName1 = "wierdlongname1"
vethName2 = "wierdlongname2"
vethName3 = "wierdlongname3"
vethName4 = "wierdlongname4"
sboxIfaceName = "containername"
)
@ -36,33 +38,59 @@ func newInfo(t *testing.T) (*Info, error) {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
PeerName: vethName2}
err := netlink.LinkAdd(veth)
if err != nil {
if err := netlink.LinkAdd(veth); err != nil {
return nil, err
}
// Store the sandbox side pipe interface
// This is needed for cleanup on DeleteEndpoint()
intf := &Interface{}
intf.SrcName = vethName2
intf.DstName = sboxIfaceName
intf1 := &Interface{}
intf1.SrcName = vethName2
intf1.DstName = sboxIfaceName
ip4, addr, err := net.ParseCIDR("192.168.1.100/24")
if err != nil {
return nil, err
}
intf.Address = addr
intf.Address.IP = ip4
intf1.Address = addr
intf1.Address.IP = ip4
// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
if err != nil {
return nil, err
}
intf.AddressIPv6 = addrv6
intf.AddressIPv6.IP = ip6
intf1.AddressIPv6 = addrv6
intf1.AddressIPv6.IP = ip6
sinfo := &Info{Interfaces: []*Interface{intf}}
veth = &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
PeerName: vethName4}
if err := netlink.LinkAdd(veth); err != nil {
return nil, err
}
intf2 := &Interface{}
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
sinfo := &Info{Interfaces: []*Interface{intf1, intf2}}
sinfo.Gateway = net.ParseIP("192.168.1.1")
// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
sinfo.GatewayIPv6 = net.ParseIP("fe80::1")
@ -97,7 +125,13 @@ func verifySandbox(t *testing.T, s Sandbox) {
}
defer netns.Set(origns)
_, err = netlink.LinkByName(sboxIfaceName)
_, err = netlink.LinkByName(sboxIfaceName + "0")
if err != nil {
t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
err)
}
_, err = netlink.LinkByName(sboxIfaceName + "1")
if err != nil {
t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
err)