diff --git a/dataplane/saiserver/acl.go b/dataplane/saiserver/acl.go index 64e1584b..f6b343a6 100644 --- a/dataplane/saiserver/acl.go +++ b/dataplane/saiserver/acl.go @@ -370,9 +370,16 @@ func (a *acl) CreateAclEntry(ctx context.Context, req *saipb.CreateAclEntryReque aReq.Actions = append(aReq.Actions, &fwdpb.ActionDesc{ActionType: fwdpb.ActionType_ACTION_TYPE_DROP}) case saipb.PacketAction_PACKET_ACTION_TRAP: // COPY and DROP aReq.Actions = append(aReq.Actions, fwdconfig.Action(fwdconfig.TransmitAction(fmt.Sprint(resp.GetAttr().GetCpuPort())).WithImmediate(true)).Build()) - case saipb.PacketAction_PACKET_ACTION_FORWARD, - saipb.PacketAction_PACKET_ACTION_LOG, // COPY and FORWARD - saipb.PacketAction_PACKET_ACTION_TRANSIT: // COPY_CANCEL and FORWARD + case saipb.PacketAction_PACKET_ACTION_LOG: // COPY and FORWARD + mirror := &fwdpb.ActionDesc{ + ActionType: fwdpb.ActionType_ACTION_TYPE_MIRROR, + Action: &fwdpb.ActionDesc_Mirror{Mirror: &fwdpb.MirrorActionDesc{ + PortId: &fwdpb.PortId{ObjectId: &fwdpb.ObjectId{Id: fmt.Sprint(resp.GetAttr().GetCpuPort())}}, + PortAction: fwdpb.PortAction_PORT_ACTION_OUTPUT, + }}, + } + aReq.Actions = append(aReq.Actions, mirror, &fwdpb.ActionDesc{ActionType: fwdpb.ActionType_ACTION_TYPE_CONTINUE}) + case saipb.PacketAction_PACKET_ACTION_FORWARD, saipb.PacketAction_PACKET_ACTION_TRANSIT: // COPY_CANCEL and FORWARD aReq.Actions = append(aReq.Actions, &fwdpb.ActionDesc{ActionType: fwdpb.ActionType_ACTION_TYPE_CONTINUE}) // Packets are forwarded by default so continue. default: return nil, status.Errorf(codes.InvalidArgument, "unknown packet action type: %v", req.GetActionPacketAction().GetPacketAction()) diff --git a/dataplane/saiserver/policer.go b/dataplane/saiserver/policer.go index 0670986b..0553b49f 100644 --- a/dataplane/saiserver/policer.go +++ b/dataplane/saiserver/policer.go @@ -52,21 +52,31 @@ func (p *policer) CreatePolicer(ctx context.Context, req *saipb.CreatePolicerReq return nil, err } - var action *fwdconfig.ActionBuilder + var action *fwdpb.ActionDesc switch req.GetGreenPacketAction() { - case saipb.PacketAction_PACKET_ACTION_TRAP, saipb.PacketAction_PACKET_ACTION_COPY: - action = fwdconfig.Action(fwdconfig.TransmitAction(fmt.Sprint(resp.GetAttr().GetCpuPort())).WithImmediate(true)) + case saipb.PacketAction_PACKET_ACTION_TRAP: + action = fwdconfig.Action(fwdconfig.TransmitAction(fmt.Sprint(resp.GetAttr().GetCpuPort())).WithImmediate(true)).Build() + case saipb.PacketAction_PACKET_ACTION_COPY: + action = &fwdpb.ActionDesc{ + ActionType: fwdpb.ActionType_ACTION_TYPE_MIRROR, + Action: &fwdpb.ActionDesc_Mirror{Mirror: &fwdpb.MirrorActionDesc{ + PortId: &fwdpb.PortId{ObjectId: &fwdpb.ObjectId{Id: fmt.Sprint(resp.GetAttr().GetCpuPort())}}, + PortAction: fwdpb.PortAction_PORT_ACTION_OUTPUT, + }}, + } case saipb.PacketAction_PACKET_ACTION_FORWARD, saipb.PacketAction_PACKET_ACTION_UNSPECIFIED: // If unset, the default action is FORWARD. - action = fwdconfig.Action(fwdconfig.ContinueAction()) + action = fwdconfig.Action(fwdconfig.ContinueAction()).Build() default: return nil, fmt.Errorf("unsupport policer action: %v", req.GetGreenPacketAction()) } tReq := fwdconfig.TableEntryAddRequest(p.dataplane.ID(), policerTabler). - AppendEntry(fwdconfig.EntryDesc(fwdconfig.ExactEntry(fwdconfig.PacketFieldBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_POLICER_ID).WithUint64(id))), action) + AppendEntry(fwdconfig.EntryDesc(fwdconfig.ExactEntry(fwdconfig.PacketFieldBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_POLICER_ID).WithUint64(id)))).Build() - if _, err := p.dataplane.TableEntryAdd(ctx, tReq.Build()); err != nil { + tReq.Entries[0].Actions = append(tReq.Entries[0].Actions, action) + + if _, err := p.dataplane.TableEntryAdd(ctx, tReq); err != nil { return nil, err } diff --git a/dataplane/saiserver/ports.go b/dataplane/saiserver/ports.go index bf9d5b8c..bb89bebf 100644 --- a/dataplane/saiserver/ports.go +++ b/dataplane/saiserver/ports.go @@ -92,6 +92,7 @@ func getPreIngressPipeline() []*fwdpb.ActionDesc { func getL3Pipeline() []*fwdpb.ActionDesc { return []*fwdpb.ActionDesc{ fwdconfig.Action(fwdconfig.LookupAction(IngressActionTable)).Build(), // Run ingress action. + fwdconfig.Action(fwdconfig.LookupAction(invalidIPTable)).Build(), // Do not forward packets with invalid addresses fwdconfig.Action(fwdconfig.DecapAction(fwdpb.PacketHeaderId_PACKET_HEADER_ID_ETHERNET)).Build(), // Decap L2 header. fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_DEC, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_HOP).WithValue([]byte{0x1})).Build(), // Decrement TTL. fwdconfig.Action(fwdconfig.LookupAction(FIBSelectorTable)).Build(), // Lookup in FIB. diff --git a/dataplane/saiserver/switch.go b/dataplane/saiserver/switch.go index abe66f5c..ddadb8cf 100644 --- a/dataplane/saiserver/switch.go +++ b/dataplane/saiserver/switch.go @@ -17,6 +17,7 @@ package saiserver import ( "context" "fmt" + "net" "strconv" "google.golang.org/grpc" @@ -113,6 +114,7 @@ const ( VlanTable = "vlan" L2MCGroupTable = "l2mcg" policerTabler = "policerTable" + invalidIPTable = "invalid-ip" DefaultVlanId = 1 ) @@ -318,6 +320,10 @@ func (sw *saiSwitch) CreateSwitch(ctx context.Context, _ *saipb.CreateSwitchRequ return nil, err } + if err := sw.createInvalidIPFilter(ctx); err != nil { + return nil, err + } + myMAC := &fwdpb.TableCreateRequest{ ContextId: &fwdpb.ContextId{Id: sw.dataplane.ID()}, Desc: &fwdpb.TableDesc{ @@ -795,6 +801,60 @@ func (sw *saiSwitch) CreateSwitch(ctx context.Context, _ *saipb.CreateSwitchRequ }, nil } +// Set up rules to drop packets that contain invalid IP. +// https://www.rfc-editor.org/rfc/rfc1812#section-5.3.7 +func (sw *saiSwitch) createInvalidIPFilter(ctx context.Context) error { + _, err := sw.dataplane.TableCreate(ctx, &fwdpb.TableCreateRequest{ + ContextId: &fwdpb.ContextId{Id: sw.dataplane.ID()}, + Desc: &fwdpb.TableDesc{ + Actions: []*fwdpb.ActionDesc{{ActionType: fwdpb.ActionType_ACTION_TYPE_CONTINUE}}, + TableType: fwdpb.TableType_TABLE_TYPE_FLOW, + TableId: &fwdpb.TableId{ObjectId: &fwdpb.ObjectId{Id: invalidIPTable}}, + Table: &fwdpb.TableDesc_Flow{ + Flow: &fwdpb.FlowTableDesc{ + BankCount: 1, + }, + }, + }, + }) + if err != nil { + return err + } + // Packets can't have multicast, or loopback IP as the source IP. + invalidSrcIP := []string{"224.0.0.0/4", "ff00::/8", "127.0.0.0/8"} + for _, ip := range invalidSrcIP { + _, prefix, err := net.ParseCIDR(ip) + if err != nil { + return err + } + req := fwdconfig.TableEntryAddRequest(sw.dataplane.ID(), invalidIPTable). + AppendEntry( + fwdconfig.EntryDesc(fwdconfig.FlowEntry(fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_SRC).WithBytes(prefix.IP, prefix.Mask))), + fwdconfig.Action(fwdconfig.DropAction()), + ).Build() + if _, err := sw.dataplane.TableEntryAdd(ctx, req); err != nil { + return err + } + } + // Only unicast MAC address are processed at this stage, so multicast IPs are invalid + invalidDstIP := []string{"224.0.0.0/4", "ff00::/8", "fe80::/10", "127.0.0.0/8", "255.255.255.255/24"} + for _, ip := range invalidDstIP { + _, prefix, err := net.ParseCIDR(ip) + if err != nil { + return err + } + req := fwdconfig.TableEntryAddRequest(sw.dataplane.ID(), invalidIPTable). + AppendEntry( + fwdconfig.EntryDesc(fwdconfig.FlowEntry(fwdconfig.PacketFieldMaskedBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST).WithBytes(prefix.IP, prefix.Mask))), + fwdconfig.Action(fwdconfig.DropAction()), + ).Build() + if _, err := sw.dataplane.TableEntryAdd(ctx, req); err != nil { + return err + } + } + return nil +} + func (sw *saiSwitch) SetSwitchAttribute(ctx context.Context, req *saipb.SetSwitchAttributeRequest) (*saipb.SetSwitchAttributeResponse, error) { switch { case req.PreIngressAcl != nil: