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