diff --git a/cni-plugin/pkg/dataplane/dataplane.go b/cni-plugin/pkg/dataplane/dataplane.go index db9419d737b..baa6f2e566d 100644 --- a/cni-plugin/pkg/dataplane/dataplane.go +++ b/cni-plugin/pkg/dataplane/dataplane.go @@ -50,10 +50,28 @@ func GetDataplane(conf types.NetConf, logger *logrus.Entry) (Dataplane, error) { if !ok { return getDefaultSystemDataplane(conf, logger) } + + var externalDataplane Dataplane + switch name { case "grpc": - return grpc.NewGrpcDataplane(conf, logger) + var err error + externalDataplane, err = grpc.NewGrpcDataplane(conf, logger) + if err != nil { + return nil, fmt.Errorf("Unable to create a new GRPC dataplane: %w", err) + } default: return nil, fmt.Errorf("Invalid dataplane type: %s", name) } + + useAsSecondary, ok := conf.DataplaneOptions["useAsSecondary"] + if useAsSecondary == "true" { + defaultSystemDataplane, err := getDefaultSystemDataplane(conf, logger) + if err != nil { + return nil, fmt.Errorf("Unable to create new GRPC dataplane: %w", err) + } + return multiplexer{primary: defaultSystemDataplane, secondary: externalDataplane}, nil + } + + return externalDataplane, nil } diff --git a/cni-plugin/pkg/dataplane/multiplexer.go b/cni-plugin/pkg/dataplane/multiplexer.go new file mode 100644 index 00000000000..552db684ddf --- /dev/null +++ b/cni-plugin/pkg/dataplane/multiplexer.go @@ -0,0 +1,64 @@ +// Copyright (c) 2025 NeuReality Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dataplane + +import ( + "context" + "fmt" + "net" + + "github.com/containernetworking/cni/pkg/skel" + cniv1 "github.com/containernetworking/cni/pkg/types/100" + api "github.com/projectcalico/calico/libcalico-go/lib/apis/v3" + calicoclient "github.com/projectcalico/calico/libcalico-go/lib/clientv3" +) + +type multiplexer struct { + primary Dataplane + secondary Dataplane +} + +func (m multiplexer) DoNetworking( + ctx context.Context, + calicoClient calicoclient.Interface, + args *skel.CmdArgs, + result *cniv1.Result, + desiredVethName string, + routes []*net.IPNet, + endpoint *api.WorkloadEndpoint, + annotations map[string]string, +) (string, string, error) { + _, _, secondaryErr := m.secondary.DoNetworking(ctx, calicoClient, args, result, desiredVethName, routes, endpoint, annotations) + hostVethName, contVethMAC, primaryErr := m.primary.DoNetworking(ctx, calicoClient, args, result, desiredVethName, routes, endpoint, annotations) + + if primaryErr != nil || secondaryErr != nil { + return "", "", fmt.Errorf("errors in sending message to dataplanes: primary error %w, secondary error %w", + primaryErr, secondaryErr) + } + + return hostVethName, contVethMAC, nil +} + +func (m multiplexer) CleanUpNamespace(args *skel.CmdArgs) error { + secondaryErr := m.secondary.CleanUpNamespace(args) + primaryErr := m.primary.CleanUpNamespace(args) + + if primaryErr != nil || secondaryErr != nil { + return fmt.Errorf("errors in clean up namespaces of dataplanes: primary error %w, secondary error %w", + primaryErr, secondaryErr) + } + + return nil +}