Skip to content

Commit

Permalink
colibri: application level types requests (#3763)
Browse files Browse the repository at this point in the history
Add functions to convert between application level types and control messages from capnp.
  • Loading branch information
juagargi authored May 13, 2020
1 parent e99e9a3 commit 8ede270
Show file tree
Hide file tree
Showing 11 changed files with 721 additions and 204 deletions.
9 changes: 8 additions & 1 deletion go/cs/reservation/e2e/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,26 @@ go_library(
"//go/cs/reservation:go_default_library",
"//go/cs/reservation/segment:go_default_library",
"//go/lib/colibri/reservation:go_default_library",
"//go/lib/ctrl/colibri_mgmt:go_default_library",
"//go/lib/serrors:go_default_library",
"//go/proto:go_default_library",
],
)

go_test(
name = "go_default_test",
srcs = ["reservation_test.go"],
srcs = [
"request_test.go",
"reservation_test.go",
],
embed = [":go_default_library"],
deps = [
"//go/cs/reservation/segment:go_default_library",
"//go/cs/reservation/segmenttest:go_default_library",
"//go/lib/colibri/reservation:go_default_library",
"//go/lib/ctrl/colibri_mgmt:go_default_library",
"//go/lib/xtest:go_default_library",
"//go/proto:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
],
)
132 changes: 129 additions & 3 deletions go/cs/reservation/e2e/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,134 @@

package e2e

