Skip to content

Commit

Permalink
retriving nextHop from path and local Interface information
Browse files Browse the repository at this point in the history
  • Loading branch information
JordiSubira committed Dec 11, 2023
1 parent 5cd34db commit ec48d39
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 54 deletions.
13 changes: 13 additions & 0 deletions control/cmd/control/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"path/filepath"
Expand Down Expand Up @@ -959,6 +960,18 @@ func (c controller) PortRange(_ context.Context) (uint16, uint16, error) {
return start, end, nil
}

func (c controller) Interfaces(_ context.Context) (map[uint16]*net.UDPAddr, error) {
ifMap := c.topo.InterfaceInfoMap()
ifsToUDP := make(map[uint16]*net.UDPAddr, len(ifMap))
for i, v := range ifMap {
if i > (1<<16)-1 {
return nil, serrors.New("Invalid interface id", "id", i)
}
ifsToUDP[uint16(i)] = v.InternalAddr
}
return ifsToUDP, nil
}

func getCAHealth(
ctx context.Context,
caClient *caapi.Client,
Expand Down
4 changes: 2 additions & 2 deletions daemon/internal/servers/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,15 @@ func (s *DaemonServer) interfaces(ctx context.Context,
_ *sdpb.InterfacesRequest) (*sdpb.InterfacesResponse, error) {

reply := &sdpb.InterfacesResponse{
Interfaces: make(map[uint64]*sdpb.Interface),
Interfaces: make(map[uint32]*sdpb.Interface),
}
topo := s.Topology
for _, ifID := range topo.InterfaceIDs() {
nextHop := topo.UnderlayNextHop(ifID)
if nextHop == nil {
continue
}
reply.Interfaces[uint64(ifID)] = &sdpb.Interface{
reply.Interfaces[uint32(ifID)] = &sdpb.Interface{
Address: &sdpb.Underlay{
Address: nextHop.String(),
},
Expand Down
7 changes: 2 additions & 5 deletions pkg/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"github.com/scionproto/scion/pkg/daemon/internal/metrics"
"github.com/scionproto/scion/pkg/drkey"
libmetrics "github.com/scionproto/scion/pkg/metrics"
"github.com/scionproto/scion/pkg/private/common"
"github.com/scionproto/scion/pkg/private/ctrl/path_mgmt"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/pkg/snet"
Expand Down Expand Up @@ -67,15 +66,13 @@ type Connector interface {
// PortRange returns the beginning and the end of the SCION/UDP endhost port range, configured
// for the local IA.
PortRange(ctx context.Context) (uint16, uint16, error)
// Interfaces returns the map of interface identifiers to the underlay internal address.
Interfaces(ctx context.Context) (map[uint16]*net.UDPAddr, error)
// Paths requests from the daemon a set of end to end paths between the source and destination.
Paths(ctx context.Context, dst, src addr.IA, f PathReqFlags) ([]snet.Path, error)
// ASInfo requests from the daemon information about AS ia, the zero IA can be
// use to detect the local IA.
ASInfo(ctx context.Context, ia addr.IA) (ASInfo, error)
// IFInfo requests from SCION Daemon addresses and ports of interfaces. Slice
// ifs contains interface IDs of BRs. If empty, a fresh (i.e., uncached)
// answer containing all interfaces is returned.
IFInfo(ctx context.Context, ifs []common.IFIDType) (map[common.IFIDType]*net.UDPAddr, error)
// SVCInfo requests from the daemon information about addresses and ports of
// infrastructure services. Slice svcTypes contains a list of desired
// service types. If unset, a fresh (i.e., uncached) answer containing all
Expand Down
43 changes: 21 additions & 22 deletions pkg/daemon/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ func (c grpcConn) PortRange(ctx context.Context) (uint16, uint16, error) {
return asInfo.EndhostStartPort, asInfo.EndhostEndPort, nil
}

func (c grpcConn) Interfaces(ctx context.Context) (map[uint16]*net.UDPAddr, error) {

client := sdpb.NewDaemonServiceClient(c.conn)
response, err := client.Interfaces(ctx, &sdpb.InterfacesRequest{})
if err != nil {
c.metrics.incInterface(err)
return nil, err
}
result := make(map[uint16]*net.UDPAddr)
for ifID, intf := range response.Interfaces {
a, err := net.ResolveUDPAddr("udp", intf.Address.Address)
if err != nil {
c.metrics.incInterface(err)
return nil, serrors.WrapStr("parsing reply", err, "raw_uri", intf.Address.Address)
}
result[uint16(ifID)] = a
}
c.metrics.incInterface(nil)
return result, nil
}

func (c grpcConn) Paths(ctx context.Context, dst, src addr.IA,
f PathReqFlags) ([]snet.Path, error) {

Expand Down Expand Up @@ -117,28 +138,6 @@ func (c grpcConn) ASInfo(ctx context.Context, ia addr.IA) (ASInfo, error) {
}, nil
}

func (c grpcConn) IFInfo(ctx context.Context,
_ []common.IFIDType) (map[common.IFIDType]*net.UDPAddr, error) {

client := sdpb.NewDaemonServiceClient(c.conn)
response, err := client.Interfaces(ctx, &sdpb.InterfacesRequest{})
if err != nil {
c.metrics.incInterface(err)
return nil, err
}
result := make(map[common.IFIDType]*net.UDPAddr)
for ifID, intf := range response.Interfaces {
a, err := net.ResolveUDPAddr("udp", intf.Address.Address)
if err != nil {
c.metrics.incInterface(err)
return nil, serrors.WrapStr("parsing reply", err, "raw_uri", intf.Address.Address)
}
result[common.IFIDType(ifID)] = a
}
c.metrics.incInterface(nil)
return result, nil
}

func (c grpcConn) SVCInfo(
ctx context.Context,
_ []addr.SVC,
Expand Down
1 change: 0 additions & 1 deletion pkg/daemon/mock_daemon/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ go_library(
"//pkg/addr:go_default_library",
"//pkg/daemon:go_default_library",
"//pkg/drkey:go_default_library",
"//pkg/private/common:go_default_library",
"//pkg/private/ctrl/path_mgmt:go_default_library",
"//pkg/snet:go_default_library",
"@com_github_golang_mock//gomock:go_default_library",
Expand Down
15 changes: 7 additions & 8 deletions pkg/daemon/mock_daemon/mock.go

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

6 changes: 3 additions & 3 deletions pkg/proto/daemon/daemon.pb.go

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

4 changes: 4 additions & 0 deletions pkg/snet/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ go_library(
"//pkg/private/util:go_default_library",
"//pkg/slayers:go_default_library",
"//pkg/slayers/path:go_default_library",
"//pkg/slayers/path/empty:go_default_library",
"//pkg/slayers/path/epic:go_default_library",
"//pkg/slayers/path/onehop:go_default_library",
"//pkg/slayers/path/scion:go_default_library",
"//private/topology:go_default_library",
"//private/topology/underlay:go_default_library",
"@com_github_google_gopacket//:go_default_library",
],
)
Expand Down
104 changes: 93 additions & 11 deletions pkg/snet/packet_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import (
"github.com/scionproto/scion/pkg/private/common"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/pkg/slayers/path/empty"
"github.com/scionproto/scion/pkg/slayers/path/epic"
"github.com/scionproto/scion/pkg/slayers/path/onehop"
"github.com/scionproto/scion/pkg/slayers/path/scion"
"github.com/scionproto/scion/private/topology/underlay"
)

// PacketConn gives applications easy access to writing and reading custom
Expand Down Expand Up @@ -114,7 +119,8 @@ type SCIONPacketConn struct {
// SCMP message is received.
SCMPHandler SCMPHandler
// Metrics are the metrics exported by the conn.
Metrics SCIONPacketConnMetrics
Metrics SCIONPacketConnMetrics
getLastHopAddr func(id uint16) (*net.UDPAddr, error)
}

func (c *SCIONPacketConn) SetReadBuffer(bytes int) error {
Expand Down Expand Up @@ -185,7 +191,7 @@ func (c *SCIONPacketConn) SyscallConn() (syscall.RawConn, error) {

func (c *SCIONPacketConn) readFrom(pkt *Packet, ov *net.UDPAddr) error {
pkt.Prepare()
n, lastHopNetAddr, err := c.Conn.ReadFrom(pkt.Bytes)
n, err := c.Conn.Read(pkt.Bytes)
if err != nil {
metrics.CounterInc(c.Metrics.UnderlayConnectionErrors)
return serrors.WrapStr("Reliable socket read error", err)
Expand All @@ -194,20 +200,17 @@ func (c *SCIONPacketConn) readFrom(pkt *Packet, ov *net.UDPAddr) error {
metrics.CounterInc(c.Metrics.ReadPackets)

pkt.Bytes = pkt.Bytes[:n]
var lastHop *net.UDPAddr

var ok bool
lastHop, ok = lastHopNetAddr.(*net.UDPAddr)
if !ok {
return serrors.New("Invalid lastHop address Type",
"Actual", lastHopNetAddr)
}

if err := pkt.Decode(); err != nil {
metrics.CounterInc(c.Metrics.ParseErrors)
return serrors.WrapStr("decoding packet", err)
}

// Get ingress interface internal address
lastHop, err := c.lastHop(pkt)
if err != nil {
return serrors.WrapStr("extracting next hop based on packet path", err)
}

if ov != nil {
*ov = *lastHop
}
Expand Down Expand Up @@ -236,3 +239,82 @@ type SerializationOptions struct {
// unchanged.
InitializePaths bool
}

func (c *SCIONPacketConn) lastHop(p *Packet) (*net.UDPAddr, error) {
rpath, ok := p.Path.(RawPath)
if !ok {
return nil, serrors.New("Unexpected path", "type", common.TypeOf(p.Path))
}
switch rpath.PathType {
case empty.PathType:
if p.Source.Host.Type() != addr.HostTypeIP {
return nil, serrors.New("Unexpected source address in packet",
"type", p.Source.Host.Type().String())
}
var port int
switch p := p.PacketInfo.Payload.(type) {
case UDPPayload:
port = int(p.SrcPort)
case SCMPPayload:
port = underlay.EndhostPort
default:
// we fallback to the endhost port also for unknown payloads
port = underlay.EndhostPort
}
return &net.UDPAddr{
IP: p.Source.Host.IP().AsSlice(),
Port: port,
}, nil
case onehop.PathType:
var path onehop.Path
err := path.DecodeFromBytes(rpath.Raw)
if err != nil {
return nil, err
}
ifid := path.SecondHop.ConsIngress
if !path.Info.ConsDir {
ifid = path.SecondHop.ConsEgress
}
return c.getLastHopAddr(ifid)
case epic.PathType:
var path epic.Path
err := path.DecodeFromBytes(rpath.Raw)
if err != nil {
return nil, err
}
infoField, err := path.ScionPath.GetCurrentInfoField()
if err != nil {
return nil, err
}
hf, err := path.ScionPath.GetCurrentHopField()
if err != nil {
return nil, err
}
ifid := hf.ConsIngress
if !infoField.ConsDir {
ifid = hf.ConsEgress
}
return c.getLastHopAddr(ifid)
case scion.PathType:
var path scion.Raw
err := path.DecodeFromBytes(rpath.Raw)
if err != nil {
return nil, err
}
infoField, err := path.GetCurrentInfoField()
if err != nil {
return nil, err
}
hf, err := path.GetCurrentHopField()
if err != nil {
return nil, err
}
ifid := hf.ConsIngress
if !infoField.ConsDir {
ifid = hf.ConsEgress
}
return c.getLastHopAddr(ifid)
default:
return nil, serrors.New("Unknown type", "type", rpath.PathType.String())
}
}
13 changes: 12 additions & 1 deletion pkg/snet/snet.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import (
// Controller provides local-IA control-plane information
type Controller interface {
PortRange(ctx context.Context) (uint16, uint16, error)
Interfaces(ctx context.Context) (map[uint16]*net.UDPAddr, error)
}

type Connector interface {
Expand All @@ -75,7 +76,10 @@ func (d *DefaultConnector) OpenUDP(ctx context.Context, addr *net.UDPAddr) (Pack
if err != nil {
return nil, err
}
log.Debug("OpenUDP", "addr", addr)
ifAddrs, err := d.Controller.Interfaces(ctx)
if err != nil {
return nil, err
}
if addr.Port == 0 {
pconn, err = listenUDPRange(addr, start, end)
} else {
Expand All @@ -94,6 +98,13 @@ func (d *DefaultConnector) OpenUDP(ctx context.Context, addr *net.UDPAddr) (Pack
Conn: pconn,
SCMPHandler: d.SCMPHandler,
Metrics: d.Metrics,
getLastHopAddr: func(id uint16) (*net.UDPAddr, error) {
addr, ok := ifAddrs[id]
if !ok {
return nil, serrors.New("Interface number not found", "if", id)
}
return addr, nil
},
}, nil
}

Expand Down
Loading

0 comments on commit ec48d39

Please sign in to comment.