-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for retreiving from a remote RIB. (#196)
Add support for retrieving a RIB from a remote source. * (M) go.{mod,sum} - Move to non-release version of ygot to get new `protomap` features. * (M) rib/remote.go - Add support for a RIB that is accessed via the `Get` RPC rather than locally. * (M) rib/rib(_test).go - Add a mechanism to retrieve RIB contents, improve testing.
- Loading branch information
Showing
9 changed files
with
438 additions
and
13 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,67 @@ | ||
package reconciler | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/openconfig/gribigo/client" | ||
"github.com/openconfig/gribigo/rib" | ||
|
||
spb "github.com/openconfig/gribi/v1/proto/service" | ||
) | ||
|
||
// RemoteRIB implements the RIBTarget interface and wraps a remote gRIBI RIB. | ||
// The contents are accessed via the gRIBI gRPC API. | ||
type RemoteRIB struct { | ||
c *client.Client | ||
|
||
defaultName string | ||
} | ||
|
||
// NewRemoteRIB returns a new remote gRIBI RIB. The context supplied is used to | ||
// dial the remote gRIBI server at the address 'addr'. the 'defName' argument | ||
// is used to identify the name of the default network instance on the server. | ||
func NewRemoteRIB(ctx context.Context, defName, addr string) (*RemoteRIB, error) { | ||
gc, err := client.New() | ||
if err != nil { | ||
return nil, fmt.Errorf("cannot create gRIBI client, %v", err) | ||
} | ||
|
||
r := &RemoteRIB{ | ||
c: gc, | ||
defaultName: defName, | ||
} | ||
|
||
if err := r.c.Dial(ctx, addr); err != nil { | ||
return nil, fmt.Errorf("cannot dial remote server, %v", err) | ||
} | ||
return r, nil | ||
} | ||
|
||
// CleanUp closes the remote connection to the gRIBI server. | ||
func (r *RemoteRIB) CleanUp() { | ||
r.c.Close() | ||
} | ||
|
||
// Get retrieves the contents of the remote gRIBI server's RIB and returns it as a | ||
// gRIBIgo RIB struct. The context is used for a Get RPC call to the remote server. | ||
func (r *RemoteRIB) Get(ctx context.Context) (*rib.RIB, error) { | ||
resp, err := r.c.Get(ctx, &spb.GetRequest{ | ||
NetworkInstance: &spb.GetRequest_All{ | ||
All: &spb.Empty{}, | ||
}, | ||
Aft: spb.AFTType_ALL, | ||
}) | ||
if err != nil { | ||
return nil, fmt.Errorf("cannot get remote RIB, %v", err) | ||
} | ||
|
||
// We always disable the RIB checking function because we want to see entries that have | ||
// not got valid references so that we can reconcile them. | ||
remRIB, err := rib.FromGetResponses(r.defaultName, []*spb.GetResponse{resp}, rib.DisableRIBCheckFn()) | ||
if err != nil { | ||
return nil, fmt.Errorf("cannot build remote RIB from responses, %v", err) | ||
} | ||
|
||
return remRIB, 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,184 @@ | ||
package reconciler | ||
|
||
import ( | ||
"context" | ||
"net" | ||
"testing" | ||
"time" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/openconfig/gribigo/aft" | ||
"github.com/openconfig/gribigo/rib" | ||
"github.com/openconfig/gribigo/server" | ||
"github.com/openconfig/gribigo/testcommon" | ||
"github.com/openconfig/ygot/ygot" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/credentials" | ||
"google.golang.org/grpc/status" | ||
|
||
spb "github.com/openconfig/gribi/v1/proto/service" | ||
) | ||
|
||
func newServer(t *testing.T, r *rib.RIB) (string, func()) { | ||
creds, err := credentials.NewServerTLSFromFile(testcommon.TLSCreds()) | ||
if err != nil { | ||
t.Fatalf("cannot load TLS credentials, got err: %v", err) | ||
} | ||
srv := grpc.NewServer(grpc.Creds(creds)) | ||
s, err := server.NewFake() | ||
if err != nil { | ||
t.Fatalf("cannot create server, got err: %v", err) | ||
} | ||
s.InjectRIB(r) | ||
|
||
l, err := net.Listen("tcp", "localhost:0") | ||
if err != nil { | ||
t.Fatalf("cannot create listener, got err: %v", err) | ||
} | ||
spb.RegisterGRIBIServer(srv, s) | ||
|
||
go srv.Serve(l) | ||
return l.Addr().String(), srv.Stop | ||
} | ||
|
||
func TestNewRemoteRIB(t *testing.T) { | ||
tests := []struct { | ||
desc string | ||
inDefName string | ||
inAddrOverride string | ||
wantErr bool | ||
}{{ | ||
desc: "successful dial", | ||
inDefName: "DEFAULT", | ||
}, { | ||
desc: "unsuccessful dial", | ||
inDefName: "DEFAULT", | ||
inAddrOverride: "invalid.addr:999999", | ||
wantErr: true, | ||
}} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.desc, func(t *testing.T) { | ||
addr, stop := newServer(t, nil) | ||
defer stop() | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | ||
defer cancel() | ||
|
||
if tt.inAddrOverride != "" { | ||
addr = tt.inAddrOverride | ||
} | ||
|
||
if _, err := NewRemoteRIB(ctx, tt.inDefName, addr); (err != nil) != tt.wantErr { | ||
t.Fatalf("NewRemoteRIB(ctx, %s, %s): did not get expected error, got: %v, wantErr? %v", tt.inDefName, addr, err, tt.wantErr) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
type badGRIBI struct { | ||
*spb.UnimplementedGRIBIServer | ||
} | ||
|
||
func (b *badGRIBI) Get(_ *spb.GetRequest, _ spb.GRIBI_GetServer) error { | ||
return status.Errorf(codes.Unimplemented, "RPC unimplemented") | ||
} | ||
|
||
func newBadServer(t *testing.T, r *rib.RIB) (string, func()) { | ||
creds, err := credentials.NewServerTLSFromFile(testcommon.TLSCreds()) | ||
if err != nil { | ||
t.Fatalf("cannot load TLS credentials, got err: %v", err) | ||
} | ||
srv := grpc.NewServer(grpc.Creds(creds)) | ||
s := &badGRIBI{} | ||
|
||
l, err := net.Listen("tcp", "localhost:0") | ||
if err != nil { | ||
t.Fatalf("cannot create listener, got err: %v", err) | ||
} | ||
spb.RegisterGRIBIServer(srv, s) | ||
|
||
go srv.Serve(l) | ||
return l.Addr().String(), srv.Stop | ||
|
||
} | ||
|
||
func TestGet(t *testing.T) { | ||
dn := "DEFAULT" | ||
tests := []struct { | ||
desc string | ||
inDefName string | ||
inServer func(*testing.T, *rib.RIB) (string, func()) | ||
inInjectedRIB *rib.RIB | ||
wantRIBContents map[string]*aft.RIB | ||
wantErr bool | ||
}{{ | ||
desc: "cannot get RIB", | ||
inDefName: "DEFAULT", | ||
inServer: newBadServer, | ||
wantErr: true, | ||
}, { | ||
desc: "successfully got RIB", | ||
inDefName: dn, | ||
inServer: newServer, | ||
inInjectedRIB: func() *rib.RIB { | ||
r := rib.NewFake(dn) | ||
if err := r.InjectNH(dn, 1); err != nil { | ||
t.Fatalf("cannot add NH, %v", err) | ||
} | ||
if err := r.InjectNHG(dn, 1, map[uint64]uint64{1: 1}); err != nil { | ||
t.Fatalf("cannot add NHG, %v", err) | ||
} | ||
if err := r.InjectIPv4(dn, "1.0.0.0/24", 1); err != nil { | ||
t.Fatalf("cannot add IPv4, %v", err) | ||
} | ||
return r.RIB() | ||
}(), | ||
wantRIBContents: map[string]*aft.RIB{ | ||
dn: func() *aft.RIB { | ||
r := &aft.RIB{} | ||
a := r.GetOrCreateAfts() | ||
a.GetOrCreateIpv4Entry("1.0.0.0/24").NextHopGroup = ygot.Uint64(1) | ||
a.GetOrCreateNextHopGroup(1).GetOrCreateNextHop(1).Weight = ygot.Uint64(1) | ||
a.GetOrCreateNextHop(1) | ||
return r | ||
}(), | ||
}, | ||
}} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.desc, func(t *testing.T) { | ||
addr, stop := tt.inServer(t, tt.inInjectedRIB) | ||
defer stop() | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | ||
defer cancel() | ||
|
||
rr, err := NewRemoteRIB(ctx, tt.inDefName, addr) | ||
if err != nil { | ||
t.Fatalf("NewRemoteRIB(_, %s, %s): cannot connect, got err: %v", tt.inDefName, addr, err) | ||
} | ||
|
||
got, err := rr.Get(ctx) | ||
if (err != nil) != tt.wantErr { | ||
t.Fatalf("(*RemoteRIB).Get(ctx): did not get expected err, got: %v, wantErr? %v", err, tt.wantErr) | ||
} | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
// We can't introspect the private RIB contents, so make a copy to introspect. | ||
gotContents, err := got.RIBContents() | ||
if err != nil { | ||
t.Fatalf("(*RemoteRIB).Get(ctx).RIBContents(): can't introspect RIB, err: %v", err) | ||
} | ||
|
||
if diff := cmp.Diff(gotContents, tt.wantRIBContents); diff != "" { | ||
t.Fatalf("(*RemoteRIB).Get(ctx): did not get expected contents, diff(-got,+want):\n%s", diff) | ||
} | ||
|
||
}) | ||
} | ||
} |
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
Oops, something went wrong.