github.com/moby/docker@v26.1.3+incompatible/libnetwork/drivers/macvlan/macvlan_joinleave.go (about)

     1  //go:build linux
     2  
     3  package macvlan
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"net"
     9  
    10  	"github.com/containerd/log"
    11  	"github.com/docker/docker/libnetwork/driverapi"
    12  	"github.com/docker/docker/libnetwork/netutils"
    13  	"github.com/docker/docker/libnetwork/ns"
    14  )
    15  
    16  // Join method is invoked when a Sandbox is attached to an endpoint.
    17  func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
    18  	n, err := d.getNetwork(nid)
    19  	if err != nil {
    20  		return err
    21  	}
    22  	endpoint := n.endpoint(eid)
    23  	if endpoint == nil {
    24  		return fmt.Errorf("could not find endpoint with id %s", eid)
    25  	}
    26  	// generate a name for the iface that will be renamed to eth0 in the sbox
    27  	containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
    28  	if err != nil {
    29  		return fmt.Errorf("error generating an interface name: %s", err)
    30  	}
    31  	// create the netlink macvlan interface
    32  	vethName, err := createMacVlan(containerIfName, n.config.Parent, n.config.MacvlanMode)
    33  	if err != nil {
    34  		return err
    35  	}
    36  	// bind the generated iface name to the endpoint
    37  	endpoint.srcName = vethName
    38  	ep := n.endpoint(eid)
    39  	if ep == nil {
    40  		return fmt.Errorf("could not find endpoint with id %s", eid)
    41  	}
    42  	// parse and match the endpoint address with the available v4 subnets
    43  	if !n.config.Internal {
    44  		if len(n.config.Ipv4Subnets) > 0 {
    45  			s := n.getSubnetforIPv4(ep.addr)
    46  			if s == nil {
    47  				return fmt.Errorf("could not find a valid ipv4 subnet for endpoint %s", eid)
    48  			}
    49  			v4gw, _, err := net.ParseCIDR(s.GwIP)
    50  			if err != nil {
    51  				return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err)
    52  			}
    53  			err = jinfo.SetGateway(v4gw)
    54  			if err != nil {
    55  				return err
    56  			}
    57  			log.G(context.TODO()).Debugf("Macvlan Endpoint Joined with IPv4_Addr: %s, Gateway: %s, MacVlan_Mode: %s, Parent: %s",
    58  				ep.addr.IP.String(), v4gw.String(), n.config.MacvlanMode, n.config.Parent)
    59  		}
    60  		// parse and match the endpoint address with the available v6 subnets
    61  		if len(n.config.Ipv6Subnets) > 0 {
    62  			s := n.getSubnetforIPv6(ep.addrv6)
    63  			if s == nil {
    64  				return fmt.Errorf("could not find a valid ipv6 subnet for endpoint %s", eid)
    65  			}
    66  			v6gw, _, err := net.ParseCIDR(s.GwIP)
    67  			if err != nil {
    68  				return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err)
    69  			}
    70  			err = jinfo.SetGatewayIPv6(v6gw)
    71  			if err != nil {
    72  				return err
    73  			}
    74  			log.G(context.TODO()).Debugf("Macvlan Endpoint Joined with IPv6_Addr: %s Gateway: %s MacVlan_Mode: %s, Parent: %s",
    75  				ep.addrv6.IP.String(), v6gw.String(), n.config.MacvlanMode, n.config.Parent)
    76  		}
    77  	} else {
    78  		if len(n.config.Ipv4Subnets) > 0 {
    79  			log.G(context.TODO()).Debugf("Macvlan Endpoint Joined with IPv4_Addr: %s, MacVlan_Mode: %s, Parent: %s",
    80  				ep.addr.IP.String(), n.config.MacvlanMode, n.config.Parent)
    81  		}
    82  		if len(n.config.Ipv6Subnets) > 0 {
    83  			log.G(context.TODO()).Debugf("Macvlan Endpoint Joined with IPv6_Addr: %s MacVlan_Mode: %s, Parent: %s",
    84  				ep.addrv6.IP.String(), n.config.MacvlanMode, n.config.Parent)
    85  		}
    86  		// If n.config.Internal was set locally by the driver because there's no parent
    87  		// interface, libnetwork doesn't know the network is internal. So, stop it from
    88  		// adding a gateway endpoint.
    89  		jinfo.DisableGatewayService()
    90  	}
    91  	iNames := jinfo.InterfaceName()
    92  	err = iNames.SetNames(vethName, containerVethPrefix)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if err := d.storeUpdate(ep); err != nil {
    97  		return fmt.Errorf("failed to save macvlan endpoint %.7s to store: %v", ep.id, err)
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  // Leave method is invoked when a Sandbox detaches from an endpoint.
   104  func (d *driver) Leave(nid, eid string) error {
   105  	network, err := d.getNetwork(nid)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	endpoint, err := network.getEndpoint(eid)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	if endpoint == nil {
   114  		return fmt.Errorf("could not find endpoint with id %s", eid)
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  // getSubnetforIPv4 returns the ipv4 subnet to which the given IP belongs
   121  func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipSubnet {
   122  	return getSubnetForIP(ip, n.config.Ipv4Subnets)
   123  }
   124  
   125  // getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs
   126  func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipSubnet {
   127  	return getSubnetForIP(ip, n.config.Ipv6Subnets)
   128  }
   129  
   130  func getSubnetForIP(ip *net.IPNet, subnets []*ipSubnet) *ipSubnet {
   131  	for _, s := range subnets {
   132  		_, snet, err := net.ParseCIDR(s.SubnetIP)
   133  		if err != nil {
   134  			return nil
   135  		}
   136  		// first check if the mask lengths are the same
   137  		i, _ := snet.Mask.Size()
   138  		j, _ := ip.Mask.Size()
   139  		if i != j {
   140  			continue
   141  		}
   142  		if snet.Contains(ip.IP) {
   143  			return s
   144  		}
   145  	}
   146  
   147  	return nil
   148  }