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