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 }