-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add method to filter segments with a path policy (#3072)
This method pre-filters a list of segments with a given path policy. Note that filtering with sequences is not easily possible since we do not know where a segment would fit into the sequence (up, core, down). A possibility to add sequence filtering for segments would be to split the sequence into up, core, and down parts. Note that filtering with ACLs should only be done on core segments. Up and down segments contain peering interfaces which might be used in the final path, eventhough the ACL would filter it. Fixes #2820
- Loading branch information
1 parent
e09809d
commit 2bbb531
Showing
7 changed files
with
240 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") | ||
|
||
go_library( | ||
name = "go_default_library", | ||
srcs = ["filter.go"], | ||
importpath = "github.com/scionproto/scion/go/path_srv/internal/segutil", | ||
visibility = ["//go/path_srv:__subpackages__"], | ||
deps = [ | ||
"//go/lib/addr:go_default_library", | ||
"//go/lib/common:go_default_library", | ||
"//go/lib/ctrl/seg:go_default_library", | ||
"//go/lib/pathpol:go_default_library", | ||
], | ||
) | ||
|
||
go_test( | ||
name = "go_default_test", | ||
srcs = ["filter_test.go"], | ||
embed = [":go_default_library"], | ||
deps = [ | ||
"//go/lib/addr:go_default_library", | ||
"//go/lib/common:go_default_library", | ||
"//go/lib/ctrl/seg:go_default_library", | ||
"//go/lib/pathpol:go_default_library", | ||
"//go/lib/xtest:go_default_library", | ||
"//go/lib/xtest/graph:go_default_library", | ||
"@com_github_golang_mock//gomock:go_default_library", | ||
"@com_github_stretchr_testify//assert:go_default_library", | ||
"@com_github_stretchr_testify//require:go_default_library", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// 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 segutil | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/scionproto/scion/go/lib/addr" | ||
"github.com/scionproto/scion/go/lib/common" | ||
"github.com/scionproto/scion/go/lib/ctrl/seg" | ||
"github.com/scionproto/scion/go/lib/pathpol" | ||
) | ||
|
||
type Direction int | ||
|
||
const ( | ||
ReverseConsDir Direction = iota | ||
ConsDir | ||
) | ||
|
||
// Filter filters the given segments with the policy. Dir indicates the | ||
// direction of intended usage of the segments. For example up and core segments | ||
// are most often used in reverse construction dir. The direction parameter is | ||
// relevant for the sequence matching of policies. Note that order of segs is | ||
// not preserved. | ||
// NOTE: This function should only be applied on core segments, otherwise the PS | ||
// might filter segments that could still have been used in a final path, | ||
// because of peering links. | ||
func Filter(segs seg.Segments, policy *pathpol.Policy, dir Direction) seg.Segments { | ||
if policy == nil { | ||
return segs | ||
} | ||
// The sequence filter doesn't work for segments, therefore a policy | ||
// without sequence is used. | ||
actPolicy := pathpol.NewPolicy(policy.Name, policy.ACL, nil, policy.Options) | ||
return psToSegs(actPolicy.Act(segsToPs(segs, dir))) | ||
} | ||
|
||
func segsToPs(segs seg.Segments, dir Direction) pathpol.PathSet { | ||
ps := make(pathpol.PathSet, len(segs)) | ||
for _, seg := range segs { | ||
sw := wrap(seg, dir) | ||
ps[sw.Key()] = sw | ||
} | ||
return ps | ||
} | ||
|
||
func psToSegs(ps pathpol.PathSet) seg.Segments { | ||
segs := make(seg.Segments, 0, len(ps)) | ||
for _, sw := range ps { | ||
seg := sw.(segWrap).origSeg | ||
segs = append(segs, seg) | ||
} | ||
return segs | ||
} | ||
|
||
type segWrap struct { | ||
intfs []pathpol.PathInterface | ||
key string | ||
origSeg *seg.PathSegment | ||
} | ||
|
||
func wrap(seg *seg.PathSegment, dir Direction) segWrap { | ||
intfs := make([]pathpol.PathInterface, 0, len(seg.ASEntries)) | ||
keyParts := make([]string, 0, len(seg.ASEntries)) | ||
for _, asEntry := range seg.ASEntries { | ||
for _, hopEntry := range asEntry.HopEntries { | ||
hopField, err := hopEntry.HopField() | ||
// This library expects the segments to be verified first. | ||
if err != nil { | ||
panic(err) | ||
} | ||
for _, ifid := range []common.IFIDType{hopField.ConsIngress, hopField.ConsEgress} { | ||
if ifid != 0 { | ||
intfs = append(intfs, pathInterface{ia: asEntry.IA(), ifid: ifid}) | ||
keyParts = append(keyParts, fmt.Sprintf("%s#%d", asEntry.IA(), ifid)) | ||
} | ||
} | ||
} | ||
} | ||
if dir == ReverseConsDir { | ||
// reverse interfaces | ||
for left, right := 0, len(intfs)-1; left < right; left, right = left+1, right-1 { | ||
intfs[left], intfs[right] = intfs[right], intfs[left] | ||
} | ||
} | ||
return segWrap{ | ||
intfs: intfs, | ||
key: strings.Join(keyParts, " "), | ||
origSeg: seg, | ||
} | ||
} | ||
|
||
func (s segWrap) Interfaces() []pathpol.PathInterface { return s.intfs } | ||
func (s segWrap) Key() string { return s.key } | ||
|
||
type pathInterface struct { | ||
ia addr.IA | ||
ifid common.IFIDType | ||
} | ||
|
||
func (i pathInterface) IA() addr.IA { return i.ia } | ||
func (i pathInterface) IfId() common.IFIDType { return i.ifid } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// 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 segutil | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/golang/mock/gomock" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/scionproto/scion/go/lib/addr" | ||
"github.com/scionproto/scion/go/lib/common" | ||
"github.com/scionproto/scion/go/lib/ctrl/seg" | ||
"github.com/scionproto/scion/go/lib/pathpol" | ||
"github.com/scionproto/scion/go/lib/xtest" | ||
"github.com/scionproto/scion/go/lib/xtest/graph" | ||
) | ||
|
||
func TestFilter(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
g := graph.NewDefaultGraph(ctrl) | ||
ia110 := xtest.MustParseIA("1-ff00:0:110") | ||
ia111 := xtest.MustParseIA("1-ff00:0:111") | ||
ia120 := xtest.MustParseIA("1-ff00:0:120") | ||
seg110To120 := g.Beacon([]common.IFIDType{graph.If_110_X_120_A}) | ||
seg110To130 := g.Beacon([]common.IFIDType{graph.If_110_X_130_A}) | ||
|
||
tests := map[string]struct { | ||
Segs seg.Segments | ||
Dir Direction | ||
Policy *pathpol.Policy | ||
ExpectedSegs seg.Segments | ||
}{ | ||
"no policy": { | ||
Segs: seg.Segments{seg110To120, seg110To130}, | ||
ExpectedSegs: seg.Segments{seg110To120, seg110To130}, | ||
}, | ||
"acl policy": { | ||
Segs: seg.Segments{seg110To120, seg110To130}, | ||
Policy: &pathpol.Policy{ACL: acl(t, ia120)}, | ||
ExpectedSegs: seg.Segments{seg110To130}, | ||
}, | ||
"sequence policy doesn't filter": { | ||
Segs: seg.Segments{seg110To120, seg110To130}, | ||
Policy: &pathpol.Policy{Sequence: sequence(t, ia111, ia110)}, | ||
ExpectedSegs: seg.Segments{seg110To120, seg110To130}, | ||
}, | ||
} | ||
for name, test := range tests { | ||
t.Run(name, func(t *testing.T) { | ||
assert.ElementsMatch(t, test.ExpectedSegs, Filter(test.Segs, test.Policy, test.Dir)) | ||
}) | ||
} | ||
} | ||
|
||
func acl(t testing.TB, disallow addr.IA) *pathpol.ACL { | ||
var disallowEntry pathpol.ACLEntry | ||
err := disallowEntry.LoadFromString(fmt.Sprintf("- %s", disallow)) | ||
xtest.FailOnErr(t, err) | ||
var allowEntry pathpol.ACLEntry | ||
err = allowEntry.LoadFromString("+") | ||
xtest.FailOnErr(t, err) | ||
acl, err := pathpol.NewACL(&disallowEntry, &allowEntry) | ||
xtest.FailOnErr(t, err) | ||
return acl | ||
} | ||
|
||
func sequence(t testing.TB, ias ...addr.IA) *pathpol.Sequence { | ||
parts := make([]string, 0, len(ias)) | ||
for _, ia := range ias { | ||
parts = append(parts, ia.String()) | ||
} | ||
seq, err := pathpol.NewSequence(strings.Join(parts, " ")) | ||
require.NoError(t, err) | ||
return seq | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters