github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/macvlan/macvlan_network.go (about) 1 package macvlan 2 3 import ( 4 "fmt" 5 6 "github.com/Sirupsen/logrus" 7 "github.com/docker/docker/pkg/parsers/kernel" 8 "github.com/docker/docker/pkg/stringid" 9 "github.com/docker/libnetwork/driverapi" 10 "github.com/docker/libnetwork/netlabel" 11 "github.com/docker/libnetwork/options" 12 "github.com/docker/libnetwork/osl" 13 "github.com/docker/libnetwork/types" 14 ) 15 16 // CreateNetwork the network for the specified driver type 17 func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { 18 defer osl.InitOSContext()() 19 kv, err := kernel.GetKernelVersion() 20 if err != nil { 21 return fmt.Errorf("failed to check kernel version for %s driver support: %v", macvlanType, err) 22 } 23 // ensure Kernel version is >= v3.9 for macvlan support 24 if kv.Kernel < macvlanKernelVer || (kv.Kernel == macvlanKernelVer && kv.Major < macvlanMajorVer) { 25 return fmt.Errorf("kernel version failed to meet the minimum macvlan kernel requirement of %d.%d, found %d.%d.%d", 26 macvlanKernelVer, macvlanMajorVer, kv.Kernel, kv.Major, kv.Minor) 27 } 28 // reject a null v4 network 29 if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" { 30 return fmt.Errorf("ipv4 pool is empty") 31 } 32 // parse and validate the config and bind to networkConfiguration 33 config, err := parseNetworkOptions(nid, option) 34 if err != nil { 35 return err 36 } 37 config.ID = nid 38 err = config.processIPAM(nid, ipV4Data, ipV6Data) 39 if err != nil { 40 return err 41 } 42 // verify the macvlan mode from -o macvlan_mode option 43 switch config.MacvlanMode { 44 case "", modeBridge: 45 // default to macvlan bridge mode if -o macvlan_mode is empty 46 config.MacvlanMode = modeBridge 47 case modePrivate: 48 config.MacvlanMode = modePrivate 49 case modePassthru: 50 config.MacvlanMode = modePassthru 51 case modeVepa: 52 config.MacvlanMode = modeVepa 53 default: 54 return fmt.Errorf("requested macvlan mode '%s' is not valid, 'bridge' mode is the macvlan driver default", config.MacvlanMode) 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", macvlanType) 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 // empty parent and --internal are handled the same. Set here to update k/v 64 config.Internal = true 65 } 66 err = d.createNetwork(config) 67 if err != nil { 68 return err 69 } 70 // update persistent db, rollback on fail 71 err = d.storeUpdate(config) 72 if err != nil { 73 d.deleteNetwork(config.ID) 74 logrus.Debugf("encoutered an error rolling back a network create for %s : %v", config.ID, err) 75 return err 76 } 77 78 return nil 79 } 80 81 // createNetwork is used by new network callbacks and persistent network cache 82 func (d *driver) createNetwork(config *configuration) error { 83 networkList := d.getNetworks() 84 for _, nw := range networkList { 85 if config.Parent == nw.config.Parent { 86 return fmt.Errorf("network %s is already using parent interface %s", 87 getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent) 88 } 89 } 90 if !parentExists(config.Parent) { 91 // if the --internal flag is set, create a dummy link 92 if config.Internal { 93 err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID))) 94 if err != nil { 95 return err 96 } 97 config.CreatedSlaveLink = true 98 // notify the user in logs they have limited comunicatins 99 if config.Parent == getDummyName(stringid.TruncateID(config.ID)) { 100 logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s", 101 config.Parent) 102 } 103 } else { 104 // if the subinterface parent_iface.vlan_id checks do not pass, return err. 105 // a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10' 106 err := createVlanLink(config.Parent) 107 if err != nil { 108 return err 109 } 110 // if driver created the networks slave link, record it for future deletion 111 config.CreatedSlaveLink = true 112 } 113 } 114 n := &network{ 115 id: config.ID, 116 driver: d, 117 endpoints: endpointTable{}, 118 config: config, 119 } 120 // add the *network 121 d.addNetwork(n) 122 123 return nil 124 } 125 126 // DeleteNetwork the network for the specified driver type 127 func (d *driver) DeleteNetwork(nid string) error { 128 defer osl.InitOSContext()() 129 n := d.network(nid) 130 if n == nil { 131 return fmt.Errorf("network id %s not found", nid) 132 } 133 // if the driver created the slave interface, delete it, otherwise leave it 134 if ok := n.config.CreatedSlaveLink; ok { 135 // if the interface exists, only delete if it matches iface.vlan or dummy.net_id naming 136 if ok := parentExists(n.config.Parent); ok { 137 // only delete the link if it is named the net_id 138 if n.config.Parent == getDummyName(stringid.TruncateID(nid)) { 139 err := delDummyLink(n.config.Parent) 140 if err != nil { 141 logrus.Debugf("link %s was not deleted, continuing the delete network operation: %v", 142 n.config.Parent, err) 143 } 144 } else { 145 // only delete the link if it matches iface.vlan naming 146 err := delVlanLink(n.config.Parent) 147 if err != nil { 148 logrus.Debugf("link %s was not deleted, continuing the delete network operation: %v", 149 n.config.Parent, err) 150 } 151 } 152 } 153 } 154 // delete the *network 155 d.deleteNetwork(nid) 156 // delete the network record from persistent cache 157 err := d.storeDelete(n.config) 158 if err != nil { 159 return fmt.Errorf("error deleting deleting id %s from datastore: %v", nid, err) 160 } 161 return nil 162 } 163 164 // parseNetworkOptions parse docker network options 165 func parseNetworkOptions(id string, option options.Generic) (*configuration, error) { 166 var ( 167 err error 168 config = &configuration{} 169 ) 170 // parse generic labels first 171 if genData, ok := option[netlabel.GenericData]; ok && genData != nil { 172 if config, err = parseNetworkGenericOptions(genData); err != nil { 173 return nil, err 174 } 175 } 176 // setting the parent to "" will trigger an isolated network dummy parent link 177 if _, ok := option[netlabel.Internal]; ok { 178 config.Internal = true 179 // empty --parent= and --internal are handled the same. 180 config.Parent = "" 181 } 182 183 return config, nil 184 } 185 186 // parseNetworkGenericOptions parse generic driver docker network options 187 func parseNetworkGenericOptions(data interface{}) (*configuration, error) { 188 var ( 189 err error 190 config *configuration 191 ) 192 switch opt := data.(type) { 193 case *configuration: 194 config = opt 195 case map[string]string: 196 config = &configuration{} 197 err = config.fromOptions(opt) 198 case options.Generic: 199 var opaqueConfig interface{} 200 if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil { 201 config = opaqueConfig.(*configuration) 202 } 203 default: 204 err = types.BadRequestErrorf("unrecognized network configuration format: %v", opt) 205 } 206 207 return config, err 208 } 209 210 // fromOptions binds the generic options to networkConfiguration to cache 211 func (config *configuration) fromOptions(labels map[string]string) error { 212 for label, value := range labels { 213 switch label { 214 case parentOpt: 215 // parse driver option '-o parent' 216 config.Parent = value 217 case driverModeOpt: 218 // parse driver option '-o macvlan_mode' 219 config.MacvlanMode = value 220 } 221 } 222 223 return nil 224 } 225 226 // processIPAM parses v4 and v6 IP information and binds it to the network configuration 227 func (config *configuration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error { 228 if len(ipamV4Data) > 0 { 229 for _, ipd := range ipamV4Data { 230 s := &ipv4Subnet{ 231 SubnetIP: ipd.Pool.String(), 232 GwIP: ipd.Gateway.String(), 233 } 234 config.Ipv4Subnets = append(config.Ipv4Subnets, s) 235 } 236 } 237 if len(ipamV6Data) > 0 { 238 for _, ipd := range ipamV6Data { 239 s := &ipv6Subnet{ 240 SubnetIP: ipd.Pool.String(), 241 GwIP: ipd.Gateway.String(), 242 } 243 config.Ipv6Subnets = append(config.Ipv6Subnets, s) 244 } 245 } 246 247 return nil 248 }