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