From e9f9b496a801e814ee6b65e7de03c23f19f38c7d Mon Sep 17 00:00:00 2001 From: mawyss Date: Sat, 12 Mar 2022 13:34:32 +0100 Subject: [PATCH] epic: endhost logic This PR implements the EPIC endhost logic. Applications can now send packets using the EPIC path type header. Major changes: - The gRPC communication between the SCION daemon and the application is extended, so that the application gets the two authenticators necessary to calculate the PHVF and LHVF when fetching paths from the daemon. - `snet` contains the major logic behind the creation of EPIC packets, where `snet/path` keeps the necessary state and uses it to create the PHVF and LHVF when the packet is serialized. - There is an additional argument "--epic" for the ping, traceroute, showpaths, end2end_integration, and scion_integration tools. The argument enables those tools to send EPIC-HP path type packets (if paths with the necessary EPIC authenticators are available). Closes #4079 GitOrigin-RevId: f7436eb98840064fc905d56602ae8d65f7f44106 --- go/cs/config/bs_sample.go | 3 + go/cs/config/config.go | 2 + go/cs/main.go | 1 + go/dispatcher/dispatcher/BUILD.bazel | 2 + go/dispatcher/dispatcher/underlay.go | 11 + go/integration/end2end/main.go | 23 +- go/integration/end2end_integration/main.go | 4 + go/integration/scion_integration/main.go | 4 +- go/lib/daemon/grpc.go | 13 +- go/lib/epic/epic.go | 2 +- go/lib/infra/modules/combinator/graph.go | 58 ++- go/lib/snet/BUILD.bazel | 1 + go/lib/snet/path.go | 20 + go/lib/snet/path/BUILD.bazel | 3 + go/lib/snet/path/epic.go | 96 ++++ go/lib/snet/reply_pather.go | 7 + go/pkg/app/path/path.go | 30 +- go/pkg/cs/tasks.go | 4 +- go/pkg/daemon/internal/servers/grpc.go | 7 + go/pkg/pathprobe/paths.go | 55 ++- go/pkg/proto/daemon/daemon.pb.go | 487 ++++++++++++--------- go/pkg/router/dataplane.go | 45 +- go/pkg/showpaths/config.go | 3 + go/pkg/showpaths/showpaths.go | 16 +- go/pkg/traceroute/traceroute.go | 21 +- go/scion/BUILD.bazel | 1 + go/scion/ping.go | 23 +- go/scion/showpaths.go | 1 + go/scion/traceroute.go | 5 +- proto/daemon/v1/daemon.proto | 9 + 30 files changed, 717 insertions(+), 240 deletions(-) create mode 100644 go/lib/snet/path/epic.go diff --git a/go/cs/config/bs_sample.go b/go/cs/config/bs_sample.go index 812efce996..bd207c5875 100644 --- a/go/cs/config/bs_sample.go +++ b/go/cs/config/bs_sample.go @@ -23,6 +23,9 @@ propagation_interval = "5s" # The interval between registering beacons. (default 5s) registration_interval = "5s" + +# Add EPIC authenticators to the beacons. (default false) +epic = false ` const policiesSample = ` diff --git a/go/cs/config/config.go b/go/cs/config/config.go index af7e6412d7..cdea6d073d 100644 --- a/go/cs/config/config.go +++ b/go/cs/config/config.go @@ -153,6 +153,8 @@ type BSConfig struct { RegistrationInterval util.DurWrap `toml:"registration_interval,omitempty"` // Policies contains the policy files. Policies Policies `toml:"policies,omitempty"` + // EPIC specifies whether the EPIC authenticators should be added to the beacons. + EPIC bool `toml:"epic,omitempty" default:"false"` } // InitDefaults the default values for the durations that are equal to zero. diff --git a/go/cs/main.go b/go/cs/main.go index 072c8b66f7..820ee55064 100644 --- a/go/cs/main.go +++ b/go/cs/main.go @@ -651,6 +651,7 @@ func realMain(ctx context.Context) error { RegistrationInterval: globalCfg.BS.RegistrationInterval.Duration, HiddenPathRegistrationCfg: hpWriterCfg, AllowIsdLoop: isdLoopAllowed, + EPIC: globalCfg.BS.EPIC, }) if err != nil { return serrors.WrapStr("starting periodic tasks", err) diff --git a/go/dispatcher/dispatcher/BUILD.bazel b/go/dispatcher/dispatcher/BUILD.bazel index df5fe25e05..374753efff 100644 --- a/go/dispatcher/dispatcher/BUILD.bazel +++ b/go/dispatcher/dispatcher/BUILD.bazel @@ -19,6 +19,8 @@ go_library( "//go/lib/ringbuf:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/slayers:go_default_library", + "//go/lib/slayers/path/epic:go_default_library", + "//go/lib/slayers/path/scion:go_default_library", "//go/lib/underlay/conn:go_default_library", "@com_github_google_gopacket//:go_default_library", ], diff --git a/go/dispatcher/dispatcher/underlay.go b/go/dispatcher/dispatcher/underlay.go index 44c0edb17f..4da7798e83 100644 --- a/go/dispatcher/dispatcher/underlay.go +++ b/go/dispatcher/dispatcher/underlay.go @@ -28,6 +28,8 @@ import ( "github.com/scionproto/scion/go/lib/ringbuf" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/slayers" + "github.com/scionproto/scion/go/lib/slayers/path/epic" + "github.com/scionproto/scion/go/lib/slayers/path/scion" ) const ( @@ -343,6 +345,15 @@ func (h SCMPHandler) reverseSCION(pkt *respool.Packet) error { if err := pkt.SCION.SetDstAddr(src); err != nil { return serrors.WrapStr("setting destination address", err) } + if pkt.SCION.PathType == epic.PathType { + // Received packet with EPIC path type, hence extract the SCION path + epicPath, ok := pkt.SCION.Path.(*epic.Path) + if !ok { + return serrors.New("path type and path data do not match") + } + pkt.SCION.Path = epicPath.ScionPath + pkt.SCION.PathType = scion.PathType + } if pkt.SCION.Path, err = pkt.SCION.Path.Reverse(); err != nil { return serrors.WrapStr("reversing path", err) } diff --git a/go/integration/end2end/main.go b/go/integration/end2end/main.go index 82fea8bcdd..4d46318d4e 100644 --- a/go/integration/end2end/main.go +++ b/go/integration/end2end/main.go @@ -68,6 +68,7 @@ var ( timeout = &util.DurWrap{Duration: 10 * time.Second} scionPacketConnMetrics = metrics.NewSCIONPacketConnMetrics() scmpErrorsCounter = scionPacketConnMetrics.SCMPErrors + epic bool ) func main() { @@ -98,6 +99,7 @@ func realMain() int { func addFlags() { flag.Var(&remote, "remote", "(Mandatory for clients) address to connect to") flag.Var(timeout, "timeout", "The timeout for each attempt") + flag.BoolVar(&epic, "epic", false, "Enable EPIC.") } func validateFlags() { @@ -361,11 +363,11 @@ func (c *client) getRemote(ctx context.Context, n int) (snet.Path, error) { if err != nil { return nil, withTag(serrors.WrapStr("requesting paths", err)) } - // if all paths had an error, let's try them again. + // If all paths had an error, let's try them again. if len(paths) <= len(c.errorPaths) { c.errorPaths = make(map[snet.PathFingerprint]struct{}) } - // select first path that didn't error before. + // Select first path that didn't error before. var path snet.Path for _, p := range paths { if _, ok := c.errorPaths[snet.Fingerprint(p)]; ok { @@ -380,8 +382,21 @@ func (c *client) getRemote(ctx context.Context, n int) (snet.Path, error) { "errors", len(c.errorPaths), )) } - // Extract forwarding path from the SCION Daemon response - remote.Path = path.Dataplane() + // Extract forwarding path from the SCION Daemon response. + // If the epic flag is set, try to use the EPIC path type header. + if epic { + scionPath, ok := path.Dataplane().(snetpath.SCION) + if !ok { + return nil, serrors.New("provided path must be of type scion") + } + epicPath, err := snetpath.NewEPICDataplanePath(scionPath, path.Metadata().EpicAuths) + if err != nil { + return nil, err + } + remote.Path = epicPath + } else { + remote.Path = path.Dataplane() + } remote.NextHop = path.UnderlayNextHop() return path, nil } diff --git a/go/integration/end2end_integration/main.go b/go/integration/end2end_integration/main.go index 7cbe1d0a81..6864fc1c15 100644 --- a/go/integration/end2end_integration/main.go +++ b/go/integration/end2end_integration/main.go @@ -42,6 +42,7 @@ var ( name string cmd string features string + epic bool ) func getCmd() (string, bool) { @@ -74,6 +75,7 @@ func realMain() int { "-sciond", integration.Daemon, "-local", integration.SrcAddrPattern + ":0", "-remote", integration.DstAddrPattern + ":" + integration.ServerPortReplace, + fmt.Sprintf("-epic=%t", epic), } serverArgs := []string{ "-mode", "server", @@ -111,6 +113,7 @@ func addFlags() { flag.IntVar(¶llelism, "parallelism", 1, "How many end2end tests run in parallel.") flag.StringVar(&features, "features", "", fmt.Sprintf("enable development features (%v)", feature.String(&feature.Default{}, "|"))) + flag.BoolVar(&epic, "epic", false, "Enable EPIC.") } // runTests runs the end2end tests for all pairs. In case of an error the @@ -275,6 +278,7 @@ func clientTemplate(progressSock string) integration.Cmd { "-sciond", integration.Daemon, "-local", integration.SrcAddrPattern + ":0", "-remote", integration.DstAddrPattern + ":" + integration.ServerPortReplace, + fmt.Sprintf("-epic=%t", epic), }, } if len(features) != 0 { diff --git a/go/integration/scion_integration/main.go b/go/integration/scion_integration/main.go index b4696d564d..bb6c4f31e4 100644 --- a/go/integration/scion_integration/main.go +++ b/go/integration/scion_integration/main.go @@ -29,6 +29,7 @@ import ( var ( features string test string + epic bool ) func main() { @@ -54,6 +55,7 @@ func realMain() int { "--timeout", "4s", "--sciond", integration.Daemon, "--log.level", "debug", + fmt.Sprintf("--epic=%t", epic), } if *integration.Docker { cmnArgs = append(cmnArgs, @@ -123,5 +125,5 @@ func addFlags() { fmt.Sprintf("enable development features (%v)", feature.String(&feature.Default{}, "|"))) flag.StringVar(&test, "test", "", "Test to run. If empty, all tests are run.") - + flag.BoolVar(&epic, "epic", false, "Enable EPIC.") } diff --git a/go/lib/daemon/grpc.go b/go/lib/daemon/grpc.go index 8534730c40..a8cee33e5b 100644 --- a/go/lib/daemon/grpc.go +++ b/go/lib/daemon/grpc.go @@ -212,7 +212,7 @@ func convertPath(p *sdpb.Path, dst addr.IA) (path.Path, error) { linkType[i] = linkTypeFromPB(v) } - return path.Path{ + res := path.Path{ Src: interfaces[0].IA, Dst: dst, DataplanePath: path.SCION{ @@ -230,7 +230,16 @@ func convertPath(p *sdpb.Path, dst addr.IA) (path.Path, error) { InternalHops: p.InternalHops, Notes: p.Notes, }, - }, nil + } + + if p.EpicAuths == nil { + return res, nil + } + res.Meta.EpicAuths = snet.EpicAuths{ + AuthPHVF: append([]byte(nil), p.EpicAuths.AuthPhvf...), + AuthLHVF: append([]byte(nil), p.EpicAuths.AuthLhvf...), + } + return res, nil } func linkTypeFromPB(lt sdpb.LinkType) snet.LinkType { diff --git a/go/lib/epic/epic.go b/go/lib/epic/epic.go index f738a7d3c6..83c3cee2d8 100644 --- a/go/lib/epic/epic.go +++ b/go/lib/epic/epic.go @@ -132,7 +132,7 @@ func VerifyHVF(auth []byte, pktID epic.PktID, s *slayers.SCION, if subtle.ConstantTimeCompare(hvf, mac) == 0 { return serrors.New("epic hop validation field verification failed", - "hvf in packet", hvf, "calculated mac", mac) + "hvf in packet", hvf, "calculated mac", mac, "auth", auth) } return nil } diff --git a/go/lib/infra/modules/combinator/graph.go b/go/lib/infra/modules/combinator/graph.go index 51736182ec..39036201c8 100644 --- a/go/lib/infra/modules/combinator/graph.go +++ b/go/lib/infra/modules/combinator/graph.go @@ -309,10 +309,12 @@ type pathSolution struct { func (solution *pathSolution) Path() Path { mtu := ^uint16(0) var segments segmentList + var epicPathAuths [][]byte for _, solEdge := range solution.edges { var hops []path.HopField var intfs []snet.PathInterface var pathASEntries []seg.ASEntry // ASEntries that on the path, eventually in path order. + var epicSegAuths [][]byte // Go through each ASEntry, starting from the last one, until we // find a shortcut (which can be 0, meaning the end of the segment). @@ -324,6 +326,7 @@ func (solution *pathSolution) Path() Path { var hopField path.HopField var forwardingLinkMtu int + var epicAuth []byte if !isPeer { // Regular hop field. entry := asEntry.HopEntry @@ -334,6 +337,7 @@ func (solution *pathSolution) Path() Path { Mac: entry.HopField.MAC, } forwardingLinkMtu = entry.IngressMTU + epicAuth = getAuth(&asEntry) } else { // We've reached the ASEntry where we want to switch // segments on a peering link. @@ -345,6 +349,7 @@ func (solution *pathSolution) Path() Path { Mac: peer.HopField.MAC, } forwardingLinkMtu = peer.PeerMTU + epicAuth = getAuthPeer(&asEntry, solEdge.edge.Peer-1) } // Segment is traversed in reverse construction direction. @@ -364,6 +369,7 @@ func (solution *pathSolution) Path() Path { } hops = append(hops, hopField) pathASEntries = append(pathASEntries, asEntry) + epicSegAuths = append(epicSegAuths, epicAuth) mtu = minUint16(mtu, uint16(asEntry.MTU)) if forwardingLinkMtu != 0 { @@ -376,6 +382,7 @@ func (solution *pathSolution) Path() Path { reverseHops(hops) reverseIntfs(intfs) reverseASEntries(pathASEntries) + reverseEpicAuths(epicSegAuths) } segments = append(segments, segment{ @@ -389,13 +396,14 @@ func (solution *pathSolution) Path() Path { Interfaces: intfs, ASEntries: pathASEntries, }) + epicPathAuths = append(epicPathAuths, epicSegAuths...) } interfaces := segments.Interfaces() asEntries := segments.ASEntries() staticInfo := collectMetadata(interfaces, asEntries) - return Path{ + path := Path{ SCIONPath: segments.ScionPath(), Metadata: snet.PathMetadata{ Interfaces: interfaces, @@ -410,6 +418,48 @@ func (solution *pathSolution) Path() Path { }, Weight: solution.cost, } + + if authPHVF, authLHVF, ok := isEpicAvailable(epicPathAuths); ok { + path.Metadata.EpicAuths = snet.EpicAuths{ + AuthPHVF: authPHVF, + AuthLHVF: authLHVF, + } + } + + return path +} + +func getAuth(a *seg.ASEntry) []byte { + if a.UnsignedExtensions.EpicDetached == nil { + return nil + } + + auth := make([]byte, 16) + copy(auth[0:6], a.HopEntry.HopField.MAC[:]) + copy(auth[6:16], a.UnsignedExtensions.EpicDetached.AuthHopEntry) + return auth +} + +func getAuthPeer(a *seg.ASEntry, i int) []byte { + if a.UnsignedExtensions.EpicDetached == nil { + return nil + } + + auth := make([]byte, 16) + copy(auth[0:6], a.HopEntry.HopField.MAC[:]) + copy(auth[6:16], a.UnsignedExtensions.EpicDetached.AuthPeerEntries[i]) + return auth +} + +func isEpicAvailable(epicPathAuths [][]byte) ([]byte, []byte, bool) { + l := len(epicPathAuths) + if l < 2 { + return nil, nil, false + } + if epicPathAuths[l-1] == nil || epicPathAuths[l-2] == nil { + return nil, nil, false + } + return epicPathAuths[l-2], epicPathAuths[l-1], true } func reverseHops(s []path.HopField) { @@ -430,6 +480,12 @@ func reverseASEntries(s []seg.ASEntry) { } } +func reverseEpicAuths(s [][]byte) { + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } +} + func calculateBeta(se *solutionEdge) uint16 { var index int if se.segment.IsDownSeg() { diff --git a/go/lib/snet/BUILD.bazel b/go/lib/snet/BUILD.bazel index 435d708948..cff0daa0e4 100644 --- a/go/lib/snet/BUILD.bazel +++ b/go/lib/snet/BUILD.bazel @@ -29,6 +29,7 @@ go_library( "//go/lib/serrors:go_default_library", "//go/lib/slayers:go_default_library", "//go/lib/slayers/path:go_default_library", + "//go/lib/slayers/path/epic:go_default_library", "//go/lib/sock/reliable:go_default_library", "//go/lib/topology/underlay:go_default_library", "//go/lib/util:go_default_library", diff --git a/go/lib/snet/path.go b/go/lib/snet/path.go index ec2e490a4d..0c9809ee1e 100644 --- a/go/lib/snet/path.go +++ b/go/lib/snet/path.go @@ -79,6 +79,18 @@ func (iface PathInterface) String() string { return fmt.Sprintf("%s#%d", iface.IA, iface.ID) } +// EpicAuths is a container for the EPIC hop authenticators. +type EpicAuths struct { + // AuthPHVF is the authenticator for the penultimate hop. + AuthPHVF []byte + // AuthLHVF is the authenticator for the last hop + AuthLHVF []byte +} + +func (ea *EpicAuths) SupportsEpic() bool { + return (len(ea.AuthPHVF) == 16 && len(ea.AuthLHVF) == 16) +} + // PathMetadata contains supplementary information about a path. // // The information about MTU, Latency, Bandwidth etc. are based solely on data @@ -125,12 +137,16 @@ type PathMetadata struct { // Notes contains the notes added by ASes on the path, in the order of occurrence. // Entry i is the note of AS i on the path. Notes []string + + // EpicAuths contains the EPIC authenticators. + EpicAuths EpicAuths } func (pm *PathMetadata) Copy() *PathMetadata { if pm == nil { return nil } + return &PathMetadata{ Interfaces: append(pm.Interfaces[:0:0], pm.Interfaces...), MTU: pm.MTU, @@ -141,6 +157,10 @@ func (pm *PathMetadata) Copy() *PathMetadata { LinkType: append(pm.LinkType[:0:0], pm.LinkType...), InternalHops: append(pm.InternalHops[:0:0], pm.InternalHops...), Notes: append(pm.Notes[:0:0], pm.Notes...), + EpicAuths: EpicAuths{ + AuthPHVF: append([]byte(nil), pm.EpicAuths.AuthPHVF...), + AuthLHVF: append([]byte(nil), pm.EpicAuths.AuthLHVF...), + }, } } diff --git a/go/lib/snet/path/BUILD.bazel b/go/lib/snet/path/BUILD.bazel index cd5ddb6311..830f1d7ad6 100644 --- a/go/lib/snet/path/BUILD.bazel +++ b/go/lib/snet/path/BUILD.bazel @@ -4,6 +4,7 @@ go_library( name = "go_default_library", srcs = [ "empty.go", + "epic.go", "onehop.go", "path.go", "scion.go", @@ -12,10 +13,12 @@ go_library( visibility = ["//visibility:public"], deps = [ "//go/lib/addr:go_default_library", + "//go/lib/epic:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/slayers:go_default_library", "//go/lib/slayers/path:go_default_library", "//go/lib/slayers/path/empty:go_default_library", + "//go/lib/slayers/path/epic:go_default_library", "//go/lib/slayers/path/onehop:go_default_library", "//go/lib/slayers/path/scion:go_default_library", "//go/lib/snet:go_default_library", diff --git a/go/lib/snet/path/epic.go b/go/lib/snet/path/epic.go new file mode 100644 index 0000000000..517ac9d657 --- /dev/null +++ b/go/lib/snet/path/epic.go @@ -0,0 +1,96 @@ +// Copyright 2021 ETH Zurich +// +// 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 path + +import ( + "sync" + "time" + + libepic "github.com/scionproto/scion/go/lib/epic" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/slayers" + "github.com/scionproto/scion/go/lib/slayers/path/epic" + "github.com/scionproto/scion/go/lib/slayers/path/scion" + "github.com/scionproto/scion/go/lib/snet" +) + +type EPIC struct { + AuthPHVF []byte + AuthLHVF []byte + SCION []byte + + mu sync.Mutex + counter uint32 +} + +func NewEPICDataplanePath(p SCION, auths snet.EpicAuths) (*EPIC, error) { + if !auths.SupportsEpic() { + return &EPIC{}, serrors.New("EPIC not supported") + } + epicPath := &EPIC{ + AuthPHVF: append([]byte(nil), auths.AuthPHVF...), + AuthLHVF: append([]byte(nil), auths.AuthLHVF...), + SCION: append([]byte(nil), p.Raw...), + } + return epicPath, nil +} + +func (e *EPIC) SetPath(s *slayers.SCION) error { + e.mu.Lock() + defer e.mu.Unlock() + + // XXX(roosd): This is not optimal regarding allocations etc. But it should + // serve as an example. + var sp scion.Raw + if err := sp.DecodeFromBytes(e.SCION); err != nil { + return err + } + + info, err := sp.GetInfoField(0) + if err != nil { + return err + } + + // Calculate packet ID. + tsInfo := time.Unix(int64(info.Timestamp), 0) + timestamp, err := libepic.CreateTimestamp(tsInfo, time.Now()) + if err != nil { + return err + } + e.counter += 1 + pktID := epic.PktID{ + Timestamp: timestamp, + Counter: e.counter, + } + + // Calculate HVFs. + phvf, err := libepic.CalcMac(e.AuthPHVF, pktID, s, info.Timestamp, nil) + if err != nil { + return err + } + lhvf, err := libepic.CalcMac(e.AuthLHVF, pktID, s, info.Timestamp, nil) + if err != nil { + return err + } + + ep := &epic.Path{ + PktID: pktID, + PHVF: phvf[:epic.HVFLen], + LHVF: lhvf[:epic.HVFLen], + ScionPath: &sp, + } + s.Path, s.PathType = ep, ep.Type() + return nil +} diff --git a/go/lib/snet/reply_pather.go b/go/lib/snet/reply_pather.go index a7113f78d9..97015f2ab1 100644 --- a/go/lib/snet/reply_pather.go +++ b/go/lib/snet/reply_pather.go @@ -18,6 +18,7 @@ import ( "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/slayers" "github.com/scionproto/scion/go/lib/slayers/path" + "github.com/scionproto/scion/go/lib/slayers/path/epic" ) // DefaultReplyPather constructs dataplane reply paths. @@ -32,6 +33,12 @@ func (DefaultReplyPather) ReplyPath(rpath RawPath) (DataplanePath, error) { if err := p.DecodeFromBytes(rpath.Raw); err != nil { return nil, serrors.WrapStr("decoding path", err) } + + // By default, reversing an EPIC path means getting a reversed SCION path. + if epicPath, ok := p.(*epic.Path); ok { + p = epicPath.ScionPath + } + reversed, err := p.Reverse() if err != nil { return nil, serrors.WrapStr("reversing path", err) diff --git a/go/pkg/app/path/path.go b/go/pkg/app/path/path.go index ca972f18cd..63a95bfc5c 100644 --- a/go/pkg/app/path/path.go +++ b/go/pkg/app/path/path.go @@ -83,8 +83,26 @@ func Choose( if err != nil { return nil, serrors.WrapStr("fetching paths", err) } + if o.epic { + // Only use paths that support EPIC and intra-AS (empty) paths. + epicPaths := []snet.Path{} + for _, p := range paths { + if p.Metadata().EpicAuths.SupportsEpic() { + epicPaths = append(epicPaths, p) + } + + // Also include empty paths for AS internal communication. + if _, isEmpty := p.Dataplane().(snetpath.Empty); isEmpty { + epicPaths = append(epicPaths, p) + } + } + if len(epicPaths) == 0 { + return nil, serrors.New("no EPIC paths available") + } + paths = epicPaths + } if o.probeCfg != nil { - paths, err = filterUnhealthy(ctx, paths, remote, conn, o.probeCfg) + paths, err = filterUnhealthy(ctx, paths, remote, conn, o.probeCfg, o.epic) if err != nil { return nil, serrors.WrapStr("probing paths", err) } @@ -102,6 +120,7 @@ func filterUnhealthy( remote addr.IA, sd daemon.Connector, cfg *ProbeConfig, + epic bool, ) ([]snet.Path, error) { // Filter and save empty paths. They are considered healthy by definition, but must not be used @@ -124,7 +143,7 @@ func filterUnhealthy( ID: uint16(rand.Uint32()), SCIONPacketConnMetrics: cfg.SCIONPacketConnMetrics, Dispatcher: cfg.Dispatcher, - }.GetStatuses(subCtx, nonEmptyPaths) + }.GetStatuses(subCtx, nonEmptyPaths, pathprobe.WithEPIC(epic)) if err != nil { return nil, serrors.WrapStr("probing paths", err) } @@ -297,6 +316,7 @@ type options struct { seq string colorScheme ColorScheme probeCfg *ProbeConfig + epic bool } type Option func(o *options) @@ -338,3 +358,9 @@ func WithProbing(cfg *ProbeConfig) Option { o.probeCfg = cfg } } + +func WithEPIC(epic bool) Option { + return func(o *options) { + o.epic = epic + } +} diff --git a/go/pkg/cs/tasks.go b/go/pkg/cs/tasks.go index a41fa90132..1fd61466d1 100644 --- a/go/pkg/cs/tasks.go +++ b/go/pkg/cs/tasks.go @@ -71,6 +71,8 @@ type TasksConfig struct { HiddenPathRegistrationCfg *HiddenPathRegistrationCfg AllowIsdLoop bool + + EPIC bool } // Originator starts a periodic beacon origination task. For non-core ASes, no @@ -206,7 +208,7 @@ func (t *TasksConfig) extender(task string, ia addr.IA, mtu uint16, MaxExpTime: func() uint8 { return maxExp() }, StaticInfo: t.StaticInfo, Task: task, - EPIC: false, + EPIC: t.EPIC, } } diff --git a/go/pkg/daemon/internal/servers/grpc.go b/go/pkg/daemon/internal/servers/grpc.go index ff4ed5cc31..db7f166690 100644 --- a/go/pkg/daemon/internal/servers/grpc.go +++ b/go/pkg/daemon/internal/servers/grpc.go @@ -159,6 +159,12 @@ func pathToPB(path snet.Path) *sdpb.Path { if nextHop := path.UnderlayNextHop(); nextHop != nil { nextHopStr = nextHop.String() } + + epicAuths := &sdpb.EpicAuths{ + AuthPhvf: append([]byte(nil), meta.EpicAuths.AuthPHVF...), + AuthLhvf: append([]byte(nil), meta.EpicAuths.AuthLHVF...), + } + return &sdpb.Path{ Raw: raw, Interface: &sdpb.Interface{ @@ -173,6 +179,7 @@ func pathToPB(path snet.Path) *sdpb.Path { LinkType: linkType, InternalHops: meta.InternalHops, Notes: meta.Notes, + EpicAuths: epicAuths, } } diff --git a/go/pkg/pathprobe/paths.go b/go/pkg/pathprobe/paths.go index ab69e209fc..17f73c2d24 100644 --- a/go/pkg/pathprobe/paths.go +++ b/go/pkg/pathprobe/paths.go @@ -70,11 +70,13 @@ func (s Status) String() string { // GetStatuses. func PathKey(path snet.Path) string { dp := path.Dataplane() - scionPath, ok := dp.(snetpath.SCION) - if !ok { - return "" + switch p := dp.(type) { + case snetpath.SCION: + return string(p.Raw) + case *snetpath.EPIC: + return string(p.SCION) } - return string(scionPath.Raw) + return "" } // FilterEmptyPaths removes all empty paths from paths and returns a copy. @@ -110,10 +112,33 @@ type Prober struct { SCIONPacketConnMetrics snet.SCIONPacketConnMetrics } +type options struct { + epic bool +} + +type Option func(o *options) + +func applyOption(opts []Option) options { + var o options + for _, option := range opts { + option(&o) + } + return o +} + +func WithEPIC(epic bool) Option { + return func(o *options) { + o.epic = epic + } +} + // GetStatuses probes the paths and returns the statuses of the paths. The // returned map is keyed with path.Path.FwdPath. The input should only be // non-empty paths. -func (p Prober) GetStatuses(ctx context.Context, paths []snet.Path) (map[string]Status, error) { +func (p Prober) GetStatuses(ctx context.Context, paths []snet.Path, + opts ...Option) (map[string]Status, error) { + + o := applyOption(opts) deadline, ok := ctx.Deadline() if !ok { return nil, serrors.New("deadline required on ctx") @@ -121,7 +146,8 @@ func (p Prober) GetStatuses(ctx context.Context, paths []snet.Path) (map[string] for _, path := range paths { if _, ok := path.Dataplane().(snetpath.SCION); !ok { - return nil, serrors.New("paths must be of type SCION") + return nil, serrors.New("paths must be of type SCION", + "path", common.TypeOf(path.Dataplane())) } } @@ -185,10 +211,25 @@ func (p Prober) GetStatuses(ctx context.Context, paths []snet.Path) (map[string] if !ok { return serrors.New("not a scion path") } - alertPath, err := setAlertFlag(originalPath) + + scionAlertPath, err := setAlertFlag(originalPath) if err != nil { return serrors.WrapStr("setting alert flag", err) } + var alertPath snet.DataplanePath + if o.epic { + epicAlertPath, err := snetpath.NewEPICDataplanePath( + scionAlertPath, + path.Metadata().EpicAuths, + ) + if err != nil { + return err + } + alertPath = epicAlertPath + } else { + alertPath = scionAlertPath + } + pkt := &snet.Packet{ PacketInfo: snet.PacketInfo{ Destination: snet.SCIONAddress{ diff --git a/go/pkg/proto/daemon/daemon.pb.go b/go/pkg/proto/daemon/daemon.pb.go index 73e91f6476..c79eccc0b2 100644 --- a/go/pkg/proto/daemon/daemon.pb.go +++ b/go/pkg/proto/daemon/daemon.pb.go @@ -212,6 +212,7 @@ type Path struct { LinkType []LinkType `protobuf:"varint,9,rep,packed,name=link_type,json=linkType,proto3,enum=proto.daemon.v1.LinkType" json:"link_type,omitempty"` InternalHops []uint32 `protobuf:"varint,10,rep,packed,name=internal_hops,json=internalHops,proto3" json:"internal_hops,omitempty"` Notes []string `protobuf:"bytes,11,rep,name=notes,proto3" json:"notes,omitempty"` + EpicAuths *EpicAuths `protobuf:"bytes,12,opt,name=epic_auths,json=epicAuths,proto3" json:"epic_auths,omitempty"` } func (x *Path) Reset() { @@ -323,6 +324,68 @@ func (x *Path) GetNotes() []string { return nil } +func (x *Path) GetEpicAuths() *EpicAuths { + if x != nil { + return x.EpicAuths + } + return nil +} + +type EpicAuths struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuthPhvf []byte `protobuf:"bytes,1,opt,name=auth_phvf,json=authPhvf,proto3" json:"auth_phvf,omitempty"` + AuthLhvf []byte `protobuf:"bytes,2,opt,name=auth_lhvf,json=authLhvf,proto3" json:"auth_lhvf,omitempty"` +} + +func (x *EpicAuths) Reset() { + *x = EpicAuths{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EpicAuths) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EpicAuths) ProtoMessage() {} + +func (x *EpicAuths) ProtoReflect() protoreflect.Message { + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EpicAuths.ProtoReflect.Descriptor instead. +func (*EpicAuths) Descriptor() ([]byte, []int) { + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{3} +} + +func (x *EpicAuths) GetAuthPhvf() []byte { + if x != nil { + return x.AuthPhvf + } + return nil +} + +func (x *EpicAuths) GetAuthLhvf() []byte { + if x != nil { + return x.AuthLhvf + } + return nil +} + type PathInterface struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -335,7 +398,7 @@ type PathInterface struct { func (x *PathInterface) Reset() { *x = PathInterface{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[3] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -348,7 +411,7 @@ func (x *PathInterface) String() string { func (*PathInterface) ProtoMessage() {} func (x *PathInterface) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[3] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -361,7 +424,7 @@ func (x *PathInterface) ProtoReflect() protoreflect.Message { // Deprecated: Use PathInterface.ProtoReflect.Descriptor instead. func (*PathInterface) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{3} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{4} } func (x *PathInterface) GetIsdAs() uint64 { @@ -391,7 +454,7 @@ type GeoCoordinates struct { func (x *GeoCoordinates) Reset() { *x = GeoCoordinates{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[4] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -404,7 +467,7 @@ func (x *GeoCoordinates) String() string { func (*GeoCoordinates) ProtoMessage() {} func (x *GeoCoordinates) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[4] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -417,7 +480,7 @@ func (x *GeoCoordinates) ProtoReflect() protoreflect.Message { // Deprecated: Use GeoCoordinates.ProtoReflect.Descriptor instead. func (*GeoCoordinates) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{4} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{5} } func (x *GeoCoordinates) GetLatitude() float32 { @@ -452,7 +515,7 @@ type ASRequest struct { func (x *ASRequest) Reset() { *x = ASRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[5] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -465,7 +528,7 @@ func (x *ASRequest) String() string { func (*ASRequest) ProtoMessage() {} func (x *ASRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[5] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -478,7 +541,7 @@ func (x *ASRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ASRequest.ProtoReflect.Descriptor instead. func (*ASRequest) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{5} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{6} } func (x *ASRequest) GetIsdAs() uint64 { @@ -501,7 +564,7 @@ type ASResponse struct { func (x *ASResponse) Reset() { *x = ASResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[6] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -514,7 +577,7 @@ func (x *ASResponse) String() string { func (*ASResponse) ProtoMessage() {} func (x *ASResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[6] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -527,7 +590,7 @@ func (x *ASResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ASResponse.ProtoReflect.Descriptor instead. func (*ASResponse) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{6} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{7} } func (x *ASResponse) GetIsdAs() uint64 { @@ -560,7 +623,7 @@ type InterfacesRequest struct { func (x *InterfacesRequest) Reset() { *x = InterfacesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[7] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -573,7 +636,7 @@ func (x *InterfacesRequest) String() string { func (*InterfacesRequest) ProtoMessage() {} func (x *InterfacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[7] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -586,7 +649,7 @@ func (x *InterfacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use InterfacesRequest.ProtoReflect.Descriptor instead. func (*InterfacesRequest) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{7} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{8} } type InterfacesResponse struct { @@ -600,7 +663,7 @@ type InterfacesResponse struct { func (x *InterfacesResponse) Reset() { *x = InterfacesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[8] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -613,7 +676,7 @@ func (x *InterfacesResponse) String() string { func (*InterfacesResponse) ProtoMessage() {} func (x *InterfacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[8] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -626,7 +689,7 @@ func (x *InterfacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use InterfacesResponse.ProtoReflect.Descriptor instead. func (*InterfacesResponse) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{8} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{9} } func (x *InterfacesResponse) GetInterfaces() map[uint64]*Interface { @@ -647,7 +710,7 @@ type Interface struct { func (x *Interface) Reset() { *x = Interface{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[9] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -660,7 +723,7 @@ func (x *Interface) String() string { func (*Interface) ProtoMessage() {} func (x *Interface) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[9] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -673,7 +736,7 @@ func (x *Interface) ProtoReflect() protoreflect.Message { // Deprecated: Use Interface.ProtoReflect.Descriptor instead. func (*Interface) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{9} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{10} } func (x *Interface) GetAddress() *Underlay { @@ -692,7 +755,7 @@ type ServicesRequest struct { func (x *ServicesRequest) Reset() { *x = ServicesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[10] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -705,7 +768,7 @@ func (x *ServicesRequest) String() string { func (*ServicesRequest) ProtoMessage() {} func (x *ServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[10] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -718,7 +781,7 @@ func (x *ServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ServicesRequest.ProtoReflect.Descriptor instead. func (*ServicesRequest) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{10} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{11} } type ServicesResponse struct { @@ -732,7 +795,7 @@ type ServicesResponse struct { func (x *ServicesResponse) Reset() { *x = ServicesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[11] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -745,7 +808,7 @@ func (x *ServicesResponse) String() string { func (*ServicesResponse) ProtoMessage() {} func (x *ServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[11] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -758,7 +821,7 @@ func (x *ServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServicesResponse.ProtoReflect.Descriptor instead. func (*ServicesResponse) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{11} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{12} } func (x *ServicesResponse) GetServices() map[string]*ListService { @@ -779,7 +842,7 @@ type ListService struct { func (x *ListService) Reset() { *x = ListService{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[12] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -792,7 +855,7 @@ func (x *ListService) String() string { func (*ListService) ProtoMessage() {} func (x *ListService) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[12] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -805,7 +868,7 @@ func (x *ListService) ProtoReflect() protoreflect.Message { // Deprecated: Use ListService.ProtoReflect.Descriptor instead. func (*ListService) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{12} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{13} } func (x *ListService) GetServices() []*Service { @@ -826,7 +889,7 @@ type Service struct { func (x *Service) Reset() { *x = Service{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[13] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -839,7 +902,7 @@ func (x *Service) String() string { func (*Service) ProtoMessage() {} func (x *Service) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[13] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -852,7 +915,7 @@ func (x *Service) ProtoReflect() protoreflect.Message { // Deprecated: Use Service.ProtoReflect.Descriptor instead. func (*Service) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{13} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{14} } func (x *Service) GetUri() string { @@ -873,7 +936,7 @@ type Underlay struct { func (x *Underlay) Reset() { *x = Underlay{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[14] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -886,7 +949,7 @@ func (x *Underlay) String() string { func (*Underlay) ProtoMessage() {} func (x *Underlay) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[14] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -899,7 +962,7 @@ func (x *Underlay) ProtoReflect() protoreflect.Message { // Deprecated: Use Underlay.ProtoReflect.Descriptor instead. func (*Underlay) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{14} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{15} } func (x *Underlay) GetAddress() string { @@ -921,7 +984,7 @@ type NotifyInterfaceDownRequest struct { func (x *NotifyInterfaceDownRequest) Reset() { *x = NotifyInterfaceDownRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[15] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -934,7 +997,7 @@ func (x *NotifyInterfaceDownRequest) String() string { func (*NotifyInterfaceDownRequest) ProtoMessage() {} func (x *NotifyInterfaceDownRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[15] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -947,7 +1010,7 @@ func (x *NotifyInterfaceDownRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyInterfaceDownRequest.ProtoReflect.Descriptor instead. func (*NotifyInterfaceDownRequest) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{15} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{16} } func (x *NotifyInterfaceDownRequest) GetIsdAs() uint64 { @@ -973,7 +1036,7 @@ type NotifyInterfaceDownResponse struct { func (x *NotifyInterfaceDownResponse) Reset() { *x = NotifyInterfaceDownResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[16] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -986,7 +1049,7 @@ func (x *NotifyInterfaceDownResponse) String() string { func (*NotifyInterfaceDownResponse) ProtoMessage() {} func (x *NotifyInterfaceDownResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_daemon_v1_daemon_proto_msgTypes[16] + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -999,7 +1062,7 @@ func (x *NotifyInterfaceDownResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyInterfaceDownResponse.ProtoReflect.Descriptor instead. func (*NotifyInterfaceDownResponse) Descriptor() ([]byte, []int) { - return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{16} + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{17} } var File_proto_daemon_v1_daemon_proto protoreflect.FileDescriptor @@ -1025,7 +1088,7 @@ var file_proto_daemon_v1_daemon_proto_rawDesc = []byte{ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x05, 0x70, 0x61, - 0x74, 0x68, 0x73, 0x22, 0xd9, 0x03, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, + 0x74, 0x68, 0x73, 0x22, 0x94, 0x04, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x61, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, 0x38, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, @@ -1054,108 +1117,116 @@ var file_proto_daemon_v1_daemon_proto_rawDesc = []byte{ 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x48, 0x6f, 0x70, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, - 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x22, - 0x36, 0x0a, 0x0d, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x64, 0x0a, 0x0e, 0x47, 0x65, 0x6f, 0x43, 0x6f, - 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, - 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x6c, 0x61, 0x74, - 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, - 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, - 0x75, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x22, 0x0a, - 0x09, 0x41, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, - 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, - 0x73, 0x22, 0x49, 0x0a, 0x0a, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, - 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x22, 0x13, 0x0a, 0x11, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0xc4, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x1a, 0x59, 0x0a, - 0x0f, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, - 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x61, - 0x79, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xba, 0x01, - 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, - 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, - 0x59, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x43, 0x0a, 0x0b, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, - 0x1b, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, - 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x22, 0x24, 0x0a, 0x08, - 0x55, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x22, 0x43, 0x0a, 0x1a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x6c, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x6b, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, - 0x10, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, - 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x48, 0x4f, 0x50, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, - 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x4e, - 0x45, 0x54, 0x10, 0x03, 0x32, 0xba, 0x03, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, - 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x12, + 0x39, 0x0a, 0x0a, 0x65, 0x70, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x73, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x70, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x52, + 0x09, 0x65, 0x70, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x22, 0x45, 0x0a, 0x09, 0x45, 0x70, + 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, + 0x70, 0x68, 0x76, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, + 0x50, 0x68, 0x76, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6c, 0x68, 0x76, + 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x4c, 0x68, 0x76, + 0x66, 0x22, 0x36, 0x0a, 0x0d, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x64, 0x0a, 0x0e, 0x47, 0x65, 0x6f, + 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, + 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x6c, + 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, + 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, + 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x22, 0x0a, 0x09, 0x41, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, + 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x73, + 0x64, 0x41, 0x73, 0x22, 0x49, 0x0a, 0x0a, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x6d, 0x74, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x22, 0x13, + 0x0a, 0x11, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0xc4, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0a, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x3f, 0x0a, 0x02, 0x41, 0x53, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, - 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x57, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, - 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, + 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x1a, + 0x59, 0x0a, 0x0f, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x09, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x72, + 0x6c, 0x61, 0x79, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x11, 0x0a, 0x0f, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0xba, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x1a, 0x59, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x43, 0x0a, 0x0b, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x22, 0x1b, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x22, 0x24, + 0x0a, 0x08, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x22, 0x43, 0x0a, 0x1a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x6c, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x6b, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x14, 0x0a, 0x10, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x52, + 0x45, 0x43, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x48, 0x4f, 0x50, 0x10, 0x02, 0x12, 0x16, + 0x0a, 0x12, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, + 0x5f, 0x4e, 0x45, 0x54, 0x10, 0x03, 0x32, 0xba, 0x03, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x68, + 0x73, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x02, 0x41, 0x53, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, + 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x73, 0x12, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, + 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x72, 0x0a, - 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, - 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, - 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x61, - 0x65, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x72, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, + 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, 0x69, + 0x6f, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1171,60 +1242,62 @@ func file_proto_daemon_v1_daemon_proto_rawDescGZIP() []byte { } var file_proto_daemon_v1_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_daemon_v1_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_proto_daemon_v1_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 20) var file_proto_daemon_v1_daemon_proto_goTypes = []interface{}{ (LinkType)(0), // 0: proto.daemon.v1.LinkType (*PathsRequest)(nil), // 1: proto.daemon.v1.PathsRequest (*PathsResponse)(nil), // 2: proto.daemon.v1.PathsResponse (*Path)(nil), // 3: proto.daemon.v1.Path - (*PathInterface)(nil), // 4: proto.daemon.v1.PathInterface - (*GeoCoordinates)(nil), // 5: proto.daemon.v1.GeoCoordinates - (*ASRequest)(nil), // 6: proto.daemon.v1.ASRequest - (*ASResponse)(nil), // 7: proto.daemon.v1.ASResponse - (*InterfacesRequest)(nil), // 8: proto.daemon.v1.InterfacesRequest - (*InterfacesResponse)(nil), // 9: proto.daemon.v1.InterfacesResponse - (*Interface)(nil), // 10: proto.daemon.v1.Interface - (*ServicesRequest)(nil), // 11: proto.daemon.v1.ServicesRequest - (*ServicesResponse)(nil), // 12: proto.daemon.v1.ServicesResponse - (*ListService)(nil), // 13: proto.daemon.v1.ListService - (*Service)(nil), // 14: proto.daemon.v1.Service - (*Underlay)(nil), // 15: proto.daemon.v1.Underlay - (*NotifyInterfaceDownRequest)(nil), // 16: proto.daemon.v1.NotifyInterfaceDownRequest - (*NotifyInterfaceDownResponse)(nil), // 17: proto.daemon.v1.NotifyInterfaceDownResponse - nil, // 18: proto.daemon.v1.InterfacesResponse.InterfacesEntry - nil, // 19: proto.daemon.v1.ServicesResponse.ServicesEntry - (*timestamppb.Timestamp)(nil), // 20: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 21: google.protobuf.Duration + (*EpicAuths)(nil), // 4: proto.daemon.v1.EpicAuths + (*PathInterface)(nil), // 5: proto.daemon.v1.PathInterface + (*GeoCoordinates)(nil), // 6: proto.daemon.v1.GeoCoordinates + (*ASRequest)(nil), // 7: proto.daemon.v1.ASRequest + (*ASResponse)(nil), // 8: proto.daemon.v1.ASResponse + (*InterfacesRequest)(nil), // 9: proto.daemon.v1.InterfacesRequest + (*InterfacesResponse)(nil), // 10: proto.daemon.v1.InterfacesResponse + (*Interface)(nil), // 11: proto.daemon.v1.Interface + (*ServicesRequest)(nil), // 12: proto.daemon.v1.ServicesRequest + (*ServicesResponse)(nil), // 13: proto.daemon.v1.ServicesResponse + (*ListService)(nil), // 14: proto.daemon.v1.ListService + (*Service)(nil), // 15: proto.daemon.v1.Service + (*Underlay)(nil), // 16: proto.daemon.v1.Underlay + (*NotifyInterfaceDownRequest)(nil), // 17: proto.daemon.v1.NotifyInterfaceDownRequest + (*NotifyInterfaceDownResponse)(nil), // 18: proto.daemon.v1.NotifyInterfaceDownResponse + nil, // 19: proto.daemon.v1.InterfacesResponse.InterfacesEntry + nil, // 20: proto.daemon.v1.ServicesResponse.ServicesEntry + (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 22: google.protobuf.Duration } var file_proto_daemon_v1_daemon_proto_depIdxs = []int32{ 3, // 0: proto.daemon.v1.PathsResponse.paths:type_name -> proto.daemon.v1.Path - 10, // 1: proto.daemon.v1.Path.interface:type_name -> proto.daemon.v1.Interface - 4, // 2: proto.daemon.v1.Path.interfaces:type_name -> proto.daemon.v1.PathInterface - 20, // 3: proto.daemon.v1.Path.expiration:type_name -> google.protobuf.Timestamp - 21, // 4: proto.daemon.v1.Path.latency:type_name -> google.protobuf.Duration - 5, // 5: proto.daemon.v1.Path.geo:type_name -> proto.daemon.v1.GeoCoordinates + 11, // 1: proto.daemon.v1.Path.interface:type_name -> proto.daemon.v1.Interface + 5, // 2: proto.daemon.v1.Path.interfaces:type_name -> proto.daemon.v1.PathInterface + 21, // 3: proto.daemon.v1.Path.expiration:type_name -> google.protobuf.Timestamp + 22, // 4: proto.daemon.v1.Path.latency:type_name -> google.protobuf.Duration + 6, // 5: proto.daemon.v1.Path.geo:type_name -> proto.daemon.v1.GeoCoordinates 0, // 6: proto.daemon.v1.Path.link_type:type_name -> proto.daemon.v1.LinkType - 18, // 7: proto.daemon.v1.InterfacesResponse.interfaces:type_name -> proto.daemon.v1.InterfacesResponse.InterfacesEntry - 15, // 8: proto.daemon.v1.Interface.address:type_name -> proto.daemon.v1.Underlay - 19, // 9: proto.daemon.v1.ServicesResponse.services:type_name -> proto.daemon.v1.ServicesResponse.ServicesEntry - 14, // 10: proto.daemon.v1.ListService.services:type_name -> proto.daemon.v1.Service - 10, // 11: proto.daemon.v1.InterfacesResponse.InterfacesEntry.value:type_name -> proto.daemon.v1.Interface - 13, // 12: proto.daemon.v1.ServicesResponse.ServicesEntry.value:type_name -> proto.daemon.v1.ListService - 1, // 13: proto.daemon.v1.DaemonService.Paths:input_type -> proto.daemon.v1.PathsRequest - 6, // 14: proto.daemon.v1.DaemonService.AS:input_type -> proto.daemon.v1.ASRequest - 8, // 15: proto.daemon.v1.DaemonService.Interfaces:input_type -> proto.daemon.v1.InterfacesRequest - 11, // 16: proto.daemon.v1.DaemonService.Services:input_type -> proto.daemon.v1.ServicesRequest - 16, // 17: proto.daemon.v1.DaemonService.NotifyInterfaceDown:input_type -> proto.daemon.v1.NotifyInterfaceDownRequest - 2, // 18: proto.daemon.v1.DaemonService.Paths:output_type -> proto.daemon.v1.PathsResponse - 7, // 19: proto.daemon.v1.DaemonService.AS:output_type -> proto.daemon.v1.ASResponse - 9, // 20: proto.daemon.v1.DaemonService.Interfaces:output_type -> proto.daemon.v1.InterfacesResponse - 12, // 21: proto.daemon.v1.DaemonService.Services:output_type -> proto.daemon.v1.ServicesResponse - 17, // 22: proto.daemon.v1.DaemonService.NotifyInterfaceDown:output_type -> proto.daemon.v1.NotifyInterfaceDownResponse - 18, // [18:23] is the sub-list for method output_type - 13, // [13:18] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 4, // 7: proto.daemon.v1.Path.epic_auths:type_name -> proto.daemon.v1.EpicAuths + 19, // 8: proto.daemon.v1.InterfacesResponse.interfaces:type_name -> proto.daemon.v1.InterfacesResponse.InterfacesEntry + 16, // 9: proto.daemon.v1.Interface.address:type_name -> proto.daemon.v1.Underlay + 20, // 10: proto.daemon.v1.ServicesResponse.services:type_name -> proto.daemon.v1.ServicesResponse.ServicesEntry + 15, // 11: proto.daemon.v1.ListService.services:type_name -> proto.daemon.v1.Service + 11, // 12: proto.daemon.v1.InterfacesResponse.InterfacesEntry.value:type_name -> proto.daemon.v1.Interface + 14, // 13: proto.daemon.v1.ServicesResponse.ServicesEntry.value:type_name -> proto.daemon.v1.ListService + 1, // 14: proto.daemon.v1.DaemonService.Paths:input_type -> proto.daemon.v1.PathsRequest + 7, // 15: proto.daemon.v1.DaemonService.AS:input_type -> proto.daemon.v1.ASRequest + 9, // 16: proto.daemon.v1.DaemonService.Interfaces:input_type -> proto.daemon.v1.InterfacesRequest + 12, // 17: proto.daemon.v1.DaemonService.Services:input_type -> proto.daemon.v1.ServicesRequest + 17, // 18: proto.daemon.v1.DaemonService.NotifyInterfaceDown:input_type -> proto.daemon.v1.NotifyInterfaceDownRequest + 2, // 19: proto.daemon.v1.DaemonService.Paths:output_type -> proto.daemon.v1.PathsResponse + 8, // 20: proto.daemon.v1.DaemonService.AS:output_type -> proto.daemon.v1.ASResponse + 10, // 21: proto.daemon.v1.DaemonService.Interfaces:output_type -> proto.daemon.v1.InterfacesResponse + 13, // 22: proto.daemon.v1.DaemonService.Services:output_type -> proto.daemon.v1.ServicesResponse + 18, // 23: proto.daemon.v1.DaemonService.NotifyInterfaceDown:output_type -> proto.daemon.v1.NotifyInterfaceDownResponse + 19, // [19:24] is the sub-list for method output_type + 14, // [14:19] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_proto_daemon_v1_daemon_proto_init() } @@ -1270,7 +1343,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PathInterface); i { + switch v := v.(*EpicAuths); i { case 0: return &v.state case 1: @@ -1282,7 +1355,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GeoCoordinates); i { + switch v := v.(*PathInterface); i { case 0: return &v.state case 1: @@ -1294,7 +1367,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ASRequest); i { + switch v := v.(*GeoCoordinates); i { case 0: return &v.state case 1: @@ -1306,7 +1379,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ASResponse); i { + switch v := v.(*ASRequest); i { case 0: return &v.state case 1: @@ -1318,7 +1391,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InterfacesRequest); i { + switch v := v.(*ASResponse); i { case 0: return &v.state case 1: @@ -1330,7 +1403,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InterfacesResponse); i { + switch v := v.(*InterfacesRequest); i { case 0: return &v.state case 1: @@ -1342,7 +1415,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Interface); i { + switch v := v.(*InterfacesResponse); i { case 0: return &v.state case 1: @@ -1354,7 +1427,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServicesRequest); i { + switch v := v.(*Interface); i { case 0: return &v.state case 1: @@ -1366,7 +1439,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServicesResponse); i { + switch v := v.(*ServicesRequest); i { case 0: return &v.state case 1: @@ -1378,7 +1451,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListService); i { + switch v := v.(*ServicesResponse); i { case 0: return &v.state case 1: @@ -1390,7 +1463,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Service); i { + switch v := v.(*ListService); i { case 0: return &v.state case 1: @@ -1402,7 +1475,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Underlay); i { + switch v := v.(*Service); i { case 0: return &v.state case 1: @@ -1414,7 +1487,7 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyInterfaceDownRequest); i { + switch v := v.(*Underlay); i { case 0: return &v.state case 1: @@ -1426,6 +1499,18 @@ func file_proto_daemon_v1_daemon_proto_init() { } } file_proto_daemon_v1_daemon_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyInterfaceDownRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_daemon_v1_daemon_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyInterfaceDownResponse); i { case 0: return &v.state @@ -1444,7 +1529,7 @@ func file_proto_daemon_v1_daemon_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_daemon_v1_daemon_proto_rawDesc, NumEnums: 1, - NumMessages: 19, + NumMessages: 20, NumExtensions: 0, NumServices: 1, }, diff --git a/go/pkg/router/dataplane.go b/go/pkg/router/dataplane.go index 787f925c81..9ca2c6252d 100644 --- a/go/pkg/router/dataplane.go +++ b/go/pkg/router/dataplane.go @@ -689,22 +689,21 @@ func (p *scionPacketProcessor) processEPIC() (processResult, error) { return processResult{}, malformedPath } - info, err := p.path.GetCurrentInfoField() - if err != nil { - return processResult{}, err - } + isPenultimate := p.path.IsPenultimateHop() + isLast := p.path.IsLastHop() result, err := p.process() if err != nil { - // TODO(mawyss): Send back SCMP packet - return processResult{}, err + return result, err } - isPenultimate := p.path.IsPenultimateHop() - isLast := p.path.IsLastHop() - if isPenultimate || isLast { - timestamp := time.Unix(int64(info.Timestamp), 0) + firstInfo, err := p.path.GetInfoField(0) + if err != nil { + return processResult{}, err + } + + timestamp := time.Unix(int64(firstInfo.Timestamp), 0) err = libepic.VerifyTimestamp(timestamp, epicPath.PktID.Timestamp, time.Now()) if err != nil { // TODO(mawyss): Send back SCMP packet @@ -715,8 +714,8 @@ func (p *scionPacketProcessor) processEPIC() (processResult, error) { if isLast { HVF = epicPath.LHVF } - err = libepic.VerifyHVF(p.cachedMac, epicPath.PktID, &p.scionLayer, info.Timestamp, HVF, - p.macBuffers.epicInput) + err = libepic.VerifyHVF(p.cachedMac, epicPath.PktID, + &p.scionLayer, firstInfo.Timestamp, HVF, p.macBuffers.epicInput) if err != nil { // TODO(mawyss): Send back SCMP packet return processResult{}, err @@ -1427,10 +1426,26 @@ func (p *scionPacketProcessor) prepareSCMP(scmpH *slayers.SCMP, scmpP gopacket.S // *copy* and reverse path -- the original path should not be modified as this writes directly // back to rawPkt (quote). - path, ok := p.scionLayer.Path.(*scion.Raw) - if !ok { + var path *scion.Raw + pathType := p.scionLayer.Path.Type() + switch pathType { + case scion.PathType: + var ok bool + path, ok = p.scionLayer.Path.(*scion.Raw) + if !ok { + return nil, serrors.WithCtx(cannotRoute, "details", "unsupported path type", + "path type", pathType) + } + case epic.PathType: + epicPath, ok := p.scionLayer.Path.(*epic.Path) + if !ok { + return nil, serrors.WithCtx(cannotRoute, "details", "unsupported path type", + "path type", pathType) + } + path = epicPath.ScionPath + default: return nil, serrors.WithCtx(cannotRoute, "details", "unsupported path type", - "path type", p.scionLayer.Path.Type()) + "path type", pathType) } decPath, err := path.ToDecoded() if err != nil { diff --git a/go/pkg/showpaths/config.go b/go/pkg/showpaths/config.go index fdeade6f50..c6419d4689 100644 --- a/go/pkg/showpaths/config.go +++ b/go/pkg/showpaths/config.go @@ -41,4 +41,7 @@ type Config struct { // Dispatcher is the path to the dispatcher socket. Leaving this empty uses // the default dispatcher socket value. Dispatcher string + // Epic filters paths for which EPIC is not available, and when probing, the + // EPIC path type header is used. + Epic bool } diff --git a/go/pkg/showpaths/showpaths.go b/go/pkg/showpaths/showpaths.go index 394bbf3d96..7945b52df0 100644 --- a/go/pkg/showpaths/showpaths.go +++ b/go/pkg/showpaths/showpaths.go @@ -22,6 +22,7 @@ import ( "math" "math/rand" "net" + "strconv" "strings" "time" @@ -106,6 +107,7 @@ func (r Result) Human(w io.Writer, showExtendedMetadata, colored bool) { "LinkType", humanLinkType(meta), "InternalHops", humanInternalHops(meta), "Notes", humanNotes(meta), + "SupportsEPIC", strconv.FormatBool(meta.EpicAuths.SupportsEpic()), )...) } if path.Status != "" { @@ -341,6 +343,18 @@ func Run(ctx context.Context, dst addr.IA, cfg Config) (*Result, error) { paths = paths[:cfg.MaxPaths] } + // If the epic flag is set, filter all paths that do not have + // the necessary epic authenticators. + if cfg.Epic { + epicPaths := []snet.Path{} + for _, p := range paths { + if p.Metadata().EpicAuths.SupportsEpic() { + epicPaths = append(epicPaths, p) + } + } + paths = epicPaths + } + var statuses map[string]pathprobe.Status if !cfg.NoProbe { p := pathprobe.FilterEmptyPaths(paths) @@ -350,7 +364,7 @@ func Run(ctx context.Context, dst addr.IA, cfg Config) (*Result, error) { LocalIP: cfg.Local, ID: uint16(rand.Uint32()), Dispatcher: cfg.Dispatcher, - }.GetStatuses(ctx, p) + }.GetStatuses(ctx, p, pathprobe.WithEPIC(cfg.Epic)) if err != nil { return nil, serrors.WrapStr("getting statuses", err) } diff --git a/go/pkg/traceroute/traceroute.go b/go/pkg/traceroute/traceroute.go index eba2fb50ed..ddd001d8fb 100644 --- a/go/pkg/traceroute/traceroute.go +++ b/go/pkg/traceroute/traceroute.go @@ -63,6 +63,7 @@ type Config struct { PayloadSize uint Remote *snet.UDPAddr Timeout time.Duration + EPIC bool // ProbesPerHop indicates how many probes should be done per hop. ProbesPerHop int @@ -86,6 +87,7 @@ type tracerouter struct { replies <-chan reply path snet.Path + epic bool id uint16 index int @@ -120,6 +122,7 @@ func Run(ctx context.Context, cfg Config) (Stats, error) { updateHandler: cfg.UpdateHandler, id: uint16(id), path: cfg.PathEntry, + epic: cfg.EPIC, } return t.Traceroute(ctx) } @@ -196,11 +199,25 @@ func (t *tracerouter) probeHop(ctx context.Context, hfIdx uint8, egress bool) (U hf.IngressRouterAlert = true } - alert, err := snetpath.NewSCIONFromDecoded(decoded) + scionAlertPath, err := snetpath.NewSCIONFromDecoded(decoded) if err != nil { return Update{}, serrors.WrapStr("setting alert flag", err) } + var alertPath snet.DataplanePath + if t.epic { + epicAlertPath, err := snetpath.NewEPICDataplanePath( + scionAlertPath, + t.path.Metadata().EpicAuths, + ) + if err != nil { + return Update{}, err + } + alertPath = epicAlertPath + } else { + alertPath = scionAlertPath + } + u := Update{ Index: t.index, RTTs: make([]time.Duration, 0, t.probesPerHop), @@ -216,7 +233,7 @@ func (t *tracerouter) probeHop(ctx context.Context, hfIdx uint8, egress bool) (U IA: t.local.IA, Host: addr.HostFromIP(t.local.Host.IP), }, - Path: alert, + Path: alertPath, Payload: snet.SCMPTracerouteRequest{Identifier: t.id}, }, } diff --git a/go/scion/BUILD.bazel b/go/scion/BUILD.bazel index cf821043c8..ff317b4cc7 100644 --- a/go/scion/BUILD.bazel +++ b/go/scion/BUILD.bazel @@ -21,6 +21,7 @@ go_library( "//go/lib/serrors:go_default_library", "//go/lib/snet:go_default_library", "//go/lib/snet/addrutil:go_default_library", + "//go/lib/snet/path:go_default_library", "//go/lib/sock/reliable:go_default_library", "//go/lib/topology:go_default_library", "//go/lib/tracing:go_default_library", diff --git a/go/scion/ping.go b/go/scion/ping.go index e0d42ff636..54e3a3d0a0 100644 --- a/go/scion/ping.go +++ b/go/scion/ping.go @@ -30,6 +30,7 @@ import ( "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/snet" "github.com/scionproto/scion/go/lib/snet/addrutil" + snetpath "github.com/scionproto/scion/go/lib/snet/path" "github.com/scionproto/scion/go/lib/sock/reliable" "github.com/scionproto/scion/go/lib/tracing" "github.com/scionproto/scion/go/pkg/app" @@ -54,6 +55,7 @@ func newPing(pather CommandPather) *cobra.Command { size uint timeout time.Duration tracer string + epic bool } var cmd = &cobra.Command{ @@ -125,6 +127,7 @@ On other errors, ping will exit with code 2. path.WithRefresh(flags.refresh), path.WithSequence(flags.sequence), path.WithColorScheme(path.DefaultColorScheme(flags.noColor)), + path.WithEPIC(flags.epic), } if flags.healthyOnly { opts = append(opts, path.WithProbing(&path.ProbeConfig{ @@ -137,7 +140,24 @@ On other errors, ping will exit with code 2. if err != nil { return err } - remote.Path = path.Dataplane() + + // If the EPIC flag is set, use the EPIC-HP path type + if flags.epic { + switch s := path.Dataplane().(type) { + case snetpath.SCION: + epicPath, err := snetpath.NewEPICDataplanePath(s, path.Metadata().EpicAuths) + if err != nil { + return err + } + remote.Path = epicPath + case snetpath.Empty: + remote.Path = s + default: + return serrors.New("unsupported path type") + } + } else { + remote.Path = path.Dataplane() + } remote.NextHop = path.UnderlayNextHop() // Resolve local IP based on underlay next hop @@ -235,6 +255,7 @@ SCMP echo header and payload are equal to the MTU of the path. This flag overrid 'payload_size' flag.`) cmd.Flags().StringVar(&flags.logLevel, "log.level", "", app.LogLevelUsage) cmd.Flags().StringVar(&flags.tracer, "tracing.agent", "", "Tracing agent address") + cmd.Flags().BoolVar(&flags.epic, "epic", false, "Enable EPIC for path probing.") return cmd } diff --git a/go/scion/showpaths.go b/go/scion/showpaths.go index 908573b24e..d5fa72e7f3 100644 --- a/go/scion/showpaths.go +++ b/go/scion/showpaths.go @@ -142,5 +142,6 @@ On other errors, showpaths will exit with code 2. cmd.Flags().BoolVar(&flags.noColor, "no-color", false, "disable colored output") cmd.Flags().StringVar(&flags.logLevel, "log.level", "", app.LogLevelUsage) cmd.Flags().StringVar(&flags.tracer, "tracing.agent", "", "Tracing agent address") + cmd.Flags().BoolVar(&flags.cfg.Epic, "epic", false, "Enable EPIC.") return cmd } diff --git a/go/scion/traceroute.go b/go/scion/traceroute.go index 5515fd6008..2d1eeba231 100644 --- a/go/scion/traceroute.go +++ b/go/scion/traceroute.go @@ -50,6 +50,7 @@ func newTraceroute(pather CommandPather) *cobra.Command { sequence string timeout time.Duration tracer string + epic bool } var cmd = &cobra.Command{ @@ -114,11 +115,11 @@ On other errors, traceroute will exit with code 2. path.WithRefresh(flags.refresh), path.WithSequence(flags.sequence), path.WithColorScheme(path.DefaultColorScheme(flags.noColor)), + path.WithEPIC(flags.epic), ) if err != nil { return err } - remote.Path = path.Dataplane() remote.NextHop = path.UnderlayNextHop() if remote.NextHop == nil { remote.NextHop = &net.UDPAddr{ @@ -158,6 +159,7 @@ On other errors, traceroute will exit with code 2. fmt.Printf("%d %s %s\n", u.Index, fmtRemote(u.Remote, u.Interface), fmtRTTs(u.RTTs, flags.timeout)) }, + EPIC: flags.epic, } stats, err = traceroute.Run(ctx, cfg) if err != nil { @@ -178,6 +180,7 @@ On other errors, traceroute will exit with code 2. cmd.Flags().StringVar(&flags.sequence, "sequence", "", app.SequenceUsage) cmd.Flags().StringVar(&flags.logLevel, "log.level", "", app.LogLevelUsage) cmd.Flags().StringVar(&flags.tracer, "tracing.agent", "", "Tracing agent address") + cmd.Flags().BoolVar(&flags.epic, "epic", false, "Enable EPIC.") return cmd } diff --git a/proto/daemon/v1/daemon.proto b/proto/daemon/v1/daemon.proto index 51e4f1549d..8f894ef5e5 100644 --- a/proto/daemon/v1/daemon.proto +++ b/proto/daemon/v1/daemon.proto @@ -94,6 +94,15 @@ message Path { // occurrence. // Entry i is the note of AS i on the path. repeated string notes = 11; + // EpicAuths contains the EPIC authenticators used to calculate the PHVF and LHVF. + EpicAuths epic_auths = 12; +} + +message EpicAuths { + // AuthPHVF is the authenticator use to calculate the PHVF. + bytes auth_phvf = 1; + // AuthLHVF is the authenticator use to calculate the LHVF. + bytes auth_lhvf = 2; } message PathInterface {