Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use libovsdb bindings for collecting ovs metrics #4637

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 6 additions & 2 deletions go-controller/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ else
CONTAINER_RUNTIME=docker
endif
CONTAINER_RUNNABLE ?= $(shell $(CONTAINER_RUNTIME) -v > /dev/null 2>&1; echo $$?)
# FIXME(tssurya): In one week when OVN 24.09 is released change the schema version
OVN_SCHEMA_VERSION ?= 8efac26f6637fc
OVS_VERSION ?= v2.17.0
ifeq ($(NOROOT),TRUE)
C_ARGS = -e NOROOT=TRUE
else
Expand Down Expand Up @@ -65,7 +65,7 @@ else
RACE=1 hack/test-go.sh
endif

modelgen: pkg/nbdb/ovn-nb.ovsschema pkg/sbdb/ovn-sb.ovsschema
modelgen: pkg/nbdb/ovn-nb.ovsschema pkg/sbdb/ovn-sb.ovsschema pkg/vswitchd/vswitch.ovsschema
hack/update-modelgen.sh

codegen:
Expand All @@ -86,6 +86,7 @@ clean:
rm -rf ${TEST_REPORT_DIR}
rm -f ./pkg/nbdb/ovn-nb.ovsschema
rm -f ./pkg/sbdb/ovn-sb.ovsschema
rm -f ./pkg/vswitchd/vswitch.ovsschema

.PHONY: lint gofmt

Expand All @@ -109,6 +110,9 @@ pkg/nbdb/ovn-nb.ovsschema:
pkg/sbdb/ovn-sb.ovsschema:
curl -sSL https://raw.githubusercontent.com/ovn-org/ovn/$(OVN_SCHEMA_VERSION)/ovn-sb.ovsschema -o $@

pkg/vswitchd/vswitch.ovsschema:
curl -sSL https://raw.githubusercontent.com/openvswitch/ovs/${OVS_VERSION}/vswitchd/vswitch.ovsschema -o $@

${TOOLS_OUTPUT_DIR}:
mkdir -p ${TOOLS_OUTPUT_DIR}

Expand Down
17 changes: 16 additions & 1 deletion go-controller/cmd/ovn-kube-util/app/ovs-exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import (
"net/http"
"time"

"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/libovsdb"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/metrics"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/urfave/cli/v2"
kexec "k8s.io/utils/exec"
)

var metricsScrapeInterval int

var OvsExporterCommand = cli.Command{
Name: "ovs-exporter",
Usage: "",
Expand All @@ -21,6 +24,12 @@ var OvsExporterCommand = cli.Command{
Name: "metrics-bind-address",
Usage: `The IP address and port for the metrics server to serve on (default ":9310")`,
},
&cli.IntFlag{
Name: "metrics-interval",
Usage: "The interval in seconds at which ovs metrics are collected",
Value: 30,
Destination: &metricsScrapeInterval,
},
},
Action: func(ctx *cli.Context) error {
stopChan := make(chan struct{})
Expand All @@ -33,11 +42,17 @@ var OvsExporterCommand = cli.Command{
return err
}

// start the ovsdb client for ovs metrics monitoring
ovsClient, err := libovsdb.NewOVSClient(stopChan)
if err != nil {
klog.Errorf("Error initializing ovs client: %v", err)
}

mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())

// register ovs metrics that will be served off of /metrics path
metrics.RegisterStandaloneOvsMetrics(stopChan)
metrics.RegisterStandaloneOvsMetrics(ovsClient, metricsScrapeInterval, stopChan)

