123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- package overlay
- import (
- "context"
- "encoding/json"
- "fmt"
- "net"
- "strconv"
- "strings"
- "sync"
- "github.com/Microsoft/hcsshim"
- "github.com/containerd/log"
- "github.com/docker/docker/libnetwork/driverapi"
- "github.com/docker/docker/libnetwork/netlabel"
- "github.com/docker/docker/libnetwork/portmapper"
- "github.com/docker/docker/libnetwork/types"
- )
- var (
- hostMode bool
- networkMu sync.Mutex
- )
- type networkTable map[string]*network
- type subnet struct {
- vni uint32
- subnetIP *net.IPNet
- gwIP *net.IP
- }
- type subnetJSON struct {
- SubnetIP string
- GwIP string
- Vni uint32
- }
- type network struct {
- id string
- name string
- hnsID string
- providerAddress string
- interfaceName string
- endpoints endpointTable
- driver *driver
- initEpoch int
- initErr error
- subnets []*subnet
- secure bool
- portMapper *portmapper.PortMapper
- sync.Mutex
- }
- func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
- return nil, types.NotImplementedErrorf("not implemented")
- }
- func (d *driver) NetworkFree(id string) error {
- return types.NotImplementedErrorf("not implemented")
- }
- func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
- var (
- networkName string
- interfaceName string
- staleNetworks []string
- )
- if id == "" {
- return fmt.Errorf("invalid network id")
- }
- if nInfo == nil {
- return fmt.Errorf("invalid network info structure")
- }
- if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
- return types.InvalidParameterErrorf("ipv4 pool is empty")
- }
- staleNetworks = make([]string, 0)
- vnis := make([]uint32, 0, len(ipV4Data))
- existingNetwork := d.network(id)
- if existingNetwork != nil {
- log.G(context.TODO()).Debugf("Network preexists. Deleting %s", id)
- err := d.DeleteNetwork(id)
- if err != nil {
- log.G(context.TODO()).Errorf("Error deleting stale network %s", err.Error())
- }
- }
- n := &network{
- id: id,
- driver: d,
- endpoints: endpointTable{},
- subnets: []*subnet{},
- portMapper: portmapper.New(),
- }
- genData, ok := option[netlabel.GenericData].(map[string]string)
- if !ok {
- return fmt.Errorf("Unknown generic data option")
- }
- for label, value := range genData {
- switch label {
- case "com.docker.network.windowsshim.networkname":
- networkName = value
- case "com.docker.network.windowsshim.interface":
- interfaceName = value
- case "com.docker.network.windowsshim.hnsid":
- n.hnsID = value
- case netlabel.OverlayVxlanIDList:
- vniStrings := strings.Split(value, ",")
- for _, vniStr := range vniStrings {
- vni, err := strconv.Atoi(vniStr)
- if err != nil {
- return fmt.Errorf("invalid vxlan id value %q passed", vniStr)
- }
- vnis = append(vnis, uint32(vni))
- }
- }
- }
- // If we are getting vnis from libnetwork, either we get for
- // all subnets or none.
- if len(vnis) < len(ipV4Data) {
- return fmt.Errorf("insufficient vnis(%d) passed to overlay. Windows driver requires VNIs to be prepopulated", len(vnis))
- }
- for i, ipd := range ipV4Data {
- s := &subnet{
- subnetIP: ipd.Pool,
- gwIP: &ipd.Gateway.IP,
- }
- if len(vnis) != 0 {
- s.vni = vnis[i]
- }
- d.Lock()
- for _, network := range d.networks {
- found := false
- for _, sub := range network.subnets {
- if sub.vni == s.vni {
- staleNetworks = append(staleNetworks, network.id)
- found = true
- break
- }
- }
- if found {
- break
- }
- }
- d.Unlock()
- n.subnets = append(n.subnets, s)
- }
- for _, staleNetwork := range staleNetworks {
- d.DeleteNetwork(staleNetwork)
- }
- n.name = networkName
- if n.name == "" {
- n.name = id
- }
- n.interfaceName = interfaceName
- if nInfo != nil {
- if err := nInfo.TableEventRegister(ovPeerTable, driverapi.EndpointObject); err != nil {
- return err
- }
- }
- d.addNetwork(n)
- err := d.createHnsNetwork(n)
- if err != nil {
- d.deleteNetwork(id)
- } else {
- genData["com.docker.network.windowsshim.hnsid"] = n.hnsID
- }
- return err
- }
- func (d *driver) DeleteNetwork(nid string) error {
- if nid == "" {
- return fmt.Errorf("invalid network id")
- }
- n := d.network(nid)
- if n == nil {
- return types.ForbiddenErrorf("could not find network with id %s", nid)
- }
- _, err := hcsshim.HNSNetworkRequest("DELETE", n.hnsID, "")
- if err != nil {
- return types.ForbiddenErrorf(err.Error())
- }
- d.deleteNetwork(nid)
- return nil
- }
- func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
- return nil
- }
- func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
- return nil
- }
- func (d *driver) addNetwork(n *network) {
- d.Lock()
- d.networks[n.id] = n
- d.Unlock()
- }
- func (d *driver) deleteNetwork(nid string) {
- d.Lock()
- delete(d.networks, nid)
- d.Unlock()
- }
- func (d *driver) network(nid string) *network {
- d.Lock()
- defer d.Unlock()
- return d.networks[nid]
- }
- // func (n *network) restoreNetworkEndpoints() error {
- // log.G(ctx).Infof("Restoring endpoints for overlay network: %s", n.id)
- // hnsresponse, err := hcsshim.HNSListEndpointRequest("GET", "", "")
- // if err != nil {
- // return err
- // }
- // for _, endpoint := range hnsresponse {
- // if endpoint.VirtualNetwork != n.hnsID {
- // continue
- // }
- // ep := n.convertToOverlayEndpoint(&endpoint)
- // if ep != nil {
- // log.G(ctx).Debugf("Restored endpoint:%s Remote:%t", ep.id, ep.remote)
- // n.addEndpoint(ep)
- // }
- // }
- // return nil
- // }
- func (n *network) convertToOverlayEndpoint(v *hcsshim.HNSEndpoint) *endpoint {
- ep := &endpoint{
- id: v.Name,
- profileID: v.Id,
- nid: n.id,
- remote: v.IsRemoteEndpoint,
- }
- mac, err := net.ParseMAC(v.MacAddress)
- if err != nil {
- return nil
- }
- ep.mac = mac
- ep.addr = &net.IPNet{
- IP: v.IPAddress,
- Mask: net.CIDRMask(32, 32),
- }
- return ep
- }
- func (d *driver) createHnsNetwork(n *network) error {
- subnets := []hcsshim.Subnet{}
- for _, s := range n.subnets {
- subnet := hcsshim.Subnet{
- AddressPrefix: s.subnetIP.String(),
- }
- if s.gwIP != nil {
- subnet.GatewayAddress = s.gwIP.String()
- }
- vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
- Type: "VSID",
- VSID: uint(s.vni),
- })
- if err != nil {
- return err
- }
- subnet.Policies = append(subnet.Policies, vsidPolicy)
- subnets = append(subnets, subnet)
- }
- network := &hcsshim.HNSNetwork{
- Name: n.name,
- Type: d.Type(),
- Subnets: subnets,
- NetworkAdapterName: n.interfaceName,
- AutomaticDNS: true,
- }
- configurationb, err := json.Marshal(network)
- if err != nil {
- return err
- }
- configuration := string(configurationb)
- log.G(context.TODO()).Infof("HNSNetwork Request =%v", configuration)
- hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
- if err != nil {
- return err
- }
- n.hnsID = hnsresponse.Id
- n.providerAddress = hnsresponse.ManagementIP
- return nil
- }
- // contains return true if the passed ip belongs to one the network's
- // subnets
- func (n *network) contains(ip net.IP) bool {
- for _, s := range n.subnets {
- if s.subnetIP.Contains(ip) {
- return true
- }
- }
- return false
- }
- // getSubnetforIP returns the subnet to which the given IP belongs
- func (n *network) getSubnetforIP(ip *net.IPNet) *subnet {
- for _, s := range n.subnets {
- // first check if the mask lengths are the same
- i, _ := s.subnetIP.Mask.Size()
- j, _ := ip.Mask.Size()
- if i != j {
- continue
- }
- if s.subnetIP.Contains(ip.IP) {
- return s
- }
- }
- return nil
- }
- // getMatchingSubnet return the network's subnet that matches the input
- func (n *network) getMatchingSubnet(ip *net.IPNet) *subnet {
- if ip == nil {
- return nil
- }
- for _, s := range n.subnets {
- // first check if the mask lengths are the same
- i, _ := s.subnetIP.Mask.Size()
- j, _ := ip.Mask.Size()
- if i != j {
- continue
- }
- if s.subnetIP.IP.Equal(ip.IP) {
- return s
- }
- }
- return nil
- }
|