• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openconfig / gribigo / 10240276659

01 Aug 2024 09:24PM UTC coverage: 73.778%. Remained the same
10240276659

push

github

web-flow
Merge pull request #242 from openconfig/nh-delete-rjs

Ensure that non-nil NH is written in fluent test.

15 of 32 new or added lines in 2 files covered. (46.88%)

2 existing lines in 1 file now uncovered.

6398 of 8672 relevant lines covered (73.78%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.96
/fluent/fluent.go
1
// Copyright 2021 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
// Package fluent defines a fluent-style API for a gRIBI client that
16
// can be called from testing frameworks such as ONDATRA.
17
package fluent
18

19
import (
20
        "context"
21
        "errors"
22
        "fmt"
23
        "testing"
24

25
        log "github.com/golang/glog"
26
        "github.com/openconfig/gribigo/client"
27
        "github.com/openconfig/gribigo/constants"
28
        "google.golang.org/grpc/codes"
29
        "google.golang.org/grpc/status"
30
        "google.golang.org/protobuf/proto"
31

32
        aftpb "github.com/openconfig/gribi/v1/proto/gribi_aft"
33
        enums "github.com/openconfig/gribi/v1/proto/gribi_aft/enums"
34
        spb "github.com/openconfig/gribi/v1/proto/service"
35
        wpb "github.com/openconfig/ygot/proto/ywrapper"
36
)
37

38
// GRIBIClient stores internal state and arguments related to the gRIBI client
39
// that is exposed by the fluent API.
40
type GRIBIClient struct {
41
        // connection stores the configuration related to the connection.
42
        connection *gRIBIConnection
43
        // Internal state.
44
        c *client.Client
45
        // ctx is the context being used to dial.
46
        ctx context.Context
47

48
        // opCount is the count of AFTOperations that has been sent by the client,
49
        // used to populate the ID of AFTOperation messages automatically.
50
        opCount uint64
51
        // currentElectionID is the current electionID that the client should use.
52
        currentElectionID *spb.Uint128
53
}
54

55
type gRIBIConnection struct {
56
        // targetAddr stores the address that is to be dialed by the client.
57
        targetAddr string
58
        // stub is a gRPC GRIBIClient stub implementation that could be used
59
        // alternatively in lieu of targetAddr.
60
        stub spb.GRIBIClient
61
        // redundMode specifies the redundancy mode that the client is using,
62
        // this is set only at initialisation time and cannot be changed during
63
        // the lifetime of the session.
64
        redundMode RedundancyMode
65
        // electionID specifies the initial election ID for the client.
66
        electionID *spb.Uint128
67
        // persist indicates whether the client requests that the server persists
68
        // entries after it disconnects.
69
        persist bool
70
        // fibACK indicates whether the client requests that the server sends
71
        // a FIB ACK rather than a RIB ACK.
72
        fibACK bool
73

74
        // parent is a pointer to the parent of the gRIBIConnection.
75
        parent *GRIBIClient
76
}
77

78
// NewClient returns a new gRIBI client instance, and is an entrypoint to this
79
// package.
80
func NewClient() *GRIBIClient {
1✔
81
        return &GRIBIClient{}
1✔
82
}
1✔
83

84
// Connection allows any parameters relating to gRIBI connections to be set through
85
// the gRIBI fluent API.
86
func (g *GRIBIClient) Connection() *gRIBIConnection {
1✔
87
        if g.connection != nil {
1✔
88
                return g.connection
×
89
        }
×
90
        c := &gRIBIConnection{parent: g}
1✔
91
        g.connection = c
1✔
92
        return c
1✔
93
}
94

95
// WithTarget specifies the gRIBI target (server) address that is to be dialed,
96
// the addr argument supplied is the address of the server specified in the standard
97
// form of address:port.
98
func (g *gRIBIConnection) WithTarget(addr string) *gRIBIConnection {
1✔
99
        g.targetAddr = addr
1✔
100
        g.stub = nil
1✔
101
        return g
1✔
102
}
1✔
103

104
// WithStub specifies the gRPC GRIBIClient stub for use with this
105
// connection, in lieu of a gRIBI target (server) address.
106
func (g *gRIBIConnection) WithStub(stub spb.GRIBIClient) *gRIBIConnection {
×
107
        g.targetAddr = ""
×
108
        g.stub = stub
×
109
        return g
×
110
}
×
111

112
// WithPersistence specifies that the gRIBI server should maintain the RIB
113
// state after the client disconnects.
114
func (g *gRIBIConnection) WithPersistence() *gRIBIConnection {
1✔
115
        g.persist = true
1✔
116
        return g
1✔
117
}
1✔
118

119
// WithFIBACK indicates that the gRIBI server should send an ACK after the
120
// entry has been programmed into the FIB.
121
func (g *gRIBIConnection) WithFIBACK() *gRIBIConnection {
×
122
        g.fibACK = true
×
123
        return g
×
124
}
×
125

126
// RedundancyMode is a type used to indicate the redundancy modes supported in gRIBI.
127
type RedundancyMode int64
128

129
const (
130
        _ RedundancyMode = iota
131
        // AllPrimaryClients indicates that all clients should be treated as a primary
132
        // and the server should do reference counting and bestpath selection between
133
        // them using the standard mechansisms defined in gRIBI.
134
        AllPrimaryClients
135
        // ElectedPrimaryClient indicates that this client is treated as part of an
136
        // elected set of clients that have an external election process that assigns
137
        // a uint128 election ID.
138
        ElectedPrimaryClient
139
)
140

141
// WithRedundancyMode specifies the redundancy mode that is to be used by the client
142
// from the enumerated types specified in the RedundancyMode.
143
func (g *gRIBIConnection) WithRedundancyMode(m RedundancyMode) *gRIBIConnection {
1✔
144
        g.redundMode = m
1✔
145
        return g
1✔
146
}
1✔
147

148
// WithInitialElectionID specifies the election ID that is to be used to start the
149
// connection. It is not sent until a Modify RPC has been opened to the client. The
150
// arguments specify the high and low 64-bit integers that from the uint128.
151
func (g *gRIBIConnection) WithInitialElectionID(low, high uint64) *gRIBIConnection {
1✔
152
        eid := &spb.Uint128{
1✔
153
                Low:  low,
1✔
154
                High: high,
1✔
155
        }
1✔
156
        g.electionID = eid
1✔
157
        // also set the current election ID for subsequent operations.
1✔
158
        g.parent.currentElectionID = eid
1✔
159
        return g
1✔
160
}
1✔
161

162
// Start connects the gRIBI client to the target using the specified context as
163
// the connection parameters. The dial to the target is blocking, so Start() will
164
// not return until a connection is successfully made. Any error in parsing the
165
// specified arguments required for connections is raised using the supplied
166
// testing.TB.
167
func (g *GRIBIClient) Start(ctx context.Context, t testing.TB) {
1✔
168
        t.Helper()
1✔
169
        if c := g.connection; c.targetAddr == "" && c.stub == nil {
1✔
170
                t.Fatalf("cannot dial without specifying target address or stub")
×
171
        }
×
172

173
        opts := []client.Opt{}
1✔
174
        switch g.connection.redundMode {
1✔
175
        case AllPrimaryClients:
1✔
176
                opts = append(opts, client.AllPrimaryClients())
1✔
177
        case ElectedPrimaryClient:
1✔
178
                if g.connection.electionID == nil {
1✔
179
                        t.Fatalf("client must specify Election ID in elected primary mode")
×
180
                }
×
181
                opts = append(opts, client.ElectedPrimaryClient(g.connection.electionID))
1✔
182
        }
183

184
        if g.connection.persist {
2✔
185
                opts = append(opts, client.PersistEntries())
1✔
186
        }
1✔
187

188
        if g.connection.fibACK {
1✔
189
                opts = append(opts, client.FIBACK())
×
190
        }
×
191

192
        log.V(2).Infof("setting client parameters to %+v", opts)
1✔
193
        c, err := client.New(opts...)
1✔
194
        if err != nil {
1✔
195
                t.Fatalf("cannot create new client, %v", err)
×
196
        }
×
197
        g.c = c
1✔
198

1✔
199
        if g.connection.stub != nil {
1✔
200
                log.V(2).Infof("using stub %#v", g.connection.stub)
×
201
                c.UseStub(g.connection.stub)
×
202
        } else {
1✔
203
                log.V(2).Infof("dialing %s", g.connection.targetAddr)
1✔
204
                if err := c.Dial(ctx, g.connection.targetAddr); err != nil {
2✔
205
                        t.Fatalf("cannot dial target, %v", err)
1✔
206
                }
1✔
207
        }
208

209
        g.ctx = ctx
1✔
210
}
211

212
// Stop specifies that the gRIBI client should stop sending operations,
213
// and subsequently disconnect from the server.
214
func (g *GRIBIClient) Stop(t testing.TB) {
1✔
215
        if g.c != nil {
2✔
216
                g.c.StopSending()
1✔
217
                if err := g.c.Close(); err != nil {
1✔
218
                        log.Infof("cannot disconnect from server, %v", err)
×
219
                }
×
220
        }
221
}
222

223
// StartSending specifies that the Modify stream to the target should be made, and
224
// the client should start to send any queued messages to the target. Any error
225
// encountered is reported using the supplied testing.TB.
226
func (g *GRIBIClient) StartSending(ctx context.Context, t testing.TB) {
1✔
227
        t.Helper()
1✔
228
        if err := g.c.Connect(ctx); err != nil {
1✔
229
                t.Fatalf("cannot connect Modify request, %v", err)
×
230
        }
×
231
        g.c.StartSending()
1✔
232
}
233

234
// Await waits until the underlying gRIBI client has completed its work to return -
235
// complete is defined as both the send and pending queue being empty, or an error
236
// being hit by the client. It returns an error in the case that there were errors
237
// reported.
238
func (g *GRIBIClient) Await(ctx context.Context, t testing.TB) error {
1✔
239
        if err := g.c.AwaitConverged(ctx); err != nil {
2✔
240
                return err
1✔
241
        }
1✔
242
        return nil
1✔
243
}
244

245
// Results returns the transaction results from the client. If the client is not converged
246
// it will return a partial set of results from transactions that have completed, otherwise
247
// it will return the complete set of results received from the server.
248
func (g *GRIBIClient) Results(t testing.TB) []*client.OpResult {
×
249
        r, err := g.c.Results()
×
250
        if err != nil {
×
251
                t.Fatalf("did not get valid results, %v", err)
×
252
        }
×
253
        return r
×
254
}
255

256
// Status returns the status of the client. It can be used to check whether there pending
257
// operations or whether errors have occurred in the client.
258
func (g *GRIBIClient) Status(t testing.TB) *client.ClientStatus {
1✔
259
        s, err := g.c.Status()
1✔
260
        if err != nil {
1✔
261
                t.Fatalf("did not get valid status, %v", err)
×
262
        }
×
263
        return s
1✔
264
}
265

266
// gRIBIGet is a container for arguments to the Get RPC.
267
type gRIBIGet struct {
268
        // parent is a reference to the parent client.
269
        parent *GRIBIClient
270
        // pb is the GetRequest protobuf.
271
        pb *spb.GetRequest
272
}
273

274
// Get is a wrapper for the gRIBI Get RPC which is used to retrieve the current
275
// entries that are in the active gRIBI RIB. Get returns only entries that have
276
// been succesfully installed according to the request's ACK type. It can be filtered
277
// according to network instance and AFT.
278
func (g *GRIBIClient) Get() *gRIBIGet {
×
279
        return &gRIBIGet{
×
280
                parent: g,
×
281
                pb:     &spb.GetRequest{},
×
282
        }
×
283
}
×
284

285
// AllNetworkInstance requests entries from all network instances.
286
func (g *gRIBIGet) AllNetworkInstances() *gRIBIGet {
×
287
        g.pb.NetworkInstance = &spb.GetRequest_All{
×
288
                All: &spb.Empty{},
×
289
        }
×
290
        return g
×
291
}
×
292

293
// WithNetworkInstance requests the specific network instance, ni, with the Get
294
// request.
295
func (g *gRIBIGet) WithNetworkInstance(ni string) *gRIBIGet {
×
296
        g.pb.NetworkInstance = &spb.GetRequest_Name{
×
297
                Name: ni,
×
298
        }
×
299
        return g
×
300
}
×
301

302
// AFT is an enumerated type describing the AFTs available within gRIBI.
303
type AFT int64
304

305
const (
306
        _ AFT = iota
307
        AllAFTs
308
        // IPv4 references the IPv4Entry AFT.
309
        IPv4
310
        // NextHopGroup references the NextHopGroupEntry AFT.
311
        NextHopGroup
312
        // NextHop references the NextHop AFT.
313
        NextHop
314
        // IPv6 references the IPv6Entry AFT.
315
        IPv6
316
)
317

318
// aftMap provides mapping between the AFT enumerated type within the fluent
319
// package and that within the gRIBI protobuf.
320
var aftMap = map[AFT]spb.AFTType{
321
        AllAFTs:      spb.AFTType_ALL,
322
        IPv4:         spb.AFTType_IPV4,
323
        NextHopGroup: spb.AFTType_NEXTHOP_GROUP,
324
        NextHop:      spb.AFTType_NEXTHOP,
325
        IPv6:         spb.AFTType_IPV6,
326
}
327

328
// WithAFT specifies the AFT for which the Get request is made. The AllAFTs
329
// value can be used to retrieve all AFTs.
330
func (g *gRIBIGet) WithAFT(a AFT) *gRIBIGet {
×
331
        g.pb.Aft = aftMap[a]
×
332
        return g
×
333
}
×
334

335
// Send issues Get RPC to the target and returns the results.
336
func (g *gRIBIGet) Send() (*spb.GetResponse, error) {
×
337
        return g.parent.c.Get(g.parent.ctx, g.pb)
×
338
}
×
339

340
// gRIBIFlush is a container for arguments to the Flush RPC.
341
type gRIBIFlush struct {
342
        // parent is a reference to the parent client.
343
        parent *GRIBIClient
344
        // pb is the FlushRequest protobuf.
345
        pb *spb.FlushRequest
346
}
347

348
// Flush is a wrapper for the gRIBI Flush RPC which is used to remove the current
349
// entries from the active gRIBI RIB. Flush operations can be restricted based on
350
// a single network-instnace, or applied to all NIs on the server. Where the server
351
// is in SINGLE_PRIMARY mode Flush can either consider the current ID, or override
352
// it.
353
func (g *GRIBIClient) Flush() *gRIBIFlush {
×
354
        return &gRIBIFlush{
×
355
                parent: g,
×
356
                pb:     &spb.FlushRequest{},
×
357
        }
×
358
}
×
359

360
// WithElectionID sets the election ID that is sent to the server to a specific
361
// value specified by the low and high arguments, which make up the lower and upper
362
// 64 bits respectively of the uint128 election ID.
363
func (g *gRIBIFlush) WithElectionID(low, high uint64) *gRIBIFlush {
×
364
        g.pb.Election = &spb.FlushRequest_Id{
×
365
                Id: &spb.Uint128{
×
366
                        Low:  low,
×
367
                        High: high,
×
368
                },
×
369
        }
×
370
        return g
×
371
}
×
372

373
// WithElectionOverride specifies that the client should override the election
374
// status on the gRIBI server when calling the Flush operation.
375
func (g *gRIBIFlush) WithElectionOverride() *gRIBIFlush {
×
376
        g.pb.Election = &spb.FlushRequest_Override{
×
377
                Override: &spb.Empty{},
×
378
        }
×
379
        return g
×
380
}
×
381

382
// WithNetworkInstance specifies that the Flush should be performed on the specific
383
// named network instance.
384
func (g *gRIBIFlush) WithNetworkInstance(n string) *gRIBIFlush {
×
385
        g.pb.NetworkInstance = &spb.FlushRequest_Name{
×
386
                Name: n,
×
387
        }
×
388
        return g
×
389
}
×
390

391
// WithAllNetworkInstances specifies that the Flush should be applied to all of
392
// the network instances on the server.
393
func (g *gRIBIFlush) WithAllNetworkInstances() *gRIBIFlush {
×
394
        g.pb.NetworkInstance = &spb.FlushRequest_All{
×
395
                All: &spb.Empty{},
×
396
        }
×
397
        return g
×
398
}
×
399

400
// Send sends the flush operation to the device.
401
func (g *gRIBIFlush) Send() (*spb.FlushResponse, error) {
×
402
        return g.parent.c.Flush(g.parent.ctx, g.pb)
×
403
}
×
404

405
// Modify wraps methods that trigger operations within the gRIBI Modify RPC.
406
func (g *GRIBIClient) Modify() *gRIBIModify {
1✔
407
        return &gRIBIModify{parent: g}
1✔
408
}
1✔
409

410
// gRIBIModify provides a wrapper for methods associated with the gRIBI Modify RPC.
411
type gRIBIModify struct {
412
        // parent is a pointer to the parent of the gRIBI modify.
413
        parent *GRIBIClient
414
}
415

416
// InjectRequest injects a gRIBI ModifyRequest that is created by an external
417
// entity into the modify stream. No validation of the input message is performed.
418
// It is intended to allow for invalid messages that the fluent library does not
419
// allow the creation of to be sent to a server.
420
func (g *gRIBIModify) InjectRequest(t testing.TB, m *spb.ModifyRequest) *gRIBIModify {
×
421
        g.parent.c.Q(m)
×
422
        return g
×
423
}
×
424

425
// AddEntry creates an operation adding the set of entries specified to the server.
426
func (g *gRIBIModify) AddEntry(t testing.TB, entries ...GRIBIEntry) *gRIBIModify {
1✔
427
        m, err := g.entriesToModifyRequest(spb.AFTOperation_ADD, entries)
1✔
428
        if err != nil {
1✔
429
                t.Fatalf("cannot build modify request: %v", err)
×
430
        }
×
431
        g.parent.c.Q(m)
1✔
432
        return g
1✔
433
}
434

435
// DeleteEntry creates an operation deleting the set of entries specified from the server.
436
func (g *gRIBIModify) DeleteEntry(t testing.TB, entries ...GRIBIEntry) *gRIBIModify {
1✔
437
        m, err := g.entriesToModifyRequest(spb.AFTOperation_DELETE, entries)
1✔
438
        if err != nil {
1✔
439
                t.Fatalf("cannot build modify request, %v", err)
×
440
        }
×
441
        g.parent.c.Q(m)
1✔
442
        return g
1✔
443
}
444

445
// ReplaceEntry creates an operation replacing the set of entries specified on the server.
446
func (g *gRIBIModify) ReplaceEntry(t testing.TB, entries ...GRIBIEntry) *gRIBIModify {
×
447
        m, err := g.entriesToModifyRequest(spb.AFTOperation_REPLACE, entries)
×
448
        if err != nil {
×
449
                t.Fatalf("cannot build modify request, %v", err)
×
450
        }
×
451
        g.parent.c.Q(m)
×
452
        return g
×
453
}
454

455
// Enqueue adds the pre-formed set of ModifyRequests to the queue that are to be
456
// sent by the client. The entries are not validated or modified.
457
func (g *gRIBIModify) Enqueue(t testing.TB, entries ...*spb.ModifyRequest) *gRIBIModify {
×
458
        for _, m := range entries {
×
459
                g.parent.c.Q(m)
×
460
        }
×
461
        return g
×
462
}
463

464
// UpdateElectionID updates the election ID on the gRIBI Modify channel using value provided.
465
// The election ID is a uint128 made up of concatenating the low and high uint64 values provided.
466
func (g *gRIBIModify) UpdateElectionID(t testing.TB, low, high uint64) *gRIBIModify {
×
467
        eid := &spb.Uint128{
×
468
                Low:  low,
×
469
                High: high,
×
470
        }
×
471
        g.parent.currentElectionID = eid
×
472
        g.parent.c.Q(&spb.ModifyRequest{ElectionId: eid})
×
473
        return g
×
474
}
×
475

476
// entriesToModifyRequest creates a ModifyRequest from a set of input entries.
477
func (g *gRIBIModify) entriesToModifyRequest(op spb.AFTOperation_Operation, entries []GRIBIEntry) (*spb.ModifyRequest, error) {
1✔
478
        m := &spb.ModifyRequest{}
1✔
479
        for _, e := range entries {
2✔
480
                ep, err := e.OpProto()
1✔
481
                if err != nil {
1✔
482
                        return nil, fmt.Errorf("cannot build entry protobuf, got err: %v", err)
×
483
                }
×
484
                ep.Op = op
1✔
485

1✔
486
                // ID was unset, so use the library maintained count. Note, that clients
1✔
487
                // should not use both explictly and manually specified IDs. To this end
1✔
488
                // initially we do not allow this API to be used for anything other than
1✔
489
                // automatically set values.
1✔
490
                if ep.Id != 0 {
1✔
491
                        return nil, fmt.Errorf("cannot use explicitly set operation IDs for a message, got: %d, want: 0", ep.Id)
×
492
                }
×
493

494
                if g.parent == nil {
1✔
495
                        return nil, errors.New("invalid nil parent")
×
496
                }
×
497
                // increment before first use of the opCount so that we start at 1.
498
                g.parent.opCount++
1✔
499
                ep.Id = g.parent.opCount
1✔
500

1✔
501
                // If the election ID wasn't explicitly set then write the current one
1✔
502
                // to the message if this is a client that requires it.
1✔
503
                if g.parent.connection != nil && g.parent.connection.redundMode == ElectedPrimaryClient && ep.ElectionId == nil {
2✔
504
                        ep.ElectionId = g.parent.currentElectionID
1✔
505
                }
1✔
506

507
                m.Operation = append(m.Operation, ep)
1✔
508
        }
509
        return m, nil
1✔
510
}
511

512
// GRIBIEntry is an entry implemented for all types that can be returned
513
// as a gRIBI entry.
514
type GRIBIEntry interface {
515
        // OpProto builds the entry as a new AFTOperation protobuf.
516
        OpProto() (*spb.AFTOperation, error)
517
        // EntryProto builds the entry as a new AFTEntry protobuf.
518
        EntryProto() (*spb.AFTEntry, error)
519
}
520

521
// ipv4Entry is the internal representation of a gRIBI IPv4Entry.
522
type ipv4Entry struct {
523
        // pb is the gRIBI IPv4Entry that is being composed.
524
        pb *aftpb.Afts_Ipv4EntryKey
525
        // ni is the network instance to which the IPv4Entry is applied.
526
        ni string
527
        // electionID is an explicit election ID to be used for an
528
        // operation using the entry.
529
        electionID *spb.Uint128
530
}
531

532
// IPv4Entry returns a new gRIBI IPv4Entry builder.
533
func IPv4Entry() *ipv4Entry {
1✔
534
        return &ipv4Entry{
1✔
535
                pb: &aftpb.Afts_Ipv4EntryKey{
1✔
536
                        Ipv4Entry: &aftpb.Afts_Ipv4Entry{},
1✔
537
                },
1✔
538
        }
1✔
539
}
1✔
540

541
// WithPrefix sets the prefix of the IPv4Entry to the specified value, which
542
// must be a valid IPv4 prefix in the form prefix/mask.
543
func (i *ipv4Entry) WithPrefix(p string) *ipv4Entry {
1✔
544
        i.pb.Prefix = p
1✔
545
        return i
1✔
546
}
1✔
547

548
// WithNetworkInstance specifies the network instance to which the IPv4Entry
549
// is being applied.
550
func (i *ipv4Entry) WithNetworkInstance(n string) *ipv4Entry {
1✔
551
        i.ni = n
1✔
552
        return i
1✔
553
}
1✔
554

555
// WithNextHopGroup specifies the next-hop group that the IPv4Entry points to.
556
func (i *ipv4Entry) WithNextHopGroup(u uint64) *ipv4Entry {
1✔
557
        i.pb.Ipv4Entry.NextHopGroup = &wpb.UintValue{Value: u}
1✔
558
        return i
1✔
559
}
1✔
560

561
// WithNextHopGroupNetworkInstance specifies the network-instance within which
562
// the next-hop-group for the IPv4 entry should be resolved.
563
func (i *ipv4Entry) WithNextHopGroupNetworkInstance(n string) *ipv4Entry {
×
564
        i.pb.Ipv4Entry.NextHopGroupNetworkInstance = &wpb.StringValue{Value: n}
×
565
        return i
×
566
}
×
567

568
// WithMetadata specifies a byte slice that is stored as metadata alongside
569
// the entry on the gRIBI server.
570
func (i *ipv4Entry) WithMetadata(b []byte) *ipv4Entry {
×
571
        i.pb.Ipv4Entry.EntryMetadata = &wpb.BytesValue{Value: b}
×
572
        return i
×
573
}
×
574

575
// WithElectionID specifies an explicit election ID to be used for the Entry.
576
// The election ID is made up of the concatenation of the low and high uint64
577
// values provided.
578
func (i *ipv4Entry) WithElectionID(low, high uint64) *ipv4Entry {
×
579
        i.electionID = &spb.Uint128{
×
580
                Low:  low,
×
581
                High: high,
×
582
        }
×
583
        return i
×
584
}
×
585

586
// OpProto implements the gRIBIEntry interface, returning a gRIBI AFTOperation. ID
587
// is explicitly not populated such that they can be populated by
588
// the function (e.g., AddEntry) to which they are an argument.
589
func (i *ipv4Entry) OpProto() (*spb.AFTOperation, error) {
1✔
590
        return &spb.AFTOperation{
1✔
591
                NetworkInstance: i.ni,
1✔
592
                Entry: &spb.AFTOperation_Ipv4{
1✔
593
                        Ipv4: proto.Clone(i.pb).(*aftpb.Afts_Ipv4EntryKey),
1✔
594
                },
1✔
595
                ElectionId: i.electionID,
1✔
596
        }, nil
1✔
597
}
1✔
598

599
// EntryProto implements the GRIBIEntry interface, building a gRIBI AFTEntry.
600
func (i *ipv4Entry) EntryProto() (*spb.AFTEntry, error) {
1✔
601
        return &spb.AFTEntry{
1✔
602
                NetworkInstance: i.ni,
1✔
603
                Entry: &spb.AFTEntry_Ipv4{
1✔
604
                        Ipv4: proto.Clone(i.pb).(*aftpb.Afts_Ipv4EntryKey),
1✔
605
                },
1✔
606
        }, nil
1✔
607
}
1✔
608

609
// ipv6Entry is the internal representation of a gRIBI IPv6Entry.
610
type ipv6Entry struct {
611
        // pb is the gRIBI IPv4Entry that is being composed.
612
        pb *aftpb.Afts_Ipv6EntryKey
613
        // ni is the network instance to which the IPv4Entry is applied.
614
        ni string
615
        // electionID is an explicit election ID to be used for an
616
        // operation using the entry.
617
        electionID *spb.Uint128
618
}
619

620
// IPv6Entry returns a new gRIBI IPv6Entry builder.
621
func IPv6Entry() *ipv6Entry {
1✔
622
        return &ipv6Entry{
1✔
623
                pb: &aftpb.Afts_Ipv6EntryKey{
1✔
624
                        Ipv6Entry: &aftpb.Afts_Ipv6Entry{},
1✔
625
                },
1✔
626
        }
1✔
627
}
1✔
628

629
// WithPrefix sets the prefix of the IPv6Entry to the specified value, which
630
// must be a valid IPv6 prefix in the form prefix/mask.
631
func (i *ipv6Entry) WithPrefix(p string) *ipv6Entry {
1✔
632
        i.pb.Prefix = p
1✔
633
        return i
1✔
634
}
1✔
635

636
// WithNetworkInstance specifies the network instance to which the IPv6Entry
637
// is being applied.
638
func (i *ipv6Entry) WithNetworkInstance(n string) *ipv6Entry {
1✔
639
        i.ni = n
1✔
640
        return i
1✔
641
}
1✔
642

643
// WithNextHopGroup specifies the next-hop group that the IPv6Entry points to.
644
func (i *ipv6Entry) WithNextHopGroup(u uint64) *ipv6Entry {
1✔
645
        i.pb.Ipv6Entry.NextHopGroup = &wpb.UintValue{Value: u}
1✔
646
        return i
1✔
647
}
1✔
648

649
// WithNextHopGroupNetworkInstance specifies the network-instance within which
650
// the next-hop-group for the IPv6 entry should be resolved.
651
func (i *ipv6Entry) WithNextHopGroupNetworkInstance(n string) *ipv6Entry {
1✔
652
        i.pb.Ipv6Entry.NextHopGroupNetworkInstance = &wpb.StringValue{Value: n}
1✔
653
        return i
1✔
654
}
1✔
655

656
// WithMetadata specifies a byte slice that is stored as metadata alongside
657
// the IPV6 entry on the gRIBI server.
658
func (i *ipv6Entry) WithMetadata(b []byte) *ipv6Entry {
1✔
659
        i.pb.Ipv6Entry.EntryMetadata = &wpb.BytesValue{Value: b}
1✔
660
        return i
1✔
661
}
1✔
662

663
// WithElectionID specifies an explicit election ID to be used for the Entry.
664
// The election ID is made up of the concatenation of the low and high uint64
665
// values provided.
666
func (i *ipv6Entry) WithElectionID(low, high uint64) *ipv6Entry {
×
667
        i.electionID = &spb.Uint128{
×
668
                Low:  low,
×
669
                High: high,
×
670
        }
×
671
        return i
×
672
}
×
673

674
// OpProto implements the gRIBIEntry interface, returning a gRIBI AFTOperation. ID
675
// is explicitly not populated such that they can be populated by
676
// the function (e.g., AddEntry) to which they are an argument.
677
func (i *ipv6Entry) OpProto() (*spb.AFTOperation, error) {
1✔
678
        return &spb.AFTOperation{
1✔
679
                NetworkInstance: i.ni,
1✔
680
                Entry: &spb.AFTOperation_Ipv6{
1✔
681
                        Ipv6: proto.Clone(i.pb).(*aftpb.Afts_Ipv6EntryKey),
1✔
682
                },
1✔
683
                ElectionId: i.electionID,
1✔
684
        }, nil
1✔
685
}
1✔
686

687
// EntryProto implements the GRIBIEntry interface, building a gRIBI AFTEntry.
688
func (i *ipv6Entry) EntryProto() (*spb.AFTEntry, error) {
1✔
689
        return &spb.AFTEntry{
1✔
690
                NetworkInstance: i.ni,
1✔
691
                Entry: &spb.AFTEntry_Ipv6{
1✔
692
                        Ipv6: proto.Clone(i.pb).(*aftpb.Afts_Ipv6EntryKey),
1✔
693
                },
1✔
694
        }, nil
1✔
695
}
1✔
696

697
// labelEntry is the internal representation of a MPLS label entry in gRIBI.
698
type labelEntry struct {
699
        // ni is the network instance that the MPLS label entry is within.
700
        ni string
701
        // pb is the AFT protobuf representing the label entry.
702
        pb *aftpb.Afts_LabelEntryKey
703

704
        // electionID is the explicit electionID to be used when the MPLS
705
        // entry is programmed.
706
        electionID *spb.Uint128
707
}
708

709
// LabelEntry returns a builder that can be used to define a MPLS label entry in
710
// the gRIBI AFT schema.
711
func LabelEntry() *labelEntry {
1✔
712
        return &labelEntry{
1✔
713
                pb: &aftpb.Afts_LabelEntryKey{
1✔
714
                        LabelEntry: &aftpb.Afts_LabelEntry{},
1✔
715
                },
1✔
716
        }
1✔
717
}
1✔
718

719
// EntryProto implements the GRIBIEntry interface, to represent the label entry
720
// as an AFTEntry.
721
func (l *labelEntry) EntryProto() (*spb.AFTEntry, error) {
1✔
722
        return &spb.AFTEntry{
1✔
723
                NetworkInstance: l.ni,
1✔
724
                Entry: &spb.AFTEntry_Mpls{
1✔
725
                        Mpls: proto.Clone(l.pb).(*aftpb.Afts_LabelEntryKey),
1✔
726
                },
1✔
727
        }, nil
1✔
728
}
1✔
729

730
// OpProto implements the GRIBIEntry interface, returning a gRIBI AFTOperation. The
731
// ID is explicitly not populated so it can be set by the caller.
732
func (l *labelEntry) OpProto() (*spb.AFTOperation, error) {
1✔
733
        return &spb.AFTOperation{
1✔
734
                NetworkInstance: l.ni,
1✔
735
                Entry: &spb.AFTOperation_Mpls{
1✔
736
                        Mpls: proto.Clone(l.pb).(*aftpb.Afts_LabelEntryKey),
1✔
737
                },
1✔
738
                ElectionId: l.electionID,
1✔
739
        }, nil
1✔
740
}
1✔
741

742
// WithLabel modifies the supplied label entry to include the label that it matches.
743
func (l *labelEntry) WithLabel(v uint32) *labelEntry {
1✔
744
        l.pb.Label = &aftpb.Afts_LabelEntryKey_LabelUint64{LabelUint64: uint64(v)}
1✔
745
        return l
1✔
746
}
1✔
747

748
// WithNetworkInstance specifies the network instance within which the label entry
749
// is to be installed.
750
func (l *labelEntry) WithNetworkInstance(ni string) *labelEntry {
1✔
751
        l.ni = ni
1✔
752
        return l
1✔
753
}
1✔
754

755
// WithNextHopGroup specifies the next-hop group that should be used by the label
756
// entry.
757
func (l *labelEntry) WithNextHopGroup(id uint64) *labelEntry {
1✔
758
        l.pb.LabelEntry.NextHopGroup = &wpb.UintValue{Value: id}
1✔
759
        return l
1✔
760
}
1✔
761

762
// WithNextHopGroupNetworkInstance specifies the network instance within which the
763
// label entry's NHG should be resolved.
764
func (l *labelEntry) WithNextHopGroupNetworkInstance(ni string) *labelEntry {
1✔
765
        l.pb.LabelEntry.NextHopGroupNetworkInstance = &wpb.StringValue{Value: ni}
1✔
766
        return l
1✔
767
}
1✔
768

769
// WithPoppedLabelStack specifies the labels that should be popped from the
770
// label entry. The labels are specified from the outer-most (top) label to the
771
// inner-most (bottom-of-stack).
772
func (l *labelEntry) WithPoppedLabelStack(labels ...uint32) *labelEntry {
1✔
773
        l.pb.LabelEntry.PoppedMplsLabelStack = []*aftpb.Afts_LabelEntry_PoppedMplsLabelStackUnion{}
1✔
774
        for _, v := range labels {
2✔
775
                lbl := &aftpb.Afts_LabelEntry_PoppedMplsLabelStackUnion{
1✔
776
                        PoppedMplsLabelStackUint64: uint64(v),
1✔
777
                }
1✔
778
                l.pb.LabelEntry.PoppedMplsLabelStack = append(l.pb.LabelEntry.PoppedMplsLabelStack, lbl)
1✔
779
        }
1✔
780
        return l
1✔
781
}
782

783
// nextHopEntry is the internal representation of a next-hop Entry in gRIBI.
784
type nextHopEntry struct {
785
        // ni is the network instance that the next-hop entry is within.
786
        ni string
787
        // pb is the AFT protobuf representing the next-hop entry.
788
        pb *aftpb.Afts_NextHopKey
789

790
        // electionID is an explicit electionID to be used when the next-hop entry
791
        // is programmed.
792
        electionID *spb.Uint128
793
}
794

795
// NextHopEntry returns a builder that can be used to build up a NextHop within
796
// gRIBI.
797
func NextHopEntry() *nextHopEntry {
1✔
798
        return &nextHopEntry{
1✔
799
                pb: &aftpb.Afts_NextHopKey{},
1✔
800
        }
1✔
801
}
1✔
802

803
// WithIndex specifies the index of the next-hop entry.
804
func (n *nextHopEntry) WithIndex(i uint64) *nextHopEntry {
1✔
805
        n.pb.Index = i
1✔
806
        return n
1✔
807
}
1✔
808

809
// WithNetworkInstance specifies the network instance within which the next-hop
810
// is being created.
811
func (n *nextHopEntry) WithNetworkInstance(ni string) *nextHopEntry {
1✔
812
        n.ni = ni
1✔
813
        return n
1✔
814
}
1✔
815

816
// WithIPAddress specifies an IP address to be used for the next-hop. The IP
817
// address is resolved within the network instance specified by WithNextHopNetworkInstance.
818
func (n *nextHopEntry) WithIPAddress(addr string) *nextHopEntry {
1✔
819
        if n.pb.NextHop == nil {
2✔
820
                n.pb.NextHop = &aftpb.Afts_NextHop{}
1✔
821
        }
1✔
822
        n.pb.NextHop.IpAddress = &wpb.StringValue{Value: addr}
1✔
823
        return n
1✔
824
}
825

826
// WithInterfaceRef specifies an interface to be used for the next-hop.
827
func (n *nextHopEntry) WithInterfaceRef(name string) *nextHopEntry {
1✔
828
        if n.pb.NextHop == nil {
2✔
829
                n.pb.NextHop = &aftpb.Afts_NextHop{}
1✔
830
        }
1✔
831
        n.pb.NextHop.InterfaceRef = &aftpb.Afts_NextHop_InterfaceRef{
1✔
832
                Interface: &wpb.StringValue{Value: name},
1✔
833
        }
1✔
834
        return n
1✔
835
}
836

837
// WithSubinterfaceRef specifies both an interface and a specific
838
// subinterface to be used for the next-hop.
839
func (n *nextHopEntry) WithSubinterfaceRef(name string, subinterface uint64) *nextHopEntry {
1✔
840
        if n.pb.NextHop == nil {
1✔
NEW
841
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
842
        }
×
843
        n.pb.NextHop.InterfaceRef = &aftpb.Afts_NextHop_InterfaceRef{
1✔
844
                Interface:    &wpb.StringValue{Value: name},
1✔
845
                Subinterface: &wpb.UintValue{Value: subinterface},
1✔
846
        }
1✔
847
        return n
1✔
848
}
849

850
// WithMacAddress specifies a MAC address to be used for the next-hop.
851
func (n *nextHopEntry) WithMacAddress(mac string) *nextHopEntry {
1✔
852
        if n.pb.NextHop == nil {
1✔
NEW
853
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
854
        }
×
855
        n.pb.NextHop.MacAddress = &wpb.StringValue{Value: mac}
1✔
856
        return n
1✔
857
}
858

859
// WithIPinIP specifies that IP-in-IP encapsulation should be used for
860
// the next-hop, and the source and destination IP addresses for the
861
// packet.
862
func (n *nextHopEntry) WithIPinIP(srcIP, dstIP string) *nextHopEntry {
1✔
863
        if n.pb.NextHop == nil {
1✔
NEW
864
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
865
        }
×
866
        n.pb.NextHop.IpInIp = &aftpb.Afts_NextHop_IpInIp{
1✔
867
                SrcIp: &wpb.StringValue{Value: srcIP},
1✔
868
                DstIp: &wpb.StringValue{Value: dstIP},
1✔
869
        }
1✔
870
        return n
1✔
871
}
872

873
// WithNextHopNetworkInstance specifies the network instance within which the next-hop
874
// should be resolved. If it is not specified, the next-hop is resolved in the network
875
// instance that the next-hop is installed in. If no other parameters are specified, the
876
// lookup uses the input packet within the specified network instance to determine the
877
// next-hop.
878
func (n *nextHopEntry) WithNextHopNetworkInstance(ni string) *nextHopEntry {
×
NEW
879
        if n.pb.NextHop == nil {
×
NEW
880
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
881
        }
×
882
        n.pb.NextHop.NetworkInstance = &wpb.StringValue{Value: ni}
×
883
        return n
×
884
}
885

886
// WithPopTopLabel specifies that the top-most MPLS label should be popped from the
887
// packet. In this case, the exact value of the label to be popped need not be
888
// specified.
889
func (n *nextHopEntry) WithPopTopLabel() *nextHopEntry {
×
NEW
890
        if n.pb.NextHop == nil {
×
NEW
891
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
892
        }
×
893
        n.pb.NextHop.PopTopLabel = &wpb.BoolValue{Value: true}
×
894
        return n
×
895
}
896

897
// WithPushedLabelStack specifies the label stack that should be pushed onto the
898
// packet as it is routed to this next-hop. The order of the labels is specified from
899
// in the inner-most to the outer-most such that the first label is the closest to the
900
// bottom of the stack.
901
func (n *nextHopEntry) WithPushedLabelStack(labels ...uint32) *nextHopEntry {
×
NEW
902
        if n.pb.NextHop == nil {
×
NEW
903
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
904
        }
×
905
        n.pb.NextHop.PushedMplsLabelStack = []*aftpb.Afts_NextHop_PushedMplsLabelStackUnion{}
×
906
        for _, v := range labels {
×
907
                lbl := &aftpb.Afts_NextHop_PushedMplsLabelStackUnion{
×
908
                        PushedMplsLabelStackUint64: uint64(v),
×
909
                }
×
910
                n.pb.NextHop.PushedMplsLabelStack = append(n.pb.NextHop.PushedMplsLabelStack, lbl)
×
911
        }
×
912
        return n
×
913

914
}
915

916
// Header represents the enumerated set of headers that a packet can be encapsulated or
917
// decapsulated from.
918
type Header int64
919

920
const (
921
        _ Header = iota
922
        // IPinIP specifies that the header to be decpsulated is an IPv4 header, and is typically
923
        // used when IP-in-IP tunnels are created.
924
        IPinIP
925
)
926

927
var (
928
        // encapMap translates between the fluent DecapsulateHeader type and the generated
929
        // protobuf name.
930
        encapMap = map[Header]enums.OpenconfigAftTypesEncapsulationHeaderType{
931
                IPinIP: enums.OpenconfigAftTypesEncapsulationHeaderType_OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4,
932
        }
933
)
934

935
// WithDecapsulateHeader specifies that the next-hop should apply an action to decapsulate
936
// the packet from the specified header, h.
937
func (n *nextHopEntry) WithDecapsulateHeader(h Header) *nextHopEntry {
1✔
938
        if n.pb.NextHop == nil {
2✔
939
                n.pb.NextHop = &aftpb.Afts_NextHop{}
1✔
940
        }
1✔
941
        n.pb.NextHop.DecapsulateHeader = encapMap[h]
1✔
942
        return n
1✔
943
}
944

945
// WithEncapsulateHeader specifies that the next-hop should apply an action to encapsulate
946
// the packet with the specified header, h.
947
func (n *nextHopEntry) WithEncapsulateHeader(h Header) *nextHopEntry {
1✔
948
        if n.pb.NextHop == nil {
1✔
NEW
949
                n.pb.NextHop = &aftpb.Afts_NextHop{}
×
NEW
950
        }
×
951
        n.pb.NextHop.EncapsulateHeader = encapMap[h]
1✔
952
        return n
1✔
953
}
954

955
// WithElectionID specifies an explicit election ID that is to be used hen the next hop
956
// is programmed in an AFTOperation. The electionID is a uint128 made up of concatenating
957
// the low and high uint64 values provided.
958
func (n *nextHopEntry) WithElectionID(low, high uint64) *nextHopEntry {
×
959
        n.electionID = &spb.Uint128{
×
960
                Low:  low,
×
961
                High: high,
×
962
        }
×
963
        return n
×
964
}
×
965

966
// TODO(robjs): add additional NextHopEntry fields.
967

968
// OpProto implements the GRIBIEntry interface, building a gRIBI AFTOperation. ID
969
// and ElectionID are explicitly not populated such that they can be populated by
970
// the function (e.g., AddEntry) to which they are an argument.
971
func (n *nextHopEntry) OpProto() (*spb.AFTOperation, error) {
1✔
972
        return &spb.AFTOperation{
1✔
973
                NetworkInstance: n.ni,
1✔
974
                Entry: &spb.AFTOperation_NextHop{
1✔
975
                        NextHop: proto.Clone(n.pb).(*aftpb.Afts_NextHopKey),
1✔
976
                },
1✔
977
                ElectionId: n.electionID,
1✔
978
        }, nil
1✔
979
}
1✔
980

981
// EntryProto implements the GRIBIEntry interface, building a gRIBI AFTEntry.
982
func (n *nextHopEntry) EntryProto() (*spb.AFTEntry, error) {
1✔
983
        return &spb.AFTEntry{
1✔
984
                NetworkInstance: n.ni,
1✔
985
                Entry: &spb.AFTEntry_NextHop{
1✔
986
                        NextHop: proto.Clone(n.pb).(*aftpb.Afts_NextHopKey),
1✔
987
                },
1✔
988
        }, nil
1✔
989
}
1✔
990

991
// nextHopGroupEntry is the internal representation of a next-hop-group Entry in gRIBI.
992
type nextHopGroupEntry struct {
993
        // ni is the network instance that the next-hop-group entry is within.
994
        ni string
995
        // pb is the AFT protobuf that describes the NextHopGroup entry.
996
        pb *aftpb.Afts_NextHopGroupKey
997

998
        // electionID is the explicit election ID to be used when this entry is used
999
        // in an AFTOperation.
1000
        electionID *spb.Uint128
1001
}
1002

1003
// NextHopGroupEntry returns a builder that can be used to build up a NextHopGroup within
1004
// gRIBI.
1005
func NextHopGroupEntry() *nextHopGroupEntry {
1✔
1006
        return &nextHopGroupEntry{
1✔
1007
                pb: &aftpb.Afts_NextHopGroupKey{
1✔
1008
                        NextHopGroup: &aftpb.Afts_NextHopGroup{},
1✔
1009
                },
1✔
1010
        }
1✔
1011
}
1✔
1012

1013
// WithID specifies the index of the next-hop entry.
1014
func (n *nextHopGroupEntry) WithID(i uint64) *nextHopGroupEntry {
1✔
1015
        n.pb.Id = i
1✔
1016
        return n
1✔
1017
}
1✔
1018

1019
// WithNetworkInstance specifies the network instance within which the next-hop-group
1020
// is being created.
1021
func (n *nextHopGroupEntry) WithNetworkInstance(ni string) *nextHopGroupEntry {
1✔
1022
        n.ni = ni
1✔
1023
        return n
1✔
1024
}
1✔
1025

1026
// WithBackupNHG specifies a backup next-hop-group that is to be used when the
1027
// next-hop-group being created is not viable.
1028
func (n *nextHopGroupEntry) WithBackupNHG(id uint64) *nextHopGroupEntry {
1✔
1029
        n.pb.NextHopGroup.BackupNextHopGroup = &wpb.UintValue{Value: id}
1✔
1030
        return n
1✔
1031
}
1✔
1032

1033
// AddNextHop adds the specified nexthop index to the NextHopGroup with the specified weight.
1034
func (n *nextHopGroupEntry) AddNextHop(index, weight uint64) *nextHopGroupEntry {
1✔
1035
        n.pb.NextHopGroup.NextHop = append(n.pb.NextHopGroup.NextHop, &aftpb.Afts_NextHopGroup_NextHopKey{
1✔
1036
                Index: index,
1✔
1037
                NextHop: &aftpb.Afts_NextHopGroup_NextHop{
1✔
1038
                        Weight: &wpb.UintValue{Value: weight},
1✔
1039
                },
1✔
1040
        })
1✔
1041
        return n
1✔
1042
}
1✔
1043

1044
// WithElectionID specifies an explicit election ID that is to be used when the next hop group
1045
// is programmed in an AFTOperation. The electionID is a uint128 made up of concatenating
1046
// the low and high uint64 values provided.
1047
func (n *nextHopGroupEntry) WithElectionID(low, high uint64) *nextHopGroupEntry {
×
1048
        n.electionID = &spb.Uint128{
×
1049
                Low:  low,
×
1050
                High: high,
×
1051
        }
×
1052
        return n
×
1053
}
×
1054

1055
// OpProto implements the GRIBIEntry interface, building a gRIBI AFTOperation. ID
1056
// and ElectionID are explicitly not populated such that they can be populated by
1057
// the function (e.g., AddEntry) to which they are an argument.
1058
func (n *nextHopGroupEntry) OpProto() (*spb.AFTOperation, error) {
1✔
1059
        return &spb.AFTOperation{
1✔
1060
                NetworkInstance: n.ni,
1✔
1061
                Entry: &spb.AFTOperation_NextHopGroup{
1✔
1062
                        NextHopGroup: proto.Clone(n.pb).(*aftpb.Afts_NextHopGroupKey),
1✔
1063
                },
1✔
1064
                ElectionId: n.electionID,
1✔
1065
        }, nil
1✔
1066
}
1✔
1067

1068
// EntryProto implements the GRIBIEntry interface, returning a gRIBI AFTEntry.
1069
func (n *nextHopGroupEntry) EntryProto() (*spb.AFTEntry, error) {
1✔
1070
        return &spb.AFTEntry{
1✔
1071
                NetworkInstance: n.ni,
1✔
1072
                Entry: &spb.AFTEntry_NextHopGroup{
1✔
1073
                        NextHopGroup: proto.Clone(n.pb).(*aftpb.Afts_NextHopGroupKey),
1✔
1074
                },
1✔
1075
        }, nil
1✔
1076
}
1✔
1077

1078
// modifyError is a type that can be used to build a gRIBI Modify error.
1079
type modifyError struct {
1080
        Reason spb.ModifyRPCErrorDetails_Reason
1081
        Code   codes.Code
1082
}
1083

1084
// ModifyError allows a gRIBI ModifyError to be constructed.
1085
func ModifyError() *modifyError {
1✔
1086
        return &modifyError{}
1✔
1087
}
1✔
1088

1089
// ModifyErrReason is a type used to express reasons for errors within the Modify RPC.
1090
type ModifyErrReason int64
1091

1092
const (
1093
        _ ModifyErrReason = iota
1094
        // Unsupported parameters indicates that the server does not support the client parameters.
1095
        UnsupportedParameters
1096
        // ModifyParamsNotAllowed indicates that the client tried to modify the parameters after they
1097
        // were set.
1098
        ModifyParamsNotAllowed
1099
        // ParamsDiffereFromOtherClients indicates that the parameters specified are inconsistent
1100
        // with other clients that are connected to the server.
1101
        ParamsDifferFromOtherClients
1102
        // ElectionIDNotAllowed indicates that a client tried to send an election ID in a context
1103
        // within which it was not allowed.
1104
        ElectionIDNotAllowed
1105
)
1106

1107
// reasonMap provides a mapping between the fluent readable modify error reason and
1108
// the defined reason in the gRIBI protobuf.
1109
var reasonMap = map[ModifyErrReason]spb.ModifyRPCErrorDetails_Reason{
1110
        UnsupportedParameters:        spb.ModifyRPCErrorDetails_UNSUPPORTED_PARAMS,
1111
        ModifyParamsNotAllowed:       spb.ModifyRPCErrorDetails_MODIFY_NOT_ALLOWED,
1112
        ParamsDifferFromOtherClients: spb.ModifyRPCErrorDetails_PARAMS_DIFFER_FROM_OTHER_CLIENTS,
1113
        ElectionIDNotAllowed:         spb.ModifyRPCErrorDetails_ELECTION_ID_IN_ALL_PRIMARY,
1114
}
1115

1116
// WithReason specifies the reason for the modify error from the enumeration
1117
// in the protobuf.
1118
func (m *modifyError) WithReason(r ModifyErrReason) *modifyError {
1✔
1119
        m.Reason = reasonMap[r]
1✔
1120
        return m
1✔
1121
}
1✔
1122

1123
// WithCode specifies the well known code that is expected in the error.
1124
func (m *modifyError) WithCode(c codes.Code) *modifyError {
1✔
1125
        m.Code = c
1✔
1126
        return m
1✔
1127
}
1✔
1128

1129
// AsStatus returns the modifyError as a status.Status.
1130
func (m *modifyError) AsStatus(t testing.TB) *status.Status {
1✔
1131
        s := status.New(m.Code, "")
1✔
1132
        var err error
1✔
1133
        s, err = s.WithDetails(&spb.ModifyRPCErrorDetails{
1✔
1134
                Reason: m.Reason,
1✔
1135
        })
1✔
1136
        if err != nil {
1✔
1137
                t.Fatalf("cannot build error, %v", err)
×
1138
        }
×
1139
        return s
1✔
1140
}
1141

1142
// opResult is an internal representation of the client
1143
// operation result that can be built up using the fluent API.
1144
type opResult struct {
1145
        r *client.OpResult
1146
}
1147

1148
// OperationResult is a response that is received from the gRIBI server.
1149
func OperationResult() *opResult {
×
1150
        return &opResult{
×
1151
                r: &client.OpResult{},
×
1152
        }
×
1153
}
×
1154

1155
// WithCurrentServerElectionID specifies a result that contains a response
1156
// that set the election ID to the uint128 value represented by low and high.
1157
func (o *opResult) WithCurrentServerElectionID(low, high uint64) *opResult {
×
1158
        o.r.CurrentServerElectionID = &spb.Uint128{Low: low, High: high}
×
1159
        return o
×
1160
}
×
1161

1162
// WithSuccessfulSessionParams specifies that the server responded to a
1163
// session parameters request with an OK response.
1164
func (o *opResult) WithSuccessfulSessionParams() *opResult {
×
1165
        o.r.SessionParameters = &spb.SessionParametersResult{
×
1166
                Status: spb.SessionParametersResult_OK,
×
1167
        }
×
1168
        return o
×
1169
}
×
1170

1171
// WithOperationID specifies the result was in response to a specific
1172
// operation ID.
1173
func (o *opResult) WithOperationID(i uint64) *opResult {
×
1174
        o.r.OperationID = i
×
1175
        return o
×
1176
}
×
1177

1178
// WithIPv4Operation indicates that the result corresponds to
1179
// an operation impacting the IPv4 prefix p which is of the form
1180
// prefix/mask.
1181
func (o *opResult) WithIPv4Operation(p string) *opResult {
×
1182
        if o.r.Details == nil {
×
1183
                o.r.Details = &client.OpDetailsResults{}
×
1184
        }
×
1185
        o.r.Details.IPv4Prefix = p
×
1186
        return o
×
1187
}
1188

1189
// WithIPv6Operation indicates that the result corresponds to
1190
// an operation impacting the IPv6 prefix p which is of the form
1191
// prefix/mask.
1192
func (o *opResult) WithIPv6Operation(p string) *opResult {
×
1193
        if o.r.Details == nil {
×
1194
                o.r.Details = &client.OpDetailsResults{}
×
1195
        }
×
1196
        o.r.Details.IPv6Prefix = p
×
1197
        return o
×
1198
}
1199

1200
// WithNextHopGroupOperation indicates that the result correspodns to
1201
// an operation impacting the next-hop-group with index i.
1202
func (o *opResult) WithNextHopGroupOperation(i uint64) *opResult {
×
1203
        if o.r.Details == nil {
×
1204
                o.r.Details = &client.OpDetailsResults{}
×
1205
        }
×
1206
        o.r.Details.NextHopGroupID = i
×
1207
        return o
×
1208
}
1209

1210
// WithNextHopOperation indicates that the result corresponds to
1211
// an operation impacting the next-hop with ID i.
1212
func (o *opResult) WithNextHopOperation(i uint64) *opResult {
×
1213
        if o.r.Details == nil {
×
1214
                o.r.Details = &client.OpDetailsResults{}
×
1215
        }
×
1216
        o.r.Details.NextHopIndex = i
×
1217
        return o
×
1218
}
1219

1220
// WithMPLSOperation indicates that the result corresponds to an
1221
// operation impacting the MPLS LabelEntry with label i.
1222
func (o *opResult) WithMPLSOperation(i uint64) *opResult {
×
1223
        if o.r.Details == nil {
×
1224
                o.r.Details = &client.OpDetailsResults{}
×
1225
        }
×
1226
        o.r.Details.MPLSLabel = i
×
1227
        return o
×
1228
}
1229

1230
// WithOperationType indicates that the result corresponds to
1231
// an operation with a specific type.
1232
func (o *opResult) WithOperationType(c constants.OpType) *opResult {
×
1233
        if o.r.Details == nil {
×
1234
                o.r.Details = &client.OpDetailsResults{}
×
1235
        }
×
1236
        o.r.Details.Type = c
×
1237
        return o
×
1238
}
1239

1240
// ProgrammingResult is a fluent-style representation of the AFTResult Status
1241
// enumeration in gRIBI.
1242
type ProgrammingResult int64
1243

1244
const (
1245
        // ProgrammingFailed indicates that the entry was not installed into the
1246
        // RIB or FIB, and cannot be.
1247
        ProgrammingFailed ProgrammingResult = iota
1248
        // InstalledInRIB indicates that the entry was installed into the RIB. It
1249
        // does not guarantee that the system is using the entry, and does not
1250
        // guarantee that it is in hardware.
1251
        InstalledInRIB
1252
        // InstalledInFIB indicates that the entry was installed into the FIB. It
1253
        // indicates that the system is using the entry and it is installed in
1254
        // hardware.
1255
        InstalledInFIB
1256
)
1257

1258
// programmingResultMap maps the fluent-style programming result to the
1259
// enumerated value in the protobuf.
1260
var programmingResultMap = map[ProgrammingResult]spb.AFTResult_Status{
1261
        ProgrammingFailed: spb.AFTResult_FAILED,
1262
        InstalledInRIB:    spb.AFTResult_RIB_PROGRAMMED,
1263
        InstalledInFIB:    spb.AFTResult_FIB_PROGRAMMED,
1264
}
1265

1266
// WithProgrammingResult specifies an expected programming result for
1267
// the operation result.
1268
func (o *opResult) WithProgrammingResult(r ProgrammingResult) *opResult {
×
1269
        o.r.ProgrammingResult = programmingResultMap[r]
×
1270
        return o
×
1271
}
×
1272

1273
// AsResult returns the operation result as a client OpResult for comparison.
1274
func (o *opResult) AsResult() *client.OpResult {
×
1275
        return o.r
×
1276
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc