From edc85232a24f303445feb5a7b03f0c5177d3becb Mon Sep 17 00:00:00 2001 From: rohrerj <26304001+rohrerj@users.noreply.github.com> Date: Fri, 8 Sep 2023 20:30:01 +0200 Subject: [PATCH] modified test cases and PR comments --- router/dataplane.go | 40 ++++---- router/dataplane_internal_test.go | 147 +++++++++++++++++++++++++++++- router/dataplane_test.go | 107 ---------------------- router/export_test.go | 15 --- 4 files changed, 166 insertions(+), 143 deletions(-) diff --git a/router/dataplane.go b/router/dataplane.go index 1d4ee1db1e..f271c2e768 100644 --- a/router/dataplane.go +++ b/router/dataplane.go @@ -116,26 +116,26 @@ type DataPlane struct { } var ( - alreadySet = serrors.New("already set") - invalidSrcIA = serrors.New("invalid source ISD-AS") - invalidDstIA = serrors.New("invalid destination ISD-AS") - invalidSrcAddrForTransit = serrors.New("invalid source address for transit pkt") - cannotRoute = serrors.New("cannot route, dropping pkt") - emptyValue = serrors.New("empty value") - malformedPath = serrors.New("malformed path content") - modifyExisting = serrors.New("modifying a running dataplane is not allowed") - noSVCBackend = serrors.New("cannot find internal IP for the SVC") - unsupportedPathType = serrors.New("unsupported path type") - unsupportedPathTypeNextHeader = serrors.New("unsupported combination") - noBFDSessionFound = serrors.New("no BFD sessions was found") - noBFDSessionConfigured = serrors.New("no BFD sessions have been configured") - errBFDDisabled = serrors.New("BFD is disabled") - bfdSessionDown = serrors.New("bfd session down") - expiredHop = serrors.New("expired hop") - ingressInterfaceInvalid = serrors.New("ingress interface invalid") - macVerificationFailed = serrors.New("MAC verification failed") - badPacketSize = serrors.New("bad packet size") - slowPathRequired = serrors.New("slow-path required") + alreadySet = errors.New("already set") + invalidSrcIA = errors.New("invalid source ISD-AS") + invalidDstIA = errors.New("invalid destination ISD-AS") + invalidSrcAddrForTransit = errors.New("invalid source address for transit pkt") + cannotRoute = errors.New("cannot route, dropping pkt") + emptyValue = errors.New("empty value") + malformedPath = errors.New("malformed path content") + modifyExisting = errors.New("modifying a running dataplane is not allowed") + noSVCBackend = errors.New("cannot find internal IP for the SVC") + unsupportedPathType = errors.New("unsupported path type") + unsupportedPathTypeNextHeader = errors.New("unsupported combination") + noBFDSessionFound = errors.New("no BFD sessions was found") + noBFDSessionConfigured = errors.New("no BFD sessions have been configured") + errBFDDisabled = errors.New("BFD is disabled") + bfdSessionDown = errors.New("bfd session down") + expiredHop = errors.New("expired hop") + ingressInterfaceInvalid = errors.New("ingress interface invalid") + macVerificationFailed = errors.New("MAC verification failed") + badPacketSize = errors.New("bad packet size") + slowPathRequired = errors.New("slow-path required") // zeroBuffer will be used to reset the Authenticator option in the // scionPacketProcessor.OptAuth zeroBuffer = make([]byte, 16) diff --git a/router/dataplane_internal_test.go b/router/dataplane_internal_test.go index 5a5d9c786b..7b06e74433 100644 --- a/router/dataplane_internal_test.go +++ b/router/dataplane_internal_test.go @@ -29,11 +29,13 @@ import ( "github.com/google/gopacket" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/net/ipv4" "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/private/util" "github.com/scionproto/scion/pkg/private/xtest" + "github.com/scionproto/scion/pkg/scrypto" "github.com/scionproto/scion/pkg/slayers" "github.com/scionproto/scion/pkg/slayers/path" "github.com/scionproto/scion/pkg/slayers/path/scion" @@ -41,6 +43,8 @@ import ( "github.com/scionproto/scion/router/mock_router" ) +var key = []byte("testkey_xxxxxxxx") + // TestReceiver sets up a mocked batchConn, starts the receiver that reads from // this batchConn and forwards it to the processing routines channels. We verify // by directly reading from the processing routine channels that we received @@ -414,6 +418,146 @@ func TestComputeProcIdErrorCases(t *testing.T) { } } +func TestSlowPathProcessing(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + key := []byte("testkey_xxxxxxxx") + payload := []byte("actualpayloadbytes") + testCases := map[string]struct { + mockMsg func() *ipv4.Message + prepareDP func(*gomock.Controller) *DataPlane + expectedSlowPathRequest slowPathRequest + srcInterface uint16 + expectedLayerType gopacket.LayerType + }{ + "svc nobackend": { + prepareDP: func(ctrl *gomock.Controller) *DataPlane { + return NewDP(nil, nil, mock_router.NewMockBatchConn(ctrl), nil, + map[addr.SVC][]*net.UDPAddr{}, + xtest.MustParseIA("1-ff00:0:110"), nil, key) + }, + mockMsg: func() *ipv4.Message { + spkt := prepBaseMsg(t, payload, 0) + _ = spkt.SetDstAddr(addr.MustParseHost("CS")) + spkt.DstIA = xtest.MustParseIA("1-ff00:0:110") + ret := toMsg(t, spkt, spkt.Path) + return ret + }, + srcInterface: 1, + expectedSlowPathRequest: slowPathRequest{ + typ: slowPathSCMP, + scmpType: slayers.SCMPTypeDestinationUnreachable, + code: slayers.SCMPCodeNoRoute, + cause: noSVCBackend, + }, + expectedLayerType: slayers.LayerTypeSCMPDestinationUnreachable, + }, + "svc invalid": { + prepareDP: func(ctrl *gomock.Controller) *DataPlane { + return NewDP(nil, nil, mock_router.NewMockBatchConn(ctrl), nil, + map[addr.SVC][]*net.UDPAddr{}, + xtest.MustParseIA("1-ff00:0:110"), nil, key) + }, + mockMsg: func() *ipv4.Message { + spkt := prepBaseMsg(t, payload, 0) + _ = spkt.SetDstAddr(addr.MustParseHost("CS")) + spkt.DstIA = xtest.MustParseIA("1-ff00:0:110") + ret := toMsg(t, spkt, spkt.Path) + return ret + }, + srcInterface: 1, + expectedSlowPathRequest: slowPathRequest{ + typ: slowPathSCMP, + scmpType: slayers.SCMPTypeDestinationUnreachable, + code: slayers.SCMPCodeNoRoute, + cause: noSVCBackend, + }, + expectedLayerType: slayers.LayerTypeSCMPDestinationUnreachable, + }, + "invalid dest": { + prepareDP: func(ctrl *gomock.Controller) *DataPlane { + return NewDP(nil, nil, mock_router.NewMockBatchConn(ctrl), nil, + map[addr.SVC][]*net.UDPAddr{}, + xtest.MustParseIA("1-ff00:0:110"), nil, key) + }, + mockMsg: func() *ipv4.Message { + spkt := prepBaseMsg(t, payload, 0) + spkt.DstIA = xtest.MustParseIA("1-ff00:0:f1") + ret := toMsg(t, spkt, spkt.Path) + return ret + }, + srcInterface: 1, + expectedSlowPathRequest: slowPathRequest{ + typ: slowPathSCMP, + scmpType: slayers.SCMPTypeParameterProblem, + code: slayers.SCMPCodeInvalidDestinationAddress, + cause: invalidDstIA, + }, + expectedLayerType: slayers.LayerTypeSCMPParameterProblem, + }, + } + for name, tc := range testCases { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + t.Parallel() + dp := tc.prepareDP(ctrl) + input := tc.mockMsg() + result, err := dp.ProcessPkt(tc.srcInterface, input) + assert.ErrorIs(t, err, SlowPathRequired) + selectedResult := slowPathRequest{ + typ: result.SlowPathRequest.typ, + scmpType: result.SlowPathRequest.scmpType, + code: result.SlowPathRequest.code, + cause: result.SlowPathRequest.cause, + } + assert.Equal(t, tc.expectedSlowPathRequest, selectedResult) + result, err = dp.ProcessSlowPath(tc.srcInterface, input, result.SlowPathRequest) + assert.NoError(t, err) + + // here we parse the result.OutPkt to verify that it contains the correct SCMP + // header and typecodes. + packet := gopacket.NewPacket(result.OutPkt, slayers.LayerTypeSCION, gopacket.Default) + scmpLayer := packet.Layer(slayers.LayerTypeSCMP) + scmp := scmpLayer.(*slayers.SCMP) + expectedTypeCode := slayers.CreateSCMPTypeCode(tc.expectedSlowPathRequest.scmpType, + tc.expectedSlowPathRequest.code) + assert.Equal(t, expectedTypeCode, scmp.TypeCode) + layerFound := false + for _, l := range packet.Layers() { + if l.LayerType() == tc.expectedLayerType { + layerFound = true + break + } + } + assert.True(t, layerFound) + }) + } +} + +func toMsg(t *testing.T, spkt *slayers.SCION, dpath path.Path) *ipv4.Message { + t.Helper() + ret := &ipv4.Message{} + spkt.Path = dpath + buffer := gopacket.NewSerializeBuffer() + payload := []byte("actualpayloadbytes") + err := gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{FixLengths: true}, + spkt, gopacket.Payload(payload)) + require.NoError(t, err) + raw := buffer.Bytes() + ret.Buffers = make([][]byte, 1) + ret.Buffers[0] = make([]byte, 1500) + copy(ret.Buffers[0], raw) + ret.N = len(raw) + ret.Buffers[0] = ret.Buffers[0][:ret.N] + return ret +} + +func computeMAC(t *testing.T, key []byte, info path.InfoField, hf path.HopField) [path.MacLen]byte { + mac, err := scrypto.InitMac(key) + require.NoError(t, err) + return path.MAC(mac, info, hf, nil) +} + func serializedBaseMsg(t *testing.T, payload []byte, flowId uint32) []byte { s := prepBaseMsg(t, payload, flowId) buffer := gopacket.NewSerializeBuffer() @@ -440,7 +584,7 @@ func prepBaseMsg(t *testing.T, payload []byte, flowId uint32) *slayers.SCION { dpath := &scion.Decoded{ Base: scion.Base{ PathMeta: scion.MetaHdr{ - CurrHF: 1, + CurrHF: 2, SegLen: [3]uint8{3, 0, 0}, }, NumINF: 1, @@ -456,6 +600,7 @@ func prepBaseMsg(t *testing.T, payload []byte, flowId uint32) *slayers.SCION { {ConsIngress: 1, ConsEgress: 0}, }, } + dpath.HopFields[2].Mac = computeMAC(t, key, dpath.InfoFields[0], dpath.HopFields[2]) spkt.Path = dpath return spkt } diff --git a/router/dataplane_test.go b/router/dataplane_test.go index b48b3a5606..f922ccad94 100644 --- a/router/dataplane_test.go +++ b/router/dataplane_test.go @@ -566,113 +566,6 @@ func TestDataPlaneRun(t *testing.T) { } } -func TestSlowPathProcessing(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - key := []byte("testkey_xxxxxxxx") - now := time.Now() - testCases := map[string]struct { - mockMsg func() *ipv4.Message - prepareDP func(*gomock.Controller) *router.DataPlane - expectedSlowPathRequest router.SlowPathRequest - srcInterface uint16 - }{ - "svc nobackend": { - prepareDP: func(ctrl *gomock.Controller) *router.DataPlane { - return router.NewDP(nil, nil, mock_router.NewMockBatchConn(ctrl), nil, - map[addr.SVC][]*net.UDPAddr{}, - xtest.MustParseIA("1-ff00:0:110"), nil, key) - }, - mockMsg: func() *ipv4.Message { - spkt, dpath := prepBaseMsg(now) - _ = spkt.SetDstAddr(addr.MustParseHost("CS")) - spkt.DstIA = xtest.MustParseIA("1-ff00:0:110") - dpath.HopFields = []path.HopField{ - {ConsIngress: 41, ConsEgress: 40}, - {ConsIngress: 31, ConsEgress: 30}, - {ConsIngress: 1, ConsEgress: 0}, - } - dpath.Base.PathMeta.CurrHF = 2 - dpath.HopFields[2].Mac = computeMAC(t, key, dpath.InfoFields[0], dpath.HopFields[2]) - ret := toMsg(t, spkt, dpath) - return ret - }, - srcInterface: 1, - expectedSlowPathRequest: router.SlowPathRequest{ - Typ: 0, - ScmpType: slayers.SCMPTypeDestinationUnreachable, - Code: slayers.SCMPCodeNoRoute, - }, - }, - "svc invalid": { - prepareDP: func(ctrl *gomock.Controller) *router.DataPlane { - return router.NewDP(nil, nil, mock_router.NewMockBatchConn(ctrl), nil, - map[addr.SVC][]*net.UDPAddr{}, - xtest.MustParseIA("1-ff00:0:110"), nil, key) - }, - mockMsg: func() *ipv4.Message { - spkt, dpath := prepBaseMsg(now) - _ = spkt.SetDstAddr(addr.MustParseHost("CS")) - spkt.DstIA = xtest.MustParseIA("1-ff00:0:110") - dpath.HopFields = []path.HopField{ - {ConsIngress: 41, ConsEgress: 40}, - {ConsIngress: 31, ConsEgress: 30}, - {ConsIngress: 1, ConsEgress: 0}, - } - dpath.Base.PathMeta.CurrHF = 2 - dpath.HopFields[2].Mac = computeMAC(t, key, dpath.InfoFields[0], dpath.HopFields[2]) - ret := toMsg(t, spkt, dpath) - return ret - }, - srcInterface: 1, - expectedSlowPathRequest: router.SlowPathRequest{ - Typ: 0, - ScmpType: slayers.SCMPTypeDestinationUnreachable, - Code: slayers.SCMPCodeNoRoute, - }, - }, - "invalid dest": { - prepareDP: func(ctrl *gomock.Controller) *router.DataPlane { - return router.NewDP(nil, nil, mock_router.NewMockBatchConn(ctrl), nil, - map[addr.SVC][]*net.UDPAddr{}, - xtest.MustParseIA("1-ff00:0:110"), nil, key) - }, - mockMsg: func() *ipv4.Message { - spkt, dpath := prepBaseMsg(now) - spkt.DstIA = xtest.MustParseIA("1-ff00:0:f1") - dpath.HopFields = []path.HopField{ - {ConsIngress: 41, ConsEgress: 40}, - {ConsIngress: 31, ConsEgress: 404}, - {ConsIngress: 1, ConsEgress: 0}, - } - dpath.Base.PathMeta.CurrHF = 2 - dpath.HopFields[1].Mac = computeMAC(t, key, dpath.InfoFields[0], dpath.HopFields[1]) - ret := toMsg(t, spkt, dpath) - return ret - }, - srcInterface: 1, - expectedSlowPathRequest: router.SlowPathRequest{ - Typ: 0, - ScmpType: slayers.SCMPTypeParameterProblem, - Code: slayers.SCMPCodeInvalidDestinationAddress, - }, - }, - } - for name, tc := range testCases { - name, tc := name, tc - t.Run(name, func(t *testing.T) { - t.Parallel() - dp := tc.prepareDP(ctrl) - input := tc.mockMsg() - result, err := dp.ProcessPkt(tc.srcInterface, input) - assert.ErrorIs(t, err, router.SlowPathRequired) - assert.Equal(t, tc.expectedSlowPathRequest, result.SlowPathRequest.Wrap()) - result, err = dp.ProcessSlowPath(tc.srcInterface, input, result.SlowPathRequest) - assert.NoError(t, err) - }) - } -} - func TestProcessPkt(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/router/export_test.go b/router/export_test.go index effd961c66..a80aafe28c 100644 --- a/router/export_test.go +++ b/router/export_test.go @@ -22,7 +22,6 @@ import ( "golang.org/x/net/ipv4" "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/slayers" "github.com/scionproto/scion/private/topology" ) @@ -102,20 +101,6 @@ func (d *DataPlane) ProcessSlowPath(ifID uint16, m *ipv4.Message, return ProcessResult{processResult: result}, err } -type SlowPathRequest struct { - Typ int - ScmpType slayers.SCMPType - Code slayers.SCMPCode -} - -func (s slowPathRequest) Wrap() SlowPathRequest { - return SlowPathRequest{ - Typ: int(s.typ), - ScmpType: s.scmpType, - Code: s.code, - } -} - func ExtractServices(s *services) map[addr.SVC][]*net.UDPAddr { return s.m }