github.com/rish1988/moby@v25.0.2+incompatible/libnetwork/osl/route_linux.go (about)

     1  package osl
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/docker/docker/libnetwork/types"
     8  	"github.com/vishvananda/netlink"
     9  )
    10  
    11  // Gateway returns the IPv4 gateway for the sandbox.
    12  func (n *Namespace) Gateway() net.IP {
    13  	n.mu.Lock()
    14  	defer n.mu.Unlock()
    15  
    16  	return n.gw
    17  }
    18  
    19  // GatewayIPv6 returns the IPv6 gateway for the sandbox.
    20  func (n *Namespace) GatewayIPv6() net.IP {
    21  	n.mu.Lock()
    22  	defer n.mu.Unlock()
    23  
    24  	return n.gwv6
    25  }
    26  
    27  // StaticRoutes returns additional static routes for the sandbox. Note that
    28  // directly connected routes are stored on the particular interface they
    29  // refer to.
    30  func (n *Namespace) StaticRoutes() []*types.StaticRoute {
    31  	n.mu.Lock()
    32  	defer n.mu.Unlock()
    33  
    34  	routes := make([]*types.StaticRoute, len(n.staticRoutes))
    35  	for i, route := range n.staticRoutes {
    36  		r := route.GetCopy()
    37  		routes[i] = r
    38  	}
    39  
    40  	return routes
    41  }
    42  
    43  // SetGateway sets the default IPv4 gateway for the sandbox. It is a no-op
    44  // if the given gateway is empty.
    45  func (n *Namespace) SetGateway(gw net.IP) error {
    46  	if len(gw) == 0 {
    47  		return nil
    48  	}
    49  
    50  	if err := n.programGateway(gw, true); err != nil {
    51  		return err
    52  	}
    53  	n.mu.Lock()
    54  	n.gw = gw
    55  	n.mu.Unlock()
    56  	return nil
    57  }
    58  
    59  // UnsetGateway the previously set default IPv4 gateway in the sandbox.
    60  // It is a no-op if no gateway was set.
    61  func (n *Namespace) UnsetGateway() error {
    62  	gw := n.Gateway()
    63  	if len(gw) == 0 {
    64  		return nil
    65  	}
    66  
    67  	if err := n.programGateway(gw, false); err != nil {
    68  		return err
    69  	}
    70  	n.mu.Lock()
    71  	n.gw = net.IP{}
    72  	n.mu.Unlock()
    73  	return nil
    74  }
    75  
    76  func (n *Namespace) programGateway(gw net.IP, isAdd bool) error {
    77  	gwRoutes, err := n.nlHandle.RouteGet(gw)
    78  	if err != nil {
    79  		return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
    80  	}
    81  
    82  	var linkIndex int
    83  	for _, gwRoute := range gwRoutes {
    84  		if gwRoute.Gw == nil {
    85  			linkIndex = gwRoute.LinkIndex
    86  			break
    87  		}
    88  	}
    89  
    90  	if linkIndex == 0 {
    91  		return fmt.Errorf("direct route for the gateway %s could not be found", gw)
    92  	}
    93  
    94  	if isAdd {
    95  		return n.nlHandle.RouteAdd(&netlink.Route{
    96  			Scope:     netlink.SCOPE_UNIVERSE,
    97  			LinkIndex: linkIndex,
    98  			Gw:        gw,
    99  		})
   100  	}
   101  
   102  	return n.nlHandle.RouteDel(&netlink.Route{
   103  		Scope:     netlink.SCOPE_UNIVERSE,
   104  		LinkIndex: linkIndex,
   105  		Gw:        gw,
   106  	})
   107  }
   108  
   109  // Program a route in to the namespace routing table.
   110  func (n *Namespace) programRoute(dest *net.IPNet, nh net.IP) error {
   111  	gwRoutes, err := n.nlHandle.RouteGet(nh)
   112  	if err != nil {
   113  		return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
   114  	}
   115  
   116  	return n.nlHandle.RouteAdd(&netlink.Route{
   117  		Scope:     netlink.SCOPE_UNIVERSE,
   118  		LinkIndex: gwRoutes[0].LinkIndex,
   119  		Gw:        nh,
   120  		Dst:       dest,
   121  	})
   122  }
   123  
   124  // Delete a route from the namespace routing table.
   125  func (n *Namespace) removeRoute(dest *net.IPNet, nh net.IP) error {
   126  	gwRoutes, err := n.nlHandle.RouteGet(nh)
   127  	if err != nil {
   128  		return fmt.Errorf("route for the next hop could not be found: %v", err)
   129  	}
   130  
   131  	return n.nlHandle.RouteDel(&netlink.Route{
   132  		Scope:     netlink.SCOPE_UNIVERSE,
   133  		LinkIndex: gwRoutes[0].LinkIndex,
   134  		Gw:        nh,
   135  		Dst:       dest,
   136  	})
   137  }
   138  
   139  // SetGatewayIPv6 sets the default IPv6 gateway for the sandbox. It is a no-op
   140  // if the given gateway is empty.
   141  func (n *Namespace) SetGatewayIPv6(gwv6 net.IP) error {
   142  	if len(gwv6) == 0 {
   143  		return nil
   144  	}
   145  
   146  	if err := n.programGateway(gwv6, true); err != nil {
   147  		return err
   148  	}
   149  
   150  	n.mu.Lock()
   151  	n.gwv6 = gwv6
   152  	n.mu.Unlock()
   153  	return nil
   154  }
   155  
   156  // UnsetGatewayIPv6 unsets the previously set default IPv6 gateway in the sandbox.
   157  // It is a no-op if no gateway was set.
   158  func (n *Namespace) UnsetGatewayIPv6() error {
   159  	gwv6 := n.GatewayIPv6()
   160  	if len(gwv6) == 0 {
   161  		return nil
   162  	}
   163  
   164  	if err := n.programGateway(gwv6, false); err != nil {
   165  		return err
   166  	}
   167  
   168  	n.mu.Lock()
   169  	n.gwv6 = net.IP{}
   170  	n.mu.Unlock()
   171  	return nil
   172  }
   173  
   174  // AddStaticRoute adds a static route to the sandbox.
   175  func (n *Namespace) AddStaticRoute(r *types.StaticRoute) error {
   176  	if err := n.programRoute(r.Destination, r.NextHop); err != nil {
   177  		return err
   178  	}
   179  
   180  	n.mu.Lock()
   181  	n.staticRoutes = append(n.staticRoutes, r)
   182  	n.mu.Unlock()
   183  	return nil
   184  }
   185  
   186  // RemoveStaticRoute removes a static route from the sandbox.
   187  func (n *Namespace) RemoveStaticRoute(r *types.StaticRoute) error {
   188  	if err := n.removeRoute(r.Destination, r.NextHop); err != nil {
   189  		return err
   190  	}
   191  
   192  	n.mu.Lock()
   193  	lastIndex := len(n.staticRoutes) - 1
   194  	for i, v := range n.staticRoutes {
   195  		if v == r {
   196  			// Overwrite the route we're removing with the last element
   197  			n.staticRoutes[i] = n.staticRoutes[lastIndex]
   198  			// Shorten the slice to trim the extra element
   199  			n.staticRoutes = n.staticRoutes[:lastIndex]
   200  			break
   201  		}
   202  	}
   203  	n.mu.Unlock()
   204  	return nil
   205  }