2015-02-19 17:21:42 -08:00
|
|
|
package bridge
|
|
|
|
|
2015-02-19 22:21:05 -08:00
|
|
|
import (
|
|
|
|
"net"
|
2015-04-13 18:40:42 +00:00
|
|
|
"strings"
|
2015-04-10 11:59:05 -07:00
|
|
|
"sync"
|
2015-02-19 22:21:05 -08:00
|
|
|
|
2015-04-13 18:40:42 +00:00
|
|
|
"github.com/docker/libnetwork/driverapi"
|
2015-04-10 11:59:05 -07:00
|
|
|
"github.com/docker/libnetwork/ipallocator"
|
2015-04-14 00:12:40 -04:00
|
|
|
"github.com/docker/libnetwork/netutils"
|
2015-04-13 18:40:42 +00:00
|
|
|
"github.com/docker/libnetwork/pkg/options"
|
2015-04-10 11:59:05 -07:00
|
|
|
"github.com/docker/libnetwork/portmapper"
|
2015-04-20 08:44:06 -07:00
|
|
|
"github.com/docker/libnetwork/sandbox"
|
|
|
|
"github.com/docker/libnetwork/types"
|
2015-04-13 18:40:42 +00:00
|
|
|
"github.com/vishvananda/netlink"
|
2015-02-19 22:21:05 -08:00
|
|
|
)
|
2015-02-19 17:21:42 -08:00
|
|
|
|
2015-02-22 17:24:22 -08:00
|
|
|
const (
|
2015-04-23 10:49:57 -07:00
|
|
|
networkType = "bridge"
|
2015-04-14 00:12:40 -04:00
|
|
|
vethPrefix = "veth"
|
|
|
|
vethLen = 7
|
|
|
|
containerVeth = "eth0"
|
2015-02-22 17:24:22 -08:00
|
|
|
)
|
2015-02-19 17:21:42 -08:00
|
|
|
|
2015-04-10 11:59:05 -07:00
|
|
|
var (
|
|
|
|
ipAllocator *ipallocator.IPAllocator
|
|
|
|
portMapper *portmapper.PortMapper
|
|
|
|
)
|
|
|
|
|
2015-04-23 10:49:57 -07:00
|
|
|
// Configuration info for the "bridge" driver.
|
2015-02-22 17:24:22 -08:00
|
|
|
type Configuration struct {
|
2015-04-15 05:25:42 +00:00
|
|
|
BridgeName string
|
|
|
|
AddressIPv4 *net.IPNet
|
|
|
|
FixedCIDR *net.IPNet
|
|
|
|
FixedCIDRv6 *net.IPNet
|
|
|
|
EnableIPv6 bool
|
|
|
|
EnableIPTables bool
|
|
|
|
EnableIPMasquerade bool
|
|
|
|
EnableICC bool
|
|
|
|
EnableIPForwarding bool
|
|
|
|
AllowNonDefaultBridge bool
|
2015-02-19 17:21:42 -08:00
|
|
|
}
|
|
|
|
|
2015-04-13 18:40:42 +00:00
|
|
|
type bridgeEndpoint struct {
|
2015-04-20 04:23:04 -07:00
|
|
|
id types.UUID
|
|
|
|
port *sandbox.Interface
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type bridgeNetwork struct {
|
2015-04-20 04:23:04 -07:00
|
|
|
id types.UUID
|
|
|
|
bridge *bridgeInterface // The bridge's L3 interface
|
|
|
|
endpoints map[string]*bridgeEndpoint // key: sandbox id
|
2015-04-13 18:40:42 +00:00
|
|
|
sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
type driver struct {
|
2015-04-15 05:25:42 +00:00
|
|
|
config *Configuration
|
2015-04-13 18:40:42 +00:00
|
|
|
network *bridgeNetwork
|
|
|
|
sync.Mutex
|
|
|
|
}
|
2015-03-05 19:04:07 +00:00
|
|
|
|
2015-02-19 22:21:05 -08:00
|
|
|
func init() {
|
2015-04-10 11:59:05 -07:00
|
|
|
ipAllocator = ipallocator.New()
|
2015-04-16 15:16:11 -07:00
|
|
|
portMapper = portmapper.New()
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// New provides a new instance of bridge driver
|
2015-04-13 18:40:42 +00:00
|
|
|
func New() (string, driverapi.Driver) {
|
|
|
|
return networkType, &driver{}
|
2015-02-22 17:24:22 -08:00
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
func (n *bridgeNetwork) getEndpoint(eid types.UUID) (string, *bridgeEndpoint, error) {
|
|
|
|
n.Lock()
|
|
|
|
defer n.Unlock()
|
|
|
|
|
|
|
|
if eid == "" {
|
|
|
|
return "", nil, InvalidEndpointIDError(eid)
|
|
|
|
}
|
|
|
|
|
|
|
|
for sk, ep := range n.endpoints {
|
|
|
|
if ep.id == eid {
|
|
|
|
return sk, ep, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", nil, nil
|
|
|
|
}
|
|
|
|
|
2015-04-15 05:25:42 +00:00
|
|
|
func (d *driver) Config(option interface{}) error {
|
|
|
|
var config *Configuration
|
|
|
|
|
|
|
|
d.Lock()
|
|
|
|
defer d.Unlock()
|
|
|
|
|
|
|
|
if d.config != nil {
|
2015-04-17 02:47:12 +00:00
|
|
|
return ErrConfigExists
|
2015-04-15 05:25:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch opt := option.(type) {
|
|
|
|
case options.Generic:
|
|
|
|
opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
|
|
|
|
if err != nil {
|
2015-04-17 02:47:12 +00:00
|
|
|
return err
|
2015-04-15 05:25:42 +00:00
|
|
|
}
|
|
|
|
config = opaqueConfig.(*Configuration)
|
|
|
|
case *Configuration:
|
|
|
|
config = opt
|
|
|
|
}
|
|
|
|
|
|
|
|
d.config = config
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-23 10:49:57 -07:00
|
|
|
// Create a new network using bridge plugin
|
2015-04-20 08:44:06 -07:00
|
|
|
func (d *driver) CreateNetwork(id types.UUID, option interface{}) error {
|
2015-04-20 04:23:04 -07:00
|
|
|
var err error
|
2015-04-13 18:40:42 +00:00
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Driver must be configured
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Lock()
|
2015-04-15 05:25:42 +00:00
|
|
|
if d.config == nil {
|
|
|
|
d.Unlock()
|
2015-04-17 02:47:12 +00:00
|
|
|
return ErrInvalidConfig
|
2015-04-15 05:25:42 +00:00
|
|
|
}
|
|
|
|
config := d.config
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Sanity checks
|
2015-04-13 18:40:42 +00:00
|
|
|
if d.network != nil {
|
|
|
|
d.Unlock()
|
2015-04-17 02:47:12 +00:00
|
|
|
return ErrNetworkExists
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// Create and set network handler in driver
|
|
|
|
d.network = &bridgeNetwork{id: id, endpoints: make(map[string]*bridgeEndpoint)}
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Unlock()
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// On failure make sure to reset driver network handler to nil
|
2015-04-13 18:40:42 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
d.Lock()
|
|
|
|
d.network = nil
|
|
|
|
d.Unlock()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Create or retrieve the bridge L3 interface
|
2015-04-13 18:40:42 +00:00
|
|
|
bridgeIface := newInterface(config)
|
2015-04-20 04:23:04 -07:00
|
|
|
d.network.bridge = bridgeIface
|
|
|
|
|
|
|
|
// Prepare the bridge setup configuration
|
2015-04-15 05:25:42 +00:00
|
|
|
bridgeSetup := newBridgeSetup(config, bridgeIface)
|
2015-02-22 17:24:22 -08:00
|
|
|
|
|
|
|
// If the bridge interface doesn't exist, we need to start the setup steps
|
|
|
|
// by creating a new device and assigning it an IPv4 address.
|
2015-04-13 18:40:42 +00:00
|
|
|
bridgeAlreadyExists := bridgeIface.exists()
|
2015-02-22 17:24:22 -08:00
|
|
|
if !bridgeAlreadyExists {
|
2015-03-04 13:25:43 -08:00
|
|
|
bridgeSetup.queueStep(setupDevice)
|
|
|
|
bridgeSetup.queueStep(setupBridgeIPv4)
|
2015-02-22 17:24:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Conditionnally queue setup steps depending on configuration values.
|
2015-02-22 17:58:52 -08:00
|
|
|
for _, step := range []struct {
|
2015-02-22 17:24:22 -08:00
|
|
|
Condition bool
|
2015-03-04 13:25:43 -08:00
|
|
|
Fn setupStep
|
2015-02-22 17:24:22 -08:00
|
|
|
}{
|
|
|
|
// Enable IPv6 on the bridge if required. We do this even for a
|
|
|
|
// previously existing bridge, as it may be here from a previous
|
|
|
|
// installation where IPv6 wasn't supported yet and needs to be
|
|
|
|
// assigned an IPv6 link-local address.
|
2015-03-04 13:25:43 -08:00
|
|
|
{config.EnableIPv6, setupBridgeIPv6},
|
2015-02-22 17:24:22 -08:00
|
|
|
|
|
|
|
// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
|
|
|
|
// the case of a previously existing device.
|
2015-04-16 05:02:21 +00:00
|
|
|
{bridgeAlreadyExists, setupVerifyAndReconcile},
|
2015-02-22 17:24:22 -08:00
|
|
|
|
|
|
|
// Setup the bridge to allocate containers IPv4 addresses in the
|
|
|
|
// specified subnet.
|
2015-03-04 13:25:43 -08:00
|
|
|
{config.FixedCIDR != nil, setupFixedCIDRv4},
|
2015-02-22 17:24:22 -08:00
|
|
|
|
|
|
|
// Setup the bridge to allocate containers global IPv6 addresses in the
|
|
|
|
// specified subnet.
|
2015-03-04 13:25:43 -08:00
|
|
|
{config.FixedCIDRv6 != nil, setupFixedCIDRv6},
|
2015-02-22 17:24:22 -08:00
|
|
|
|
|
|
|
// Setup IPTables.
|
2015-03-04 13:25:43 -08:00
|
|
|
{config.EnableIPTables, setupIPTables},
|
2015-02-22 17:24:22 -08:00
|
|
|
|
|
|
|
// Setup IP forwarding.
|
2015-03-04 13:25:43 -08:00
|
|
|
{config.EnableIPForwarding, setupIPForwarding},
|
2015-02-22 17:58:52 -08:00
|
|
|
} {
|
2015-02-22 17:24:22 -08:00
|
|
|
if step.Condition {
|
2015-03-04 13:25:43 -08:00
|
|
|
bridgeSetup.queueStep(step.Fn)
|
2015-02-22 17:24:22 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply the prepared list of steps, and abort at the first error.
|
2015-03-04 13:25:43 -08:00
|
|
|
bridgeSetup.queueStep(setupDeviceUp)
|
2015-04-13 18:40:42 +00:00
|
|
|
if err = bridgeSetup.apply(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-20 08:44:06 -07:00
|
|
|
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
2015-04-13 18:40:42 +00:00
|
|
|
var err error
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// Get network handler and remove it from driver
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Lock()
|
|
|
|
n := d.network
|
|
|
|
d.network = nil
|
|
|
|
d.Unlock()
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// On failure set network handler back in driver, but
|
|
|
|
// only if is not already taken over by some other thread
|
2015-04-13 18:40:42 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
d.Lock()
|
|
|
|
if d.network == nil {
|
|
|
|
d.network = n
|
|
|
|
}
|
|
|
|
d.Unlock()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Sanity check
|
2015-04-13 18:40:42 +00:00
|
|
|
if n == nil {
|
|
|
|
err = driverapi.ErrNoNetwork
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Cannot remove network if endpoints are still present
|
|
|
|
if len(n.endpoints) != 0 {
|
|
|
|
err = ActiveEndpointsError(n.id)
|
2015-04-13 18:40:42 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Programming
|
2015-04-13 18:40:42 +00:00
|
|
|
err = netlink.LinkDel(n.bridge.Link)
|
2015-04-20 04:23:04 -07:00
|
|
|
|
2015-04-13 18:40:42 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-20 08:44:06 -07:00
|
|
|
func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption interface{}) (*sandbox.Info, error) {
|
2015-04-13 18:40:42 +00:00
|
|
|
var (
|
2015-04-17 15:42:23 -07:00
|
|
|
ipv6Addr *net.IPNet
|
2015-04-13 18:40:42 +00:00
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Get the network handler and make sure it exists
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Lock()
|
|
|
|
n := d.network
|
2015-04-15 05:25:42 +00:00
|
|
|
config := d.config
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Unlock()
|
|
|
|
if n == nil {
|
|
|
|
return nil, driverapi.ErrNoNetwork
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Sanity check
|
2015-04-13 18:40:42 +00:00
|
|
|
n.Lock()
|
|
|
|
if n.id != nid {
|
|
|
|
n.Unlock()
|
2015-04-17 02:47:12 +00:00
|
|
|
return nil, InvalidNetworkIDError(nid)
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
2015-04-20 04:23:04 -07:00
|
|
|
n.Unlock()
|
2015-04-13 18:40:42 +00:00
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Check if endpoint id is good and retrieve correspondent endpoint
|
|
|
|
_, ep, err := n.getEndpoint(eid)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Endpoint with that id exists either on desired or other sandbox
|
|
|
|
if ep != nil {
|
|
|
|
return nil, driverapi.ErrEndpointExists
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if valid sandbox key
|
|
|
|
if sboxKey == "" {
|
|
|
|
return nil, InvalidSandboxIDError(sboxKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if endpoint already exists for this sandbox
|
|
|
|
n.Lock()
|
|
|
|
if _, ok := n.endpoints[sboxKey]; ok {
|
2015-04-13 18:40:42 +00:00
|
|
|
n.Unlock()
|
|
|
|
return nil, driverapi.ErrEndpointExists
|
|
|
|
}
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// Create and add the endpoint
|
|
|
|
endpoint := &bridgeEndpoint{id: eid}
|
|
|
|
n.endpoints[sboxKey] = endpoint
|
2015-04-13 18:40:42 +00:00
|
|
|
n.Unlock()
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// On failure make sure to remove the endpoint
|
2015-04-13 18:40:42 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
n.Lock()
|
2015-04-20 04:23:04 -07:00
|
|
|
delete(n.endpoints, sboxKey)
|
2015-04-13 18:40:42 +00:00
|
|
|
n.Unlock()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Generate a name for what will be the host side pipe interface
|
2015-04-13 18:40:42 +00:00
|
|
|
name1, err := generateIfaceName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Generate a name for what will be the sandbox side pipe interface
|
2015-04-13 18:40:42 +00:00
|
|
|
name2, err := generateIfaceName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Generate and add the interface pipe host <-> sandbox
|
2015-04-13 18:40:42 +00:00
|
|
|
veth := &netlink.Veth{
|
|
|
|
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
|
|
|
PeerName: name2}
|
|
|
|
if err = netlink.LinkAdd(veth); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Get the host side pipe interface handler
|
2015-04-13 18:40:42 +00:00
|
|
|
host, err := netlink.LinkByName(name1)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
netlink.LinkDel(host)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Get the sandbox side pipe interface handler
|
|
|
|
sbox, err := netlink.LinkByName(name2)
|
2015-04-13 18:40:42 +00:00
|
|
|
if err != nil {
|
2015-02-22 17:24:22 -08:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-04-13 18:40:42 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
2015-04-20 04:23:04 -07:00
|
|
|
netlink.LinkDel(sbox)
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Attach host side pipe interface into the bridge
|
2015-04-13 18:40:42 +00:00
|
|
|
if err = netlink.LinkSetMaster(host,
|
2015-04-15 05:25:42 +00:00
|
|
|
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil {
|
2015-04-13 18:40:42 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Reuqest a v4 address for the sandbox side pipe interface
|
2015-04-13 18:40:42 +00:00
|
|
|
ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-04-17 15:42:23 -07:00
|
|
|
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
2015-04-13 18:40:42 +00:00
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Request a v6 address for the sandbox side pipe interface
|
2015-04-15 05:25:42 +00:00
|
|
|
if config.EnableIPv6 {
|
2015-04-13 18:40:42 +00:00
|
|
|
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-04-17 15:42:23 -07:00
|
|
|
ipv6Addr = &net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Store the sandbox side pipe interface
|
|
|
|
// This is needed for cleanup on DeleteEndpoint()
|
2015-04-20 08:44:06 -07:00
|
|
|
intf := &sandbox.Interface{}
|
2015-04-13 18:40:42 +00:00
|
|
|
intf.SrcName = name2
|
2015-04-14 00:12:40 -04:00
|
|
|
intf.DstName = containerVeth
|
2015-04-14 01:36:58 +00:00
|
|
|
intf.Address = ipv4Addr
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// Update endpoint with the sandbox interface info
|
|
|
|
endpoint.port = intf
|
|
|
|
|
|
|
|
// Generate the sandbox info to return
|
|
|
|
sinfo := &sandbox.Info{Interfaces: []*sandbox.Interface{intf}}
|
2015-04-14 01:36:58 +00:00
|
|
|
sinfo.Gateway = n.bridge.bridgeIPv4.IP
|
2015-04-15 05:25:42 +00:00
|
|
|
if config.EnableIPv6 {
|
2015-04-14 01:36:58 +00:00
|
|
|
intf.AddressIPv6 = ipv6Addr
|
|
|
|
sinfo.GatewayIPv6 = n.bridge.bridgeIPv6.IP
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sinfo, nil
|
|
|
|
}
|
|
|
|
|
2015-04-20 08:44:06 -07:00
|
|
|
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
2015-04-13 18:40:42 +00:00
|
|
|
var err error
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Get the network handler and make sure it exists
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Lock()
|
|
|
|
n := d.network
|
2015-04-15 05:25:42 +00:00
|
|
|
config := d.config
|
2015-04-13 18:40:42 +00:00
|
|
|
d.Unlock()
|
|
|
|
if n == nil {
|
|
|
|
return driverapi.ErrNoNetwork
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Sanity Check
|
2015-04-13 18:40:42 +00:00
|
|
|
n.Lock()
|
|
|
|
if n.id != nid {
|
|
|
|
n.Unlock()
|
2015-04-17 02:47:12 +00:00
|
|
|
return InvalidNetworkIDError(nid)
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
2015-04-20 04:23:04 -07:00
|
|
|
n.Unlock()
|
2015-04-13 18:40:42 +00:00
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Check endpoint id and if an endpoint is actually there
|
|
|
|
sboxKey, ep, err := n.getEndpoint(eid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
2015-04-20 04:23:04 -07:00
|
|
|
if ep == nil {
|
|
|
|
return EndpointNotFoundError(eid)
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Remove it
|
|
|
|
n.Lock()
|
|
|
|
delete(n.endpoints, sboxKey)
|
2015-04-13 18:40:42 +00:00
|
|
|
n.Unlock()
|
2015-04-20 04:23:04 -07:00
|
|
|
|
|
|
|
// On failure make sure to set back ep in n.endpoints, but only
|
|
|
|
// if it hasn't been taken over already by some other thread.
|
2015-04-13 18:40:42 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
n.Lock()
|
2015-04-20 04:23:04 -07:00
|
|
|
if _, ok := n.endpoints[sboxKey]; !ok {
|
|
|
|
n.endpoints[sboxKey] = ep
|
2015-04-13 18:40:42 +00:00
|
|
|
}
|
|
|
|
n.Unlock()
|
|
|
|
}
|
|
|
|
}()
|
2015-02-22 17:24:22 -08:00
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Release the v4 address allocated to this endpoint's sandbox interface
|
|
|
|
err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.port.Address.IP)
|
2015-04-13 18:40:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Release the v6 address allocated to this endpoint's sandbox interface
|
2015-04-15 05:25:42 +00:00
|
|
|
if config.EnableIPv6 {
|
2015-04-20 04:23:04 -07:00
|
|
|
err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, ep.port.AddressIPv6.IP)
|
2015-04-13 18:40:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-20 04:23:04 -07:00
|
|
|
// Try removal of link. Discard error: link pair might have
|
|
|
|
// already been deleted by sandbox delete.
|
|
|
|
link, err := netlink.LinkByName(ep.port.SrcName)
|
|
|
|
if err == nil {
|
|
|
|
netlink.LinkDel(link)
|
|
|
|
}
|
|
|
|
|
2015-04-13 18:40:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-14 00:12:40 -04:00
|
|
|
// Generates a name to be used for a virtual ethernet
|
|
|
|
// interface. The name is constructed by 'veth' appended
|
|
|
|
// by a randomly generated hex value. (example: veth0f60e2c)
|
2015-04-13 18:40:42 +00:00
|
|
|
func generateIfaceName() (string, error) {
|
2015-04-14 00:12:40 -04:00
|
|
|
for i := 0; i < 3; i++ {
|
|
|
|
name, err := netutils.GenerateRandomName(vethPrefix, vethLen)
|
2015-04-13 18:40:42 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if _, err := net.InterfaceByName(name); err != nil {
|
|
|
|
if strings.Contains(err.Error(), "no such") {
|
|
|
|
return name, nil
|
|
|
|
}
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
2015-04-17 02:47:12 +00:00
|
|
|
return "", ErrIfaceName
|
2015-02-22 17:24:22 -08:00
|
|
|
}
|