Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ CNSFILES = \
$(COREFILES) \
$(CNMFILES)

CNMSFILES = \
$(wildcard cnms/*.go) \
$(wildcard cnms/service/*.go) \
$(wildcard cnms/cnmspackage/*.go) \
$(COREFILES)

NPMFILES = \
$(wildcard npm/*.go) \
$(wildcard npm/ipsm/*.go) \
Expand All @@ -71,13 +77,15 @@ CNI_IPAM_DIR = cni/ipam/plugin
CNI_TELEMETRY_DIR = cni/telemetry/service
TELEMETRY_CONF_DIR = telemetry
CNS_DIR = cns/service
CNMS_DIR = cnms/service
NPM_DIR = npm/plugin
OUTPUT_DIR = output
BUILD_DIR = $(OUTPUT_DIR)/$(GOOS)_$(GOARCH)
CNM_BUILD_DIR = $(BUILD_DIR)/cnm
CNI_BUILD_DIR = $(BUILD_DIR)/cni
CNI_MULTITENANCY_BUILD_DIR = $(BUILD_DIR)/cni-multitenancy
CNS_BUILD_DIR = $(BUILD_DIR)/cns
CNMS_BUILD_DIR = $(BUILD_DIR)/cnms
NPM_BUILD_DIR = $(BUILD_DIR)/npm
NPM_TELEMETRY_DIR = $(NPM_BUILD_DIR)/telemetry
CNI_AI_ID = 5515a1eb-b2bc-406a-98eb-ba462e6f0411
Expand Down Expand Up @@ -107,6 +115,7 @@ CNM_ARCHIVE_NAME = azure-vnet-cnm-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
CNI_ARCHIVE_NAME = azure-vnet-cni-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
CNI_MULTITENANCY_ARCHIVE_NAME = azure-vnet-cni-multitenancy-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
CNS_ARCHIVE_NAME = azure-cns-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
CNMS_ARCHIVE_NAME = azure-cnms-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
NPM_ARCHIVE_NAME = azure-npm-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
NPM_IMAGE_ARCHIVE_NAME = azure-npm-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
TELEMETRY_IMAGE_ARCHIVE_NAME = azure-vnet-telemetry-$(GOOS)-$(GOARCH)-$(VERSION).$(ARCHIVE_EXT)
Expand Down Expand Up @@ -140,11 +149,12 @@ azure-vnet-telemetry: $(CNI_BUILD_DIR)/azure-vnet-telemetry$(EXE_EXT)

# Azure-NPM only supports Linux for now.
ifeq ($(GOOS),linux)
azure-cnms: $(CNMS_BUILD_DIR)/azure-cnms$(EXE_EXT) cnms-archive
azure-npm: $(NPM_BUILD_DIR)/azure-npm$(EXE_EXT) npm-archive
endif

ifeq ($(GOOS),linux)
all-binaries: azure-cnm-plugin azure-cni-plugin azure-cns azure-npm
all-binaries: azure-cnm-plugin azure-cni-plugin azure-cns azure-cnms azure-npm
else
all-binaries: azure-cnm-plugin azure-cni-plugin azure-cns
endif
Expand Down Expand Up @@ -181,6 +191,10 @@ $(CNI_BUILD_DIR)/azure-vnet-telemetry$(EXE_EXT): $(CNIFILES)
$(CNS_BUILD_DIR)/azure-cns$(EXE_EXT): $(CNSFILES)
go build -v -o $(CNS_BUILD_DIR)/azure-cns$(EXE_EXT) -ldflags "-X main.version=$(VERSION) -X $(cnsaipath)=$(CNS_AI_ID) -s -w" $(CNS_DIR)/*.go

# Build the Azure CNMS Service.
$(CNMS_BUILD_DIR)/azure-cnms$(EXE_EXT): $(CNMSFILES)
go build -v -o $(CNMS_BUILD_DIR)/azure-cnms$(EXE_EXT) -ldflags "-X main.version=$(VERSION) -s -w" $(CNMS_DIR)/*.go

# Build the Azure NPM plugin.
$(NPM_BUILD_DIR)/azure-npm$(EXE_EXT): $(NPMFILES)
go build -v -o $(NPM_BUILD_DIR)/azure-vnet-telemetry$(EXE_EXT) -ldflags "-X main.version=$(VERSION) -s -w" $(CNI_TELEMETRY_DIR)/*.go
Expand Down Expand Up @@ -325,6 +339,15 @@ cns-archive:
cd $(CNS_BUILD_DIR) && $(ARCHIVE_CMD) $(CNS_ARCHIVE_NAME) azure-cns$(EXE_EXT) cns_config.json
chown $(BUILD_USER):$(BUILD_USER) $(CNS_BUILD_DIR)/$(CNS_ARCHIVE_NAME)

# Create a CNMS archive for the target platform. Only Linux is supported for now.
.PHONY: cnms-archive
cnms-archive:
ifeq ($(GOOS),linux)
chmod 0755 $(CNMS_BUILD_DIR)/azure-cnms$(EXE_EXT)
cd $(CNMS_BUILD_DIR) && $(ARCHIVE_CMD) $(CNMS_ARCHIVE_NAME) azure-cnms$(EXE_EXT)
chown $(BUILD_USER):$(BUILD_USER) $(CNMS_BUILD_DIR)/$(CNMS_ARCHIVE_NAME)
endif

# Create a NPM archive for the target platform. Only Linux is supported for now.
.PHONY: npm-archive
npm-archive:
Expand Down
7 changes: 7 additions & 0 deletions cnms/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM ubuntu:latest
RUN apt -y update
RUN apt-get -y upgrade
RUN apt install -y ebtables
RUN apt install -y net-tools
COPY networkmonitor /usr/bin/networkmonitor
CMD ["/usr/bin/networkmonitor"]
6 changes: 6 additions & 0 deletions cnms/cnmspackage/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package cnms

type NetworkMonitor struct {
AddRulesToBeValidated map[string]int
DeleteRulesToBeValidated map[string]int
}
117 changes: 117 additions & 0 deletions cnms/cnmspackage/monitor2rules_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package cnms

import (
"github.com/Azure/azure-container-networking/ebtables"
"github.com/Azure/azure-container-networking/log"
)

// deleteRulesNotExistInMap deletes rules from nat Ebtable if rule was not in stateRules after a certain number of iterations.
func (networkMonitor *NetworkMonitor) deleteRulesNotExistInMap(chainRules map[string]string, stateRules map[string]string) {

table := ebtables.Nat
action := ebtables.Delete

for rule, chain := range chainRules {
if _, ok := stateRules[rule]; !ok {
if itr, ok := networkMonitor.DeleteRulesToBeValidated[rule]; ok && itr > 0 {
log.Printf("[monitor] Deleting Ebtable rule as it didn't exist in state for %d iterations chain %v rule %v", itr, chain, rule)
if err := ebtables.SetEbRule(table, action, chain, rule); err != nil {
log.Printf("[monitor] Error while deleting ebtable rule %v", err)
}

delete(networkMonitor.DeleteRulesToBeValidated, rule)
} else {
log.Printf("[DELETE] Found unmatched rule chain %v rule %v itr %d. Giving one more iteration.", chain, rule, itr)
networkMonitor.DeleteRulesToBeValidated[rule] = itr + 1
}
}
}
}

// addRulesNotExistInMap adds rules to nat Ebtable if rule was in stateRules and not in current chain rules after a certain number of iterations.
func (networkMonitor *NetworkMonitor) addRulesNotExistInMap(
stateRules map[string]string,
chainRules map[string]string) {

table := ebtables.Nat
action := ebtables.Append

for rule, chain := range stateRules {
if _, ok := chainRules[rule]; !ok {
if itr, ok := networkMonitor.AddRulesToBeValidated[rule]; ok && itr > 0 {
log.Printf("[monitor] Adding Ebtable rule as it existed in state rules but not in current chain rules for %d iterations chain %v rule %v", itr, chain, rule)
if err := ebtables.SetEbRule(table, action, chain, rule); err != nil {
log.Printf("[monitor] Error while adding ebtable rule %v", err)
}

delete(networkMonitor.AddRulesToBeValidated, rule)
} else {
log.Printf("[ADD] Found unmatched rule chain %v rule %v itr %d. Giving one more iteration", chain, rule, itr)
networkMonitor.AddRulesToBeValidated[rule] = itr + 1
}
}
}
}

// CreateRequiredL2Rules finds the rules that should be in nat ebtable based on state.
func (networkMonitor *NetworkMonitor) CreateRequiredL2Rules(
currentEbtableRulesMap map[string]string,
currentStateRulesMap map[string]string) error {

for rule := range networkMonitor.AddRulesToBeValidated {
if _, ok := currentStateRulesMap[rule]; !ok {
delete(networkMonitor.AddRulesToBeValidated, rule)
}
}

networkMonitor.addRulesNotExistInMap(currentStateRulesMap, currentEbtableRulesMap)

return nil
}

// RemoveInvalidL2Rules removes rules that should not be in nat ebtable based on state.
func (networkMonitor *NetworkMonitor) RemoveInvalidL2Rules(
currentEbtableRulesMap map[string]string,
currentStateRulesMap map[string]string) error {

for rule := range networkMonitor.DeleteRulesToBeValidated {
if _, ok := currentEbtableRulesMap[rule]; !ok {
delete(networkMonitor.DeleteRulesToBeValidated, rule)
}
}

networkMonitor.deleteRulesNotExistInMap(currentEbtableRulesMap, currentStateRulesMap)

return nil
}

// generateL2RulesMap gets rules from chainName and puts them in currentEbtableRulesMap.
func generateL2RulesMap(currentEbtableRulesMap map[string]string, chainName string) error {
table := ebtables.Nat
rules, err := ebtables.GetEbtableRules(table, chainName)
if err != nil {
log.Printf("[monitor] Error while getting rules list from table %v chain %v. Error: %v",
table, chainName, err)
return err
}

for _, rule := range rules {
currentEbtableRulesMap[rule] = chainName
}

return nil
}

// GetEbTableRulesInMap gathers prerouting and postrouting rules into a map.
func GetEbTableRulesInMap() (map[string]string, error) {
currentEbtableRulesMap := make(map[string]string)
if err := generateL2RulesMap(currentEbtableRulesMap, ebtables.PreRouting); err != nil {
return nil, err
}

if err := generateL2RulesMap(currentEbtableRulesMap, ebtables.PostRouting); err != nil {
return nil, err
}

return currentEbtableRulesMap, nil
}
150 changes: 150 additions & 0 deletions cnms/service/networkmonitor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2017 Microsoft. All rights reserved.
// MIT License

package main

import (
"fmt"
"os"
"time"

cnms "github.com/Azure/azure-container-networking/cnms/cnmspackage"
acn "github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/network"
"github.com/Azure/azure-container-networking/platform"
"github.com/Azure/azure-container-networking/store"
)

const (
// Service name.
name = "azure-cnimonitor"
pluginName = "azure-vnet"
DEFAULT_TIMEOUT_IN_SECS = "10"
)

// Version is populated by make during build.
var version string

// Command line arguments for CNM plugin.
var args = acn.ArgumentList{
{
Name: acn.OptLogLevel,
Shorthand: acn.OptLogLevelAlias,
Description: "Set the logging level",
Type: "int",
DefaultValue: acn.OptLogLevelInfo,
ValueMap: map[string]interface{}{
acn.OptLogLevelInfo: log.LevelInfo,
acn.OptLogLevelDebug: log.LevelDebug,
},
},
{
Name: acn.OptLogTarget,
Shorthand: acn.OptLogTargetAlias,
Description: "Set the logging target",
Type: "int",
DefaultValue: acn.OptLogTargetFile,
ValueMap: map[string]interface{}{
acn.OptLogTargetSyslog: log.TargetSyslog,
acn.OptLogTargetStderr: log.TargetStderr,
acn.OptLogTargetFile: log.TargetLogfile,
},
},
{
Name: acn.OptLogLocation,
Shorthand: acn.OptLogLocationAlias,
Description: "Set the directory location where logs will be saved",
Type: "string",
DefaultValue: "",
},
{
Name: acn.OptIntervalTime,
Shorthand: acn.OptIntervalTimeAlias,
Description: "Periodic Interval Time",
Type: "int",
DefaultValue: DEFAULT_TIMEOUT_IN_SECS,
},
{
Name: acn.OptVersion,
Shorthand: acn.OptVersionAlias,
Description: "Print version information",
Type: "bool",
DefaultValue: false,
},
}

// Prints description and version information.
func printVersion() {
fmt.Printf("Azure Container Network Monitoring Service\n")
fmt.Printf("Version %v\n", version)
}

// Main is the entry point for CNMS.
func main() {
// Initialize and parse command line arguments.
acn.ParseArgs(&args, printVersion)
logLevel := acn.GetArg(acn.OptLogLevel).(int)
logTarget := acn.GetArg(acn.OptLogTarget).(int)
logDirectory := acn.GetArg(acn.OptLogLocation).(string)
timeout := acn.GetArg(acn.OptIntervalTime).(int)
vers := acn.GetArg(acn.OptVersion).(bool)
if vers {
printVersion()
os.Exit(0)
}

// Initialize CNMS.
var config acn.PluginConfig
config.Version = version

// Create a channel to receive unhandled errors from CNMS.
config.ErrChan = make(chan error, 1)

var err error
// Create logging provider.
log.SetName(name)
log.SetLevel(logLevel)
if err := log.SetTargetLogDirectory(logTarget, logDirectory); err != nil {
fmt.Printf("[monitor] Failed to configure logging: %v\n", err)
return
}

// Log platform information.
log.Printf("[monitor] Running on %v", platform.GetOSInfo())

netMonitor := &cnms.NetworkMonitor{
AddRulesToBeValidated: make(map[string]int),
DeleteRulesToBeValidated: make(map[string]int),
}

for true {
config.Store, err = store.NewJsonFileStore(platform.CNIRuntimePath + pluginName + ".json")
if err != nil {
fmt.Printf("[monitor] Failed to create store: %v\n", err)
return
}

nm, err := network.NewNetworkManager()
if err != nil {
log.Printf("[monitor] Failed while creating network manager")
return
}

if err := nm.Initialize(&config); err != nil {
log.Printf("[monitor] Failed while initializing network manager %+v", err)
}

log.Printf("[monitor] network manager:%+v", nm)

if err := nm.SetupNetworkUsingState(netMonitor); err != nil {
log.Printf("[monitor] Failed while calling SetupNetworkUsingState with error %v", err)
}

log.Printf("[monitor] Going to sleep for %v seconds", timeout)
time.Sleep(time.Duration(timeout) * time.Second)
nm = nil
}

log.Close()
}
Loading