// "github.com/scionproto/scion/go/lib/colibri/reservation"
import (
"time"

type SetupReq struct {
//
"github.com/scionproto/scion/go/lib/colibri/reservation"
"github.com/scionproto/scion/go/lib/ctrl/colibri_mgmt"
"github.com/scionproto/scion/go/lib/serrors"
"github.com/scionproto/scion/go/proto"
)

// SetupReq is the interface for an e2e setup request.
// Currently it's implemented by either SuccessSetupReq or FailureSetupReq.
type SetupReq interface {
Reservation() *Reservation
Timestamp() time.Time
ToCtrlMsg() (*colibri_mgmt.E2ESetup, error)
}

// BaseSetupReq is the common part of any e2e setup request.
type BaseSetupReq struct {
reservation *Reservation
timestamp time.Time
}

func (r *BaseSetupReq) Timestamp() time.Time { return r.timestamp }
func (r *BaseSetupReq) Reservation() *Reservation { return r.reservation }

// SuccessSetupReq is a successful e2e resevation setup request.
type SuccessSetupReq struct {
BaseSetupReq
ID reservation.E2EID
Token reservation.Token
}

var _ SetupReq = (*SuccessSetupReq)(nil)

func (r *SuccessSetupReq) ToCtrlMsg() (*colibri_mgmt.E2ESetup, error) {
id := make([]byte, reservation.E2EIDLen)
_, err := r.ID.Read(id)
if err != nil {
return nil, err
}
token := make([]byte, r.Token.Len())
_, err = r.Token.Read(token)
if err != nil {
return nil, err
}
msg := &colibri_mgmt.E2ESetup{
Which: proto.E2ESetupData_Which_success,
Success: &colibri_mgmt.E2ESetupSuccess{
ReservationID: &colibri_mgmt.E2EReservationID{
ASID: id[:6],
Suffix: id[6:],
},
Token: token,
},
}
return msg, nil
}

// FailureSetupReq is a failing e2e resevation setup request.
type FailureSetupReq struct {
BaseSetupReq
ErrorCode int
InfoField reservation.InfoField
MaxBWTrail []reservation.BWCls
}

var _ SetupReq = (*FailureSetupReq)(nil)

func (r *FailureSetupReq) ToCtrlMsg() (*colibri_mgmt.E2ESetup, error) {
inf := make([]byte, reservation.InfoFieldLen)
_, err := r.InfoField.Read(inf)
if err != nil {
return nil, err
}
trail := make([]uint8, len(r.MaxBWTrail))
for i, bw := range r.MaxBWTrail {
trail[i] = uint8(bw)
}
msg := &colibri_mgmt.E2ESetup{
Which: proto.E2ESetupData_Which_failure,
Failure: &colibri_mgmt.E2ESetupFailure{
ErrorCode: uint8(r.ErrorCode),
InfoField: inf,
MaxBWs: trail,
},
}
return msg, nil
}

// NewRequestFromCtrlMsg will return a SuccessSetupReq or FailSetupReq depending on the
// success flag of the ctrl message.
func NewRequestFromCtrlMsg(setup *colibri_mgmt.E2ESetup, ts time.Time) (SetupReq, error) {
var s SetupReq
switch {
case setup.Success != nil:
id, err := reservation.E2EIDFromRawBuffers(setup.Success.ReservationID.ASID,
setup.Success.ReservationID.Suffix)
if err != nil {
return nil, err
}
tok, err := reservation.TokenFromRaw(setup.Success.Token)
if err != nil {
return nil, err
}
s = &SuccessSetupReq{
BaseSetupReq: BaseSetupReq{timestamp: ts},
ID: *id,
Token: *tok,
}
case setup.Failure != nil:
ifield, err := reservation.InfoFieldFromRaw(setup.Failure.InfoField)
if err != nil {
return nil, err
}
bwTrail := make([]reservation.BWCls, len(setup.Failure.MaxBWs))
for i, bw := range setup.Failure.MaxBWs {
bwTrail[i] = reservation.BWCls(bw)
}
s = &FailureSetupReq{
BaseSetupReq: BaseSetupReq{timestamp: ts},
ErrorCode: int(setup.Failure.ErrorCode),
InfoField: *ifield,
MaxBWTrail: bwTrail,
}
default:
return nil, serrors.New("invalid E2E setup request received, neither successful or failed",
"success_ptr", setup.Success, "failure_ptr", setup.Failure)
}
return s, nil
}
123 changes: 123 additions & 0 deletions go/cs/reservation/e2e/request_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2020 ETH Zurich, Anapaya Systems
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e_test

import (
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/scionproto/scion/go/cs/reservation/e2e"
"github.com/scionproto/scion/go/lib/colibri/reservation"
"github.com/scionproto/scion/go/lib/ctrl/colibri_mgmt"
"github.com/scionproto/scion/go/lib/xtest"
"github.com/scionproto/scion/go/proto"
)

func TestNewRequestFromCtrlMsg(t *testing.T) {
setup := newE2ESetupSuccess()
ts := time.Unix(1, 0)
r, err := e2e.NewRequestFromCtrlMsg(setup, ts)
require.NoError(t, err)
checkRequest(t, setup, r, ts)

setup = newE2ESetupFailure()
r, err = e2e.NewRequestFromCtrlMsg(setup, ts)
require.NoError(t, err)
checkRequest(t, setup, r, ts)
}

func TestRequestToCtrlMsg(t *testing.T) {
setup := newE2ESetupSuccess()
ts := time.Unix(1, 0)
r, _ := e2e.NewRequestFromCtrlMsg(setup, ts)
anotherSetup, err := r.ToCtrlMsg()
require.NoError(t, err)
require.Equal(t, setup, anotherSetup)

setup = newE2ESetupFailure()
r, _ = e2e.NewRequestFromCtrlMsg(setup, ts)
anotherSetup, err = r.ToCtrlMsg()
require.NoError(t, err)
require.Equal(t, setup, anotherSetup)
}

func newE2ESetupSuccess() *colibri_mgmt.E2ESetup {
return &colibri_mgmt.E2ESetup{
Which: proto.E2ESetupData_Which_success,
Success: &colibri_mgmt.E2ESetupSuccess{
ReservationID: &colibri_mgmt.E2EReservationID{
ASID: xtest.MustParseHexString("ff00cafe0001"),
Suffix: xtest.MustParseHexString("0123456789abcdef0123"),
},
Token: xtest.MustParseHexString("16ebdb4f0d042500003f001002bad1ce003f001002facade"),
},
}
}

func newE2ESetupFailure() *colibri_mgmt.E2ESetup {
return &colibri_mgmt.E2ESetup{
Which: proto.E2ESetupData_Which_failure,
Failure: &colibri_mgmt.E2ESetupFailure{
ErrorCode: 42,
InfoField: xtest.MustParseHexString("16ebdb4f0d042500"),
MaxBWs: []uint8{1, 2},
},
}
}

func checkRequest(t *testing.T, e2eSetup *colibri_mgmt.E2ESetup, r e2e.SetupReq, ts time.Time) {
var base *e2e.BaseSetupReq
var successSetup *e2e.SuccessSetupReq
var failureSetup *e2e.FailureSetupReq
switch s := r.(type) {
case *e2e.SuccessSetupReq:
base = &s.BaseSetupReq
successSetup = s
case *e2e.FailureSetupReq:
base = &s.BaseSetupReq
failureSetup = s
default:
require.FailNow(t, "invalid type for request", "request type: %T", r)
}

require.Equal(t, (*e2e.Reservation)(nil), base.Reservation())
require.Equal(t, ts, base.Timestamp())
if successSetup != nil {
buff := make([]byte, len(e2eSetup.Success.Token))
_, err := successSetup.Token.Read(buff)
require.NoError(t, err) // tested in the Token UT, should not fail
require.Equal(t, e2eSetup.Success.Token, buff)
buff = make([]byte, reservation.E2EIDLen)
_, err = successSetup.ID.Read(buff)
require.NoError(t, err) // tested in the E2EID UT, should not fail
require.Equal(t, e2eSetup.Success.ReservationID.ASID, buff[:6])
require.Equal(t, e2eSetup.Success.ReservationID.Suffix, buff[6:])
}
if failureSetup != nil {
require.Equal(t, int(e2eSetup.Failure.ErrorCode), failureSetup.ErrorCode)
buff := make([]byte, reservation.InfoFieldLen)
_, err := failureSetup.InfoField.Read(buff)
require.NoError(t, err) // tested in the InfoField UT, should not fail
require.Equal(t, e2eSetup.Failure.InfoField, buff)
trail := make([]uint8, len(failureSetup.MaxBWTrail))
for i := range trail {
trail[i] = uint8(failureSetup.MaxBWTrail[i])
}
require.Equal(t, e2eSetup.Failure.MaxBWs, trail)

}
}
4 changes: 4 additions & 0 deletions go/cs/reservation/segment/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ go_library(
"//go/lib/addr:go_default_library",
"//go/lib/colibri/reservation:go_default_library",
"//go/lib/common:go_default_library",
"//go/lib/ctrl/colibri_mgmt:go_default_library",
"//go/lib/serrors:go_default_library",
],
)
Expand All @@ -24,12 +25,15 @@ go_test(
srcs = [
"export_test.go",
"path_test.go",
"request_test.go",
"reservation_test.go",
],
embed = [":go_default_library"],
deps = [
"//go/cs/reservation/segmenttest:go_default_library",
"//go/lib/colibri/reservation:go_default_library",
"//go/lib/ctrl/colibri_mgmt:go_default_library",
"//go/lib/xtest:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
],
)
Loading

0 comments on commit 8ede270

Please sign in to comment.