Skip to content
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
53 changes: 53 additions & 0 deletions dataplane/saiserver/routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,59 @@ func (nhg *nextHopGroup) updateNextHopGroupMember(ctx context.Context, nhgid, mi
return err
}

// SetNextHopGroupAttribute sets the attribute of the next hop group.
func (nhg *nextHopGroup) SetNextHopGroupAttribute(ctx context.Context, req *saipb.SetNextHopGroupAttributeRequest) (*saipb.SetNextHopGroupAttributeResponse, error) {
if _, ok := nhg.groups[req.GetOid()]; !ok {
return nil, status.Errorf(codes.NotFound, "group %d does not exist", req.GetOid())
}
resp := &saipb.GetNextHopGroupAttributeResponse{
Attr: &saipb.NextHopGroupAttribute{},
}
pBytes, err := proto.Marshal(req)
if err != nil {
return nil, err
}
if err := nhg.mgr.PopulateAllAttributes(string(pBytes), resp.Attr); err != nil {
return nil, err
}

// If next hop list is set, then replace all members.
if len(req.GetNextHopList()) > 0 {
attr := &saipb.NextHopGroupAttribute{}
if err := nhg.mgr.PopulateAllAttributes(fmt.Sprint(req.GetOid()), attr); err != nil {
return nil, err
}
attr.NextHopList = req.GetNextHopList()
attr.NextHopMemberWeightList = nil

for mid := range nhg.groups[req.GetOid()] { // Create a copy of the keys since we are deleting them.
if _, err := nhg.RemoveNextHopGroupMember(ctx, &saipb.RemoveNextHopGroupMemberRequest{Oid: mid}); err != nil {
return nil, err
}
}
memReq := &saipb.CreateNextHopGroupMembersRequest{}
for i, nh := range req.GetNextHopList() {
weight := uint32(1)
if len(req.GetNextHopMemberWeightList()) > i {
weight = req.GetNextHopMemberWeightList()[i]
}
attr.NextHopMemberWeightList = append(attr.NextHopMemberWeightList, weight)
memReq.Reqs = append(memReq.Reqs, &saipb.CreateNextHopGroupMemberRequest{
Switch: switchID,
NextHopGroupId: proto.Uint64(req.GetOid()),
NextHopId: proto.Uint64(nh),
Weight: proto.Uint32(weight),
})
}
if _, err := attrmgr.InvokeAndSave(ctx, nhg.mgr, nhg.CreateNextHopGroupMembers, memReq); err != nil {
return nil, err
}
nhg.mgr.StoreAttributes(req.GetOid(), attr)
}

return &saipb.SetNextHopGroupAttributeResponse{}, nil
}

// RemoveNextHopGroup removes the next hop group specified in the OID.
func (nhg *nextHopGroup) RemoveNextHopGroup(_ context.Context, req *saipb.RemoveNextHopGroupRequest) (*saipb.RemoveNextHopGroupResponse, error) {
oid := req.GetOid()
Expand Down
66 changes: 66 additions & 0 deletions dataplane/saiserver/routing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package saiserver
import (
"context"
"encoding/binary"
"fmt"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -181,6 +182,71 @@ func TestRemoveNextHopGroup(t *testing.T) {
}
}

func TestSetNextHopGroupAttribute(t *testing.T) {
tests := []struct {
desc string
req *saipb.SetNextHopGroupAttributeRequest
wantAttr *saipb.NextHopGroupAttribute
wantErr string
}{{
desc: "replace members",
req: &saipb.SetNextHopGroupAttributeRequest{
NextHopList: []uint64{3},
},
wantAttr: &saipb.NextHopGroupAttribute{
NextHopList: []uint64{3},
NextHopMemberWeightList: []uint32{1},
Type: saipb.NextHopGroupType_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP.Enum(),
},
}}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
dplane := &fakeSwitchDataplane{}
c, mgr, stopFn := newTestNextHopGroup(t, dplane)
defer stopFn()

mgr.StoreAttributes(mgr.NextID(), &saipb.SwitchAttribute{EcmpHashIpv4: proto.Uint64(10), EcmpHashIpv6: proto.Uint64(9)})
mgr.StoreAttributes(3, &saipb.CreateNextHopRequest{Ip: []byte{127, 0, 0, 1}})
mgr.StoreAttributes(4, &saipb.CreateNextHopRequest{Ip: []byte{127, 0, 0, 2}})
mgr.StoreAttributes(10, &saipb.CreateHashRequest{
NativeHashFieldList: []saipb.NativeHashField{saipb.NativeHashField_NATIVE_HASH_FIELD_DST_IP},
})

ctx := context.Background()
resp, err := c.CreateNextHopGroup(ctx, &saipb.CreateNextHopGroupRequest{Type: saipb.NextHopGroupType_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP.Enum()})
if err != nil {
t.Fatal(err)
}
tt.req.Oid = resp.Oid

_, err = c.CreateNextHopGroupMember(ctx, &saipb.CreateNextHopGroupMemberRequest{
NextHopGroupId: proto.Uint64(resp.Oid),
NextHopId: proto.Uint64(4),
Weight: proto.Uint32(1),
})
if err != nil {
t.Fatal(err)
}

_, gotErr := c.SetNextHopGroupAttribute(ctx, tt.req)
if diff := errdiff.Check(gotErr, tt.wantErr); diff != "" {
t.Fatalf("SetNextHopGroupAttribute() unexpected err: %s", diff)
}
if gotErr != nil {
return
}

attr := &saipb.NextHopGroupAttribute{}
if err := mgr.PopulateAllAttributes(fmt.Sprint(resp.Oid), attr); err != nil {
t.Fatal(err)
}
if d := cmp.Diff(attr, tt.wantAttr, protocmp.Transform()); d != "" {
t.Errorf("SetNextHopGroupAttribute() failed: diff(-got,+want)\n:%s", d)
}
})
}
}

func TestCreateNextHopGroupMember(t *testing.T) {
tests := []struct {
desc string
Expand Down
8 changes: 7 additions & 1 deletion dataplane/standalone/sai/next_hop_group.cc
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,13 @@ sai_status_t l_remove_next_hop_groups(uint32_t object_count, const sai_object_id
}

sai_status_t l_set_next_hop_groups_attribute(uint32_t object_count, const sai_object_id_t *object_id, const sai_attribute_t *attr_list, sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) {
LOG(INFO) << "Func: " << __PRETTY_FUNCTION__ << " is not implemented but by-passing check";
LOG(INFO) << "Func: " << __PRETTY_FUNCTION__;
for (uint32_t i = 0; i < object_count; i++) {
object_statuses[i] = l_set_next_hop_group_attribute(object_id[i], &attr_list[i]);
if (object_statuses[i] != SAI_STATUS_SUCCESS && mode == SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR) {
return SAI_STATUS_FAILURE;
}
}
return SAI_STATUS_SUCCESS;
}

Expand Down
Loading