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