...

Source file src/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go

Documentation: github.com/Microsoft/hcsshim/hcn

     1  //go:build windows
     2  
     3  package hcn
     4  
     5  import (
     6  	"encoding/json"
     7  	"errors"
     8  
     9  	"github.com/Microsoft/go-winio/pkg/guid"
    10  	"github.com/Microsoft/hcsshim/internal/interop"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  // Route is associated with a subnet.
    15  type Route struct {
    16  	NextHop           string `json:",omitempty"`
    17  	DestinationPrefix string `json:",omitempty"`
    18  	Metric            uint16 `json:",omitempty"`
    19  }
    20  
    21  // Subnet is associated with a Ipam.
    22  type Subnet struct {
    23  	IpAddressPrefix string            `json:",omitempty"`
    24  	Policies        []json.RawMessage `json:",omitempty"`
    25  	Routes          []Route           `json:",omitempty"`
    26  }
    27  
    28  // Ipam (Internet Protocol Address Management) is associated with a network
    29  // and represents the address space(s) of a network.
    30  type Ipam struct {
    31  	Type    string   `json:",omitempty"` // Ex: Static, DHCP
    32  	Subnets []Subnet `json:",omitempty"`
    33  }
    34  
    35  // MacRange is associated with MacPool and respresents the start and end addresses.
    36  type MacRange struct {
    37  	StartMacAddress string `json:",omitempty"`
    38  	EndMacAddress   string `json:",omitempty"`
    39  }
    40  
    41  // MacPool is associated with a network and represents pool of MacRanges.
    42  type MacPool struct {
    43  	Ranges []MacRange `json:",omitempty"`
    44  }
    45  
    46  // Dns (Domain Name System is associated with a network).
    47  type Dns struct {
    48  	Domain     string   `json:",omitempty"`
    49  	Search     []string `json:",omitempty"`
    50  	ServerList []string `json:",omitempty"`
    51  	Options    []string `json:",omitempty"`
    52  }
    53  
    54  // NetworkType are various networks.
    55  type NetworkType string
    56  
    57  // NetworkType const
    58  const (
    59  	NAT         NetworkType = "NAT"
    60  	Transparent NetworkType = "Transparent"
    61  	L2Bridge    NetworkType = "L2Bridge"
    62  	L2Tunnel    NetworkType = "L2Tunnel"
    63  	ICS         NetworkType = "ICS"
    64  	Private     NetworkType = "Private"
    65  	Overlay     NetworkType = "Overlay"
    66  )
    67  
    68  // NetworkFlags are various network flags.
    69  type NetworkFlags uint32
    70  
    71  // NetworkFlags const
    72  const (
    73  	None                NetworkFlags = 0
    74  	EnableNonPersistent NetworkFlags = 8
    75  )
    76  
    77  // HostComputeNetwork represents a network
    78  type HostComputeNetwork struct {
    79  	Id            string          `json:"ID,omitempty"`
    80  	Name          string          `json:",omitempty"`
    81  	Type          NetworkType     `json:",omitempty"`
    82  	Policies      []NetworkPolicy `json:",omitempty"`
    83  	MacPool       MacPool         `json:",omitempty"`
    84  	Dns           Dns             `json:",omitempty"`
    85  	Ipams         []Ipam          `json:",omitempty"`
    86  	Flags         NetworkFlags    `json:",omitempty"` // 0: None
    87  	Health        Health          `json:",omitempty"`
    88  	SchemaVersion SchemaVersion   `json:",omitempty"`
    89  }
    90  
    91  // NetworkResourceType are the 3 different Network settings resources.
    92  type NetworkResourceType string
    93  
    94  var (
    95  	// NetworkResourceTypePolicy is for Network's policies. Ex: RemoteSubnet
    96  	NetworkResourceTypePolicy NetworkResourceType = "Policy"
    97  	// NetworkResourceTypeDNS is for Network's DNS settings.
    98  	NetworkResourceTypeDNS NetworkResourceType = "DNS"
    99  	// NetworkResourceTypeExtension is for Network's extension settings.
   100  	NetworkResourceTypeExtension NetworkResourceType = "Extension"
   101  )
   102  
   103  // ModifyNetworkSettingRequest is the structure used to send request to modify an network.
   104  // Used to update DNS/extension/policy on an network.
   105  type ModifyNetworkSettingRequest struct {
   106  	ResourceType NetworkResourceType `json:",omitempty"` // Policy, DNS, Extension
   107  	RequestType  RequestType         `json:",omitempty"` // Add, Remove, Update, Refresh
   108  	Settings     json.RawMessage     `json:",omitempty"`
   109  }
   110  
   111  type PolicyNetworkRequest struct {
   112  	Policies []NetworkPolicy `json:",omitempty"`
   113  }
   114  
   115  func getNetwork(networkGUID guid.GUID, query string) (*HostComputeNetwork, error) {
   116  	// Open network.
   117  	var (
   118  		networkHandle    hcnNetwork
   119  		resultBuffer     *uint16
   120  		propertiesBuffer *uint16
   121  	)
   122  	hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
   123  	if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
   124  		return nil, err
   125  	}
   126  	// Query network.
   127  	hr = hcnQueryNetworkProperties(networkHandle, query, &propertiesBuffer, &resultBuffer)
   128  	if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
   129  		return nil, err
   130  	}
   131  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
   132  	// Close network.
   133  	hr = hcnCloseNetwork(networkHandle)
   134  	if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
   135  		return nil, err
   136  	}
   137  	// Convert output to HostComputeNetwork
   138  	var outputNetwork HostComputeNetwork
   139  
   140  	// If HNS sets the network type to NAT (i.e. '0' in HNS.Schema.Network.NetworkMode),
   141  	// the value will be omitted from the JSON blob. We therefore need to initialize NAT here before
   142  	// unmarshaling the JSON blob.
   143  	outputNetwork.Type = NAT
   144  
   145  	if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
   146  		return nil, err
   147  	}
   148  	return &outputNetwork, nil
   149  }
   150  
   151  func enumerateNetworks(query string) ([]HostComputeNetwork, error) {
   152  	// Enumerate all Network Guids
   153  	var (
   154  		resultBuffer  *uint16
   155  		networkBuffer *uint16
   156  	)
   157  	hr := hcnEnumerateNetworks(query, &networkBuffer, &resultBuffer)
   158  	if err := checkForErrors("hcnEnumerateNetworks", hr, resultBuffer); err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	networks := interop.ConvertAndFreeCoTaskMemString(networkBuffer)
   163  	var networkIds []guid.GUID
   164  	if err := json.Unmarshal([]byte(networks), &networkIds); err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	var outputNetworks []HostComputeNetwork
   169  	for _, networkGUID := range networkIds {
   170  		network, err := getNetwork(networkGUID, query)
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  		outputNetworks = append(outputNetworks, *network)
   175  	}
   176  	return outputNetworks, nil
   177  }
   178  
   179  func createNetwork(settings string) (*HostComputeNetwork, error) {
   180  	// Create new network.
   181  	var (
   182  		networkHandle    hcnNetwork
   183  		resultBuffer     *uint16
   184  		propertiesBuffer *uint16
   185  	)
   186  	networkGUID := guid.GUID{}
   187  	hr := hcnCreateNetwork(&networkGUID, settings, &networkHandle, &resultBuffer)
   188  	if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil {
   189  		return nil, err
   190  	}
   191  	// Query network.
   192  	hcnQuery := defaultQuery()
   193  	query, err := json.Marshal(hcnQuery)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	hr = hcnQueryNetworkProperties(networkHandle, string(query), &propertiesBuffer, &resultBuffer)
   198  	if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
   199  		return nil, err
   200  	}
   201  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
   202  	// Close network.
   203  	hr = hcnCloseNetwork(networkHandle)
   204  	if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
   205  		return nil, err
   206  	}
   207  	// Convert output to HostComputeNetwork
   208  	var outputNetwork HostComputeNetwork
   209  
   210  	// If HNS sets the network type to NAT (i.e. '0' in HNS.Schema.Network.NetworkMode),
   211  	// the value will be omitted from the JSON blob. We therefore need to initialize NAT here before
   212  	// unmarshaling the JSON blob.
   213  	outputNetwork.Type = NAT
   214  
   215  	if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
   216  		return nil, err
   217  	}
   218  	return &outputNetwork, nil
   219  }
   220  
   221  func modifyNetwork(networkID string, settings string) (*HostComputeNetwork, error) {
   222  	networkGUID, err := guid.FromString(networkID)
   223  	if err != nil {
   224  		return nil, errInvalidNetworkID
   225  	}
   226  	// Open Network
   227  	var (
   228  		networkHandle    hcnNetwork
   229  		resultBuffer     *uint16
   230  		propertiesBuffer *uint16
   231  	)
   232  	hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
   233  	if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
   234  		return nil, err
   235  	}
   236  	// Modify Network
   237  	hr = hcnModifyNetwork(networkHandle, settings, &resultBuffer)
   238  	if err := checkForErrors("hcnModifyNetwork", hr, resultBuffer); err != nil {
   239  		return nil, err
   240  	}
   241  	// Query network.
   242  	hcnQuery := defaultQuery()
   243  	query, err := json.Marshal(hcnQuery)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	hr = hcnQueryNetworkProperties(networkHandle, string(query), &propertiesBuffer, &resultBuffer)
   248  	if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
   249  		return nil, err
   250  	}
   251  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
   252  	// Close network.
   253  	hr = hcnCloseNetwork(networkHandle)
   254  	if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
   255  		return nil, err
   256  	}
   257  	// Convert output to HostComputeNetwork
   258  	var outputNetwork HostComputeNetwork
   259  
   260  	// If HNS sets the network type to NAT (i.e. '0' in HNS.Schema.Network.NetworkMode),
   261  	// the value will be omitted from the JSON blob. We therefore need to initialize NAT here before
   262  	// unmarshaling the JSON blob.
   263  	outputNetwork.Type = NAT
   264  
   265  	if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
   266  		return nil, err
   267  	}
   268  	return &outputNetwork, nil
   269  }
   270  
   271  func deleteNetwork(networkID string) error {
   272  	networkGUID, err := guid.FromString(networkID)
   273  	if err != nil {
   274  		return errInvalidNetworkID
   275  	}
   276  	var resultBuffer *uint16
   277  	hr := hcnDeleteNetwork(&networkGUID, &resultBuffer)
   278  	if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil {
   279  		return err
   280  	}
   281  	return nil
   282  }
   283  
   284  // ListNetworks makes a call to list all available networks.
   285  func ListNetworks() ([]HostComputeNetwork, error) {
   286  	hcnQuery := defaultQuery()
   287  	networks, err := ListNetworksQuery(hcnQuery)
   288  	if err != nil {
   289  		return nil, err
   290  	}
   291  	return networks, nil
   292  }
   293  
   294  // ListNetworksQuery makes a call to query the list of available networks.
   295  func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) {
   296  	queryJSON, err := json.Marshal(query)
   297  	if err != nil {
   298  		return nil, err
   299  	}
   300  
   301  	networks, err := enumerateNetworks(string(queryJSON))
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  	return networks, nil
   306  }
   307  
   308  // GetNetworkByID returns the network specified by Id.
   309  func GetNetworkByID(networkID string) (*HostComputeNetwork, error) {
   310  	hcnQuery := defaultQuery()
   311  	mapA := map[string]string{"ID": networkID}
   312  	filter, err := json.Marshal(mapA)
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  	hcnQuery.Filter = string(filter)
   317  
   318  	networks, err := ListNetworksQuery(hcnQuery)
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	if len(networks) == 0 {
   323  		return nil, NetworkNotFoundError{NetworkID: networkID}
   324  	}
   325  	return &networks[0], err
   326  }
   327  
   328  // GetNetworkByName returns the network specified by Name.
   329  func GetNetworkByName(networkName string) (*HostComputeNetwork, error) {
   330  	hcnQuery := defaultQuery()
   331  	mapA := map[string]string{"Name": networkName}
   332  	filter, err := json.Marshal(mapA)
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  	hcnQuery.Filter = string(filter)
   337  
   338  	networks, err := ListNetworksQuery(hcnQuery)
   339  	if err != nil {
   340  		return nil, err
   341  	}
   342  	if len(networks) == 0 {
   343  		return nil, NetworkNotFoundError{NetworkName: networkName}
   344  	}
   345  	return &networks[0], err
   346  }
   347  
   348  // Create Network.
   349  func (network *HostComputeNetwork) Create() (*HostComputeNetwork, error) {
   350  	logrus.Debugf("hcn::HostComputeNetwork::Create id=%s", network.Id)
   351  	for _, ipam := range network.Ipams {
   352  		for _, subnet := range ipam.Subnets {
   353  			if subnet.IpAddressPrefix != "" {
   354  				hasDefault := false
   355  				for _, route := range subnet.Routes {
   356  					if route.NextHop == "" {
   357  						return nil, errors.New("network create error, subnet has address prefix but no gateway specified")
   358  					}
   359  					if route.DestinationPrefix == "0.0.0.0/0" || route.DestinationPrefix == "::/0" {
   360  						hasDefault = true
   361  					}
   362  				}
   363  				if !hasDefault {
   364  					return nil, errors.New("network create error, no default gateway")
   365  				}
   366  			}
   367  		}
   368  	}
   369  
   370  	jsonString, err := json.Marshal(network)
   371  	if err != nil {
   372  		return nil, err
   373  	}
   374  
   375  	logrus.Debugf("hcn::HostComputeNetwork::Create JSON: %s", jsonString)
   376  	network, hcnErr := createNetwork(string(jsonString))
   377  	if hcnErr != nil {
   378  		return nil, hcnErr
   379  	}
   380  	return network, nil
   381  }
   382  
   383  // Delete Network.
   384  func (network *HostComputeNetwork) Delete() error {
   385  	logrus.Debugf("hcn::HostComputeNetwork::Delete id=%s", network.Id)
   386  
   387  	if err := deleteNetwork(network.Id); err != nil {
   388  		return err
   389  	}
   390  	return nil
   391  }
   392  
   393  // ModifyNetworkSettings updates the Policy for a network.
   394  func (network *HostComputeNetwork) ModifyNetworkSettings(request *ModifyNetworkSettingRequest) error {
   395  	logrus.Debugf("hcn::HostComputeNetwork::ModifyNetworkSettings id=%s", network.Id)
   396  
   397  	networkSettingsRequest, err := json.Marshal(request)
   398  	if err != nil {
   399  		return err
   400  	}
   401  
   402  	_, err = modifyNetwork(network.Id, string(networkSettingsRequest))
   403  	if err != nil {
   404  		return err
   405  	}
   406  	return nil
   407  }
   408  
   409  // AddPolicy applies a Policy (ex: RemoteSubnet) on the Network.
   410  func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error {
   411  	logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id)
   412  
   413  	settingsJSON, err := json.Marshal(networkPolicy)
   414  	if err != nil {
   415  		return err
   416  	}
   417  	requestMessage := &ModifyNetworkSettingRequest{
   418  		ResourceType: NetworkResourceTypePolicy,
   419  		RequestType:  RequestTypeAdd,
   420  		Settings:     settingsJSON,
   421  	}
   422  
   423  	return network.ModifyNetworkSettings(requestMessage)
   424  }
   425  
   426  // RemovePolicy removes a Policy (ex: RemoteSubnet) from the Network.
   427  func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error {
   428  	logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id)
   429  
   430  	settingsJSON, err := json.Marshal(networkPolicy)
   431  	if err != nil {
   432  		return err
   433  	}
   434  	requestMessage := &ModifyNetworkSettingRequest{
   435  		ResourceType: NetworkResourceTypePolicy,
   436  		RequestType:  RequestTypeRemove,
   437  		Settings:     settingsJSON,
   438  	}
   439  
   440  	return network.ModifyNetworkSettings(requestMessage)
   441  }
   442  
   443  // CreateEndpoint creates an endpoint on the Network.
   444  func (network *HostComputeNetwork) CreateEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) {
   445  	isRemote := endpoint.Flags&EndpointFlagsRemoteEndpoint != 0
   446  	logrus.Debugf("hcn::HostComputeNetwork::CreatEndpoint, networkId=%s remote=%t", network.Id, isRemote)
   447  
   448  	endpoint.HostComputeNetwork = network.Id
   449  	endpointSettings, err := json.Marshal(endpoint)
   450  	if err != nil {
   451  		return nil, err
   452  	}
   453  	newEndpoint, err := createEndpoint(network.Id, string(endpointSettings))
   454  	if err != nil {
   455  		return nil, err
   456  	}
   457  	return newEndpoint, nil
   458  }
   459  
   460  // CreateRemoteEndpoint creates a remote endpoint on the Network.
   461  func (network *HostComputeNetwork) CreateRemoteEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) {
   462  	endpoint.Flags = EndpointFlagsRemoteEndpoint | endpoint.Flags
   463  	return network.CreateEndpoint(endpoint)
   464  }
   465  

View as plain text