github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/libnetwork/endpoint_info.go (about)

     1  package libnetwork
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net"
     7  
     8  	"github.com/docker/docker/libnetwork/driverapi"
     9  	"github.com/docker/docker/libnetwork/types"
    10  )
    11  
    12  // EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
    13  type EndpointInfo interface {
    14  	// Iface returns information about the interface which was assigned to
    15  	// the endpoint by the driver. This can be used after the
    16  	// endpoint has been created.
    17  	Iface() *EndpointInterface
    18  
    19  	// Gateway returns the IPv4 gateway assigned by the driver.
    20  	// This will only return a valid value if a container has joined the endpoint.
    21  	Gateway() net.IP
    22  
    23  	// GatewayIPv6 returns the IPv6 gateway assigned by the driver.
    24  	// This will only return a valid value if a container has joined the endpoint.
    25  	GatewayIPv6() net.IP
    26  
    27  	// StaticRoutes returns the list of static routes configured by the network
    28  	// driver when the container joins a network
    29  	StaticRoutes() []*types.StaticRoute
    30  
    31  	// Sandbox returns the attached sandbox if there, nil otherwise.
    32  	Sandbox() *Sandbox
    33  
    34  	// LoadBalancer returns whether the endpoint is the load balancer endpoint for the network.
    35  	LoadBalancer() bool
    36  }
    37  
    38  // EndpointInterface holds interface addresses bound to the endpoint.
    39  type EndpointInterface struct {
    40  	mac       net.HardwareAddr
    41  	addr      *net.IPNet
    42  	addrv6    *net.IPNet
    43  	llAddrs   []*net.IPNet
    44  	srcName   string
    45  	dstPrefix string
    46  	routes    []*net.IPNet
    47  	v4PoolID  string
    48  	v6PoolID  string
    49  }
    50  
    51  func (epi *EndpointInterface) MarshalJSON() ([]byte, error) {
    52  	epMap := make(map[string]interface{})
    53  	if epi.mac != nil {
    54  		epMap["mac"] = epi.mac.String()
    55  	}
    56  	if epi.addr != nil {
    57  		epMap["addr"] = epi.addr.String()
    58  	}
    59  	if epi.addrv6 != nil {
    60  		epMap["addrv6"] = epi.addrv6.String()
    61  	}
    62  	if len(epi.llAddrs) != 0 {
    63  		list := make([]string, 0, len(epi.llAddrs))
    64  		for _, ll := range epi.llAddrs {
    65  			list = append(list, ll.String())
    66  		}
    67  		epMap["llAddrs"] = list
    68  	}
    69  	epMap["srcName"] = epi.srcName
    70  	epMap["dstPrefix"] = epi.dstPrefix
    71  	var routes []string
    72  	for _, route := range epi.routes {
    73  		routes = append(routes, route.String())
    74  	}
    75  	epMap["routes"] = routes
    76  	epMap["v4PoolID"] = epi.v4PoolID
    77  	epMap["v6PoolID"] = epi.v6PoolID
    78  	return json.Marshal(epMap)
    79  }
    80  
    81  func (epi *EndpointInterface) UnmarshalJSON(b []byte) error {
    82  	var (
    83  		err   error
    84  		epMap map[string]interface{}
    85  	)
    86  	if err = json.Unmarshal(b, &epMap); err != nil {
    87  		return err
    88  	}
    89  	if v, ok := epMap["mac"]; ok {
    90  		if epi.mac, err = net.ParseMAC(v.(string)); err != nil {
    91  			return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
    92  		}
    93  	}
    94  	if v, ok := epMap["addr"]; ok {
    95  		if epi.addr, err = types.ParseCIDR(v.(string)); err != nil {
    96  			return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
    97  		}
    98  	}
    99  	if v, ok := epMap["addrv6"]; ok {
   100  		if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
   101  			return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
   102  		}
   103  	}
   104  	if v, ok := epMap["llAddrs"]; ok {
   105  		list := v.([]interface{})
   106  		epi.llAddrs = make([]*net.IPNet, 0, len(list))
   107  		for _, llS := range list {
   108  			ll, err := types.ParseCIDR(llS.(string))
   109  			if err != nil {
   110  				return types.InternalErrorf("failed to decode endpoint interface link-local address (%v) after json unmarshal: %v", llS, err)
   111  			}
   112  			epi.llAddrs = append(epi.llAddrs, ll)
   113  		}
   114  	}
   115  	epi.srcName = epMap["srcName"].(string)
   116  	epi.dstPrefix = epMap["dstPrefix"].(string)
   117  
   118  	rb, _ := json.Marshal(epMap["routes"])
   119  	var routes []string
   120  
   121  	// TODO(cpuguy83): linter noticed we don't check the error here... no idea why but it seems like it could introduce problems if we start checking
   122  	json.Unmarshal(rb, &routes) //nolint:errcheck
   123  
   124  	epi.routes = make([]*net.IPNet, 0)
   125  	for _, route := range routes {
   126  		ip, ipr, err := net.ParseCIDR(route)
   127  		if err == nil {
   128  			ipr.IP = ip
   129  			epi.routes = append(epi.routes, ipr)
   130  		}
   131  	}
   132  	epi.v4PoolID = epMap["v4PoolID"].(string)
   133  	epi.v6PoolID = epMap["v6PoolID"].(string)
   134  
   135  	return nil
   136  }
   137  
   138  func (epi *EndpointInterface) CopyTo(dstEpi *EndpointInterface) error {
   139  	dstEpi.mac = types.GetMacCopy(epi.mac)
   140  	dstEpi.addr = types.GetIPNetCopy(epi.addr)
   141  	dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6)
   142  	dstEpi.srcName = epi.srcName
   143  	dstEpi.dstPrefix = epi.dstPrefix
   144  	dstEpi.v4PoolID = epi.v4PoolID
   145  	dstEpi.v6PoolID = epi.v6PoolID
   146  	if len(epi.llAddrs) != 0 {
   147  		dstEpi.llAddrs = make([]*net.IPNet, 0, len(epi.llAddrs))
   148  		dstEpi.llAddrs = append(dstEpi.llAddrs, epi.llAddrs...)
   149  	}
   150  
   151  	for _, route := range epi.routes {
   152  		dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
   153  	}
   154  
   155  	return nil
   156  }
   157  
   158  type endpointJoinInfo struct {
   159  	gw                    net.IP
   160  	gw6                   net.IP
   161  	StaticRoutes          []*types.StaticRoute
   162  	driverTableEntries    []*tableEntry
   163  	disableGatewayService bool
   164  }
   165  
   166  type tableEntry struct {
   167  	tableName string
   168  	key       string
   169  	value     []byte
   170  }
   171  
   172  // Info hydrates the endpoint and returns certain operational data belonging
   173  // to this endpoint.
   174  //
   175  // TODO(thaJeztah): make sure that Endpoint is always fully hydrated, and remove the EndpointInfo interface, and use Endpoint directly.
   176  func (ep *Endpoint) Info() EndpointInfo {
   177  	if ep.sandboxID != "" {
   178  		return ep
   179  	}
   180  	n, err := ep.getNetworkFromStore()
   181  	if err != nil {
   182  		return nil
   183  	}
   184  
   185  	ep, err = n.getEndpointFromStore(ep.ID())
   186  	if err != nil {
   187  		return nil
   188  	}
   189  
   190  	sb, ok := ep.getSandbox()
   191  	if !ok {
   192  		// endpoint hasn't joined any sandbox.
   193  		// Just return the endpoint
   194  		return ep
   195  	}
   196  
   197  	return sb.GetEndpoint(ep.ID())
   198  }
   199  
   200  // Iface returns information about the interface which was assigned to
   201  // the endpoint by the driver. This can be used after the
   202  // endpoint has been created.
   203  func (ep *Endpoint) Iface() *EndpointInterface {
   204  	ep.mu.Lock()
   205  	defer ep.mu.Unlock()
   206  	return ep.iface
   207  }
   208  
   209  // SetMacAddress allows the driver to set the mac address to the endpoint interface
   210  // during the call to CreateEndpoint, if the mac address is not already set.
   211  func (epi *EndpointInterface) SetMacAddress(mac net.HardwareAddr) error {
   212  	if epi.mac != nil {
   213  		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
   214  	}
   215  	if mac == nil {
   216  		return types.InvalidParameterErrorf("tried to set nil MAC address to endpoint interface")
   217  	}
   218  	epi.mac = types.GetMacCopy(mac)
   219  	return nil
   220  }
   221  
   222  func (epi *EndpointInterface) SetIPAddress(address *net.IPNet) error {
   223  	if address.IP == nil {
   224  		return types.InvalidParameterErrorf("tried to set nil IP address to endpoint interface")
   225  	}
   226  	if address.IP.To4() == nil {
   227  		return setAddress(&epi.addrv6, address)
   228  	}
   229  	return setAddress(&epi.addr, address)
   230  }
   231  
   232  func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
   233  	if *ifaceAddr != nil {
   234  		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
   235  	}
   236  	*ifaceAddr = types.GetIPNetCopy(address)
   237  	return nil
   238  }
   239  
   240  // MacAddress returns the MAC address assigned to the endpoint.
   241  func (epi *EndpointInterface) MacAddress() net.HardwareAddr {
   242  	return types.GetMacCopy(epi.mac)
   243  }
   244  
   245  // Address returns the IPv4 address assigned to the endpoint.
   246  func (epi *EndpointInterface) Address() *net.IPNet {
   247  	return types.GetIPNetCopy(epi.addr)
   248  }
   249  
   250  // AddressIPv6 returns the IPv6 address assigned to the endpoint.
   251  func (epi *EndpointInterface) AddressIPv6() *net.IPNet {
   252  	return types.GetIPNetCopy(epi.addrv6)
   253  }
   254  
   255  // LinkLocalAddresses returns the list of link-local (IPv4/IPv6) addresses assigned to the endpoint.
   256  func (epi *EndpointInterface) LinkLocalAddresses() []*net.IPNet {
   257  	return epi.llAddrs
   258  }
   259  
   260  // SrcName returns the name of the interface w/in the container
   261  func (epi *EndpointInterface) SrcName() string {
   262  	return epi.srcName
   263  }
   264  
   265  // SetNames method assigns the srcName and dstPrefix for the interface.
   266  func (epi *EndpointInterface) SetNames(srcName string, dstPrefix string) error {
   267  	epi.srcName = srcName
   268  	epi.dstPrefix = dstPrefix
   269  	return nil
   270  }
   271  
   272  func (ep *Endpoint) InterfaceName() driverapi.InterfaceNameInfo {
   273  	ep.mu.Lock()
   274  	defer ep.mu.Unlock()
   275  	return ep.iface
   276  }
   277  
   278  // AddStaticRoute adds a route to the sandbox.
   279  // It may be used in addition to or instead of a default gateway (as above).
   280  func (ep *Endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
   281  	ep.mu.Lock()
   282  	defer ep.mu.Unlock()
   283  	if routeType == types.NEXTHOP {
   284  		// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
   285  		ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &types.StaticRoute{
   286  			Destination: destination,
   287  			RouteType:   routeType,
   288  			NextHop:     nextHop,
   289  		})
   290  	} else {
   291  		// If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
   292  		ep.iface.routes = append(ep.iface.routes, destination)
   293  	}
   294  	return nil
   295  }
   296  
   297  // AddTableEntry adds a table entry to the gossip layer
   298  // passing the table name, key and an opaque value.
   299  func (ep *Endpoint) AddTableEntry(tableName, key string, value []byte) error {
   300  	ep.mu.Lock()
   301  	defer ep.mu.Unlock()
   302  
   303  	ep.joinInfo.driverTableEntries = append(ep.joinInfo.driverTableEntries, &tableEntry{
   304  		tableName: tableName,
   305  		key:       key,
   306  		value:     value,
   307  	})
   308  
   309  	return nil
   310  }
   311  
   312  // Sandbox returns the attached sandbox if there, nil otherwise.
   313  func (ep *Endpoint) Sandbox() *Sandbox {
   314  	cnt, ok := ep.getSandbox()
   315  	if !ok {
   316  		return nil
   317  	}
   318  	return cnt
   319  }
   320  
   321  // LoadBalancer returns whether the endpoint is the load balancer endpoint for the network.
   322  func (ep *Endpoint) LoadBalancer() bool {
   323  	ep.mu.Lock()
   324  	defer ep.mu.Unlock()
   325  	return ep.loadBalancer
   326  }
   327  
   328  // StaticRoutes returns the list of static routes configured by the network
   329  // driver when the container joins a network
   330  func (ep *Endpoint) StaticRoutes() []*types.StaticRoute {
   331  	ep.mu.Lock()
   332  	defer ep.mu.Unlock()
   333  
   334  	if ep.joinInfo == nil {
   335  		return nil
   336  	}
   337  
   338  	return ep.joinInfo.StaticRoutes
   339  }
   340  
   341  // Gateway returns the IPv4 gateway assigned by the driver.
   342  // This will only return a valid value if a container has joined the endpoint.
   343  func (ep *Endpoint) Gateway() net.IP {
   344  	ep.mu.Lock()
   345  	defer ep.mu.Unlock()
   346  
   347  	if ep.joinInfo == nil {
   348  		return net.IP{}
   349  	}
   350  
   351  	return types.GetIPCopy(ep.joinInfo.gw)
   352  }
   353  
   354  // GatewayIPv6 returns the IPv6 gateway assigned by the driver.
   355  // This will only return a valid value if a container has joined the endpoint.
   356  func (ep *Endpoint) GatewayIPv6() net.IP {
   357  	ep.mu.Lock()
   358  	defer ep.mu.Unlock()
   359  
   360  	if ep.joinInfo == nil {
   361  		return net.IP{}
   362  	}
   363  
   364  	return types.GetIPCopy(ep.joinInfo.gw6)
   365  }
   366  
   367  // SetGateway sets the default IPv4 gateway when a container joins the endpoint.
   368  func (ep *Endpoint) SetGateway(gw net.IP) error {
   369  	ep.mu.Lock()
   370  	defer ep.mu.Unlock()
   371  
   372  	ep.joinInfo.gw = types.GetIPCopy(gw)
   373  	return nil
   374  }
   375  
   376  // SetGatewayIPv6 sets the default IPv6 gateway when a container joins the endpoint.
   377  func (ep *Endpoint) SetGatewayIPv6(gw6 net.IP) error {
   378  	ep.mu.Lock()
   379  	defer ep.mu.Unlock()
   380  
   381  	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
   382  	return nil
   383  }
   384  
   385  func (ep *Endpoint) retrieveFromStore() (*Endpoint, error) {
   386  	n, err := ep.getNetworkFromStore()
   387  	if err != nil {
   388  		return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err)
   389  	}
   390  	return n.getEndpointFromStore(ep.ID())
   391  }
   392  
   393  // DisableGatewayService tells libnetwork not to provide Default GW for the container
   394  func (ep *Endpoint) DisableGatewayService() {
   395  	ep.mu.Lock()
   396  	defer ep.mu.Unlock()
   397  
   398  	ep.joinInfo.disableGatewayService = true
   399  }
   400  
   401  func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) {
   402  	epMap := make(map[string]interface{})
   403  	if epj.gw != nil {
   404  		epMap["gw"] = epj.gw.String()
   405  	}
   406  	if epj.gw6 != nil {
   407  		epMap["gw6"] = epj.gw6.String()
   408  	}
   409  	epMap["disableGatewayService"] = epj.disableGatewayService
   410  	epMap["StaticRoutes"] = epj.StaticRoutes
   411  	return json.Marshal(epMap)
   412  }
   413  
   414  func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error {
   415  	var (
   416  		err   error
   417  		epMap map[string]interface{}
   418  	)
   419  	if err = json.Unmarshal(b, &epMap); err != nil {
   420  		return err
   421  	}
   422  	if v, ok := epMap["gw"]; ok {
   423  		epj.gw = net.ParseIP(v.(string))
   424  	}
   425  	if v, ok := epMap["gw6"]; ok {
   426  		epj.gw6 = net.ParseIP(v.(string))
   427  	}
   428  	epj.disableGatewayService = epMap["disableGatewayService"].(bool)
   429  
   430  	var tStaticRoute []types.StaticRoute
   431  	if v, ok := epMap["StaticRoutes"]; ok {
   432  		tb, _ := json.Marshal(v)
   433  		var tStaticRoute []types.StaticRoute
   434  		// TODO(cpuguy83): Linter caught that we aren't checking errors here
   435  		// I don't know why we aren't other than potentially the data is not always expected to be right?
   436  		// This is why I'm not adding the error check.
   437  		//
   438  		// In any case for posterity please if you figure this out document it or check the error
   439  		json.Unmarshal(tb, &tStaticRoute) //nolint:errcheck
   440  	}
   441  	var StaticRoutes []*types.StaticRoute
   442  	for _, r := range tStaticRoute {
   443  		r := r
   444  		StaticRoutes = append(StaticRoutes, &r)
   445  	}
   446  	epj.StaticRoutes = StaticRoutes
   447  
   448  	return nil
   449  }
   450  
   451  func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error {
   452  	dstEpj.disableGatewayService = epj.disableGatewayService
   453  	dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes))
   454  	copy(dstEpj.StaticRoutes, epj.StaticRoutes)
   455  	dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries))
   456  	copy(dstEpj.driverTableEntries, epj.driverTableEntries)
   457  	dstEpj.gw = types.GetIPCopy(epj.gw)
   458  	dstEpj.gw6 = types.GetIPCopy(epj.gw6)
   459  	return nil
   460  }