Skip to content

Commit

Permalink
Add support for MPLS reconciliation. (#201)
Browse files Browse the repository at this point in the history
* Add support for MPLS reconciliation.

  * (M) rib/helpers.go
  * (M) rib/helpers_test.go
    - Add fake RIB helper methods for MPLS.
  * (M) rib/reconciler/reconcile.go
  * (M) rib/reconciler/reconcile_test.go
    - Add support for reconciliation of label entries.

* Add support for `ALL` address families in explicitReplace.

  * (M) rib/reconciler/reconcile.go
  * (M) rib/reconciler/reconcile_test.go
    - Ensure that the `ALL` `AFTType` is mapped to the correct address
       families when reconciling.
  • Loading branch information
robshakir committed Oct 24, 2023
1 parent 8b06205 commit e6f4419
Show file tree
Hide file tree
Showing 4 changed files with 421 additions and 4 deletions.
31 changes: 27 additions & 4 deletions rib/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,17 @@ func (f *fakeRIB) InjectIPv4(ni, pfx string, nhg uint64) error {
}

// InjectNHG adds a next-hop-group entry to network instance ni, with the specified
// ID (nhgId). The next-hop-group contains the next hops specified in the nhs map,
// ID (nhgID). The next-hop-group contains the next hops specified in the nhs map,
// with the key of the map being the next-hop ID and the value being the weight within
// the group.
func (f *fakeRIB) InjectNHG(ni string, nhgId uint64, nhs map[uint64]uint64) error {
func (f *fakeRIB) InjectNHG(ni string, nhgID uint64, nhs map[uint64]uint64) error {
niR, ok := f.r.NetworkInstanceRIB(ni)
if !ok {
return fmt.Errorf("unknown NI, %s", ni)
}

nhg := &aftpb.Afts_NextHopGroupKey{
Id: nhgId,
Id: nhgID,
NextHopGroup: &aftpb.Afts_NextHopGroup{},
}
for nh, weight := range nhs {
Expand All @@ -142,7 +142,8 @@ func (f *fakeRIB) InjectNHG(ni string, nhgId uint64, nhs map[uint64]uint64) erro
}

// InjectNH adds a next-hop entry to network instance ni, with the specified
// index (nhIdx). An error is returned if it cannot be added.
// index (nhIdx), and interface ref to intName. An error is returned if it cannot
// be added.
func (f *fakeRIB) InjectNH(ni string, nhIdx uint64, intName string) error {
niR, ok := f.r.NetworkInstanceRIB(ni)
if !ok {
Expand All @@ -162,3 +163,25 @@ func (f *fakeRIB) InjectNH(ni string, nhIdx uint64, intName string) error {

return nil
}

// InjectMPLS adds an MPLS (Label) entry to network instance ni, with the
// specified next-hop-group. An error is returned if it cannot be added.
func (f *fakeRIB) InjectMPLS(ni string, label, nhg uint64) error {
niR, ok := f.r.NetworkInstanceRIB(ni)
if !ok {
return fmt.Errorf("unknown NI, %s", ni)
}

if _, _, err := niR.AddMPLS(&aftpb.Afts_LabelEntryKey{
Label: &aftpb.Afts_LabelEntryKey_LabelUint64{
LabelUint64: label,
},
LabelEntry: &aftpb.Afts_LabelEntry{
NextHopGroup: &wpb.UintValue{Value: nhg},
},
}, false); err != nil {
return fmt.Errorf("cannot add MPLS entry, err: %v", err)
}

return nil
}
27 changes: 27 additions & 0 deletions rib/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,33 @@ func TestFakeRIB(t *testing.T) {
},
},
},
}, {
desc: "mpls only",
inBuild: func() *fakeRIB {
f := NewFake(dn, DisableRIBCheckFn())
if err := f.InjectMPLS(dn, 42, 1); err != nil {
t.Fatalf("cannot add MPLS, err: %v", err)
}
return f
},
wantRIB: &RIB{
defaultName: dn,
niRIB: map[string]*RIBHolder{
dn: {
name: dn,
r: &aft.RIB{
Afts: &aft.Afts{
LabelEntry: map[aft.Afts_LabelEntry_Label_Union]*aft.Afts_LabelEntry{
aft.UnionUint32(42): {
Label: aft.UnionUint32(42),
NextHopGroup: ygot.Uint64(1),
},
},
},
},
},
},
},
}, {
desc: "nhg only",
inBuild: func() *fakeRIB {
Expand Down
62 changes: 62 additions & 0 deletions rib/reconciler/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) (*reconcileOp
if src == nil || dst == nil {
return nil, fmt.Errorf("invalid nil input RIBs, src: %v, dst: %v", src, dst)
}

// Re-map ALL into the supported address families.
if _, ok := explicitReplace[spb.AFTType_ALL]; ok {
explicitReplace = map[spb.AFTType]bool{
spb.AFTType_IPV4: true,
spb.AFTType_MPLS: true,
spb.AFTType_NEXTHOP: true,
spb.AFTType_NEXTHOP_GROUP: true,
}
}

srcContents, err := src.RIBContents()
if err != nil {
return nil, fmt.Errorf("cannot copy source RIB contents, err: %v", err)
Expand Down Expand Up @@ -210,6 +221,28 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) (*reconcileOp
}
}

for lbl, srcE := range srcNIEntries.GetAfts().LabelEntry {
if dstE, ok := dstNIEntries.GetAfts().LabelEntry[lbl]; !ok || !reflect.DeepEqual(srcE, dstE) {
opType := spb.AFTOperation_ADD
if ok && explicitReplace[spb.AFTType_MPLS] {
opType = spb.AFTOperation_REPLACE
}
id++
op, err := mplsOperation(opType, srcNI, lbl, id, srcE)
if err != nil {
return nil, err
}

// If this entry already exists then this is an addition rather than a replace.
switch ok {
case true:
ops.Replace.TopLevel = append(ops.Replace.TopLevel, op)
case false:
ops.Add.TopLevel = append(ops.Add.TopLevel, op)
}
}
}

for nhgID, srcE := range srcNIEntries.GetAfts().NextHopGroup {
if dstE, ok := dstNIEntries.GetAfts().NextHopGroup[nhgID]; !ok || !reflect.DeepEqual(srcE, dstE) {
opType := spb.AFTOperation_ADD
Expand Down Expand Up @@ -266,6 +299,17 @@ func diff(src, dst *rib.RIB, explicitReplace map[spb.AFTType]bool) (*reconcileOp
}
}

for lbl, dstE := range dstNIEntries.GetAfts().LabelEntry {
if _, ok := srcNIEntries.GetAfts().LabelEntry[lbl]; !ok {
id++
op, err := mplsOperation(spb.AFTOperation_DELETE, srcNI, lbl, id, dstE)
if err != nil {
return nil, err
}
ops.Delete.TopLevel = append(ops.Delete.TopLevel, op)
}
}

for nhgID, dstE := range dstNIEntries.GetAfts().NextHopGroup {
if _, ok := srcNIEntries.GetAfts().NextHopGroup[nhgID]; !ok {
id++
Expand Down Expand Up @@ -345,3 +389,21 @@ func nhOperation(method spb.AFTOperation_Operation, ni string, nhID, id uint64,
},
}, nil
}

// mplsOperation builds a gRIBI LabelEntry operation with the specified method corresponding to
// the MPLS label entry lbl. The operation is targeted at network instance ni, and uses the specified
// ID. The contents of the operation are the entry e.
func mplsOperation(method spb.AFTOperation_Operation, ni string, lbl aft.Afts_LabelEntry_Label_Union, id uint64, e *aft.Afts_LabelEntry) (*spb.AFTOperation, error) {
p, err := rib.ConcreteMPLSProto(e)
if err != nil {
return nil, fmt.Errorf("cannot create operation for label %d, %v", lbl, err)
}
return &spb.AFTOperation{
Id: id,
NetworkInstance: ni,
Op: method,
Entry: &spb.AFTOperation_Mpls{
Mpls: p,
},
}, nil
}
Loading

0 comments on commit e6f4419

Please sign in to comment.