github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/windows/windows.go (about) 1 // +build windows 2 3 // Shim for the Host Network Service (HNS) to manage networking for 4 // Windows Server containers and Hyper-V containers. This module 5 // is a basic libnetwork driver that passes all the calls to HNS 6 // It implements the 4 networking modes supported by HNS L2Bridge, 7 // L2Tunnel, NAT and Transparent(DHCP) 8 // 9 // The network are stored in memory and docker daemon ensures discovering 10 // and loading these networks on startup 11 12 package windows 13 14 import ( 15 "encoding/json" 16 "fmt" 17 "net" 18 "strconv" 19 "strings" 20 "sync" 21 22 "github.com/Microsoft/hcsshim" 23 log "github.com/Sirupsen/logrus" 24 "github.com/docker/libnetwork/datastore" 25 "github.com/docker/libnetwork/discoverapi" 26 "github.com/docker/libnetwork/driverapi" 27 "github.com/docker/libnetwork/netlabel" 28 "github.com/docker/libnetwork/types" 29 ) 30 31 // networkConfiguration for network specific configuration 32 type networkConfiguration struct { 33 ID string 34 Type string 35 Name string 36 HnsID string 37 RDID string 38 VLAN uint 39 VSID uint 40 DNSServers string 41 DNSSuffix string 42 SourceMac string 43 NetworkAdapterName string 44 } 45 46 // endpointConfiguration represents the user specified configuration for the sandbox endpoint 47 type endpointConfiguration struct { 48 MacAddress net.HardwareAddr 49 PortBindings []types.PortBinding 50 ExposedPorts []types.TransportPort 51 QosPolicies []types.QosPolicy 52 DNSServers []string 53 } 54 55 type hnsEndpoint struct { 56 id string 57 profileID string 58 macAddress net.HardwareAddr 59 config *endpointConfiguration // User specified parameters 60 portMapping []types.PortBinding // Operation port bindings 61 addr *net.IPNet 62 } 63 64 type hnsNetwork struct { 65 id string 66 config *networkConfiguration 67 endpoints map[string]*hnsEndpoint // key: endpoint id 68 driver *driver // The network's driver 69 sync.Mutex 70 } 71 72 type driver struct { 73 name string 74 networks map[string]*hnsNetwork 75 sync.Mutex 76 } 77 78 func isValidNetworkType(networkType string) bool { 79 if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "ics" == networkType || "transparent" == networkType { 80 return true 81 } 82 83 return false 84 } 85 86 // New constructs a new bridge driver 87 func newDriver(networkType string) *driver { 88 return &driver{name: networkType, networks: map[string]*hnsNetwork{}} 89 } 90 91 // GetInit returns an initializer for the given network type 92 func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error { 93 return func(dc driverapi.DriverCallback, config map[string]interface{}) error { 94 if !isValidNetworkType(networkType) { 95 return types.BadRequestErrorf("Network type not supported: %s", networkType) 96 } 97 98 return dc.RegisterDriver(networkType, newDriver(networkType), driverapi.Capability{ 99 DataScope: datastore.LocalScope, 100 }) 101 } 102 } 103 104 func (d *driver) getNetwork(id string) (*hnsNetwork, error) { 105 d.Lock() 106 defer d.Unlock() 107 108 if nw, ok := d.networks[id]; ok { 109 return nw, nil 110 } 111 112 return nil, types.NotFoundErrorf("network not found: %s", id) 113 } 114 115 func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) { 116 n.Lock() 117 defer n.Unlock() 118 119 if ep, ok := n.endpoints[eid]; ok { 120 return ep, nil 121 } 122 123 return nil, types.NotFoundErrorf("Endpoint not found: %s", eid) 124 } 125 126 func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) { 127 config := &networkConfiguration{} 128 129 for label, value := range genericOptions { 130 switch label { 131 case NetworkName: 132 config.Name = value 133 case HNSID: 134 config.HnsID = value 135 case RoutingDomain: 136 config.RDID = value 137 case Interface: 138 config.NetworkAdapterName = value 139 case DNSSuffix: 140 config.DNSSuffix = value 141 case DNSServers: 142 config.DNSServers = value 143 case VLAN: 144 vlan, err := strconv.ParseUint(value, 10, 32) 145 if err != nil { 146 return nil, err 147 } 148 config.VLAN = uint(vlan) 149 case VSID: 150 vsid, err := strconv.ParseUint(value, 10, 32) 151 if err != nil { 152 return nil, err 153 } 154 config.VSID = uint(vsid) 155 } 156 } 157 158 config.ID = id 159 config.Type = d.name 160 return config, nil 161 } 162 163 func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error { 164 if len(ipamV6Data) > 0 { 165 return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets") 166 } 167 168 if len(ipamV4Data) == 0 { 169 return types.BadRequestErrorf("network %s requires ipv4 configuration", id) 170 } 171 172 return nil 173 } 174 175 func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { 176 } 177 178 // Create a new network 179 func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { 180 if _, err := d.getNetwork(id); err == nil { 181 return types.ForbiddenErrorf("network %s exists", id) 182 } 183 184 genData, ok := option[netlabel.GenericData].(map[string]string) 185 if !ok { 186 return fmt.Errorf("Unknown generic data option") 187 } 188 189 // Parse and validate the config. It should not conflict with existing networks' config 190 config, err := d.parseNetworkOptions(id, genData) 191 if err != nil { 192 return err 193 } 194 195 err = config.processIPAM(id, ipV4Data, ipV6Data) 196 if err != nil { 197 return err 198 } 199 200 network := &hnsNetwork{ 201 id: config.ID, 202 endpoints: make(map[string]*hnsEndpoint), 203 config: config, 204 driver: d, 205 } 206 207 d.Lock() 208 d.networks[config.ID] = network 209 d.Unlock() 210 211 // A non blank hnsid indicates that the network was discovered 212 // from HNS. No need to call HNS if this network was discovered 213 // from HNS 214 if config.HnsID == "" { 215 subnets := []hcsshim.Subnet{} 216 217 for _, ipData := range ipV4Data { 218 subnet := hcsshim.Subnet{ 219 AddressPrefix: ipData.Pool.String(), 220 } 221 222 if ipData.Gateway != nil { 223 subnet.GatewayAddress = ipData.Gateway.IP.String() 224 } 225 226 subnets = append(subnets, subnet) 227 } 228 229 network := &hcsshim.HNSNetwork{ 230 Name: config.Name, 231 Type: d.name, 232 Subnets: subnets, 233 DNSServerList: config.DNSServers, 234 DNSSuffix: config.DNSSuffix, 235 SourceMac: config.SourceMac, 236 NetworkAdapterName: config.NetworkAdapterName, 237 } 238 239 if config.VLAN != 0 { 240 vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{ 241 Type: "VLAN", 242 VLAN: config.VLAN, 243 }) 244 245 if err != nil { 246 return err 247 } 248 network.Policies = append(network.Policies, vlanPolicy) 249 } 250 251 if config.VSID != 0 { 252 vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{ 253 Type: "VSID", 254 VSID: config.VSID, 255 }) 256 257 if err != nil { 258 return err 259 } 260 network.Policies = append(network.Policies, vsidPolicy) 261 } 262 263 if network.Name == "" { 264 network.Name = id 265 } 266 267 configurationb, err := json.Marshal(network) 268 if err != nil { 269 return err 270 } 271 272 configuration := string(configurationb) 273 log.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets) 274 275 hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration) 276 if err != nil { 277 return err 278 } 279 280 config.HnsID = hnsresponse.Id 281 genData[HNSID] = config.HnsID 282 } 283 284 return nil 285 } 286 287 func (d *driver) DeleteNetwork(nid string) error { 288 n, err := d.getNetwork(nid) 289 if err != nil { 290 return types.InternalMaskableErrorf("%s", err) 291 } 292 293 n.Lock() 294 config := n.config 295 n.Unlock() 296 297 // Cannot remove network if endpoints are still present 298 if len(n.endpoints) != 0 { 299 return fmt.Errorf("network %s has active endpoint", n.id) 300 } 301 302 _, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "") 303 if err != nil { 304 return err 305 } 306 307 d.Lock() 308 delete(d.networks, nid) 309 d.Unlock() 310 311 return nil 312 } 313 314 func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error) { 315 var qps []json.RawMessage 316 317 // Enumerate through the qos policies specified by the user and convert 318 // them into the internal structure matching the JSON blob that can be 319 // understood by the HCS. 320 for _, elem := range qosPolicies { 321 encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{ 322 Type: "QOS", 323 MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth, 324 }) 325 326 if err != nil { 327 return nil, err 328 } 329 qps = append(qps, encodedPolicy) 330 } 331 return qps, nil 332 } 333 334 func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) { 335 var pbs []json.RawMessage 336 337 // Enumerate through the port bindings specified by the user and convert 338 // them into the internal structure matching the JSON blob that can be 339 // understood by the HCS. 340 for _, elem := range portBindings { 341 proto := strings.ToUpper(elem.Proto.String()) 342 if proto != "TCP" && proto != "UDP" { 343 return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String()) 344 } 345 346 if elem.HostPort != elem.HostPortEnd { 347 return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings") 348 } 349 350 if len(elem.HostIP) != 0 { 351 return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings") 352 } 353 354 encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{ 355 Type: "NAT", 356 ExternalPort: elem.HostPort, 357 InternalPort: elem.Port, 358 Protocol: elem.Proto.String(), 359 }) 360 361 if err != nil { 362 return nil, err 363 } 364 pbs = append(pbs, encodedPolicy) 365 } 366 return pbs, nil 367 } 368 369 func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) { 370 var bindings []types.PortBinding 371 hcsPolicy := &hcsshim.NatPolicy{} 372 373 for _, elem := range policies { 374 375 if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" { 376 continue 377 } 378 379 binding := types.PortBinding{ 380 HostPort: hcsPolicy.ExternalPort, 381 HostPortEnd: hcsPolicy.ExternalPort, 382 Port: hcsPolicy.InternalPort, 383 Proto: types.ParseProtocol(hcsPolicy.Protocol), 384 HostIP: net.IPv4(0, 0, 0, 0), 385 } 386 387 bindings = append(bindings, binding) 388 } 389 390 return bindings, nil 391 } 392 393 func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { 394 if epOptions == nil { 395 return nil, nil 396 } 397 398 ec := &endpointConfiguration{} 399 400 if opt, ok := epOptions[netlabel.MacAddress]; ok { 401 if mac, ok := opt.(net.HardwareAddr); ok { 402 ec.MacAddress = mac 403 } else { 404 return nil, fmt.Errorf("Invalid endpoint configuration") 405 } 406 } 407 408 if opt, ok := epOptions[netlabel.PortMap]; ok { 409 if bs, ok := opt.([]types.PortBinding); ok { 410 ec.PortBindings = bs 411 } else { 412 return nil, fmt.Errorf("Invalid endpoint configuration") 413 } 414 } 415 416 if opt, ok := epOptions[netlabel.ExposedPorts]; ok { 417 if ports, ok := opt.([]types.TransportPort); ok { 418 ec.ExposedPorts = ports 419 } else { 420 return nil, fmt.Errorf("Invalid endpoint configuration") 421 } 422 } 423 424 if opt, ok := epOptions[QosPolicies]; ok { 425 if policies, ok := opt.([]types.QosPolicy); ok { 426 ec.QosPolicies = policies 427 } else { 428 return nil, fmt.Errorf("Invalid endpoint configuration") 429 } 430 } 431 432 if opt, ok := epOptions[netlabel.DNSServers]; ok { 433 if dns, ok := opt.([]string); ok { 434 ec.DNSServers = dns 435 } else { 436 return nil, fmt.Errorf("Invalid endpoint configuration") 437 } 438 } 439 440 return ec, nil 441 } 442 443 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { 444 n, err := d.getNetwork(nid) 445 if err != nil { 446 return err 447 } 448 449 // Check if endpoint id is good and retrieve corresponding endpoint 450 ep, err := n.getEndpoint(eid) 451 if err == nil && ep != nil { 452 return driverapi.ErrEndpointExists(eid) 453 } 454 455 endpointStruct := &hcsshim.HNSEndpoint{ 456 VirtualNetwork: n.config.HnsID, 457 } 458 459 ec, err := parseEndpointOptions(epOptions) 460 461 macAddress := ifInfo.MacAddress() 462 // Use the macaddress if it was provided 463 if macAddress != nil { 464 endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1) 465 } 466 467 endpointStruct.Policies, err = convertPortBindings(ec.PortBindings) 468 if err != nil { 469 return err 470 } 471 472 qosPolicies, err := convertQosPolicies(ec.QosPolicies) 473 if err != nil { 474 return err 475 } 476 endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...) 477 478 if ifInfo.Address() != nil { 479 endpointStruct.IPAddress = ifInfo.Address().IP 480 } 481 482 endpointStruct.DNSServerList = strings.Join(ec.DNSServers, ",") 483 484 if n.driver.name == "nat" { 485 endpointStruct.EnableInternalDNS = true 486 } 487 488 configurationb, err := json.Marshal(endpointStruct) 489 if err != nil { 490 return err 491 } 492 493 hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb)) 494 if err != nil { 495 return err 496 } 497 498 mac, err := net.ParseMAC(hnsresponse.MacAddress) 499 if err != nil { 500 return err 501 } 502 503 // TODO For now the ip mask is not in the info generated by HNS 504 endpoint := &hnsEndpoint{ 505 id: eid, 506 addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()}, 507 macAddress: mac, 508 } 509 510 endpoint.profileID = hnsresponse.Id 511 endpoint.config = ec 512 endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies) 513 514 if err != nil { 515 hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "") 516 return err 517 } 518 519 n.Lock() 520 n.endpoints[eid] = endpoint 521 n.Unlock() 522 523 if ifInfo.Address() == nil { 524 ifInfo.SetIPAddress(endpoint.addr) 525 } 526 527 if macAddress == nil { 528 ifInfo.SetMacAddress(endpoint.macAddress) 529 } 530 531 return nil 532 } 533 534 func (d *driver) DeleteEndpoint(nid, eid string) error { 535 n, err := d.getNetwork(nid) 536 if err != nil { 537 return types.InternalMaskableErrorf("%s", err) 538 } 539 540 ep, err := n.getEndpoint(eid) 541 if err != nil { 542 return err 543 } 544 545 n.Lock() 546 delete(n.endpoints, eid) 547 n.Unlock() 548 549 _, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "") 550 if err != nil { 551 return err 552 } 553 554 return nil 555 } 556 557 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 558 network, err := d.getNetwork(nid) 559 if err != nil { 560 return nil, err 561 } 562 563 ep, err := network.getEndpoint(eid) 564 if err != nil { 565 return nil, err 566 } 567 568 data := make(map[string]interface{}, 1) 569 if network.driver.name == "nat" { 570 data["AllowUnqualifiedDNSQuery"] = true 571 } 572 573 data["hnsid"] = ep.profileID 574 if ep.config.ExposedPorts != nil { 575 // Return a copy of the config data 576 epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts)) 577 for _, tp := range ep.config.ExposedPorts { 578 epc = append(epc, tp.GetCopy()) 579 } 580 data[netlabel.ExposedPorts] = epc 581 } 582 583 if ep.portMapping != nil { 584 // Return a copy of the operational data 585 pmc := make([]types.PortBinding, 0, len(ep.portMapping)) 586 for _, pm := range ep.portMapping { 587 pmc = append(pmc, pm.GetCopy()) 588 } 589 data[netlabel.PortMap] = pmc 590 } 591 592 if len(ep.macAddress) != 0 { 593 data[netlabel.MacAddress] = ep.macAddress 594 } 595 return data, nil 596 } 597 598 // Join method is invoked when a Sandbox is attached to an endpoint. 599 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 600 network, err := d.getNetwork(nid) 601 if err != nil { 602 return err 603 } 604 605 // Ensure that the endpoint exists 606 _, err = network.getEndpoint(eid) 607 if err != nil { 608 return err 609 } 610 611 // This is just a stub for now 612 613 jinfo.DisableGatewayService() 614 return nil 615 } 616 617 // Leave method is invoked when a Sandbox detaches from an endpoint. 618 func (d *driver) Leave(nid, eid string) error { 619 network, err := d.getNetwork(nid) 620 if err != nil { 621 return types.InternalMaskableErrorf("%s", err) 622 } 623 624 // Ensure that the endpoint exists 625 _, err = network.getEndpoint(eid) 626 if err != nil { 627 return err 628 } 629 630 // This is just a stub for now 631 632 return nil 633 } 634 635 func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { 636 return nil 637 } 638 639 func (d *driver) RevokeExternalConnectivity(nid, eid string) error { 640 return nil 641 } 642 643 func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { 644 return nil, types.NotImplementedErrorf("not implemented") 645 } 646 647 func (d *driver) NetworkFree(id string) error { 648 return types.NotImplementedErrorf("not implemented") 649 } 650 651 func (d *driver) Type() string { 652 return d.name 653 } 654 655 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster 656 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { 657 return nil 658 } 659 660 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster 661 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { 662 return nil 663 }