Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BS: Implement revocation part of DB #2644

Merged
merged 6 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go/beacon_srv/internal/beacon/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ go_library(
deps = [
"//go/lib/addr:go_default_library",
"//go/lib/common:go_default_library",
"//go/lib/ctrl/path_mgmt:go_default_library",
"//go/lib/ctrl/seg:go_default_library",
"//go/lib/infra/modules/db:go_default_library",
"//go/lib/log:go_default_library",
Expand Down
7 changes: 7 additions & 0 deletions go/beacon_srv/internal/beacon/beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package beacon
import (
"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/common"
"github.com/scionproto/scion/go/lib/ctrl/path_mgmt"
"github.com/scionproto/scion/go/lib/ctrl/seg"
)

Expand Down Expand Up @@ -59,3 +60,9 @@ type BeaconOrErr struct {
Beacon Beacon
Err error
}

// RevocationOrErr contains a signed revocation or an error.
type RevocationOrErr struct {
Rev *path_mgmt.SignedRevInfo
Err error
}
3 changes: 3 additions & 0 deletions go/beacon_srv/internal/beacon/beacondbsqlite/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ go_library(
"//go/beacon_srv/internal/beacon:go_default_library",
"//go/lib/addr:go_default_library",
"//go/lib/common:go_default_library",
"//go/lib/ctrl/path_mgmt:go_default_library",
"//go/lib/ctrl/seg:go_default_library",
"//go/lib/infra/modules/db:go_default_library",
"//go/lib/log:go_default_library",
"//go/lib/util:go_default_library",
"@com_github_mattn_go_sqlite3//:go_default_library",
],
)
Expand Down
167 changes: 152 additions & 15 deletions go/beacon_srv/internal/beacon/beacondbsqlite/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package beacondbsqlite
import (
"context"
"database/sql"
"fmt"
"sync"
"time"

Expand All @@ -25,8 +26,11 @@ import (
"github.com/scionproto/scion/go/beacon_srv/internal/beacon"
"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/common"
"github.com/scionproto/scion/go/lib/ctrl/path_mgmt"
"github.com/scionproto/scion/go/lib/ctrl/seg"
"github.com/scionproto/scion/go/lib/infra/modules/db"
"github.com/scionproto/scion/go/lib/log"
"github.com/scionproto/scion/go/lib/util"
)

var _ beacon.DB = (*Backend)(nil)
Expand Down Expand Up @@ -120,6 +124,43 @@ type beaconMeta struct {
LastUpdated time.Time
}

func (e *executor) AllRevocations(ctx context.Context) (<-chan beacon.RevocationOrErr, error) {

e.RLock()
defer e.RUnlock()
query := `SELECT RawSignedRev FROM Revocations`
rows, err := e.db.QueryContext(ctx, query)
if err != nil {
return nil, common.NewBasicError("Error selecting revocations", err)
}
res := make(chan beacon.RevocationOrErr)
go func() {
defer log.LogPanicAndExit()
defer close(res)
defer rows.Close()
for rows.Next() {
var rawRev common.RawBytes
err = rows.Scan(&rawRev)
if err != nil {
res <- beacon.RevocationOrErr{Err: common.NewBasicError(beacon.ErrReadingRows, err)}
return
}
srev, err := path_mgmt.NewSignedRevInfoFromRaw(rawRev)
if err != nil {
err = common.NewBasicError(beacon.ErrParse, err)
}
res <- beacon.RevocationOrErr{
Rev: srev,
Err: err,
}
// Continue here as this should not really happen if the insertion
// is properly guarded.
// Like this the client might still be able to proceed.
}
}()
return res, nil
}

func (e *executor) BeaconSources(ctx context.Context) ([]addr.IA, error) {

e.RLock()
Expand Down Expand Up @@ -156,14 +197,26 @@ func (e *executor) CandidateBeacons(ctx context.Context, setSize int, usage beac
if e.db == nil {
return nil, common.NewBasicError("No database open", nil)
}
query := `SELECT Beacon, InIntfID FROM Beacons
WHERE ( Usage & ?1 ) == ?1 ORDER BY HopsLength ASC LIMIT ?2`
srcCond := ``
if !src.IsZero() {
query = `SELECT Beacon, InIntfID FROM Beacons
WHERE ( Usage & ?1 ) == ?1 AND StartIsd == ?3 AND StartAs == ?4
ORDER BY HopsLength ASC LIMIT ?2`
}
rows, err := e.db.QueryContext(ctx, query, usage, setSize, src.I, src.A)
srcCond = `AND StartIsd == ?4 AND StartAs == ?5`
}
query := fmt.Sprintf(`
SELECT b.Beacon, b.InIntfID
FROM Beacons b
JOIN IntfToBeacon ib ON b.RowId = ib.BeaconRowID
WHERE ( b.Usage & ?1 ) == ?1 %s AND NOT EXISTS(
SELECT 1
FROM IntfToBeacon ib
JOIN Revocations r USING (IsdID, AsID, IntfID)
WHERE ib.BeaconRowID = RowID AND r.ExpirationTime >= ?3
)
GROUP BY b.RowID
ORDER BY b.HopsLength ASC
LIMIT ?2
`, srcCond)
rows, err := e.db.QueryContext(ctx, query, usage, setSize, util.TimeToSecs(time.Now()),
src.I, src.A)
if err != nil {
return nil, common.NewBasicError("Error selecting beacons", err)
}
Expand All @@ -175,12 +228,12 @@ func (e *executor) CandidateBeacons(ctx context.Context, setSize int, usage beac
var rawBeacon sql.RawBytes
var inIntfId common.IFIDType
if err = rows.Scan(&rawBeacon, &inIntfId); err != nil {
errors = append(errors, err)
errors = append(errors, common.NewBasicError(beacon.ErrReadingRows, err))
continue
}
s, err := seg.NewBeaconFromRaw(common.RawBytes(rawBeacon))
if err != nil {
errors = append(errors, common.NewBasicError("Unable to parse beacon", err))
errors = append(errors, common.NewBasicError(beacon.ErrParse, err))
}
beacons = append(beacons, beacon.Beacon{Segment: s, InIfId: inIntfId})
}
Expand Down Expand Up @@ -321,18 +374,20 @@ func insertNewBeacon(ctx context.Context, tx *sql.Tx, b beacon.Beacon,
lastUpdated := now.UnixNano()
expTime := b.Segment.MaxExpiry().Unix()

// Insert path segment.
inst := `INSERT INTO Beacons (SegID, FullID, StartIsd, StartAs, InIntfID, HopsLength, InfoTime,
ExpirationTime, LastUpdated, Usage, Beacon)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
// Insert beacon.
inst := `
INSERT INTO Beacons (SegID, FullID, StartIsd, StartAs, InIntfID, HopsLength, InfoTime,
ExpirationTime, LastUpdated, Usage, Beacon)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`
res, err := tx.ExecContext(ctx, inst, segId, fullId, start.I, start.A, b.InIfId,
len(b.Segment.ASEntries), infoTime, expTime, lastUpdated, usage, packed)
if err != nil {
return common.NewBasicError("Failed to insert path segment", err)
return common.NewBasicError("Failed to insert beacon", err)
}
rowId, err := res.LastInsertId()
if err != nil {
return common.NewBasicError("Failed to retrieve segRowID of inserted segment", err)
return common.NewBasicError("Failed to retrieve RowID of inserted beacon", err)
}
// Insert all interfaces.
if err = insertInterfaces(ctx, tx, b, rowId, localIA); err != nil {
Expand Down Expand Up @@ -410,3 +465,85 @@ func (e *executor) deleteInTx(ctx context.Context,
deleted, _ := res.RowsAffected()
return int(deleted), nil
}

func (e *executor) DeleteRevokedBeacons(ctx context.Context, now time.Time) (int, error) {
return e.deleteInTx(ctx, func(tx *sql.Tx) (sql.Result, error) {
delStmt := `
DELETE FROM Beacons
WHERE EXISTS(
SELECT 1
FROM IntfToBeacon ib
JOIN Revocations r USING (IsdID, AsID, IntfID)
WHERE ib.BeaconRowID = RowID AND r.ExpirationTime >= ?
)
`
return tx.ExecContext(ctx, delStmt, now.Unix())
})
}

func (e *executor) InsertRevocation(ctx context.Context,
revocation *path_mgmt.SignedRevInfo) error {

revInfo, err := revocation.RevInfo()
if err != nil {
return common.NewBasicError("Failed to extract revocation", err)
}
packedRev, err := revocation.Pack()
if err != nil {
return common.NewBasicError("Failed to pack revocation", err)
}
e.Lock()
defer e.Unlock()
query := `
INSERT OR REPLACE INTO Revocations
(IsdID, AsID, IntfID, LinkType, IssuingTime, ExpirationTime, RawSignedRev)
VALUES (?, ?, ?, ?, ?, ?, ?)
`
return db.DoInTx(ctx, e.db, func(ctx context.Context, tx *sql.Tx) error {
existingRev, err := containsNewerRev(ctx, tx, revInfo)
if err != nil {
return common.NewBasicError("Failed to check for existing rev", err)
}
if !existingRev {
_, err = tx.ExecContext(ctx, query, revInfo.IA().I, revInfo.IA().A, revInfo.IfID,
revInfo.LinkType, revInfo.RawTimestamp, revInfo.Expiration().Unix(), packedRev)
}
return err
})
}

func containsNewerRev(ctx context.Context, tx *sql.Tx,
revInfo *path_mgmt.RevInfo) (bool, error) {

query := `
SELECT 1 FROM Revocations
WHERE IsdID = ? AND AsID = ? AND IntfID = ? AND IssuingTime > ?
`
err := tx.QueryRowContext(ctx, query, revInfo.IA().I, revInfo.IA().A,
revInfo.IfID, revInfo.RawTimestamp).Scan()
if err == sql.ErrNoRows {
return false, nil
}
return err == nil, err
}

func (e *executor) DeleteRevocation(ctx context.Context, ia addr.IA, ifid common.IFIDType) error {
query := `
DELETE FROM Revocations
WHERE IsdID = ? AND AsID = ? AND IntfID = ?
`
_, err := e.deleteInTx(ctx, func(tx *sql.Tx) (sql.Result, error) {
return tx.ExecContext(ctx, query, ia.I, ia.A, ifid)
})
return err
}

func (e *executor) DeleteExpiredRevocations(ctx context.Context, now time.Time) (int, error) {
query := `
DELETE FROM Revocations
WHERE ExpirationTime < ?
`
return e.deleteInTx(ctx, func(tx *sql.Tx) (sql.Result, error) {
return tx.ExecContext(ctx, query, now.Unix())
})
}
1 change: 1 addition & 0 deletions go/beacon_srv/internal/beacon/beacondbsqlite/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const (
AsID INTEGER NOT NULL,
IntfID INTEGER NOT NULL,
LinkType INTEGER NOT NULL,
IssuingTime INTEGER NOT NULL,
ExpirationTime INTEGER NOT NULL,
RawSignedRev BLOB NOT NULL,
PRIMARY KEY (IsdID, AsID, IntfID)
Expand Down
3 changes: 3 additions & 0 deletions go/beacon_srv/internal/beacon/beacondbtest/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ go_library(
"//go/beacon_srv/internal/beacon:go_default_library",
"//go/lib/addr:go_default_library",
"//go/lib/common:go_default_library",
"//go/lib/ctrl/path_mgmt:go_default_library",
"//go/lib/ctrl/seg:go_default_library",
"//go/lib/ctrl/seg/mock_seg:go_default_library",
"//go/lib/infra:go_default_library",
"//go/lib/spath:go_default_library",
"//go/lib/util:go_default_library",
"//go/lib/xtest:go_default_library",
"//go/proto:go_default_library",
"@com_github_golang_mock//gomock:go_default_library",
Expand Down
Loading