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

     1  // +build linux
     2  
     3  package ipvlan
     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/docker/docker/libnetwork/types"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  type staticRoute struct {
    18  	Destination *net.IPNet
    19  	RouteType   int
    20  	NextHop     net.IP
    21  }
    22  
    23  const (
    24  	defaultV4RouteCidr = "0.0.0.0/0"
    25  	defaultV6RouteCidr = "::/0"
    26  )
    27  
    28  // Join method is invoked when a Sandbox is attached to an endpoint.
    29  func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
    30  	defer osl.InitOSContext()()
    31  	n, err := d.getNetwork(nid)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	endpoint := n.endpoint(eid)
    36  	if endpoint == nil {
    37  		return fmt.Errorf("could not find endpoint with id %s", eid)
    38  	}
    39  	// generate a name for the iface that will be renamed to eth0 in the sbox
    40  	containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
    41  	if err != nil {
    42  		return fmt.Errorf("error generating an interface name: %v", err)
    43  	}
    44  	// create the netlink ipvlan interface
    45  	vethName, err := createIPVlan(containerIfName, n.config.Parent, n.config.IpvlanMode)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	// bind the generated iface name to the endpoint
    50  	endpoint.srcName = vethName
    51  	ep := n.endpoint(eid)
    52  	if ep == nil {
    53  		return fmt.Errorf("could not find endpoint with id %s", eid)
    54  	}
    55  	if !n.config.Internal {
    56  		if n.config.IpvlanMode == modeL3 {
    57  			// disable gateway services to add a default gw using dev eth0 only
    58  			jinfo.DisableGatewayService()
    59  			defaultRoute, err := ifaceGateway(defaultV4RouteCidr)
    60  			if err != nil {
    61  				return err
    62  			}
    63  			if err := jinfo.AddStaticRoute(defaultRoute.Destination, defaultRoute.RouteType, defaultRoute.NextHop); err != nil {
    64  				return fmt.Errorf("failed to set an ipvlan l3 mode ipv4 default gateway: %v", err)
    65  			}
    66  			logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Ipvlan_Mode: %s, Parent: %s",
    67  				ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent)
    68  			// If the endpoint has a v6 address, set a v6 default route
    69  			if ep.addrv6 != nil {
    70  				default6Route, err := ifaceGateway(defaultV6RouteCidr)
    71  				if err != nil {
    72  					return err
    73  				}
    74  				if err = jinfo.AddStaticRoute(default6Route.Destination, default6Route.RouteType, default6Route.NextHop); err != nil {
    75  					return fmt.Errorf("failed to set an ipvlan l3 mode ipv6 default gateway: %v", err)
    76  				}
    77  				logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Ipvlan_Mode: %s, Parent: %s",
    78  					ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent)
    79  			}
    80  		}
    81  		if n.config.IpvlanMode == modeL2 {
    82  			// parse and correlate the endpoint v4 address with the available v4 subnets
    83  			if len(n.config.Ipv4Subnets) > 0 {
    84  				s := n.getSubnetforIPv4(ep.addr)
    85  				if s == nil {
    86  					return fmt.Errorf("could not find a valid ipv4 subnet for endpoint %s", eid)
    87  				}
    88  				v4gw, _, err := net.ParseCIDR(s.GwIP)
    89  				if err != nil {
    90  					return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err)
    91  				}
    92  				err = jinfo.SetGateway(v4gw)
    93  				if err != nil {
    94  					return err
    95  				}
    96  				logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Gateway: %s, Ipvlan_Mode: %s, Parent: %s",
    97  					ep.addr.IP.String(), v4gw.String(), n.config.IpvlanMode, n.config.Parent)
    98  			}
    99  			// parse and correlate the endpoint v6 address with the available v6 subnets
   100  			if len(n.config.Ipv6Subnets) > 0 {
   101  				s := n.getSubnetforIPv6(ep.addrv6)
   102  				if s == nil {
   103  					return fmt.Errorf("could not find a valid ipv6 subnet for endpoint %s", eid)
   104  				}
   105  				v6gw, _, err := net.ParseCIDR(s.GwIP)
   106  				if err != nil {
   107  					return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err)
   108  				}
   109  				err = jinfo.SetGatewayIPv6(v6gw)
   110  				if err != nil {
   111  					return err
   112  				}
   113  				logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Gateway: %s, Ipvlan_Mode: %s, Parent: %s",
   114  					ep.addrv6.IP.String(), v6gw.String(), n.config.IpvlanMode, n.config.Parent)
   115  			}
   116  		}
   117  	} else {
   118  		if len(n.config.Ipv4Subnets) > 0 {
   119  			logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, IpVlan_Mode: %s, Parent: %s",
   120  				ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent)
   121  		}
   122  		if len(n.config.Ipv6Subnets) > 0 {
   123  			logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s IpVlan_Mode: %s, Parent: %s",
   124  				ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent)
   125  		}
   126  	}
   127  	iNames := jinfo.InterfaceName()
   128  	err = iNames.SetNames(vethName, containerVethPrefix)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	if err = d.storeUpdate(ep); err != nil {
   133  		return fmt.Errorf("failed to save ipvlan endpoint %.7s to store: %v", ep.id, err)
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  // Leave method is invoked when a Sandbox detaches from an endpoint.
   140  func (d *driver) Leave(nid, eid string) error {
   141  	defer osl.InitOSContext()()
   142  	network, err := d.getNetwork(nid)
   143  	if err != nil {
   144  		return err
   145  	}
   146  	endpoint, err := network.getEndpoint(eid)
   147  	if err != nil {
   148  		return err
   149  	}
   150  	if endpoint == nil {
   151  		return fmt.Errorf("could not find endpoint with id %s", eid)
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // ifaceGateway returns a static route for either v4/v6 to be set to the container eth0
   158  func ifaceGateway(dfNet string) (*staticRoute, error) {
   159  	nh, dst, err := net.ParseCIDR(dfNet)
   160  	if err != nil {
   161  		return nil, fmt.Errorf("unable to parse default route %v", err)
   162  	}
   163  	defaultRoute := &staticRoute{
   164  		Destination: dst,
   165  		RouteType:   types.CONNECTED,
   166  		NextHop:     nh,
   167  	}
   168  
   169  	return defaultRoute, nil
   170  }
   171  
   172  // getSubnetforIPv4 returns the ipv4 subnet to which the given IP belongs
   173  func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipv4Subnet {
   174  	for _, s := range n.config.Ipv4Subnets {
   175  		_, snet, err := net.ParseCIDR(s.SubnetIP)
   176  		if err != nil {
   177  			return nil
   178  		}
   179  		// first check if the mask lengths are the same
   180  		i, _ := snet.Mask.Size()
   181  		j, _ := ip.Mask.Size()
   182  		if i != j {
   183  			continue
   184  		}
   185  		if snet.Contains(ip.IP) {
   186  			return s
   187  		}
   188  	}
   189  
   190  	return nil
   191  }
   192  
   193  // getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs
   194  func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipv6Subnet {
   195  	for _, s := range n.config.Ipv6Subnets {
   196  		_, snet, err := net.ParseCIDR(s.SubnetIP)
   197  		if err != nil {
   198  			return nil
   199  		}
   200  		// first check if the mask lengths are the same
   201  		i, _ := snet.Mask.Size()
   202  		j, _ := ip.Mask.Size()
   203  		if i != j {
   204  			continue
   205  		}
   206  		if snet.Contains(ip.IP) {
   207  			return s
   208  		}
   209  	}
   210  
   211  	return nil
   212  }