-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: split server object per package
Signed-off-by: Boris Glimcher <[email protected]>
- Loading branch information
Showing
32 changed files
with
1,382 additions
and
369 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
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,212 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. | ||
|
||
// Package bridge is the main package of the application | ||
package bridge | ||
|
||
import ( | ||
"context" | ||
"crypto/rand" | ||
"fmt" | ||
"log" | ||
"net" | ||
|
||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"google.golang.org/protobuf/proto" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/test/bufconn" | ||
|
||
pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" | ||
pc "github.com/opiproject/opi-api/network/opinetcommon/v1alpha1/gen/go" | ||
) | ||
|
||
// TODO: move all of this to a common place | ||
const ( | ||
tenantbridgeName = "br-tenant" | ||
) | ||
|
||
var ( | ||
testLogicalBridgeID = "opi-bridge9" | ||
testLogicalBridgeName = resourceIDToFullName("bridges", testLogicalBridgeID) | ||
testLogicalBridge = pb.LogicalBridge{ | ||
Spec: &pb.LogicalBridgeSpec{ | ||
Vni: proto.Uint32(11), | ||
VlanId: 22, | ||
VtepIpPrefix: &pc.IPPrefix{ | ||
Addr: &pc.IPAddress{ | ||
Af: pc.IpAf_IP_AF_INET, | ||
V4OrV6: &pc.IPAddress_V4Addr{ | ||
V4Addr: 167772162, | ||
}, | ||
}, | ||
Len: 24, | ||
}, | ||
}, | ||
} | ||
testLogicalBridgeWithStatus = pb.LogicalBridge{ | ||
Name: testLogicalBridgeName, | ||
Spec: testLogicalBridge.Spec, | ||
Status: &pb.LogicalBridgeStatus{ | ||
OperStatus: pb.LBOperStatus_LB_OPER_STATUS_UP, | ||
}, | ||
} | ||
|
||
testBridgePortID = "opi-port8" | ||
testBridgePortName = resourceIDToFullName("ports", testBridgePortID) | ||
testBridgePort = pb.BridgePort{ | ||
Spec: &pb.BridgePortSpec{ | ||
MacAddress: []byte{0xCB, 0xB8, 0x33, 0x4C, 0x88, 0x4F}, | ||
Ptype: pb.BridgePortType_TRUNK, | ||
LogicalBridges: []string{testLogicalBridgeName}, | ||
}, | ||
} | ||
testBridgePortWithStatus = pb.BridgePort{ | ||
Name: testBridgePortName, | ||
Spec: testBridgePort.Spec, | ||
Status: &pb.BridgePortStatus{ | ||
OperStatus: pb.BPOperStatus_BP_OPER_STATUS_UP, | ||
}, | ||
} | ||
|
||
testSviID = "opi-svi8" | ||
testSviName = resourceIDToFullName("svis", testSviID) | ||
testSvi = pb.Svi{ | ||
Spec: &pb.SviSpec{ | ||
Vrf: testVrfName, | ||
LogicalBridge: testLogicalBridgeName, | ||
MacAddress: []byte{0xCB, 0xB8, 0x33, 0x4C, 0x88, 0x4F}, | ||
GwIpPrefix: []*pc.IPPrefix{{Len: 24}}, | ||
}, | ||
} | ||
testSviWithStatus = pb.Svi{ | ||
Name: testSviName, | ||
Spec: testSvi.Spec, | ||
Status: &pb.SviStatus{ | ||
OperStatus: pb.SVIOperStatus_SVI_OPER_STATUS_UP, | ||
}, | ||
} | ||
|
||
testVrfID = "opi-vrf8" | ||
testVrfName = resourceIDToFullName("vrfs", testVrfID) | ||
testVrf = pb.Vrf{ | ||
Spec: &pb.VrfSpec{ | ||
Vni: proto.Uint32(1000), | ||
LoopbackIpPrefix: &pc.IPPrefix{ | ||
// Addr: &pc.IPAddress{ | ||
// Af: pc.IpAf_IP_AF_INET, | ||
// V4OrV6: &pc.IPAddress_V4Addr{ | ||
// V4Addr: 167772162, | ||
// }, | ||
// }, | ||
Len: 24, | ||
}, | ||
VtepIpPrefix: &pc.IPPrefix{ | ||
Addr: &pc.IPAddress{ | ||
Af: pc.IpAf_IP_AF_INET, | ||
V4OrV6: &pc.IPAddress_V4Addr{ | ||
V4Addr: 167772162, | ||
}, | ||
}, | ||
Len: 24, | ||
}, | ||
}, | ||
} | ||
testVrfWithStatus = pb.Vrf{ | ||
Name: testVrfName, | ||
Spec: testVrf.Spec, | ||
Status: &pb.VrfStatus{ | ||
LocalAs: 4, | ||
}, | ||
} | ||
) | ||
|
||
func resourceIDToFullName(container string, resourceID string) string { | ||
return fmt.Sprintf("//network.opiproject.org/%s/%s", container, resourceID) | ||
} | ||
|
||
func protoClone[T proto.Message](protoStruct T) T { | ||
return proto.Clone(protoStruct).(T) | ||
} | ||
|
||
func generateRandMAC() ([]byte, error) { | ||
buf := make([]byte, 6) | ||
if _, err := rand.Read(buf); err != nil { | ||
return nil, fmt.Errorf("unable to retrieve 6 rnd bytes: %s", err) | ||
} | ||
|
||
// Set locally administered addresses bit and reset multicast bit | ||
buf[0] = (buf[0] | 0x02) & 0xfe | ||
|
||
return buf, nil | ||
} | ||
|
||
func extractPagination(pageSize int32, pageToken string, pagination map[string]int) (size int, offset int, err error) { | ||
const ( | ||
maxPageSize = 250 | ||
defaultPageSize = 50 | ||
) | ||
switch { | ||
case pageSize < 0: | ||
return -1, -1, status.Error(codes.InvalidArgument, "negative PageSize is not allowed") | ||
case pageSize == 0: | ||
size = defaultPageSize | ||
case pageSize > maxPageSize: | ||
size = maxPageSize | ||
default: | ||
size = int(pageSize) | ||
} | ||
// fetch offset from the database using opaque token | ||
offset = 0 | ||
if pageToken != "" { | ||
var ok bool | ||
offset, ok = pagination[pageToken] | ||
if !ok { | ||
return -1, -1, status.Errorf(codes.NotFound, "unable to find pagination token %s", pageToken) | ||
} | ||
log.Printf("Found offset %d from pagination token: %s", offset, pageToken) | ||
} | ||
return size, offset, nil | ||
} | ||
|
||
func limitPagination[T any](result []T, offset int, size int) ([]T, bool) { | ||
end := offset + size | ||
hasMoreElements := false | ||
if end < len(result) { | ||
hasMoreElements = true | ||
} else { | ||
end = len(result) | ||
} | ||
return result[offset:end], hasMoreElements | ||
} | ||
|
||
func dialer(opi *Server) func(context.Context, string) (net.Conn, error) { | ||
listener := bufconn.Listen(1024 * 1024) | ||
server := grpc.NewServer() | ||
|
||
pb.RegisterLogicalBridgeServiceServer(server, opi) | ||
|
||
go func() { | ||
if err := server.Serve(listener); err != nil { | ||
log.Fatal(err) | ||
} | ||
}() | ||
|
||
return func(context.Context, string) (net.Conn, error) { | ||
return listener.Dial() | ||
} | ||
} | ||
|
||
func equalProtoSlices[T proto.Message](x, y []T) bool { | ||
if len(x) != len(y) { | ||
return false | ||
} | ||
|
||
for i := 0; i < len(x); i++ { | ||
if !proto.Equal(x[i], y[i]) { | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} |
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,58 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. | ||
|
||
// Package bridge is the main package of the application | ||
package bridge | ||
|
||
import ( | ||
"log" | ||
|
||
"go.opentelemetry.io/otel" | ||
"go.opentelemetry.io/otel/trace" | ||
|
||
"github.com/philippgille/gokv" | ||
|
||
pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" | ||
|
||
"github.com/opiproject/opi-evpn-bridge/pkg/utils" | ||
) | ||
|
||
// Server represents the Server object | ||
type Server struct { | ||
pb.UnimplementedLogicalBridgeServiceServer | ||
Pagination map[string]int | ||
ListHelper map[string]bool | ||
nLink utils.Netlink | ||
frr utils.Frr | ||
tracer trace.Tracer | ||
store gokv.Store | ||
} | ||
|
||
// NewServer creates initialized instance of EVPN server | ||
func NewServer(store gokv.Store) *Server { | ||
nLink := utils.NewNetlinkWrapper() | ||
frr := utils.NewFrrWrapper() | ||
return NewServerWithArgs(nLink, frr, store) | ||
} | ||
|
||
// NewServerWithArgs creates initialized instance of EVPN server | ||
// with externally created Netlink | ||
func NewServerWithArgs(nLink utils.Netlink, frr utils.Frr, store gokv.Store) *Server { | ||
if frr == nil { | ||
log.Panic("nil for Frr is not allowed") | ||
} | ||
if nLink == nil { | ||
log.Panic("nil for Netlink is not allowed") | ||
} | ||
if store == nil { | ||
log.Panic("nil for Store is not allowed") | ||
} | ||
return &Server{ | ||
ListHelper: make(map[string]bool), | ||
Pagination: make(map[string]int), | ||
nLink: nLink, | ||
frr: frr, | ||
tracer: otel.Tracer(""), | ||
store: store, | ||
} | ||
} |
Oops, something went wrong.