github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/libnetwork/drivers/ipvlan/ipvlan_joinleave.go (about)

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