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

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