Implement CNI update for Azure CNI (#265)

* Implement CNI Update for Azure CNI (#21)
This commit is contained in:
Sushant Sharma 2018-10-29 11:10:27 -07:00 коммит произвёл Yongli Chen
Родитель 5f123a0c15
Коммит 6e6260afe5
12 изменённых файлов: 618 добавлений и 88 удалений

Просмотреть файл

@ -9,10 +9,11 @@ import (
const (
// CNI commands.
Cmd = "CNI_COMMAND"
CmdAdd = "ADD"
CmdGet = "GET"
CmdDel = "DEL"
Cmd = "CNI_COMMAND"
CmdAdd = "ADD"
CmdGet = "GET"
CmdDel = "DEL"
CmdUpdate = "UPDATE"
// CNI errors.
ErrRuntime = 100
@ -29,4 +30,5 @@ type PluginApi interface {
Add(args *cniSkel.CmdArgs) error
Get(args *cniSkel.CmdArgs) error
Delete(args *cniSkel.CmdArgs) error
Update(args *cniSkel.CmdArgs) error
}

Просмотреть файл

@ -290,3 +290,8 @@ func (plugin *ipamPlugin) Delete(args *cniSkel.CmdArgs) error {
return nil
}
// Update handles CNI update command.
func (plugin *ipamPlugin) Update(args *cniSkel.CmdArgs) error {
return nil
}

Просмотреть файл

@ -48,6 +48,7 @@ type NetworkConfig struct {
MultiTenancy bool `json:"multiTenancy,omitempty"`
EnableSnatOnHost bool `json:"enableSnatOnHost,omitempty"`
EnableExactMatchForPodName bool `json:"enableExactMatchForPodName,omitempty"`
CNSUrl string `json:"cnsurl,omitempty"`
Ipam struct {
Type string `json:"type"`
Environment string `json:"environment,omitempty"`

Просмотреть файл

@ -205,6 +205,7 @@ func checkIfSubnetOverlaps(enableInfraVnet bool, nwCfg *cni.NetworkConfig, cnsNe
return false
}
// GetMultiTenancyCNIResult retrieves network goal state of a container from CNS
func GetMultiTenancyCNIResult(
enableInfraVnet bool,
nwCfg *cni.NetworkConfig,
@ -214,7 +215,7 @@ func GetMultiTenancyCNIResult(
ifName string) (*cniTypesCurr.Result, *cns.GetNetworkContainerResponse, net.IPNet, *cniTypesCurr.Result, error) {
if nwCfg.MultiTenancy {
result, cnsNetworkConfig, subnetPrefix, err := getContainerNetworkConfiguration(nwCfg, "", k8sPodName, k8sNamespace, ifName)
result, cnsNetworkConfig, subnetPrefix, err := getContainerNetworkConfiguration(nwCfg, nwCfg.CNSUrl, k8sPodName, k8sNamespace, ifName)
if err != nil {
log.Printf("GetContainerNetworkConfiguration failed for podname %v namespace %v with error %v", k8sPodName, k8sNamespace, err)
return nil, nil, net.IPNet{}, nil, err

Просмотреть файл

@ -4,11 +4,13 @@
package network
import (
"encoding/json"
"fmt"
"net"
"github.com/Azure/azure-container-networking/cni"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/cnsclient"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/network"
@ -397,17 +399,20 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) error {
}
epInfo = &network.EndpointInfo{
Id: endpointId,
ContainerID: args.ContainerID,
NetNsPath: args.Netns,
IfName: args.IfName,
EnableSnatOnHost: nwCfg.EnableSnatOnHost,
EnableInfraVnet: enableInfraVnet,
Data: make(map[string]interface{}),
DNS: epDNSInfo,
Policies: policies,
Id: endpointId,
ContainerID: args.ContainerID,
NetNsPath: args.Netns,
IfName: args.IfName,
Data: make(map[string]interface{}),
DNS: epDNSInfo,
Policies: policies,
EnableSnatOnHost: nwCfg.EnableSnatOnHost,
EnableMultiTenancy: nwCfg.MultiTenancy,
EnableInfraVnet: enableInfraVnet,
PODName: k8sPodName,
PODNameSpace: k8sNamespace,
}
epPolicies := getPoliciesFromRuntimeCfg(nwCfg)
for _, epPolicy := range epPolicies {
epInfo.Policies = append(epInfo.Policies, epPolicy)
@ -599,3 +604,159 @@ func (plugin *netPlugin) Delete(args *cniSkel.CmdArgs) error {
return nil
}
// Update handles CNI update commands.
// Update is only supported for multitenancy and to update routes.
func (plugin *netPlugin) Update(args *cniSkel.CmdArgs) error {
var (
result *cniTypesCurr.Result
err error
nwCfg *cni.NetworkConfig
existingEpInfo *network.EndpointInfo
)
log.Printf("[cni-net] Processing UPDATE command with args {Netns:%v Args:%v Path:%v}.",
args.Netns, args.Args, args.Path)
// Parse network configuration from stdin.
nwCfg, err = cni.ParseNetworkConfig(args.StdinData)
if err != nil {
err = plugin.Errorf("Failed to parse network configuration: %v.", err)
return err
}
log.Printf("[cni-net] Read network configuration %+v.", nwCfg)
defer func() {
if result == nil {
result = &cniTypesCurr.Result{}
}
// Convert result to the requested CNI version.
res, vererr := result.GetAsVersion(nwCfg.CNIVersion)
if vererr != nil {
log.Printf("GetAsVersion failed with error %v", vererr)
plugin.Error(vererr)
}
if err == nil && res != nil {
// Output the result to stdout.
res.Print()
}
log.Printf("[cni-net] UPDATE command completed with result:%+v err:%v.", result, err)
}()
// Parse Pod arguments.
podCfg, err := cni.ParseCniArgs(args.Args)
if err != nil {
log.Printf("Error while parsing CNI Args during UPDATE %v", err)
return err
}
k8sNamespace := string(podCfg.K8S_POD_NAMESPACE)
if len(k8sNamespace) == 0 {
errMsg := "Required parameter Pod Namespace not specified in CNI Args during UPDATE"
log.Printf(errMsg)
return plugin.Errorf(errMsg)
}
k8sPodName := string(podCfg.K8S_POD_NAME)
if len(k8sPodName) == 0 {
errMsg := "Required parameter Pod Name not specified in CNI Args during UPDATE"
log.Printf(errMsg)
return plugin.Errorf(errMsg)
}
// Initialize values from network config.
networkID := nwCfg.Name
// Query the network.
_, err = plugin.nm.GetNetworkInfo(networkID)
if err != nil {
errMsg := fmt.Sprintf("Failed to query network during CNI UPDATE: %v", err)
log.Printf(errMsg)
return plugin.Errorf(errMsg)
}
// Query the existing endpoint since this is an update.
// Right now, we do not support updating pods that have multiple endpoints.
existingEpInfo, err = plugin.nm.GetEndpointInfoBasedOnPODDetails(networkID, k8sPodName, k8sNamespace)
if err != nil {
plugin.Errorf("Failed to retrieve target endpoint for CNI UPDATE [name=%v, namespace=%v]: %v", k8sPodName, k8sNamespace, err)
return err
} else {
log.Printf("Retrieved existing endpoint from state that may get update: %+v", existingEpInfo)
}
// now query CNS to get the target routes that should be there in the networknamespace (as a result of update)
log.Printf("Going to collect target routes for [name=%v, namespace=%v] from CNS.", k8sPodName, k8sNamespace)
cnsClient, err := cnsclient.NewCnsClient(nwCfg.CNSUrl)
if err != nil {
log.Printf("Initializing CNS client error in CNI Update%v", err)
log.Printf(err.Error())
return plugin.Errorf(err.Error())
}
// create struct with info for target POD
podInfo := cns.KubernetesPodInfo{PodName: k8sPodName, PodNamespace: k8sNamespace}
orchestratorContext, err := json.Marshal(podInfo)
if err != nil {
log.Printf("Marshalling KubernetesPodInfo failed with %v", err)
return plugin.Errorf(err.Error())
}
targetNetworkConfig, err := cnsClient.GetNetworkConfiguration(orchestratorContext)
if err != nil {
log.Printf("GetNetworkConfiguration failed with %v", err)
return plugin.Errorf(err.Error())
}
log.Printf("Network config received from cns for [name=%v, namespace=%v] is as follows -> %+v", k8sPodName, k8sNamespace, targetNetworkConfig)
targetEpInfo := &network.EndpointInfo{}
// get the target routes that should replace existingEpInfo.Routes inside the network namespace
log.Printf("Going to collect target routes for [name=%v, namespace=%v] from targetNetworkConfig.", k8sPodName, k8sNamespace)
if targetNetworkConfig.Routes != nil && len(targetNetworkConfig.Routes) > 0 {
for _, route := range targetNetworkConfig.Routes {
log.Printf("Adding route from routes to targetEpInfo %+v", route)
_, dstIPNet, _ := net.ParseCIDR(route.IPAddress)
gwIP := net.ParseIP(route.GatewayIPAddress)
targetEpInfo.Routes = append(targetEpInfo.Routes, network.RouteInfo{Dst: *dstIPNet, Gw: gwIP, DevName: existingEpInfo.IfName})
log.Printf("Successfully added route from routes to targetEpInfo %+v", route)
}
}
log.Printf("Going to collect target routes based on Cnetaddressspace for [name=%v, namespace=%v] from targetNetworkConfig.", k8sPodName, k8sNamespace)
ipconfig := targetNetworkConfig.IPConfiguration
for _, ipRouteSubnet := range targetNetworkConfig.CnetAddressSpace {
log.Printf("Adding route from cnetAddressspace to targetEpInfo %+v", ipRouteSubnet)
dstIPNet := net.IPNet{IP: net.ParseIP(ipRouteSubnet.IPAddress), Mask: net.CIDRMask(int(ipRouteSubnet.PrefixLength), 32)}
gwIP := net.ParseIP(ipconfig.GatewayIPAddress)
route := network.RouteInfo{Dst: dstIPNet, Gw: gwIP, DevName: existingEpInfo.IfName}
targetEpInfo.Routes = append(targetEpInfo.Routes, route)
log.Printf("Successfully added route from cnetAddressspace to targetEpInfo %+v", ipRouteSubnet)
}
log.Printf("Finished collecting new routes in targetEpInfo as follows: %+v", targetEpInfo.Routes)
log.Printf("Now saving existing infravnetaddress space if needed.")
for _, ns := range nwCfg.PodNamespaceForDualNetwork {
if k8sNamespace == ns {
targetEpInfo.EnableInfraVnet = true
targetEpInfo.InfraVnetAddressSpace = nwCfg.InfraVnetAddressSpace
log.Printf("Saving infravnet address space %s for [%s-%s]",
targetEpInfo.InfraVnetAddressSpace, existingEpInfo.PODNameSpace, existingEpInfo.PODName)
break
}
}
// Update the endpoint.
log.Printf("Now updating existing endpoint %v with targetNetworkConfig %+v.", existingEpInfo.Id, targetNetworkConfig)
err = plugin.nm.UpdateEndpoint(networkID, existingEpInfo, targetEpInfo)
if err != nil {
err = plugin.Errorf("Failed to update endpoint: %v", err)
return err
}
return nil
}

Просмотреть файл

@ -4,14 +4,19 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"reflect"
"github.com/Azure/azure-container-networking/cni"
"github.com/Azure/azure-container-networking/cni/network"
"github.com/Azure/azure-container-networking/common"
acn "github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/telemetry"
"github.com/containernetworking/cni/pkg/skel"
)
const (
@ -23,6 +28,22 @@ const (
// Version is populated by make during build.
var version string
// Command line arguments for CNI plugin.
var args = acn.ArgumentList{
{
Name: acn.OptVersion,
Shorthand: acn.OptVersionAlias,
Description: "Print version information",
Type: "bool",
DefaultValue: false,
},
}
// Prints version information.
func printVersion() {
fmt.Printf("Azure CNI Version %v\n", version)
}
// If report write succeeded, mark the report flag state to false.
func markSendReport(reportManager *telemetry.ReportManager) {
if err := reportManager.SetReportState(telemetry.CNITelemetryFile); err != nil {
@ -48,8 +69,82 @@ func reportPluginError(reportManager *telemetry.ReportManager, err error) {
}
}
func validateConfig(jsonBytes []byte) error {
var conf struct {
Name string `json:"name"`
}
if err := json.Unmarshal(jsonBytes, &conf); err != nil {
return fmt.Errorf("error reading network config: %s", err)
}
if conf.Name == "" {
return fmt.Errorf("missing network name")
}
return nil
}
func getCmdArgsFromEnv() (string, *skel.CmdArgs, error) {
log.Printf("Going to read from stdin")
stdinData, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return "", nil, fmt.Errorf("error reading from stdin: %v", err)
}
cmdArgs := &skel.CmdArgs{
ContainerID: os.Getenv("CNI_CONTAINERID"),
Netns: os.Getenv("CNI_NETNS"),
IfName: os.Getenv("CNI_IFNAME"),
Args: os.Getenv("CNI_ARGS"),
Path: os.Getenv("CNI_PATH"),
StdinData: stdinData,
}
cmd := os.Getenv("CNI_COMMAND")
return cmd, cmdArgs, nil
}
func handleIfCniUpdate(update func(*skel.CmdArgs) error) (bool, error) {
isupdate := true
if os.Getenv("CNI_COMMAND") != cni.CmdUpdate {
return false, nil
}
log.Printf("CNI UPDATE received.")
_, cmdArgs, err := getCmdArgsFromEnv()
if err != nil {
log.Printf("Received error while retrieving cmds from environment: %+v", err)
return isupdate, err
}
log.Printf("Retrieved command args for update +%v", cmdArgs)
err = validateConfig(cmdArgs.StdinData)
if err != nil {
log.Printf("Failed to handle CNI UPDATE, err:%v.", err)
return isupdate, err
}
err = update(cmdArgs)
if err != nil {
log.Printf("Failed to handle CNI UPDATE, err:%v.", err)
return isupdate, err
}
return isupdate, nil
}
// Main is the entry point for CNI network plugin.
func main() {
// Initialize and parse command line arguments.
acn.ParseArgs(&args, printVersion)
vers := acn.GetArg(acn.OptVersion).(bool)
if vers {
printVersion()
os.Exit(0)
}
var (
config common.PluginConfig
err error
@ -109,7 +204,10 @@ func main() {
panic("network plugin fatal error")
}
if err = netPlugin.Execute(cni.PluginApi(netPlugin)); err != nil {
handled, err := handleIfCniUpdate(netPlugin.Update)
if handled == true {
log.Printf("CNI UPDATE finished.")
} else if err = netPlugin.Execute(cni.PluginApi(netPlugin)); err != nil {
log.Printf("Failed to execute network plugin, err:%v.\n", err)
reportPluginError(reportManager, err)
}

Просмотреть файл

@ -28,7 +28,7 @@ const (
// Version is populated by make during build.
var version string
// Command line arguments for CNM plugin.
// Command line arguments for CNS.
var args = acn.ArgumentList{
{
Name: acn.OptEnvironment,

Просмотреть файл

@ -9,12 +9,14 @@ import (
var (
// Error responses returned by NetworkManager.
errSubnetNotFound = fmt.Errorf("Subnet not found")
errNetworkModeInvalid = fmt.Errorf("Network mode is invalid")
errNetworkExists = fmt.Errorf("Network already exists")
errNetworkNotFound = fmt.Errorf("Network not found")
errEndpointExists = fmt.Errorf("Endpoint already exists")
errEndpointNotFound = fmt.Errorf("Endpoint not found")
errEndpointInUse = fmt.Errorf("Endpoint is already joined to a sandbox")
errEndpointNotInUse = fmt.Errorf("Endpoint is not joined to a sandbox")
errSubnetNotFound = fmt.Errorf("Subnet not found")
errNetworkModeInvalid = fmt.Errorf("Network mode is invalid")
errNetworkExists = fmt.Errorf("Network already exists")
errNetworkNotFound = fmt.Errorf("Network not found")
errEndpointExists = fmt.Errorf("Endpoint already exists")
errEndpointNotFound = fmt.Errorf("Endpoint not found")
errNamespaceNotFound = fmt.Errorf("Namespace not found")
errMultipleEndpointsFound = fmt.Errorf("Multiple endpoints found")
errEndpointInUse = fmt.Errorf("Endpoint is already joined to a sandbox")
errEndpointNotInUse = fmt.Errorf("Endpoint is not joined to a sandbox")
)

Просмотреть файл

@ -16,40 +16,50 @@ const (
// Endpoint represents a container network interface.
type endpoint struct {
Id string
HnsId string `json:",omitempty"`
SandboxKey string
IfName string
HostIfName string
MacAddress net.HardwareAddr
InfraVnetIP net.IPNet
IPAddresses []net.IPNet
Gateways []net.IP
DNS DNSInfo
Routes []RouteInfo
VlanID int
EnableSnatOnHost bool
EnableInfraVnet bool
Id string
HnsId string `json:",omitempty"`
SandboxKey string
IfName string
HostIfName string
MacAddress net.HardwareAddr
InfraVnetIP net.IPNet
IPAddresses []net.IPNet
Gateways []net.IP
DNS DNSInfo
Routes []RouteInfo
VlanID int
EnableSnatOnHost bool
EnableInfraVnet bool
EnableMultitenancy bool
NetworkNameSpace string `json:",omitempty"`
ContainerID string
PODName string `json:",omitempty"`
PODNameSpace string `json:",omitempty"`
InfraVnetAddressSpace string `json:",omitempty"`
}
// EndpointInfo contains read-only information about an endpoint.
type EndpointInfo struct {
Id string
ContainerID string
NetNsPath string
IfName string
SandboxKey string
IfIndex int
MacAddress net.HardwareAddr
DNS DNSInfo
IPAddresses []net.IPNet
InfraVnetIP net.IPNet
Routes []RouteInfo
Policies []policy.Policy
Gateways []net.IP
EnableSnatOnHost bool
EnableInfraVnet bool
Data map[string]interface{}
Id string
ContainerID string
NetNsPath string
IfName string
SandboxKey string
IfIndex int
MacAddress net.HardwareAddr
DNS DNSInfo
IPAddresses []net.IPNet
InfraVnetIP net.IPNet
Routes []RouteInfo
Policies []policy.Policy
Gateways []net.IP
EnableSnatOnHost bool
EnableInfraVnet bool
EnableMultiTenancy bool
PODName string
PODNameSpace string
Data map[string]interface{}
InfraVnetAddressSpace string
}
// RouteInfo contains information about an IP route.
@ -128,6 +138,29 @@ func (nw *network) getEndpoint(endpointId string) (*endpoint, error) {
return ep, nil
}
// GetEndpointByPOD returns the endpoint with the given ID.
func (nw *network) getEndpointByPOD(podName string, podNameSpace string) (*endpoint, error) {
log.Printf("Trying to retrieve endpoint for pod name: %v in namespace: %v", podName, podNameSpace)
var ep *endpoint
for _, endpoint := range nw.Endpoints {
if endpoint.PODName == podName && endpoint.PODNameSpace == podNameSpace {
if ep == nil {
ep = endpoint
} else {
return nil, errMultipleEndpointsFound
}
}
}
if ep == nil {
return nil, errEndpointNotFound
}
return ep, nil
}
//
// Endpoint
//
@ -135,16 +168,22 @@ func (nw *network) getEndpoint(endpointId string) (*endpoint, error) {
// GetInfo returns information about the endpoint.
func (ep *endpoint) getInfo() *EndpointInfo {
info := &EndpointInfo{
Id: ep.Id,
IPAddresses: ep.IPAddresses,
InfraVnetIP: ep.InfraVnetIP,
Data: make(map[string]interface{}),
MacAddress: ep.MacAddress,
SandboxKey: ep.SandboxKey,
IfIndex: 0, // Azure CNI supports only one interface
DNS: ep.DNS,
EnableSnatOnHost: ep.EnableSnatOnHost,
EnableInfraVnet: ep.EnableInfraVnet,
Id: ep.Id,
IPAddresses: ep.IPAddresses,
InfraVnetIP: ep.InfraVnetIP,
Data: make(map[string]interface{}),
MacAddress: ep.MacAddress,
SandboxKey: ep.SandboxKey,
IfIndex: 0, // Azure CNI supports only one interface
DNS: ep.DNS,
EnableSnatOnHost: ep.EnableSnatOnHost,
EnableInfraVnet: ep.EnableInfraVnet,
EnableMultiTenancy: ep.EnableMultitenancy,
IfName: ep.IfName,
ContainerID: ep.ContainerID,
NetNsPath: ep.NetworkNameSpace,
PODName: ep.PODName,
PODNameSpace: ep.PODNameSpace,
}
for _, route := range ep.Routes {
@ -186,3 +225,35 @@ func (ep *endpoint) detach() error {
return nil
}
// updateEndpoint updates an existing endpoint in the network.
func (nw *network) updateEndpoint(exsitingEpInfo *EndpointInfo, targetEpInfo *EndpointInfo) (*endpoint, error) {
var err error
log.Printf("[net] Updating existing endpoint [%+v] in network %v to target [%+v].", exsitingEpInfo, nw.Id, targetEpInfo)
defer func() {
if err != nil {
log.Printf("[net] Failed to update endpoint %v, err:%v.", exsitingEpInfo.Id, err)
}
}()
log.Printf("Trying to retrieve endpoint id %v", exsitingEpInfo.Id)
ep := nw.Endpoints[exsitingEpInfo.Id]
if ep == nil {
return nil, errEndpointNotFound
}
log.Printf("[net] Retrieved endpoint to update %+v.", ep)
// Call the platform implementation.
ep, err = nw.updateEndpointImpl(exsitingEpInfo, targetEpInfo)
if err != nil {
return nil, err
}
// Update routes for existing endpoint
nw.Endpoints[exsitingEpInfo.Id].Routes = ep.Routes
return ep, nil
}

Просмотреть файл

@ -96,14 +96,15 @@ func (nw *network) newEndpointImpl(epInfo *EndpointInfo) (*endpoint, error) {
if err != nil {
log.Printf("CNI error. Delete Endpoint %v and rules that are created.", contIfName)
endpt := &endpoint{
Id: epInfo.Id,
IfName: contIfName,
HostIfName: hostIfName,
IPAddresses: epInfo.IPAddresses,
Gateways: []net.IP{nw.extIf.IPv4Gateway},
DNS: epInfo.DNS,
VlanID: vlanid,
EnableSnatOnHost: epInfo.EnableSnatOnHost,
Id: epInfo.Id,
IfName: contIfName,
HostIfName: hostIfName,
IPAddresses: epInfo.IPAddresses,
Gateways: []net.IP{nw.extIf.IPv4Gateway},
DNS: epInfo.DNS,
VlanID: vlanid,
EnableSnatOnHost: epInfo.EnableSnatOnHost,
EnableMultitenancy: epInfo.EnableMultiTenancy,
}
if containerIf != nil {
@ -171,17 +172,22 @@ func (nw *network) newEndpointImpl(epInfo *EndpointInfo) (*endpoint, error) {
// Create the endpoint object.
ep = &endpoint{
Id: epInfo.Id,
IfName: epInfo.IfName,
HostIfName: hostIfName,
MacAddress: containerIf.HardwareAddr,
InfraVnetIP: epInfo.InfraVnetIP,
IPAddresses: epInfo.IPAddresses,
Gateways: []net.IP{nw.extIf.IPv4Gateway},
DNS: epInfo.DNS,
VlanID: vlanid,
EnableSnatOnHost: epInfo.EnableSnatOnHost,
EnableInfraVnet: epInfo.EnableInfraVnet,
Id: epInfo.Id,
IfName: epInfo.IfName,
HostIfName: hostIfName,
MacAddress: containerIf.HardwareAddr,
InfraVnetIP: epInfo.InfraVnetIP,
IPAddresses: epInfo.IPAddresses,
Gateways: []net.IP{nw.extIf.IPv4Gateway},
DNS: epInfo.DNS,
VlanID: vlanid,
EnableSnatOnHost: epInfo.EnableSnatOnHost,
EnableInfraVnet: epInfo.EnableInfraVnet,
EnableMultitenancy: epInfo.EnableMultiTenancy,
NetworkNameSpace: epInfo.NetNsPath,
ContainerID: epInfo.ContainerID,
PODName: epInfo.PODName,
PODNameSpace: epInfo.PODNameSpace,
}
for _, route := range epInfo.Routes {
@ -253,7 +259,7 @@ func deleteRoutes(interfaceName string, routes []RouteInfo) error {
interfaceIf, _ := net.InterfaceByName(interfaceName)
for _, route := range routes {
log.Printf("[ovs] Adding IP route %+v to link %v.", route, interfaceName)
log.Printf("[ovs] Deleting IP route %+v from link %v.", route, interfaceName)
if route.DevName != "" {
devIf, _ := net.InterfaceByName(route.DevName)
@ -276,3 +282,137 @@ func deleteRoutes(interfaceName string, routes []RouteInfo) error {
return nil
}
// updateEndpointImpl updates an existing endpoint in the network.
func (nw *network) updateEndpointImpl(existingEpInfo *EndpointInfo, targetEpInfo *EndpointInfo) (*endpoint, error) {
var ns *Namespace
var ep *endpoint
var err error
existingEpFromRepository := nw.Endpoints[existingEpInfo.Id]
log.Printf("[updateEndpointImpl] Going to retrieve endpoint with Id %+v to update.", existingEpInfo.Id)
if existingEpFromRepository == nil {
log.Printf("[updateEndpointImpl] Endpoint cannot be updated as it does not exist.")
err = errEndpointNotFound
return nil, err
}
netns := existingEpFromRepository.NetworkNameSpace
// Network namespace for the container interface has to be specified
if netns != "" {
// Open the network namespace.
log.Printf("[updateEndpointImpl] Opening netns %v.", netns)
ns, err = OpenNamespace(netns)
if err != nil {
return nil, err
}
defer ns.Close()
// Enter the container network namespace.
log.Printf("[updateEndpointImpl] Entering netns %v.", netns)
if err = ns.Enter(); err != nil {
return nil, err
}
// Return to host network namespace.
defer func() {
log.Printf("[updateEndpointImpl] Exiting netns %v.", netns)
if err := ns.Exit(); err != nil {
log.Printf("[updateEndpointImpl] Failed to exit netns, err:%v.", err)
}
}()
} else {
log.Printf("[updateEndpointImpl] Endpoint cannot be updated as the network namespace does not exist: Epid: %v", existingEpInfo.Id)
err = errNamespaceNotFound
return nil, err
}
log.Printf("[updateEndpointImpl] Going to update routes in netns %v.", netns)
if err = updateRoutes(existingEpInfo, targetEpInfo); err != nil {
return nil, err
}
// Create the endpoint object.
ep = &endpoint{
Id: existingEpInfo.Id,
}
// Update existing endpoint state with the new routes to persist
for _, route := range targetEpInfo.Routes {
ep.Routes = append(ep.Routes, route)
}
return ep, nil
}
func updateRoutes(existingEp *EndpointInfo, targetEp *EndpointInfo) error {
log.Printf("Updating routes for the endpoint %+v.", existingEp)
log.Printf("Target endpoint is %+v", targetEp)
existingRoutes := make(map[string]RouteInfo)
targetRoutes := make(map[string]RouteInfo)
var tobeDeletedRoutes []RouteInfo
var tobeAddedRoutes []RouteInfo
// we should not remove default route from container if it exists
// we do not support enable/disable snat for now
defaultDst := net.ParseIP("0.0.0.0")
log.Printf("Going to collect routes and skip default and infravnet routes if applicable.")
log.Printf("Key for default route: %+v", defaultDst.String())
infraVnetKey := ""
if targetEp.EnableInfraVnet {
infraVnetSubnet := targetEp.InfraVnetAddressSpace
if infraVnetSubnet != "" {
infraVnetKey = strings.Split(infraVnetSubnet, "/")[0]
}
}
log.Printf("Key for route to infra vnet: %+v", infraVnetKey)
for _, route := range existingEp.Routes {
destination := route.Dst.IP.String()
log.Printf("Checking destination as %+v to skip or not", destination)
isDefaultRoute := destination == defaultDst.String()
isInfraVnetRoute := targetEp.EnableInfraVnet && (destination == infraVnetKey)
if !isDefaultRoute && !isInfraVnetRoute {
existingRoutes[route.Dst.String()] = route
log.Printf("%+v was skipped", destination)
}
}
for _, route := range targetEp.Routes {
targetRoutes[route.Dst.String()] = route
}
for _, existingRoute := range existingRoutes {
dst := existingRoute.Dst.String()
if _, ok := targetRoutes[dst]; !ok {
tobeDeletedRoutes = append(tobeDeletedRoutes, existingRoute)
log.Printf("Adding following route to the tobeDeleted list: %+v", existingRoute)
}
}
for _, targetRoute := range targetRoutes {
dst := targetRoute.Dst.String()
if _, ok := existingRoutes[dst]; !ok {
tobeAddedRoutes = append(tobeAddedRoutes, targetRoute)
log.Printf("Adding following route to the tobeAdded list: %+v", targetRoute)
}
}
err := deleteRoutes(existingEp.IfName, tobeDeletedRoutes)
if err != nil {
return err
}
err = addRoutes(existingEp.IfName, tobeAddedRoutes)
if err != nil {
return err
}
log.Printf("Successfully updated routes for the endpoint %+v using target: %+v", existingEp, targetEp)
return nil
}

Просмотреть файл

@ -128,3 +128,8 @@ func (nw *network) deleteEndpointImpl(ep *endpoint) error {
func (ep *endpoint) getInfoImpl(epInfo *EndpointInfo) {
epInfo.Data["hnsid"] = ep.HnsId
}
// updateEndpointImpl in windows does nothing for now
func (nw *network) updateEndpointImpl(existingEpInfo *EndpointInfo, targetEpInfo *EndpointInfo) (*endpoint, error) {
return nil, nil
}

Просмотреть файл

@ -61,8 +61,10 @@ type NetworkManager interface {
CreateEndpoint(networkId string, epInfo *EndpointInfo) error
DeleteEndpoint(networkId string, endpointId string) error
GetEndpointInfo(networkId string, endpointId string) (*EndpointInfo, error)
GetEndpointInfoBasedOnPODDetails(networkId string, podName string, podNameSpace string) (*EndpointInfo, error)
AttachEndpoint(networkId string, endpointId string, sandboxKey string) (*endpoint, error)
DetachEndpoint(networkId string, endpointId string) error
UpdateEndpoint(networkId string, existingEpInfo *EndpointInfo, targetEpInfo *EndpointInfo) error
}
// Creates a new network manager.
@ -153,11 +155,11 @@ func (nm *networkManager) restore() error {
log.Printf("[net] Restored state, %+v\n", nm)
for _, extIf := range nm.ExternalInterfaces {
log.Printf("External Interface %v", extIf)
log.Printf("External Interface %+v", extIf)
for _, nw := range extIf.Networks {
log.Printf("network %v", nw)
log.Printf("network %+v", nw)
for _, ep := range nw.Endpoints {
log.Printf("endpoint %v", ep)
log.Printf("endpoint %+v", ep)
}
}
}
@ -341,6 +343,25 @@ func (nm *networkManager) GetEndpointInfo(networkId string, endpointId string) (
return ep.getInfo(), nil
}
// GetEndpointInfoBasedOnPODDetails returns information about the given endpoint.
// It returns an error if a single pod has multiple endpoints.
func (nm *networkManager) GetEndpointInfoBasedOnPODDetails(networkID string, podName string, podNameSpace string) (*EndpointInfo, error) {
nm.Lock()
defer nm.Unlock()
nw, err := nm.getNetwork(networkID)
if err != nil {
return nil, err
}
ep, err := nw.getEndpointByPOD(podName, podNameSpace)
if err != nil {
return nil, err
}
return ep.getInfo(), nil
}
// AttachEndpoint attaches an endpoint to a sandbox.
func (nm *networkManager) AttachEndpoint(networkId string, endpointId string, sandboxKey string) (*endpoint, error) {
nm.Lock()
@ -396,3 +417,26 @@ func (nm *networkManager) DetachEndpoint(networkId string, endpointId string) er
return nil
}
// UpdateEndpoint updates an existing container endpoint.
func (nm *networkManager) UpdateEndpoint(networkID string, existingEpInfo *EndpointInfo, targetEpInfo *EndpointInfo) error {
nm.Lock()
defer nm.Unlock()
nw, err := nm.getNetwork(networkID)
if err != nil {
return err
}
_, err = nw.updateEndpoint(existingEpInfo, targetEpInfo)
if err != nil {
return err
}
err = nm.save()
if err != nil {
return err
}
return nil
}