server := &http.Server{Addr: bindAddress, Handler: mux}
go func() {
Expand Down
12 changes: 10 additions & 2 deletions go-controller/cmd/ovnkube/ovnkube.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,10 +566,18 @@ func runOvnKube(ctx context.Context, runMode *ovnkubeRunMode, ovnClientset *util
// start the prometheus server to serve OVS and OVN Metrics (default port: 9476)
// Note: for ovnkube node mode dpu-host no metrics is required as ovs/ovn is not running on the node.
if config.OvnKubeNode.Mode != types.NodeModeDPUHost && config.Metrics.OVNMetricsBindAddress != "" {
metricsScrapeInterval := 30
defer cancel()

ovsClient, err := libovsdb.NewOVSClient(ctx.Done())
if err != nil {
return fmt.Errorf("failed to initialize libovsdb vswitchd client: %w", err)
}
if config.Metrics.ExportOVSMetrics {
metrics.RegisterOvsMetricsWithOvnMetrics(ctx.Done())
metrics.RegisterOvsMetricsWithOvnMetrics(ovsClient, metricsScrapeInterval, ctx.Done())
}
metrics.RegisterOvnMetrics(ovnClientset.KubeClient, runMode.identity, ctx.Done())
metrics.RegisterOvnMetrics(ovnClientset.KubeClient, runMode.identity,
ovsClient, metricsScrapeInterval, ctx.Done())
metrics.StartOVNMetricsServer(config.Metrics.OVNMetricsBindAddress,
config.Metrics.NodeServerCert, config.Metrics.NodeServerPrivKey, ctx.Done(), wg)
}
Expand Down
1 change: 1 addition & 0 deletions go-controller/hack/update-modelgen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ fi

go generate ./pkg/nbdb
go generate ./pkg/sbdb
go generate ./pkg/vswitchd
42 changes: 42 additions & 0 deletions go-controller/pkg/libovsdb/libovsdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/sbdb"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/vswitchd"
"github.com/prometheus/client_golang/prometheus"
"gopkg.in/fsnotify/fsnotify.v1"
"gopkg.in/natefinch/lumberjack.v2"
Expand Down Expand Up @@ -226,6 +227,47 @@ func NewNBClientWithConfig(cfg config.OvnAuthConfig, promRegistry prometheus.Reg
return c, nil
}

// NewOVSClient creates a new openvswitch Database client
func NewOVSClient(stopCh <-chan struct{}) (client.Client, error) {
cfg := &config.OvnAuthConfig{
Scheme: config.OvnDBSchemeUnix,
Address: "unix:/var/run/openvswitch/db.sock",
}

return NewOVSClientWithConfig(*cfg, stopCh)
}

func NewOVSClientWithConfig(cfg config.OvnAuthConfig, stopCh <-chan struct{}) (client.Client, error) {
dbModel, err := vswitchd.FullDatabaseModel()
if err != nil {
return nil, err
}
c, err := newClient(cfg, dbModel, stopCh)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), types.OVSDBTimeout)
go func() {
<-stopCh
cancel()
}()

_, err = c.Monitor(ctx,
c.NewMonitor(
client.WithTable(&vswitchd.OpenvSwitch{}),
client.WithTable(&vswitchd.Bridge{}),
client.WithTable(&vswitchd.Port{}),
client.WithTable(&vswitchd.Interface{}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that metrics is not the best amortization of the extra memory consumption this brings. But I also guess as we further migrate things to libovsdb it would make more sense. What are the plans for further pieces? This is marked as WIP, do you plan to merge this before the other pieces come? Trying to get a sense of a timeline.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I am planning to start the migration to libovsdb with metrics first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to have and merge all at once? Each bit could be a different commit here, and I would do a staggered review of each without waiting for the full set. The only problem would be rebases, but we don't expect a lot of changes on the OVS calls that we make.

It is more convenient for our downstream but I understand it might be too much to ask.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be difficult to address all at once. I have added another commit to this though, to address those OVN metrics using vsctl.

),
)
if err != nil {
c.Close()
return nil, err
}

return c, nil
}

func createTLSConfig(certFile, privKeyFile, caCertFile, serverName string) (*tls.Config, error) {
cert, err := tls.LoadX509KeyPair(certFile, privKeyFile)
if err != nil {
Expand Down
17 changes: 17 additions & 0 deletions go-controller/pkg/libovsdb/ops/ovs/bridge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ovs

import (
"context"
libovsdbclient "github.com/ovn-org/libovsdb/client"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/vswitchd"
)

// ListBridges looks up all ovs bridges from the cache
func ListBridges(ovsClient libovsdbclient.Client) ([]*vswitchd.Bridge, error) {
ctx, cancel := context.WithTimeout(context.Background(), types.OVSDBTimeout)
defer cancel()
searchedBridges := []*vswitchd.Bridge{}
err := ovsClient.List(ctx, &searchedBridges)
return searchedBridges, err
}
30 changes: 30 additions & 0 deletions go-controller/pkg/libovsdb/ops/ovs/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ovs

import (
"context"
libovsdbclient "github.com/ovn-org/libovsdb/client"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/vswitchd"
)

type interfacePredicate func(*vswitchd.Interface) bool

// ListInterfaces looks up all ovs interfaces from the cache
func ListInterfaces(ovsClient libovsdbclient.Client) ([]*vswitchd.Interface, error) {
ctx, cancel := context.WithTimeout(context.Background(), types.OVSDBTimeout)
defer cancel()
searchedInterfaces := []*vswitchd.Interface{}
err := ovsClient.List(ctx, &searchedInterfaces)
return searchedInterfaces, err
}

// FindInterfacesWithPredicate returns all the ovs interfaces in the cache
// that matches the lookup function
func FindInterfacesWithPredicate(ovsClient libovsdbclient.Client, p interfacePredicate) ([]*vswitchd.Interface, error) {
ctx, cancel := context.WithTimeout(context.Background(), types.OVSDBTimeout)
defer cancel()
searchedInterfaces := []*vswitchd.Interface{}

err := ovsClient.WhereCache(p).List(ctx, &searchedInterfaces)
return searchedInterfaces, err
}
25 changes: 25 additions & 0 deletions go-controller/pkg/libovsdb/ops/ovs/openvswitch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ovs

import (
"context"
"fmt"
libovsdbclient "github.com/ovn-org/libovsdb/client"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/vswitchd"
)

// Get OpenvSwitch entry from the cache
func GetOpenvSwitch(ovsClient libovsdbclient.Client) (*vswitchd.OpenvSwitch, error) {
ctx, cancel := context.WithTimeout(context.Background(), types.OVSDBTimeout)
defer cancel()
openvSwitchList := []*vswitchd.OpenvSwitch{}
err := ovsClient.List(ctx, &openvSwitchList)
if err != nil {
return nil, err
}
if len(openvSwitchList) == 0 {
return nil, fmt.Errorf("no openvSwitch entry found")
}

return openvSwitchList[0], err
}
6 changes: 4 additions & 2 deletions go-controller/pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"sync"
"time"

libovsdbclient "github.com/ovn-org/libovsdb/client"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/config"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -560,8 +561,9 @@ func startMetricsServer(bindAddress, certFile, keyFile string, handler http.Hand
}()
}

func RegisterOvnMetrics(clientset kubernetes.Interface, k8sNodeName string, stopChan <-chan struct{}) {
func RegisterOvnMetrics(clientset kubernetes.Interface, k8sNodeName string, ovsDBClient libovsdbclient.Client,
metricsScrapeInterval int, stopChan <-chan struct{}) {
go RegisterOvnDBMetrics(clientset, k8sNodeName, stopChan)
go RegisterOvnControllerMetrics(stopChan)
go RegisterOvnControllerMetrics(ovsDBClient, metricsScrapeInterval, stopChan)
go RegisterOvnNorthdMetrics(clientset, k8sNodeName, stopChan)
}
Loading
Loading