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