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

Add support for next-hop-group into reconciler. #199

Merged
merged 4 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
71 changes: 64 additions & 7 deletions rib/reconciler/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) ([]*spb.AFTOp
return nil, fmt.Errorf("cannot copy destination RIB contents, err: %v", err)
}

ops := []*spb.AFTOperation{}
// Store the "top-level" operations (i.e., IPv4, IPv6, MPLS) and then the NHG and NHs
// separately. This allows us to return the operations separately so that they can be
// ordered in terms of programming. NHs need to be installed/replaced before NHGs, and
// then subsequently top-level entries.
topLevelOps, nhgOps, nhOps := []*spb.AFTOperation{}, []*spb.AFTOperation{}, []*spb.AFTOperation{}
var id uint64
for srcNI, srcNIEntries := range srcContents {
dstNIEntries, ok := dstContents[srcNI]
Expand All @@ -152,8 +156,18 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) ([]*spb.AFTOp
if err != nil {
return nil, err
}
ops = append(ops, op)
topLevelOps = append(topLevelOps, op)
}

for nhgID, e := range srcNIEntries.GetAfts().NextHopGroup {
id++
op, err := nhgOperation(spb.AFTOperation_ADD, srcNI, nhgID, id, e)
if err != nil {
return nil, err
}
nhgOps = append(nhgOps, op)
}

continue
}
// For each AFT:
Expand All @@ -171,7 +185,22 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) ([]*spb.AFTOp
if err != nil {
return nil, err
}
ops = append(ops, op)
topLevelOps = append(topLevelOps, op)
}
}

for nhgID, srcE := range srcNIEntries.GetAfts().NextHopGroup {
if dstE, ok := dstNIEntries.GetAfts().NextHopGroup[nhgID]; !ok || !reflect.DeepEqual(srcE, dstE) {
opType := spb.AFTOperation_ADD
if ok && explicitReplace[spb.AFTType_NEXTHOP_GROUP] {
opType = spb.AFTOperation_REPLACE
}
id++
op, err := nhgOperation(opType, srcNI, nhgID, id, srcE)
if err != nil {
return nil, err
}
nhgOps = append(nhgOps, op)
}
}

Expand All @@ -182,13 +211,19 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) ([]*spb.AFTOp
if err != nil {
return nil, err
}
ops = append(ops, op)
topLevelOps = append(topLevelOps, op)
}
}

if srcN, dstN := len(srcNIEntries.GetAfts().NextHopGroup), len(dstNIEntries.GetAfts().NextHopGroup); srcN != 0 || dstN != 0 {
// TODO(robjs): Implement diffing of NHG entries.
klog.Warningf("next-hop-group reconcilation unimplemented, NHG entries, src: %d, dst: %d", srcN, dstN)
for nhgID, dstE := range dstNIEntries.GetAfts().NextHopGroup {
if _, ok := srcNIEntries.GetAfts().NextHopGroup[nhgID]; !ok {
id++
op, err := nhgOperation(spb.AFTOperation_DELETE, srcNI, nhgID, id, dstE)
if err != nil {
return nil, err
}
nhgOps = append(nhgOps, op)
}
}

if srcN, dstN := len(srcNIEntries.GetAfts().NextHop), len(dstNIEntries.GetAfts().NextHop); srcN != 0 || dstN != 0 {
Expand All @@ -197,6 +232,10 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) ([]*spb.AFTOp
}
}

ops := append([]*spb.AFTOperation{}, nhOps...)
ops = append(ops, nhgOps...)
ops = append(ops, topLevelOps...)

return ops, nil
}

Expand All @@ -217,3 +256,21 @@ func v4Operation(method spb.AFTOperation_Operation, ni, pfx string, id uint64, e
},
}, nil
}

