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

     1  //go:build linux
     2  // +build linux
     3  
     4  package ipvlan
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/docker/docker/libnetwork/driverapi"
    10  	"github.com/docker/docker/libnetwork/netlabel"
    11  	"github.com/docker/docker/libnetwork/ns"
    12  	"github.com/docker/docker/libnetwork/options"
    13  	"github.com/docker/docker/libnetwork/osl"
    14  	"github.com/docker/docker/libnetwork/types"
    15  	"github.com/docker/docker/pkg/parsers/kernel"
    16  	"github.com/docker/docker/pkg/stringid"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  // CreateNetwork the network for the specified driver type
    21  func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
    22  	defer osl.InitOSContext()()
    23  	kv, err := kernel.GetKernelVersion()
    24  	if err != nil {
    25  		return fmt.Errorf("Failed to check kernel version for %s driver support: %v", ipvlanType, err)
    26  	}
    27  	// ensure Kernel version is >= v4.2 for ipvlan support
    28  	if kv.Kernel < ipvlanKernelVer || (kv.Kernel == ipvlanKernelVer && kv.Major < ipvlanMajorVer) {
    29  		return fmt.Errorf("kernel version failed to meet the minimum ipvlan kernel requirement of %d.%d, found %d.%d.%d",
    30  			ipvlanKernelVer, ipvlanMajorVer, kv.Kernel, kv.Major, kv.Minor)
    31  	}
    32  	// reject a null v4 network
    33  	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
    34  		return fmt.Errorf("ipv4 pool is empty")
    35  	}
    36  	// parse and validate the config and bind to networkConfiguration
    37  	config, err := parseNetworkOptions(nid, option)
    38  	if err != nil {
    39  		return err
    40  	}
    41  	config.ID = nid
    42  	err = config.processIPAM(nid, ipV4Data, ipV6Data)
    43  	if err != nil {
    44  		return err
    45  	}
    46  	// verify the ipvlan mode from -o ipvlan_mode option
    47  	switch config.IpvlanMode {
    48  	case "", modeL2:
    49  		// default to ipvlan L2 mode if -o ipvlan_mode is empty
    50  		config.IpvlanMode = modeL2
    51  	case modeL3:
    52  		config.IpvlanMode = modeL3
    53  	case modeL3S:
    54  		config.IpvlanMode = modeL3S
    55  	default:
    56  		return fmt.Errorf("requested ipvlan mode '%s' is not valid, 'l2' mode is the ipvlan driver default", config.IpvlanMode)
    57  	}
    58  	// verify the ipvlan flag from -o ipvlan_flag option
    59  	switch config.IpvlanFlag {
    60  	case "", flagBridge:
    61  		// default to bridge if -o ipvlan_flag is empty
    62  		config.IpvlanFlag = flagBridge
    63  	case flagPrivate:
    64  		config.IpvlanFlag = flagPrivate
    65  	case flagVepa:
    66  		config.IpvlanFlag = flagVepa
    67  	default:
    68  		return fmt.Errorf("requested ipvlan flag '%s' is not valid, 'bridge' is the ipvlan driver default", config.IpvlanFlag)
    69  	}
    70  	// loopback is not a valid parent link
    71  	if config.Parent == "lo" {
    72  		return fmt.Errorf("loopback interface is not a valid %s parent link", ipvlanType)
    73  	}
    74  	// if parent interface not specified, create a dummy type link to use named dummy+net_id
    75  	if config.Parent == "" {
    76  		config.Parent = getDummyName(stringid.TruncateID(config.ID))
    77  	}
    78  	foundExisting, err := d.createNetwork(config)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	if foundExisting {
    84  		return types.InternalMaskableErrorf("restoring existing network %s", config.ID)
    85  	}
    86  	// update persistent db, rollback on fail
    87  	err = d.storeUpdate(config)
    88  	if err != nil {
    89  		d.deleteNetwork(config.ID)
    90  		logrus.Debugf("encountered an error rolling back a network create for %s : %v", config.ID, err)
    91  		return err
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // createNetwork is used by new network callbacks and persistent network cache
    98  func (d *driver) createNetwork(config *configuration) (bool, error) {
    99  	foundExisting := false
   100  	networkList := d.getNetworks()
   101  	for _, nw := range networkList {
   102  		if config.Parent == nw.config.Parent {
   103  			if config.ID != nw.config.ID {
   104  				return false, fmt.Errorf("network %s is already using parent interface %s",
   105  					getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
   106  			}
   107  			logrus.Debugf("Create Network for the same ID %s\n", config.ID)
   108  			foundExisting = true
   109  			break
   110  		}
   111  	}
   112  	if !parentExists(config.Parent) {
   113  		// Create a dummy link if a dummy name is set for parent
   114  		if dummyName := getDummyName(stringid.TruncateID(config.ID)); dummyName == config.Parent {
   115  			err := createDummyLink(config.Parent, dummyName)
   116  			if err != nil {
   117  				return false, err
   118  			}
   119  			config.CreatedSlaveLink = true
   120  
   121  			// notify the user in logs they have limited communications
   122  			logrus.Debugf("Empty -o parent= flags limit communications to other containers inside of network: %s",
   123  				config.Parent)
   124  		} else {
   125  			// if the subinterface parent_iface.vlan_id checks do not pass, return err.
   126  			//  a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10'
   127  			err := createVlanLink(config.Parent)
   128  			if err != nil {
   129  				return false, err
   130  			}
   131  			// if driver created the networks slave link, record it for future deletion
   132  			config.CreatedSlaveLink = true
   133  		}
   134  	}
   135  	if !foundExisting {
   136  		n := &network{
   137  			id:        config.ID,
   138  			driver:    d,
   139  			endpoints: endpointTable{},
   140  			config:    config,
   141  		}
   142  		// add the network
   143  		d.addNetwork(n)
   144  	}
   145  
   146  	return foundExisting, nil
   147  }
   148  
   149  // DeleteNetwork the network for the specified driver type
   150  func (d *driver) DeleteNetwork(nid string) error {
   151  	defer osl.InitOSContext()()
   152  	n := d.network(nid)
   153  	if n == nil {
   154  		return fmt.Errorf("network id %s not found", nid)
   155  	}
   156  	// if the driver created the slave interface, delete it, otherwise leave it
   157  	if ok := n.config.CreatedSlaveLink; ok {
   158  		// if the interface exists, only delete if it matches iface.vlan or dummy.net_id naming
   159  		if ok := parentExists(n.config.Parent); ok {
   160  			// only delete the link if it is named the net_id
   161  			if n.config.Parent == getDummyName(stringid.TruncateID(nid)) {
   162  				err := delDummyLink(n.config.Parent)
   163  				if err != nil {
   164  					logrus.Debugf("link %s was not deleted, continuing the delete network operation: %v",
   165  						n.config.Parent, err)
   166  				}
   167  			} else {
   168  				// only delete the link if it matches iface.vlan naming
   169  				err := delVlanLink(n.config.Parent)
   170  				if err != nil {
   171  					logrus.Debugf("link %s was not deleted, continuing the delete network operation: %v",
   172  						n.config.Parent, err)
   173  				}
   174  			}
   175  		}
   176  	}
   177  	for _, ep := range n.endpoints {
   178  		if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
   179  			if err := ns.NlHandle().LinkDel(link); err != nil {
   180  				logrus.WithError(err).Warnf("Failed to delete interface (%s)'s link on endpoint (%s) delete", ep.srcName, ep.id)
   181  			}
   182  		}
   183  
   184  		if err := d.storeDelete(ep); err != nil {
   185  			logrus.Warnf("Failed to remove ipvlan endpoint %.7s from store: %v", ep.id, err)
   186  		}
   187  	}
   188  	// delete the *network
   189  	d.deleteNetwork(nid)
   190  	// delete the network record from persistent cache
   191  	err := d.storeDelete(n.config)
   192  	if err != nil {
   193  		return fmt.Errorf("error deleting deleting id %s from datastore: %v", nid, err)
   194  	}
   195  	return nil
   196  }
   197  
   198  // parseNetworkOptions parse docker network options
   199  func parseNetworkOptions(id string, option options.Generic) (*configuration, error) {
   200  	var (
   201  		err    error
   202  		config = &configuration{}
   203  	)
   204  	// parse generic labels first
   205  	if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
   206  		if config, err = parseNetworkGenericOptions(genData); err != nil {
   207  			return nil, err
   208  		}
   209  	}
   210  	if val, ok := option[netlabel.Internal]; ok {
   211  		if internal, ok := val.(bool); ok && internal {
   212  			config.Internal = true
   213  		}
   214  	}
   215  	return config, nil
   216  }
   217  
   218  // parseNetworkGenericOptions parse generic driver docker network options
   219  func parseNetworkGenericOptions(data interface{}) (*configuration, error) {
   220  	var (
   221  		err    error
   222  		config *configuration
   223  	)
   224  	switch opt := data.(type) {
   225  	case *configuration:
   226  		config = opt
   227  	case map[string]string:
   228  		config = &configuration{}
   229  		err = config.fromOptions(opt)
   230  	case options.Generic:
   231  		var opaqueConfig interface{}
   232  		if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
   233  			config = opaqueConfig.(*configuration)
   234  		}
   235  	default:
   236  		err = types.BadRequestErrorf("unrecognized network configuration format: %v", opt)
   237  	}
   238  	return config, err
   239  }
   240  
   241  // fromOptions binds the generic options to networkConfiguration to cache
   242  func (config *configuration) fromOptions(labels map[string]string) error {
   243  	for label, value := range labels {
   244  		switch label {
   245  		case parentOpt:
   246  			// parse driver option '-o parent'
   247  			config.Parent = value
   248  		case driverModeOpt:
   249  			// parse driver option '-o ipvlan_mode'
   250  			config.IpvlanMode = value
   251  		case driverFlagOpt:
   252  			// parse driver option '-o ipvlan_flag'
   253  			config.IpvlanFlag = value
   254  		}
   255  	}
   256  	return nil
   257  }
   258  
   259  // processIPAM parses v4 and v6 IP information and binds it to the network configuration
   260  func (config *configuration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
   261  	if len(ipamV4Data) > 0 {
   262  		for _, ipd := range ipamV4Data {
   263  			s := &ipv4Subnet{
   264  				SubnetIP: ipd.Pool.String(),
   265  				GwIP:     ipd.Gateway.String(),
   266  			}
   267  			config.Ipv4Subnets = append(config.Ipv4Subnets, s)
   268  		}
   269  	}
   270  	if len(ipamV6Data) > 0 {
   271  		for _, ipd := range ipamV6Data {
   272  			s := &ipv6Subnet{
   273  				SubnetIP: ipd.Pool.String(),
   274  				GwIP:     ipd.Gateway.String(),
   275  			}
   276  			config.Ipv6Subnets = append(config.Ipv6Subnets, s)
   277  		}
   278  	}
   279  	return nil
   280  }