package osl import ( "fmt" "net" "github.com/docker/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 := n.programGateway(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 := n.programGateway(gw, false) if err == nil { n.setGateway(net.IP{}) } return err } func (n *networkNamespace) 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 *networkNamespace) programRoute(path string, 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 *networkNamespace) removeRoute(path string, 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, }) } func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error { // Silently return if the gateway is empty if len(gwv6) == 0 { return nil } err := n.programGateway(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 := n.programGateway(gwv6, false) if err == nil { n.Lock() n.gwv6 = net.IP{} n.Unlock() } return err } func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error { err := n.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 { err := n.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 }