// nhgOperation builds a gRIBI NHG operation with the specified method, corresponding to the
// NHG ID nhgID, in network instance ni, using the specified ID for the operation. The
// contents of the operation are the entry e.
func nhgOperation(method spb.AFTOperation_Operation, ni string, nhgID, id uint64, e *aft.Afts_NextHopGroup) (*spb.AFTOperation, error) {
p, err := rib.ConcreteNextHopGroupProto(e)
if err != nil {
return nil, fmt.Errorf("cannot create operation for NHG %d, %v", nhgID, err)
}
return &spb.AFTOperation{
Id: id,
NetworkInstance: ni,
Op: method,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: p,
},
}, nil
}
241 changes: 240 additions & 1 deletion rib/reconciler/reconcile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ func TestDiff(t *testing.T) {
}(),
inDst: rib.NewFake(dn).RIB(),
wantOps: []*spb.AFTOperation{{
Id: 2,
NetworkInstance: "FOO",
Op: spb.AFTOperation_ADD,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 1,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 1},
},
}},
},
},
},
}, {
Id: 1,
NetworkInstance: "FOO",
Op: spb.AFTOperation_ADD,
Expand Down Expand Up @@ -164,6 +181,23 @@ func TestDiff(t *testing.T) {
return r.RIB()
}(),
wantOps: []*spb.AFTOperation{{
Id: 2,
NetworkInstance: dn,
Op: spb.AFTOperation_ADD,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 2,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 2},
},
}},
},
},
},
}, {
Id: 1,
NetworkInstance: dn,
Op: spb.AFTOperation_ADD,
Expand Down Expand Up @@ -211,6 +245,23 @@ func TestDiff(t *testing.T) {
spb.AFTType_IPV4: true,
},
wantOps: []*spb.AFTOperation{{
Id: 2,
NetworkInstance: dn,
Op: spb.AFTOperation_ADD,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 2,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 2},
},
}},
},
},
},
}, {
Id: 1,
NetworkInstance: dn,
Op: spb.AFTOperation_REPLACE,
Expand All @@ -223,6 +274,191 @@ func TestDiff(t *testing.T) {
},
},
}},
}, {
desc: "NHG installed",
inSrc: 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 1, %v", err)
}
return r.RIB()
}(),
inDst: func() *rib.RIB {
r := rib.NewFake(dn)
if err := r.InjectNH(dn, 1); err != nil {
t.Fatalf("cannot add NH, %v", err)
}
return r.RIB()
}(),
wantOps: []*spb.AFTOperation{{
Id: 1,
NetworkInstance: dn,
Op: spb.AFTOperation_ADD,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 1,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 1},
},
}},
},
},
},
}},
}, {
desc: "NHG deleted",
inSrc: func() *rib.RIB {
r := rib.NewFake(dn)
if err := r.InjectNH(dn, 1); err != nil {
t.Fatalf("cannot add NH, %v", err)
}
return r.RIB()
}(),
inDst: 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 1, %v", err)
}
return r.RIB()
}(),
wantOps: []*spb.AFTOperation{{
Id: 1,
NetworkInstance: dn,
Op: spb.AFTOperation_DELETE,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 1,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 1},
},
}},
},
},
},
}},
}, {
desc: "NHG implicitly replaced",
inSrc: 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.InjectNH(dn, 2); err != nil {
t.Fatalf("cannot add NH, %v", err)
}
if err := r.InjectNHG(dn, 1, map[uint64]uint64{
1: 2,
2: 4,
}); err != nil {
t.Fatalf("cannot add NHG 1, %v", err)
}
return r.RIB()
}(),
inDst: 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.InjectNH(dn, 2); 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 1, %v", err)
}
return r.RIB()
}(),
wantOps: []*spb.AFTOperation{{
Id: 1,
NetworkInstance: dn,
Op: spb.AFTOperation_ADD,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 1,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 2},
},
}, {
Index: 2,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 4},
},
}},
},
},
},
}},
}, {
desc: "NHG explicitly replaced",
inSrc: 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.InjectNH(dn, 2); err != nil {
t.Fatalf("cannot add NH, %v", err)
}
if err := r.InjectNHG(dn, 1, map[uint64]uint64{
1: 2,
2: 4,
}); err != nil {
t.Fatalf("cannot add NHG 1, %v", err)
}
return r.RIB()
}(),
inDst: 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.InjectNH(dn, 2); 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 1, %v", err)
}
return r.RIB()
}(),
inExplicitReplace: map[spb.AFTType]bool{
spb.AFTType_NEXTHOP_GROUP: true,
},
wantOps: []*spb.AFTOperation{{
Id: 1,
NetworkInstance: dn,
Op: spb.AFTOperation_REPLACE,
Entry: &spb.AFTOperation_NextHopGroup{
NextHopGroup: &aftpb.Afts_NextHopGroupKey{
Id: 1,
NextHopGroup: &aftpb.Afts_NextHopGroup{
NextHop: []*aftpb.Afts_NextHopGroup_NextHopKey{{
Index: 1,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 2},
},
}, {
Index: 2,
NextHop: &aftpb.Afts_NextHopGroup_NextHop{
Weight: &wpb.UintValue{Value: 4},
},
}},
},
},
},
}},
}}

for _, tt := range tests {
Expand All @@ -231,7 +467,10 @@ func TestDiff(t *testing.T) {
if (err != nil) != tt.wantErr {
t.Fatalf("did not get expected error, got: %v, wantErr? %v", err, tt.wantErr)
}
if diff := cmp.Diff(got, tt.wantOps, protocmp.Transform()); diff != "" {
if diff := cmp.Diff(got, tt.wantOps,
protocmp.Transform(),
protocmp.SortRepeatedFields(&aftpb.Afts_NextHopGroup{}, "next_hop"),
); diff != "" {
t.Fatalf("diff(%s, %s): did not get expected operations, diff(-got,+want):\n%s", tt.inSrc, tt.inDst, diff)
}
})
Expand Down