github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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  func (ep *endpoint) Info() EndpointInfo {
   191  	if ep.sandboxID != "" {
   192  		return ep
   193  	}
   194  	n, err := ep.getNetworkFromStore()
   195  	if err != nil {
   196  		return nil
   197  	}
   198  
   199  	ep, err = n.getEndpointFromStore(ep.ID())
   200  	if err != nil {
   201  		return nil
   202  	}
   203  
   204  	sb, ok := ep.getSandbox()
   205  	if !ok {
   206  		// endpoint hasn't joined any sandbox.
   207  		// Just return the endpoint
   208  		return ep
   209  	}
   210  
   211  	return sb.getEndpoint(ep.ID())
   212  }
   213  
   214  func (ep *endpoint) Iface() InterfaceInfo {
   215  	ep.Lock()
   216  	defer ep.Unlock()
   217  
   218  	if ep.iface != nil {
   219  		return ep.iface
   220  	}
   221  
   222  	return nil
   223  }
   224  
   225  func (ep *endpoint) Interface() driverapi.InterfaceInfo {
   226  	ep.Lock()
   227  	defer ep.Unlock()
   228  
   229  	if ep.iface != nil {
   230  		return ep.iface
   231  	}
   232  
   233  	return nil
   234  }
   235  
   236  func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error {
   237  	if epi.mac != nil {
   238  		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
   239  	}
   240  	if mac == nil {
   241  		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
   242  	}
   243  	epi.mac = types.GetMacCopy(mac)
   244  	return nil
   245  }
   246  
   247  func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error {
   248  	if address.IP == nil {
   249  		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
   250  	}
   251  	if address.IP.To4() == nil {
   252  		return setAddress(&epi.addrv6, address)
   253  	}
   254  	return setAddress(&epi.addr, address)
   255  }
   256  
   257  func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
   258  	if *ifaceAddr != nil {
   259  		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
   260  	}
   261  	*ifaceAddr = types.GetIPNetCopy(address)
   262  	return nil
   263  }
   264  
   265  func (epi *endpointInterface) MacAddress() net.HardwareAddr {
   266  	return types.GetMacCopy(epi.mac)
   267  }
   268  
   269  func (epi *endpointInterface) Address() *net.IPNet {
   270  	return types.GetIPNetCopy(epi.addr)
   271  }
   272  
   273  func (epi *endpointInterface) AddressIPv6() *net.IPNet {
   274  	return types.GetIPNetCopy(epi.addrv6)
   275  }
   276  
   277  func (epi *endpointInterface) LinkLocalAddresses() []*net.IPNet {
   278  	return epi.llAddrs
   279  }
   280  
   281  func (epi *endpointInterface) SrcName() string {
   282  	return epi.srcName
   283  }
   284  
   285  func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
   286  	epi.srcName = srcName
   287  	epi.dstPrefix = dstPrefix
   288  	return nil
   289  }
   290  
   291  func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
   292  	ep.Lock()
   293  	defer ep.Unlock()
   294  
   295  	if ep.iface != nil {
   296  		return ep.iface
   297  	}
   298  
   299  	return nil
   300  }
   301  
   302  func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
   303  	ep.Lock()
   304  	defer ep.Unlock()
   305  
   306  	r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}
   307  
   308  	if routeType == types.NEXTHOP {
   309  		// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
   310  		ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r)
   311  	} else {
   312  		// If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
   313  		ep.iface.routes = append(ep.iface.routes, r.Destination)
   314  	}
   315  	return nil
   316  }
   317  
   318  func (ep *endpoint) AddTableEntry(tableName, key string, value []byte) error {
   319  	ep.Lock()
   320  	defer ep.Unlock()
   321  
   322  	ep.joinInfo.driverTableEntries = append(ep.joinInfo.driverTableEntries, &tableEntry{
   323  		tableName: tableName,
   324  		key:       key,
   325  		value:     value,
   326  	})
   327  
   328  	return nil
   329  }
   330  
   331  func (ep *endpoint) Sandbox() Sandbox {
   332  	cnt, ok := ep.getSandbox()
   333  	if !ok {
   334  		return nil
   335  	}
   336  	return cnt
   337  }
   338  
   339  func (ep *endpoint) LoadBalancer() bool {
   340  	ep.Lock()
   341  	defer ep.Unlock()
   342  	return ep.loadBalancer
   343  }
   344  
   345  func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
   346  	ep.Lock()
   347  	defer ep.Unlock()
   348  
   349  	if ep.joinInfo == nil {
   350  		return nil
   351  	}
   352  
   353  	return ep.joinInfo.StaticRoutes
   354  }
   355  
   356  func (ep *endpoint) Gateway() net.IP {
   357  	ep.Lock()
   358  	defer ep.Unlock()
   359  
   360  	if ep.joinInfo == nil {
   361  		return net.IP{}
   362  	}
   363  
   364  	return types.GetIPCopy(ep.joinInfo.gw)
   365  }
   366  
   367  func (ep *endpoint) GatewayIPv6() net.IP {
   368  	ep.Lock()
   369  	defer ep.Unlock()
   370  
   371  	if ep.joinInfo == nil {
   372  		return net.IP{}
   373  	}
   374  
   375  	return types.GetIPCopy(ep.joinInfo.gw6)
   376  }
   377  
   378  func (ep *endpoint) SetGateway(gw net.IP) error {
   379  	ep.Lock()
   380  	defer ep.Unlock()
   381  
   382  	ep.joinInfo.gw = types.GetIPCopy(gw)
   383  	return nil
   384  }
   385  
   386  func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
   387  	ep.Lock()
   388  	defer ep.Unlock()
   389  
   390  	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
   391  	return nil
   392  }
   393  
   394  func (ep *endpoint) retrieveFromStore() (*endpoint, error) {
   395  	n, err := ep.getNetworkFromStore()
   396  	if err != nil {
   397  		return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err)
   398  	}
   399  	return n.getEndpointFromStore(ep.ID())
   400  }
   401  
   402  func (ep *endpoint) DisableGatewayService() {
   403  	ep.Lock()
   404  	defer ep.Unlock()
   405  
   406  	ep.joinInfo.disableGatewayService = true
   407  }
   408  
   409  func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) {
   410  	epMap := make(map[string]interface{})
   411  	if epj.gw != nil {
   412  		epMap["gw"] = epj.gw.String()
   413  	}
   414  	if epj.gw6 != nil {
   415  		epMap["gw6"] = epj.gw6.String()
   416  	}
   417  	epMap["disableGatewayService"] = epj.disableGatewayService
   418  	epMap["StaticRoutes"] = epj.StaticRoutes
   419  	return json.Marshal(epMap)
   420  }
   421  
   422  func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error {
   423  	var (
   424  		err   error
   425  		epMap map[string]interface{}
   426  	)
   427  	if err = json.Unmarshal(b, &epMap); err != nil {
   428  		return err
   429  	}
   430  	if v, ok := epMap["gw"]; ok {
   431  		epj.gw = net.ParseIP(v.(string))
   432  	}
   433  	if v, ok := epMap["gw6"]; ok {
   434  		epj.gw6 = net.ParseIP(v.(string))
   435  	}
   436  	epj.disableGatewayService = epMap["disableGatewayService"].(bool)
   437  
   438  	var tStaticRoute []types.StaticRoute
   439  	if v, ok := epMap["StaticRoutes"]; ok {
   440  		tb, _ := json.Marshal(v)
   441  		var tStaticRoute []types.StaticRoute
   442  		// TODO(cpuguy83): Linter caught that we aren't checking errors here
   443  		// I don't know why we aren't other than potentially the data is not always expected to be right?
   444  		// This is why I'm not adding the error check.
   445  		//
   446  		// In any case for posterity please if you figure this out document it or check the error
   447  		json.Unmarshal(tb, &tStaticRoute) //nolint:errcheck
   448  	}
   449  	var StaticRoutes []*types.StaticRoute
   450  	for _, r := range tStaticRoute {
   451  		r := r
   452  		StaticRoutes = append(StaticRoutes, &r)
   453  	}
   454  	epj.StaticRoutes = StaticRoutes
   455  
   456  	return nil
   457  }
   458  
   459  func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error {
   460  	dstEpj.disableGatewayService = epj.disableGatewayService
   461  	dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes))
   462  	copy(dstEpj.StaticRoutes, epj.StaticRoutes)
   463  	dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries))
   464  	copy(dstEpj.driverTableEntries, epj.driverTableEntries)
   465  	dstEpj.gw = types.GetIPCopy(epj.gw)
   466  	dstEpj.gw6 = types.GetIPCopy(epj.gw6)
   467  	return nil
   468  }