| package osl | |
| import ( | |
| "fmt" | |
| "net" | |
| "github.com/docker/docker/libnetwork/types" | |
| "github.com/vishvananda/netlink" | |
| ) | |
| // Gateway returns the IPv4 gateway for the sandbox. | |
| func (n *Namespace) Gateway() net.IP { | |
| n.mu.Lock() | |
| defer n.mu.Unlock() | |
| return n.gw | |
| } | |
| // GatewayIPv6 returns the IPv6 gateway for the sandbox. | |
| func (n *Namespace) GatewayIPv6() net.IP { | |
| n.mu.Lock() | |
| defer n.mu.Unlock() | |
| return n.gwv6 | |
| } | |
| // StaticRoutes returns additional static routes for the sandbox. Note that | |
| // directly connected routes are stored on the particular interface they | |
| // refer to. | |
| func (n *Namespace) StaticRoutes() []*types.StaticRoute { | |
| n.mu.Lock() | |
| defer n.mu.Unlock() | |
| routes := make([]*types.StaticRoute, len(n.staticRoutes)) | |
| for i, route := range n.staticRoutes { | |
| r := route.GetCopy() | |
| routes[i] = r | |
| } | |
| return routes | |
| } | |
| // SetGateway sets the default IPv4 gateway for the sandbox. It is a no-op | |
| // if the given gateway is empty. | |
| func (n *Namespace) SetGateway(gw net.IP) error { | |
| if len(gw) == 0 { | |
| return nil | |
| } | |
| if err := n.programGateway(gw, true); err != nil { | |
| return err | |
| } | |
| n.mu.Lock() | |
| n.gw = gw | |
| n.mu.Unlock() | |
| return nil | |
| } | |
| // UnsetGateway the previously set default IPv4 gateway in the sandbox. | |
| // It is a no-op if no gateway was set. | |
| func (n *Namespace) UnsetGateway() error { | |
| gw := n.Gateway() | |
| if len(gw) == 0 { | |
| return nil | |
| } | |
| if err := n.programGateway(gw, false); err != nil { | |
| return err | |
| } | |
| n.mu.Lock() | |
| n.gw = net.IP{} | |
| n.mu.Unlock() | |
| return nil | |
| } | |
| func (n *Namespace) programGateway(gw net.IP, isAdd bool) error { | |
| gwRoutes, err := n.nlHandle.RouteGet(gw) | |
| if err != nil { | |
| return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err) | |
| } | |
| var linkIndex int | |
| for _, gwRoute := range gwRoutes { | |
| if gwRoute.Gw == nil { | |
| linkIndex = gwRoute.LinkIndex | |
| break | |
| } | |
| } | |
| if linkIndex == 0 { | |
| return fmt.Errorf("direct route for the gateway %s could not be found", gw) | |
| } | |
| if isAdd { | |
| return n.nlHandle.RouteAdd(&netlink.Route{ | |
| Scope: netlink.SCOPE_UNIVERSE, | |
| LinkIndex: linkIndex, | |
| Gw: gw, | |
| }) | |
| } | |
| return n.nlHandle.RouteDel(&netlink.Route{ | |
| Scope: netlink.SCOPE_UNIVERSE, | |
| LinkIndex: linkIndex, | |
| Gw: gw, | |
| }) | |
| } | |
| // Program a route in to the namespace routing table. | |
| func (n *Namespace) programRoute(dest *net.IPNet, nh net.IP) error { | |
| gwRoutes, err := n.nlHandle.RouteGet(nh) | |
| if err != nil { | |
| return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err) | |
| } | |
| return n.nlHandle.RouteAdd(&netlink.Route{ | |
| Scope: netlink.SCOPE_UNIVERSE, | |
| LinkIndex: gwRoutes[0].LinkIndex, | |
| Gw: nh, | |
| Dst: dest, | |
| }) | |
| } | |
| // Delete a route from the namespace routing table. | |
| func (n *Namespace) removeRoute(dest *net.IPNet, nh net.IP) error { | |
| gwRoutes, err := n.nlHandle.RouteGet(nh) | |
| if err != nil { | |
| return fmt.Errorf("route for the next hop could not be found: %v", err) | |
| } | |
| return n.nlHandle.RouteDel(&netlink.Route{ | |
| Scope: netlink.SCOPE_UNIVERSE, | |
| LinkIndex: gwRoutes[0].LinkIndex, | |
| Gw: nh, | |
| Dst: dest, | |
| }) | |
| } | |
| // SetGatewayIPv6 sets the default IPv6 gateway for the sandbox. It is a no-op | |
| // if the given gateway is empty. | |
| func (n *Namespace) SetGatewayIPv6(gwv6 net.IP) error { | |
| if len(gwv6) == 0 { | |
| return nil | |
| } | |
| if err := n.programGateway(gwv6, true); err != nil { | |
| return err | |
| } | |
| n.mu.Lock() | |
| n.gwv6 = gwv6 | |
| n.mu.Unlock() | |
| return nil | |
| } | |
| // UnsetGatewayIPv6 unsets the previously set default IPv6 gateway in the sandbox. | |
| // It is a no-op if no gateway was set. | |
| func (n *Namespace) UnsetGatewayIPv6() error { | |
| gwv6 := n.GatewayIPv6() | |
| if len(gwv6) == 0 { | |
| return nil | |
| } | |
| if err := n.programGateway(gwv6, false); err != nil { | |
| return err | |
| } | |
| n.mu.Lock() | |
| n.gwv6 = net.IP{} | |
| n.mu.Unlock() | |
| return nil | |
| } | |
| // AddStaticRoute adds a static route to the sandbox. | |
| func (n *Namespace) AddStaticRoute(r *types.StaticRoute) error { | |
| if err := n.programRoute(r.Destination, r.NextHop); err != nil { | |
| return err | |
| } | |
| n.mu.Lock() | |
| n.staticRoutes = append(n.staticRoutes, r) | |
| n.mu.Unlock() | |
| return nil | |
| } | |
| // RemoveStaticRoute removes a static route from the sandbox. | |
| func (n *Namespace) RemoveStaticRoute(r *types.StaticRoute) error { | |
| if err := n.removeRoute(r.Destination, r.NextHop); err != nil { | |
| return err | |
| } | |
| n.mu.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.mu.Unlock() | |
| return nil | |
| } |