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