azure-container-networking/network/network.go

356 строки
10 KiB
Go

// Copyright 2017 Microsoft. All rights reserved.
// MIT License
package network
import (
"fmt"
"net"
"strings"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/network/policy"
"github.com/Azure/azure-container-networking/platform"
"github.com/pkg/errors"
"go.uber.org/zap"
)
const (
// Operational modes.
opModeBridge = "bridge"
opModeTunnel = "tunnel"
opModeTransparent = "transparent"
opModeTransparentVlan = "transparent-vlan"
opModeDefault = opModeTunnel
)
const (
// ipv6 modes
IPV6Nat = "ipv6nat"
)
// externalInterface is a host network interface that bridges containers to external networks.
type externalInterface struct {
Name string
Networks map[string]*network
Subnets []string
BridgeName string
DNSInfo DNSInfo
MacAddress net.HardwareAddr
IPAddresses []*net.IPNet
Routes []*route
IPv4Gateway net.IP
IPv6Gateway net.IP
}
// A container network is a set of endpoints allowed to communicate with each other.
type network struct {
Id string
HnsId string `json:",omitempty"`
Mode string
VlanId int
Subnets []SubnetInfo
Endpoints map[string]*endpoint
extIf *externalInterface
DNS DNSInfo
EnableSnatOnHost bool
NetNs string
SnatBridgeIP string
}
// NetworkInfo contains read-only information about a container network. Use EndpointInfo instead when possible.
type NetworkInfo struct {
MasterIfName string
AdapterName string
Id string
Mode string
Subnets []SubnetInfo
PodSubnet SubnetInfo
DNS DNSInfo
Policies []policy.Policy
BridgeName string
EnableSnatOnHost bool
NetNs string
Options map[string]interface{}
DisableHairpinOnHostInterface bool
IPV6Mode string
IPAMType string
ServiceCidrs string
IsIPv6Enabled bool
}
// SubnetInfo contains subnet information for a container network.
type SubnetInfo struct {
Family platform.AddressFamily
Prefix net.IPNet
Gateway net.IP
PrimaryIP net.IP
}
// DNSInfo contains DNS information for a container network or endpoint.
type DNSInfo struct {
Suffix string
Servers []string
Options []string
}
func (nwInfo *NetworkInfo) PrettyString() string {
return fmt.Sprintf("Id:%s MasterIfName:%s AdapterName:%s Mode:%s Subnets:%v podsubnet:%v Enablesnatonhost:%t", nwInfo.Id, nwInfo.MasterIfName,
nwInfo.AdapterName, nwInfo.Mode, nwInfo.Subnets, nwInfo.PodSubnet, nwInfo.EnableSnatOnHost)
}
// NewExternalInterface adds a host interface to the list of available external interfaces.
func (nm *networkManager) newExternalInterface(ifName, subnet, nicType string) error {
// Check whether the external interface is already configured.
if nm.ExternalInterfaces[ifName] != nil {
return nil
}
// Find the host interface.
macAddress := net.HardwareAddr{}
if nicType != string(cns.BackendNIC) {
hostIf, err := net.InterfaceByName(ifName)
if err != nil {
return errors.Wrap(err, "failed to find host interface")
}
macAddress = hostIf.HardwareAddr
}
extIf := externalInterface{
Name: ifName,
Networks: make(map[string]*network),
MacAddress: macAddress,
IPv4Gateway: net.IPv4zero,
IPv6Gateway: net.IPv6unspecified,
}
extIf.Subnets = append(extIf.Subnets, subnet)
nm.ExternalInterfaces[ifName] = &extIf
logger.Info("Added ExternalInterface for subnet", zap.String("ifName", ifName), zap.String("subnet", subnet))
return nil
}
// DeleteExternalInterface removes an interface from the list of available external interfaces.
func (nm *networkManager) deleteExternalInterface(ifName string) error {
delete(nm.ExternalInterfaces, ifName)
logger.Info("Deleted ExternalInterface", zap.String("ifName", ifName))
return nil
}
// FindExternalInterfaceBySubnet finds an external interface connected to the given subnet.
func (nm *networkManager) findExternalInterfaceBySubnet(subnet string) *externalInterface {
for _, extIf := range nm.ExternalInterfaces {
for _, s := range extIf.Subnets {
if s == subnet {
return extIf
}
}
}
return nil
}
// FindExternalInterfaceByName finds an external interface by name.
func (nm *networkManager) findExternalInterfaceByName(ifName string) *externalInterface {
extIf, exists := nm.ExternalInterfaces[ifName]
if exists && extIf != nil {
return extIf
}
return nil
}
func (nm *networkManager) findExternalInterface(nwInfo *EndpointInfo) (*externalInterface, error) {
extIf := &externalInterface{}
if len(strings.TrimSpace(nwInfo.MasterIfName)) > 0 {
extIf = nm.findExternalInterfaceByName(nwInfo.MasterIfName)
} else {
extIf = nm.findExternalInterfaceBySubnet(nwInfo.Subnets[0].Prefix.String())
}
if extIf == nil {
err := errSubnetNotFound
return nil, err
}
// Make sure this network does not already exist.
if extIf.Networks[nwInfo.NetworkID] != nil {
err := errNetworkExists
return nil, err
}
return extIf, nil
}
// NewNetwork creates a new container network.
func (nm *networkManager) newNetwork(nwInfo *EndpointInfo) (*network, error) {
var nw *network
var err error
logger.Info("Creating", zap.String("network", nwInfo.PrettyString()))
defer func() {
if err != nil {
logger.Error("Failed to create network", zap.String("id", nwInfo.NetworkID), zap.Error(err))
}
}()
// Set defaults.
if nwInfo.Mode == "" {
nwInfo.Mode = opModeDefault
}
// If the master interface name is provided, find the external interface by name
// else use subnet to to find the interface
extIf, err := nm.findExternalInterface(nwInfo)
if err != nil {
return nil, err // nolint
}
// Call the OS-specific implementation.
nw, err = nm.newNetworkImpl(nwInfo, extIf)
if err != nil {
return nil, err
}
// Add the network object.
nw.Subnets = nwInfo.Subnets
extIf.Networks[nwInfo.NetworkID] = nw
logger.Info("Created network on interface", zap.String("id", nwInfo.NetworkID), zap.String("Name", extIf.Name))
return nw, nil
}
// DeleteNetwork deletes an existing container network.
func (nm *networkManager) deleteNetwork(networkID string) error {
var err error
logger.Info("Deleting network", zap.String("networkID", networkID))
defer func() {
if err != nil {
logger.Error("Failed to delete network", zap.String("networkID", networkID), zap.Error(err))
}
}()
// Find the network.
nw, err := nm.getNetwork(networkID)
if err != nil {
return err
}
// Call the OS-specific implementation.
err = nm.deleteNetworkImpl(nw, cns.InfraNIC)
if err != nil {
return err
}
// Remove the network object.
if nw.extIf != nil {
delete(nw.extIf.Networks, networkID)
}
logger.Info("Deleted network", zap.Any("nw", nw))
return nil
}
// GetNetwork returns the network with the given ID.
func (nm *networkManager) getNetwork(networkId string) (*network, error) {
for _, extIf := range nm.ExternalInterfaces {
nw, ok := extIf.Networks[networkId]
if ok {
return nw, nil
}
}
return nil, errNetworkNotFound
}
// getNetworkIDForNetNs finds the network that contains the endpoint that was created for this netNs. Returns
// and errNetworkNotFound if the netNs is not found in any network
func (nm *networkManager) FindNetworkIDFromNetNs(netNs string) (string, error) {
logger.Info("Querying state for network for NetNs", zap.String("netNs", netNs))
// Look through the external interfaces
for _, iface := range nm.ExternalInterfaces {
// Look through the networks
for _, network := range iface.Networks {
// Network may have multiple endpoints, so look through all of them
for _, endpoint := range network.Endpoints {
// If the netNs matches for this endpoint, return the network ID (which is the name)
if endpoint.NetNs == netNs {
logger.Info("Found network for NetNS", zap.String("id", network.Id), zap.String("netNs", netNs))
return network.Id, nil
}
}
}
}
return "", errNetworkNotFound
}
// GetNumEndpointsInNetNs returns number of endpoints
func (nm *networkManager) GetNumEndpointsByContainerID(containerID string) int {
numEndpoints := 0
// Look through the external interfaces
for _, iface := range nm.ExternalInterfaces {
// Look through the networks
for _, network := range iface.Networks {
// Network may have multiple endpoints, so look through all of them
for _, endpoint := range network.Endpoints {
// If the netNs matches for this endpoint, return the network ID (which is the name)
if endpoint.ContainerID == containerID {
logger.Info("Found endpoint for containerID", zap.String("id", endpoint.Id), zap.String("containerID", containerID))
numEndpoints++
}
}
}
}
return numEndpoints
}
// Creates the network and corresponding endpoint (should be called once during Add)
func (nm *networkManager) EndpointCreate(cnsclient apipaClient, epInfos []*EndpointInfo) error {
eps := []*endpoint{} // save endpoints for stateless
for _, epInfo := range epInfos {
logger.Info("Creating endpoint and network", zap.String("endpointInfo", epInfo.PrettyString()))
// check if network exists by searching through all external interfaces for the network
_, nwGetErr := nm.GetNetworkInfo(epInfo.NetworkID)
if nwGetErr != nil {
logger.Info("Existing network not found", zap.String("networkID", epInfo.NetworkID))
logger.Info("Found master interface", zap.String("masterIfName", epInfo.MasterIfName))
// Add the master as an external interface.
err := nm.AddExternalInterface(epInfo.MasterIfName, epInfo.HostSubnetPrefix, string(epInfo.NICType))
if err != nil {
return err
}
// Create the network if it is not found
err = nm.CreateNetwork(epInfo)
if err != nil {
return err
}
}
ep, err := nm.createEndpoint(cnsclient, epInfo.NetworkID, epInfo)
if err != nil {
return err
}
eps = append(eps, ep)
}
if err := validateEndpoints(eps); err != nil {
return err
}
// save endpoints
return nm.SaveState(eps)
}