From a19a018377522ec404f2660560e86170661aa819 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 3 Jun 2020 18:00:38 +0200 Subject: [PATCH 01/22] DB interface for storage --- go/cs/reservationstorage/backend/BUILD.bazel | 16 +++ go/cs/reservationstorage/backend/db.go | 112 +++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 go/cs/reservationstorage/backend/BUILD.bazel create mode 100644 go/cs/reservationstorage/backend/db.go diff --git a/go/cs/reservationstorage/backend/BUILD.bazel b/go/cs/reservationstorage/backend/BUILD.bazel new file mode 100644 index 0000000000..e680baf9e9 --- /dev/null +++ b/go/cs/reservationstorage/backend/BUILD.bazel @@ -0,0 +1,16 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["db.go"], + importpath = "github.com/scionproto/scion/go/cs/reservationstorage/backend", + visibility = ["//visibility:public"], + deps = [ + "//go/cs/reservation/e2e:go_default_library", + "//go/cs/reservation/segment:go_default_library", + "//go/lib/addr:go_default_library", + "//go/lib/colibri/reservation:go_default_library", + "//go/lib/common:go_default_library", + "//go/lib/infra/modules/db:go_default_library", + ], +) diff --git a/go/cs/reservationstorage/backend/db.go b/go/cs/reservationstorage/backend/db.go new file mode 100644 index 0000000000..00e0a744eb --- /dev/null +++ b/go/cs/reservationstorage/backend/db.go @@ -0,0 +1,112 @@ +// 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 backend + +import ( + "context" + "database/sql" + "io" + + "github.com/scionproto/scion/go/cs/reservation/e2e" + "github.com/scionproto/scion/go/cs/reservation/segment" + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/colibri/reservation" + "github.com/scionproto/scion/go/lib/common" + "github.com/scionproto/scion/go/lib/infra/modules/db" +) + +type SegmentRead interface { + // GetSegmentRsvFromID will return the reservation with that ID. + // If an IndexNumber is specified it will populate its indices with that one. + // If the ID is not found, or the index (if specified) is not found, an error will be returned. + GetSegmentRsvFromID(ctx context.Context, ID reservation.SegmentID, + idx *reservation.IndexNumber) (*segment.Reservation, error) + // GetSegmentRsvFromSrcDstAS returns all reservations that start at src AS and end in dst AS. + GetSegmentRsvFromSrcDstAS(ctx context.Context, srcAS, dstAS addr.IA) ( + []*segment.Reservation, error) + // GetSegmentRsvFromPath searches for a segment reservation with the specified path. + GetSegmentRsvFromPath(ctx context.Context, path *segment.Path) ( + *segment.Reservation, error) + // GetSegmentRsvsFromIFPair returns all segment reservations that enter this AS at + // the specified ingress and exit at that egress. + GetSegmentRsvsFromIFPair(ctx context.Context, ingress, egress common.IFIDType) ( + []*segment.Reservation, error) +} + +type SegmentWrite interface { + // NewSegmentRsv creates a new segment reservation in the DB, with an unused reservation ID. + // The created ID is set in the reservation pointer argument. + NewSegmentRsv(ctx context.Context, rsv *segment.Reservation) error + // SetActiveIndex updates the active index for the segment reservation. + SetSegmentActiveIndex(ctx context.Context, rsv segment.Reservation, + idx reservation.IndexNumber) error + // NewSegmentRsvIndex stores a new index for a segment reservation. + NewSegmentIndex(ctx context.Context, rsv *segment.Reservation, + idx reservation.IndexNumber) error + // UpdateSegmentRsvIndex updates an index of a segment reservation. + UpdateSegmentIndex(ctx context.Context, rsv *segment.Reservation, + idx reservation.IndexNumber) error + // DeleteExpiredIndices removes the index from the DB. Used in cleanup. + DeleteSegmentIndex(ctx context.Context, rsv *segment.Reservation, + idx reservation.IndexNumber) error + + // DeleteExpiredIndices will remove expired indices from the DB. If a reservation is left + // without any index after removing the expired ones, it will also be removed. + DeleteExpiredIndices(ctx context.Context) (int, error) + // DeleteExpiredIndices removes the segment reservation + DeleteSegmentRsv(ctx context.Context, ID reservation.SegmentID) error +} + +type E2ERead interface { + // GetE2ERsvFromID finds the end to end resevation given its ID. + GetE2ERsvFromID(ctx context.Context, ID reservation.E2EID, idx reservation.IndexNumber) ( + *e2e.Reservation, error) +} + +type E2EWrite interface { + // NewE2EIndex stores a new index in the DB. + // If the e2e reservation does not exist, it is created. + NewE2EIndex(ctx context.Context, rsv *e2e.Reservation, idx reservation.IndexNumber) error + // UpdateE2EIndex updates the token in an index of the e2e reservation. + UpdateE2EIndex(ctx context.Context, rsv *e2e.Reservation, idx reservation.IndexNumber) error + // DeleteE2EIndex removes an e2e index. It is used in the cleanup process. + DeleteE2EIndex(ctx context.Context, rsv *e2e.Reservation, idx reservation.IndexNumber) error +} + +// DBRead specifies the read operations a reservation storage must have. +type DBRead interface { + SegmentRead + E2ERead +} + +// DBWrite specifies the write operations a reservation storage must have. +type DBWrite interface { + SegmentWrite + E2EWrite +} + +type Transaction interface { + DBRead + DBWrite + Commit() error + Rollback() error +} + +// DB is the interface for any reservation backend. +type DB interface { + BeginTransaction(ctx context.Context, opts *sql.TxOptions) (Transaction, error) + db.LimitSetter + io.Closer +} From 233caf563a3c46f13e36830e6e008eda6a5adabc Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Mon, 8 Jun 2020 16:27:30 +0200 Subject: [PATCH 02/22] structure interfaces by usage --- go/cs/reservationstorage/backend/db.go | 70 +++++++++++++------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/go/cs/reservationstorage/backend/db.go b/go/cs/reservationstorage/backend/db.go index 00e0a744eb..29245cd02d 100644 --- a/go/cs/reservationstorage/backend/db.go +++ b/go/cs/reservationstorage/backend/db.go @@ -27,55 +27,59 @@ import ( "github.com/scionproto/scion/go/lib/infra/modules/db" ) -type SegmentRead interface { - // GetSegmentRsvFromID will return the reservation with that ID. - // If an IndexNumber is specified it will populate its indices with that one. - // If the ID is not found, or the index (if specified) is not found, an error will be returned. - GetSegmentRsvFromID(ctx context.Context, ID reservation.SegmentID, - idx *reservation.IndexNumber) (*segment.Reservation, error) +// ReserverOnly has the methods available to the AS that starts the reservation. +type ReserverOnly interface { // GetSegmentRsvFromSrcDstAS returns all reservations that start at src AS and end in dst AS. GetSegmentRsvFromSrcDstAS(ctx context.Context, srcAS, dstAS addr.IA) ( []*segment.Reservation, error) // GetSegmentRsvFromPath searches for a segment reservation with the specified path. GetSegmentRsvFromPath(ctx context.Context, path *segment.Path) ( *segment.Reservation, error) + + // NewSegmentRsv creates a new segment reservation in the DB, with an unused reservation ID. + // The created ID is set in the reservation pointer argument. Used by setup req. + NewSegmentRsv(ctx context.Context, rsv *segment.Reservation) error +} + +// TransitOnly represents an AS in-path of a reservation, not the one originating it. +type TransitOnly interface { // GetSegmentRsvsFromIFPair returns all segment reservations that enter this AS at - // the specified ingress and exit at that egress. + // the specified ingress and exit at that egress. Used by setup req. GetSegmentRsvsFromIFPair(ctx context.Context, ingress, egress common.IFIDType) ( []*segment.Reservation, error) } -type SegmentWrite interface { - // NewSegmentRsv creates a new segment reservation in the DB, with an unused reservation ID. - // The created ID is set in the reservation pointer argument. - NewSegmentRsv(ctx context.Context, rsv *segment.Reservation) error - // SetActiveIndex updates the active index for the segment reservation. +// ReserverAndTransit contains the functionallity for any AS that has a COLIBRI service. +type ReserverAndTransit interface { + // GetSegmentRsvFromID will return the reservation with that ID. + // If an IndexNumber is specified it will populate its indices only with that one. + // If the ID is not found, or the index (if specified) is not found, an error will be returned. + // Used by setup/renew req/resp. and any request. + GetSegmentRsvFromID(ctx context.Context, ID reservation.SegmentID, + idx *reservation.IndexNumber) (*segment.Reservation, error) + // SetActiveIndex updates the active index. Used in index confirmation. SetSegmentActiveIndex(ctx context.Context, rsv segment.Reservation, idx reservation.IndexNumber) error - // NewSegmentRsvIndex stores a new index for a segment reservation. + // NewSegmentRsvIndex stores a new index for a segment reservation. Used in setup/renew. NewSegmentIndex(ctx context.Context, rsv *segment.Reservation, idx reservation.IndexNumber) error - // UpdateSegmentRsvIndex updates an index of a segment reservation. + // UpdateSegmentRsvIndex updates an index of a segment rsv. Used in setup/renew response. UpdateSegmentIndex(ctx context.Context, rsv *segment.Reservation, idx reservation.IndexNumber) error - // DeleteExpiredIndices removes the index from the DB. Used in cleanup. + // DeleteSegmentIndex removes the index from the DB. Used in cleanup. DeleteSegmentIndex(ctx context.Context, rsv *segment.Reservation, idx reservation.IndexNumber) error + // DeleteExpiredIndices removes the segment reservation. Used in teardown. + DeleteSegmentRsv(ctx context.Context, ID reservation.SegmentID) error // DeleteExpiredIndices will remove expired indices from the DB. If a reservation is left // without any index after removing the expired ones, it will also be removed. + // Used on schedule. DeleteExpiredIndices(ctx context.Context) (int, error) - // DeleteExpiredIndices removes the segment reservation - DeleteSegmentRsv(ctx context.Context, ID reservation.SegmentID) error -} -type E2ERead interface { // GetE2ERsvFromID finds the end to end resevation given its ID. GetE2ERsvFromID(ctx context.Context, ID reservation.E2EID, idx reservation.IndexNumber) ( *e2e.Reservation, error) -} - -type E2EWrite interface { // NewE2EIndex stores a new index in the DB. // If the e2e reservation does not exist, it is created. NewE2EIndex(ctx context.Context, rsv *e2e.Reservation, idx reservation.IndexNumber) error @@ -85,21 +89,10 @@ type E2EWrite interface { DeleteE2EIndex(ctx context.Context, rsv *e2e.Reservation, idx reservation.IndexNumber) error } -// DBRead specifies the read operations a reservation storage must have. -type DBRead interface { - SegmentRead - E2ERead -} - -// DBWrite specifies the write operations a reservation storage must have. -type DBWrite interface { - SegmentWrite - E2EWrite -} - type Transaction interface { - DBRead - DBWrite + ReserverOnly + TransitOnly + ReserverAndTransit Commit() error Rollback() error } @@ -107,6 +100,11 @@ type Transaction interface { // DB is the interface for any reservation backend. type DB interface { BeginTransaction(ctx context.Context, opts *sql.TxOptions) (Transaction, error) + + ReserverOnly + TransitOnly + ReserverAndTransit + db.LimitSetter io.Closer } From 4b55f1653b5e097230611732554917941b60dd84 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 10 Jun 2020 10:00:51 +0200 Subject: [PATCH 03/22] fix mispelling --- go/cs/reservationstorage/backend/db.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/cs/reservationstorage/backend/db.go b/go/cs/reservationstorage/backend/db.go index 29245cd02d..8c0db34bc1 100644 --- a/go/cs/reservationstorage/backend/db.go +++ b/go/cs/reservationstorage/backend/db.go @@ -49,7 +49,7 @@ type TransitOnly interface { []*segment.Reservation, error) } -// ReserverAndTransit contains the functionallity for any AS that has a COLIBRI service. +// ReserverAndTransit contains the functionality for any AS that has a COLIBRI service. type ReserverAndTransit interface { // GetSegmentRsvFromID will return the reservation with that ID. // If an IndexNumber is specified it will populate its indices only with that one. From 54933d753fd5a62f0396f2ae1d902ea809f57037 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Mon, 8 Jun 2020 16:03:04 +0200 Subject: [PATCH 04/22] schema --- .../reservationdbsqlite/BUILD.bazel | 18 ++ go/cs/reservation/reservationdbsqlite/db.go | 205 ++++++++++++++++++ .../reservation/reservationdbsqlite/schema.go | 76 +++++++ go/cs/reservation/segment/reservation.go | 27 ++- go/cs/reservation/segment/reservation_test.go | 2 +- 5 files changed, 318 insertions(+), 10 deletions(-) create mode 100644 go/cs/reservation/reservationdbsqlite/BUILD.bazel create mode 100644 go/cs/reservation/reservationdbsqlite/db.go create mode 100644 go/cs/reservation/reservationdbsqlite/schema.go diff --git a/go/cs/reservation/reservationdbsqlite/BUILD.bazel b/go/cs/reservation/reservationdbsqlite/BUILD.bazel new file mode 100644 index 0000000000..743524f7a7 --- /dev/null +++ b/go/cs/reservation/reservationdbsqlite/BUILD.bazel @@ -0,0 +1,18 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["db.go"], + importpath = "github.com/scionproto/scion/go/cs/reservation/reservationdbsqlite", + visibility = ["//visibility:public"], + deps = [ + "//go/cs/reservation/e2e:go_default_library", + "//go/cs/reservation/segment:go_default_library", + "//go/cs/reservationstorage/backend:go_default_library", + "//go/lib/addr:go_default_library", + "//go/lib/colibri/reservation:go_default_library", + "//go/lib/common:go_default_library", + "//go/lib/infra/modules/db:go_default_library", + "@com_github_mattn_go_sqlite3//:go_default_library", + ], +) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go new file mode 100644 index 0000000000..d31d3607c5 --- /dev/null +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -0,0 +1,205 @@ +// 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 reservationdbsqlite + +import ( + "context" + "database/sql" + "sync" + + _ "github.com/mattn/go-sqlite3" + + "github.com/scionproto/scion/go/cs/reservation/e2e" + "github.com/scionproto/scion/go/cs/reservation/segment" + "github.com/scionproto/scion/go/cs/reservationstorage/backend" + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/colibri/reservation" + "github.com/scionproto/scion/go/lib/common" + "github.com/scionproto/scion/go/lib/infra/modules/db" +) + +type Backend struct { + *executor + db *sql.DB +} + +var _ backend.DB = (*Backend)(nil) + +func New(path string) (*Backend, error) { + // TODO(juagargi) + return nil, nil +} + +// SetMaxOpenConns sets the maximum number of open connections. +func (b *Backend) SetMaxOpenConns(maxOpenConns int) { + b.db.SetMaxOpenConns(maxOpenConns) +} + +// SetMaxIdleConns sets the maximum number of idle connections. +func (b *Backend) SetMaxIdleConns(maxIdleConns int) { + b.db.SetMaxIdleConns(maxIdleConns) +} + +func (b *Backend) BeginTransaction(ctx context.Context, opts *sql.TxOptions) ( + backend.Transaction, error) { + + b.Lock() + defer b.Unlock() + tx, err := b.db.BeginTx(ctx, opts) + if err != nil { + return nil, db.NewTxError("create tx", err) + } + return &transaction{ + executor: &executor{ + db: tx, + }, + tx: tx, + }, nil +} + +func (b *Backend) Close() error { + // TODO(juagargi) + return nil +} + +type transaction struct { + *executor + tx *sql.Tx +} + +var _ backend.Transaction = (*transaction)(nil) + +func (t *transaction) Commit() error { + t.Lock() + defer t.Unlock() + return t.tx.Commit() +} + +func (t *transaction) Rollback() error { + t.Lock() + defer t.Unlock() + return t.tx.Rollback() +} + +type executor struct { + sync.RWMutex + db db.Sqler +} + +func (x *executor) GetSegmentRsvFromID(ctx context.Context, ID reservation.SegmentID, + idx *reservation.IndexNumber) (*segment.Reservation, error) { + + return nil, nil +} + +// GetSegmentRsvFromSrcDstAS returns all reservations that start at src AS and end in dst AS. +func (x *executor) GetSegmentRsvFromSrcDstAS(ctx context.Context, srcAS, dstAS addr.IA) ( + []*segment.Reservation, error) { + + x.Lock() + defer x.Unlock() + // query := "SELECT " + return nil, nil +} + +// GetSegmentRsvFromPath searches for a segment reservation with the specified path. +func (x *executor) GetSegmentRsvFromPath(ctx context.Context, path *segment.Path) ( + *segment.Reservation, error) { + + return nil, nil +} + +// GetSegmentRsvsFromIFPair returns all segment reservations that enter this AS at +// the specified ingress and exit at that egress. +func (x *executor) GetSegmentRsvsFromIFPair(ctx context.Context, ingress, egress common.IFIDType) ( + []*segment.Reservation, error) { + + return nil, nil +} + +// NewSegmentRsv creates a new segment reservation in the DB, with an unused reservation ID. +// The created ID is set in the reservation pointer argument. +func (x *executor) NewSegmentRsv(ctx context.Context, rsv *segment.Reservation) error { + return nil +} + +// SetActiveIndex updates the active index for the segment reservation. +func (x *executor) SetSegmentActiveIndex(ctx context.Context, rsv segment.Reservation, + idx reservation.IndexNumber) error { + + return nil +} + +// NewSegmentRsvIndex stores a new index for a segment reservation. +func (x *executor) NewSegmentIndex(ctx context.Context, rsv *segment.Reservation, + idx reservation.IndexNumber) error { + + return nil +} + +// UpdateSegmentRsvIndex updates an index of a segment reservation. +func (x *executor) UpdateSegmentIndex(ctx context.Context, rsv *segment.Reservation, + idx reservation.IndexNumber) error { + + return nil +} + +// DeleteExpiredIndices removes the index from the DB. Used in cleanup. +func (x *executor) DeleteSegmentIndex(ctx context.Context, rsv *segment.Reservation, + idx reservation.IndexNumber) error { + + return nil +} + +// DeleteExpiredIndices will remove expired indices from the DB. If a reservation is left +// without any index after removing the expired ones, it will also be removed. +func (x *executor) DeleteExpiredIndices(ctx context.Context) (int, error) { + return 0, nil +} + +// DeleteExpiredIndices removes the segment reservation +func (x *executor) DeleteSegmentRsv(ctx context.Context, ID reservation.SegmentID) error { + return nil +} + +// GetE2ERsvFromID finds the end to end resevation given its ID. +func (x *executor) GetE2ERsvFromID(ctx context.Context, ID reservation.E2EID, + idx reservation.IndexNumber) (*e2e.Reservation, error) { + + return nil, nil +} + +// NewE2EIndex stores a new index in the DB. +// If the e2e reservation does not exist, it is created. +func (x *executor) NewE2EIndex(ctx context.Context, rsv *e2e.Reservation, + idx reservation.IndexNumber) error { + + return nil +} + +// UpdateE2EIndex updates the token in an index of the e2e reservation. +func (x *executor) UpdateE2EIndex(ctx context.Context, rsv *e2e.Reservation, + idx reservation.IndexNumber) error { + + return nil + +} + +// DeleteE2EIndex removes an e2e index. It is used in the cleanup process. +func (x *executor) DeleteE2EIndex(ctx context.Context, rsv *e2e.Reservation, + idx reservation.IndexNumber) error { + + return nil +} diff --git a/go/cs/reservation/reservationdbsqlite/schema.go b/go/cs/reservation/reservationdbsqlite/schema.go new file mode 100644 index 0000000000..c682f1afb6 --- /dev/null +++ b/go/cs/reservation/reservationdbsqlite/schema.go @@ -0,0 +1,76 @@ +// 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 reservationdbsqlite + +const ( + // SchemaVersion is the version of the SQLite schema understood by this backend. + // Whenever changes to the schema are made, this version number should be increased + // to prevent data corruption between incompatible database schemas. + SchemaVersion = 1 + // Schema is the SQLite database layout. + // TODO(juagargi) explain the DB structure here or in the design markdown. + // TODO(juagargi) create appropriate SQL indices. + Schema = ` + + CREATE TABLE "seg_reservation" ( + "row_id" INTEGER, + "reservation_id" BLOB NOT NULL, + "inout_ingress" INTEGER NOT NULL, + "inout_egress" INTEGER NOT NULL, + "path" BLOB NOT NULL, + "src_as" INTEGER NOT NULL, + "dst_as" INTEGER NOT NULL, + PRIMARY KEY("row_id") + ); + + CREATE TABLE "seg_index" ( + "reservation" INTEGER NOT NULL, + "index_number" INTEGER NOT NULL, + "expiration" INTEGER NOT NULL, + "state" INTEGER NOT NULL, + "min_bw" INTEGER NOT NULL, + "max_bw" INTEGER NOT NULL, + "alloc_bw" INTEGER NOT NULL, + "token" BLOB, + PRIMARY KEY("Reservation","index_number"), + FOREIGN KEY("reservation") REFERENCES "seg_reservation"("row_id") ON DELETE CASCADE + ); + + CREATE TABLE "e2e_reservation" ( + "row_id" INTEGER, + "reservation_id" BLOB NOT NULL, + PRIMARY KEY("row_id") + ); + + CREATE TABLE "e2e_index" ( + "reservation" INTEGER NOT NULL, + "index_number" INTEGER NOT NULL, + "expiration" INTEGER NOT NULL, + "alloc_bw" INTEGER NOT NULL, + "token" BLOB NOT NULL, + FOREIGN KEY("reservation") REFERENCES "e2e_reservation"("row_id") ON DELETE CASCADE + ); + + CREATE TABLE "e2e_to_seg" ( + "e2e" INTEGER NOT NULL, + "seg" INTEGER NOT NULL, + FOREIGN KEY("seg") REFERENCES "seg_reservation"("row_id") ON DELETE CASCADE, + FOREIGN KEY("e2e") REFERENCES "e2e_reservation"("row_id") ON DELETE CASCADE + ); + + + + ` +) diff --git a/go/cs/reservation/segment/reservation.go b/go/cs/reservation/segment/reservation.go index 18c3715a7f..81e658c698 100644 --- a/go/cs/reservation/segment/reservation.go +++ b/go/cs/reservation/segment/reservation.go @@ -24,11 +24,13 @@ import ( // Reservation represents a segment reservation. type Reservation struct { - ID reservation.SegmentID - Indices Indices // existing indices in this reservation - activeIndex int // -1 <= activeIndex < len(Indices) - PathStep PathStep // Ingress and Egress interfaces - Path *Path // nil if this AS is not at the source of the reservation + ID reservation.SegmentID + Indices Indices // existing indices in this reservation + activeIndex int // -1 <= activeIndex < len(Indices) + InOutIFIDs PathStep // Ingress and Egress interfaces + Path *Path // nil if this AS is not at the source of the reservation + PathEndProps reservation.PathEndProps // the properties for stitching and start/end + TrafficSplit reservation.SplitCls // the traffic split between control and data planes } func NewReservation() *Reservation { @@ -62,16 +64,23 @@ func (r *Reservation) Validate() error { } var err error if r.Path != nil { - if r.PathStep.Ingress != 0 { + if r.InOutIFIDs.Ingress != 0 { return serrors.New("reservation starts in this AS but ingress interface is not zero", - "ingress_if", r.PathStep.Ingress) + "ingress_if", r.InOutIFIDs.Ingress) // TODO(juagargi) test } err = r.Path.Validate() - } else if r.PathStep.Ingress == 0 { + } else if r.InOutIFIDs.Ingress == 0 { return serrors.New("reservation does not start in this AS but ingress interface is zero") } - return err + if err != nil { + return serrors.WrapStr("validating reservation, path failed", err) + } + err = r.PathEndProps.Validate() + if err != nil { + return serrors.WrapStr("validating reservation, end properties failed", err) + } + return nil } // ActiveIndex returns the currently active Index for this reservation, or nil if none. diff --git a/go/cs/reservation/segment/reservation_test.go b/go/cs/reservation/segment/reservation_test.go index 1e9e851a02..9a0ee0f3d5 100644 --- a/go/cs/reservation/segment/reservation_test.go +++ b/go/cs/reservation/segment/reservation_test.go @@ -165,7 +165,7 @@ func TestReservationValidate(t *testing.T) { // starts in this AS but ingress nonzero r = segmenttest.NewReservation() - r.PathStep.Ingress = 1 + r.InOutIFIDs.Ingress = 1 err = r.Validate() require.Error(t, err) From cfc524a9aef9bd1347194cfcdb0db705908ba055 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 10 Jun 2020 10:49:36 +0200 Subject: [PATCH 05/22] implementing DB methods, get --- go/cs/reservation/reservationdbsqlite/db.go | 17 +++++++++++++++-- go/cs/reservationstorage/backend/db.go | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index d31d3607c5..78ff1442a8 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -105,12 +105,25 @@ func (x *executor) GetSegmentRsvFromID(ctx context.Context, ID reservation.Segme } // GetSegmentRsvFromSrcDstAS returns all reservations that start at src AS and end in dst AS. -func (x *executor) GetSegmentRsvFromSrcDstAS(ctx context.Context, srcAS, dstAS addr.IA) ( +func (x *executor) GetSegmentRsvFromSrcDstAS(ctx context.Context, srcIA, dstIA addr.IA) ( []*segment.Reservation, error) { x.Lock() defer x.Unlock() - // query := "SELECT " + + query := `SELECT r.reservation_id, r.inout_ingress, r.inout_egress + FROM seg_reservation r + WHERE r.src_as = ?1 AND r.dst_as = ?2` + rows, err := x.db.QueryContext(ctx, query, srcIA.IAInt(), dstIA.IAInt()) + if err != nil { + return nil, db.NewReadError("error obtaining segment reservations", err) + } + defer rows.Close() + for rows.Next() { + if err := rows.Scan(); err != nil { + return nil, db.NewReadError("error reading segment reservation", err) + } + } return nil, nil } diff --git a/go/cs/reservationstorage/backend/db.go b/go/cs/reservationstorage/backend/db.go index 8c0db34bc1..3aebe5b361 100644 --- a/go/cs/reservationstorage/backend/db.go +++ b/go/cs/reservationstorage/backend/db.go @@ -30,7 +30,7 @@ import ( // ReserverOnly has the methods available to the AS that starts the reservation. type ReserverOnly interface { // GetSegmentRsvFromSrcDstAS returns all reservations that start at src AS and end in dst AS. - GetSegmentRsvFromSrcDstAS(ctx context.Context, srcAS, dstAS addr.IA) ( + GetSegmentRsvFromSrcDstAS(ctx context.Context, srcIA, dstIA addr.IA) ( []*segment.Reservation, error) // GetSegmentRsvFromPath searches for a segment reservation with the specified path. GetSegmentRsvFromPath(ctx context.Context, path *segment.Path) ( From 55be3d514c907c1761ffb3658598ad52aa0ae08c Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 10 Jun 2020 14:57:47 +0200 Subject: [PATCH 06/22] extend segment.Path to ease DB io --- go/cs/reservation/segment/path.go | 87 +++++++++++++++++++++++++- go/cs/reservation/segment/path_test.go | 40 ++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index 0c45feb198..64a56a94c3 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -15,6 +15,8 @@ package segment import ( + "io" + "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/serrors" @@ -23,6 +25,22 @@ import ( // Path represents a reservation path, in the reservation order. type Path []PathStepWithIA +var _ io.Reader = (*Path)(nil) + +// NewPathFromRaw constructs a new Path from the byte representation. +func NewPathFromRaw(buff []byte) Path { + steps := len(buff) / PathStepWithIALen + p := make(Path, steps) + for i := 0; i < steps; i++ { + offset := i * PathStepWithIALen + p[i].Ingress = common.IFIDType(common.Order.Uint64(buff[offset:])) + p[i].Egress = common.IFIDType(common.Order.Uint64(buff[offset+8:])) + p[i].IA = addr.IAFromRaw(buff[offset+16:]) + } + return p +} + +// Validate returns an error if there is invalid data. func (p Path) Validate() error { if len(p) < 2 { return serrors.New("invalid path length", "len", len(p)) @@ -37,6 +55,7 @@ func (p Path) Validate() error { return nil } +// Equal returns true if both Path contain the same values. func (p Path) Equal(o Path) bool { if len(p) != len(o) { return false @@ -49,23 +68,87 @@ func (p Path) Equal(o Path) bool { return true } +// GetSrcIA returns the source IA in the path or a zero IA if the path is nil (it's not the +// source AS of the reservation and has no access to the Path of the reservation). +// If the Path is not nil, it assumes is valid, i.e. it has at least length 2. +func (p *Path) GetSrcIA() addr.IA { + if p == nil { + return addr.IA{I: 0, A: 0} + } + return (*p)[0].IA +} + +// GetDstIA returns the source IA in the path or a zero IA if the path is nil (it's not the +// source AS of the reservation and has no access to the Path of the reservation). +// If the Path is not nil, it assumes is valid, i.e. it has at least length 2. +func (p *Path) GetDstIA() addr.IA { + if p == nil { + return addr.IA{I: 0, A: 0} + } + return (*p)[len(*p)-1].IA +} + +// Len returns the length of this Path in bytes, when serialized. +func (p *Path) Len() int { + if p == nil { + return 0 + } + return len(*p) * PathStepWithIALen +} + +func (p *Path) Read(buff []byte) (int, error) { + if p == nil { + return 0, nil + } + if len(buff) < p.Len() { + return 0, serrors.New("buffer too small", "min_size", p.Len(), "actual_size", len(buff)) + } + for i, s := range *p { + offset := i * PathStepWithIALen + common.Order.PutUint64(buff[offset:], uint64(s.Ingress)) + common.Order.PutUint64(buff[offset+8:], uint64(s.Egress)) + common.Order.PutUint64(buff[offset+16:], uint64(s.IA.IAInt())) + } + return p.Len(), nil +} + +// ToRaw returns a buffer representing this Path. +func (p *Path) ToRaw() []byte { + if p == nil { + return []byte{} + } + buff := make([]byte, p.Len()) + p.Read(buff) + return buff +} + // PathStep is one hop of the Path. For a source AS Ingress will be invalid. Conversely for dst. type PathStep struct { - // IA addr.IA Ingress common.IFIDType Egress common.IFIDType } +// Equal returns true if both PathStep variables contain the same values, or both nil. func (s *PathStep) Equal(o *PathStep) bool { - // return s.IA == o.IA && s.Ingress == o.Ingress && s.Egress == o.Egress + if s == o { + return true + } return s.Ingress == o.Ingress && s.Egress == o.Egress } +// PathStepWithIA is a step in a reservation path as seen from the source AS. type PathStepWithIA struct { PathStep IA addr.IA } +// PathStepWithIALen amounts for Ingress+Egress+IA. +const PathStepWithIALen = 8 + 8 + 8 + +// Equal returns true if both PathStep variables contain the same values, or both nil. func (s *PathStepWithIA) Equal(o *PathStepWithIA) bool { + if s == o { + return true + } return s.PathStep.Equal(&o.PathStep) && s.IA == o.IA } diff --git a/go/cs/reservation/segment/path_test.go b/go/cs/reservation/segment/path_test.go index 8d9c22764a..3d5b336633 100644 --- a/go/cs/reservation/segment/path_test.go +++ b/go/cs/reservation/segment/path_test.go @@ -21,6 +21,7 @@ import ( "github.com/scionproto/scion/go/cs/reservation/segment" "github.com/scionproto/scion/go/cs/reservation/segmenttest" + "github.com/scionproto/scion/go/lib/xtest" ) func TestValidatePath(t *testing.T) { @@ -104,3 +105,42 @@ func TestEqualPath(t *testing.T) { }) } } + +func TestGetIAs(t *testing.T) { + + pValue := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) + p := &pValue + require.Equal(t, xtest.MustParseIA("1-ff00:0:1"), p.GetSrcIA()) + require.Equal(t, xtest.MustParseIA("1-ff00:0:2"), p.GetDstIA()) + p = nil + require.Equal(t, xtest.MustParseIA("0-0"), p.GetSrcIA()) + require.Equal(t, xtest.MustParseIA("0-0"), p.GetDstIA()) +} + +func TestPathLen(t *testing.T) { + p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) + require.Equal(t, 8*6, p.Len()) + p = segment.Path{} + require.Equal(t, 0, p.Len()) + p = nil + require.Equal(t, 0, p.Len()) +} + +func TestToFromBinary(t *testing.T) { + p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) + var buff []byte + _, err := p.Read(buff) + require.Error(t, err) + _, err = p.Read(buff) + require.Error(t, err) + buff = make([]byte, 2*3*8) + c, err := p.Read(buff) + require.NoError(t, err) + require.Equal(t, 2*3*8, c) + + anotherP := segment.NewPathFromRaw(buff) + require.Equal(t, p, anotherP) + + anotherBuff := p.ToRaw() + require.Equal(t, buff, anotherBuff) +} From 90f7d9b22f4ec8d78365bf69fb858e7053e68ee0 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 11 Jun 2020 17:27:06 +0200 Subject: [PATCH 07/22] schema and implementing sqlite methods --- .../reservationdbsqlite/BUILD.bazel | 19 ++- go/cs/reservation/reservationdbsqlite/db.go | 73 ++++++++++- .../reservationdbsqlite/db_test.go | 116 ++++++++++++++++++ .../reservation/reservationdbsqlite/schema.go | 86 ++++++------- .../reservation/reservationdbtest/BUILD.bazel | 15 +++ .../reservationdbtest/reservationdbtest.go | 56 +++++++++ go/cs/reservationstorage/backend/db.go | 2 - 7 files changed, 311 insertions(+), 56 deletions(-) create mode 100644 go/cs/reservation/reservationdbsqlite/db_test.go create mode 100644 go/cs/reservation/reservationdbtest/BUILD.bazel create mode 100644 go/cs/reservation/reservationdbtest/reservationdbtest.go diff --git a/go/cs/reservation/reservationdbsqlite/BUILD.bazel b/go/cs/reservation/reservationdbsqlite/BUILD.bazel index 743524f7a7..5c8e62bc86 100644 --- a/go/cs/reservation/reservationdbsqlite/BUILD.bazel +++ b/go/cs/reservation/reservationdbsqlite/BUILD.bazel @@ -1,8 +1,11 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = ["db.go"], + srcs = [ + "db.go", + "schema.go", + ], importpath = "github.com/scionproto/scion/go/cs/reservation/reservationdbsqlite", visibility = ["//visibility:public"], deps = [ @@ -13,6 +16,18 @@ go_library( "//go/lib/colibri/reservation:go_default_library", "//go/lib/common:go_default_library", "//go/lib/infra/modules/db:go_default_library", + "//go/lib/serrors:go_default_library", "@com_github_mattn_go_sqlite3//:go_default_library", ], ) + +go_test( + name = "go_default_test", + srcs = ["db_test.go"], + embed = [":go_default_library"], + deps = [ + "//go/cs/reservation/reservationdbtest:go_default_library", + "//go/lib/xtest:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index 78ff1442a8..86122e4ba3 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -19,6 +19,7 @@ import ( "database/sql" "sync" + "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3" "github.com/scionproto/scion/go/cs/reservation/e2e" @@ -28,6 +29,7 @@ import ( "github.com/scionproto/scion/go/lib/colibri/reservation" "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/infra/modules/db" + "github.com/scionproto/scion/go/lib/serrors" ) type Backend struct { @@ -37,9 +39,20 @@ type Backend struct { var _ backend.DB = (*Backend)(nil) +// New returns a new SQLite backend opening a database at the given path. If +// no database exists a new database is be created. If the schema version of the +// stored database is different from the one in schema.go, an error is returned. func New(path string) (*Backend, error) { - // TODO(juagargi) - return nil, nil + db, err := db.NewSqlite(path, Schema, SchemaVersion) + if err != nil { + return nil, err + } + return &Backend{ + executor: &executor{ + db: db, + }, + db: db, + }, nil } // SetMaxOpenConns sets the maximum number of open connections. @@ -52,6 +65,7 @@ func (b *Backend) SetMaxIdleConns(maxIdleConns int) { b.db.SetMaxIdleConns(maxIdleConns) } +// BeginTransaction begins a transaction on the database. func (b *Backend) BeginTransaction(ctx context.Context, opts *sql.TxOptions) ( backend.Transaction, error) { @@ -69,9 +83,9 @@ func (b *Backend) BeginTransaction(ctx context.Context, opts *sql.TxOptions) ( }, nil } +// Close closes the databse. func (b *Backend) Close() error { - // TODO(juagargi) - return nil + return b.db.Close() } type transaction struct { @@ -142,10 +156,41 @@ func (x *executor) GetSegmentRsvsFromIFPair(ctx context.Context, ingress, egress return nil, nil } +func insertNewSegReservation(ctx context.Context, x db.Sqler, rsv *segment.Reservation, + suffix uint32) error { + const query = `INSERT INTO seg_reservation (id_as, id_suffix, inout_ingress ,inout_egress, + path, src_as, dst_as) VALUES ($1, $2, $3, $4, $5, $6, $7)` + _, err := x.ExecContext(ctx, query, rsv.Path.GetSrcIA().A, suffix, + rsv.InOutIFIDs.Ingress, rsv.InOutIFIDs.Egress, + rsv.Path.ToRaw(), rsv.Path.GetSrcIA().IAInt(), rsv.Path.GetDstIA().IAInt()) + return err +} + // NewSegmentRsv creates a new segment reservation in the DB, with an unused reservation ID. // The created ID is set in the reservation pointer argument. func (x *executor) NewSegmentRsv(ctx context.Context, rsv *segment.Reservation) error { - return nil + var err error + for retries := 0; retries < 3; retries++ { + err = db.DoInTx(ctx, x.db, func(ctx context.Context, tx *sql.Tx) error { + suffix, err := newSuffix(ctx, tx, rsv.ID.ASID) + if err != nil { + return err + } + if err := insertNewSegReservation(ctx, tx, rsv, suffix); err != nil { + return err + } + common.Order.PutUint32(rsv.ID.Suffix[:], suffix) + return nil + }) + if err == nil { + return nil + } + sqliteError, ok := err.(sqlite3.Error) + if !ok || sqliteError.Code != sqlite3.ErrConstraint { + return db.NewTxError("error inserting segment reservation", err) + } + } + return db.NewTxError("error inserting segment reservation after 3 retries", err) } // SetActiveIndex updates the active index for the segment reservation. @@ -216,3 +261,21 @@ func (x *executor) DeleteE2EIndex(ctx context.Context, rsv *e2e.Reservation, return nil } + +// newSuffix finds a segment reservation ID suffix not being used at the moment. Should be called +// inside a transaction so the suffix is not used in the meantime, or fail. +func newSuffix(ctx context.Context, x db.Sqler, ASID addr.AS) (uint32, error) { + query := `SELECT MIN(id_suffix)+1 FROM ( + SELECT 0 AS id_suffix UNION ALL + SELECT id_suffix FROM seg_reservation WHERE id_as = $1 + ) WHERE id_suffix+1 NOT IN (SELECT id_suffix FROM seg_reservation WHERE id_as = $1);` + var suffix uint32 + err := x.QueryRowContext(ctx, query, uint64(ASID)).Scan(&suffix) + switch { + case err == sql.ErrNoRows: + return 0, serrors.New("unexpected error getting new suffix: no rows") + case err != nil: + return 0, serrors.WrapStr("unexpected error getting new suffix", err) + } + return suffix, nil +} diff --git a/go/cs/reservation/reservationdbsqlite/db_test.go b/go/cs/reservation/reservationdbsqlite/db_test.go new file mode 100644 index 0000000000..2df5f3ac01 --- /dev/null +++ b/go/cs/reservation/reservationdbsqlite/db_test.go @@ -0,0 +1,116 @@ +// 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 reservationdbsqlite + +import ( + "context" + "testing" + + "github.com/mattn/go-sqlite3" + "github.com/scionproto/scion/go/cs/reservation/reservationdbtest" + "github.com/scionproto/scion/go/cs/reservation/segment" + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/colibri/reservation" + "github.com/scionproto/scion/go/lib/xtest" + "github.com/stretchr/testify/require" +) + +type TestDB struct { + *Backend +} + +func (b *TestDB) Prepare(t *testing.T, _ context.Context) { + b.Backend = newDB(t) +} + +func TestReservationDBSuite(t *testing.T) { + db := &TestDB{} + reservationdbtest.TestDB(t, db) +} + +func TestNewSuffix(t *testing.T) { + ctx := context.Background() + asid := xtest.MustParseAS("ff00:0:1") + db := newDB(t) + suffix, err := newSuffix(ctx, db.db, asid) + require.NoError(t, err) + require.Equal(t, uint32(1), suffix) + // add reservations + addSegRsvRows(t, db, asid, 3, 5) + suffix, err = newSuffix(ctx, db.db, asid) + require.NoError(t, err) + require.Equal(t, uint32(1), suffix) + addSegRsvRows(t, db, asid, 1, 2) + suffix, err = newSuffix(ctx, db.db, asid) + require.NoError(t, err) + require.Equal(t, uint32(6), suffix) +} + +func TestRaceForSuffix(t *testing.T) { + ctx := context.Background() + asid := xtest.MustParseAS("ff00:0:1") + db := newDB(t) + addSegRsvRows(t, db, asid, 1, 2) + suffix1, err := newSuffix(ctx, db.db, asid) + require.NoError(t, err) + require.Equal(t, uint32(3), suffix1) + suffix2, err := newSuffix(ctx, db.db, asid) + require.NoError(t, err) + require.Equal(t, uint32(3), suffix2) + rsv := &segment.Reservation{ + ID: reservation.SegmentID{ASID: asid}, + } + err = insertNewSegReservation(ctx, db.db, rsv, suffix1) + require.NoError(t, err) + err = insertNewSegReservation(ctx, db.db, rsv, suffix2) + require.Error(t, err) + sqliteError, ok := err.(sqlite3.Error) + require.True(t, ok) + require.Equal(t, sqlite3.ErrConstraint, sqliteError.Code) +} + +func BenchmarkNewSuffix10K(b *testing.B) { benchmarkNewSuffix(b, 10000) } +func BenchmarkNewSuffix100K(b *testing.B) { benchmarkNewSuffix(b, 100000) } +func BenchmarkNewSuffix1M(b *testing.B) { benchmarkNewSuffix(b, 1000000) } + +func newDB(t testing.TB) *Backend { + db, err := New("file::memory:") + require.NoError(t, err) + return db +} + +func addSegRsvRows(t testing.TB, b *Backend, asid addr.AS, firstSuffix, lastSuffix uint32) { + ctx := context.Background() + query := `INSERT INTO seg_reservation (id_as, id_suffix, inout_ingress, inout_egress, path, + src_as, dst_as) VALUES ($1, $2, $3, $4, $5, $6, $7)` + for suffix := firstSuffix; suffix <= lastSuffix; suffix++ { + _, err := b.db.ExecContext(ctx, query, asid, suffix, 0, 0, nil, nil, nil) + require.NoError(t, err) + } +} + +func benchmarkNewSuffix(b *testing.B, entries uint32) { + db := newDB(b) + ctx := context.Background() + asid := xtest.MustParseAS("ff00:0:1") + addSegRsvRows(b, db, asid, 1, entries) + b.ResetTimer() + + for n := 0; n < b.N; n++ { + suffix, err := newSuffix(ctx, db.db, asid) + require.NoError(b, err) + require.Equal(b, entries+1, suffix) + } +} diff --git a/go/cs/reservation/reservationdbsqlite/schema.go b/go/cs/reservation/reservationdbsqlite/schema.go index c682f1afb6..610c866ab7 100644 --- a/go/cs/reservation/reservationdbsqlite/schema.go +++ b/go/cs/reservation/reservationdbsqlite/schema.go @@ -22,55 +22,47 @@ const ( // Schema is the SQLite database layout. // TODO(juagargi) explain the DB structure here or in the design markdown. // TODO(juagargi) create appropriate SQL indices. - Schema = ` - - CREATE TABLE "seg_reservation" ( - "row_id" INTEGER, - "reservation_id" BLOB NOT NULL, - "inout_ingress" INTEGER NOT NULL, - "inout_egress" INTEGER NOT NULL, - "path" BLOB NOT NULL, - "src_as" INTEGER NOT NULL, - "dst_as" INTEGER NOT NULL, - PRIMARY KEY("row_id") + Schema = `CREATE TABLE seg_reservation ( + row_id INTEGER, + id_as INTEGER NOT NULL, + id_suffix INTEGER NOT NULL, + inout_ingress INTEGER NOT NULL, + inout_egress INTEGER NOT NULL, + path BLOB, + src_as INTEGER, + dst_as INTEGER, + PRIMARY KEY(row_id), + UNIQUE(id_as,id_suffix) ); - - CREATE TABLE "seg_index" ( - "reservation" INTEGER NOT NULL, - "index_number" INTEGER NOT NULL, - "expiration" INTEGER NOT NULL, - "state" INTEGER NOT NULL, - "min_bw" INTEGER NOT NULL, - "max_bw" INTEGER NOT NULL, - "alloc_bw" INTEGER NOT NULL, - "token" BLOB, - PRIMARY KEY("Reservation","index_number"), - FOREIGN KEY("reservation") REFERENCES "seg_reservation"("row_id") ON DELETE CASCADE + CREATE TABLE seg_index ( + reservation INTEGER NOT NULL, + index_number INTEGER NOT NULL, + expiration INTEGER NOT NULL, + state INTEGER NOT NULL, + min_bw INTEGER NOT NULL, + max_bw INTEGER NOT NULL, + alloc_bw INTEGER NOT NULL, + token BLOB, + PRIMARY KEY(Reservation,index_number), + FOREIGN KEY(reservation) REFERENCES seg_reservation(row_id) ON DELETE CASCADE ); - - CREATE TABLE "e2e_reservation" ( - "row_id" INTEGER, - "reservation_id" BLOB NOT NULL, - PRIMARY KEY("row_id") + CREATE TABLE e2e_reservation ( + row_id INTEGER, + reservation_id BLOB NOT NULL, + PRIMARY KEY(row_id) ); - - CREATE TABLE "e2e_index" ( - "reservation" INTEGER NOT NULL, - "index_number" INTEGER NOT NULL, - "expiration" INTEGER NOT NULL, - "alloc_bw" INTEGER NOT NULL, - "token" BLOB NOT NULL, - FOREIGN KEY("reservation") REFERENCES "e2e_reservation"("row_id") ON DELETE CASCADE - ); - - CREATE TABLE "e2e_to_seg" ( - "e2e" INTEGER NOT NULL, - "seg" INTEGER NOT NULL, - FOREIGN KEY("seg") REFERENCES "seg_reservation"("row_id") ON DELETE CASCADE, - FOREIGN KEY("e2e") REFERENCES "e2e_reservation"("row_id") ON DELETE CASCADE + CREATE TABLE e2e_index ( + reservation INTEGER NOT NULL, + index_number INTEGER NOT NULL, + expiration INTEGER NOT NULL, + alloc_bw INTEGER NOT NULL, + token BLOB NOT NULL, + FOREIGN KEY(reservation) REFERENCES e2e_reservation(row_id) ON DELETE CASCADE ); - - - - ` + CREATE TABLE e2e_to_seg ( + e2e INTEGER NOT NULL, + seg INTEGER NOT NULL, + FOREIGN KEY(seg) REFERENCES seg_reservation(row_id) ON DELETE CASCADE, + FOREIGN KEY(e2e) REFERENCES e2e_reservation(row_id) ON DELETE CASCADE + );` ) diff --git a/go/cs/reservation/reservationdbtest/BUILD.bazel b/go/cs/reservation/reservationdbtest/BUILD.bazel new file mode 100644 index 0000000000..fce894ec76 --- /dev/null +++ b/go/cs/reservation/reservationdbtest/BUILD.bazel @@ -0,0 +1,15 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["reservationdbtest.go"], + importpath = "github.com/scionproto/scion/go/cs/reservation/reservationdbtest", + visibility = ["//visibility:public"], + deps = [ + "//go/cs/reservation/segment:go_default_library", + "//go/cs/reservation/segmenttest:go_default_library", + "//go/cs/reservationstorage/backend:go_default_library", + "//go/lib/xtest:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/cs/reservation/reservationdbtest/reservationdbtest.go b/go/cs/reservation/reservationdbtest/reservationdbtest.go new file mode 100644 index 0000000000..68d33681cf --- /dev/null +++ b/go/cs/reservation/reservationdbtest/reservationdbtest.go @@ -0,0 +1,56 @@ +// 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 reservationdbtest + +import ( + "context" + "testing" + + "github.com/scionproto/scion/go/cs/reservation/segment" + "github.com/scionproto/scion/go/cs/reservation/segmenttest" + "github.com/scionproto/scion/go/cs/reservationstorage/backend" + "github.com/scionproto/scion/go/lib/xtest" + "github.com/stretchr/testify/require" +) + +type TestableDB interface { + backend.DB + Prepare(*testing.T, context.Context) +} + +func TestDB(t *testing.T, db TestableDB) { + tests := map[string]func(*testing.T, backend.DB){ + "insert segment reservations create ID": testNewSegmentReservation, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + ctx := context.Background() + db.Prepare(t, ctx) + test(t, db) + }) + } +} + +func testNewSegmentReservation(t *testing.T, db backend.DB) { + r := segment.NewReservation() + r.InOutIFIDs.Egress = 1 + p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) + r.Path = &p + r.ID.ASID = xtest.MustParseAS("ff00:0:1") + ctx := context.Background() + err := db.NewSegmentRsv(ctx, r) + require.NoError(t, err) + require.Equal(t, xtest.MustParseHexString("00000001"), r.ID.Suffix[:]) +} diff --git a/go/cs/reservationstorage/backend/db.go b/go/cs/reservationstorage/backend/db.go index 3aebe5b361..7b4e7b4be0 100644 --- a/go/cs/reservationstorage/backend/db.go +++ b/go/cs/reservationstorage/backend/db.go @@ -100,11 +100,9 @@ type Transaction interface { // DB is the interface for any reservation backend. type DB interface { BeginTransaction(ctx context.Context, opts *sql.TxOptions) (Transaction, error) - ReserverOnly TransitOnly ReserverAndTransit - db.LimitSetter io.Closer } From f3004345481c84086ecdeb8476247031abbc5f77 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 11 Jun 2020 17:33:13 +0200 Subject: [PATCH 08/22] refactor InOutIFIDs out --- go/cs/reservation/reservationdbsqlite/db.go | 2 +- .../reservation/reservationdbtest/reservationdbtest.go | 2 +- go/cs/reservation/segment/reservation.go | 10 ++++++---- go/cs/reservation/segment/reservation_test.go | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index 86122e4ba3..7fe3569239 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -161,7 +161,7 @@ func insertNewSegReservation(ctx context.Context, x db.Sqler, rsv *segment.Reser const query = `INSERT INTO seg_reservation (id_as, id_suffix, inout_ingress ,inout_egress, path, src_as, dst_as) VALUES ($1, $2, $3, $4, $5, $6, $7)` _, err := x.ExecContext(ctx, query, rsv.Path.GetSrcIA().A, suffix, - rsv.InOutIFIDs.Ingress, rsv.InOutIFIDs.Egress, + rsv.IngressIFID, rsv.EgressIFID, rsv.Path.ToRaw(), rsv.Path.GetSrcIA().IAInt(), rsv.Path.GetDstIA().IAInt()) return err } diff --git a/go/cs/reservation/reservationdbtest/reservationdbtest.go b/go/cs/reservation/reservationdbtest/reservationdbtest.go index 68d33681cf..5eaa30579a 100644 --- a/go/cs/reservation/reservationdbtest/reservationdbtest.go +++ b/go/cs/reservation/reservationdbtest/reservationdbtest.go @@ -45,7 +45,7 @@ func TestDB(t *testing.T, db TestableDB) { func testNewSegmentReservation(t *testing.T, db backend.DB) { r := segment.NewReservation() - r.InOutIFIDs.Egress = 1 + r.EgressIFID = 1 p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) r.Path = &p r.ID.ASID = xtest.MustParseAS("ff00:0:1") diff --git a/go/cs/reservation/segment/reservation.go b/go/cs/reservation/segment/reservation.go index 81e658c698..a74601036a 100644 --- a/go/cs/reservation/segment/reservation.go +++ b/go/cs/reservation/segment/reservation.go @@ -19,6 +19,7 @@ import ( base "github.com/scionproto/scion/go/cs/reservation" "github.com/scionproto/scion/go/lib/colibri/reservation" + "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/serrors" ) @@ -27,7 +28,8 @@ type Reservation struct { ID reservation.SegmentID Indices Indices // existing indices in this reservation activeIndex int // -1 <= activeIndex < len(Indices) - InOutIFIDs PathStep // Ingress and Egress interfaces + IngressIFID common.IFIDType // igress interface ID: reservation packets enter + EgressIFID common.IFIDType // egress interface ID: reservation packets leave Path *Path // nil if this AS is not at the source of the reservation PathEndProps reservation.PathEndProps // the properties for stitching and start/end TrafficSplit reservation.SplitCls // the traffic split between control and data planes @@ -64,13 +66,13 @@ func (r *Reservation) Validate() error { } var err error if r.Path != nil { - if r.InOutIFIDs.Ingress != 0 { + if r.IngressIFID != 0 { return serrors.New("reservation starts in this AS but ingress interface is not zero", - "ingress_if", r.InOutIFIDs.Ingress) + "ingress_if", r.IngressIFID) // TODO(juagargi) test } err = r.Path.Validate() - } else if r.InOutIFIDs.Ingress == 0 { + } else if r.IngressIFID == 0 { return serrors.New("reservation does not start in this AS but ingress interface is zero") } if err != nil { diff --git a/go/cs/reservation/segment/reservation_test.go b/go/cs/reservation/segment/reservation_test.go index 9a0ee0f3d5..575da76aca 100644 --- a/go/cs/reservation/segment/reservation_test.go +++ b/go/cs/reservation/segment/reservation_test.go @@ -165,7 +165,7 @@ func TestReservationValidate(t *testing.T) { // starts in this AS but ingress nonzero r = segmenttest.NewReservation() - r.InOutIFIDs.Ingress = 1 + r.IngressIFID = 1 err = r.Validate() require.Error(t, err) From a6762be2ca9cf89ec9f926430693077af3855b08 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Fri, 12 Jun 2020 09:29:47 +0200 Subject: [PATCH 09/22] no more common.Order --- go/cs/reservation/reservationdbsqlite/db.go | 3 ++- go/cs/reservation/segment/path.go | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index 7fe3569239..ebce8522f2 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -17,6 +17,7 @@ package reservationdbsqlite import ( "context" "database/sql" + "encoding/binary" "sync" "github.com/mattn/go-sqlite3" @@ -179,7 +180,7 @@ func (x *executor) NewSegmentRsv(ctx context.Context, rsv *segment.Reservation) if err := insertNewSegReservation(ctx, tx, rsv, suffix); err != nil { return err } - common.Order.PutUint32(rsv.ID.Suffix[:], suffix) + binary.BigEndian.PutUint32(rsv.ID.Suffix[:], suffix) return nil }) if err == nil { diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index 64a56a94c3..5140896172 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -15,6 +15,7 @@ package segment import ( + "encoding/binary" "io" "github.com/scionproto/scion/go/lib/addr" @@ -33,8 +34,8 @@ func NewPathFromRaw(buff []byte) Path { p := make(Path, steps) for i := 0; i < steps; i++ { offset := i * PathStepWithIALen - p[i].Ingress = common.IFIDType(common.Order.Uint64(buff[offset:])) - p[i].Egress = common.IFIDType(common.Order.Uint64(buff[offset+8:])) + p[i].Ingress = common.IFIDType(binary.BigEndian.Uint64(buff[offset:])) + p[i].Egress = common.IFIDType(binary.BigEndian.Uint64(buff[offset+8:])) p[i].IA = addr.IAFromRaw(buff[offset+16:]) } return p @@ -105,9 +106,9 @@ func (p *Path) Read(buff []byte) (int, error) { } for i, s := range *p { offset := i * PathStepWithIALen - common.Order.PutUint64(buff[offset:], uint64(s.Ingress)) - common.Order.PutUint64(buff[offset+8:], uint64(s.Egress)) - common.Order.PutUint64(buff[offset+16:], uint64(s.IA.IAInt())) + binary.BigEndian.PutUint64(buff[offset:], uint64(s.Ingress)) + binary.BigEndian.PutUint64(buff[offset+8:], uint64(s.Egress)) + binary.BigEndian.PutUint64(buff[offset+16:], uint64(s.IA.IAInt())) } return p.Len(), nil } From c74e2f7cc3e87d4b03713d32b861405fea82bb5a Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Fri, 12 Jun 2020 09:45:01 +0200 Subject: [PATCH 10/22] linter --- go/cs/reservation/reservationdbsqlite/BUILD.bazel | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/go/cs/reservation/reservationdbsqlite/BUILD.bazel b/go/cs/reservation/reservationdbsqlite/BUILD.bazel index 5c8e62bc86..2d42270854 100644 --- a/go/cs/reservation/reservationdbsqlite/BUILD.bazel +++ b/go/cs/reservation/reservationdbsqlite/BUILD.bazel @@ -27,7 +27,11 @@ go_test( embed = [":go_default_library"], deps = [ "//go/cs/reservation/reservationdbtest:go_default_library", + "//go/cs/reservation/segment:go_default_library", + "//go/lib/addr:go_default_library", + "//go/lib/colibri/reservation:go_default_library", "//go/lib/xtest:go_default_library", + "@com_github_mattn_go_sqlite3//:go_default_library", "@com_github_stretchr_testify//require:go_default_library", ], ) From 620f3dbe8684fe95b3832fbe8aa4ce67279b8ccd Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Tue, 16 Jun 2020 11:49:32 +0200 Subject: [PATCH 11/22] fix import groups (noticed by linter) --- go/cs/reservation/reservationdbsqlite/db_test.go | 3 ++- go/cs/reservation/reservationdbtest/reservationdbtest.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db_test.go b/go/cs/reservation/reservationdbsqlite/db_test.go index 2df5f3ac01..4432c1dc7a 100644 --- a/go/cs/reservation/reservationdbsqlite/db_test.go +++ b/go/cs/reservation/reservationdbsqlite/db_test.go @@ -19,12 +19,13 @@ import ( "testing" "github.com/mattn/go-sqlite3" + "github.com/stretchr/testify/require" + "github.com/scionproto/scion/go/cs/reservation/reservationdbtest" "github.com/scionproto/scion/go/cs/reservation/segment" "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/colibri/reservation" "github.com/scionproto/scion/go/lib/xtest" - "github.com/stretchr/testify/require" ) type TestDB struct { diff --git a/go/cs/reservation/reservationdbtest/reservationdbtest.go b/go/cs/reservation/reservationdbtest/reservationdbtest.go index 5eaa30579a..56404f58c3 100644 --- a/go/cs/reservation/reservationdbtest/reservationdbtest.go +++ b/go/cs/reservation/reservationdbtest/reservationdbtest.go @@ -18,11 +18,12 @@ import ( "context" "testing" + "github.com/stretchr/testify/require" + "github.com/scionproto/scion/go/cs/reservation/segment" "github.com/scionproto/scion/go/cs/reservation/segmenttest" "github.com/scionproto/scion/go/cs/reservationstorage/backend" "github.com/scionproto/scion/go/lib/xtest" - "github.com/stretchr/testify/require" ) type TestableDB interface { From 2e207d850c7ced1df08934ff18d56a0d9eb83659 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 17 Jun 2020 16:50:56 +0200 Subject: [PATCH 12/22] changed package name,inout_X to X in schema --- go/cs/reservation/reservationdbsqlite/db.go | 6 +++--- go/cs/reservation/reservationdbsqlite/db_test.go | 4 ++-- go/cs/reservation/reservationdbsqlite/schema.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index ebce8522f2..93e33ee990 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package reservationdbsqlite +package sqlite import ( "context" @@ -126,7 +126,7 @@ func (x *executor) GetSegmentRsvFromSrcDstAS(ctx context.Context, srcIA, dstIA a x.Lock() defer x.Unlock() - query := `SELECT r.reservation_id, r.inout_ingress, r.inout_egress + query := `SELECT r.reservation_id, r.ingress, r.egress FROM seg_reservation r WHERE r.src_as = ?1 AND r.dst_as = ?2` rows, err := x.db.QueryContext(ctx, query, srcIA.IAInt(), dstIA.IAInt()) @@ -159,7 +159,7 @@ func (x *executor) GetSegmentRsvsFromIFPair(ctx context.Context, ingress, egress func insertNewSegReservation(ctx context.Context, x db.Sqler, rsv *segment.Reservation, suffix uint32) error { - const query = `INSERT INTO seg_reservation (id_as, id_suffix, inout_ingress ,inout_egress, + const query = `INSERT INTO seg_reservation (id_as, id_suffix, ingress ,egress, path, src_as, dst_as) VALUES ($1, $2, $3, $4, $5, $6, $7)` _, err := x.ExecContext(ctx, query, rsv.Path.GetSrcIA().A, suffix, rsv.IngressIFID, rsv.EgressIFID, diff --git a/go/cs/reservation/reservationdbsqlite/db_test.go b/go/cs/reservation/reservationdbsqlite/db_test.go index 4432c1dc7a..4ae32288f1 100644 --- a/go/cs/reservation/reservationdbsqlite/db_test.go +++ b/go/cs/reservation/reservationdbsqlite/db_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package reservationdbsqlite +package sqlite import ( "context" @@ -94,7 +94,7 @@ func newDB(t testing.TB) *Backend { func addSegRsvRows(t testing.TB, b *Backend, asid addr.AS, firstSuffix, lastSuffix uint32) { ctx := context.Background() - query := `INSERT INTO seg_reservation (id_as, id_suffix, inout_ingress, inout_egress, path, + query := `INSERT INTO seg_reservation (id_as, id_suffix, ingress, egress, path, src_as, dst_as) VALUES ($1, $2, $3, $4, $5, $6, $7)` for suffix := firstSuffix; suffix <= lastSuffix; suffix++ { _, err := b.db.ExecContext(ctx, query, asid, suffix, 0, 0, nil, nil, nil) diff --git a/go/cs/reservation/reservationdbsqlite/schema.go b/go/cs/reservation/reservationdbsqlite/schema.go index 610c866ab7..02e1fe5e29 100644 --- a/go/cs/reservation/reservationdbsqlite/schema.go +++ b/go/cs/reservation/reservationdbsqlite/schema.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package reservationdbsqlite +package sqlite const ( // SchemaVersion is the version of the SQLite schema understood by this backend. @@ -26,8 +26,8 @@ const ( row_id INTEGER, id_as INTEGER NOT NULL, id_suffix INTEGER NOT NULL, - inout_ingress INTEGER NOT NULL, - inout_egress INTEGER NOT NULL, + ingress INTEGER NOT NULL, + egress INTEGER NOT NULL, path BLOB, src_as INTEGER, dst_as INTEGER, From 783189006815b477905f923550fbe33cd33e6740 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 17 Jun 2020 17:13:50 +0200 Subject: [PATCH 13/22] addr.IA{} is zero IA,Context to test functions --- go/cs/reservation/reservationdbtest/reservationdbtest.go | 7 +++---- go/cs/reservation/segment/path.go | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/go/cs/reservation/reservationdbtest/reservationdbtest.go b/go/cs/reservation/reservationdbtest/reservationdbtest.go index 56404f58c3..71f99bb009 100644 --- a/go/cs/reservation/reservationdbtest/reservationdbtest.go +++ b/go/cs/reservation/reservationdbtest/reservationdbtest.go @@ -32,25 +32,24 @@ type TestableDB interface { } func TestDB(t *testing.T, db TestableDB) { - tests := map[string]func(*testing.T, backend.DB){ + tests := map[string]func(context.Context, *testing.T, backend.DB){ "insert segment reservations create ID": testNewSegmentReservation, } for name, test := range tests { t.Run(name, func(t *testing.T) { ctx := context.Background() db.Prepare(t, ctx) - test(t, db) + test(ctx, t, db) }) } } -func testNewSegmentReservation(t *testing.T, db backend.DB) { +func testNewSegmentReservation(ctx context.Context, t *testing.T, db backend.DB) { r := segment.NewReservation() r.EgressIFID = 1 p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) r.Path = &p r.ID.ASID = xtest.MustParseAS("ff00:0:1") - ctx := context.Background() err := db.NewSegmentRsv(ctx, r) require.NoError(t, err) require.Equal(t, xtest.MustParseHexString("00000001"), r.ID.Suffix[:]) diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index 5140896172..ef7c4edbba 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -74,7 +74,7 @@ func (p Path) Equal(o Path) bool { // If the Path is not nil, it assumes is valid, i.e. it has at least length 2. func (p *Path) GetSrcIA() addr.IA { if p == nil { - return addr.IA{I: 0, A: 0} + return addr.IA{} } return (*p)[0].IA } @@ -84,7 +84,7 @@ func (p *Path) GetSrcIA() addr.IA { // If the Path is not nil, it assumes is valid, i.e. it has at least length 2. func (p *Path) GetDstIA() addr.IA { if p == nil { - return addr.IA{I: 0, A: 0} + return addr.IA{} } return (*p)[len(*p)-1].IA } From 63c11664585c17cf5d715bac42f8d8d64700c392 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 17 Jun 2020 17:15:27 +0200 Subject: [PATCH 14/22] less Equal functions --- go/cs/reservation/segment/path.go | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index ef7c4edbba..8180c6a3c8 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -62,7 +62,7 @@ func (p Path) Equal(o Path) bool { return false } for i := 0; i < len(p); i++ { - if !p[i].Equal(&o[i]) { + if p[i] != o[i] { return false } } @@ -129,14 +129,6 @@ type PathStep struct { Egress common.IFIDType } -// Equal returns true if both PathStep variables contain the same values, or both nil. -func (s *PathStep) Equal(o *PathStep) bool { - if s == o { - return true - } - return s.Ingress == o.Ingress && s.Egress == o.Egress -} - // PathStepWithIA is a step in a reservation path as seen from the source AS. type PathStepWithIA struct { PathStep @@ -145,11 +137,3 @@ type PathStepWithIA struct { // PathStepWithIALen amounts for Ingress+Egress+IA. const PathStepWithIALen = 8 + 8 + 8 - -// Equal returns true if both PathStep variables contain the same values, or both nil. -func (s *PathStepWithIA) Equal(o *PathStepWithIA) bool { - if s == o { - return true - } - return s.PathStep.Equal(&o.PathStep) && s.IA == o.IA -} From 323769c0b9e8512d467ad8fc1560d9ad06db81b1 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 17 Jun 2020 17:23:11 +0200 Subject: [PATCH 15/22] s/IngressIFID/Ingress/ s/EgressIFID/Egress/ --- go/cs/reservation/reservationdbsqlite/db.go | 2 +- .../reservationdbtest/reservationdbtest.go | 2 +- go/cs/reservation/segment/request.go | 14 +++++++------- go/cs/reservation/segment/request_test.go | 4 ++-- go/cs/reservation/segment/reservation.go | 10 +++++----- go/cs/reservation/segment/reservation_test.go | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index 93e33ee990..5851fcf5e2 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -162,7 +162,7 @@ func insertNewSegReservation(ctx context.Context, x db.Sqler, rsv *segment.Reser const query = `INSERT INTO seg_reservation (id_as, id_suffix, ingress ,egress, path, src_as, dst_as) VALUES ($1, $2, $3, $4, $5, $6, $7)` _, err := x.ExecContext(ctx, query, rsv.Path.GetSrcIA().A, suffix, - rsv.IngressIFID, rsv.EgressIFID, + rsv.Ingress, rsv.Egress, rsv.Path.ToRaw(), rsv.Path.GetSrcIA().IAInt(), rsv.Path.GetDstIA().IAInt()) return err } diff --git a/go/cs/reservation/reservationdbtest/reservationdbtest.go b/go/cs/reservation/reservationdbtest/reservationdbtest.go index 71f99bb009..0a885bb62c 100644 --- a/go/cs/reservation/reservationdbtest/reservationdbtest.go +++ b/go/cs/reservation/reservationdbtest/reservationdbtest.go @@ -46,7 +46,7 @@ func TestDB(t *testing.T, db TestableDB) { func testNewSegmentReservation(ctx context.Context, t *testing.T, db backend.DB) { r := segment.NewReservation() - r.EgressIFID = 1 + r.Egress = 1 p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) r.Path = &p r.ID.ASID = xtest.MustParseAS("ff00:0:1") diff --git a/go/cs/reservation/segment/request.go b/go/cs/reservation/segment/request.go index 506a1f40c8..d33123491b 100644 --- a/go/cs/reservation/segment/request.go +++ b/go/cs/reservation/segment/request.go @@ -30,8 +30,8 @@ type Request struct { Metadata base.RequestMetadata // information about the request (forwarding path) ID reservation.SegmentID // the ID this request refers to Timestamp time.Time // the mandatory timestamp - IngressIFID common.IFIDType // the interface the reservation traffic uses to enter the AS - EgressIFID common.IFIDType // the interface the reservation traffic uses to leave the AS + Ingress common.IFIDType // the interface the reservation traffic uses to enter the AS + Egress common.IFIDType // the interface the reservation traffic uses to leave the AS Reservation *Reservation // nil if no reservation yet } @@ -64,11 +64,11 @@ func NewRequest(ts time.Time, ID *colibri_mgmt.SegmentReservationID, return nil, serrors.WrapStr("new segment request", err) } return &Request{ - Timestamp: ts, - Metadata: *metadata, - ID: *segID, - IngressIFID: ingressIFID, - EgressIFID: egressIFID, + Timestamp: ts, + Metadata: *metadata, + ID: *segID, + Ingress: ingressIFID, + Egress: egressIFID, }, nil } diff --git a/go/cs/reservation/segment/request_test.go b/go/cs/reservation/segment/request_test.go index 259b679bdb..e54d0066ab 100644 --- a/go/cs/reservation/segment/request_test.go +++ b/go/cs/reservation/segment/request_test.go @@ -42,8 +42,8 @@ func TestNewSetupReqFromCtrlMsg(t *testing.T) { require.NoError(t, err) require.Equal(t, *p, r.Metadata.Path) checkRequest(t, ctrlMsg, r, ts) - require.Equal(t, common.IFIDType(1), r.IngressIFID) - require.Equal(t, common.IFIDType(2), r.EgressIFID) + require.Equal(t, common.IFIDType(1), r.Ingress) + require.Equal(t, common.IFIDType(2), r.Egress) } func TestRequestToCtrlMsg(t *testing.T) { diff --git a/go/cs/reservation/segment/reservation.go b/go/cs/reservation/segment/reservation.go index a74601036a..0121f386eb 100644 --- a/go/cs/reservation/segment/reservation.go +++ b/go/cs/reservation/segment/reservation.go @@ -28,8 +28,8 @@ type Reservation struct { ID reservation.SegmentID Indices Indices // existing indices in this reservation activeIndex int // -1 <= activeIndex < len(Indices) - IngressIFID common.IFIDType // igress interface ID: reservation packets enter - EgressIFID common.IFIDType // egress interface ID: reservation packets leave + Ingress common.IFIDType // igress interface ID: reservation packets enter + Egress common.IFIDType // egress interface ID: reservation packets leave Path *Path // nil if this AS is not at the source of the reservation PathEndProps reservation.PathEndProps // the properties for stitching and start/end TrafficSplit reservation.SplitCls // the traffic split between control and data planes @@ -66,13 +66,13 @@ func (r *Reservation) Validate() error { } var err error if r.Path != nil { - if r.IngressIFID != 0 { + if r.Ingress != 0 { return serrors.New("reservation starts in this AS but ingress interface is not zero", - "ingress_if", r.IngressIFID) + "ingress_if", r.Ingress) // TODO(juagargi) test } err = r.Path.Validate() - } else if r.IngressIFID == 0 { + } else if r.Ingress == 0 { return serrors.New("reservation does not start in this AS but ingress interface is zero") } if err != nil { diff --git a/go/cs/reservation/segment/reservation_test.go b/go/cs/reservation/segment/reservation_test.go index 575da76aca..f2ad5233f0 100644 --- a/go/cs/reservation/segment/reservation_test.go +++ b/go/cs/reservation/segment/reservation_test.go @@ -165,7 +165,7 @@ func TestReservationValidate(t *testing.T) { // starts in this AS but ingress nonzero r = segmenttest.NewReservation() - r.IngressIFID = 1 + r.Ingress = 1 err = r.Validate() require.Error(t, err) From 323674d0867192cb1be55ea2e523f84f7db36f2b Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 17 Jun 2020 17:30:49 +0200 Subject: [PATCH 16/22] fix doc string, change DB interface --- go/cs/reservation/reservationdbsqlite/db.go | 7 ++++--- go/cs/reservationstorage/backend/db.go | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/reservationdbsqlite/db.go index 5851fcf5e2..a8e11bcfe6 100644 --- a/go/cs/reservation/reservationdbsqlite/db.go +++ b/go/cs/reservation/reservationdbsqlite/db.go @@ -19,6 +19,7 @@ import ( "database/sql" "encoding/binary" "sync" + "time" "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3" @@ -215,7 +216,7 @@ func (x *executor) UpdateSegmentIndex(ctx context.Context, rsv *segment.Reservat return nil } -// DeleteExpiredIndices removes the index from the DB. Used in cleanup. +// DeleteSegmentIndex removes the index from the DB. Used in cleanup. func (x *executor) DeleteSegmentIndex(ctx context.Context, rsv *segment.Reservation, idx reservation.IndexNumber) error { @@ -224,11 +225,11 @@ func (x *executor) DeleteSegmentIndex(ctx context.Context, rsv *segment.Reservat // DeleteExpiredIndices will remove expired indices from the DB. If a reservation is left // without any index after removing the expired ones, it will also be removed. -func (x *executor) DeleteExpiredIndices(ctx context.Context) (int, error) { +func (x *executor) DeleteExpiredIndices(ctx context.Context, now time.Time) (int, error) { return 0, nil } -// DeleteExpiredIndices removes the segment reservation +// DeleteSegmentRsv removes the segment reservation func (x *executor) DeleteSegmentRsv(ctx context.Context, ID reservation.SegmentID) error { return nil } diff --git a/go/cs/reservationstorage/backend/db.go b/go/cs/reservationstorage/backend/db.go index 7b4e7b4be0..2afdf24677 100644 --- a/go/cs/reservationstorage/backend/db.go +++ b/go/cs/reservationstorage/backend/db.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" "io" + "time" "github.com/scionproto/scion/go/cs/reservation/e2e" "github.com/scionproto/scion/go/cs/reservation/segment" @@ -69,13 +70,13 @@ type ReserverAndTransit interface { // DeleteSegmentIndex removes the index from the DB. Used in cleanup. DeleteSegmentIndex(ctx context.Context, rsv *segment.Reservation, idx reservation.IndexNumber) error - // DeleteExpiredIndices removes the segment reservation. Used in teardown. + // DeleteSegmentRsv removes the segment reservation. Used in teardown. DeleteSegmentRsv(ctx context.Context, ID reservation.SegmentID) error // DeleteExpiredIndices will remove expired indices from the DB. If a reservation is left // without any index after removing the expired ones, it will also be removed. // Used on schedule. - DeleteExpiredIndices(ctx context.Context) (int, error) + DeleteExpiredIndices(ctx context.Context, now time.Time) (int, error) // GetE2ERsvFromID finds the end to end resevation given its ID. GetE2ERsvFromID(ctx context.Context, ID reservation.E2EID, idx reservation.IndexNumber) ( From 9a1074f12b3cf2389563709422edbd1f6bbb2332 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Wed, 17 Jun 2020 17:45:36 +0200 Subject: [PATCH 17/22] making NewPathFromRaw safer --- go/cs/reservation/segment/path.go | 7 +++++-- go/cs/reservation/segment/path_test.go | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index 8180c6a3c8..d593433881 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -29,7 +29,10 @@ type Path []PathStepWithIA var _ io.Reader = (*Path)(nil) // NewPathFromRaw constructs a new Path from the byte representation. -func NewPathFromRaw(buff []byte) Path { +func NewPathFromRaw(buff []byte) (Path, error) { + if len(buff)%PathStepWithIALen != 0 { + return nil, serrors.New("buffer input is not a multiple of a path step", "len", len(buff)) + } steps := len(buff) / PathStepWithIALen p := make(Path, steps) for i := 0; i < steps; i++ { @@ -38,7 +41,7 @@ func NewPathFromRaw(buff []byte) Path { p[i].Egress = common.IFIDType(binary.BigEndian.Uint64(buff[offset+8:])) p[i].IA = addr.IAFromRaw(buff[offset+16:]) } - return p + return p, nil } // Validate returns an error if there is invalid data. diff --git a/go/cs/reservation/segment/path_test.go b/go/cs/reservation/segment/path_test.go index 3d5b336633..b7ff75b425 100644 --- a/go/cs/reservation/segment/path_test.go +++ b/go/cs/reservation/segment/path_test.go @@ -138,9 +138,22 @@ func TestToFromBinary(t *testing.T) { require.NoError(t, err) require.Equal(t, 2*3*8, c) - anotherP := segment.NewPathFromRaw(buff) + anotherP, err := segment.NewPathFromRaw(buff) + require.NoError(t, err) require.Equal(t, p, anotherP) anotherBuff := p.ToRaw() require.Equal(t, buff, anotherBuff) + // wrong buffer + buff = buff[:len(buff)-1] + _, err = segment.NewPathFromRaw(buff) + require.Error(t, err) + // empty and nil buffer + p, err = segment.NewPathFromRaw(nil) + require.NoError(t, err) + require.Empty(t, p) + p, err = segment.NewPathFromRaw([]byte{}) + require.NoError(t, err) + require.Empty(t, p) + } From 81fbb6a65269de953393e42a543fe8b316f872ad Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 18 Jun 2020 15:10:05 +0200 Subject: [PATCH 18/22] remove pointers to Path, use Path instead --- go/cs/reservation/e2e/reservation_test.go | 5 ++--- .../reservationdbtest/reservationdbtest.go | 3 +-- go/cs/reservation/segment/path.go | 18 +++++++++--------- go/cs/reservation/segment/path_test.go | 3 +-- go/cs/reservation/segment/reservation.go | 2 +- go/cs/reservation/segment/reservation_test.go | 2 +- go/cs/reservation/segmenttest/common.go | 3 +-- 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/go/cs/reservation/e2e/reservation_test.go b/go/cs/reservation/e2e/reservation_test.go index de26014099..30d2094a63 100644 --- a/go/cs/reservation/e2e/reservation_test.go +++ b/go/cs/reservation/e2e/reservation_test.go @@ -46,7 +46,7 @@ func TestValidate(t *testing.T) { // invalid segment reservation r = newReservation() - r.SegmentReservations[0].Path = &segment.Path{} + r.SegmentReservations[0].Path = segment.Path{} err = r.Validate() require.Error(t, err) @@ -93,8 +93,7 @@ func newSegmentReservation(asidPath ...string) *segment.Reservation { pathComponents[i*3+2] = i*2 + 1 } pathComponents[len(pathComponents)-1] = 0 - p := segmenttest.NewPathFromComponents(pathComponents...) - r.Path = &p + r.Path = segmenttest.NewPathFromComponents(pathComponents...) return r } diff --git a/go/cs/reservation/reservationdbtest/reservationdbtest.go b/go/cs/reservation/reservationdbtest/reservationdbtest.go index 0a885bb62c..c97eba3dc2 100644 --- a/go/cs/reservation/reservationdbtest/reservationdbtest.go +++ b/go/cs/reservation/reservationdbtest/reservationdbtest.go @@ -47,8 +47,7 @@ func TestDB(t *testing.T, db TestableDB) { func testNewSegmentReservation(ctx context.Context, t *testing.T, db backend.DB) { r := segment.NewReservation() r.Egress = 1 - p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) - r.Path = &p + r.Path = segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) r.ID.ASID = xtest.MustParseAS("ff00:0:1") err := db.NewSegmentRsv(ctx, r) require.NoError(t, err) diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index d593433881..6d0fdf3577 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -75,39 +75,39 @@ func (p Path) Equal(o Path) bool { // GetSrcIA returns the source IA in the path or a zero IA if the path is nil (it's not the // source AS of the reservation and has no access to the Path of the reservation). // If the Path is not nil, it assumes is valid, i.e. it has at least length 2. -func (p *Path) GetSrcIA() addr.IA { +func (p Path) GetSrcIA() addr.IA { if p == nil { return addr.IA{} } - return (*p)[0].IA + return p[0].IA } // GetDstIA returns the source IA in the path or a zero IA if the path is nil (it's not the // source AS of the reservation and has no access to the Path of the reservation). // If the Path is not nil, it assumes is valid, i.e. it has at least length 2. -func (p *Path) GetDstIA() addr.IA { +func (p Path) GetDstIA() addr.IA { if p == nil { return addr.IA{} } - return (*p)[len(*p)-1].IA + return p[len(p)-1].IA } // Len returns the length of this Path in bytes, when serialized. -func (p *Path) Len() int { +func (p Path) Len() int { if p == nil { return 0 } - return len(*p) * PathStepWithIALen + return len(p) * PathStepWithIALen } -func (p *Path) Read(buff []byte) (int, error) { +func (p Path) Read(buff []byte) (int, error) { if p == nil { return 0, nil } if len(buff) < p.Len() { return 0, serrors.New("buffer too small", "min_size", p.Len(), "actual_size", len(buff)) } - for i, s := range *p { + for i, s := range p { offset := i * PathStepWithIALen binary.BigEndian.PutUint64(buff[offset:], uint64(s.Ingress)) binary.BigEndian.PutUint64(buff[offset+8:], uint64(s.Egress)) @@ -117,7 +117,7 @@ func (p *Path) Read(buff []byte) (int, error) { } // ToRaw returns a buffer representing this Path. -func (p *Path) ToRaw() []byte { +func (p Path) ToRaw() []byte { if p == nil { return []byte{} } diff --git a/go/cs/reservation/segment/path_test.go b/go/cs/reservation/segment/path_test.go index b7ff75b425..a4b651c0de 100644 --- a/go/cs/reservation/segment/path_test.go +++ b/go/cs/reservation/segment/path_test.go @@ -108,8 +108,7 @@ func TestEqualPath(t *testing.T) { func TestGetIAs(t *testing.T) { - pValue := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) - p := &pValue + p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) require.Equal(t, xtest.MustParseIA("1-ff00:0:1"), p.GetSrcIA()) require.Equal(t, xtest.MustParseIA("1-ff00:0:2"), p.GetDstIA()) p = nil diff --git a/go/cs/reservation/segment/reservation.go b/go/cs/reservation/segment/reservation.go index 0121f386eb..4d9bc17b9d 100644 --- a/go/cs/reservation/segment/reservation.go +++ b/go/cs/reservation/segment/reservation.go @@ -30,7 +30,7 @@ type Reservation struct { activeIndex int // -1 <= activeIndex < len(Indices) Ingress common.IFIDType // igress interface ID: reservation packets enter Egress common.IFIDType // egress interface ID: reservation packets leave - Path *Path // nil if this AS is not at the source of the reservation + Path Path // empty if this AS is not at the source of the reservation PathEndProps reservation.PathEndProps // the properties for stitching and start/end TrafficSplit reservation.SplitCls // the traffic split between control and data planes } diff --git a/go/cs/reservation/segment/reservation_test.go b/go/cs/reservation/segment/reservation_test.go index f2ad5233f0..1ee97f7ac2 100644 --- a/go/cs/reservation/segment/reservation_test.go +++ b/go/cs/reservation/segment/reservation_test.go @@ -109,7 +109,7 @@ func TestReservationValidate(t *testing.T) { require.Error(t, err) // wrong path - r.Path = &segment.Path{} + r.Path = segment.Path{} err = r.Validate() require.Error(t, err) diff --git a/go/cs/reservation/segmenttest/common.go b/go/cs/reservation/segmenttest/common.go index a581d01c11..24294f2039 100644 --- a/go/cs/reservation/segmenttest/common.go +++ b/go/cs/reservation/segmenttest/common.go @@ -44,9 +44,8 @@ func NewReservation() *segment.Reservation { if err != nil { panic(err) } - p := NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) r := segment.NewReservation() r.ID = *segID - r.Path = &p + r.Path = NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) return r } From 188b56e19a45d818ecd90acf7ef3b357a6f27dd0 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 18 Jun 2020 15:50:39 +0200 Subject: [PATCH 19/22] rename directory reservationdbsqlite to sqlite --- go/cs/reservation/{reservationdbsqlite => sqlite}/BUILD.bazel | 0 go/cs/reservation/{reservationdbsqlite => sqlite}/db.go | 0 go/cs/reservation/{reservationdbsqlite => sqlite}/db_test.go | 0 go/cs/reservation/{reservationdbsqlite => sqlite}/schema.go | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename go/cs/reservation/{reservationdbsqlite => sqlite}/BUILD.bazel (100%) rename go/cs/reservation/{reservationdbsqlite => sqlite}/db.go (100%) rename go/cs/reservation/{reservationdbsqlite => sqlite}/db_test.go (100%) rename go/cs/reservation/{reservationdbsqlite => sqlite}/schema.go (100%) diff --git a/go/cs/reservation/reservationdbsqlite/BUILD.bazel b/go/cs/reservation/sqlite/BUILD.bazel similarity index 100% rename from go/cs/reservation/reservationdbsqlite/BUILD.bazel rename to go/cs/reservation/sqlite/BUILD.bazel diff --git a/go/cs/reservation/reservationdbsqlite/db.go b/go/cs/reservation/sqlite/db.go similarity index 100% rename from go/cs/reservation/reservationdbsqlite/db.go rename to go/cs/reservation/sqlite/db.go diff --git a/go/cs/reservation/reservationdbsqlite/db_test.go b/go/cs/reservation/sqlite/db_test.go similarity index 100% rename from go/cs/reservation/reservationdbsqlite/db_test.go rename to go/cs/reservation/sqlite/db_test.go diff --git a/go/cs/reservation/reservationdbsqlite/schema.go b/go/cs/reservation/sqlite/schema.go similarity index 100% rename from go/cs/reservation/reservationdbsqlite/schema.go rename to go/cs/reservation/sqlite/schema.go From 2ac070ff023af0b85196d447c295ef793f455b3d Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 18 Jun 2020 15:52:59 +0200 Subject: [PATCH 20/22] BUILD file --- go/cs/reservation/sqlite/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/cs/reservation/sqlite/BUILD.bazel b/go/cs/reservation/sqlite/BUILD.bazel index 2d42270854..fda2ab149d 100644 --- a/go/cs/reservation/sqlite/BUILD.bazel +++ b/go/cs/reservation/sqlite/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "db.go", "schema.go", ], - importpath = "github.com/scionproto/scion/go/cs/reservation/reservationdbsqlite", + importpath = "github.com/scionproto/scion/go/cs/reservation/sqlite", visibility = ["//visibility:public"], deps = [ "//go/cs/reservation/e2e:go_default_library", From f311681df12387644ca546b2937bb40e09006181 Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 18 Jun 2020 15:54:44 +0200 Subject: [PATCH 21/22] happy linting --- go/cs/reservation/segment/reservation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/cs/reservation/segment/reservation.go b/go/cs/reservation/segment/reservation.go index 4d9bc17b9d..238f0104f1 100644 --- a/go/cs/reservation/segment/reservation.go +++ b/go/cs/reservation/segment/reservation.go @@ -30,7 +30,7 @@ type Reservation struct { activeIndex int // -1 <= activeIndex < len(Indices) Ingress common.IFIDType // igress interface ID: reservation packets enter Egress common.IFIDType // egress interface ID: reservation packets leave - Path Path // empty if this AS is not at the source of the reservation + Path Path // empty if not at the source of the reservation PathEndProps reservation.PathEndProps // the properties for stitching and start/end TrafficSplit reservation.SplitCls // the traffic split between control and data planes } From d3f5f8924162159dda2f3b427d6ff270a160b61e Mon Sep 17 00:00:00 2001 From: "Juan A. Garcia Pardo" Date: Thu, 18 Jun 2020 21:53:41 +0200 Subject: [PATCH 22/22] check Path against zero-length instead --- go/cs/reservation/segment/path.go | 10 +++++----- go/cs/reservation/segment/path_test.go | 22 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/go/cs/reservation/segment/path.go b/go/cs/reservation/segment/path.go index 6d0fdf3577..190df45218 100644 --- a/go/cs/reservation/segment/path.go +++ b/go/cs/reservation/segment/path.go @@ -76,7 +76,7 @@ func (p Path) Equal(o Path) bool { // source AS of the reservation and has no access to the Path of the reservation). // If the Path is not nil, it assumes is valid, i.e. it has at least length 2. func (p Path) GetSrcIA() addr.IA { - if p == nil { + if len(p) == 0 { return addr.IA{} } return p[0].IA @@ -86,7 +86,7 @@ func (p Path) GetSrcIA() addr.IA { // source AS of the reservation and has no access to the Path of the reservation). // If the Path is not nil, it assumes is valid, i.e. it has at least length 2. func (p Path) GetDstIA() addr.IA { - if p == nil { + if len(p) == 0 { return addr.IA{} } return p[len(p)-1].IA @@ -94,14 +94,14 @@ func (p Path) GetDstIA() addr.IA { // Len returns the length of this Path in bytes, when serialized. func (p Path) Len() int { - if p == nil { + if len(p) == 0 { return 0 } return len(p) * PathStepWithIALen } func (p Path) Read(buff []byte) (int, error) { - if p == nil { + if len(p) == 0 { return 0, nil } if len(buff) < p.Len() { @@ -118,7 +118,7 @@ func (p Path) Read(buff []byte) (int, error) { // ToRaw returns a buffer representing this Path. func (p Path) ToRaw() []byte { - if p == nil { + if len(p) == 0 { return []byte{} } buff := make([]byte, p.Len()) diff --git a/go/cs/reservation/segment/path_test.go b/go/cs/reservation/segment/path_test.go index a4b651c0de..f3d83b94a6 100644 --- a/go/cs/reservation/segment/path_test.go +++ b/go/cs/reservation/segment/path_test.go @@ -74,6 +74,16 @@ func TestEqualPath(t *testing.T) { 1, "1-ff00:0:2", 0), IsEqual: true, }, + "eq3": { + Path1: nil, + Path2: nil, + IsEqual: true, + }, + "eq4": { + Path1: nil, + Path2: make(segment.Path, 0), + IsEqual: true, + }, "neq1": { Path1: segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0), Path2: segmenttest.NewPathFromComponents(1, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0), @@ -107,13 +117,15 @@ func TestEqualPath(t *testing.T) { } func TestGetIAs(t *testing.T) { - p := segmenttest.NewPathFromComponents(0, "1-ff00:0:1", 1, 1, "1-ff00:0:2", 0) require.Equal(t, xtest.MustParseIA("1-ff00:0:1"), p.GetSrcIA()) require.Equal(t, xtest.MustParseIA("1-ff00:0:2"), p.GetDstIA()) p = nil require.Equal(t, xtest.MustParseIA("0-0"), p.GetSrcIA()) require.Equal(t, xtest.MustParseIA("0-0"), p.GetDstIA()) + p = make(segment.Path, 0) + require.Equal(t, xtest.MustParseIA("0-0"), p.GetSrcIA()) + require.Equal(t, xtest.MustParseIA("0-0"), p.GetDstIA()) } func TestPathLen(t *testing.T) { @@ -123,6 +135,8 @@ func TestPathLen(t *testing.T) { require.Equal(t, 0, p.Len()) p = nil require.Equal(t, 0, p.Len()) + p = make(segment.Path, 0) + require.Equal(t, 0, p.Len()) } func TestToFromBinary(t *testing.T) { @@ -154,5 +168,9 @@ func TestToFromBinary(t *testing.T) { p, err = segment.NewPathFromRaw([]byte{}) require.NoError(t, err) require.Empty(t, p) - + // empty and nil path + p = nil + require.Empty(t, p.ToRaw()) + p = make(segment.Path, 0) + require.Empty(t, p.ToRaw()) }