1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/libnetwork/sandbox/route_linux.go
Jana Radhakrishnan 1ac72c85cb Add LeaveAll support
Currently container can join one endpoint when it is started.
More endpoints can be attached at a later point in time. But
when that happens this attachment should only have meaning
only as long as the container is alive. The attachment should
lose it's meaning when the container goes away. Cuurently there
is no way for the container management code to tell libnetwork
to detach the container from all attached endpoints. This PR
provides an additional API `LeaveAll` which adds this
functionality,

To facilitate this and make the sanbox lifecycle consistent
some slight changes have been made to the behavior of sandbox
management code. The sandbox is no longer destroyed when the
last endpoint is detached from the container. Instead the sandbox
ie kept alive and can only be destroyed with a `LeaveAll` call.
This gives better control of sandbox lifecycle by the container
management code and the sandbox doesn't get destroyed from under
the carpet while the container is still using it.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
2015-06-19 18:55:26 -07:00

198 lines
4.1 KiB
Go

package sandbox
import (
"fmt"
"net"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
)
func (n *networkNamespace) Gateway() net.IP {
n.Lock()
defer n.Unlock()
return n.gw
}
func (n *networkNamespace) GatewayIPv6() net.IP {
n.Lock()
defer n.Unlock()
return n.gwv6
}
func (n *networkNamespace) StaticRoutes() []*types.StaticRoute {
n.Lock()
defer n.Unlock()
routes := make([]*types.StaticRoute, len(n.staticRoutes))
for i, route := range n.staticRoutes {
r := route.GetCopy()
routes[i] = r
}
return routes
}
func (n *networkNamespace) setGateway(gw net.IP) {
n.Lock()
n.gw = gw
n.Unlock()
}
func (n *networkNamespace) setGatewayIPv6(gwv6 net.IP) {
n.Lock()
n.gwv6 = gwv6
n.Unlock()
}
func (n *networkNamespace) SetGateway(gw net.IP) error {
// Silently return if the gateway is empty
if len(gw) == 0 {
return nil
}
err := programGateway(n.nsPath(), gw, true)
if err == nil {
n.setGateway(gw)
}
return err
}
func (n *networkNamespace) UnsetGateway() error {
gw := n.Gateway()
// Silently return if the gateway is empty
if len(gw) == 0 {
return nil
}
err := programGateway(n.nsPath(), gw, false)
if err == nil {
n.setGateway(net.IP{})
}
return err
}
func programGateway(path string, gw net.IP, isAdd bool) error {
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
gwRoutes, err := netlink.RouteGet(gw)
if err != nil {
return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
}
if isAdd {
return netlink.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gw,
})
}
return netlink.RouteDel(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gw,
})
})
}
// Program a route in to the namespace routing table.
func programRoute(path string, dest *net.IPNet, nh net.IP) error {
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
gwRoutes, err := netlink.RouteGet(nh)
if err != nil {
return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
}
return netlink.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gwRoutes[0].Gw,
Dst: dest,
})
})
}
// Delete a route from the namespace routing table.
func removeRoute(path string, dest *net.IPNet, nh net.IP) error {
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
gwRoutes, err := netlink.RouteGet(nh)
if err != nil {
return fmt.Errorf("route for the next hop could not be found: %v", err)
}
return netlink.RouteDel(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gwRoutes[0].Gw,
Dst: dest,
})
})
}
func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error {
// Silently return if the gateway is empty
if len(gwv6) == 0 {
return nil
}
err := programGateway(n.nsPath(), gwv6, true)
if err == nil {
n.SetGatewayIPv6(gwv6)
}
return err
}
func (n *networkNamespace) UnsetGatewayIPv6() error {
gwv6 := n.GatewayIPv6()
// Silently return if the gateway is empty
if len(gwv6) == 0 {
return nil
}
err := programGateway(n.nsPath(), gwv6, false)
if err == nil {
n.Lock()
n.gwv6 = net.IP{}
n.Unlock()
}
return err
}
func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
err := programRoute(n.nsPath(), r.Destination, r.NextHop)
if err == nil {
n.Lock()
n.staticRoutes = append(n.staticRoutes, r)
n.Unlock()
}
return err
}
func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error {
n.Lock()
err := removeRoute(n.nsPath(), r.Destination, r.NextHop)
if err == nil {
n.Lock()
lastIndex := len(n.staticRoutes) - 1
for i, v := range n.staticRoutes {
if v == r {
// Overwrite the route we're removing with the last element
n.staticRoutes[i] = n.staticRoutes[lastIndex]
// Shorten the slice to trim the extra element
n.staticRoutes = n.staticRoutes[:lastIndex]
break
}
}
n.Unlock()
}
return err
}