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