2015-04-13 14:40:42 -04:00
|
|
|
package sandbox
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
2015-04-23 20:37:19 -04:00
|
|
|
"os"
|
|
|
|
"runtime"
|
2015-04-13 14:40:42 -04:00
|
|
|
|
|
|
|
"github.com/vishvananda/netlink"
|
2015-04-23 20:37:19 -04:00
|
|
|
"github.com/vishvananda/netns"
|
2015-04-13 14:40:42 -04:00
|
|
|
)
|
|
|
|
|
2015-04-20 11:44:06 -04:00
|
|
|
func configureInterface(iface netlink.Link, settings *Interface) error {
|
2015-04-13 14:40:42 -04:00
|
|
|
ifaceName := iface.Attrs().Name
|
|
|
|
ifaceConfigurators := []struct {
|
2015-04-20 11:44:06 -04:00
|
|
|
Fn func(netlink.Link, *Interface) error
|
2015-04-13 14:40:42 -04:00
|
|
|
ErrMessage string
|
|
|
|
}{
|
|
|
|
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, settings.DstName)},
|
|
|
|
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, settings.Address)},
|
|
|
|
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, settings.AddressIPv6)},
|
2015-05-19 20:08:56 -04:00
|
|
|
{setInterfaceRoutes, fmt.Sprintf("error setting interface %q routes to %q", ifaceName, settings.Routes)},
|
2015-04-13 14:40:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, config := range ifaceConfigurators {
|
|
|
|
if err := config.Fn(iface, settings); err != nil {
|
|
|
|
return fmt.Errorf("%s: %v", config.ErrMessage, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-24 20:08:50 -04:00
|
|
|
func programGateway(path string, gw net.IP) error {
|
2015-04-23 20:37:19 -04:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
origns, err := netns.Get()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer origns.Close()
|
|
|
|
|
|
|
|
f, err := os.OpenFile(path, os.O_RDONLY, 0)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed get network namespace %q: %v", path, err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
nsFD := f.Fd()
|
|
|
|
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer netns.Set(origns)
|
|
|
|
|
2015-04-28 01:57:36 -04:00
|
|
|
gwRoutes, err := netlink.RouteGet(gw)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("route for the gateway could not be found: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-04-13 14:40:42 -04:00
|
|
|
return netlink.RouteAdd(&netlink.Route{
|
2015-04-28 01:57:36 -04:00
|
|
|
Scope: netlink.SCOPE_UNIVERSE,
|
|
|
|
LinkIndex: gwRoutes[0].LinkIndex,
|
|
|
|
Gw: gw,
|
2015-04-13 14:40:42 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-05-19 20:08:56 -04:00
|
|
|
// Program a route in to the namespace routing table.
|
|
|
|
func programRoute(path string, dest *net.IPNet, nh net.IP) error {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
origns, err := netns.Get()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer origns.Close()
|
|
|
|
|
|
|
|
f, err := os.OpenFile(path, os.O_RDONLY, 0)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed get network namespace %q: %v", path, err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
nsFD := f.Fd()
|
|
|
|
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer netns.Set(origns)
|
|
|
|
|
|
|
|
gwRoutes, err := netlink.RouteGet(nh)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("route for the next hop could not be found: %v", 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 {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
origns, err := netns.Get()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer origns.Close()
|
|
|
|
|
|
|
|
f, err := os.OpenFile(path, os.O_RDONLY, 0)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed get network namespace %q: %v", path, err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
nsFD := f.Fd()
|
|
|
|
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer netns.Set(origns)
|
|
|
|
|
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-04-20 11:44:06 -04:00
|
|
|
func setInterfaceIP(iface netlink.Link, settings *Interface) error {
|
2015-04-17 18:42:23 -04:00
|
|
|
ipAddr := &netlink.Addr{IPNet: settings.Address, Label: ""}
|
2015-04-13 21:36:58 -04:00
|
|
|
return netlink.AddrAdd(iface, ipAddr)
|
2015-04-13 14:40:42 -04:00
|
|
|
}
|
|
|
|
|
2015-04-20 11:44:06 -04:00
|
|
|
func setInterfaceIPv6(iface netlink.Link, settings *Interface) error {
|
2015-04-23 20:37:19 -04:00
|
|
|
if settings.AddressIPv6 == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ipAddr := &netlink.Addr{IPNet: settings.AddressIPv6, Label: ""}
|
2015-04-13 21:36:58 -04:00
|
|
|
return netlink.AddrAdd(iface, ipAddr)
|
2015-04-13 14:40:42 -04:00
|
|
|
}
|
|
|
|
|
2015-04-20 11:44:06 -04:00
|
|
|
func setInterfaceName(iface netlink.Link, settings *Interface) error {
|
2015-04-13 14:40:42 -04:00
|
|
|
return netlink.LinkSetName(iface, settings.DstName)
|
|
|
|
}
|
2015-05-19 20:08:56 -04:00
|
|
|
|
|
|
|
func setInterfaceRoutes(iface netlink.Link, settings *Interface) error {
|
|
|
|
for _, route := range settings.Routes {
|
|
|
|
err := netlink.RouteAdd(&netlink.Route{
|
|
|
|
Scope: netlink.SCOPE_UNIVERSE,
|
|
|
|
LinkIndex: iface.Attrs().Index,
|
|
|
|
Dst: route,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|