diff --git a/go/cs/beaconing/BUILD.bazel b/go/cs/beaconing/BUILD.bazel index 67a3635613..f5c2e8241c 100644 --- a/go/cs/beaconing/BUILD.bazel +++ b/go/cs/beaconing/BUILD.bazel @@ -33,7 +33,6 @@ go_library( "//go/lib/serrors:go_default_library", "//go/lib/slayers/path:go_default_library", "//go/lib/snet:go_default_library", - "//go/lib/snet/addrutil:go_default_library", "//go/lib/spath:go_default_library", "//go/lib/topology:go_default_library", "//go/lib/util:go_default_library", @@ -71,6 +70,7 @@ go_test( "//go/lib/scrypto/cppki:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/snet:go_default_library", + "//go/lib/snet/addrutil:go_default_library", "//go/lib/spath:go_default_library", "//go/lib/topology:go_default_library", "//go/lib/util:go_default_library", diff --git a/go/cs/beaconing/registrar.go b/go/cs/beaconing/registrar.go index 71da04799a..9124f44801 100644 --- a/go/cs/beaconing/registrar.go +++ b/go/cs/beaconing/registrar.go @@ -30,7 +30,6 @@ import ( "github.com/scionproto/scion/go/lib/infra/modules/seghandler" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/periodic" - "github.com/scionproto/scion/go/lib/snet/addrutil" "github.com/scionproto/scion/go/lib/topology" "github.com/scionproto/scion/go/proto" ) @@ -51,6 +50,11 @@ type RPC interface { RegisterSegment(ctx context.Context, meta seg.Meta, remote net.Addr) error } +// Pather computes the remote address with a path based on the provided segment. +type Pather interface { + GetPath(svc addr.HostSVC, ps *seg.PathSegment) (net.Addr, error) +} + var _ periodic.Task = (*Registrar)(nil) // Registrar is used to periodically register path segments with the appropriate @@ -61,13 +65,12 @@ type Registrar struct { Provider SegmentProvider Store SegmentStore RPC RPC + Pather Pather IA addr.IA Signer ctrl.Signer Intfs *ifstate.Interfaces Type proto.PathSegType - TopoProvider topology.Provider // FIXME(roosd): reduce this to the minimal required interface. - // tick is mutable. Tick Tick lastSucc time.Time @@ -134,11 +137,11 @@ func (r *Registrar) registerRemote(ctx context.Context, segments <-chan beacon.B } expected++ s := remoteRegistrar{ - segType: r.Type, - rpc: r.RPC, - topoProvider: r.TopoProvider, - summary: s, - wg: &wg, + segType: r.Type, + rpc: r.RPC, + pather: r.Pather, + summary: s, + wg: &wg, } // Avoid head-of-line blocking when sending message to slow servers. @@ -210,18 +213,18 @@ func (r *Registrar) logSummary(logger log.Logger, s *summary) { // remoteRegistrar registers one segment with the path server. type remoteRegistrar struct { - segType proto.PathSegType - rpc RPC - topoProvider topology.Provider - summary *summary - wg *sync.WaitGroup + segType proto.PathSegType + rpc RPC + pather Pather + summary *summary + wg *sync.WaitGroup } // start extends the beacon and starts a go routine that registers the beacon // with the path server. func (r *remoteRegistrar) start(ctx context.Context, bseg beacon.Beacon) { logger := log.FromCtx(ctx) - addr, err := addrutil.GetPath(addr.SvcPS, bseg.Segment, r.topoProvider) + addr, err := r.pather.GetPath(addr.SvcPS, bseg.Segment) if err != nil { metrics.Registrar.InternalErrorsWithType(r.segType.String()).Inc() logger.Error("[beaconing.Registrar] Unable to choose server", "err", err) diff --git a/go/cs/beaconing/registrar_test.go b/go/cs/beaconing/registrar_test.go index afa29244cb..bbe4305ee9 100644 --- a/go/cs/beaconing/registrar_test.go +++ b/go/cs/beaconing/registrar_test.go @@ -44,6 +44,7 @@ import ( "github.com/scionproto/scion/go/lib/scrypto" "github.com/scionproto/scion/go/lib/scrypto/cppki" "github.com/scionproto/scion/go/lib/snet" + "github.com/scionproto/scion/go/lib/snet/addrutil" "github.com/scionproto/scion/go/lib/xtest/graph" "github.com/scionproto/scion/go/pkg/trust" "github.com/scionproto/scion/go/proto" @@ -102,14 +103,14 @@ func TestRegistrarRun(t *testing.T) { MaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime), StaticInfo: func() *StaticInfoCfg { return nil }, }, - IA: topoProvider.Get().IA(), - Signer: testSigner(t, priv, topoProvider.Get().IA()), - Intfs: intfs, - Tick: NewTick(time.Hour), - Provider: segProvider, - Store: segStore, - TopoProvider: topoProvider, - Type: test.segType, + IA: topoProvider.Get().IA(), + Signer: testSigner(t, priv, topoProvider.Get().IA()), + Intfs: intfs, + Tick: NewTick(time.Hour), + Provider: segProvider, + Store: segStore, + Pather: addrutil.LegacyPather{TopoProvider: topoProvider}, + Type: test.segType, } g := graph.NewDefaultGraph(mctrl) segProvider.EXPECT().SegmentsToRegister(gomock.Any(), test.segType).DoAndReturn( @@ -188,14 +189,14 @@ func TestRegistrarRun(t *testing.T) { MaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime), StaticInfo: func() *StaticInfoCfg { return nil }, }, - IA: topoProvider.Get().IA(), - Signer: testSigner(t, priv, topoProvider.Get().IA()), - Intfs: intfs, - Tick: NewTick(time.Hour), - Provider: segProvider, - TopoProvider: topoProvider, - Type: test.segType, - RPC: rpc, + IA: topoProvider.Get().IA(), + Signer: testSigner(t, priv, topoProvider.Get().IA()), + Intfs: intfs, + Tick: NewTick(time.Hour), + Provider: segProvider, + Pather: addrutil.LegacyPather{TopoProvider: topoProvider}, + Type: test.segType, + RPC: rpc, } g := graph.NewDefaultGraph(mctrl) segProvider.EXPECT().SegmentsToRegister(gomock.Any(), test.segType).DoAndReturn( @@ -279,13 +280,13 @@ func TestRegistrarRun(t *testing.T) { MaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime), StaticInfo: func() *StaticInfoCfg { return nil }, }, - IA: topoProvider.Get().IA(), - Signer: testSigner(t, priv, topoProvider.Get().IA()), - Intfs: intfs, - Tick: NewTick(time.Hour), - Provider: segProvider, - TopoProvider: topoProvider, - Type: proto.PathSegType_core, + IA: topoProvider.Get().IA(), + Signer: testSigner(t, priv, topoProvider.Get().IA()), + Intfs: intfs, + Tick: NewTick(time.Hour), + Provider: segProvider, + Pather: addrutil.LegacyPather{TopoProvider: topoProvider}, + Type: proto.PathSegType_core, } res := make(chan beacon.BeaconOrErr, 3) segProvider.EXPECT().SegmentsToRegister(gomock.Any(), proto.PathSegType_core).DoAndReturn( @@ -322,14 +323,14 @@ func TestRegistrarRun(t *testing.T) { MaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime), StaticInfo: func() *StaticInfoCfg { return nil }, }, - IA: topoProvider.Get().IA(), - Signer: testSigner(t, priv, topoProvider.Get().IA()), - Intfs: intfs, - Tick: NewTick(time.Hour), - Provider: segProvider, - TopoProvider: topoProvider, - Type: proto.PathSegType_down, - RPC: rpc, + IA: topoProvider.Get().IA(), + Signer: testSigner(t, priv, topoProvider.Get().IA()), + Intfs: intfs, + Tick: NewTick(time.Hour), + Provider: segProvider, + Pather: addrutil.LegacyPather{TopoProvider: topoProvider}, + Type: proto.PathSegType_down, + RPC: rpc, } g := graph.NewDefaultGraph(mctrl) require.NoError(t, err) diff --git a/go/lib/snet/addrutil/BUILD.bazel b/go/lib/snet/addrutil/BUILD.bazel index a0e60f87ff..0327e24526 100644 --- a/go/lib/snet/addrutil/BUILD.bazel +++ b/go/lib/snet/addrutil/BUILD.bazel @@ -10,6 +10,8 @@ go_library( "//go/lib/common:go_default_library", "//go/lib/ctrl/seg:go_default_library", "//go/lib/serrors:go_default_library", + "//go/lib/slayers/path:go_default_library", + "//go/lib/slayers/path/scion:go_default_library", "//go/lib/snet:go_default_library", "//go/lib/spath:go_default_library", "//go/lib/topology:go_default_library", diff --git a/go/lib/snet/addrutil/addrutil.go b/go/lib/snet/addrutil/addrutil.go index ff01cb2876..e197fed68b 100644 --- a/go/lib/snet/addrutil/addrutil.go +++ b/go/lib/snet/addrutil/addrutil.go @@ -16,17 +16,91 @@ package addrutil import ( "bytes" + "encoding/binary" "net" "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/serrors" + "github.com/scionproto/scion/go/lib/slayers/path" + "github.com/scionproto/scion/go/lib/slayers/path/scion" "github.com/scionproto/scion/go/lib/snet" "github.com/scionproto/scion/go/lib/spath" "github.com/scionproto/scion/go/lib/topology" ) +type Pather struct { + // UnderlayNextHop determines the next hop underlay address for the + // specified interface id. + UnderlayNextHop func(ifID uint16) (*net.UDPAddr, bool) +} + +func (p Pather) GetPath(svc addr.HostSVC, ps *seg.PathSegment) (net.Addr, error) { + if len(ps.ASEntries) == 0 { + return nil, serrors.New("empty path") + } + + beta := ps.SData.SegID + // The hop fields need to be in reversed order. + hopFields := make([]*path.HopField, len(ps.ASEntries)) + for i, entry := range ps.ASEntries { + if len(entry.HopEntries) == 0 { + return nil, serrors.New("hop with no entry", "index", i) + } + hopFields[len(hopFields)-1-i] = &path.HopField{ + ConsIngress: entry.HopEntries[0].HopField.ConsIngress, + ConsEgress: entry.HopEntries[0].HopField.ConsEgress, + ExpTime: entry.HopEntries[0].HopField.ExpTime, + Mac: entry.HopEntries[0].HopField.MAC, + } + beta = beta ^ binary.BigEndian.Uint16(entry.HopEntries[0].HopField.MAC[:2]) + } + + hops := len(hopFields) - 1 + dec := scion.Decoded{ + Base: scion.Base{ + PathMeta: scion.MetaHdr{ + CurrHF: 0, + CurrINF: 0, + SegLen: [3]uint8{uint8(hops), 0, 0}, + }, + NumHops: hops, + NumINF: 1, + }, + InfoFields: []*path.InfoField{{ + Timestamp: ps.SData.RawTimestamp, + ConsDir: false, + SegID: beta, + }}, + HopFields: hopFields, + } + raw := make([]byte, dec.Len()) + if err := dec.SerializeTo(raw); err != nil { + return nil, serrors.WrapStr("serializing path", err) + } + ifID := dec.HopFields[0].ConsIngress + nextHop, ok := p.UnderlayNextHop(ifID) + if !ok { + return nil, serrors.New("first-hop border router not found", "intf_id", ifID) + } + return &snet.SVCAddr{ + IA: ps.FirstIA(), + Path: spath.NewV2(raw), + NextHop: nextHop, + SVC: svc, + }, nil + +} + +type LegacyPather struct { + TopoProvider topology.Provider +} + +func (p LegacyPather) GetPath(svc addr.HostSVC, ps *seg.PathSegment) (net.Addr, error) { + return GetPath(svc, ps, p.TopoProvider) +} + // GetPath creates a path from the given segment and then creates a snet.SVCAddr. func GetPath(svc addr.HostSVC, ps *seg.PathSegment, topoProv topology.Provider) (net.Addr, error) { p, err := legacyPath(ps) diff --git a/go/pkg/cs/BUILD.bazel b/go/pkg/cs/BUILD.bazel index 97f1f824ab..9e1042cd40 100644 --- a/go/pkg/cs/BUILD.bazel +++ b/go/pkg/cs/BUILD.bazel @@ -43,6 +43,7 @@ go_library( "//go/lib/scrypto:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/snet:go_default_library", + "//go/lib/snet/addrutil:go_default_library", "//go/lib/sock/reliable:go_default_library", "//go/lib/sock/reliable/reconnect:go_default_library", "//go/lib/spath:go_default_library", diff --git a/go/pkg/cs/main.go b/go/pkg/cs/main.go index 09af0e345e..1704f36003 100644 --- a/go/pkg/cs/main.go +++ b/go/pkg/cs/main.go @@ -71,6 +71,7 @@ import ( "github.com/scionproto/scion/go/lib/scrypto" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/snet" + "github.com/scionproto/scion/go/lib/snet/addrutil" "github.com/scionproto/scion/go/lib/sock/reliable" "github.com/scionproto/scion/go/lib/sock/reliable/reconnect" "github.com/scionproto/scion/go/lib/spath" @@ -474,6 +475,7 @@ func (app *App) Run() int { return 1 } Tasks = &PeriodicTasks{ + headerV2: Cfg.Features.HeaderV2, args: args, intfs: Intfs, conn: conn.(*snet.SCIONPacketConn), @@ -543,6 +545,7 @@ type PeriodicTasks struct { TopoProvider topology.Provider allowIsdLoop bool addressRewriter *messenger.AddressRewriter + headerV2 bool Keepalive *periodic.Runner originator *periodic.Runner @@ -686,16 +689,7 @@ func (t *PeriodicTasks) startOriginator(a *net.UDPAddr) (*periodic.Runner, error return nil, nil } s := &beaconing.Originator{ - Extender: &beaconing.LegacyExtender{ - IA: topo.IA(), - Signer: t.signer, - MAC: t.genMac, - Intfs: t.intfs, - MTU: topo.MTU(), - MaxExpTime: maxExpTimeFactory(t.store, beacon.PropPolicy), - StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfoCfg }, - Task: "originator", - }, + Extender: t.extender("propagator", topo, maxExpTimeFactory(t.store, beacon.PropPolicy)), BeaconSender: &onehop.BeaconSender{ Sender: onehop.Sender{ Conn: t.conn, @@ -717,16 +711,7 @@ func (t *PeriodicTasks) startOriginator(a *net.UDPAddr) (*periodic.Runner, error func (t *PeriodicTasks) startPropagator(a *net.UDPAddr) (*periodic.Runner, error) { topo := t.TopoProvider.Get() p := &beaconing.Propagator{ - Extender: &beaconing.LegacyExtender{ - IA: topo.IA(), - Signer: t.signer, - MAC: t.genMac, - Intfs: t.intfs, - MTU: topo.MTU(), - MaxExpTime: maxExpTimeFactory(t.store, beacon.PropPolicy), - StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfoCfg }, - Task: "propagator", - }, + Extender: t.extender("propagator", topo, maxExpTimeFactory(t.store, beacon.PropPolicy)), BeaconSender: &onehop.BeaconSender{ Sender: onehop.Sender{ Conn: t.conn, @@ -773,28 +758,56 @@ func (t *PeriodicTasks) startSegRegRunners() (segRegRunners, error) { func (t *PeriodicTasks) startRegistrar(topo topology.Topology, segType proto.PathSegType, policyType beacon.PolicyType) (*periodic.Runner, error) { + var pather beaconing.Pather = addrutil.LegacyPather{TopoProvider: t.TopoProvider} + if t.headerV2 { + pather = addrutil.Pather{ + UnderlayNextHop: func(ifID uint16) (*net.UDPAddr, bool) { + return t.TopoProvider.Get().UnderlayNextHop2(common.IFIDType(ifID)) + }, + } + } + r := &beaconing.Registrar{ - Extender: &beaconing.LegacyExtender{ + Extender: t.extender("registrar", topo, maxExpTimeFactory(t.store, policyType)), + Provider: t.store, + Store: &seghandler.DefaultStorage{PathDB: t.pathDB}, + RPC: beaconingcompat.RPC{Messenger: t.msgr}, + IA: topo.IA(), + Signer: t.signer, + Intfs: t.intfs, + Type: segType, + Pather: pather, + Tick: beaconing.NewTick(Cfg.BS.RegistrationInterval.Duration), + } + return periodic.Start(r, 500*time.Millisecond, Cfg.BS.RegistrationInterval.Duration), nil +} + +func (t *PeriodicTasks) extender(task string, topo topology.Topology, + maxExp func() spath.ExpTimeType) beaconing.Extender { + + if !t.headerV2 { + return &beaconing.LegacyExtender{ IA: topo.IA(), Signer: t.signer, MAC: t.genMac, Intfs: t.intfs, MTU: topo.MTU(), - MaxExpTime: maxExpTimeFactory(t.store, policyType), + MaxExpTime: maxExp, StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfoCfg }, - Task: "registrar", - }, - Provider: t.store, - Store: &seghandler.DefaultStorage{PathDB: t.pathDB}, - RPC: beaconingcompat.RPC{Messenger: t.msgr}, - IA: topo.IA(), - Signer: t.signer, - Intfs: t.intfs, - Type: segType, - TopoProvider: t.TopoProvider, - Tick: beaconing.NewTick(Cfg.BS.RegistrationInterval.Duration), + Task: task, + } } - return periodic.Start(r, 500*time.Millisecond, Cfg.BS.RegistrationInterval.Duration), nil + return &beaconing.DefaultExtender{ + IA: topo.IA(), + Signer: t.signer, + MAC: t.genMac, + Intfs: t.intfs, + MTU: topo.MTU(), + MaxExpTime: func() uint8 { return uint8(maxExp()) }, + StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfoCfg }, + Task: task, + } + } func (t *PeriodicTasks) Kill() {