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