Skip to content

Commit

Permalink
Introduce request splitter (#2898)
Browse files Browse the repository at this point in the history
This is the first part of the new path lookup strategy.
It splits up a request into up, core, and down parts.

Contributes #2454
  • Loading branch information
lukedirtwalker authored Jul 24, 2019
1 parent 8babff1 commit d0d1b10
Show file tree
Hide file tree
Showing 7 changed files with 459 additions and 4 deletions.
16 changes: 14 additions & 2 deletions go/lib/infra/modules/segfetcher/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = ["segreplyhandler.go"],
srcs = [
"request.go",
"segreplyhandler.go",
"splitter.go",
],
importpath = "github.com/scionproto/scion/go/lib/infra/modules/segfetcher",
visibility = ["//visibility:public"],
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",
Expand All @@ -15,21 +20,28 @@ go_library(
"//go/lib/pathdb:go_default_library",
"//go/lib/pathdb/query:go_default_library",
"//go/lib/revcache:go_default_library",
"//go/lib/scrypto:go_default_library",
"//go/lib/scrypto/trc:go_default_library",
],
)

go_test(
name = "go_default_test",
srcs = ["segreplyhandler_test.go"],
srcs = [
"segreplyhandler_test.go",
"splitter_test.go",
],
embed = [":go_default_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:go_default_library",
"//go/lib/infra/modules/segfetcher/mock_segfetcher:go_default_library",
"//go/lib/infra/modules/segverifier:go_default_library",
"//go/lib/pathdb/query:go_default_library",
"//go/lib/scrypto/trc:go_default_library",
"//go/lib/xtest:go_default_library",
"//go/proto:go_default_library",
"@com_github_golang_mock//gomock:go_default_library",
Expand Down
2 changes: 2 additions & 0 deletions go/lib/infra/modules/segfetcher/mock_segfetcher/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ go_library(
importpath = "github.com/scionproto/scion/go/lib/infra/modules/segfetcher/mock_segfetcher",
visibility = ["//visibility:public"],
deps = [
"//go/lib/addr:go_default_library",
"//go/lib/ctrl/path_mgmt:go_default_library",
"//go/lib/infra/modules/segfetcher:go_default_library",
"//go/lib/infra/modules/segverifier:go_default_library",
"//go/lib/scrypto/trc:go_default_library",
"@com_github_golang_mock//gomock:go_default_library",
],
)
42 changes: 41 additions & 1 deletion go/lib/infra/modules/segfetcher/mock_segfetcher/segfetcher.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions go/lib/infra/modules/segfetcher/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2019 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 segfetcher

import "github.com/scionproto/scion/go/lib/addr"

// Request represents a path or segment request.
type Request struct {
Src addr.IA
Dst addr.IA
}

// IsZero returns whether the request is empty.
func (r Request) IsZero() bool {
return r.Src.IsZero() && r.Dst.IsZero()
}

// RequestSet is a set of requests.
type RequestSet struct {
Up Request
Cores Requests
Down Request
}

// IsEmpty returns whether the request set is empty.
func (r RequestSet) IsEmpty() bool {
return r.Up.IsZero() && r.Cores.IsEmpty() && r.Down.IsZero()
}

// Requests is a list of requests and provides some convenience methods on top
// of it.
type Requests []Request

// SrcIAs returns all unique sources in the request list.
func (r Requests) SrcIAs() []addr.IA {
return r.extractIAs(func(req Request) addr.IA { return req.Src })
}

// DstIAs returns all unique destinations in the request list.
func (r Requests) DstIAs() []addr.IA {
return r.extractIAs(func(req Request) addr.IA { return req.Dst })
}

// IsEmpty returns whether the list of requests is empty.
func (r Requests) IsEmpty() bool {
return len(r) == 0
}

func (r Requests) extractIAs(extract func(Request) addr.IA) []addr.IA {
set := make(map[addr.IA]struct{})
for _, req := range r {
set[extract(req)] = struct{}{}
}
ias := make([]addr.IA, 0, len(set))
for ia := range set {
ias = append(ias, ia)
}
return ias
}
148 changes: 148 additions & 0 deletions go/lib/infra/modules/segfetcher/splitter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright 2019 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 segfetcher

import (
"context"
"time"

"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/scrypto"
"github.com/scionproto/scion/go/lib/scrypto/trc"
)

// TRCProvider provides TRCs.
type TRCProvider interface {
GetTRC(ctx context.Context, isd addr.ISD, version uint64) (*trc.TRC, error)
}

// RequestSplitter splits a single request into a request set.
type RequestSplitter interface {
// Split splits the request into a request set. Assumes that the request
// has been validated for the local IA.
Split(ctx context.Context, r Request) (RequestSet, error)
}

// NewRequestSplitter creates a request splitter for the given local IA. The
// TRC provider is used to get TRCs and check whether an IA is core or not.
func NewRequestSplitter(localIA addr.IA, trcProvider TRCProvider) (RequestSplitter, error) {
ctx, cancelF := context.WithTimeout(context.Background(), time.Second)
defer cancelF()
baseSplitter := baseRequestSplitter{
LocalIA: localIA,
TRCProvider: trcProvider,
}
core, err := baseSplitter.isCore(ctx, localIA)
if err != nil {
return nil, err
}
if core {
return &coreRequestSplitter{
baseRequestSplitter: baseSplitter,
}, nil
}
return &nonCoreRequestSplitter{
baseRequestSplitter: baseSplitter,
}, nil
}

// baseRequestSplitter implements common functionality for request splitters.
type baseRequestSplitter struct {
LocalIA addr.IA
TRCProvider TRCProvider
}

func (s *baseRequestSplitter) isCore(ctx context.Context, dst addr.IA) (bool, error) {
if s.isWildCard(dst) {
return true, nil
}
trc, err := s.TRCProvider.GetTRC(ctx, dst.I, scrypto.LatestVer)
if err != nil {
return false, err
}
return trc.CoreASes.Contains(dst), nil
}

func (s *baseRequestSplitter) isISDLocal(dst addr.IA) bool {
return s.LocalIA.I == dst.I
}

func (s *baseRequestSplitter) isWildCard(dst addr.IA) bool {
return dst.A == 0
}

func (s *baseRequestSplitter) toWildCard(dst addr.IA) addr.IA {
return addr.IA{I: dst.I}
}

func (s *baseRequestSplitter) srcOrLocalIA(src addr.IA) addr.IA {
if src.IsZero() {
return s.LocalIA
}
return src
}

type coreRequestSplitter struct {
baseRequestSplitter
}

func (s *coreRequestSplitter) Split(ctx context.Context, r Request) (RequestSet, error) {
core, err := s.isCore(ctx, r.Dst)
if err != nil {
return RequestSet{}, err
}
src := s.srcOrLocalIA(r.Src)
if core {
// core to core
return RequestSet{
Cores: []Request{{Src: src, Dst: r.Dst}},
}, nil
}
return RequestSet{
Cores: []Request{{Src: src, Dst: s.toWildCard(r.Dst)}},
Down: Request{Src: s.toWildCard(r.Dst), Dst: r.Dst},
}, nil
}

type nonCoreRequestSplitter struct {
baseRequestSplitter
}

func (s *nonCoreRequestSplitter) Split(ctx context.Context, r Request) (RequestSet, error) {
core, err := s.isCore(ctx, r.Dst)
if err != nil {
return RequestSet{}, err
}
wildcard := s.isWildCard(r.Dst)
local := s.isISDLocal(r.Dst)
src := s.srcOrLocalIA(r.Src)
switch {
case core && wildcard && local:
return RequestSet{
Up: Request{Src: src, Dst: r.Dst},
}, nil
case core:
return RequestSet{
Up: Request{Src: src, Dst: s.toWildCard(src)},
Cores: []Request{{Src: s.toWildCard(src), Dst: r.Dst}},
}, nil
default:
return RequestSet{
Up: Request{Src: src, Dst: s.toWildCard(src)},
Cores: []Request{{Src: s.toWildCard(src), Dst: s.toWildCard(r.Dst)}},
Down: Request{Src: s.toWildCard(r.Dst), Dst: r.Dst},
}, nil
}
}
Loading

0 comments on commit d0d1b10

Please sign in to comment.