github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/libnetwork/default_gateway.go (about)

     1  package libnetwork
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/docker/docker/libnetwork/netlabel"
     8  	"github.com/docker/docker/libnetwork/types"
     9  	"github.com/sirupsen/logrus"
    10  )
    11  
    12  const (
    13  	gwEPlen = 12
    14  )
    15  
    16  var procGwNetwork = make(chan (bool), 1)
    17  
    18  /*
    19     libnetwork creates a bridge network "docker_gw_bridge" for providing
    20     default gateway for the containers if none of the container's endpoints
    21     have GW set by the driver. ICC is set to false for the GW_bridge network.
    22  
    23     If a driver can't provide external connectivity it can choose to not set
    24     the GW IP for the endpoint.
    25  
    26     endpoint on the GW_bridge network is managed dynamically by libnetwork.
    27     ie:
    28     - its created when an endpoint without GW joins the container
    29     - its deleted when an endpoint with GW joins the container
    30  */
    31  
    32  func (sb *sandbox) setupDefaultGW() error {
    33  
    34  	// check if the container already has a GW endpoint
    35  	if ep := sb.getEndpointInGWNetwork(); ep != nil {
    36  		return nil
    37  	}
    38  
    39  	c := sb.controller
    40  
    41  	// Look for default gw network. In case of error (includes not found),
    42  	// retry and create it if needed in a serialized execution.
    43  	n, err := c.NetworkByName(libnGWNetwork)
    44  	if err != nil {
    45  		if n, err = c.defaultGwNetwork(); err != nil {
    46  			return err
    47  		}
    48  	}
    49  
    50  	createOptions := []EndpointOption{CreateOptionAnonymous()}
    51  
    52  	var gwName string
    53  	if len(sb.containerID) <= gwEPlen {
    54  		gwName = "gateway_" + sb.containerID
    55  	} else {
    56  		gwName = "gateway_" + sb.id[:gwEPlen]
    57  	}
    58  
    59  	sbLabels := sb.Labels()
    60  
    61  	if sbLabels[netlabel.PortMap] != nil {
    62  		createOptions = append(createOptions, CreateOptionPortMapping(sbLabels[netlabel.PortMap].([]types.PortBinding)))
    63  	}
    64  
    65  	if sbLabels[netlabel.ExposedPorts] != nil {
    66  		createOptions = append(createOptions, CreateOptionExposedPorts(sbLabels[netlabel.ExposedPorts].([]types.TransportPort)))
    67  	}
    68  
    69  	epOption := getPlatformOption()
    70  	if epOption != nil {
    71  		createOptions = append(createOptions, epOption)
    72  	}
    73  
    74  	newEp, err := n.CreateEndpoint(gwName, createOptions...)
    75  	if err != nil {
    76  		return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err)
    77  	}
    78  
    79  	defer func() {
    80  		if err != nil {
    81  			if err2 := newEp.Delete(true); err2 != nil {
    82  				logrus.Warnf("Failed to remove gw endpoint for container %s after failing to join the gateway network: %v",
    83  					sb.containerID, err2)
    84  			}
    85  		}
    86  	}()
    87  
    88  	epLocal := newEp.(*endpoint)
    89  
    90  	if err = epLocal.sbJoin(sb); err != nil {
    91  		return fmt.Errorf("container %s: endpoint join on GW Network failed: %v", sb.containerID, err)
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // If present, detach and remove the endpoint connecting the sandbox to the default gw network.
    98  func (sb *sandbox) clearDefaultGW() error {
    99  	var ep *endpoint
   100  
   101  	if ep = sb.getEndpointInGWNetwork(); ep == nil {
   102  		return nil
   103  	}
   104  	if err := ep.sbLeave(sb, false); err != nil {
   105  		return fmt.Errorf("container %s: endpoint leaving GW Network failed: %v", sb.containerID, err)
   106  	}
   107  	if err := ep.Delete(false); err != nil {
   108  		return fmt.Errorf("container %s: deleting endpoint on GW Network failed: %v", sb.containerID, err)
   109  	}
   110  	return nil
   111  }
   112  
   113  // Evaluate whether the sandbox requires a default gateway based
   114  // on the endpoints to which it is connected. It does not account
   115  // for the default gateway network endpoint.
   116  
   117  func (sb *sandbox) needDefaultGW() bool {
   118  	var needGW bool
   119  
   120  	for _, ep := range sb.getConnectedEndpoints() {
   121  		if ep.endpointInGWNetwork() {
   122  			continue
   123  		}
   124  		if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
   125  			continue
   126  		}
   127  		if ep.getNetwork().Internal() {
   128  			continue
   129  		}
   130  		// During stale sandbox cleanup, joinInfo may be nil
   131  		if ep.joinInfo != nil && ep.joinInfo.disableGatewayService {
   132  			continue
   133  		}
   134  		// TODO v6 needs to be handled.
   135  		if len(ep.Gateway()) > 0 {
   136  			return false
   137  		}
   138  		for _, r := range ep.StaticRoutes() {
   139  			if r.Destination != nil && r.Destination.String() == "0.0.0.0/0" {
   140  				return false
   141  			}
   142  		}
   143  		needGW = true
   144  	}
   145  
   146  	return needGW
   147  }
   148  
   149  func (sb *sandbox) getEndpointInGWNetwork() *endpoint {
   150  	for _, ep := range sb.getConnectedEndpoints() {
   151  		if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") {
   152  			return ep
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  func (ep *endpoint) endpointInGWNetwork() bool {
   159  	if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") {
   160  		return true
   161  	}
   162  	return false
   163  }
   164  
   165  // Looks for the default gw network and creates it if not there.
   166  // Parallel executions are serialized.
   167  func (c *controller) defaultGwNetwork() (Network, error) {
   168  	procGwNetwork <- true
   169  	defer func() { <-procGwNetwork }()
   170  
   171  	n, err := c.NetworkByName(libnGWNetwork)
   172  	if _, ok := err.(types.NotFoundError); ok {
   173  		n, err = c.createGWNetwork()
   174  	}
   175  	return n, err
   176  }
   177  
   178  // Returns the endpoint which is providing external connectivity to the sandbox
   179  func (sb *sandbox) getGatewayEndpoint() *endpoint {
   180  	for _, ep := range sb.getConnectedEndpoints() {
   181  		if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
   182  			continue
   183  		}
   184  		if len(ep.Gateway()) != 0 {
   185  			return ep
   186  		}
   187  	}
   188  	return nil
   189  }