github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/libnetwork/drivers/macvlan/macvlan_joinleave.go (about)

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