From 0b0eb68757b946696e13b40984b9ffaf93203336 Mon Sep 17 00:00:00 2001 From: Teja Tamboli Date: Thu, 8 Jan 2026 00:36:05 +0000 Subject: [PATCH] Add bulk support for set operation for route --- dataplane/saiserver/routing.go | 127 ++++++++++++++++++++++++++++++ dataplane/standalone/sai/route.cc | 21 ++++- 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/dataplane/saiserver/routing.go b/dataplane/saiserver/routing.go index 9cf7cbfc3..f4ccc625f 100644 --- a/dataplane/saiserver/routing.go +++ b/dataplane/saiserver/routing.go @@ -544,6 +544,10 @@ func (r *route) CreateRouteEntry(ctx context.Context, req *saipb.CreateRouteEntr fib = FIBV4Table } + if req.PacketAction == nil { + req.PacketAction = saipb.PacketAction_PACKET_ACTION_FORWARD.Enum() + } + entry := fwdconfig.TableEntryAddRequest(r.dataplane.ID(), fib).AppendEntry(fwdconfig.EntryDesc( fwdconfig.PrefixEntry( fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_PACKET_VRF).WithUint64(req.GetEntry().GetVrId()), @@ -635,6 +639,129 @@ func (r *route) CreateRouteEntry(ctx context.Context, req *saipb.CreateRouteEntr return &saipb.CreateRouteEntryResponse{}, nil } +func (r *route) SetRouteEntryAttribute(ctx context.Context, req *saipb.SetRouteEntryAttributeRequest) (*saipb.SetRouteEntryAttributeResponse, error) { + resp := &saipb.GetRouteEntryAttributeResponse{ + Attr: &saipb.RouteEntryAttribute{}, + } + pBytes, err := proto.Marshal(req.GetEntry()) + if err != nil { + return nil, err + } + if err := r.mgr.PopulateAllAttributes(string(pBytes), resp.Attr); err != nil { + return nil, err + } + // The request only has one attribute, so find the one that is set. + // Only these three attributes are supported. + packetAction := resp.Attr.GetPacketAction() + if req.PacketAction != nil { + packetAction = req.GetPacketAction() + } + nextHopID := resp.Attr.GetNextHopId() + if req.NextHopId != nil { + nextHopID = req.GetNextHopId() + } + metaData := resp.Attr.MetaData + if req.MetaData != nil { + metaData = req.MetaData + } + + fib := FIBV6Table + if len(req.GetEntry().GetDestination().GetAddr()) == 4 { + fib = FIBV4Table + } + + entry := fwdconfig.TableEntryAddRequest(r.dataplane.ID(), fib).AppendEntry(fwdconfig.EntryDesc( + fwdconfig.PrefixEntry( + fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_PACKET_VRF).WithUint64(req.GetEntry().GetVrId()), + fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST).WithBytes( + req.GetEntry().GetDestination().GetAddr(), + req.GetEntry().GetDestination().GetMask(), + ), + ), + )) + + forward := true + if packetAction == saipb.PacketAction_PACKET_ACTION_DROP || + packetAction == saipb.PacketAction_PACKET_ACTION_TRAP || + packetAction == saipb.PacketAction_PACKET_ACTION_DENY { + forward = false + } + nextType := r.mgr.GetType(fmt.Sprint(nextHopID)) + + actions := []fwdconfig.ActionDescBuilder{} + + // If the packet action is drop, then next hop is optional. + if forward { + actions = append(actions, fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_BIT_WRITE, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_PACKET_ACTION).WithBitOp(1, 0).WithValue([]byte{1})) + switch nextType { + case saipb.ObjectType_OBJECT_TYPE_NEXT_HOP: + actions = append(actions, + fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_ID).WithUint64Value(nextHopID), + fwdconfig.LookupAction(NHTable), + ) + case saipb.ObjectType_OBJECT_TYPE_NEXT_HOP_GROUP: + actions = append(actions, + fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_GROUP_ID).WithUint64Value(nextHopID), + fwdconfig.LookupAction(NHGTable), + ) + case saipb.ObjectType_OBJECT_TYPE_ROUTER_INTERFACE: + actions = append(actions, + // Set the next hop IP in the packet's metadata. + fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_COPY, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_IP).WithFieldSrc(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST), + // Set the output iface. + fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE).WithUint64Value(nextHopID), + ) + case saipb.ObjectType_OBJECT_TYPE_PORT: + attrReq := &saipb.GetSwitchAttributeRequest{ + Oid: req.GetEntry().GetSwitchId(), + AttrType: []saipb.SwitchAttr{saipb.SwitchAttr_SWITCH_ATTR_CPU_PORT}, + } + resp := &saipb.GetSwitchAttributeResponse{} + if err := r.mgr.PopulateAttributes(attrReq, resp); err != nil { + return nil, err + } + if nextHopID == *resp.Attr.CpuPort { + _, err := r.dataplane.TableEntryAdd(ctx, fwdconfig.TableEntryAddRequest(r.dataplane.ID(), trapTableID). + AppendEntry( + fwdconfig.EntryDesc(fwdconfig.FlowEntry( + fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST).WithBytes( + req.GetEntry().GetDestination().GetAddr(), + req.GetEntry().GetDestination().GetMask()), + fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_PACKET_VRF).WithUint64(req.GetEntry().GetVrId()))), + fwdconfig.TransmitAction(fmt.Sprint(nextHopID)).WithImmediate(true)). + Build()) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to add next IP2ME route: %v", nextType) + } + return &saipb.SetRouteEntryAttributeResponse{}, nil + } + actions = append(actions, + // Set the next hop IP in the packet's metadata. + fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_COPY, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_IP).WithFieldSrc(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST), + // Set the output port. + fwdconfig.TransmitAction(fmt.Sprint(nextHopID)), + ) + default: + return nil, status.Errorf(codes.InvalidArgument, "unknown next hop type: %v", nextType) + } + } else { + actions = append(actions, fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_BIT_WRITE, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_PACKET_ACTION).WithBitOp(1, 0).WithValue([]byte{0})) + } + if metaData != nil { + actions = append(actions, fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_PACKET_ATTRIBUTE_32). + WithFieldIDInstance(routeDstMeta).WithValue(binary.BigEndian.AppendUint32(nil, *metaData))) + } + entry.AppendActions(actions...) + + route := entry.Build() + _, err = r.dataplane.TableEntryAdd(ctx, route) + if err != nil { + return nil, err + } + + return &saipb.SetRouteEntryAttributeResponse{}, nil +} + func (r *route) CreateRouteEntries(ctx context.Context, re *saipb.CreateRouteEntriesRequest) (*saipb.CreateRouteEntriesResponse, error) { var errs errlist.List resp := &saipb.CreateRouteEntriesResponse{} diff --git a/dataplane/standalone/sai/route.cc b/dataplane/standalone/sai/route.cc index 8caaa335c..67aef566e 100644 --- a/dataplane/standalone/sai/route.cc +++ b/dataplane/standalone/sai/route.cc @@ -284,7 +284,26 @@ sai_status_t l_remove_route_entries(uint32_t object_count, const sai_route_entry sai_status_t l_set_route_entries_attribute(uint32_t object_count, const sai_route_entry_t *route_entry, const sai_attribute_t *attr_list, sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) { LOG(INFO) << "Func: " << __PRETTY_FUNCTION__; - return SAI_STATUS_NOT_IMPLEMENTED; + sai_status_t status; + sai_status_t overall_status = SAI_STATUS_SUCCESS; + bool error = false; + + for (uint32_t i = 0; i < object_count; i++) { + object_statuses[i] = SAI_STATUS_NOT_EXECUTED; + if (false == error) + { + status = l_set_route_entry_attribute(&route_entry[i], &attr_list[i]); + object_statuses[i] = status; + if (status != SAI_STATUS_SUCCESS) { + overall_status = SAI_STATUS_FAILURE; + if (mode == SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR) { + error = true; + } + } + } + } + + return overall_status; } sai_status_t l_get_route_entries_attribute(uint32_t object_count, const sai_route_entry_t *route_entry, const uint32_t *attr_count, sai_attribute_t **attr_list, sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) {