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

[vlan multiplexing] use single veth pair for kernel vlan case #62

Merged
merged 1 commit into from
Nov 9, 2021
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
14 changes: 8 additions & 6 deletions pkg/networkservice/mechanisms/kernel/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ import (
)

type kernelClient struct {
bridgeName string
parentIfmutex sync.Locker
parentIfRefCountMap map[string]int
bridgeName string
parentIfmutex sync.Locker
parentIfRefCountMap map[string]int
serviceToparentIfMap map[string]string
}

// NewClient returns a client chain element implementing kernel mechanism with veth pair or smartvf
func NewClient(bridgeName string, mutex sync.Locker, parentIfRefCountMap map[string]int) networkservice.NetworkServiceClient {
return &kernelClient{bridgeName: bridgeName, parentIfmutex: mutex, parentIfRefCountMap: parentIfRefCountMap}
return &kernelClient{bridgeName: bridgeName, parentIfmutex: mutex, parentIfRefCountMap: parentIfRefCountMap,
serviceToparentIfMap: make(map[string]string)}
}

func (c *kernelClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
Expand Down Expand Up @@ -83,7 +85,7 @@ func (c *kernelClient) Request(ctx context.Context, request *networkservice.Netw
}
}
} else {
if err = setupVeth(ctx, logger, conn, c.bridgeName, c.parentIfRefCountMap, metadata.IsClient(c)); err != nil {
if err = setupVeth(ctx, logger, conn, c.bridgeName, c.parentIfRefCountMap, c.serviceToparentIfMap, metadata.IsClient(c)); err != nil {
closeCtx, cancelClose := postponeCtxFunc()
defer cancelClose()
if _, closeErr := c.Close(closeCtx, conn, opts...); closeErr != nil {
Expand All @@ -106,7 +108,7 @@ func (c *kernelClient) Close(ctx context.Context, conn *networkservice.Connectio
ovsPortInfo, exists := ifnames.Load(ctx, metadata.IsClient(c))
if exists {
if !ovsPortInfo.IsVfRepresentor {
kernelMechErr = resetVeth(ctx, logger, conn, c.bridgeName, c.parentIfRefCountMap, metadata.IsClient(c))
kernelMechErr = resetVeth(ctx, logger, conn, c.bridgeName, c.parentIfRefCountMap, c.serviceToparentIfMap, metadata.IsClient(c))
} else {
kernelMechErr = resetVF(logger, ovsPortInfo, c.parentIfRefCountMap, c.bridgeName)
}
Expand Down
63 changes: 46 additions & 17 deletions pkg/networkservice/mechanisms/kernel/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const (
)

func setupVeth(ctx context.Context, logger log.Logger, conn *networkservice.Connection, bridgeName string,
parentIfRefCountMap map[string]int, isClient bool) error {
parentIfRefCountMap map[string]int, serviceToparentIfMap map[string]string, isClient bool) error {
var mechanism *kernel.Mechanism
if mechanism = kernel.ToMechanism(conn.GetMechanism()); mechanism == nil {
return nil
Expand All @@ -53,21 +53,34 @@ func setupVeth(ctx context.Context, logger log.Logger, conn *networkservice.Conn
return nil
}

// use intermediate contIfName to avoid interface name collision with parallel service requests from other clients.
serviceName := conn.GetNetworkService()

var hostIfName, contIfName string
if isClient {
hostIfName = GetVethPeerName(conn, ovsPortDstPrefix, true)
contIfName = GetVethPeerName(conn, contPortDstPrefix, true)
} else {
hostIfName = GetVethPeerName(conn, ovsPortSrcPrefix, false)
contIfName = GetVethPeerName(conn, contPortSrcPrefix, false)
if mechanism.GetVLAN() > 0 {
if parentIfName, exists := serviceToparentIfMap[serviceName]; exists {
hostIfName = parentIfName
}
}

if err := createInterfaces(contIfName, hostIfName); err != nil {
return err
}
if err := SetInterfacesUp(logger, contIfName, hostIfName); err != nil {
return err
// use intermediate contIfName to avoid interface name collision with parallel service requests from other clients.
if hostIfName == "" {
if isClient {
hostIfName = GetVethPeerName(conn, ovsPortDstPrefix, true)
contIfName = GetVethPeerName(conn, contPortDstPrefix, true)
} else {
hostIfName = GetVethPeerName(conn, ovsPortSrcPrefix, false)
contIfName = GetVethPeerName(conn, contPortSrcPrefix, false)
}

if err := createInterfaces(contIfName, hostIfName); err != nil {
return err
}
if err := SetInterfacesUp(logger, contIfName, hostIfName); err != nil {
return err
}
if mechanism.GetVLAN() > 0 {
serviceToparentIfMap[serviceName] = hostIfName
}
}

if _, exists := parentIfRefCountMap[hostIfName]; !exists {
Expand Down Expand Up @@ -96,12 +109,27 @@ func setupVeth(ctx context.Context, logger log.Logger, conn *networkservice.Conn
}

func resetVeth(ctx context.Context, logger log.Logger, conn *networkservice.Connection, bridgeName string,
parentIfRefCountMap map[string]int, isClient bool) error {
parentIfRefCountMap map[string]int, serviceToparentIfMap map[string]string, isClient bool) error {
var mechanism *kernel.Mechanism
if mechanism = kernel.ToMechanism(conn.GetMechanism()); mechanism == nil {
return nil
}

serviceName := conn.GetNetworkService()

var ifaceName string
if isClient {
ifaceName = GetVethPeerName(conn, ovsPortDstPrefix, true)
if mechanism.GetVLAN() > 0 {
if parentIfName, exists := serviceToparentIfMap[serviceName]; exists {
ifaceName = parentIfName
} else {
return errors.Errorf("parent interface not found for connection %v", conn)
}
} else {
ifaceName = GetVethPeerName(conn, ovsPortSrcPrefix, false)
if isClient {
ifaceName = GetVethPeerName(conn, ovsPortDstPrefix, true)
} else {
ifaceName = GetVethPeerName(conn, ovsPortSrcPrefix, false)
}
}

var refCount int
Expand Down Expand Up @@ -135,6 +163,7 @@ func resetVeth(ctx context.Context, logger log.Logger, conn *networkservice.Conn
return errors.Errorf("local: failed to delete the VETH pair - %v", err)
}
delete(parentIfRefCountMap, ifaceName)
delete(serviceToparentIfMap, serviceName)
}

vfconfig.Delete(ctx, isClient)
Expand Down
18 changes: 10 additions & 8 deletions pkg/networkservice/mechanisms/kernel/veth_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@ import (
)

type kernelVethServer struct {
bridgeName string
parentIfmutex sync.Locker
parentIfRefCountMap map[string]int
bridgeName string
parentIfmutex sync.Locker
parentIfRefCountMap map[string]int
serviceToparentIfMap map[string]string
}

// NewVethServer - return a new Veth Server chain element for kernel mechanism
func NewVethServer(bridgeName string, mutex sync.Locker, parentIfRefCountMap map[string]int) networkservice.NetworkServiceServer {
return &kernelVethServer{bridgeName: bridgeName, parentIfmutex: mutex, parentIfRefCountMap: parentIfRefCountMap}
return &kernelVethServer{bridgeName: bridgeName, parentIfmutex: mutex, parentIfRefCountMap: parentIfRefCountMap,
serviceToparentIfMap: make(map[string]string)}
}

// NewClient create a kernel veth server chain element which would be useful to do network plumbing
Expand All @@ -54,8 +56,8 @@ func (k *kernelVethServer) Request(ctx context.Context, request *networkservice.

if !isEstablished {
k.parentIfmutex.Lock()
if err := setupVeth(ctx, logger, request.GetConnection(), k.bridgeName, k.parentIfRefCountMap, metadata.IsClient(k)); err != nil {
_ = resetVeth(ctx, logger, request.GetConnection(), k.bridgeName, k.parentIfRefCountMap, metadata.IsClient(k))
if err := setupVeth(ctx, logger, request.GetConnection(), k.bridgeName, k.parentIfRefCountMap, k.serviceToparentIfMap, metadata.IsClient(k)); err != nil {
_ = resetVeth(ctx, logger, request.GetConnection(), k.bridgeName, k.parentIfRefCountMap, k.serviceToparentIfMap, metadata.IsClient(k))
k.parentIfmutex.Unlock()
return nil, err
}
Expand All @@ -69,7 +71,7 @@ func (k *kernelVethServer) Request(ctx context.Context, request *networkservice.
defer cancelClose()
if _, exists := ifnames.LoadAndDelete(closeCtx, metadata.IsClient(k)); exists {
k.parentIfmutex.Lock()
if kernelServerErr := resetVeth(closeCtx, logger, request.GetConnection(), k.bridgeName, k.parentIfRefCountMap, metadata.IsClient(k)); kernelServerErr != nil {
if kernelServerErr := resetVeth(closeCtx, logger, request.GetConnection(), k.bridgeName, k.parentIfRefCountMap, k.serviceToparentIfMap, metadata.IsClient(k)); kernelServerErr != nil {
err = errors.Wrapf(err, "connection closed with error: %s", kernelServerErr.Error())
}
k.parentIfmutex.Unlock()
Expand All @@ -90,7 +92,7 @@ func (k *kernelVethServer) Close(ctx context.Context, conn *networkservice.Conne
var kernelServerErr error
_, exists := ifnames.LoadAndDelete(ctx, metadata.IsClient(k))
if exists {
kernelServerErr = resetVeth(ctx, logger, conn, k.bridgeName, k.parentIfRefCountMap, metadata.IsClient(k))
kernelServerErr = resetVeth(ctx, logger, conn, k.bridgeName, k.parentIfRefCountMap, k.serviceToparentIfMap, metadata.IsClient(k))
}
if err != nil && kernelServerErr != nil {
return nil, errors.Wrap(err, kernelServerErr.Error())
Expand Down