Skip to content

Commit

Permalink
feat: IP flow hash settings support (#1610)
Browse files Browse the repository at this point in the history
* feat: IP flow hash settings support

Signed-off-by: Rastislav Szabo <raszabo@cisco.com>

* address review comment

Signed-off-by: Rastislav Szabo <raszabo@cisco.com>
  • Loading branch information
rastislavs authored and ondrej-fabry committed Jan 28, 2020
1 parent d462428 commit f4e780a
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 25 deletions.
63 changes: 56 additions & 7 deletions plugins/vpp/l3plugin/descriptor/vrf_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"math"
"strings"

"github.com/golang/protobuf/proto"
"github.com/ligato/cn-infra/idxmap"
"github.com/ligato/cn-infra/logging"
"github.com/pkg/errors"
Expand Down Expand Up @@ -70,6 +71,8 @@ func NewVrfTableDescriptor(
ValueComparator: ctx.EquivalentVrfTables,
Validate: ctx.Validate,
Create: ctx.Create,
Update: ctx.Update,
UpdateWithRecreate: ctx.UpdateWithRecreate,
Delete: ctx.Delete,
Retrieve: ctx.Retrieve,
}
Expand All @@ -78,7 +81,8 @@ func NewVrfTableDescriptor(

// EquivalentVrfTables is a comparison function for l3.VrfTable.
func (d *VrfTableDescriptor) EquivalentVrfTables(key string, oldVrfTable, newVrfTable *l3.VrfTable) bool {
if getVrfTableLabel(oldVrfTable) != getVrfTableLabel(newVrfTable) {
if getVrfTableLabel(oldVrfTable) != getVrfTableLabel(newVrfTable) ||
!proto.Equal(oldVrfTable.FlowHashSettings, newVrfTable.FlowHashSettings) {
return false
}
return true
Expand All @@ -99,14 +103,18 @@ func (d *VrfTableDescriptor) Validate(key string, vrfTable *l3.VrfTable) (err er

// Create adds VPP VRF table.
func (d *VrfTableDescriptor) Create(key string, vrfTable *l3.VrfTable) (metadata *vrfidx.VRFMetadata, err error) {
if vrfTable.Id == 0 {
// nothing to do, automatically created by VPP
}
err = d.vtHandler.AddVrfTable(vrfTable)
if err != nil {
return nil, err
}

if vrfTable.FlowHashSettings != nil {
err = d.vtHandler.SetVrfFlowHashSettings(vrfTable.Id, vrfTable.Protocol == l3.VrfTable_IPV6, vrfTable.FlowHashSettings)
if err != nil {
return nil, err
}
}

// fill the metadata
metadata = &vrfidx.VRFMetadata{
Index: vrfTable.Id,
Expand All @@ -116,11 +124,36 @@ func (d *VrfTableDescriptor) Create(key string, vrfTable *l3.VrfTable) (metadata
return metadata, nil
}

// UpdateWithRecreate returns true if a VRF update needs to be performed via re-crate.
func (d *VrfTableDescriptor) UpdateWithRecreate(_ string, oldVrfTable, newVrfTable *l3.VrfTable, _ *vrfidx.VRFMetadata) bool {
if oldVrfTable.Protocol == newVrfTable.Protocol && oldVrfTable.Id == newVrfTable.Id {
return false
}
return true // protocol or VRF ID changed = recreate
}

// Update updates VPP VRF table (ony if protocol or VRF ID has not changed).
func (d *VrfTableDescriptor) Update(_ string, oldVrfTable, newVrfTable *l3.VrfTable, _ *vrfidx.VRFMetadata) (
metadata *vrfidx.VRFMetadata, err error) {

if !proto.Equal(oldVrfTable.FlowHashSettings, newVrfTable.FlowHashSettings) {
newSettings := newVrfTable.FlowHashSettings
if newSettings == nil {
newSettings = defaultVrfFlowHashSettings()
}
err = d.vtHandler.SetVrfFlowHashSettings(newVrfTable.Id, newVrfTable.Protocol == l3.VrfTable_IPV6, newSettings)
}

// fill the metadata
metadata = &vrfidx.VRFMetadata{
Index: newVrfTable.Id,
Protocol: newVrfTable.Protocol,
}
return metadata, err
}

// Delete removes VPP VRF table.
func (d *VrfTableDescriptor) Delete(key string, vrfTable *l3.VrfTable, metadata *vrfidx.VRFMetadata) error {
if vrfTable.Id == 0 {
// nothing to do, VRF ID=0 always exists
}
err := d.vtHandler.DelVrfTable(vrfTable)
if err != nil {
return err
Expand All @@ -138,6 +171,9 @@ func (d *VrfTableDescriptor) Retrieve(correlate []adapter.VrfTableKVWithMetadata
return nil, errors.Errorf("failed to dump VPP VRF tables: %v", err)
}

// TODO: implement flow hash settings dump once supported by VPP (https://jira.fd.io/browse/VPP-1829)
// (until implemented, resync will always re-configure flow hash settings if non-default settings are used)

for _, table := range tables {
origin := kvs.UnknownOrigin
// VRF with ID=0 and ID=MaxUint32 are special
Expand Down Expand Up @@ -167,3 +203,16 @@ func getVrfTableLabel(vrfTable *l3.VrfTable) string {
}
return vrfTable.Label
}

// defaultVrfFlowHashSettings returns default flow hash settings (implicitly existing if not set).
func defaultVrfFlowHashSettings() *l3.VrfTable_FlowHashSettings {
return &l3.VrfTable_FlowHashSettings{
UseSrcIp: true,
UseDstIp: true,
UseSrcPort: true,
UseDstPort: true,
UseProtocol: true,
Symmetric: false,
Reverse: false,
}
}
2 changes: 2 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/l3_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ type VrfTableVppAPI interface {
AddVrfTable(table *l3.VrfTable) error
// DelVrfTable deletes existing VRF table.
DelVrfTable(table *l3.VrfTable) error
// SetVrfFlowHashSettings sets IP flow hash settings for a VRF table.
SetVrfFlowHashSettings(vrfID uint32, isIPv6 bool, hashFields *l3.VrfTable_FlowHashSettings) error
}

// VrfTableVppRead provides read methods for VRF tables.
Expand Down
19 changes: 19 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp1904/vrf_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,22 @@ func (h *VrfTableHandler) addDelVrfTable(table *l3.VrfTable, isAdd bool) error {

return nil
}

// SetVrfFlowHashSettings sets IP flow hash settings for a VRF table.
func (h *VrfTableHandler) SetVrfFlowHashSettings(vrfID uint32, isIPv6 bool, hashFields *l3.VrfTable_FlowHashSettings) error {
req := &ip.SetIPFlowHash{
VrfID: vrfID,
IsIPv6: boolToUint(isIPv6),
Src: boolToUint(hashFields.UseSrcIp),
Dst: boolToUint(hashFields.UseDstIp),
Sport: boolToUint(hashFields.UseSrcPort),
Dport: boolToUint(hashFields.UseDstPort),
Proto: boolToUint(hashFields.UseProtocol),
Reverse: boolToUint(hashFields.Reverse),
Symmetric: boolToUint(hashFields.Symmetric),
}
reply := &ip.SetIPFlowHashReply{}

err := h.callsChannel.SendRequest(req).ReceiveReply(reply)
return err
}
27 changes: 27 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp1904/vrf_vppcalls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,33 @@ func TestDeleteVrfTable(t *testing.T) {
Expect(err).To(Not(BeNil()))
}

// Test VRF flow hash settings
func TestVrfFlowHashSettings(t *testing.T) {
ctx, vtHandler := vrfTableTestSetup(t)
defer ctx.TeardownTestCtx()

ctx.MockVpp.MockReply(&ip.SetIPFlowHashReply{})
err := vtHandler.SetVrfFlowHashSettings(5, true,
&l3.VrfTable_FlowHashSettings{
UseSrcIp: true,
UseSrcPort: true,
Symmetric: true,
})
Expect(err).To(Succeed())

vppMsg, ok := ctx.MockChannel.Msg.(*ip.SetIPFlowHash)
Expect(ok).To(BeTrue())
Expect(vppMsg.VrfID).To(BeEquivalentTo(5))
Expect(vppMsg.IsIPv6).To(BeEquivalentTo(1))
Expect(vppMsg.Src).To(BeEquivalentTo(1))
Expect(vppMsg.Dst).To(BeEquivalentTo(0))
Expect(vppMsg.Sport).To(BeEquivalentTo(1))
Expect(vppMsg.Dport).To(BeEquivalentTo(0))
Expect(vppMsg.Proto).To(BeEquivalentTo(0))
Expect(vppMsg.Symmetric).To(BeEquivalentTo(1))
Expect(vppMsg.Reverse).To(BeEquivalentTo(0))
}

func vrfTableTestSetup(t *testing.T) (*vppmock.TestCtx, vppcalls.VrfTableVppAPI) {
ctx := vppmock.SetupTestCtx(t)
log := logrus.NewLogger("test-log")
Expand Down
19 changes: 19 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp1908/vrf_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,22 @@ func (h *VrfTableHandler) addDelVrfTable(table *l3.VrfTable, isAdd bool) error {

return nil
}

// SetVrfFlowHashSettings sets IP flow hash settings for a VRF table.
func (h *VrfTableHandler) SetVrfFlowHashSettings(vrfID uint32, isIPv6 bool, hashFields *l3.VrfTable_FlowHashSettings) error {
req := &ip.SetIPFlowHash{
VrfID: vrfID,
IsIPv6: boolToUint(isIPv6),
Src: boolToUint(hashFields.UseSrcIp),
Dst: boolToUint(hashFields.UseDstIp),
Sport: boolToUint(hashFields.UseSrcPort),
Dport: boolToUint(hashFields.UseDstPort),
Proto: boolToUint(hashFields.UseProtocol),
Reverse: boolToUint(hashFields.Reverse),
Symmetric: boolToUint(hashFields.Symmetric),
}
reply := &ip.SetIPFlowHashReply{}

err := h.callsChannel.SendRequest(req).ReceiveReply(reply)
return err
}
27 changes: 27 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp1908/vrf_vppcalls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,33 @@ func TestDeleteVrfTable(t *testing.T) {
Expect(err).To(Not(BeNil()))
}

// Test VRF flow hash settings
func TestVrfFlowHashSettings(t *testing.T) {
ctx, vtHandler := vrfTableTestSetup(t)
defer ctx.TeardownTestCtx()

ctx.MockVpp.MockReply(&ip.SetIPFlowHashReply{})
err := vtHandler.SetVrfFlowHashSettings(5, true,
&l3.VrfTable_FlowHashSettings{
UseSrcIp: true,
UseSrcPort: true,
Symmetric: true,
})
Expect(err).To(Succeed())

vppMsg, ok := ctx.MockChannel.Msg.(*ip.SetIPFlowHash)
Expect(ok).To(BeTrue())
Expect(vppMsg.VrfID).To(BeEquivalentTo(5))
Expect(vppMsg.IsIPv6).To(BeEquivalentTo(1))
Expect(vppMsg.Src).To(BeEquivalentTo(1))
Expect(vppMsg.Dst).To(BeEquivalentTo(0))
Expect(vppMsg.Sport).To(BeEquivalentTo(1))
Expect(vppMsg.Dport).To(BeEquivalentTo(0))
Expect(vppMsg.Proto).To(BeEquivalentTo(0))
Expect(vppMsg.Symmetric).To(BeEquivalentTo(1))
Expect(vppMsg.Reverse).To(BeEquivalentTo(0))
}

func vrfTableTestSetup(t *testing.T) (*vppmock.TestCtx, vppcalls.VrfTableVppAPI) {
ctx := vppmock.SetupTestCtx(t)
log := logrus.NewLogger("test-log")
Expand Down
19 changes: 19 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp2001/vrf_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,22 @@ func (h *VrfTableHandler) addDelVrfTable(table *l3.VrfTable, isAdd bool) error {

return nil
}

// SetVrfFlowHashSettings sets IP flow hash settings for a VRF table.
func (h *VrfTableHandler) SetVrfFlowHashSettings(vrfID uint32, isIPv6 bool, hashFields *l3.VrfTable_FlowHashSettings) error {
req := &vpp_ip.SetIPFlowHash{
VrfID: vrfID,
IsIPv6: boolToUint(isIPv6),
Src: boolToUint(hashFields.UseSrcIp),
Dst: boolToUint(hashFields.UseDstIp),
Sport: boolToUint(hashFields.UseSrcPort),
Dport: boolToUint(hashFields.UseDstPort),
Proto: boolToUint(hashFields.UseProtocol),
Reverse: boolToUint(hashFields.Reverse),
Symmetric: boolToUint(hashFields.Symmetric),
}
reply := &vpp_ip.SetIPFlowHashReply{}

err := h.callsChannel.SendRequest(req).ReceiveReply(reply)
return err
}
27 changes: 27 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp2001/vrf_vppcalls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,33 @@ func TestDeleteVrfTable(t *testing.T) {
Expect(err).To(Not(BeNil()))
}

// Test VRF flow hash settings
func TestVrfFlowHashSettings(t *testing.T) {
ctx, vtHandler := vrfTableTestSetup(t)
defer ctx.TeardownTestCtx()

ctx.MockVpp.MockReply(&vpp_ip.SetIPFlowHashReply{})
err := vtHandler.SetVrfFlowHashSettings(5, true,
&l3.VrfTable_FlowHashSettings{
UseSrcIp: true,
UseSrcPort: true,
Symmetric: true,
})
Expect(err).To(Succeed())

vppMsg, ok := ctx.MockChannel.Msg.(*vpp_ip.SetIPFlowHash)
Expect(ok).To(BeTrue())
Expect(vppMsg.VrfID).To(BeEquivalentTo(5))
Expect(vppMsg.IsIPv6).To(BeEquivalentTo(1))
Expect(vppMsg.Src).To(BeEquivalentTo(1))
Expect(vppMsg.Dst).To(BeEquivalentTo(0))
Expect(vppMsg.Sport).To(BeEquivalentTo(1))
Expect(vppMsg.Dport).To(BeEquivalentTo(0))
Expect(vppMsg.Proto).To(BeEquivalentTo(0))
Expect(vppMsg.Symmetric).To(BeEquivalentTo(1))
Expect(vppMsg.Reverse).To(BeEquivalentTo(0))
}

func vrfTableTestSetup(t *testing.T) (*vppmock.TestCtx, vppcalls.VrfTableVppAPI) {
ctx := vppmock.SetupTestCtx(t)
log := logrus.NewLogger("test-log")
Expand Down
19 changes: 19 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp2001_324/vrf_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,22 @@ func (h *VrfTableHandler) addDelVrfTable(table *l3.VrfTable, isAdd bool) error {

return nil
}

// SetVrfFlowHashSettings sets IP flow hash settings for a VRF table.
func (h *VrfTableHandler) SetVrfFlowHashSettings(vrfID uint32, isIPv6 bool, hashFields *l3.VrfTable_FlowHashSettings) error {
req := &vpp_ip.SetIPFlowHash{
VrfID: vrfID,
IsIPv6: boolToUint(isIPv6),
Src: boolToUint(hashFields.UseSrcIp),
Dst: boolToUint(hashFields.UseDstIp),
Sport: boolToUint(hashFields.UseSrcPort),
Dport: boolToUint(hashFields.UseDstPort),
Proto: boolToUint(hashFields.UseProtocol),
Reverse: boolToUint(hashFields.Reverse),
Symmetric: boolToUint(hashFields.Symmetric),
}
reply := &vpp_ip.SetIPFlowHashReply{}

err := h.callsChannel.SendRequest(req).ReceiveReply(reply)
return err
}
27 changes: 27 additions & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp2001_324/vrf_vppcalls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,33 @@ func TestDeleteVrfTable(t *testing.T) {
Expect(err).To(Not(BeNil()))
}

// Test VRF flow hash settings
func TestVrfFlowHashSettings(t *testing.T) {
ctx, vtHandler := vrfTableTestSetup(t)
defer ctx.TeardownTestCtx()

ctx.MockVpp.MockReply(&vpp_ip.SetIPFlowHashReply{})
err := vtHandler.SetVrfFlowHashSettings(5, true,
&l3.VrfTable_FlowHashSettings{
UseSrcIp: true,
UseSrcPort: true,
Symmetric: true,
})
Expect(err).To(Succeed())

vppMsg, ok := ctx.MockChannel.Msg.(*vpp_ip.SetIPFlowHash)
Expect(ok).To(BeTrue())
Expect(vppMsg.VrfID).To(BeEquivalentTo(5))
Expect(vppMsg.IsIPv6).To(BeEquivalentTo(1))
Expect(vppMsg.Src).To(BeEquivalentTo(1))
Expect(vppMsg.Dst).To(BeEquivalentTo(0))
Expect(vppMsg.Sport).To(BeEquivalentTo(1))
Expect(vppMsg.Dport).To(BeEquivalentTo(0))
Expect(vppMsg.Proto).To(BeEquivalentTo(0))
Expect(vppMsg.Symmetric).To(BeEquivalentTo(1))
Expect(vppMsg.Reverse).To(BeEquivalentTo(0))
}

func vrfTableTestSetup(t *testing.T) (*vppmock.TestCtx, vppcalls.VrfTableVppAPI) {
ctx := vppmock.SetupTestCtx(t)
log := logrus.NewLogger("test-log")
Expand Down
Loading

0 comments on commit f4e780a

Please sign in to comment.