diff --git a/go.mod b/go.mod index b680b8742..f0b8884c3 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/HdrHistogram/hdrhistogram-go v1.0.1 // indirect + github.com/RoaringBitmap/roaring v0.9.4 github.com/benbjohnson/clock v1.1.0 github.com/edwarnicke/exechelper v1.0.2 github.com/edwarnicke/grpcfd v0.1.0 diff --git a/go.sum b/go.sum index fdcdb64cc..dd2c657e9 100644 --- a/go.sum +++ b/go.sum @@ -6,12 +6,16 @@ github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnl github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.3 h1:wS8NNaIgtzapuArKIAjsyXtEN/IUjQkbw90xszUdS40= github.com/OneOfOne/xxhash v1.2.3/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/RoaringBitmap/roaring v0.9.4 h1:ckvZSX5gwCRaJYBNe7syNawCU5oruY9gQmjXlp4riwo= +github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -116,6 +120,8 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-runewidth v0.0.0-20181025052659-b20a3daf6a39/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mna/pigeon v0.0.0-20180808201053-bb0192cfc2ae/go.mod h1:Iym28+kJVnC1hfQvv5MUtI6AiFFzvQjHcvI4RFTG/04= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= diff --git a/pkg/networkservice/common/mechanisms/kernel/vlan/server.go b/pkg/networkservice/common/mechanisms/kernel/vlan/server.go new file mode 100644 index 000000000..94f5f4328 --- /dev/null +++ b/pkg/networkservice/common/mechanisms/kernel/vlan/server.go @@ -0,0 +1,85 @@ +// 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. + +// +build linux + +// Package vlan provides server chain element setting vlan id on the kernel mechanism +package vlan + +import ( + "context" + "errors" + "sync" + + "github.com/RoaringBitmap/roaring" + "github.com/golang/protobuf/ptypes/empty" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + kernelmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel" + + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +type vlanServer struct { + freeVLANs *roaring.Bitmap + lock sync.Mutex +} + +// NewServer - creates a NetworkServiceServer that requests a kernel interface with vlan parameter +func NewServer() networkservice.NetworkServiceServer { + vlans := roaring.New() + vlans.AddRange(1, 4095) + return &vlanServer{ + freeVLANs: vlans, + } +} + +func (m *vlanServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { + mechanism := kernelmech.ToMechanism(request.GetConnection().GetMechanism()) + isEstablished := true + if mechanism != nil && mechanism.SupportsVLAN() && mechanism.GetVLAN() == 0 { + m.lock.Lock() + if m.freeVLANs.IsEmpty() { + m.lock.Unlock() + return nil, errors.New("vlan id not available for allocation") + } + vlanID := m.freeVLANs.Minimum() + m.freeVLANs.Remove(vlanID) + m.lock.Unlock() + + mechanism.SetVLAN(vlanID) + isEstablished = false + } + conn, err := next.Server(ctx).Request(ctx, request) + if err != nil && mechanism != nil && !isEstablished { + m.releaseVLANID(mechanism) + } + return conn, err +} + +func (m *vlanServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { + mechanism := kernelmech.ToMechanism(conn.GetMechanism()) + if mechanism != nil && mechanism.SupportsVLAN() && mechanism.GetVLAN() > 0 { + m.releaseVLANID(mechanism) + } + return next.Server(ctx).Close(ctx, conn) +} + +func (m *vlanServer) releaseVLANID(mechanism *kernelmech.Mechanism) { + m.lock.Lock() + defer m.lock.Unlock() + m.freeVLANs.Add(mechanism.GetVLAN()) +}