forked from networkservicemesh/sdk-vpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
See related: networkservicemesh/cmd-forwarder-vpp#365 networkservicemesh/api#112 networkservicemesh/sdk-kernel#355 Signed-off-by: Laszlo Kiraly <laszlo.kiraly@est.tech>
- Loading branch information
Showing
13 changed files
with
722 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright (c) 2021 Nordix Foundation. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// 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 vlan | ||
|
||
import ( | ||
"context" | ||
"io" | ||
"time" | ||
|
||
"git.fd.io/govpp.git/api" | ||
|
||
interfaces "github.com/edwarnicke/govpp/binapi/interface" | ||
"github.com/golang/protobuf/ptypes/empty" | ||
"github.com/pkg/errors" | ||
"google.golang.org/grpc" | ||
|
||
"github.com/networkservicemesh/api/pkg/api/networkservice" | ||
"github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/cls" | ||
vlanmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" | ||
"github.com/networkservicemesh/api/pkg/api/networkservice/payload" | ||
"github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" | ||
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next" | ||
"github.com/networkservicemesh/sdk/pkg/tools/log" | ||
"github.com/networkservicemesh/sdk/pkg/tools/postpone" | ||
|
||
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/hwaddress" | ||
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/l2vtr" | ||
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/linkinit" | ||
"github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex" | ||
) | ||
|
||
const ( | ||
serviceDomainLabel = "serviceDomain" | ||
) | ||
|
||
type vlanClient struct { | ||
vppConn api.Connection | ||
deviceNames map[string]string | ||
} | ||
|
||
// NewClient returns a VLAN client chain element | ||
func NewClient(vppConn api.Connection, domain2Device map[string]string) networkservice.NetworkServiceClient { | ||
return chain.NewNetworkServiceClient( | ||
hwaddress.NewClient(vppConn), | ||
l2vtr.NewClient(vppConn), | ||
&vlanClient{ | ||
vppConn: vppConn, | ||
deviceNames: domain2Device, | ||
}, | ||
linkinit.NewClient(vppConn, domain2Device), | ||
) | ||
} | ||
|
||
func (v *vlanClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { | ||
if request.GetConnection().GetPayload() != payload.Ethernet { | ||
return next.Client(ctx).Request(ctx, request, opts...) | ||
} | ||
|
||
mechanism := &networkservice.Mechanism{ | ||
Cls: cls.REMOTE, | ||
Type: vlanmech.MECHANISM, | ||
Parameters: make(map[string]string), | ||
} | ||
request.MechanismPreferences = append(request.MechanismPreferences, mechanism) | ||
|
||
postponeCtxFunc := postpone.ContextWithValues(ctx) | ||
|
||
conn, err := next.Client(ctx).Request(ctx, request, opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if err := addSubIf(ctx, conn, v.vppConn, v.deviceNames); err != nil { | ||
closeCtx, cancelClose := postponeCtxFunc() | ||
defer cancelClose() | ||
|
||
if _, closeErr := v.Close(closeCtx, conn, opts...); closeErr != nil { | ||
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) | ||
} | ||
|
||
return nil, err | ||
} | ||
|
||
return conn, nil | ||
} | ||
|
||
func (v *vlanClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { | ||
if conn.GetPayload() != payload.Ethernet { | ||
return next.Client(ctx).Close(ctx, conn, opts...) | ||
} | ||
_ = delSubIf(ctx, conn, v.vppConn) | ||
return next.Client(ctx).Close(ctx, conn, opts...) | ||
} | ||
|
||
func addSubIf(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection, deviceNames map[string]string) error { | ||
if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { | ||
_, ok := ifindex.Load(ctx, true) | ||
if ok { | ||
return nil | ||
} | ||
now := time.Now() | ||
serviceDomain := conn.GetLabels()[serviceDomainLabel] | ||
hostIFName, ok := deviceNames[serviceDomain] | ||
if !ok { | ||
return errors.Errorf("no interface name for service domain %s", serviceDomain) | ||
} | ||
|
||
client, err := interfaces.NewServiceClient(vppConn).SwInterfaceDump(ctx, &interfaces.SwInterfaceDump{ | ||
NameFilterValid: true, | ||
NameFilter: hostIFName, | ||
}) | ||
if err != nil { | ||
return errors.Wrapf(err, "error attempting to get interface dump client to set vlan subinterface on %q", hostIFName) | ||
} | ||
log.FromContext(ctx). | ||
WithField("duration", time.Since(now)). | ||
WithField("HostInterfaceName", hostIFName). | ||
WithField("vppapi", "SwInterfaceDump").Debug("completed") | ||
|
||
for { | ||
details, err := client.Recv() | ||
if err == io.EOF { | ||
break | ||
} | ||
if err != nil { | ||
return errors.Wrapf(err, "error attempting to get interface details to set vlan subinterface on %q", hostIFName) | ||
} | ||
now = time.Now() | ||
swIfIndex := details.SwIfIndex | ||
vlanID := mechanism.GetVlanID() | ||
vlanSubif := &interfaces.CreateVlanSubif{ | ||
SwIfIndex: swIfIndex, | ||
VlanID: vlanID, | ||
} | ||
|
||
rsp, err := interfaces.NewServiceClient(vppConn).CreateVlanSubif(ctx, vlanSubif) | ||
if err != nil { | ||
return errors.WithStack(err) | ||
} | ||
log.FromContext(ctx). | ||
WithField("duration", time.Since(now)). | ||
WithField("HostInterfaceIndex", swIfIndex). | ||
WithField("VlanID", vlanID). | ||
WithField("vppapi", "CreateVlanSubIf").Debug("completed") | ||
|
||
ifindex.Store(ctx, true, rsp.SwIfIndex) | ||
} | ||
} | ||
return nil | ||
} | ||
func delSubIf(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection) error { | ||
if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { | ||
swIfIndex, ok := ifindex.Load(ctx, true) | ||
if !ok { | ||
return nil | ||
} | ||
now := time.Now() | ||
vlanSubif := &interfaces.DeleteSubif{ | ||
SwIfIndex: swIfIndex, | ||
} | ||
_, err := interfaces.NewServiceClient(vppConn).DeleteSubif(ctx, vlanSubif) | ||
if err != nil { | ||
return errors.WithStack(err) | ||
} | ||
log.FromContext(ctx). | ||
WithField("duration", time.Since(now)). | ||
WithField("HostInterfaceIndex", swIfIndex). | ||
WithField("vppapi", "DeleteSubif").Debug("completed") | ||
ifindex.Delete(ctx, true) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright (c) 2021 Nordix Foundation. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// 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 vlan provides chain elements for implementing the vlan mechanism | ||
package vlan |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright (c) 2021 Nordix Foundation. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// 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 hwaddress | ||
|
||
import ( | ||
"context" | ||
|
||
"git.fd.io/govpp.git/api" | ||
"github.com/golang/protobuf/ptypes/empty" | ||
"github.com/pkg/errors" | ||
"google.golang.org/grpc" | ||
|
||
"github.com/networkservicemesh/api/pkg/api/networkservice" | ||
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next" | ||
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" | ||
"github.com/networkservicemesh/sdk/pkg/tools/postpone" | ||
) | ||
|
||
type hwaddressClient struct { | ||
vppConn api.Connection | ||
} | ||
|
||
// NewClient - updates ethernet context with hw address | ||
func NewClient(vppConn api.Connection) networkservice.NetworkServiceClient { | ||
return &hwaddressClient{ | ||
vppConn: vppConn, | ||
} | ||
} | ||
|
||
func (h *hwaddressClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { | ||
postponeCtxFunc := postpone.ContextWithValues(ctx) | ||
|
||
conn, err := next.Client(ctx).Request(ctx, request, opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if err := setEthContextHwaddress(ctx, conn, h.vppConn, metadata.IsClient(h)); err != nil { | ||
if closeErr := h.closeOnFailure(postponeCtxFunc, conn, opts); closeErr != nil { | ||
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) | ||
} | ||
return nil, err | ||
} | ||
return conn, nil | ||
} | ||
|
||
func (h *hwaddressClient) closeOnFailure(postponeCtxFunc func() (context.Context, context.CancelFunc), conn *networkservice.Connection, opts []grpc.CallOption) error { | ||
closeCtx, cancelClose := postponeCtxFunc() | ||
defer cancelClose() | ||
|
||
_, err := h.Close(closeCtx, conn, opts...) | ||
|
||
return err | ||
} | ||
|
||
func (h *hwaddressClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { | ||
return next.Client(ctx).Close(ctx, conn, opts...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright (c) 2021 Nordix Foundation. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// 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 hwaddress | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"git.fd.io/govpp.git/api" | ||
"github.com/pkg/errors" | ||
|
||
interfaces "github.com/edwarnicke/govpp/binapi/interface" | ||
"github.com/networkservicemesh/api/pkg/api/networkservice" | ||
vlanmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" | ||
"github.com/networkservicemesh/sdk/pkg/tools/log" | ||
|
||
"github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex" | ||
) | ||
|
||
func setEthContextHwaddress(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection, isClient bool) error { | ||
if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { | ||
now := time.Now() | ||
swIfIndex, ok := ifindex.Load(ctx, isClient) | ||
if !ok { | ||
return nil | ||
} | ||
|
||
rsp, err := interfaces.NewServiceClient(vppConn).SwInterfaceGetMacAddress(ctx, &interfaces.SwInterfaceGetMacAddress{ | ||
SwIfIndex: swIfIndex}) | ||
if err != nil { | ||
return errors.WithStack(err) | ||
} | ||
log.FromContext(ctx). | ||
WithField("duration", time.Since(now)). | ||
WithField("HostInterfaceIndex", swIfIndex). | ||
WithField("HwAddress", rsp.MacAddress). | ||
WithField("vppapi", "SwInterfaceGetMacAddress").Debug("completed") | ||
|
||
if conn.GetContext().GetEthernetContext() == nil { | ||
conn.GetContext().EthernetContext = new(networkservice.EthernetContext) | ||
} | ||
ethernetContext := conn.GetContext().GetEthernetContext() | ||
|
||
ethernetContext.SrcMac = rsp.MacAddress.String() | ||
} | ||
return nil | ||
} |
Oops, something went wrong.