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

feat: IP flow hash settings support #1610

Merged
merged 2 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
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,
rastislavs marked this conversation as resolved.
Show resolved Hide resolved
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