From 5c597c49bf3d82a92778ff7ecddd4ff7f871cd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Tue, 24 Sep 2024 16:51:57 +0200 Subject: [PATCH 01/18] SCMP problems --- .../scion/jpan/api/ScmpSenderAsyncTest.java | 116 ++++++++++++++---- .../scion/jpan/demo/ScmpTracerouteDemo.java | 3 +- 2 files changed, 93 insertions(+), 26 deletions(-) diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 6263cc84..598ea364 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; @@ -123,43 +124,104 @@ void getHandler() throws IOException { @Test void sendEcho() throws IOException { - testEcho(this::getPathTo112); + testEcho(this::getPathTo112, 5); } @Test void sendEcho_localAS_BR() throws IOException { - testEcho(this::getPathToLocalAS_BR); - assertEquals(1, MockNetwork.getAndResetForwardCount()); // 1! - assertEquals(1, MockScmpHandler.getAndResetAnswerTotal()); + int n = 5; + testEcho(this::getPathToLocalAS_BR, n); + assertEquals(n, MockNetwork.getAndResetForwardCount()); // 1! + assertEquals(n, MockScmpHandler.getAndResetAnswerTotal()); } @Test void sendEcho_localAS_BR_30041() throws IOException { - testEcho(this::getPathToLocalAS_BR_30041); + int n = 5; + testEcho(this::getPathToLocalAS_BR_30041, n); assertEquals(0, MockNetwork.getAndResetForwardCount()); // 0! - assertEquals(1, MockScmpHandler.getAndResetAnswerTotal()); + assertEquals(n, MockScmpHandler.getAndResetAnswerTotal()); } - private void testEcho(Supplier pathSupplier) throws IOException { + private void testEcho(Supplier pathSupplier, int n) throws IOException { MockNetwork.startTiny(); - MockNetwork.answerNextScmpEchos(1); + MockNetwork.answerNextScmpEchos(n); + EchoHandler handler = new EchoHandler(); + try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { + for (int i = 0; i < 5; i++) { + channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); + byte[] data = new byte[] {1, 2, 3, 4, 5}; + Path path = pathSupplier.get(); + int seqId = channel.sendEcho(path, ByteBuffer.wrap(data)); + Scmp.EchoMessage result = handler.get(); + System.err.println("seqId: " + seqId + " " + result.getSequenceNumber()); + // assertEquals(seqId, result.getSequenceNumber()); + assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); + assertTrue(result.getNanoSeconds() > 0); + assertTrue(result.getNanoSeconds() < 100_000_000); // 10 ms + assertArrayEquals(data, result.getData()); + assertFalse(result.isTimedOut()); + Path returnPath = result.getPath(); + assertEquals(path.getRemoteAddress(), returnPath.getRemoteAddress()); + assertEquals(Constants.SCMP_PORT, returnPath.getRemotePort()); + assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); + } + } finally { + MockNetwork.stopTiny(); + } + } + + @Test + void sendEcho_async() throws IOException { + testEchoAsync(this::getPathTo112, 20); + } + + @Test + void sendEcho_localAS_BR_async() throws IOException { + int n = 20; + testEchoAsync(this::getPathToLocalAS_BR, n); + assertEquals(n, MockNetwork.getAndResetForwardCount()); // 1! + assertEquals(n, MockScmpHandler.getAndResetAnswerTotal()); + } + + @Test + void sendEcho_localAS_BR_30041_async() throws IOException { + int n = 20; + testEchoAsync(this::getPathToLocalAS_BR_30041, n); + assertEquals(0, MockNetwork.getAndResetForwardCount()); // 0! + assertEquals(n, MockScmpHandler.getAndResetAnswerTotal()); + } + + private void testEchoAsync(Supplier pathSupplier, int n) throws IOException { + MockNetwork.startTiny(); + MockNetwork.answerNextScmpEchos(n); EchoHandler handler = new EchoHandler(); try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); byte[] data = new byte[] {1, 2, 3, 4, 5}; Path path = pathSupplier.get(); - int seqId = channel.sendEcho(path, ByteBuffer.wrap(data)); - Scmp.EchoMessage result = handler.get(); - assertEquals(seqId, result.getSequenceNumber()); - assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); - assertTrue(result.getNanoSeconds() > 0); - assertTrue(result.getNanoSeconds() < 100_000_000); // 10 ms - assertArrayEquals(data, result.getData()); - assertFalse(result.isTimedOut()); - Path returnPath = result.getPath(); - assertEquals(path.getRemoteAddress(), returnPath.getRemoteAddress()); - assertEquals(Constants.SCMP_PORT, returnPath.getRemotePort()); - assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); + HashSet seqIDs = new HashSet<>(); + for (int i = 0; i < n; i++) { + seqIDs.add(channel.sendEcho(path, ByteBuffer.wrap(data))); + } + + List results = handler.get(n); + for (int i = 0; i < n; i++) { + Scmp.EchoMessage result = results.get(i); + System.err.println("seqId: " + result.getSequenceNumber()); + // assertEquals(seqId, result.getSequenceNumber()); + assertTrue(seqIDs.contains(result.getSequenceNumber())); + seqIDs.remove(result.getSequenceNumber()); + assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); + assertTrue(result.getNanoSeconds() > 0); + assertTrue(result.getNanoSeconds() < 100_000_000); // 10 ms + assertArrayEquals(data, result.getData()); + assertFalse(result.isTimedOut()); + Path returnPath = result.getPath(); + assertEquals(path.getRemoteAddress(), returnPath.getRemoteAddress()); + assertEquals(Constants.SCMP_PORT, returnPath.getRemotePort()); + assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); + } } finally { MockNetwork.stopTiny(); } @@ -571,22 +633,26 @@ public void onException(Throwable t) { } } - private static class EchoHandler extends ScmpHandler { - Scmp.EchoMessage response = null; + private static class EchoHandler extends ScmpHandler> { + private ArrayList responses = new ArrayList<>(); synchronized void handle(Scmp.EchoMessage msg) { - response = msg; + responses.add(msg); this.notifyAll(); } Scmp.EchoMessage get() throws IOException { - return super.waitForResult(() -> response); + return get(1).get(0); + } + + List get(int count) throws IOException { + return super.waitForResult(() -> responses.size() >= count ? responses : null); } @Override public synchronized void reset() { super.reset(); - response = null; + responses = new ArrayList<>(); } @Override diff --git a/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java b/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java index 1f60c619..6a8e7197 100644 --- a/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java +++ b/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java @@ -87,7 +87,8 @@ public static void main(String[] args) throws IOException { // Local port must be 30041 for networks that expect a dispatcher ScmpTracerouteDemo demo = new ScmpTracerouteDemo(Constants.SCMP_PORT); - demo.runDemo(ScionUtil.parseIA("64-2:0:44")); // VEX + demo.runDemo(ScionUtil.parseIA("64-2:0:28")); // Cyberlink Cloud Test AS + // demo.runDemo(ScionUtil.parseIA("64-2:0:44")); // VEX // demo.runDemo(ScionUtil.parseIA("66-2:0:10")); //singapore // demo.runDemo(DemoConstants.iaAnapayaHK); // demo.runDemo(DemoConstants.iaOVGU); From cb212df077b045295b0957ca8528c4766147d1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Tue, 24 Sep 2024 18:21:00 +0200 Subject: [PATCH 02/18] SCMP problems --- .../java/org/scion/jpan/ScmpSenderAsync.java | 53 +++++++++++++------ .../jpan/internal/ScionHeaderParser.java | 31 +++++++---- .../org/scion/jpan/internal/ScmpParser.java | 7 +-- .../scion/jpan/api/ScmpSenderAsyncTest.java | 11 ++-- .../scion/jpan/demo/inspector/ScmpHeader.java | 4 ++ .../org/scion/jpan/testutil/MockNetwork.java | 2 +- .../scion/jpan/testutil/MockScmpHandler.java | 5 +- 7 files changed, 78 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index e48b1e7d..fd2b41f3 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -41,6 +41,8 @@ public class ScmpSenderAsync implements AutoCloseable { private final CountDownLatch receiverBarrier = new CountDownLatch(1); private final ResponseHandler handler; + public static boolean CHECK = false; + public static Builder newBuilder(ResponseHandler handler) { return new Builder(handler); } @@ -305,20 +307,39 @@ private void readIncomingScmp(SelectionKey key) throws IOException { ByteBuffer buffer = super.getBufferReceive(DEFAULT_BUFFER_SIZE); buffer.clear(); InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); +// System.err.println("readIncoming(): " + buffer.position() + " " + srcAddress); // TODO + while (srcAddress == null) { + srcAddress = (InetSocketAddress) incoming.receive(buffer); + } +// System.err.println("readIncoming() 2: " + buffer.remaining() + " " + srcAddress); // TODO buffer.flip(); - if (validate(buffer)) { - InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); - // From here on we use linear reading using the buffer's position() mechanism - buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); - // Check for extension headers. - // This should be mostly unnecessary, however we sometimes saw SCMP error headers - // wrapped in extensions headers. - hdrType = receiveExtensionHeader(buffer, hdrType); - - if (hdrType != InternalConstants.HdrTypes.SCMP) { - return; // drop + if (buffer.remaining() == 0) { + return; // Wait for data + } + boolean MULTI = buffer.remaining() > 85; + while (buffer.hasRemaining()) { + int pos1 = buffer.position(); + if (MULTI) System.err.println("readIncoming() 3: " + buffer.position() + " " + srcAddress); // TODO + if (validate(buffer)) { + InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); + ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); + int packetLength = ScionHeaderParser.extractPacketLength(buffer); + // From here on we use linear reading using the buffer's position() mechanism + buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); + // Check for extension headers. + // This should be mostly unnecessary, however we sometimes saw SCMP error headers + // wrapped in extensions headers. + hdrType = receiveExtensionHeader(buffer, hdrType); + + if (hdrType != InternalConstants.HdrTypes.SCMP) { + return; // drop + } + handleIncomingScmp(buffer, receivePath, packetLength); + int pos2 = buffer.position(); + if (CHECK && pos2 - pos1 > 85 ) { + throw new IllegalStateException(); + } } - handleIncomingScmp(buffer, srcAddress); } } catch (ScionException e) { // Validation problem -> ignore @@ -328,10 +349,10 @@ private void readIncomingScmp(SelectionKey key) throws IOException { } } - private void handleIncomingScmp(ByteBuffer buffer, InetSocketAddress srcAddress) { + private void handleIncomingScmp(ByteBuffer buffer, ResponsePath receivePath, int packetLength) { long currentNanos = System.nanoTime(); - ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); - Scmp.Message msg = ScmpParser.consume(buffer, receivePath); + int bufferStart = buffer.position(); + Scmp.Message msg = ScmpParser.consume(buffer, receivePath, packetLength); if (msg.getTypeCode().isError()) { handler.onError((Scmp.ErrorMessage) msg); checkListeners(msg); @@ -346,7 +367,7 @@ private void handleIncomingScmp(ByteBuffer buffer, InetSocketAddress srcAddress) ((Scmp.TimedMessage) msg).assignRequest(request, currentNanos); handler.onResponse((Scmp.TimedMessage) msg); } else if (msg.getTypeCode() == Scmp.TypeCode.TYPE_129) { - ((Scmp.EchoMessage) msg).setSizeReceived(buffer.position()); + ((Scmp.EchoMessage) msg).setSizeReceived(buffer.position() - bufferStart); ((Scmp.TimedMessage) msg).assignRequest(request, currentNanos); handler.onResponse((Scmp.TimedMessage) msg); } else { diff --git a/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java b/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java index aae129c6..c7bde27b 100644 --- a/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java +++ b/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java @@ -52,6 +52,17 @@ public static void extractUserPayload(ByteBuffer data, ByteBuffer userBuffer) { data.position(pos); } + /** + * Extract the total packet length without changing the buffer's position. + * + * @param data The datagram to read from. + */ + public static int extractPacketLength(ByteBuffer data) { + int headerLen = extractHeaderLength(data); + int payloadLen = ByteUtil.toUnsigned(data.getShort(data.position() + 6)); + return headerLen + payloadLen; + } + /** * Extract the remote socket address and path without changing the buffer's position. * @@ -62,8 +73,8 @@ public static ResponsePath extractResponsePath( ByteBuffer data, InetSocketAddress firstHopAddress) { int pos = data.position(); - int i1 = data.getInt(4); - int i2 = data.getInt(8); + int i1 = data.getInt(pos + 4); + int i2 = data.getInt(pos + 8); int nextHeader = ByteUtil.readInt(i1, 0, 8); InternalConstants.HdrTypes hdrType = InternalConstants.HdrTypes.parse(nextHeader); int hdrLen = ByteUtil.readInt(i1, 8, 8); @@ -79,11 +90,11 @@ public static ResponsePath extractResponsePath( // ? bit: DstHostAddr // ? bit: SrcHostAddr - long dstIsdAs = data.getLong(12); - long srcIsdAs = data.getLong(20); + long dstIsdAs = data.getLong(pos + 12); + long srcIsdAs = data.getLong(pos + 20); // dstAddress - data.position(28); + data.position(pos + 28); byte[] bytesDst = new byte[(dl + 1) * 4]; data.get(bytesDst); @@ -102,7 +113,7 @@ public static ResponsePath extractResponsePath( } // raw path - byte[] path = new byte[hdrLenBytes - data.position()]; + byte[] path = new byte[hdrLenBytes - data.position() - pos]; if (path.length > 0) { // raw path may be empty for local AS data.get(path); @@ -110,7 +121,7 @@ public static ResponsePath extractResponsePath( } // get remote port from UDP or SCMP payload - data.position(hdrLenBytes); + data.position(pos + hdrLenBytes); int srcPort; int dstPort; if (hdrType == InternalConstants.HdrTypes.UDP) { @@ -118,7 +129,7 @@ public static ResponsePath extractResponsePath( srcPort = Short.toUnsignedInt(data.getShort()); dstPort = Short.toUnsignedInt(data.getShort()); } else if (hdrType == InternalConstants.HdrTypes.SCMP) { - data.position(hdrLenBytes + 4); + data.position(pos + hdrLenBytes + 4); // ports will be swapped further down dstPort = Short.toUnsignedInt(data.getShort()); srcPort = Constants.SCMP_PORT; @@ -140,7 +151,7 @@ public static ResponsePath extractResponsePath( * @return The type of the next header. */ public static InternalConstants.HdrTypes extractNextHeader(ByteBuffer data) { - int nextHeader = ByteUtil.toUnsigned(data.get(4)); + int nextHeader = ByteUtil.toUnsigned(data.get(data.position() + 4)); return InternalConstants.HdrTypes.parse(nextHeader); } @@ -216,7 +227,7 @@ private static int extractDstPort( * @return the length of the SCION common + address + path header in bytes */ public static int extractHeaderLength(ByteBuffer data) { - int hdrLen = ByteUtil.toUnsigned(data.get(5)); + int hdrLen = ByteUtil.toUnsigned(data.get(data.position() + 5)); return hdrLen * 4; } diff --git a/src/main/java/org/scion/jpan/internal/ScmpParser.java b/src/main/java/org/scion/jpan/internal/ScmpParser.java index 85d1ecee..b9a19df5 100644 --- a/src/main/java/org/scion/jpan/internal/ScmpParser.java +++ b/src/main/java/org/scion/jpan/internal/ScmpParser.java @@ -64,7 +64,8 @@ public static void buildScmpTraceroute( public static Scmp.Type extractType(ByteBuffer data) { // Avoid changing the position! - return Scmp.Type.parse(ByteUtil.toUnsigned(data.get(data.position()))); + int headerLength = ScionHeaderParser.extractHeaderLength(data); + return Scmp.Type.parse(ByteUtil.toUnsigned(data.get(data.position() + headerLength))); } /** @@ -113,7 +114,7 @@ public static void consume(ByteBuffer data, Scmp.Message holder) { * @param data packet data * @return SCMP message */ - public static Scmp.Message consume(ByteBuffer data, ResponsePath path) { + public static Scmp.Message consume(ByteBuffer data, ResponsePath path, int packetLength) { int type = ByteUtil.toUnsigned(data.get()); int code = ByteUtil.toUnsigned(data.get()); data.getShort(); // checksum @@ -128,7 +129,7 @@ public static Scmp.Message consume(ByteBuffer data, ResponsePath path) { case INFO_129: Scmp.EchoMessage echo = Scmp.EchoMessage.createEmpty(path); echo.setMessageArgs(sc, short1, short2); - echo.setData(new byte[data.remaining()]); + echo.setData(new byte[packetLength - data.position()]); data.get(echo.getData()); return echo; case INFO_130: diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 598ea364..45846432 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -197,24 +197,27 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio MockNetwork.answerNextScmpEchos(n); EchoHandler handler = new EchoHandler(); try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { + channel.setTimeOut(10000); + ScmpSenderAsync.CHECK = true; channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); byte[] data = new byte[] {1, 2, 3, 4, 5}; Path path = pathSupplier.get(); HashSet seqIDs = new HashSet<>(); + System.err.println("************************************************* Start send()"); // TODO for (int i = 0; i < n; i++) { seqIDs.add(channel.sendEcho(path, ByteBuffer.wrap(data))); } + System.err.println("************************************************* Start get()"); // TODO List results = handler.get(n); for (int i = 0; i < n; i++) { Scmp.EchoMessage result = results.get(i); - System.err.println("seqId: " + result.getSequenceNumber()); - // assertEquals(seqId, result.getSequenceNumber()); + System.err.println("************************************************* seqId: " + result.getSequenceNumber()); // TODO assertTrue(seqIDs.contains(result.getSequenceNumber())); seqIDs.remove(result.getSequenceNumber()); assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); assertTrue(result.getNanoSeconds() > 0); - assertTrue(result.getNanoSeconds() < 100_000_000); // 10 ms + assertTrue(result.getNanoSeconds() < 990_000_000); // 10 ms assertArrayEquals(data, result.getData()); assertFalse(result.isTimedOut()); Path returnPath = result.getPath(); @@ -223,6 +226,7 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); } } finally { + ScmpSenderAsync.CHECK = false; MockNetwork.stopTiny(); } } @@ -638,6 +642,7 @@ private static class EchoHandler extends ScmpHandler> { synchronized void handle(Scmp.EchoMessage msg) { responses.add(msg); + System.err.println("seqId: " + msg.getSequenceNumber()); // TODO this.notifyAll(); } diff --git a/src/test/java/org/scion/jpan/demo/inspector/ScmpHeader.java b/src/test/java/org/scion/jpan/demo/inspector/ScmpHeader.java index 0300376f..b9acf92b 100644 --- a/src/test/java/org/scion/jpan/demo/inspector/ScmpHeader.java +++ b/src/test/java/org/scion/jpan/demo/inspector/ScmpHeader.java @@ -128,4 +128,8 @@ public void setTraceData(long isdAs, int ifID) { this.traceIsdAs = isdAs; this.traceIfID = ifID; } + + public int getSequenceId() { + return short2; + } } diff --git a/src/test/java/org/scion/jpan/testutil/MockNetwork.java b/src/test/java/org/scion/jpan/testutil/MockNetwork.java index 5d1d59cd..8b62469c 100644 --- a/src/test/java/org/scion/jpan/testutil/MockNetwork.java +++ b/src/test/java/org/scion/jpan/testutil/MockNetwork.java @@ -362,7 +362,7 @@ private void forwardPacket(ByteBuffer buffer, SocketAddress srcAddress, Datagram private void handleScmp(ByteBuffer buffer, SocketAddress srcAddress, DatagramChannel outgoing) throws IOException { - buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); + // TODO remove buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); Scmp.Type type0 = ScmpParser.extractType(buffer); // ignore SCMP responses if (type0 == Scmp.Type.INFO_129 || type0 == Scmp.Type.INFO_131) { diff --git a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java index d2f36eb9..64c47130 100644 --- a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java +++ b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java @@ -146,7 +146,6 @@ public void run() { private void handleScmp(ByteBuffer buffer, SocketAddress srcAddress, DatagramChannel incoming) throws IOException { - buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); Scmp.Type type0 = ScmpParser.extractType(buffer); // ignore SCMP responses if (type0 == Scmp.Type.INFO_129 || type0 == Scmp.Type.INFO_131) { @@ -157,10 +156,12 @@ private void handleScmp(ByteBuffer buffer, SocketAddress srcAddress, DatagramCha buffer.rewind(); InetSocketAddress dstAddress = PackageVisibilityHelper.getDstAddress(buffer); // From here on we use linear reading using the buffer's position() mechanism - buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); + // TODO remove buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); Path path = PackageVisibilityHelper.getResponsePath(buffer, (InetSocketAddress) srcAddress); Scmp.Type type = ScmpParser.extractType(buffer); Scmp.Message scmpMsg = PackageVisibilityHelper.createMessage(type, path); + // TODO incorporate into consume? + buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); ScmpParser.consume(buffer, scmpMsg); logger.info( " received SCMP {} {}", scmpMsg.getTypeCode().name(), scmpMsg.getTypeCode().getText()); From e76e6c210d1badfea4597b13079dd1200f1ae358 Mon Sep 17 00:00:00 2001 From: Tilmann Date: Wed, 25 Sep 2024 17:50:23 +0200 Subject: [PATCH 03/18] Everything is broken...??? --- .../java/org/scion/jpan/ScmpSenderAsync.java | 49 +++----- .../scion/jpan/api/ScmpSenderAsyncTest.java | 115 ++++++------------ .../scion/jpan/testutil/MockScmpHandler.java | 11 +- 3 files changed, 67 insertions(+), 108 deletions(-) diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index fd2b41f3..bd486417 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -41,8 +41,6 @@ public class ScmpSenderAsync implements AutoCloseable { private final CountDownLatch receiverBarrier = new CountDownLatch(1); private final ResponseHandler handler; - public static boolean CHECK = false; - public static Builder newBuilder(ResponseHandler handler) { return new Builder(handler); } @@ -185,6 +183,10 @@ public void close() throws IOException { stopReceiver(); } + public T getOption(SocketOption option) throws IOException { + return channel.getOption(option); + } + /** * This is currently only useful for {@link ScionSocketOptions#SCION_API_THROW_PARSER_FAILURE}. * @@ -307,39 +309,26 @@ private void readIncomingScmp(SelectionKey key) throws IOException { ByteBuffer buffer = super.getBufferReceive(DEFAULT_BUFFER_SIZE); buffer.clear(); InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); -// System.err.println("readIncoming(): " + buffer.position() + " " + srcAddress); // TODO - while (srcAddress == null) { - srcAddress = (InetSocketAddress) incoming.receive(buffer); - } -// System.err.println("readIncoming() 2: " + buffer.remaining() + " " + srcAddress); // TODO buffer.flip(); if (buffer.remaining() == 0) { + System.err.println("readIncoming() - remaining= " + buffer.position() + " " + srcAddress); // TODO return; // Wait for data } - boolean MULTI = buffer.remaining() > 85; - while (buffer.hasRemaining()) { - int pos1 = buffer.position(); - if (MULTI) System.err.println("readIncoming() 3: " + buffer.position() + " " + srcAddress); // TODO - if (validate(buffer)) { - InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); - ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); - int packetLength = ScionHeaderParser.extractPacketLength(buffer); - // From here on we use linear reading using the buffer's position() mechanism - buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); - // Check for extension headers. - // This should be mostly unnecessary, however we sometimes saw SCMP error headers - // wrapped in extensions headers. - hdrType = receiveExtensionHeader(buffer, hdrType); - - if (hdrType != InternalConstants.HdrTypes.SCMP) { - return; // drop - } - handleIncomingScmp(buffer, receivePath, packetLength); - int pos2 = buffer.position(); - if (CHECK && pos2 - pos1 > 85 ) { - throw new IllegalStateException(); - } + if (validate(buffer)) { + InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); + ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); + int packetLength = ScionHeaderParser.extractPacketLength(buffer); + // From here on we use linear reading using the buffer's position() mechanism + buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); + // Check for extension headers. + // This should be mostly unnecessary, however we sometimes saw SCMP error headers + // wrapped in extensions headers. + hdrType = receiveExtensionHeader(buffer, hdrType); + + if (hdrType != InternalConstants.HdrTypes.SCMP) { + return; // drop } + handleIncomingScmp(buffer, receivePath, packetLength); } } catch (ScionException e) { // Validation problem -> ignore diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 45846432..f3446a93 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; import org.junit.jupiter.api.AfterAll; @@ -153,9 +154,9 @@ private void testEcho(Supplier pathSupplier, int n) throws IOException { byte[] data = new byte[] {1, 2, 3, 4, 5}; Path path = pathSupplier.get(); int seqId = channel.sendEcho(path, ByteBuffer.wrap(data)); + assertEquals(i, seqId); Scmp.EchoMessage result = handler.get(); - System.err.println("seqId: " + seqId + " " + result.getSequenceNumber()); - // assertEquals(seqId, result.getSequenceNumber()); + assertEquals(seqId, result.getSequenceNumber(), "i=" + i); assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); assertTrue(result.getNanoSeconds() > 0); assertTrue(result.getNanoSeconds() < 100_000_000); // 10 ms @@ -178,7 +179,7 @@ void sendEcho_async() throws IOException { @Test void sendEcho_localAS_BR_async() throws IOException { - int n = 20; + int n = 25; testEchoAsync(this::getPathToLocalAS_BR, n); assertEquals(n, MockNetwork.getAndResetForwardCount()); // 1! assertEquals(n, MockScmpHandler.getAndResetAnswerTotal()); @@ -186,7 +187,7 @@ void sendEcho_localAS_BR_async() throws IOException { @Test void sendEcho_localAS_BR_30041_async() throws IOException { - int n = 20; + int n = 25; testEchoAsync(this::getPathToLocalAS_BR_30041, n); assertEquals(0, MockNetwork.getAndResetForwardCount()); // 0! assertEquals(n, MockScmpHandler.getAndResetAnswerTotal()); @@ -197,8 +198,7 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio MockNetwork.answerNextScmpEchos(n); EchoHandler handler = new EchoHandler(); try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { - channel.setTimeOut(10000); - ScmpSenderAsync.CHECK = true; + channel.setTimeOut(10000); // TODO channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); byte[] data = new byte[] {1, 2, 3, 4, 5}; Path path = pathSupplier.get(); @@ -210,6 +210,8 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio System.err.println("************************************************* Start get()"); // TODO List results = handler.get(n); + long nTimedOut = results.stream().filter(Scmp.TimedMessage::isTimedOut).count(); + assertEquals(0, nTimedOut); for (int i = 0; i < n; i++) { Scmp.EchoMessage result = results.get(i); System.err.println("************************************************* seqId: " + result.getSequenceNumber()); // TODO @@ -217,7 +219,7 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio seqIDs.remove(result.getSequenceNumber()); assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); assertTrue(result.getNanoSeconds() > 0); - assertTrue(result.getNanoSeconds() < 990_000_000); // 10 ms + assertTrue(result.getNanoSeconds() < 500_000_000); // 10 ms assertArrayEquals(data, result.getData()); assertFalse(result.isTimedOut()); Path returnPath = result.getPath(); @@ -226,7 +228,6 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); } } finally { - ScmpSenderAsync.CHECK = false; MockNetwork.stopTiny(); } } @@ -254,7 +255,7 @@ void sendEcho_timeout() throws IOException { assertEquals(Scmp.TypeCode.TYPE_129, result2.getTypeCode()); assertFalse(result2.isTimedOut()); assertTrue(result2.getNanoSeconds() > 0); - assertTrue(result2.getNanoSeconds() < 10_000_000); // 10 ms + assertTrue(result2.getNanoSeconds() < 50_000_000); // 10 ms assertEquals(seqId2, result2.getSequenceNumber()); } finally { MockNetwork.stopTiny(); @@ -585,20 +586,9 @@ private abstract static class ScmpHandler implements ScmpSenderAsync.Response final AtomicInteger exceptionCounter = new AtomicInteger(); volatile Scmp.ErrorMessage error = null; volatile Throwable exception = null; + final List responses = new CopyOnWriteArrayList<>(); - synchronized void handleError(Scmp.ErrorMessage msg) { - error = msg; - errorCounter.incrementAndGet(); - this.notifyAll(); - } - - synchronized void handleException(Throwable t) { - exception = t; - exceptionCounter.incrementAndGet(); - this.notifyAll(); - } - - protected T waitForResult(Supplier checkResult) throws IOException { + protected List waitForResult(int count) throws IOException { try { while (true) { synchronized (this) { @@ -608,8 +598,9 @@ protected T waitForResult(Supplier checkResult) throws IOException { if (exception != null) { throw new IOException(exception); } - T result = checkResult.get(); - if (result != null) { + if (responses.size() >= count) { + ArrayList result = new ArrayList<>(responses); + responses.clear(); return result; } this.wait(); @@ -624,84 +615,54 @@ protected T waitForResult(Supplier checkResult) throws IOException { protected synchronized void reset() { error = null; exception = null; + responses.clear(); } @Override - public void onError(Scmp.ErrorMessage msg) { - handleError(msg); - } - - @Override - public void onException(Throwable t) { - handleException(t); - } - } - - private static class EchoHandler extends ScmpHandler> { - private ArrayList responses = new ArrayList<>(); - - synchronized void handle(Scmp.EchoMessage msg) { - responses.add(msg); - System.err.println("seqId: " + msg.getSequenceNumber()); // TODO + @SuppressWarnings("unchecked") + public final synchronized void onResponse(Scmp.TimedMessage msg) { + responses.add((T) msg); this.notifyAll(); } - Scmp.EchoMessage get() throws IOException { - return get(1).get(0); - } - - List get(int count) throws IOException { - return super.waitForResult(() -> responses.size() >= count ? responses : null); - } - @Override - public synchronized void reset() { - super.reset(); - responses = new ArrayList<>(); + public final synchronized void onTimeout(Scmp.TimedMessage msg) { + onResponse(msg); } @Override - public void onResponse(Scmp.TimedMessage msg) { - handle((Scmp.EchoMessage) msg); + public final synchronized void onError(Scmp.ErrorMessage msg) { + error = msg; + errorCounter.incrementAndGet(); + this.notifyAll(); } @Override - public void onTimeout(Scmp.TimedMessage msg) { - handle((Scmp.EchoMessage) msg); + public final synchronized void onException(Throwable t) { + exception = t; + exceptionCounter.incrementAndGet(); + this.notifyAll(); } } - private static class TraceHandler extends ScmpHandler> { - private ArrayList responses = new ArrayList<>(); + private static class EchoHandler extends ScmpHandler { + Scmp.EchoMessage get() throws IOException { + return super.waitForResult(1).get(0); + } - synchronized void handle(Scmp.TracerouteMessage msg) { - responses.add(msg); - this.notifyAll(); + List get(int count) throws IOException { + return super.waitForResult(count); } + } + private static class TraceHandler extends ScmpHandler { /** * @param count Number of SCMP response that should be registered before get() returns. * @return 'Count' or more messages. * @throws IOException in case of a problem */ List get(int count) throws IOException { - return super.waitForResult(() -> responses.size() >= count ? responses : null); - } - - @Override - public synchronized void reset() { - super.reset(); - responses = new ArrayList<>(); - } - - @Override - public void onResponse(Scmp.TimedMessage msg) { - handle((Scmp.TracerouteMessage) msg); - } - - @Override - public void onTimeout(Scmp.TimedMessage msg) { - handle((Scmp.TracerouteMessage) msg); + return super.waitForResult(count); } } } diff --git a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java index 64c47130..ea300274 100644 --- a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java +++ b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java @@ -197,7 +197,16 @@ private void sendEchoReply(ByteBuffer buffer, SocketAddress srcAddress, Datagram ByteBuffer out = ByteBuffer.allocate(100); spi.writePacketSCMP(out); out.flip(); - channel.send(out, srcAddress); +// try { +// // This is required for the ScmpSenderAsync test ... +// Thread.sleep(2); +// } catch (InterruptedException e) { +// throw new RuntimeException(e); +// } + int sent = channel.send(out, srcAddress); +// if (sent != out.limit()) { +// throw new IllegalStateException(); +// } buffer.clear(); } From 2e50c29cc64edc0670b8cc2646694141b64c6496 Mon Sep 17 00:00:00 2001 From: Tilmann Date: Thu, 26 Sep 2024 12:56:07 +0200 Subject: [PATCH 04/18] Everything is broken...??? --- .../java/org/scion/jpan/ScmpSenderAsync.java | 147 ++++++++++++++---- .../scion/jpan/api/ScmpSenderAsyncTest.java | 6 +- .../scion/jpan/testutil/MockScmpHandler.java | 18 +-- 3 files changed, 126 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index bd486417..9cfbcbfa 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -22,10 +22,14 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.*; +import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + import org.scion.jpan.internal.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,9 +41,16 @@ public class ScmpSenderAsync implements AutoCloseable { private final AtomicInteger sequenceIDs = new AtomicInteger(0); private final ConcurrentHashMap timers = new ConcurrentHashMap<>(); private final Timer timer = new Timer(true); + // The receiver thread is tasked with handling incoming packets as fast as possible. To do so, it hands of any + // received packets immediately to the receiverProcessor. This construct is necessary because while the receiver is + // handling packets (while it is _not_ waiting on select()), incoming packets are likely to be dropped. private Thread receiver; - private final CountDownLatch receiverBarrier = new CountDownLatch(1); + private Thread receiverProcessor; private final ResponseHandler handler; + // Pool of buffers, shared between receiver and receiverProcessor + private final ConcurrentLinkedQueue bufferPool = new ConcurrentLinkedQueue<>(); + // Queue of buffer for moving buffers between receiver and receiverProcessor + private final ArrayBlockingQueue processingQueue = new ArrayBlockingQueue<>(50); public static Builder newBuilder(ResponseHandler handler) { return new Builder(handler); @@ -64,28 +75,31 @@ private ScmpSenderAsync( throws IOException { this.channel = new InternalChannel(service, port, channel, selector); this.handler = handler; - startReceiver(); + this.receiverProcessor = startHandler(this::receiveProcessorTask, "ScmpSender-receiverProcessor"); + this.receiver = startHandler(this::receiveTask, "ScmpSender-receiver"); } - private void startReceiver() { - this.receiver = new Thread(this::handleReceive, "ScmpSender-receiver"); - this.receiver.setDaemon(true); - this.receiver.start(); + private Thread startHandler(Consumer task, String name) { + CountDownLatch barrier = new CountDownLatch(1); + Thread thread = new Thread(() -> task.accept(barrier), name); + thread.setDaemon(true); + thread.start(); try { - if (!this.receiverBarrier.await(1, TimeUnit.SECONDS)) { - throw new IllegalStateException("Could not start receiver thread."); + if (!barrier.await(1, TimeUnit.SECONDS)) { + throw new IllegalStateException("Could not start receiver thread: " + name); } + return thread; } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new ScionRuntimeException(e); } } - private void stopReceiver() { - if (receiver != null) { - this.receiver.interrupt(); + private void stopHandler(Thread thread) { + if (thread != null) { + thread.interrupt(); try { - this.receiver.join(100); + thread.join(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } @@ -178,9 +192,10 @@ public int getTimeOut() { @Override public void close() throws IOException { - channel.close(); timer.cancel(); - stopReceiver(); + stopHandler(receiver); + stopHandler(receiverProcessor); + channel.close(); } public T getOption(SocketOption option) throws IOException { @@ -289,31 +304,92 @@ private void sendRequest(Scmp.TimedMessage request, ByteBuffer buffer, Path path sendRaw(buffer, path); } - private void receiveAsync() throws IOException { + // private void receiveAsync() throws IOException { + // while (selector.isOpen() && selector.select() > 0) { + // Iterator iter = selector.selectedKeys().iterator(); + // if (iter.hasNext()) { + // SelectionKey key = iter.next(); + // iter.remove(); + // if (key.isValid() && key.isReadable()) { + // readIncomingScmp(key); + // } + // } + // } + // } + // + // private void readIncomingScmp(SelectionKey key) throws IOException { + // readLock().lock(); + // try { + // DatagramChannel incoming = (DatagramChannel) key.channel(); + // ByteBuffer buffer = super.getBufferReceive(DEFAULT_BUFFER_SIZE); + // buffer.clear(); + // InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); + // buffer.flip(); + // if (buffer.remaining() == 0) { + // return; // Wait for data + // } + // if (validate(buffer)) { + // InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); + // ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); + // int packetLength = ScionHeaderParser.extractPacketLength(buffer); + // // From here on we use linear reading using the buffer's position() mechanism + // buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); + // // Check for extension headers. + // // This should be mostly unnecessary, however we sometimes saw SCMP error headers + // // wrapped in extensions headers. + // hdrType = receiveExtensionHeader(buffer, hdrType); + // + // if (hdrType != InternalConstants.HdrTypes.SCMP) { + // return; // drop + // } + // handleIncomingScmp(buffer, receivePath, packetLength); + // } + // } catch (ScionException e) { + // // Validation problem -> ignore + // handler.onException(e); + // } finally { + // readLock().unlock(); + // } + // } + + private void receiveAsync2() throws IOException { while (selector.isOpen() && selector.select() > 0) { Iterator iter = selector.selectedKeys().iterator(); if (iter.hasNext()) { SelectionKey key = iter.next(); iter.remove(); if (key.isValid() && key.isReadable()) { - readIncomingScmp(key); + ByteBuffer buffer = bufferPool.poll(); + if (buffer == null) { + buffer = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE); + } + buffer.clear(); + DatagramChannel incoming = (DatagramChannel) key.channel(); + InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); + if (srcAddress != null && buffer.position() > 0) { + if (!processingQueue.offer(buffer)) { + log.warn("SCMP process buffer overflow"); + } + } else { + bufferPool.offer(buffer); + } } } } } - private void readIncomingScmp(SelectionKey key) throws IOException { - readLock().lock(); + private void processAsync() throws IOException, InterruptedException { + while (!Thread.currentThread().isInterrupted()) { + ByteBuffer buffer = processingQueue.take(); + readIncomingScmp2(buffer); + bufferPool.offer(buffer); + } + } + + private void readIncomingScmp2(ByteBuffer buffer) throws IOException { try { - DatagramChannel incoming = (DatagramChannel) key.channel(); - ByteBuffer buffer = super.getBufferReceive(DEFAULT_BUFFER_SIZE); - buffer.clear(); - InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); + InetSocketAddress srcAddress = null; buffer.flip(); - if (buffer.remaining() == 0) { - System.err.println("readIncoming() - remaining= " + buffer.position() + " " + srcAddress); // TODO - return; // Wait for data - } if (validate(buffer)) { InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); @@ -333,8 +409,6 @@ private void readIncomingScmp(SelectionKey key) throws IOException { } catch (ScionException e) { // Validation problem -> ignore handler.onException(e); - } finally { - readLock().unlock(); } } @@ -388,15 +462,26 @@ public void setOverrideSourceAddress(InetSocketAddress overrideSourceAddress) { channel.setOverrideSourceAddress(overrideSourceAddress); } - private void handleReceive() { + private void receiveTask(CountDownLatch barrier) { try { - receiverBarrier.countDown(); - channel.receiveAsync(); + barrier.countDown(); + channel.receiveAsync2(); } catch (IOException e) { handler.onException(e); } } + private void receiveProcessorTask(CountDownLatch barrier) { + try { + barrier.countDown(); + channel.processAsync(); + } catch (IOException e) { + handler.onException(e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + private class TimeOutTask extends TimerTask { private final Scmp.TimedMessage request; diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index f3446a93..692f0682 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -174,7 +174,7 @@ private void testEcho(Supplier pathSupplier, int n) throws IOException { @Test void sendEcho_async() throws IOException { - testEchoAsync(this::getPathTo112, 20); + testEchoAsync(this::getPathTo112, 25); } @Test @@ -198,23 +198,19 @@ private void testEchoAsync(Supplier pathSupplier, int n) throws IOExceptio MockNetwork.answerNextScmpEchos(n); EchoHandler handler = new EchoHandler(); try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { - channel.setTimeOut(10000); // TODO channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); byte[] data = new byte[] {1, 2, 3, 4, 5}; Path path = pathSupplier.get(); HashSet seqIDs = new HashSet<>(); - System.err.println("************************************************* Start send()"); // TODO for (int i = 0; i < n; i++) { seqIDs.add(channel.sendEcho(path, ByteBuffer.wrap(data))); } - System.err.println("************************************************* Start get()"); // TODO List results = handler.get(n); long nTimedOut = results.stream().filter(Scmp.TimedMessage::isTimedOut).count(); assertEquals(0, nTimedOut); for (int i = 0; i < n; i++) { Scmp.EchoMessage result = results.get(i); - System.err.println("************************************************* seqId: " + result.getSequenceNumber()); // TODO assertTrue(seqIDs.contains(result.getSequenceNumber())); seqIDs.remove(result.getSequenceNumber()); assertEquals(Scmp.TypeCode.TYPE_129, result.getTypeCode(), "T/O=" + result.isTimedOut()); diff --git a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java index ea300274..a9c076cc 100644 --- a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java +++ b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java @@ -197,16 +197,16 @@ private void sendEchoReply(ByteBuffer buffer, SocketAddress srcAddress, Datagram ByteBuffer out = ByteBuffer.allocate(100); spi.writePacketSCMP(out); out.flip(); -// try { -// // This is required for the ScmpSenderAsync test ... -// Thread.sleep(2); -// } catch (InterruptedException e) { -// throw new RuntimeException(e); -// } + try { + // This is required for the ScmpSenderAsync test ... + Thread.sleep(2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } int sent = channel.send(out, srcAddress); -// if (sent != out.limit()) { -// throw new IllegalStateException(); -// } + if (sent != out.limit()) { + throw new IllegalStateException(); + } buffer.clear(); } From d365f87744f38027fa7041c8b353ea1d8f24e7fd Mon Sep 17 00:00:00 2001 From: Tilmann Date: Thu, 26 Sep 2024 13:08:49 +0200 Subject: [PATCH 05/18] Everything is broken...??? --- .../scion/jpan/internal/ScionHeaderParser.java | 18 +++++++++--------- .../org/scion/jpan/internal/ScmpParser.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java b/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java index c7bde27b..3cee5b56 100644 --- a/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java +++ b/src/main/java/org/scion/jpan/internal/ScionHeaderParser.java @@ -73,8 +73,8 @@ public static ResponsePath extractResponsePath( ByteBuffer data, InetSocketAddress firstHopAddress) { int pos = data.position(); - int i1 = data.getInt(pos + 4); - int i2 = data.getInt(pos + 8); + int i1 = data.getInt(4); + int i2 = data.getInt(8); int nextHeader = ByteUtil.readInt(i1, 0, 8); InternalConstants.HdrTypes hdrType = InternalConstants.HdrTypes.parse(nextHeader); int hdrLen = ByteUtil.readInt(i1, 8, 8); @@ -90,11 +90,11 @@ public static ResponsePath extractResponsePath( // ? bit: DstHostAddr // ? bit: SrcHostAddr - long dstIsdAs = data.getLong(pos + 12); - long srcIsdAs = data.getLong(pos + 20); + long dstIsdAs = data.getLong(12); + long srcIsdAs = data.getLong(20); // dstAddress - data.position(pos + 28); + data.position(28); byte[] bytesDst = new byte[(dl + 1) * 4]; data.get(bytesDst); @@ -113,7 +113,7 @@ public static ResponsePath extractResponsePath( } // raw path - byte[] path = new byte[hdrLenBytes - data.position() - pos]; + byte[] path = new byte[hdrLenBytes - data.position()]; if (path.length > 0) { // raw path may be empty for local AS data.get(path); @@ -121,7 +121,7 @@ public static ResponsePath extractResponsePath( } // get remote port from UDP or SCMP payload - data.position(pos + hdrLenBytes); + data.position(hdrLenBytes); int srcPort; int dstPort; if (hdrType == InternalConstants.HdrTypes.UDP) { @@ -129,7 +129,7 @@ public static ResponsePath extractResponsePath( srcPort = Short.toUnsignedInt(data.getShort()); dstPort = Short.toUnsignedInt(data.getShort()); } else if (hdrType == InternalConstants.HdrTypes.SCMP) { - data.position(pos + hdrLenBytes + 4); + data.position(hdrLenBytes + 4); // ports will be swapped further down dstPort = Short.toUnsignedInt(data.getShort()); srcPort = Constants.SCMP_PORT; @@ -227,7 +227,7 @@ private static int extractDstPort( * @return the length of the SCION common + address + path header in bytes */ public static int extractHeaderLength(ByteBuffer data) { - int hdrLen = ByteUtil.toUnsigned(data.get(data.position() + 5)); + int hdrLen = ByteUtil.toUnsigned(data.get(5)); return hdrLen * 4; } diff --git a/src/main/java/org/scion/jpan/internal/ScmpParser.java b/src/main/java/org/scion/jpan/internal/ScmpParser.java index b9a19df5..3647477c 100644 --- a/src/main/java/org/scion/jpan/internal/ScmpParser.java +++ b/src/main/java/org/scion/jpan/internal/ScmpParser.java @@ -65,7 +65,7 @@ public static void buildScmpTraceroute( public static Scmp.Type extractType(ByteBuffer data) { // Avoid changing the position! int headerLength = ScionHeaderParser.extractHeaderLength(data); - return Scmp.Type.parse(ByteUtil.toUnsigned(data.get(data.position() + headerLength))); + return Scmp.Type.parse(ByteUtil.toUnsigned(data.get(headerLength))); } /** From 59c0428ff6ec2f83d4b3cd8eca20ae7bddc8afef Mon Sep 17 00:00:00 2001 From: Tilmann Date: Fri, 27 Sep 2024 14:41:23 +0200 Subject: [PATCH 06/18] MockSelector mostly works! --- .../java/org/scion/jpan/ScmpSenderAsync.java | 110 ++---------------- .../org/scion/jpan/api/ScmpSenderTest.java | 8 +- .../jpan/testutil/MockDatagramChannel.java | 12 +- .../scion/jpan/testutil/MockScmpHandler.java | 11 +- 4 files changed, 21 insertions(+), 120 deletions(-) diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index 9cfbcbfa..b8408cb2 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -22,9 +22,7 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.*; -import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -41,16 +39,8 @@ public class ScmpSenderAsync implements AutoCloseable { private final AtomicInteger sequenceIDs = new AtomicInteger(0); private final ConcurrentHashMap timers = new ConcurrentHashMap<>(); private final Timer timer = new Timer(true); - // The receiver thread is tasked with handling incoming packets as fast as possible. To do so, it hands of any - // received packets immediately to the receiverProcessor. This construct is necessary because while the receiver is - // handling packets (while it is _not_ waiting on select()), incoming packets are likely to be dropped. private Thread receiver; - private Thread receiverProcessor; private final ResponseHandler handler; - // Pool of buffers, shared between receiver and receiverProcessor - private final ConcurrentLinkedQueue bufferPool = new ConcurrentLinkedQueue<>(); - // Queue of buffer for moving buffers between receiver and receiverProcessor - private final ArrayBlockingQueue processingQueue = new ArrayBlockingQueue<>(50); public static Builder newBuilder(ResponseHandler handler) { return new Builder(handler); @@ -75,7 +65,6 @@ private ScmpSenderAsync( throws IOException { this.channel = new InternalChannel(service, port, channel, selector); this.handler = handler; - this.receiverProcessor = startHandler(this::receiveProcessorTask, "ScmpSender-receiverProcessor"); this.receiver = startHandler(this::receiveTask, "ScmpSender-receiver"); } @@ -194,7 +183,6 @@ public int getTimeOut() { public void close() throws IOException { timer.cancel(); stopHandler(receiver); - stopHandler(receiverProcessor); channel.close(); } @@ -246,7 +234,7 @@ void sendEchoRequest(Scmp.EchoMessage request) throws IOException { writeLock().lock(); try { Path path = request.getPath(); - super.channel().connect(path.getFirstHopAddress()); + // super.channel().connect(path.getFirstHopAddress()); TODO ByteBuffer buffer = getBufferSend(DEFAULT_BUFFER_SIZE); // EchoHeader = 8 + data int len = 8 + request.getData().length; @@ -304,91 +292,26 @@ private void sendRequest(Scmp.TimedMessage request, ByteBuffer buffer, Path path sendRaw(buffer, path); } - // private void receiveAsync() throws IOException { - // while (selector.isOpen() && selector.select() > 0) { - // Iterator iter = selector.selectedKeys().iterator(); - // if (iter.hasNext()) { - // SelectionKey key = iter.next(); - // iter.remove(); - // if (key.isValid() && key.isReadable()) { - // readIncomingScmp(key); - // } - // } - // } - // } - // - // private void readIncomingScmp(SelectionKey key) throws IOException { - // readLock().lock(); - // try { - // DatagramChannel incoming = (DatagramChannel) key.channel(); - // ByteBuffer buffer = super.getBufferReceive(DEFAULT_BUFFER_SIZE); - // buffer.clear(); - // InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); - // buffer.flip(); - // if (buffer.remaining() == 0) { - // return; // Wait for data - // } - // if (validate(buffer)) { - // InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); - // ResponsePath receivePath = ScionHeaderParser.extractResponsePath(buffer, srcAddress); - // int packetLength = ScionHeaderParser.extractPacketLength(buffer); - // // From here on we use linear reading using the buffer's position() mechanism - // buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); - // // Check for extension headers. - // // This should be mostly unnecessary, however we sometimes saw SCMP error headers - // // wrapped in extensions headers. - // hdrType = receiveExtensionHeader(buffer, hdrType); - // - // if (hdrType != InternalConstants.HdrTypes.SCMP) { - // return; // drop - // } - // handleIncomingScmp(buffer, receivePath, packetLength); - // } - // } catch (ScionException e) { - // // Validation problem -> ignore - // handler.onException(e); - // } finally { - // readLock().unlock(); - // } - // } - - private void receiveAsync2() throws IOException { + private void receiveAsync() throws IOException { while (selector.isOpen() && selector.select() > 0) { Iterator iter = selector.selectedKeys().iterator(); if (iter.hasNext()) { SelectionKey key = iter.next(); iter.remove(); if (key.isValid() && key.isReadable()) { - ByteBuffer buffer = bufferPool.poll(); - if (buffer == null) { - buffer = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE); - } - buffer.clear(); - DatagramChannel incoming = (DatagramChannel) key.channel(); - InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); - if (srcAddress != null && buffer.position() > 0) { - if (!processingQueue.offer(buffer)) { - log.warn("SCMP process buffer overflow"); - } - } else { - bufferPool.offer(buffer); - } + readIncomingScmp(key); } } } } - private void processAsync() throws IOException, InterruptedException { - while (!Thread.currentThread().isInterrupted()) { - ByteBuffer buffer = processingQueue.take(); - readIncomingScmp2(buffer); - bufferPool.offer(buffer); - } - } - - private void readIncomingScmp2(ByteBuffer buffer) throws IOException { + private void readIncomingScmp(SelectionKey key) throws IOException { + readLock().lock(); try { - InetSocketAddress srcAddress = null; + DatagramChannel incoming = (DatagramChannel) key.channel(); + ByteBuffer buffer = super.getBufferReceive(DEFAULT_BUFFER_SIZE); + buffer.clear(); + InetSocketAddress srcAddress = (InetSocketAddress) incoming.receive(buffer); buffer.flip(); if (validate(buffer)) { InternalConstants.HdrTypes hdrType = ScionHeaderParser.extractNextHeader(buffer); @@ -409,6 +332,8 @@ private void readIncomingScmp2(ByteBuffer buffer) throws IOException { } catch (ScionException e) { // Validation problem -> ignore handler.onException(e); + } finally { + readLock().unlock(); } } @@ -465,20 +390,9 @@ public void setOverrideSourceAddress(InetSocketAddress overrideSourceAddress) { private void receiveTask(CountDownLatch barrier) { try { barrier.countDown(); - channel.receiveAsync2(); - } catch (IOException e) { - handler.onException(e); - } - } - - private void receiveProcessorTask(CountDownLatch barrier) { - try { - barrier.countDown(); - channel.processAsync(); + channel.receiveAsync(); } catch (IOException e) { handler.onException(e); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); } } diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderTest.java index 3d83ace8..44c2541c 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderTest.java @@ -304,13 +304,9 @@ private ScmpSender exceptionSender() throws IOException { (byteBuffer, socketAddress) -> { return 0; }); - errorChannel.setThrowOnConnect(true); - // This selector throws an Exception when activated. + errorChannel.setThrowOnSend(true); MockDatagramChannel.MockSelector selector = MockDatagramChannel.MockSelector.open(); - selector.setConnectCallback( - () -> { - throw new IOException(); - }); + errorChannel.setReceiveCallback(byteBuffer -> null); return Scmp.newSenderBuilder().setDatagramChannel(errorChannel).setSelector(selector).build(); } diff --git a/src/test/java/org/scion/jpan/testutil/MockDatagramChannel.java b/src/test/java/org/scion/jpan/testutil/MockDatagramChannel.java index 7748dda2..5c0b0955 100644 --- a/src/test/java/org/scion/jpan/testutil/MockDatagramChannel.java +++ b/src/test/java/org/scion/jpan/testutil/MockDatagramChannel.java @@ -56,7 +56,7 @@ public class MockDatagramChannel extends java.nio.channels.DatagramChannel { private SocketAddress bindAddress; private SocketAddress connectAddress; - private boolean throwOnConnect = false; + private boolean throwOnSend = false; private Function receiveCallback = byteBuffer -> { @@ -84,8 +84,8 @@ public void setSendCallback(BiFunction cb) { sendCallback = cb; } - public void setThrowOnConnect(boolean flag) { - this.throwOnConnect = flag; + public void setThrowOnSend(boolean flag) { + this.throwOnSend = flag; } @Override @@ -135,9 +135,6 @@ public boolean isConnected() { @Override public java.nio.channels.DatagramChannel connect(SocketAddress socketAddress) throws IOException { - if (throwOnConnect) { - throw new IOException(); - } connectAddress = socketAddress; isConnected = true; if (bindAddress == null) { @@ -168,6 +165,9 @@ public SocketAddress receive(ByteBuffer byteBuffer) throws IOException { @Override public int send(ByteBuffer byteBuffer, SocketAddress socketAddress) throws IOException { + if (throwOnSend) { + throw new IOException(); + } if (bindAddress == null) { bindAddress = BIND_ANY_SOCKET; } diff --git a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java index a9c076cc..64c47130 100644 --- a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java +++ b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java @@ -197,16 +197,7 @@ private void sendEchoReply(ByteBuffer buffer, SocketAddress srcAddress, Datagram ByteBuffer out = ByteBuffer.allocate(100); spi.writePacketSCMP(out); out.flip(); - try { - // This is required for the ScmpSenderAsync test ... - Thread.sleep(2); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - int sent = channel.send(out, srcAddress); - if (sent != out.limit()) { - throw new IllegalStateException(); - } + channel.send(out, srcAddress); buffer.clear(); } From 3ae22e16ce97f54a5ae5d2aece69558ccd81fd63 Mon Sep 17 00:00:00 2001 From: Tilmann Date: Fri, 27 Sep 2024 14:44:52 +0200 Subject: [PATCH 07/18] MockSelector mostly works! --- pom.xml | 2 +- src/main/java/org/scion/jpan/ScmpSenderAsync.java | 1 - src/main/java/org/scion/jpan/internal/GlobalTopology.java | 1 + src/test/java/org/scion/jpan/demo/inspector/HopField.java | 4 ++++ src/test/java/org/scion/jpan/testutil/MockNetwork.java | 1 - 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 05388357..8043ed40 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 6.4.0 3.3.0 - 2.20 + 2.23 3.2.0 3.11.0 3.1.1 diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index b8408cb2..b4f595d7 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -27,7 +27,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; - import org.scion.jpan.internal.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/scion/jpan/internal/GlobalTopology.java b/src/main/java/org/scion/jpan/internal/GlobalTopology.java index 5a3ea5ed..5f9b8f66 100644 --- a/src/main/java/org/scion/jpan/internal/GlobalTopology.java +++ b/src/main/java/org/scion/jpan/internal/GlobalTopology.java @@ -27,6 +27,7 @@ public class GlobalTopology { private final Map world = new HashMap<>(); + /** * The topology is "empty" if it wasn't initialized with TRC file (or TRC metadata). THis can * happen when it is initialized from a local topology file without bootstrap server. diff --git a/src/test/java/org/scion/jpan/demo/inspector/HopField.java b/src/test/java/org/scion/jpan/demo/inspector/HopField.java index 7360cbf2..2c4f690b 100644 --- a/src/test/java/org/scion/jpan/demo/inspector/HopField.java +++ b/src/test/java/org/scion/jpan/demo/inspector/HopField.java @@ -26,22 +26,26 @@ public class HopField { private boolean r3; private boolean r4; private boolean r5; + /** * 1 bit : ConsIngress Router Alert. If the ConsIngress Router Alert is set, the ingress router * (in construction direction) will process the L4 payload in the packet. */ private boolean flagI; + /** * 1 bit : ConsEgress Router Alert. If the ConsEgress Router Alert is set, the egress router (in * construction direction) will process the L4 payload in the packet. */ private boolean flagE; + /** * 8 bits : Expiry time of a hop field. The expiration time expressed is relative. An absolute * expiration time in seconds is computed in combination with the timestamp field (from the * corresponding info field) as follows: abs_time = timestamp + (1+expiryTime)*24*60*60/256 */ private int expiryTime; + // 16 bits : consIngress : The 16-bits ingress interface IDs in construction direction. private int consIngress; // 16 bits : consEgress : The 16-bits egress interface IDs in construction direction. diff --git a/src/test/java/org/scion/jpan/testutil/MockNetwork.java b/src/test/java/org/scion/jpan/testutil/MockNetwork.java index 8b62469c..0a69b301 100644 --- a/src/test/java/org/scion/jpan/testutil/MockNetwork.java +++ b/src/test/java/org/scion/jpan/testutil/MockNetwork.java @@ -37,7 +37,6 @@ import org.scion.jpan.*; import org.scion.jpan.demo.inspector.ScionPacketInspector; import org.scion.jpan.demo.inspector.ScmpHeader; -import org.scion.jpan.internal.ScionHeaderParser; import org.scion.jpan.internal.ScmpParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 112dbc56c0ea375e42194f589b7c53f20d3ae48f Mon Sep 17 00:00:00 2001 From: Tilmann Date: Fri, 27 Sep 2024 15:39:51 +0200 Subject: [PATCH 08/18] MockSelector mostly works! --- CHANGELOG.md | 1 + .../scion/jpan/api/ScmpSenderAsyncTest.java | 78 ++++++++++++++++++- .../scion/jpan/demo/ScmpTracerouteDemo.java | 3 +- .../org/scion/jpan/testutil/MockNetwork.java | 1 - .../scion/jpan/testutil/MockScmpHandler.java | 2 - 5 files changed, 79 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1613d945..373b3ec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - SocketConcurrency test takes too long. [#108](https://github.com/scionproto-contrib/jpan/issues/108) - Fixed useless error message when providing incorrect daemon address. Also: made port optional (default = 30255) [#114](https://github.com/scionproto-contrib/jpan/pull/114) +- Fixed SCMP packet loss obn receive() [#120](https://github.com/scionproto-contrib/jpan/pull/120) ### Removed - Removed some useless IP printing functions. diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 692f0682..32cadce0 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -251,7 +251,7 @@ void sendEcho_timeout() throws IOException { assertEquals(Scmp.TypeCode.TYPE_129, result2.getTypeCode()); assertFalse(result2.isTimedOut()); assertTrue(result2.getNanoSeconds() > 0); - assertTrue(result2.getNanoSeconds() < 50_000_000); // 10 ms + assertTrue(result2.getNanoSeconds() < 10_000_000); // 10 ms assertEquals(seqId2, result2.getSequenceNumber()); } finally { MockNetwork.stopTiny(); @@ -329,6 +329,44 @@ private void testTraceroute(Supplier path, int nHops) throws IOException { } } + @Test + void sendTraceroute_async() throws IOException { + testTracerouteAsync(this::getPathTo112, 2, 25); + } + + private void testTracerouteAsync(Supplier pathSupplier, int nHops, int nRepeat) throws IOException { + MockNetwork.startTiny(); + MockNetwork.answerNextScmpEchos(nRepeat); + TraceHandler handler = new TraceHandler(); + try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { + channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); + Path path = pathSupplier.get(); + HashSet seqIDs = new HashSet<>(); + for (int i = 0; i < nRepeat; i++) { + seqIDs.addAll(channel.sendTraceroute(path)); + } + + List results = handler.get(seqIDs.size()); + long nTimedOut = results.stream().filter(Scmp.TimedMessage::isTimedOut).count(); + assertEquals(0, nTimedOut); + for (int i = 0; i < nRepeat; i++) { + Scmp.TracerouteMessage result = results.get(i); + assertTrue(seqIDs.contains(result.getSequenceNumber())); + seqIDs.remove(result.getSequenceNumber()); + assertEquals(Scmp.TypeCode.TYPE_131, result.getTypeCode(), "T/O=" + result.isTimedOut()); + assertTrue(result.getNanoSeconds() > 0); + assertTrue(result.getNanoSeconds() < 500_000_000); // 10 ms + assertFalse(result.isTimedOut()); + Path returnPath = result.getPath(); + assertEquals(path.getRemoteAddress(), returnPath.getRemoteAddress()); + assertEquals(Constants.SCMP_PORT, returnPath.getRemotePort()); + assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); + } + } finally { + MockNetwork.stopTiny(); + } + } + @Test void sendTraceroute_timeout() throws IOException { MockNetwork.startTiny(); @@ -436,6 +474,44 @@ private void testTracerouteLast(Supplier pathSupplier, boolean success) th } } + @Test + void sendTracerouteLast_async() throws IOException { + testTracerouteLastAsync(this::getPathTo112, 2, 25); + } + + private void testTracerouteLastAsync(Supplier pathSupplier, int nHops, int nRepeat) throws IOException { + MockNetwork.startTiny(); + MockNetwork.answerNextScmpEchos(nRepeat); + TraceHandler handler = new TraceHandler(); + try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { + channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); + Path path = pathSupplier.get(); + HashSet seqIDs = new HashSet<>(); + for (int i = 0; i < nRepeat; i++) { + seqIDs.add(channel.sendTracerouteLast(path)); + } + + List results = handler.get(seqIDs.size()); + long nTimedOut = results.stream().filter(Scmp.TimedMessage::isTimedOut).count(); + assertEquals(0, nTimedOut); + for (int i = 0; i < nRepeat; i++) { + Scmp.TracerouteMessage result = results.get(i); + assertTrue(seqIDs.contains(result.getSequenceNumber())); + seqIDs.remove(result.getSequenceNumber()); + assertEquals(Scmp.TypeCode.TYPE_131, result.getTypeCode(), "T/O=" + result.isTimedOut()); + assertTrue(result.getNanoSeconds() > 0); + assertTrue(result.getNanoSeconds() < 500_000_000); // 10 ms + assertFalse(result.isTimedOut()); + Path returnPath = result.getPath(); + assertEquals(path.getRemoteAddress(), returnPath.getRemoteAddress()); + assertEquals(Constants.SCMP_PORT, returnPath.getRemotePort()); + assertEquals(path.getRemoteIsdAs(), returnPath.getRemoteIsdAs()); + } + } finally { + MockNetwork.stopTiny(); + } + } + @Test void sendTracerouteLast_timeout() throws IOException { MockNetwork.startTiny(); diff --git a/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java b/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java index 6a8e7197..1f60c619 100644 --- a/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java +++ b/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java @@ -87,8 +87,7 @@ public static void main(String[] args) throws IOException { // Local port must be 30041 for networks that expect a dispatcher ScmpTracerouteDemo demo = new ScmpTracerouteDemo(Constants.SCMP_PORT); - demo.runDemo(ScionUtil.parseIA("64-2:0:28")); // Cyberlink Cloud Test AS - // demo.runDemo(ScionUtil.parseIA("64-2:0:44")); // VEX + demo.runDemo(ScionUtil.parseIA("64-2:0:44")); // VEX // demo.runDemo(ScionUtil.parseIA("66-2:0:10")); //singapore // demo.runDemo(DemoConstants.iaAnapayaHK); // demo.runDemo(DemoConstants.iaOVGU); diff --git a/src/test/java/org/scion/jpan/testutil/MockNetwork.java b/src/test/java/org/scion/jpan/testutil/MockNetwork.java index 0a69b301..22bc4ad3 100644 --- a/src/test/java/org/scion/jpan/testutil/MockNetwork.java +++ b/src/test/java/org/scion/jpan/testutil/MockNetwork.java @@ -361,7 +361,6 @@ private void forwardPacket(ByteBuffer buffer, SocketAddress srcAddress, Datagram private void handleScmp(ByteBuffer buffer, SocketAddress srcAddress, DatagramChannel outgoing) throws IOException { - // TODO remove buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); Scmp.Type type0 = ScmpParser.extractType(buffer); // ignore SCMP responses if (type0 == Scmp.Type.INFO_129 || type0 == Scmp.Type.INFO_131) { diff --git a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java index 64c47130..56b3f7a8 100644 --- a/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java +++ b/src/test/java/org/scion/jpan/testutil/MockScmpHandler.java @@ -156,11 +156,9 @@ private void handleScmp(ByteBuffer buffer, SocketAddress srcAddress, DatagramCha buffer.rewind(); InetSocketAddress dstAddress = PackageVisibilityHelper.getDstAddress(buffer); // From here on we use linear reading using the buffer's position() mechanism - // TODO remove buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); Path path = PackageVisibilityHelper.getResponsePath(buffer, (InetSocketAddress) srcAddress); Scmp.Type type = ScmpParser.extractType(buffer); Scmp.Message scmpMsg = PackageVisibilityHelper.createMessage(type, path); - // TODO incorporate into consume? buffer.position(ScionHeaderParser.extractHeaderLength(buffer)); ScmpParser.consume(buffer, scmpMsg); logger.info( From 2fb85fb271335109e810dd3066cdc9c1f8bb9d53 Mon Sep 17 00:00:00 2001 From: Tilmann Date: Fri, 27 Sep 2024 15:45:25 +0200 Subject: [PATCH 09/18] MockSelector mostly works! --- src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 32cadce0..523f062e 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -334,7 +334,8 @@ void sendTraceroute_async() throws IOException { testTracerouteAsync(this::getPathTo112, 2, 25); } - private void testTracerouteAsync(Supplier pathSupplier, int nHops, int nRepeat) throws IOException { + private void testTracerouteAsync(Supplier pathSupplier, int nHops, int nRepeat) + throws IOException { MockNetwork.startTiny(); MockNetwork.answerNextScmpEchos(nRepeat); TraceHandler handler = new TraceHandler(); @@ -479,7 +480,8 @@ void sendTracerouteLast_async() throws IOException { testTracerouteLastAsync(this::getPathTo112, 2, 25); } - private void testTracerouteLastAsync(Supplier pathSupplier, int nHops, int nRepeat) throws IOException { + private void testTracerouteLastAsync(Supplier pathSupplier, int nHops, int nRepeat) + throws IOException { MockNetwork.startTiny(); MockNetwork.answerNextScmpEchos(nRepeat); TraceHandler handler = new TraceHandler(); From 1c234aba57f0e86f9c124f3c9344160e04aa601c Mon Sep 17 00:00:00 2001 From: Tilmann Date: Fri, 27 Sep 2024 16:07:58 +0200 Subject: [PATCH 10/18] MockSelector mostly works! --- src/main/java/org/scion/jpan/ScmpSenderAsync.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index b4f595d7..acf8d652 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -233,7 +233,6 @@ void sendEchoRequest(Scmp.EchoMessage request) throws IOException { writeLock().lock(); try { Path path = request.getPath(); - // super.channel().connect(path.getFirstHopAddress()); TODO ByteBuffer buffer = getBufferSend(DEFAULT_BUFFER_SIZE); // EchoHeader = 8 + data int len = 8 + request.getData().length; @@ -247,9 +246,6 @@ void sendEchoRequest(Scmp.EchoMessage request) throws IOException { sendRequest(request, buffer, path); } finally { writeLock().unlock(); - if (super.channel().isConnected()) { - super.channel().disconnect(); - } } } @@ -258,7 +254,6 @@ void sendTracerouteRequest(Scmp.TracerouteMessage request, PathHeaderParser.Node writeLock().lock(); try { Path path = request.getPath(); - super.channel().connect(path.getFirstHopAddress()); ByteBuffer buffer = getBufferSend(DEFAULT_BUFFER_SIZE); // TracerouteHeader = 24 int len = 24; @@ -275,9 +270,6 @@ void sendTracerouteRequest(Scmp.TracerouteMessage request, PathHeaderParser.Node sendRequest(request, buffer, path); } finally { writeLock().unlock(); - if (super.channel().isConnected()) { - super.channel().disconnect(); - } } } From 31850e5d2b4a32a3b630a3d148ab7a5a79d2a066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Mon, 30 Sep 2024 10:45:06 +0200 Subject: [PATCH 11/18] SCMP problems --- CHANGELOG.md | 2 +- .../scion/jpan/api/ScmpSenderAsyncTest.java | 29 ++++++++++++++----- .../demo/inspector/ScmpInspectorTest.java | 7 ++--- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 373b3ec0..d4f963ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,7 +63,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - SocketConcurrency test takes too long. [#108](https://github.com/scionproto-contrib/jpan/issues/108) - Fixed useless error message when providing incorrect daemon address. Also: made port optional (default = 30255) [#114](https://github.com/scionproto-contrib/jpan/pull/114) -- Fixed SCMP packet loss obn receive() [#120](https://github.com/scionproto-contrib/jpan/pull/120) +- Fixed SCMP packet loss on SCMP receive [#120](https://github.com/scionproto-contrib/jpan/pull/120) ### Removed - Removed some useless IP printing functions. diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 523f062e..1d0ac536 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -123,6 +123,20 @@ void getHandler() throws IOException { } } + @Test + void getOption() throws IOException { + MockNetwork.startTiny(); + EchoHandler handler = new EchoHandler(); + try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { + assertFalse(channel.getOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE)); + assertEquals(handler, channel.getHandler()); + channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); + assertTrue(channel.getOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE)); + } finally { + MockNetwork.stopTiny(); + } + } + @Test void sendEcho() throws IOException { testEcho(this::getPathTo112, 5); @@ -149,10 +163,10 @@ private void testEcho(Supplier pathSupplier, int n) throws IOException { MockNetwork.answerNextScmpEchos(n); EchoHandler handler = new EchoHandler(); try (ScmpSenderAsync channel = Scmp.newSenderAsyncBuilder(handler).build()) { + channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); + byte[] data = new byte[] {1, 2, 3, 4, 5}; + Path path = pathSupplier.get(); for (int i = 0; i < 5; i++) { - channel.setOption(ScionSocketOptions.SCION_API_THROW_PARSER_FAILURE, true); - byte[] data = new byte[] {1, 2, 3, 4, 5}; - Path path = pathSupplier.get(); int seqId = channel.sendEcho(path, ByteBuffer.wrap(data)); assertEquals(i, seqId); Scmp.EchoMessage result = handler.get(); @@ -331,11 +345,10 @@ private void testTraceroute(Supplier path, int nHops) throws IOException { @Test void sendTraceroute_async() throws IOException { - testTracerouteAsync(this::getPathTo112, 2, 25); + testTracerouteAsync(this::getPathTo112, 25); } - private void testTracerouteAsync(Supplier pathSupplier, int nHops, int nRepeat) - throws IOException { + private void testTracerouteAsync(Supplier pathSupplier, int nRepeat) throws IOException { MockNetwork.startTiny(); MockNetwork.answerNextScmpEchos(nRepeat); TraceHandler handler = new TraceHandler(); @@ -477,10 +490,10 @@ private void testTracerouteLast(Supplier pathSupplier, boolean success) th @Test void sendTracerouteLast_async() throws IOException { - testTracerouteLastAsync(this::getPathTo112, 2, 25); + testTracerouteLastAsync(this::getPathTo112, 25); } - private void testTracerouteLastAsync(Supplier pathSupplier, int nHops, int nRepeat) + private void testTracerouteLastAsync(Supplier pathSupplier, int nRepeat) throws IOException { MockNetwork.startTiny(); MockNetwork.answerNextScmpEchos(nRepeat); diff --git a/src/test/java/org/scion/jpan/demo/inspector/ScmpInspectorTest.java b/src/test/java/org/scion/jpan/demo/inspector/ScmpInspectorTest.java index ebf0705e..8acef2a7 100644 --- a/src/test/java/org/scion/jpan/demo/inspector/ScmpInspectorTest.java +++ b/src/test/java/org/scion/jpan/demo/inspector/ScmpInspectorTest.java @@ -16,7 +16,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.IOException; import java.nio.ByteBuffer; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; @@ -89,7 +88,7 @@ public static void afterAll() { } @Test - void testScmpError_WrongPacketSize() throws IOException { + void testScmpError_WrongPacketSize() { ByteBuffer data = ByteBuffer.wrap(SCMP_PKT_SIZE).asReadOnlyBuffer(); ScionPacketInspector spi = ScionPacketInspector.readPacket(data); ScmpHeader hdr = spi.getScmpHeader(); @@ -98,7 +97,7 @@ void testScmpError_WrongPacketSize() throws IOException { } @Test - void testScmpError_WrongPacketSize2() throws IOException { + void testScmpError_WrongPacketSize2() { ByteBuffer data = ByteBuffer.wrap(SCMP_PACKET_SIZE2).asReadOnlyBuffer(); ScionPacketInspector spi = ScionPacketInspector.readPacket(data); ScmpHeader hdr = spi.getScmpHeader(); @@ -107,7 +106,7 @@ void testScmpError_WrongPacketSize2() throws IOException { } @Test - void testScmpError_WrongSrcIsdAs() throws IOException { + void testScmpError_WrongSrcIsdAs() { ByteBuffer data = ByteBuffer.wrap(WRONG_SRC_ISD_AS).asReadOnlyBuffer(); ScionPacketInspector spi = ScionPacketInspector.readPacket(data); ScmpHeader hdr = spi.getScmpHeader(); From dae4bf710c2424b899cf4374e89b288784c182d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Mon, 30 Sep 2024 10:47:15 +0200 Subject: [PATCH 12/18] SCMP problems --- .../java/org/scion/jpan/api/ScmpSenderAsyncTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java index 1d0ac536..8b3f52a5 100644 --- a/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java +++ b/src/test/java/org/scion/jpan/api/ScmpSenderAsyncTest.java @@ -633,10 +633,7 @@ private Path getPathToLocalAS(String addressStr, int port) { private ScmpSenderAsync exceptionSender(ScmpHandler handler) throws IOException { MockDatagramChannel errorChannel = MockDatagramChannel.open(); - errorChannel.setSendCallback( - (byteBuffer, socketAddress) -> { - return 0; - }); + errorChannel.setSendCallback((byteBuffer, socketAddress) -> 0); // This selector throws an Exception when activated. MockDatagramChannel.MockSelector selector = MockDatagramChannel.MockSelector.open(); selector.setConnectCallback( @@ -651,10 +648,7 @@ private ScmpSenderAsync exceptionSender(ScmpHandler handler) throws IOExcepti private ScmpSenderAsync errorSender(ScmpHandler handler) throws IOException { MockDatagramChannel errorChannel = MockDatagramChannel.open(); - errorChannel.setSendCallback( - (byteBuffer, socketAddress) -> { - return 0; - }); + errorChannel.setSendCallback((byteBuffer, socketAddress) -> 0); errorChannel.setReceiveCallback( buffer -> { buffer.put(PING_ERROR_4_51_HK); From 486b5d438c0a60231cff0983a4e22b400f24870b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Mon, 30 Sep 2024 10:50:01 +0200 Subject: [PATCH 13/18] SCMP problems --- src/main/java/org/scion/jpan/ScmpSenderAsync.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/scion/jpan/ScmpSenderAsync.java b/src/main/java/org/scion/jpan/ScmpSenderAsync.java index acf8d652..162b7972 100644 --- a/src/main/java/org/scion/jpan/ScmpSenderAsync.java +++ b/src/main/java/org/scion/jpan/ScmpSenderAsync.java @@ -38,7 +38,7 @@ public class ScmpSenderAsync implements AutoCloseable { private final AtomicInteger sequenceIDs = new AtomicInteger(0); private final ConcurrentHashMap timers = new ConcurrentHashMap<>(); private final Timer timer = new Timer(true); - private Thread receiver; + private final Thread receiver; private final ResponseHandler handler; public static Builder newBuilder(ResponseHandler handler) { @@ -84,13 +84,11 @@ private Thread startHandler(Consumer task, String name) { } private void stopHandler(Thread thread) { - if (thread != null) { - thread.interrupt(); - try { - thread.join(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } + thread.interrupt(); + try { + thread.join(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } } From 01f4dd5b34b3b3e759ebe6a3a4f6e1a3425c8b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Mon, 30 Sep 2024 18:11:10 +0200 Subject: [PATCH 14/18] SCMP problems --- mytopo.topo | 19 + .../org/scion/jpan/ProtobufSegmentDemo.java | 20 +- .../scion/jpan/ProtobufSegmentMapperDemo.java | 402 ++++++++++++++++++ .../ASff00_0_1001/topology.json | 105 +++++ .../ASff00_0_1002/topology.json | 133 ++++++ .../ASff00_0_1003/topology.json | 161 +++++++ .../ASff00_0_1004/topology.json | 189 ++++++++ .../ASff00_0_1005/topology.json | 161 +++++++ .../ASff00_0_1006/topology.json | 133 ++++++ .../ASff00_0_1007/topology.json | 105 +++++ .../ISD1/trcs/ISD1-B1-S1.trc | 326 ++++++++++++++ .../scionproto-scionlab/as_list.yml | 8 + .../topologies/scionproto-scionlab/ifids.yml | 67 +++ .../scionproto-scionlab/sciond_addresses.json | 9 + .../scionproto-scionlab/scionlab.topo | 73 ++++ .../scionproto-scionlab/trcs/ISD1-B1-S1.trc | 326 ++++++++++++++ 16 files changed, 2229 insertions(+), 8 deletions(-) create mode 100644 mytopo.topo create mode 100644 src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1001/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1002/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1003/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1004/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1005/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1006/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ASff00_0_1007/topology.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/ISD1/trcs/ISD1-B1-S1.trc create mode 100644 src/test/resources/topologies/scionproto-scionlab/as_list.yml create mode 100644 src/test/resources/topologies/scionproto-scionlab/ifids.yml create mode 100644 src/test/resources/topologies/scionproto-scionlab/sciond_addresses.json create mode 100644 src/test/resources/topologies/scionproto-scionlab/scionlab.topo create mode 100644 src/test/resources/topologies/scionproto-scionlab/trcs/ISD1-B1-S1.trc diff --git a/mytopo.topo b/mytopo.topo new file mode 100644 index 00000000..130cc1f8 --- /dev/null +++ b/mytopo.topo @@ -0,0 +1,19 @@ +ASes: + "1-ff00:0:110": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:120": + core: true + voting: true + authoritative: true + issuing: true + "2-ff00:0:210": + core: true + voting: true + authoritative: true + issuing: true +links: + - {a: "2-ff00:0:210#105", b: "1-ff00:0:120#210", linkAtoB: CORE} + - {a: "1-ff00:0:120#10", b: "1-ff00:0:110#1", linkAtoB: CORE} diff --git a/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java b/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java index 52e9cfa0..c85d1c97 100644 --- a/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java +++ b/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java @@ -36,14 +36,18 @@ public class ProtobufSegmentDemo { private final ManagedChannel channel; public static void main(String[] args) throws ScionException { - // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(csETH); - // demo.getSegments(iaETH, iaETH_CORE); - // demo.getSegments(toWildcard(iaETH), toWildcard(iaAnapayaHK)); - ProtobufSegmentDemo demo = new ProtobufSegmentDemo(DemoConstants.csAddr110_minimal); - // demo.getSegments(ia110, ia121); - demo.getSegments(DemoConstants.ia110, DemoConstants.ia1111); - // demo.getSegments(toWildcard(ia121), ia121); - // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); +// // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(csETH); +// // demo.getSegments(iaETH, iaETH_CORE); +// // demo.getSegments(toWildcard(iaETH), toWildcard(iaAnapayaHK)); +// ProtobufSegmentDemo demo = new ProtobufSegmentDemo(DemoConstants.csAddr110_minimal); +// // demo.getSegments(ia110, ia121); +// demo.getSegments(DemoConstants.ia110, DemoConstants.ia1111); +// // demo.getSegments(toWildcard(ia121), ia121); +// // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); + + ProtobufSegmentDemo demoLab = new ProtobufSegmentDemo("127.0.0.71:31000"); + demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:1001"), ScionUtil.parseIA("1-ff00:0:1007")); + } public ProtobufSegmentDemo(String csAddress) { diff --git a/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java b/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java new file mode 100644 index 00000000..4c82984e --- /dev/null +++ b/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java @@ -0,0 +1,402 @@ +// Copyright 2023 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 org.scion.jpan; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Timestamp; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; +import io.grpc.ManagedChannel; +import io.grpc.StatusRuntimeException; + +import java.io.FileWriter; +import java.io.IOException; +import java.time.Instant; +import java.util.*; +import java.util.stream.Collectors; + +import org.scion.jpan.internal.Segments; +import org.scion.jpan.proto.control_plane.Seg; +import org.scion.jpan.proto.control_plane.SegExtensions; +import org.scion.jpan.proto.control_plane.SegmentLookupServiceGrpc; +import org.scion.jpan.proto.control_plane.experimental.SegDetachedExtensions; +import org.scion.jpan.proto.crypto.Signed; + +/** + * Small demo that requests and prints segments requested from a control service. The segments are + * analyzed to create a topology file. + */ +public class ProtobufSegmentMapperDemo { + + private final SegmentLookupServiceGrpc.SegmentLookupServiceBlockingStub segmentStub; + private final ManagedChannel channel; + + public static void main(String[] args) throws IOException { + // // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(csETH); + // // demo.getSegments(iaETH, iaETH_CORE); + // // demo.getSegments(toWildcard(iaETH), toWildcard(iaAnapayaHK)); + // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(DemoConstants.csAddr110_minimal); + // // demo.getSegments(ia110, ia121); + // demo.getSegments(DemoConstants.ia110, DemoConstants.ia1111); + // // demo.getSegments(toWildcard(ia121), ia121); + // // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); + +// ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("127.0.0.28:31000"); +// demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:110"), ScionUtil.parseIA("2-ff00:0:210")); + + ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("127.0.0.71:31000"); + demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:1001"), + ScionUtil.parseIA("1-ff00:0:1007")); + + } + + public ProtobufSegmentMapperDemo(String csAddress) { + channel = Grpc.newChannelBuilder(csAddress, InsecureChannelCredentials.create()).build(); + segmentStub = SegmentLookupServiceGrpc.newBlockingStub(channel); + } + + private void getSegments(long srcIsdAs, long dstIsdAs) throws IOException { + // LOG.info("*** GetASInfo ***"); + System.out.println( + "Requesting segments: " + + ScionUtil.toStringIA(srcIsdAs) + + " -> " + + ScionUtil.toStringIA(dstIsdAs)); + if (srcIsdAs == dstIsdAs) { + return; + } + Seg.SegmentsRequest request = + Seg.SegmentsRequest.newBuilder().setSrcIsdAs(srcIsdAs).setDstIsdAs(dstIsdAs).build(); + Seg.SegmentsResponse response; + try { + response = segmentStub.segments(request); + } catch (StatusRuntimeException e) { + throw new ScionException("Error while getting Segment info: " + e.getMessage(), e); + } + print(response); + } + + private static void print(Seg.SegmentsResponse response) throws IOException { + analyze(response); + // try { + // for (Map.Entry seg : + // response.getSegmentsMap().entrySet()) { + // System.out.println( + // "SEG: key=" + // + Seg.SegmentType.forNumber(seg.getKey()) + // + " -> n=" + // + seg.getValue().getSegmentsCount()); + // for (Seg.PathSegment pathSegment : seg.getValue().getSegmentsList()) { + // print(pathSegment); + // } + // } + // } catch (InvalidProtocolBufferException e) { + // throw new ScionException(e); + // } + } + + private static class AsInfo { + final long isdAs; + final Map links = new HashMap<>(); + + AsInfo(long isdAs) { + this.isdAs = isdAs; + } + + public void addLink(long id, AsLink link) { + links.put(id, link); + } + } + + private static class AsLink { + private final long as0; + private final long as1; + private final long id0; + private final long id1; + + public AsLink(long isdAs, long nextIsdAs, long id0, long id1) { + this.as0 = isdAs; + this.as1 = nextIsdAs; + this.id0 = id0; + this.id1 = id1; + } + } + + private static void analyze(Seg.SegmentsResponse response) throws IOException { + List segments = getPathSegments(response); + + Map asMap = new HashMap<>(); + Set asLinks = new HashSet<>(); + for (PathSegment s : segments) { + AsInfo asPrev = null; + long idPrev = -1; + for (int i = 0; i < s.getAsEntriesCount(); i++) { + Seg.ASEntrySignedBody body = s.getAsEntries(i); + Seg.HopEntry hopEntry = body.getHopEntry(); + Seg.HopField hopField = hopEntry.getHopField(); + + long isdAs = body.getIsdAs(); + long nextIsdAs = body.getNextIsdAs(); + AsInfo as0 = asMap.computeIfAbsent(isdAs, l -> l > 0 ? new AsInfo(l) : null); + AsInfo as1 = asMap.computeIfAbsent(nextIsdAs, l -> l > 0 ? new AsInfo(l) : null); + long id0 = hopField.getEgress(); + long id1 = hopField.getIngress(); + + if (i >= 1) { + // This is a bit weird, but it works. + AsLink link = new AsLink(asPrev.isdAs, isdAs, idPrev, id1); + asLinks.add(link); +// as0.addLink(id0, link); +// as1.addLink(id1, link); + } + asPrev = as0; + idPrev = id0; + } + } + + write(asMap, asLinks); + } + + private static void write(Map asMap, Set asLinks) throws IOException { + // write + FileWriter writer = new FileWriter("mytopo.topo"); + + String NL = System.lineSeparator(); + writer.append("--- # My Topology"); + writer.append("ASes:").append(NL); + for (AsInfo as : asMap.values()) { + writer.append(" \"").append(ScionUtil.toStringIA(as.isdAs)).append("\":").append(NL); + writer.append(" core: true").append(NL); + writer.append(" voting: true").append(NL); + writer.append(" authoritative: true").append(NL); + writer.append(" issuing: true").append(NL); + } + writer.append("links:").append(NL); + // - {a: "1-ff00:0:1001#21", b: "1-ff00:0:1002#11", linkAtoB: CORE} + for (AsLink l : asLinks) { + writer + .append(" - {a: \"") + .append(ScionUtil.toStringIA(l.as0)) + .append("#") + .append(String.valueOf(l.id0)); + writer + .append("\", b: \"") + .append(ScionUtil.toStringIA(l.as1)) + .append("#") + .append(String.valueOf(l.id1)); + writer.append("\", linkAtoB: CORE}").append(NL); + } + + writer.flush(); + writer.close(); + } + + private static List getPathSegments(Seg.SegmentsResponse response) { + List pathSegments = new ArrayList<>(); + for (Map.Entry seg : + response.getSegmentsMap().entrySet()) { + SegmentType type = SegmentType.from(Seg.SegmentType.forNumber(seg.getKey())); + seg.getValue() + .getSegmentsList() + .forEach(path -> pathSegments.add(new PathSegment(path, type))); + System.out.println( + "Segments found of type " + type.name() + ": " + seg.getValue().getSegmentsCount()); + } + return pathSegments; + } + + private static Seg.ASEntrySignedBody getBody(Seg.ASEntry asEntry) { + if (!asEntry.hasSigned()) { + throw new UnsupportedOperationException("Unsigned entries are not supported"); + } + Signed.SignedMessage sm = asEntry.getSigned(); + try { + Signed.HeaderAndBodyInternal habi = + Signed.HeaderAndBodyInternal.parseFrom(sm.getHeaderAndBody()); + return Seg.ASEntrySignedBody.parseFrom(habi.getBody()); + } catch (InvalidProtocolBufferException e) { + throw new ScionRuntimeException(e); + } + } + + private static Seg.SegmentInformation getInfo(Seg.PathSegment pathSegment) { + try { + return Seg.SegmentInformation.parseFrom(pathSegment.getSegmentInfo()); + } catch (InvalidProtocolBufferException e) { + throw new ScionRuntimeException(e); + } + } + + private enum SegmentType { + UP, + CORE, + DOWN; + + public static SegmentType from(Seg.SegmentType segmentType) { + switch (segmentType) { + case SEGMENT_TYPE_UP: + return UP; + case SEGMENT_TYPE_DOWN: + return DOWN; + case SEGMENT_TYPE_CORE: + return CORE; + default: + throw new IllegalArgumentException("type=" + segmentType); + } + } + } + + private static class PathSegment { + final Seg.PathSegment segment; + final List bodies; + final Seg.SegmentInformation info; + final SegmentType type; // + + PathSegment(Seg.PathSegment segment, SegmentType type) { + this.segment = segment; + this.bodies = + Collections.unmodifiableList( + segment.getAsEntriesList().stream() + .map(ProtobufSegmentMapperDemo::getBody) + .collect(Collectors.toList())); + this.info = getInfo(segment); + this.type = type; + } + + public Seg.ASEntrySignedBody getAsEntriesFirst() { + return bodies.get(0); + } + + public Seg.ASEntrySignedBody getAsEntriesLast() { + return bodies.get(bodies.size() - 1); + } + + public List getAsEntriesList() { + return bodies; + } + + public Seg.ASEntrySignedBody getAsEntries(int i) { + return bodies.get(i); + } + + public int getAsEntriesCount() { + return bodies.size(); + } + + public ByteString getSegmentInfo() { + return segment.getSegmentInfo(); + } + + public boolean isCore() { + return type == SegmentType.CORE; + } + } + + public static void print(Seg.PathSegment pathSegment) throws InvalidProtocolBufferException { + System.out.println(" PathSeg: size=" + pathSegment.getSegmentInfo().size()); + Seg.SegmentInformation segInf = Seg.SegmentInformation.parseFrom(pathSegment.getSegmentInfo()); + System.out.println( + " SegInfo: ts=" + + Instant.ofEpochSecond(segInf.getTimestamp()) + + " id=" + + segInf.getSegmentId()); + for (Seg.ASEntry asEntry : pathSegment.getAsEntriesList()) { + if (asEntry.hasSigned()) { + Signed.SignedMessage sm = asEntry.getSigned(); + System.out.println( + " AS: signed=" + + sm.getHeaderAndBody().size() + + " signature size=" + + sm.getSignature().size()); + // System.out.println( + // " Header/Body=" + Arrays.toString(sm.getHeaderAndBody().toByteArray())); + // System.out.println( + // " Signature =" + Arrays.toString(sm.getSignature().toByteArray())); + + Signed.HeaderAndBodyInternal habi = + Signed.HeaderAndBodyInternal.parseFrom(sm.getHeaderAndBody()); + // System.out.println( + // " habi: " + habi.getHeader().size() + " " + + // habi.getBody().size()); + Signed.Header header = Signed.Header.parseFrom(habi.getHeader()); + // TODO body for signature verification?!? + Timestamp ts = header.getTimestamp(); + System.out.println( + " AS header: " + + header.getSignatureAlgorithm() + + " time=" + + Instant.ofEpochSecond(ts.getSeconds(), ts.getNanos()) + + " meta=" + + header.getMetadata().size() + + " data=" + + header.getAssociatedDataLength()); + + Seg.ASEntrySignedBody body = Seg.ASEntrySignedBody.parseFrom(habi.getBody()); + System.out.println( + " AS Body: IA=" + + ScionUtil.toStringIA(body.getIsdAs()) + + " nextIA=" + + ScionUtil.toStringIA(body.getNextIsdAs()) + // + " nPeers=" + // + body.getPeerEntriesCount() + + " mtu=" + + body.getMtu()); + Seg.HopEntry he = body.getHopEntry(); + System.out.println(" HopEntry: " + he.hasHopField() + " mtu=" + he.getIngressMtu()); + + if (he.hasHopField()) { + Seg.HopField hf = he.getHopField(); + System.out.println( + " HopField: exp=" + + hf.getExpTime() + + " ingress=" + + hf.getIngress() + + " egress=" + + hf.getEgress()); + } + if (body.hasExtensions()) { + SegExtensions.PathSegmentExtensions pse = body.getExtensions(); + if (pse.hasStaticInfo()) { + SegExtensions.StaticInfoExtension sie = pse.getStaticInfo(); + System.out.println( + " Static: latencies=" + + sie.getLatency().getIntraCount() + + "/" + + sie.getLatency().getInterCount() + + " bandwidth=" + + sie.getBandwidth().getIntraCount() + + "/" + + sie.getBandwidth().getInterCount() + + " geo=" + + sie.getGeoCount() + + " interfaces=" + + sie.getLinkTypeCount() + + " note=" + + sie.getNote()); + } + } + } + if (asEntry.hasUnsigned()) { + SegExtensions.PathSegmentUnsignedExtensions psue = asEntry.getUnsigned(); + System.out.println(" AS: hasEpic=" + psue.hasEpic()); + if (psue.hasEpic()) { + SegDetachedExtensions.EPICDetachedExtension epic = psue.getEpic(); + System.out.println(" EPIC: " + epic.getAuthHopEntry().size() + " ..."); + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1001/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1001/topology.json new file mode 100644 index 00000000..7d2b6e2c --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1001/topology.json @@ -0,0 +1,105 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1001", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1001-1": { + "addr": "127.0.0.71:31000" + } + }, + "discovery_service": { + "cs1-ff00_0_1001-1": { + "addr": "127.0.0.71:31000" + } + }, + "border_routers": { + "br1-ff00_0_1001-1": { + "internal_addr": "127.0.0.65:31002", + "interfaces": { + "21": { + "underlay": { + "local": "127.0.0.4:50000", + "remote": "127.0.0.5:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1001-2": { + "internal_addr": "127.0.0.66:31004", + "interfaces": { + "22": { + "underlay": { + "local": "127.0.0.6:50000", + "remote": "127.0.0.7:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1001-3": { + "internal_addr": "127.0.0.67:31006", + "interfaces": { + "31": { + "underlay": { + "local": "127.0.0.8:50000", + "remote": "127.0.0.9:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1001-4": { + "internal_addr": "127.0.0.68:31008", + "interfaces": { + "32": { + "underlay": { + "local": "127.0.0.10:50000", + "remote": "127.0.0.11:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1001-5": { + "internal_addr": "127.0.0.69:31010", + "interfaces": { + "41": { + "underlay": { + "local": "127.0.0.12:50000", + "remote": "127.0.0.13:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1001-6": { + "internal_addr": "127.0.0.70:31012", + "interfaces": { + "42": { + "underlay": { + "local": "127.0.0.14:50000", + "remote": "127.0.0.15:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1002/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1002/topology.json new file mode 100644 index 00000000..afe7d6d8 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1002/topology.json @@ -0,0 +1,133 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1002", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1002-1": { + "addr": "127.0.0.89:31014" + } + }, + "discovery_service": { + "cs1-ff00_0_1002-1": { + "addr": "127.0.0.89:31014" + } + }, + "border_routers": { + "br1-ff00_0_1002-1": { + "internal_addr": "127.0.0.81:31016", + "interfaces": { + "11": { + "underlay": { + "local": "127.0.0.5:50000", + "remote": "127.0.0.4:50000" + }, + "isd_as": "1-ff00:0:1001", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-2": { + "internal_addr": "127.0.0.82:31018", + "interfaces": { + "12": { + "underlay": { + "local": "127.0.0.7:50000", + "remote": "127.0.0.6:50000" + }, + "isd_as": "1-ff00:0:1001", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-3": { + "internal_addr": "127.0.0.83:31020", + "interfaces": { + "31": { + "underlay": { + "local": "127.0.0.16:50000", + "remote": "127.0.0.17:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-4": { + "internal_addr": "127.0.0.84:31022", + "interfaces": { + "32": { + "underlay": { + "local": "127.0.0.18:50000", + "remote": "127.0.0.19:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-5": { + "internal_addr": "127.0.0.85:31024", + "interfaces": { + "41": { + "underlay": { + "local": "127.0.0.20:50000", + "remote": "127.0.0.21:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-6": { + "internal_addr": "127.0.0.86:31026", + "interfaces": { + "42": { + "underlay": { + "local": "127.0.0.22:50000", + "remote": "127.0.0.23:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-7": { + "internal_addr": "127.0.0.87:31028", + "interfaces": { + "51": { + "underlay": { + "local": "127.0.0.24:50000", + "remote": "127.0.0.25:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1002-8": { + "internal_addr": "127.0.0.88:31030", + "interfaces": { + "52": { + "underlay": { + "local": "127.0.0.26:50000", + "remote": "127.0.0.27:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1003/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1003/topology.json new file mode 100644 index 00000000..308f0444 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1003/topology.json @@ -0,0 +1,161 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1003", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1003-1": { + "addr": "127.0.0.107:31032" + } + }, + "discovery_service": { + "cs1-ff00_0_1003-1": { + "addr": "127.0.0.107:31032" + } + }, + "border_routers": { + "br1-ff00_0_1003-1": { + "internal_addr": "127.0.0.98:31034", + "interfaces": { + "11": { + "underlay": { + "local": "127.0.0.9:50000", + "remote": "127.0.0.8:50000" + }, + "isd_as": "1-ff00:0:1001", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-2": { + "internal_addr": "127.0.0.99:31036", + "interfaces": { + "12": { + "underlay": { + "local": "127.0.0.11:50000", + "remote": "127.0.0.10:50000" + }, + "isd_as": "1-ff00:0:1001", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-3": { + "internal_addr": "127.0.0.100:31038", + "interfaces": { + "21": { + "underlay": { + "local": "127.0.0.17:50000", + "remote": "127.0.0.16:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-4": { + "internal_addr": "127.0.0.101:31040", + "interfaces": { + "22": { + "underlay": { + "local": "127.0.0.19:50000", + "remote": "127.0.0.18:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-5": { + "internal_addr": "127.0.0.102:31042", + "interfaces": { + "41": { + "underlay": { + "local": "127.0.0.30:50000", + "remote": "127.0.0.31:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-6": { + "internal_addr": "127.0.0.103:31044", + "interfaces": { + "42": { + "underlay": { + "local": "127.0.0.32:50000", + "remote": "127.0.0.33:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-7": { + "internal_addr": "127.0.0.104:31046", + "interfaces": { + "51": { + "underlay": { + "local": "127.0.0.34:50000", + "remote": "127.0.0.35:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-8": { + "internal_addr": "127.0.0.105:31048", + "interfaces": { + "52": { + "underlay": { + "local": "127.0.0.36:50000", + "remote": "127.0.0.37:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-9": { + "internal_addr": "127.0.0.106:31050", + "interfaces": { + "61": { + "underlay": { + "local": "127.0.0.38:50000", + "remote": "127.0.0.39:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1003-10": { + "internal_addr": "127.0.0.97:31052", + "interfaces": { + "62": { + "underlay": { + "local": "127.0.0.28:50000", + "remote": "127.0.0.29:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1004/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1004/topology.json new file mode 100644 index 00000000..368392fc --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1004/topology.json @@ -0,0 +1,189 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1004", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1004-1": { + "addr": "127.0.0.141:31054" + } + }, + "discovery_service": { + "cs1-ff00_0_1004-1": { + "addr": "127.0.0.141:31054" + } + }, + "border_routers": { + "br1-ff00_0_1004-1": { + "internal_addr": "127.0.0.132:31056", + "interfaces": { + "11": { + "underlay": { + "local": "127.0.0.13:50000", + "remote": "127.0.0.12:50000" + }, + "isd_as": "1-ff00:0:1001", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-2": { + "internal_addr": "127.0.0.133:31058", + "interfaces": { + "12": { + "underlay": { + "local": "127.0.0.15:50000", + "remote": "127.0.0.14:50000" + }, + "isd_as": "1-ff00:0:1001", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-3": { + "internal_addr": "127.0.0.134:31060", + "interfaces": { + "21": { + "underlay": { + "local": "127.0.0.21:50000", + "remote": "127.0.0.20:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-4": { + "internal_addr": "127.0.0.135:31062", + "interfaces": { + "22": { + "underlay": { + "local": "127.0.0.23:50000", + "remote": "127.0.0.22:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-5": { + "internal_addr": "127.0.0.136:31064", + "interfaces": { + "31": { + "underlay": { + "local": "127.0.0.31:50000", + "remote": "127.0.0.30:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-6": { + "internal_addr": "127.0.0.137:31066", + "interfaces": { + "32": { + "underlay": { + "local": "127.0.0.33:50000", + "remote": "127.0.0.32:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-7": { + "internal_addr": "127.0.0.138:31068", + "interfaces": { + "51": { + "underlay": { + "local": "127.0.0.46:50000", + "remote": "127.0.0.47:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-8": { + "internal_addr": "127.0.0.139:31070", + "interfaces": { + "52": { + "underlay": { + "local": "127.0.0.48:50000", + "remote": "127.0.0.49:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-9": { + "internal_addr": "127.0.0.140:31072", + "interfaces": { + "61": { + "underlay": { + "local": "127.0.0.50:50000", + "remote": "127.0.0.51:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-10": { + "internal_addr": "127.0.0.129:31074", + "interfaces": { + "62": { + "underlay": { + "local": "127.0.0.40:50000", + "remote": "127.0.0.41:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-11": { + "internal_addr": "127.0.0.130:31076", + "interfaces": { + "71": { + "underlay": { + "local": "127.0.0.42:50000", + "remote": "127.0.0.43:50000" + }, + "isd_as": "1-ff00:0:1007", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1004-12": { + "internal_addr": "127.0.0.131:31078", + "interfaces": { + "72": { + "underlay": { + "local": "127.0.0.44:50000", + "remote": "127.0.0.45:50000" + }, + "isd_as": "1-ff00:0:1007", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1005/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1005/topology.json new file mode 100644 index 00000000..63f1230a --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1005/topology.json @@ -0,0 +1,161 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1005", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1005-1": { + "addr": "127.0.0.123:31080" + } + }, + "discovery_service": { + "cs1-ff00_0_1005-1": { + "addr": "127.0.0.123:31080" + } + }, + "border_routers": { + "br1-ff00_0_1005-1": { + "internal_addr": "127.0.0.114:31082", + "interfaces": { + "21": { + "underlay": { + "local": "127.0.0.25:50000", + "remote": "127.0.0.24:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-2": { + "internal_addr": "127.0.0.115:31084", + "interfaces": { + "22": { + "underlay": { + "local": "127.0.0.27:50000", + "remote": "127.0.0.26:50000" + }, + "isd_as": "1-ff00:0:1002", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-3": { + "internal_addr": "127.0.0.116:31086", + "interfaces": { + "31": { + "underlay": { + "local": "127.0.0.35:50000", + "remote": "127.0.0.34:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-4": { + "internal_addr": "127.0.0.117:31088", + "interfaces": { + "32": { + "underlay": { + "local": "127.0.0.37:50000", + "remote": "127.0.0.36:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-5": { + "internal_addr": "127.0.0.118:31090", + "interfaces": { + "41": { + "underlay": { + "local": "127.0.0.47:50000", + "remote": "127.0.0.46:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-6": { + "internal_addr": "127.0.0.119:31092", + "interfaces": { + "42": { + "underlay": { + "local": "127.0.0.49:50000", + "remote": "127.0.0.48:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-7": { + "internal_addr": "127.0.0.120:31094", + "interfaces": { + "61": { + "underlay": { + "local": "127.0.0.54:50000", + "remote": "127.0.0.55:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-8": { + "internal_addr": "127.0.0.121:31096", + "interfaces": { + "62": { + "underlay": { + "local": "127.0.0.56:50000", + "remote": "127.0.0.57:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-9": { + "internal_addr": "127.0.0.122:31098", + "interfaces": { + "71": { + "underlay": { + "local": "127.0.0.58:50000", + "remote": "127.0.0.59:50000" + }, + "isd_as": "1-ff00:0:1007", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1005-10": { + "internal_addr": "127.0.0.113:31100", + "interfaces": { + "72": { + "underlay": { + "local": "127.0.0.52:50000", + "remote": "127.0.0.53:50000" + }, + "isd_as": "1-ff00:0:1007", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1006/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1006/topology.json new file mode 100644 index 00000000..ae316fe3 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1006/topology.json @@ -0,0 +1,133 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1006", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1006-1": { + "addr": "127.0.0.169:31102" + } + }, + "discovery_service": { + "cs1-ff00_0_1006-1": { + "addr": "127.0.0.169:31102" + } + }, + "border_routers": { + "br1-ff00_0_1006-1": { + "internal_addr": "127.0.0.161:31104", + "interfaces": { + "31": { + "underlay": { + "local": "127.0.0.39:50000", + "remote": "127.0.0.38:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-2": { + "internal_addr": "127.0.0.162:31106", + "interfaces": { + "32": { + "underlay": { + "local": "127.0.0.29:50000", + "remote": "127.0.0.28:50000" + }, + "isd_as": "1-ff00:0:1003", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-3": { + "internal_addr": "127.0.0.163:31108", + "interfaces": { + "41": { + "underlay": { + "local": "127.0.0.51:50000", + "remote": "127.0.0.50:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-4": { + "internal_addr": "127.0.0.164:31110", + "interfaces": { + "42": { + "underlay": { + "local": "127.0.0.41:50000", + "remote": "127.0.0.40:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-5": { + "internal_addr": "127.0.0.165:31112", + "interfaces": { + "51": { + "underlay": { + "local": "127.0.0.55:50000", + "remote": "127.0.0.54:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-6": { + "internal_addr": "127.0.0.166:31114", + "interfaces": { + "52": { + "underlay": { + "local": "127.0.0.57:50000", + "remote": "127.0.0.56:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-7": { + "internal_addr": "127.0.0.167:31116", + "interfaces": { + "71": { + "underlay": { + "local": "127.0.0.60:50000", + "remote": "127.0.0.61:50000" + }, + "isd_as": "1-ff00:0:1007", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1006-8": { + "internal_addr": "127.0.0.168:31118", + "interfaces": { + "72": { + "underlay": { + "local": "127.0.0.62:50000", + "remote": "127.0.0.63:50000" + }, + "isd_as": "1-ff00:0:1007", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1007/topology.json b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1007/topology.json new file mode 100644 index 00000000..d803fc19 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ASff00_0_1007/topology.json @@ -0,0 +1,105 @@ +{ + "attributes": [ + "core" + ], + "isd_as": "1-ff00:0:1007", + "mtu": 1472, + "test_dispatcher": true, + "dispatched_ports": "31000-32767", + "control_service": { + "cs1-ff00_0_1007-1": { + "addr": "127.0.0.183:31120" + } + }, + "discovery_service": { + "cs1-ff00_0_1007-1": { + "addr": "127.0.0.183:31120" + } + }, + "border_routers": { + "br1-ff00_0_1007-1": { + "internal_addr": "127.0.0.177:31122", + "interfaces": { + "41": { + "underlay": { + "local": "127.0.0.43:50000", + "remote": "127.0.0.42:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1007-2": { + "internal_addr": "127.0.0.178:31124", + "interfaces": { + "42": { + "underlay": { + "local": "127.0.0.45:50000", + "remote": "127.0.0.44:50000" + }, + "isd_as": "1-ff00:0:1004", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1007-3": { + "internal_addr": "127.0.0.179:31126", + "interfaces": { + "51": { + "underlay": { + "local": "127.0.0.59:50000", + "remote": "127.0.0.58:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1007-4": { + "internal_addr": "127.0.0.180:31128", + "interfaces": { + "52": { + "underlay": { + "local": "127.0.0.53:50000", + "remote": "127.0.0.52:50000" + }, + "isd_as": "1-ff00:0:1005", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1007-5": { + "internal_addr": "127.0.0.181:31130", + "interfaces": { + "61": { + "underlay": { + "local": "127.0.0.61:50000", + "remote": "127.0.0.60:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + }, + "br1-ff00_0_1007-6": { + "internal_addr": "127.0.0.182:31132", + "interfaces": { + "62": { + "underlay": { + "local": "127.0.0.63:50000", + "remote": "127.0.0.62:50000" + }, + "isd_as": "1-ff00:0:1006", + "link_to": "core", + "mtu": 1472 + } + } + } + } +} diff --git a/src/test/resources/topologies/scionproto-scionlab/ISD1/trcs/ISD1-B1-S1.trc b/src/test/resources/topologies/scionproto-scionlab/ISD1/trcs/ISD1-B1-S1.trc new file mode 100644 index 00000000..198de286 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ISD1/trcs/ISD1-B1-S1.trc @@ -0,0 +1,326 @@ +-----BEGIN TRC----- +MII8mwYJKoZIhvcNAQcCoII8jDCCPIgCAQExDTALBglghkgBZQMEAgEwgirQBgkq +hkiG9w0BBwGggirBBIIqvTCCKrkCAQAwCQIBAQIBAQIBATAiGA8yMDI0MDkzMDE2 +MDYxNloYDzIwMjUxMjI0MTYwNjE2WgIBAAEBADAAAgEEMFsTC2ZmMDA6MDoxMDA3 +EwtmZjAwOjA6MTAwMRMLZmYwMDowOjEwMDITC2ZmMDA6MDoxMDAzEwtmZjAwOjA6 +MTAwNBMLZmYwMDowOjEwMDUTC2ZmMDA6MDoxMDA2MFsTC2ZmMDA6MDoxMDA3Ewtm +ZjAwOjA6MTAwMRMLZmYwMDowOjEwMDITC2ZmMDA6MDoxMDAzEwtmZjAwOjA6MTAw +NBMLZmYwMDowOjEwMDUTC2ZmMDA6MDoxMDA2DBhUZXN0Y3J5cHRvIFRSQyBmb3Ig +SVNEIDEwgimkMIICCzCCAbGgAwIBAgIULakjzGSnOePmELVmk+d1brFEQJYwCgYI +KoZIzj0EAwIwUTEvMC0GA1UEAxMmMS1mZjAwOjA6MTAwMSBSb290IENlcnRpZmlj +YXRlIC0gR0VOIEkxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMTAeFw0y +NDA5MzAxNjA2MTZaFw0yNjA5MzAxNjA3MTZaMFExLzAtBgNVBAMTJjEtZmYwMDow +OjEwMDEgUm9vdCBDZXJ0aWZpY2F0ZSAtIEdFTiBJMR4wHAYLKwYBBAGDsBwBAgET +DTEtZmYwMDowOjEwMDEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASsScVPl7v9 +HZo0IlZhyucaa0RUV4P8DgX12arJDD9xEBt7KA6TUUsGtlBagDmdAPngMeCHt3WW +yII0qF6Rlcbio2cwZTAOBgNVHQ8BAf8EBAMCAgQwIAYDVR0lBBkwFwYIKwYBBQUH +AwgGCysGAQQBg7AcAQMDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFBhI +uWHM1n2kTyFwa2oZq9Bx0gn8MAoGCCqGSM49BAMCA0gAMEUCICx0Lp00rAf3w0Lf +Ch6T62OyMiQcRwAhER4SURkcJ/e6AiEA2p7pWrXgtLsS/x8oSz0jaR0NC/hOEnKw +spF8qbNQZ4cwggHsMIIBkaADAgECAhQnBLW11wRtPafpXJxJNc0CfXhH+jAKBggq +hkjOPQQDAjBTMTEwLwYDVQQDEygxLWZmMDA6MDoxMDAxIFJlZ3VsYXIgVm90aW5n +IENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDEwHhcN +MjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBTMTEwLwYDVQQDEygxLWZmMDA6 +MDoxMDAxIFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwB +AgETDTEtZmYwMDowOjEwMDEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATTbP5r +ScLSDr/Q3w6pqWRIVlDg+4t9y6N20GNiwBe9/xLRLf3OVl2eWeS8YIucaZuWKJyB +RPoe0dShqi3hjjTno0MwQTAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwB +AwIwHQYDVR0OBBYEFMSPf9uqyfudMcLEiAa++W71cgaWMAoGCCqGSM49BAMCA0kA +MEYCIQClOolfb2UrY8h2Fn0uWc7MLP128f/RCpTKJscV9Eg6vwIhANy5K3UsZfNv +MidC4a2KXUBMUkAO0FJzoUyBN5eo6pReMIIB7zCCAZWgAwIBAgIUP6EkSTjlkyig +4HXzYqoHA3pTcaYwCgYIKoZIzj0EAwIwVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAw +MSBTZW5zaXRpdmUgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgET +DTEtZmYwMDowOjEwMDEwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBV +MTMwMQYDVQQDEyoxLWZmMDA6MDoxMDAxIFNlbnNpdGl2ZSBWb3RpbmcgQ2VydGlm +aWNhdGUxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMTBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABLSQ4pc3Hn+tFoCEPDzImkAfpMwf16glEjD+uGxnIkG4 +VuGToRAkFlLcwYpVkCY2DvCTR691cpBoUSts0Ec1UzGjQzBBMCAGA1UdJQQZMBcG +CCsGAQUFBwMIBgsrBgEEAYOwHAEDATAdBgNVHQ4EFgQUiRjNjDvEHEYE0Pps2ZnF +XWXe5lIwCgYIKoZIzj0EAwIDSAAwRQIgMToREXqwLhYv1lcT7Ez44tUW3//39qv6 +YqE7FHfYLdgCIQDBqhjPYjLvv1CMbYlfgmZTpDOP+L6L8jww3EO9s0CG3DCCAg0w +ggGyoAMCAQICFQCUpv8GFp8piP/4PIK2K7pJuDz80zAKBggqhkjOPQQDAjBRMS8w +LQYDVQQDEyYxLWZmMDA6MDoxMDAyIFJvb3QgQ2VydGlmaWNhdGUgLSBHRU4gSTEe +MBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDAyMB4XDTI0MDkzMDE2MDYxNloX +DTI2MDkzMDE2MDcxNlowUTEvMC0GA1UEAxMmMS1mZjAwOjA6MTAwMiBSb290IENl +cnRpZmljYXRlIC0gR0VOIEkxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAw +MjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABP4gc6n07E5yQKNHgkF+O5RAXqfP +yw5yLW0FJko702tmV5gI1F0SLyoDfN/Ab1GdZgrN1OUnuoY9EZw4RIc6enCjZzBl +MA4GA1UdDwEB/wQEAwICBDAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwB +AwMwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUlrDh47Zn7zAdTlOBxOYx +YRQhYQIwCgYIKoZIzj0EAwIDSQAwRgIhAIOwQNZKEST9A/YExb9nOdyhj7W7xw7J +qGydQZwPho6lAiEA2nE5MMUkXVb7ZgBo/u/0l4k5CiRWXODRKAzce/REA34wggHs +MIIBkqADAgECAhUAz8YqlgSi3TjtAE5NgJ8e7MYtJjAwCgYIKoZIzj0EAwIwUzEx +MC8GA1UEAxMoMS1mZjAwOjA6MTAwMiBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0 +ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDAyMB4XDTI0MDkzMDE2MDYx +NloXDTI2MDkzMDE2MDcxNlowUzExMC8GA1UEAxMoMS1mZjAwOjA6MTAwMiBSZWd1 +bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6 +MDoxMDAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEI9d/+9uwXyuG4ODPiAeQ +ofsPsQeXfMUUifBlvvgf8tggp/pPDYtNDFePFXae7YMhxmu8JvmrJCO2U/Zy+jos +WqNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQW +BBTUxH1h6U44/NM7F4v3zPG4rL3WkTAKBggqhkjOPQQDAgNIADBFAiEA2V9uluSX +9+wzd3k2hKaH7LHKCN7VHAf3PBrjrSrqt8ACIAP4dZ4743Ifdux+XoS/fSdeSBvM +IF68dPRGw/YLV0tJMIIB7zCCAZWgAwIBAgIUXyDe38ogki5c2OeU8hm/VsqBqrIw +CgYIKoZIzj0EAwIwVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAwMiBTZW5zaXRpdmUg +Vm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEw +MDIwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBVMTMwMQYDVQQDEyox +LWZmMDA6MDoxMDAyIFNlbnNpdGl2ZSBWb3RpbmcgQ2VydGlmaWNhdGUxHjAcBgsr +BgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMjBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABExgbTHVfDlDOc8Sj6qIMe8zfKegwXM/awAbm0zM1g5w54IWvCDDwJYwyvH1 +NLQIaYPJ8U433ykKpP7J18eGUIyjQzBBMCAGA1UdJQQZMBcGCCsGAQUFBwMIBgsr +BgEEAYOwHAEDATAdBgNVHQ4EFgQU9cTcQcslMB5xG82ZhwHlqKT+QsIwCgYIKoZI +zj0EAwIDSAAwRQIhAJQlG1C/nLuC9RhMDr7+VbIUZHdO6RJp5SXU5UhBDLEeAiBo +6WVa48Idw4SA5ikpXvYS2WpVGKMxP4T+2rgpMrasYzCCAgswggGyoAMCAQICFQDD +wdiLl8l0lM5M5ZFEg3lSaqDjPzAKBggqhkjOPQQDAjBRMS8wLQYDVQQDEyYxLWZm +MDA6MDoxMDAzIFJvb3QgQ2VydGlmaWNhdGUgLSBHRU4gSTEeMBwGCysGAQQBg7Ac +AQIBEw0xLWZmMDA6MDoxMDAzMB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2MDcx +NlowUTEvMC0GA1UEAxMmMS1mZjAwOjA6MTAwMyBSb290IENlcnRpZmljYXRlIC0g +R0VOIEkxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMzBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABFT8kpiNc/5+anZcUP8UZuUaae2kyTQaenaUKr5oMYqI +P/OOPTrywv8UiGlf6r+h/9W0TTsbQH81VLS+9JJ0AB6jZzBlMA4GA1UdDwEB/wQE +AwICBDAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwBAwMwEgYDVR0TAQH/ +BAgwBgEB/wIBATAdBgNVHQ4EFgQU8KAax9hVCXVHRPWumrErP1ROUsMwCgYIKoZI +zj0EAwIDRwAwRAIgE5yvB1MZn4IIo04MBDWxMKG2MWm+JmgYD/xRhuj5T4YCIHtg +1wGWPe/oH9aK91MyxgL5cLGQrzFV6ETiVsxL+glCMIIB6jCCAZGgAwIBAgIUHQDc +Q1G4NKdMJ0/AeZNNl/km6TUwCgYIKoZIzj0EAwIwUzExMC8GA1UEAxMoMS1mZjAw +OjA6MTAwMyBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7Ac +AQIBEw0xLWZmMDA6MDoxMDAzMB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2MDcx +NlowUzExMC8GA1UEAxMoMS1mZjAwOjA6MTAwMyBSZWd1bGFyIFZvdGluZyBDZXJ0 +aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDAzMFkwEwYHKoZI +zj0CAQYIKoZIzj0DAQcDQgAE8oK2L/O5HRY7TOCXO2r8qjizS9MGredseokCnEYF +B/bscgoMkQCZ13PmUhIB/R7egiO5B1gQcGeHCv3T3nYTWKNDMEEwIAYDVR0lBBkw +FwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQWBBRlwxi5nALpc9qXbijs +j6ER1ZHp3DAKBggqhkjOPQQDAgNHADBEAiA6MBkifpGXUk1mkD1G/ndKjYNDCitO +rHqsWZwV09PokQIgTGQHdXTBJ46re5REok+Lvaf5xQ8SYUsH7YX2F2lmLB0wggHv +MIIBlaADAgECAhRiK51/sGQlaNLRL+xO09tc8y1uODAKBggqhkjOPQQDAjBVMTMw +MQYDVQQDEyoxLWZmMDA6MDoxMDAzIFNlbnNpdGl2ZSBWb3RpbmcgQ2VydGlmaWNh +dGUxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMzAeFw0yNDA5MzAxNjA2 +MTZaFw0yNjA5MzAxNjA3MTZaMFUxMzAxBgNVBAMTKjEtZmYwMDowOjEwMDMgU2Vu +c2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZm +MDA6MDoxMDAzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMPjbPkogvZUhskry +KqecgjJEIj6CrJOBVRU6cSGRL1sROnhztJFU6Rr49A9UFQ8Md0nRueZjOrwtGtKx +J1F9/KNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMBMB0GA1Ud +DgQWBBQHCjm3DQRVgHcKsJwlKOWzTSdzojAKBggqhkjOPQQDAgNIADBFAiEAzPOo +EoA/BB7d1hs/C5IfvL9Su0WqSbAXun5nJI+elIMCIEuINbSZ97H5KwxAgP9lYZZq +rc8lEh+INyaLK2QhuzLMMIICDDCCAbKgAwIBAgIVAP9cUIpti6SGNSRpGhsBk90a +DdllMAoGCCqGSM49BAMCMFExLzAtBgNVBAMTJjEtZmYwMDowOjEwMDQgUm9vdCBD +ZXJ0aWZpY2F0ZSAtIEdFTiBJMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEw +MDQwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBRMS8wLQYDVQQDEyYx +LWZmMDA6MDoxMDA0IFJvb3QgQ2VydGlmaWNhdGUgLSBHRU4gSTEeMBwGCysGAQQB +g7AcAQIBEw0xLWZmMDA6MDoxMDA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE +2YnOEpHRL3NQZWkpTWTL5zAzN66AOBpP9XdZclddVnlj2k4JsktvrlWJ668d/MgS +MIJUHieHeNVDSsC2fk73c6NnMGUwDgYDVR0PAQH/BAQDAgIEMCAGA1UdJQQZMBcG +CCsGAQUFBwMIBgsrBgEEAYOwHAEDAzASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1Ud +DgQWBBT0qeKAXQ7CE33pHg3pHknVO+ucyTAKBggqhkjOPQQDAgNIADBFAiB6EiLX +hmAhTlKfj6VsIzP82F2r3ngKWicb452OIi9YaAIhAJxQvm8jKwUzz6wkpT6zrX0J +XYVmHiCgX+GqP7M8m7NMMIIB6zCCAZGgAwIBAgIUfAjLUhzT9U0AY69fEKvO8cJK +oMMwCgYIKoZIzj0EAwIwUzExMC8GA1UEAxMoMS1mZjAwOjA6MTAwNCBSZWd1bGFy +IFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDox +MDA0MB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2MDcxNlowUzExMC8GA1UEAxMo +MS1mZjAwOjA6MTAwNCBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysG +AQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAE4d9ncolrAjCOeVZph+YUSBCQ2Mkfsowz+TaEx55FrqJ4pZ5yJKrG0pYK+7Et +Od70tzoNHE+8h6bc+IlvohphaaNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysG +AQQBg7AcAQMCMB0GA1UdDgQWBBS8RwKc9evSdZr1I8tNrCez3YNPwTAKBggqhkjO +PQQDAgNIADBFAiBIJ8sDbS/NOAxbRHZmvihDWXC2qmrx6Ytxkp3zkyACqgIhAI/N +McbkujaV7RqUjcW9oGORCxpMinScIF8ou/xzmqh+MIIB8TCCAZagAwIBAgIVAJBn +3Y5c123WJuGimeV2o7rtfnM7MAoGCCqGSM49BAMCMFUxMzAxBgNVBAMTKjEtZmYw +MDowOjEwMDQgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQB +g7AcAQIBEw0xLWZmMDA6MDoxMDA0MB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2 +MDcxNlowVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAwNCBTZW5zaXRpdmUgVm90aW5n +IENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDQwWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAARXC+kNVkgCCzZk75WTpg6DWQ7/FFcvFjNR +ZCKrtWwMjZiSnig/mQmgCfFNo4DedZrEZwy8jdcZ3i9y0ltTCBsZo0MwQTAgBgNV +HSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwBAwEwHQYDVR0OBBYEFCqjI9gOIY4A +zoN2c4iURXsNWK/iMAoGCCqGSM49BAMCA0kAMEYCIQD+p6zvcc7tkG5NjYGfCfq5 +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 +RuXw3NdGPWJGbGjiuTAKBggqhkjOPQQDAjBTMTEwLwYDVQQDEygxLWZmMDA6MDox +MDA3IFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgET +DTEtZmYwMDowOjEwMDcwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBT +MTEwLwYDVQQDEygxLWZmMDA6MDoxMDA3IFJlZ3VsYXIgVm90aW5nIENlcnRpZmlj +YXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDcwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAASq91ko+6ESHFZ5no1HkheGGa1DDJNtxm3/713RbZ6QGpHN +Jw8cds6iLAFNAz+KMst3d/acs4LPjIxKMg4kgmDAo0MwQTAgBgNVHSUEGTAXBggr +BgEFBQcDCAYLKwYBBAGDsBwBAwIwHQYDVR0OBBYEFAMH4qg/uveIURqncc4gheYk +tyAPMAoGCCqGSM49BAMCA0kAMEYCIQCg3CC0/zyQ9VSlbUTiAgK6b4MiZ6oJsX9U +lln8Qmf6yQIhAKUewLQIO2u+Y8kraeIe0RKn2bA1IacIURjHr9mz6NHpMIIB7zCC +AZagAwIBAgIVAPIobO4T2BfJB6jLW0lGuw/nCuA0MAoGCCqGSM49BAMCMFUxMzAx +BgNVBAMTKjEtZmYwMDowOjEwMDcgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0 +ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA3MB4XDTI0MDkzMDE2MDYx +NloXDTI2MDkzMDE2MDcxNlowVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAwNyBTZW5z +aXRpdmUgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYw +MDowOjEwMDcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQc44i42zmcd56jn0SB +0g7zcABhqfwpoHHcAsshWiHu892a2Rdhjlz7HlNmYbcLQ94CatYfvLF833Jon++6 +pV6Ho0MwQTAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwBAwEwHQYDVR0O +BBYEFAJLKgRbxcKNz/V9vE64JP+ka2H7MAoGCCqGSM49BAMCA0cAMEQCIBcBw3C+ +NxSM5bYIUzDpUwDjd038AYwwRO5XGNg/OV4aAiB9Hwf8SF+SKOJoeAkVxQmpTpmP +AkG7QxheMn/ZAkyDTDGCEZ4wggE8AgEBMGswUzExMC8GA1UEAxMoMS1mZjAwOjA6 +MTAwNiBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIB +Ew0xLWZmMDA6MDoxMDA2AhR/Tx/5n09gpLTBF2CC6Oq79o22BzALBglghkgBZQME +AgGgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0y +NDA5MzAxNjA3MTZaMC8GCSqGSIb3DQEJBDEiBCDLd1R2SkqTeKNX9x0M/hWgyk1A +NQpS5VqNyvtOv6l/jDAKBggqhkjOPQQDAgRGMEQCIGNYr7/9lFJTh8hw23yrJsFa +1d7IV3X9UgrzLROEBW0RAiBRXu7s5O88zRNevIqZqYvdyxLUjfN9ziGNUhx2rTNG +njCCAT0CAQEwazBTMTEwLwYDVQQDEygxLWZmMDA6MDoxMDAxIFJlZ3VsYXIgVm90 +aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDEC +FCcEtbXXBG09p+lcnEk1zQJ9eEf6MAsGCWCGSAFlAwQCAaBpMBgGCSqGSIb3DQEJ +AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI0MDkzMDE2MDcxNlowLwYJ +KoZIhvcNAQkEMSIEIMt3VHZKSpN4o1f3HQz+FaDKTUA1ClLlWo3K+06/qX+MMAoG +CCqGSM49BAMCBEcwRQIgRqtk8+F7x/0cOvT4iop2w0s1iOmJlcOQgAQ64XYn+TcC +IQCIlKFIwb9NvDJi8c/8IAMjYyos2O1+5Ib1U3quwmEvPTCCAT0CAQEwazBTMTEw +LwYDVQQDEygxLWZmMDA6MDoxMDAzIFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRl +MR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDMCFB0A3ENRuDSnTCdPwHmT +TZf5Juk1MAsGCWCGSAFlAwQCAaBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEw +HAYJKoZIhvcNAQkFMQ8XDTI0MDkzMDE2MDcxNlowLwYJKoZIhvcNAQkEMSIEIMt3 +VHZKSpN4o1f3HQz+FaDKTUA1ClLlWo3K+06/qX+MMAoGCCqGSM49BAMCBEcwRQIg +KJdN6kopPyhsZSy5ScE2Uci+61ksitAa8e/WDzA4zvgCIQDGK1nK/kiu8knbj9zZ +YKhGHKg0oTaYM4oITprOd9sUGTCCAT0CAQEwazBTMTEwLwYDVQQDEygxLWZmMDA6 +MDoxMDA0IFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwB +AgETDTEtZmYwMDowOjEwMDQCFHwIy1Ic0/VNAGOvXxCrzvHCSqDDMAsGCWCGSAFl +AwQCAaBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X +DTI0MDkzMDE2MDcxNlowLwYJKoZIhvcNAQkEMSIEIMt3VHZKSpN4o1f3HQz+FaDK +TUA1ClLlWo3K+06/qX+MMAoGCCqGSM49BAMCBEcwRQIgZxsACghDJpYjVEweyO6D +NZCN9Xm/oy3YXEegWqFKs4wCIQCW9+yoPHYyDbMXJy4RR7t2rqcRA3Jy8FK3eXz6 +SXC/ATCCAT0CAQEwbDBTMTEwLwYDVQQDEygxLWZmMDA6MDoxMDAyIFJlZ3VsYXIg +Vm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEw +MDICFQDPxiqWBKLdOO0ATk2Anx7sxi0mMDALBglghkgBZQMEAgGgaTAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA5MzAxNjA3MTZa +MC8GCSqGSIb3DQEJBDEiBCDLd1R2SkqTeKNX9x0M/hWgyk1ANQpS5VqNyvtOv6l/ +jDAKBggqhkjOPQQDAgRGMEQCIEpQro8ZwwxiKYk8rO+uBS2ljP0e0tOgQ6kAq3Xd +t/4BAiBVb+XMB7zxriO7LvL1mGddZhSTdU5ias1n/ohTswzCIjCCAT4CAQEwbDBT +MTEwLwYDVQQDEygxLWZmMDA6MDoxMDA1IFJlZ3VsYXIgVm90aW5nIENlcnRpZmlj +YXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDUCFQDu5fcqgr1tE7Nr +nlv8jZaB1NkDJDALBglghkgBZQMEAgGgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN +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 +ZSBWb3RpbmcgQ2VydGlmaWNhdGUxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6 +MTAwNwIVAPIobO4T2BfJB6jLW0lGuw/nCuA0MAsGCWCGSAFlAwQCAaBpMBgGCSqG +SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI0MDkzMDE2MDcx +NlowLwYJKoZIhvcNAQkEMSIEIMt3VHZKSpN4o1f3HQz+FaDKTUA1ClLlWo3K+06/ +qX+MMAoGCCqGSM49BAMCBEYwRAIgL70vFeqhFjM13CrTZSf2Vs7kSxHumG+BqtV5 +xy0CyyMCIHGP0CylRczIqFpraRHjxFZ/ujCeIY987h0bHSI9sOdcMIIBQAIBATBu +MFUxMzAxBgNVBAMTKjEtZmYwMDowOjEwMDQgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0 +aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA0AhUAkGfdjlzX +bdYm4aKZ5Xajuu1+czswCwYJYIZIAWUDBAIBoGkwGAYJKoZIhvcNAQkDMQsGCSqG +SIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjQwOTMwMTYwNzE2WjAvBgkqhkiG9w0B +CQQxIgQgy3dUdkpKk3ijV/cdDP4VoMpNQDUKUuVajcr7Tr+pf4wwCgYIKoZIzj0E +AwIERzBFAiBtdv8PgSqAcwsWlkkEnkkyWrQcjAI+Jj+BDg3mtNJM0wIhAOsnb5/X +29aZ23n2PscxtSY39AG6jJi53DsPvmPg7T6VMIIBQAIBATBuMFUxMzAxBgNVBAMT +KjEtZmYwMDowOjEwMDYgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwG +CysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA2AhUA8f9ayC2/00y1LYHXKfNWZzv/ +0akwCwYJYIZIAWUDBAIBoGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq +hkiG9w0BCQUxDxcNMjQwOTMwMTYwNzE2WjAvBgkqhkiG9w0BCQQxIgQgy3dUdkpK +k3ijV/cdDP4VoMpNQDUKUuVajcr7Tr+pf4wwCgYIKoZIzj0EAwIERzBFAiEA5hOx +ioEtA0qylUBPUGvLI3cBg/B9Crlx/Ogccyyiu9kCICa+mIXvDynrBrFKMUb1objz +KJ1gowhX7fcvnPNkWdQ/ +-----END TRC----- diff --git a/src/test/resources/topologies/scionproto-scionlab/as_list.yml b/src/test/resources/topologies/scionproto-scionlab/as_list.yml new file mode 100644 index 00000000..6ba7674a --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/as_list.yml @@ -0,0 +1,8 @@ +Core: +- 1-ff00:0:1001 +- 1-ff00:0:1002 +- 1-ff00:0:1003 +- 1-ff00:0:1004 +- 1-ff00:0:1005 +- 1-ff00:0:1006 +- 1-ff00:0:1007 diff --git a/src/test/resources/topologies/scionproto-scionlab/ifids.yml b/src/test/resources/topologies/scionproto-scionlab/ifids.yml new file mode 100644 index 00000000..b3b01da5 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/ifids.yml @@ -0,0 +1,67 @@ +1-ff00:0:1001: + br1-ff00_0_1001-1 21: br1-ff00_0_1002-1 11 + br1-ff00_0_1001-2 22: br1-ff00_0_1002-2 12 + br1-ff00_0_1001-3 31: br1-ff00_0_1003-1 11 + br1-ff00_0_1001-4 32: br1-ff00_0_1003-2 12 + br1-ff00_0_1001-5 41: br1-ff00_0_1004-1 11 + br1-ff00_0_1001-6 42: br1-ff00_0_1004-2 12 +1-ff00:0:1002: + br1-ff00_0_1002-1 11: br1-ff00_0_1001-1 21 + br1-ff00_0_1002-2 12: br1-ff00_0_1001-2 22 + br1-ff00_0_1002-3 31: br1-ff00_0_1003-3 21 + br1-ff00_0_1002-4 32: br1-ff00_0_1003-4 22 + br1-ff00_0_1002-5 41: br1-ff00_0_1004-3 21 + br1-ff00_0_1002-6 42: br1-ff00_0_1004-4 22 + br1-ff00_0_1002-7 51: br1-ff00_0_1005-1 21 + br1-ff00_0_1002-8 52: br1-ff00_0_1005-2 22 +1-ff00:0:1003: + br1-ff00_0_1003-1 11: br1-ff00_0_1001-3 31 + br1-ff00_0_1003-10 62: br1-ff00_0_1006-2 32 + br1-ff00_0_1003-2 12: br1-ff00_0_1001-4 32 + br1-ff00_0_1003-3 21: br1-ff00_0_1002-3 31 + br1-ff00_0_1003-4 22: br1-ff00_0_1002-4 32 + br1-ff00_0_1003-5 41: br1-ff00_0_1004-5 31 + br1-ff00_0_1003-6 42: br1-ff00_0_1004-6 32 + br1-ff00_0_1003-7 51: br1-ff00_0_1005-3 31 + br1-ff00_0_1003-8 52: br1-ff00_0_1005-4 32 + br1-ff00_0_1003-9 61: br1-ff00_0_1006-1 31 +1-ff00:0:1004: + br1-ff00_0_1004-1 11: br1-ff00_0_1001-5 41 + br1-ff00_0_1004-10 62: br1-ff00_0_1006-4 42 + br1-ff00_0_1004-11 71: br1-ff00_0_1007-1 41 + br1-ff00_0_1004-12 72: br1-ff00_0_1007-2 42 + br1-ff00_0_1004-2 12: br1-ff00_0_1001-6 42 + br1-ff00_0_1004-3 21: br1-ff00_0_1002-5 41 + br1-ff00_0_1004-4 22: br1-ff00_0_1002-6 42 + br1-ff00_0_1004-5 31: br1-ff00_0_1003-5 41 + br1-ff00_0_1004-6 32: br1-ff00_0_1003-6 42 + br1-ff00_0_1004-7 51: br1-ff00_0_1005-5 41 + br1-ff00_0_1004-8 52: br1-ff00_0_1005-6 42 + br1-ff00_0_1004-9 61: br1-ff00_0_1006-3 41 +1-ff00:0:1005: + br1-ff00_0_1005-1 21: br1-ff00_0_1002-7 51 + br1-ff00_0_1005-10 72: br1-ff00_0_1007-4 52 + br1-ff00_0_1005-2 22: br1-ff00_0_1002-8 52 + br1-ff00_0_1005-3 31: br1-ff00_0_1003-7 51 + br1-ff00_0_1005-4 32: br1-ff00_0_1003-8 52 + br1-ff00_0_1005-5 41: br1-ff00_0_1004-7 51 + br1-ff00_0_1005-6 42: br1-ff00_0_1004-8 52 + br1-ff00_0_1005-7 61: br1-ff00_0_1006-5 51 + br1-ff00_0_1005-8 62: br1-ff00_0_1006-6 52 + br1-ff00_0_1005-9 71: br1-ff00_0_1007-3 51 +1-ff00:0:1006: + br1-ff00_0_1006-1 31: br1-ff00_0_1003-9 61 + br1-ff00_0_1006-2 32: br1-ff00_0_1003-10 62 + br1-ff00_0_1006-3 41: br1-ff00_0_1004-9 61 + br1-ff00_0_1006-4 42: br1-ff00_0_1004-10 62 + br1-ff00_0_1006-5 51: br1-ff00_0_1005-7 61 + br1-ff00_0_1006-6 52: br1-ff00_0_1005-8 62 + br1-ff00_0_1006-7 71: br1-ff00_0_1007-5 61 + br1-ff00_0_1006-8 72: br1-ff00_0_1007-6 62 +1-ff00:0:1007: + br1-ff00_0_1007-1 41: br1-ff00_0_1004-11 71 + br1-ff00_0_1007-2 42: br1-ff00_0_1004-12 72 + br1-ff00_0_1007-3 51: br1-ff00_0_1005-9 71 + br1-ff00_0_1007-4 52: br1-ff00_0_1005-10 72 + br1-ff00_0_1007-5 61: br1-ff00_0_1006-7 71 + br1-ff00_0_1007-6 62: br1-ff00_0_1006-8 72 diff --git a/src/test/resources/topologies/scionproto-scionlab/sciond_addresses.json b/src/test/resources/topologies/scionproto-scionlab/sciond_addresses.json new file mode 100644 index 00000000..2dc372a9 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/sciond_addresses.json @@ -0,0 +1,9 @@ +{ + "1-ff00:0:1001": "127.0.0.72", + "1-ff00:0:1002": "127.0.0.90", + "1-ff00:0:1003": "127.0.0.108", + "1-ff00:0:1004": "127.0.0.142", + "1-ff00:0:1005": "127.0.0.124", + "1-ff00:0:1006": "127.0.0.170", + "1-ff00:0:1007": "127.0.0.184" +} \ No newline at end of file diff --git a/src/test/resources/topologies/scionproto-scionlab/scionlab.topo b/src/test/resources/topologies/scionproto-scionlab/scionlab.topo new file mode 100644 index 00000000..8dba42c5 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/scionlab.topo @@ -0,0 +1,73 @@ +--- # Tiny Topology +ASes: + "1-ff00:0:1001": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:1002": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:1003": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:1004": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:1005": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:1006": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:1007": + core: true + voting: true + authoritative: true + issuing: true +links: + - {a: "1-ff00:0:1001#21", b: "1-ff00:0:1002#11", linkAtoB: CORE} + - {a: "1-ff00:0:1001#22", b: "1-ff00:0:1002#12", linkAtoB: CORE} + - {a: "1-ff00:0:1001#31", b: "1-ff00:0:1003#11", linkAtoB: CORE} + - {a: "1-ff00:0:1001#32", b: "1-ff00:0:1003#12", linkAtoB: CORE} + - {a: "1-ff00:0:1001#41", b: "1-ff00:0:1004#11", linkAtoB: CORE} + - {a: "1-ff00:0:1001#42", b: "1-ff00:0:1004#12", linkAtoB: CORE} + + - {a: "1-ff00:0:1002#31", b: "1-ff00:0:1003#21", linkAtoB: CORE} + - {a: "1-ff00:0:1002#32", b: "1-ff00:0:1003#22", linkAtoB: CORE} + - {a: "1-ff00:0:1002#41", b: "1-ff00:0:1004#21", linkAtoB: CORE} + - {a: "1-ff00:0:1002#42", b: "1-ff00:0:1004#22", linkAtoB: CORE} + - {a: "1-ff00:0:1002#51", b: "1-ff00:0:1005#21", linkAtoB: CORE} + - {a: "1-ff00:0:1002#52", b: "1-ff00:0:1005#22", linkAtoB: CORE} + + - {a: "1-ff00:0:1003#41", b: "1-ff00:0:1004#31", linkAtoB: CORE} + - {a: "1-ff00:0:1003#42", b: "1-ff00:0:1004#32", linkAtoB: CORE} + - {a: "1-ff00:0:1003#51", b: "1-ff00:0:1005#31", linkAtoB: CORE} + - {a: "1-ff00:0:1003#52", b: "1-ff00:0:1005#32", linkAtoB: CORE} + - {a: "1-ff00:0:1003#61", b: "1-ff00:0:1006#31", linkAtoB: CORE} + - {a: "1-ff00:0:1003#62", b: "1-ff00:0:1006#32", linkAtoB: CORE} + + - {a: "1-ff00:0:1004#51", b: "1-ff00:0:1005#41", linkAtoB: CORE} + - {a: "1-ff00:0:1004#52", b: "1-ff00:0:1005#42", linkAtoB: CORE} + - {a: "1-ff00:0:1004#61", b: "1-ff00:0:1006#41", linkAtoB: CORE} + - {a: "1-ff00:0:1004#62", b: "1-ff00:0:1006#42", linkAtoB: CORE} + - {a: "1-ff00:0:1004#71", b: "1-ff00:0:1007#41", linkAtoB: CORE} + - {a: "1-ff00:0:1004#72", b: "1-ff00:0:1007#42", linkAtoB: CORE} + + - {a: "1-ff00:0:1005#61", b: "1-ff00:0:1006#51", linkAtoB: CORE} + - {a: "1-ff00:0:1005#62", b: "1-ff00:0:1006#52", linkAtoB: CORE} + - {a: "1-ff00:0:1005#71", b: "1-ff00:0:1007#51", linkAtoB: CORE} + - {a: "1-ff00:0:1005#72", b: "1-ff00:0:1007#52", linkAtoB: CORE} + + - {a: "1-ff00:0:1006#71", b: "1-ff00:0:1007#61", linkAtoB: CORE} + - {a: "1-ff00:0:1006#72", b: "1-ff00:0:1007#62", linkAtoB: CORE} diff --git a/src/test/resources/topologies/scionproto-scionlab/trcs/ISD1-B1-S1.trc b/src/test/resources/topologies/scionproto-scionlab/trcs/ISD1-B1-S1.trc new file mode 100644 index 00000000..198de286 --- /dev/null +++ b/src/test/resources/topologies/scionproto-scionlab/trcs/ISD1-B1-S1.trc @@ -0,0 +1,326 @@ +-----BEGIN TRC----- +MII8mwYJKoZIhvcNAQcCoII8jDCCPIgCAQExDTALBglghkgBZQMEAgEwgirQBgkq +hkiG9w0BBwGggirBBIIqvTCCKrkCAQAwCQIBAQIBAQIBATAiGA8yMDI0MDkzMDE2 +MDYxNloYDzIwMjUxMjI0MTYwNjE2WgIBAAEBADAAAgEEMFsTC2ZmMDA6MDoxMDA3 +EwtmZjAwOjA6MTAwMRMLZmYwMDowOjEwMDITC2ZmMDA6MDoxMDAzEwtmZjAwOjA6 +MTAwNBMLZmYwMDowOjEwMDUTC2ZmMDA6MDoxMDA2MFsTC2ZmMDA6MDoxMDA3Ewtm +ZjAwOjA6MTAwMRMLZmYwMDowOjEwMDITC2ZmMDA6MDoxMDAzEwtmZjAwOjA6MTAw +NBMLZmYwMDowOjEwMDUTC2ZmMDA6MDoxMDA2DBhUZXN0Y3J5cHRvIFRSQyBmb3Ig +SVNEIDEwgimkMIICCzCCAbGgAwIBAgIULakjzGSnOePmELVmk+d1brFEQJYwCgYI +KoZIzj0EAwIwUTEvMC0GA1UEAxMmMS1mZjAwOjA6MTAwMSBSb290IENlcnRpZmlj +YXRlIC0gR0VOIEkxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMTAeFw0y +NDA5MzAxNjA2MTZaFw0yNjA5MzAxNjA3MTZaMFExLzAtBgNVBAMTJjEtZmYwMDow +OjEwMDEgUm9vdCBDZXJ0aWZpY2F0ZSAtIEdFTiBJMR4wHAYLKwYBBAGDsBwBAgET +DTEtZmYwMDowOjEwMDEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASsScVPl7v9 +HZo0IlZhyucaa0RUV4P8DgX12arJDD9xEBt7KA6TUUsGtlBagDmdAPngMeCHt3WW +yII0qF6Rlcbio2cwZTAOBgNVHQ8BAf8EBAMCAgQwIAYDVR0lBBkwFwYIKwYBBQUH +AwgGCysGAQQBg7AcAQMDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFBhI +uWHM1n2kTyFwa2oZq9Bx0gn8MAoGCCqGSM49BAMCA0gAMEUCICx0Lp00rAf3w0Lf +Ch6T62OyMiQcRwAhER4SURkcJ/e6AiEA2p7pWrXgtLsS/x8oSz0jaR0NC/hOEnKw +spF8qbNQZ4cwggHsMIIBkaADAgECAhQnBLW11wRtPafpXJxJNc0CfXhH+jAKBggq +hkjOPQQDAjBTMTEwLwYDVQQDEygxLWZmMDA6MDoxMDAxIFJlZ3VsYXIgVm90aW5n +IENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDEwHhcN +MjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBTMTEwLwYDVQQDEygxLWZmMDA6 +MDoxMDAxIFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwB +AgETDTEtZmYwMDowOjEwMDEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATTbP5r +ScLSDr/Q3w6pqWRIVlDg+4t9y6N20GNiwBe9/xLRLf3OVl2eWeS8YIucaZuWKJyB +RPoe0dShqi3hjjTno0MwQTAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwB +AwIwHQYDVR0OBBYEFMSPf9uqyfudMcLEiAa++W71cgaWMAoGCCqGSM49BAMCA0kA +MEYCIQClOolfb2UrY8h2Fn0uWc7MLP128f/RCpTKJscV9Eg6vwIhANy5K3UsZfNv +MidC4a2KXUBMUkAO0FJzoUyBN5eo6pReMIIB7zCCAZWgAwIBAgIUP6EkSTjlkyig +4HXzYqoHA3pTcaYwCgYIKoZIzj0EAwIwVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAw +MSBTZW5zaXRpdmUgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgET +DTEtZmYwMDowOjEwMDEwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBV +MTMwMQYDVQQDEyoxLWZmMDA6MDoxMDAxIFNlbnNpdGl2ZSBWb3RpbmcgQ2VydGlm +aWNhdGUxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMTBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABLSQ4pc3Hn+tFoCEPDzImkAfpMwf16glEjD+uGxnIkG4 +VuGToRAkFlLcwYpVkCY2DvCTR691cpBoUSts0Ec1UzGjQzBBMCAGA1UdJQQZMBcG +CCsGAQUFBwMIBgsrBgEEAYOwHAEDATAdBgNVHQ4EFgQUiRjNjDvEHEYE0Pps2ZnF +XWXe5lIwCgYIKoZIzj0EAwIDSAAwRQIgMToREXqwLhYv1lcT7Ez44tUW3//39qv6 +YqE7FHfYLdgCIQDBqhjPYjLvv1CMbYlfgmZTpDOP+L6L8jww3EO9s0CG3DCCAg0w +ggGyoAMCAQICFQCUpv8GFp8piP/4PIK2K7pJuDz80zAKBggqhkjOPQQDAjBRMS8w +LQYDVQQDEyYxLWZmMDA6MDoxMDAyIFJvb3QgQ2VydGlmaWNhdGUgLSBHRU4gSTEe +MBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDAyMB4XDTI0MDkzMDE2MDYxNloX +DTI2MDkzMDE2MDcxNlowUTEvMC0GA1UEAxMmMS1mZjAwOjA6MTAwMiBSb290IENl +cnRpZmljYXRlIC0gR0VOIEkxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAw +MjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABP4gc6n07E5yQKNHgkF+O5RAXqfP +yw5yLW0FJko702tmV5gI1F0SLyoDfN/Ab1GdZgrN1OUnuoY9EZw4RIc6enCjZzBl +MA4GA1UdDwEB/wQEAwICBDAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwB +AwMwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUlrDh47Zn7zAdTlOBxOYx +YRQhYQIwCgYIKoZIzj0EAwIDSQAwRgIhAIOwQNZKEST9A/YExb9nOdyhj7W7xw7J +qGydQZwPho6lAiEA2nE5MMUkXVb7ZgBo/u/0l4k5CiRWXODRKAzce/REA34wggHs +MIIBkqADAgECAhUAz8YqlgSi3TjtAE5NgJ8e7MYtJjAwCgYIKoZIzj0EAwIwUzEx +MC8GA1UEAxMoMS1mZjAwOjA6MTAwMiBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0 +ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDAyMB4XDTI0MDkzMDE2MDYx +NloXDTI2MDkzMDE2MDcxNlowUzExMC8GA1UEAxMoMS1mZjAwOjA6MTAwMiBSZWd1 +bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6 +MDoxMDAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEI9d/+9uwXyuG4ODPiAeQ +ofsPsQeXfMUUifBlvvgf8tggp/pPDYtNDFePFXae7YMhxmu8JvmrJCO2U/Zy+jos +WqNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQW +BBTUxH1h6U44/NM7F4v3zPG4rL3WkTAKBggqhkjOPQQDAgNIADBFAiEA2V9uluSX +9+wzd3k2hKaH7LHKCN7VHAf3PBrjrSrqt8ACIAP4dZ4743Ifdux+XoS/fSdeSBvM +IF68dPRGw/YLV0tJMIIB7zCCAZWgAwIBAgIUXyDe38ogki5c2OeU8hm/VsqBqrIw +CgYIKoZIzj0EAwIwVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAwMiBTZW5zaXRpdmUg +Vm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEw +MDIwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBVMTMwMQYDVQQDEyox +LWZmMDA6MDoxMDAyIFNlbnNpdGl2ZSBWb3RpbmcgQ2VydGlmaWNhdGUxHjAcBgsr +BgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMjBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABExgbTHVfDlDOc8Sj6qIMe8zfKegwXM/awAbm0zM1g5w54IWvCDDwJYwyvH1 +NLQIaYPJ8U433ykKpP7J18eGUIyjQzBBMCAGA1UdJQQZMBcGCCsGAQUFBwMIBgsr +BgEEAYOwHAEDATAdBgNVHQ4EFgQU9cTcQcslMB5xG82ZhwHlqKT+QsIwCgYIKoZI +zj0EAwIDSAAwRQIhAJQlG1C/nLuC9RhMDr7+VbIUZHdO6RJp5SXU5UhBDLEeAiBo +6WVa48Idw4SA5ikpXvYS2WpVGKMxP4T+2rgpMrasYzCCAgswggGyoAMCAQICFQDD +wdiLl8l0lM5M5ZFEg3lSaqDjPzAKBggqhkjOPQQDAjBRMS8wLQYDVQQDEyYxLWZm +MDA6MDoxMDAzIFJvb3QgQ2VydGlmaWNhdGUgLSBHRU4gSTEeMBwGCysGAQQBg7Ac +AQIBEw0xLWZmMDA6MDoxMDAzMB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2MDcx +NlowUTEvMC0GA1UEAxMmMS1mZjAwOjA6MTAwMyBSb290IENlcnRpZmljYXRlIC0g +R0VOIEkxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMzBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABFT8kpiNc/5+anZcUP8UZuUaae2kyTQaenaUKr5oMYqI +P/OOPTrywv8UiGlf6r+h/9W0TTsbQH81VLS+9JJ0AB6jZzBlMA4GA1UdDwEB/wQE +AwICBDAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwBAwMwEgYDVR0TAQH/ +BAgwBgEB/wIBATAdBgNVHQ4EFgQU8KAax9hVCXVHRPWumrErP1ROUsMwCgYIKoZI +zj0EAwIDRwAwRAIgE5yvB1MZn4IIo04MBDWxMKG2MWm+JmgYD/xRhuj5T4YCIHtg +1wGWPe/oH9aK91MyxgL5cLGQrzFV6ETiVsxL+glCMIIB6jCCAZGgAwIBAgIUHQDc +Q1G4NKdMJ0/AeZNNl/km6TUwCgYIKoZIzj0EAwIwUzExMC8GA1UEAxMoMS1mZjAw +OjA6MTAwMyBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7Ac +AQIBEw0xLWZmMDA6MDoxMDAzMB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2MDcx +NlowUzExMC8GA1UEAxMoMS1mZjAwOjA6MTAwMyBSZWd1bGFyIFZvdGluZyBDZXJ0 +aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDAzMFkwEwYHKoZI +zj0CAQYIKoZIzj0DAQcDQgAE8oK2L/O5HRY7TOCXO2r8qjizS9MGredseokCnEYF +B/bscgoMkQCZ13PmUhIB/R7egiO5B1gQcGeHCv3T3nYTWKNDMEEwIAYDVR0lBBkw +FwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQWBBRlwxi5nALpc9qXbijs +j6ER1ZHp3DAKBggqhkjOPQQDAgNHADBEAiA6MBkifpGXUk1mkD1G/ndKjYNDCitO +rHqsWZwV09PokQIgTGQHdXTBJ46re5REok+Lvaf5xQ8SYUsH7YX2F2lmLB0wggHv +MIIBlaADAgECAhRiK51/sGQlaNLRL+xO09tc8y1uODAKBggqhkjOPQQDAjBVMTMw +MQYDVQQDEyoxLWZmMDA6MDoxMDAzIFNlbnNpdGl2ZSBWb3RpbmcgQ2VydGlmaWNh +dGUxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6MTAwMzAeFw0yNDA5MzAxNjA2 +MTZaFw0yNjA5MzAxNjA3MTZaMFUxMzAxBgNVBAMTKjEtZmYwMDowOjEwMDMgU2Vu +c2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZm +MDA6MDoxMDAzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMPjbPkogvZUhskry +KqecgjJEIj6CrJOBVRU6cSGRL1sROnhztJFU6Rr49A9UFQ8Md0nRueZjOrwtGtKx +J1F9/KNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMBMB0GA1Ud +DgQWBBQHCjm3DQRVgHcKsJwlKOWzTSdzojAKBggqhkjOPQQDAgNIADBFAiEAzPOo +EoA/BB7d1hs/C5IfvL9Su0WqSbAXun5nJI+elIMCIEuINbSZ97H5KwxAgP9lYZZq +rc8lEh+INyaLK2QhuzLMMIICDDCCAbKgAwIBAgIVAP9cUIpti6SGNSRpGhsBk90a +DdllMAoGCCqGSM49BAMCMFExLzAtBgNVBAMTJjEtZmYwMDowOjEwMDQgUm9vdCBD +ZXJ0aWZpY2F0ZSAtIEdFTiBJMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEw +MDQwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBRMS8wLQYDVQQDEyYx +LWZmMDA6MDoxMDA0IFJvb3QgQ2VydGlmaWNhdGUgLSBHRU4gSTEeMBwGCysGAQQB +g7AcAQIBEw0xLWZmMDA6MDoxMDA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE +2YnOEpHRL3NQZWkpTWTL5zAzN66AOBpP9XdZclddVnlj2k4JsktvrlWJ668d/MgS +MIJUHieHeNVDSsC2fk73c6NnMGUwDgYDVR0PAQH/BAQDAgIEMCAGA1UdJQQZMBcG +CCsGAQUFBwMIBgsrBgEEAYOwHAEDAzASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1Ud +DgQWBBT0qeKAXQ7CE33pHg3pHknVO+ucyTAKBggqhkjOPQQDAgNIADBFAiB6EiLX +hmAhTlKfj6VsIzP82F2r3ngKWicb452OIi9YaAIhAJxQvm8jKwUzz6wkpT6zrX0J +XYVmHiCgX+GqP7M8m7NMMIIB6zCCAZGgAwIBAgIUfAjLUhzT9U0AY69fEKvO8cJK +oMMwCgYIKoZIzj0EAwIwUzExMC8GA1UEAxMoMS1mZjAwOjA6MTAwNCBSZWd1bGFy +IFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDox +MDA0MB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2MDcxNlowUzExMC8GA1UEAxMo +MS1mZjAwOjA6MTAwNCBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysG +AQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAE4d9ncolrAjCOeVZph+YUSBCQ2Mkfsowz+TaEx55FrqJ4pZ5yJKrG0pYK+7Et +Od70tzoNHE+8h6bc+IlvohphaaNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysG +AQQBg7AcAQMCMB0GA1UdDgQWBBS8RwKc9evSdZr1I8tNrCez3YNPwTAKBggqhkjO +PQQDAgNIADBFAiBIJ8sDbS/NOAxbRHZmvihDWXC2qmrx6Ytxkp3zkyACqgIhAI/N +McbkujaV7RqUjcW9oGORCxpMinScIF8ou/xzmqh+MIIB8TCCAZagAwIBAgIVAJBn +3Y5c123WJuGimeV2o7rtfnM7MAoGCCqGSM49BAMCMFUxMzAxBgNVBAMTKjEtZmYw +MDowOjEwMDQgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQB +g7AcAQIBEw0xLWZmMDA6MDoxMDA0MB4XDTI0MDkzMDE2MDYxNloXDTI2MDkzMDE2 +MDcxNlowVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAwNCBTZW5zaXRpdmUgVm90aW5n +IENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDQwWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAARXC+kNVkgCCzZk75WTpg6DWQ7/FFcvFjNR +ZCKrtWwMjZiSnig/mQmgCfFNo4DedZrEZwy8jdcZ3i9y0ltTCBsZo0MwQTAgBgNV +HSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwBAwEwHQYDVR0OBBYEFCqjI9gOIY4A +zoN2c4iURXsNWK/iMAoGCCqGSM49BAMCA0kAMEYCIQD+p6zvcc7tkG5NjYGfCfq5 +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 +RuXw3NdGPWJGbGjiuTAKBggqhkjOPQQDAjBTMTEwLwYDVQQDEygxLWZmMDA6MDox +MDA3IFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgET +DTEtZmYwMDowOjEwMDcwHhcNMjQwOTMwMTYwNjE2WhcNMjYwOTMwMTYwNzE2WjBT +MTEwLwYDVQQDEygxLWZmMDA6MDoxMDA3IFJlZ3VsYXIgVm90aW5nIENlcnRpZmlj +YXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDcwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAASq91ko+6ESHFZ5no1HkheGGa1DDJNtxm3/713RbZ6QGpHN +Jw8cds6iLAFNAz+KMst3d/acs4LPjIxKMg4kgmDAo0MwQTAgBgNVHSUEGTAXBggr +BgEFBQcDCAYLKwYBBAGDsBwBAwIwHQYDVR0OBBYEFAMH4qg/uveIURqncc4gheYk +tyAPMAoGCCqGSM49BAMCA0kAMEYCIQCg3CC0/zyQ9VSlbUTiAgK6b4MiZ6oJsX9U +lln8Qmf6yQIhAKUewLQIO2u+Y8kraeIe0RKn2bA1IacIURjHr9mz6NHpMIIB7zCC +AZagAwIBAgIVAPIobO4T2BfJB6jLW0lGuw/nCuA0MAoGCCqGSM49BAMCMFUxMzAx +BgNVBAMTKjEtZmYwMDowOjEwMDcgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0 +ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA3MB4XDTI0MDkzMDE2MDYx +NloXDTI2MDkzMDE2MDcxNlowVTEzMDEGA1UEAxMqMS1mZjAwOjA6MTAwNyBTZW5z +aXRpdmUgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYw +MDowOjEwMDcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQc44i42zmcd56jn0SB +0g7zcABhqfwpoHHcAsshWiHu892a2Rdhjlz7HlNmYbcLQ94CatYfvLF833Jon++6 +pV6Ho0MwQTAgBgNVHSUEGTAXBggrBgEFBQcDCAYLKwYBBAGDsBwBAwEwHQYDVR0O +BBYEFAJLKgRbxcKNz/V9vE64JP+ka2H7MAoGCCqGSM49BAMCA0cAMEQCIBcBw3C+ +NxSM5bYIUzDpUwDjd038AYwwRO5XGNg/OV4aAiB9Hwf8SF+SKOJoeAkVxQmpTpmP +AkG7QxheMn/ZAkyDTDGCEZ4wggE8AgEBMGswUzExMC8GA1UEAxMoMS1mZjAwOjA6 +MTAwNiBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIB +Ew0xLWZmMDA6MDoxMDA2AhR/Tx/5n09gpLTBF2CC6Oq79o22BzALBglghkgBZQME +AgGgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0y +NDA5MzAxNjA3MTZaMC8GCSqGSIb3DQEJBDEiBCDLd1R2SkqTeKNX9x0M/hWgyk1A +NQpS5VqNyvtOv6l/jDAKBggqhkjOPQQDAgRGMEQCIGNYr7/9lFJTh8hw23yrJsFa +1d7IV3X9UgrzLROEBW0RAiBRXu7s5O88zRNevIqZqYvdyxLUjfN9ziGNUhx2rTNG +njCCAT0CAQEwazBTMTEwLwYDVQQDEygxLWZmMDA6MDoxMDAxIFJlZ3VsYXIgVm90 +aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDEC +FCcEtbXXBG09p+lcnEk1zQJ9eEf6MAsGCWCGSAFlAwQCAaBpMBgGCSqGSIb3DQEJ +AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI0MDkzMDE2MDcxNlowLwYJ +KoZIhvcNAQkEMSIEIMt3VHZKSpN4o1f3HQz+FaDKTUA1ClLlWo3K+06/qX+MMAoG +CCqGSM49BAMCBEcwRQIgRqtk8+F7x/0cOvT4iop2w0s1iOmJlcOQgAQ64XYn+TcC +IQCIlKFIwb9NvDJi8c/8IAMjYyos2O1+5Ib1U3quwmEvPTCCAT0CAQEwazBTMTEw +LwYDVQQDEygxLWZmMDA6MDoxMDAzIFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRl +MR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDMCFB0A3ENRuDSnTCdPwHmT +TZf5Juk1MAsGCWCGSAFlAwQCAaBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEw +HAYJKoZIhvcNAQkFMQ8XDTI0MDkzMDE2MDcxNlowLwYJKoZIhvcNAQkEMSIEIMt3 +VHZKSpN4o1f3HQz+FaDKTUA1ClLlWo3K+06/qX+MMAoGCCqGSM49BAMCBEcwRQIg +KJdN6kopPyhsZSy5ScE2Uci+61ksitAa8e/WDzA4zvgCIQDGK1nK/kiu8knbj9zZ +YKhGHKg0oTaYM4oITprOd9sUGTCCAT0CAQEwazBTMTEwLwYDVQQDEygxLWZmMDA6 +MDoxMDA0IFJlZ3VsYXIgVm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwB +AgETDTEtZmYwMDowOjEwMDQCFHwIy1Ic0/VNAGOvXxCrzvHCSqDDMAsGCWCGSAFl +AwQCAaBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X +DTI0MDkzMDE2MDcxNlowLwYJKoZIhvcNAQkEMSIEIMt3VHZKSpN4o1f3HQz+FaDK +TUA1ClLlWo3K+06/qX+MMAoGCCqGSM49BAMCBEcwRQIgZxsACghDJpYjVEweyO6D +NZCN9Xm/oy3YXEegWqFKs4wCIQCW9+yoPHYyDbMXJy4RR7t2rqcRA3Jy8FK3eXz6 +SXC/ATCCAT0CAQEwbDBTMTEwLwYDVQQDEygxLWZmMDA6MDoxMDAyIFJlZ3VsYXIg +Vm90aW5nIENlcnRpZmljYXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEw +MDICFQDPxiqWBKLdOO0ATk2Anx7sxi0mMDALBglghkgBZQMEAgGgaTAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA5MzAxNjA3MTZa +MC8GCSqGSIb3DQEJBDEiBCDLd1R2SkqTeKNX9x0M/hWgyk1ANQpS5VqNyvtOv6l/ +jDAKBggqhkjOPQQDAgRGMEQCIEpQro8ZwwxiKYk8rO+uBS2ljP0e0tOgQ6kAq3Xd +t/4BAiBVb+XMB7zxriO7LvL1mGddZhSTdU5ias1n/ohTswzCIjCCAT4CAQEwbDBT +MTEwLwYDVQQDEygxLWZmMDA6MDoxMDA1IFJlZ3VsYXIgVm90aW5nIENlcnRpZmlj +YXRlMR4wHAYLKwYBBAGDsBwBAgETDTEtZmYwMDowOjEwMDUCFQDu5fcqgr1tE7Nr +nlv8jZaB1NkDJDALBglghkgBZQMEAgGgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN +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 +ZSBWb3RpbmcgQ2VydGlmaWNhdGUxHjAcBgsrBgEEAYOwHAECARMNMS1mZjAwOjA6 +MTAwNwIVAPIobO4T2BfJB6jLW0lGuw/nCuA0MAsGCWCGSAFlAwQCAaBpMBgGCSqG +SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI0MDkzMDE2MDcx +NlowLwYJKoZIhvcNAQkEMSIEIMt3VHZKSpN4o1f3HQz+FaDKTUA1ClLlWo3K+06/ +qX+MMAoGCCqGSM49BAMCBEYwRAIgL70vFeqhFjM13CrTZSf2Vs7kSxHumG+BqtV5 +xy0CyyMCIHGP0CylRczIqFpraRHjxFZ/ujCeIY987h0bHSI9sOdcMIIBQAIBATBu +MFUxMzAxBgNVBAMTKjEtZmYwMDowOjEwMDQgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0 +aWZpY2F0ZTEeMBwGCysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA0AhUAkGfdjlzX +bdYm4aKZ5Xajuu1+czswCwYJYIZIAWUDBAIBoGkwGAYJKoZIhvcNAQkDMQsGCSqG +SIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjQwOTMwMTYwNzE2WjAvBgkqhkiG9w0B +CQQxIgQgy3dUdkpKk3ijV/cdDP4VoMpNQDUKUuVajcr7Tr+pf4wwCgYIKoZIzj0E +AwIERzBFAiBtdv8PgSqAcwsWlkkEnkkyWrQcjAI+Jj+BDg3mtNJM0wIhAOsnb5/X +29aZ23n2PscxtSY39AG6jJi53DsPvmPg7T6VMIIBQAIBATBuMFUxMzAxBgNVBAMT +KjEtZmYwMDowOjEwMDYgU2Vuc2l0aXZlIFZvdGluZyBDZXJ0aWZpY2F0ZTEeMBwG +CysGAQQBg7AcAQIBEw0xLWZmMDA6MDoxMDA2AhUA8f9ayC2/00y1LYHXKfNWZzv/ +0akwCwYJYIZIAWUDBAIBoGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq +hkiG9w0BCQUxDxcNMjQwOTMwMTYwNzE2WjAvBgkqhkiG9w0BCQQxIgQgy3dUdkpK +k3ijV/cdDP4VoMpNQDUKUuVajcr7Tr+pf4wwCgYIKoZIzj0EAwIERzBFAiEA5hOx +ioEtA0qylUBPUGvLI3cBg/B9Crlx/Ogccyyiu9kCICa+mIXvDynrBrFKMUb1objz +KJ1gowhX7fcvnPNkWdQ/ +-----END TRC----- From b6b55b4e63ce418b687e4e0e2f868c6ec30d2ee2 Mon Sep 17 00:00:00 2001 From: tzaeschke Date: Mon, 7 Oct 2024 14:10:04 +0200 Subject: [PATCH 15/18] Fixed generated file --- mytopo.topo | 22 +++++++++++-- .../org/scion/jpan/ProtobufSegmentDemo.java | 18 +++++------ .../scion/jpan/ProtobufSegmentMapperDemo.java | 32 ++++++++++++------- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/mytopo.topo b/mytopo.topo index 130cc1f8..92475db1 100644 --- a/mytopo.topo +++ b/mytopo.topo @@ -1,5 +1,6 @@ +--- # My Topology ASes: - "1-ff00:0:110": + "1-ff00:0:130": core: true voting: true authoritative: true @@ -9,11 +10,26 @@ ASes: voting: true authoritative: true issuing: true + "1-ff00:0:110": + core: true + voting: true + authoritative: true + issuing: true + "2-ff00:0:220": + core: true + voting: true + authoritative: true + issuing: true "2-ff00:0:210": core: true voting: true authoritative: true issuing: true links: - - {a: "2-ff00:0:210#105", b: "1-ff00:0:120#210", linkAtoB: CORE} - - {a: "1-ff00:0:120#10", b: "1-ff00:0:110#1", linkAtoB: CORE} + - {a: "1-ff00:0:120#6", b: "1-ff00:0:110#1", linkAtoB: CORE} + - {a: "1-ff00:0:120#1", b: "1-ff00:0:130#105", linkAtoB: CORE} + - {a: "1-ff00:0:130#104", b: "1-ff00:0:110#2", linkAtoB: CORE} + - {a: "2-ff00:0:220#501", b: "1-ff00:0:120#2", linkAtoB: CORE} + - {a: "2-ff00:0:220#502", b: "1-ff00:0:120#3", linkAtoB: CORE} + - {a: "2-ff00:0:210#450", b: "2-ff00:0:220#503", linkAtoB: CORE} + - {a: "2-ff00:0:210#453", b: "1-ff00:0:110#3", linkAtoB: CORE} diff --git a/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java b/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java index c85d1c97..b974ced3 100644 --- a/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java +++ b/src/test/java/org/scion/jpan/ProtobufSegmentDemo.java @@ -22,7 +22,6 @@ import io.grpc.StatusRuntimeException; import java.time.Instant; import java.util.*; -import org.scion.jpan.demo.DemoConstants; import org.scion.jpan.proto.control_plane.Seg; import org.scion.jpan.proto.control_plane.SegExtensions; import org.scion.jpan.proto.control_plane.SegmentLookupServiceGrpc; @@ -36,18 +35,17 @@ public class ProtobufSegmentDemo { private final ManagedChannel channel; public static void main(String[] args) throws ScionException { -// // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(csETH); -// // demo.getSegments(iaETH, iaETH_CORE); -// // demo.getSegments(toWildcard(iaETH), toWildcard(iaAnapayaHK)); -// ProtobufSegmentDemo demo = new ProtobufSegmentDemo(DemoConstants.csAddr110_minimal); -// // demo.getSegments(ia110, ia121); -// demo.getSegments(DemoConstants.ia110, DemoConstants.ia1111); -// // demo.getSegments(toWildcard(ia121), ia121); -// // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); + // // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(csETH); + // // demo.getSegments(iaETH, iaETH_CORE); + // // demo.getSegments(toWildcard(iaETH), toWildcard(iaAnapayaHK)); + // ProtobufSegmentDemo demo = new ProtobufSegmentDemo(DemoConstants.csAddr110_minimal); + // // demo.getSegments(ia110, ia121); + // demo.getSegments(DemoConstants.ia110, DemoConstants.ia1111); + // // demo.getSegments(toWildcard(ia121), ia121); + // // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); ProtobufSegmentDemo demoLab = new ProtobufSegmentDemo("127.0.0.71:31000"); demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:1001"), ScionUtil.parseIA("1-ff00:0:1007")); - } public ProtobufSegmentDemo(String csAddress) { diff --git a/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java b/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java index 4c82984e..8835da1e 100644 --- a/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java +++ b/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java @@ -21,14 +21,11 @@ import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; - import java.io.FileWriter; import java.io.IOException; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; - -import org.scion.jpan.internal.Segments; import org.scion.jpan.proto.control_plane.Seg; import org.scion.jpan.proto.control_plane.SegExtensions; import org.scion.jpan.proto.control_plane.SegmentLookupServiceGrpc; @@ -54,13 +51,11 @@ public static void main(String[] args) throws IOException { // // demo.getSegments(toWildcard(ia121), ia121); // // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); -// ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("127.0.0.28:31000"); -// demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:110"), ScionUtil.parseIA("2-ff00:0:210")); - - ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("127.0.0.71:31000"); - demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:1001"), - ScionUtil.parseIA("1-ff00:0:1007")); + ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("[fd00:f00d:cafe::7f00:14]:31000"); + demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:110"), ScionUtil.parseIA("2-ff00:0:210")); + // ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("127.0.0.71:31000"); + // demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:1001"), ScionUtil.parseIA("1-ff00:0:1007")); } public ProtobufSegmentMapperDemo(String csAddress) { @@ -133,6 +128,19 @@ public AsLink(long isdAs, long nextIsdAs, long id0, long id1) { this.id0 = id0; this.id1 = id1; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AsLink)) return false; + AsLink asLink = (AsLink) o; + return as0 == asLink.as0 && as1 == asLink.as1 && id0 == asLink.id0 && id1 == asLink.id1; + } + + @Override + public int hashCode() { + return Objects.hash(as0, as1, id0, id1); + } } private static void analyze(Seg.SegmentsResponse response) throws IOException { @@ -159,8 +167,8 @@ private static void analyze(Seg.SegmentsResponse response) throws IOException { // This is a bit weird, but it works. AsLink link = new AsLink(asPrev.isdAs, isdAs, idPrev, id1); asLinks.add(link); -// as0.addLink(id0, link); -// as1.addLink(id1, link); + // as0.addLink(id0, link); + // as1.addLink(id1, link); } asPrev = as0; idPrev = id0; @@ -175,7 +183,7 @@ private static void write(Map asMap, Set asLinks) throws I FileWriter writer = new FileWriter("mytopo.topo"); String NL = System.lineSeparator(); - writer.append("--- # My Topology"); + writer.append("--- # My Topology").append(NL); writer.append("ASes:").append(NL); for (AsInfo as : asMap.values()) { writer.append(" \"").append(ScionUtil.toStringIA(as.isdAs)).append("\":").append(NL); From d1f5306d962d90103c87c25e7b8477b176af0570 Mon Sep 17 00:00:00 2001 From: tzaeschke Date: Mon, 7 Oct 2024 17:43:12 +0200 Subject: [PATCH 16/18] Fixed generated file --- default-ihaquwv8.png | Bin 0 -> 126021 bytes mytopo-8w67kdb8.png | Bin 0 -> 227440 bytes mytopo.topo | 106 ++++++- .../scion/jpan/ProtobufSegmentMapperDemo.java | 17 +- .../org/scion/jpan/demo/ShowpathsDemo.java | 3 +- .../scion/jpan/demo/TopologyMapperDemo.java | 275 ++++++++++++++++++ 6 files changed, 381 insertions(+), 20 deletions(-) create mode 100644 default-ihaquwv8.png create mode 100644 mytopo-8w67kdb8.png create mode 100644 src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java diff --git a/default-ihaquwv8.png b/default-ihaquwv8.png new file mode 100644 index 0000000000000000000000000000000000000000..801143ae4962c5d5dcf097eccce877381283bf76 GIT binary patch literal 126021 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�f;l8~GCLh#nkc;5PKFq2Z(_jHNVu)FTz^ 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 literal 0 HcmV?d00001 diff --git a/mytopo-8w67kdb8.png b/mytopo-8w67kdb8.png new file mode 100644 index 0000000000000000000000000000000000000000..784f9ece5c4a67902c8c03eba8972322844344fd GIT binary patch literal 227440 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

Commented out lines show alternative ways to connect or alternative destinations. + */ +public class TopologyMapperDemo { + + public static boolean PRINT = true; + private static Network NETWORK = Network.PRODUCTION; + private final int localPort; + + public enum Network { + JUNIT_MOCK, // SCION Java JUnit mock network + SCION_PROTO, // Try to connect to scionproto networks, e.g. "tiny" + PRODUCTION // production network + } + + public static void init(boolean print, TopologyMapperDemo.Network network) { + PRINT = print; + NETWORK = network; + } + + public TopologyMapperDemo() { + this(12345); // Any port is fine unless we connect to a dispatcher network + } + + public TopologyMapperDemo(int localPort) { + this.localPort = localPort; + } + + public static void main(String[] args) throws IOException { + switch (NETWORK) { + case JUNIT_MOCK: { + DemoTopology.configureMock(); + MockDNS.install("1-ff00:0:112", "ip6-localhost", "::1"); + TopologyMapperDemo demo = new TopologyMapperDemo(); + demo.runDemo(DemoConstants.ia110); + DemoTopology.shutDown(); + break; + } + case SCION_PROTO: { + // ./bazel-bin/scion/cmd/scion/scion_/scion showpaths 2-ff00:0:222 --sciond 127.0.0.100:30255 + + // Use scenario builder to get access to relevant IP addresses + Scenario scenario = Scenario.readFrom("topologies/scionproto-default"); + // long srcIsdAs = ScionUtil.parseIA("2-ff00:0:212"); + //long srcIsdAs = ScionUtil.parseIA("1-ff00:0:132"); // TODO FIX!!! + long srcIsdAs = ScionUtil.parseIA("1-ff00:0:133"); + long dstIsdAs = ScionUtil.parseIA("2-ff00:0:222"); + + if (!true) { + // Alternative #1: Bootstrap from topo file + System.setProperty(Constants.PROPERTY_BOOTSTRAP_TOPO_FILE, "topologies/scionproto-default/ASff00_0_212/topology.json"); + } else { + // Alternative #2: Bootstrap from SCION daemon + System.setProperty(Constants.PROPERTY_DAEMON, scenario.getDaemon(srcIsdAs)); + } + +// // System.setProperty(Constants.PROPERTY_BOOTSTRAP_TOPO_FILE, +// // "topologies/minimal/ASff00_0_1111/topology.json"); +// //System.setProperty(Constants.PROPERTY_DAEMON, "[fd00:f00d:cafe::7f00:33]:31060"); // 0;132 +// System.setProperty(Constants.PROPERTY_DAEMON, "127.0.0.99:31066"); // 0:133 + TopologyMapperDemo demo = new TopologyMapperDemo(); + //demo.runDemo(ScionUtil.parseIA("2-ff00:0:211")); + demo.runDemo(ScionUtil.parseIA("2-ff00:0:222")); + break; + } + case PRODUCTION: { + // Local port must be 30041 for networks that expect a dispatcher + TopologyMapperDemo demo = new TopologyMapperDemo(Constants.DISPATCHER_PORT); + demo.runDemo(ScionUtil.parseIA("64-2:0:28")); + // demo.runDemo(DemoConstants.iaAnapayaHK); + // demo.runDemo(DemoConstants.iaOVGU); + break; + } + } + Scion.closeDefault(); + } + + private void runDemo(long destinationIA) throws IOException { + ScionService service = Scion.defaultService(); + // dummy address + InetSocketAddress destinationAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 12345); + List paths = service.getPaths(destinationIA, destinationAddress); + if (paths.isEmpty()) { + String src = ScionUtil.toStringIA(service.getLocalIsdAs()); + String dst = ScionUtil.toStringIA(destinationIA); + throw new IOException("No path found from " + src + " to " + dst); + } + + println("Listening on port " + localPort + " ..."); + println("Available paths to " + ScionUtil.toStringIA(destinationIA)); + + int id = 0; + for (Path path : paths) { + PathMetadata meta = path.getMetadata(); + println("[" + id++ + "] Hops: " + ScionUtil.toStringPath(meta)); + } + analyze(paths); + } + + private static void println(String msg) { + if (PRINT) { + System.out.println(msg); + } + } + + private static class AsInfo { + final long isdAs; + final Map links = new HashMap<>(); + + AsInfo(long isdAs) { + this.isdAs = isdAs; + } + + public void addLink(long id, AsLink link) { + links.put(id, link); + } + } + + private static class AsLink { + private final long as0; + private final long as1; + private final long id0; + private final long id1; + + public AsLink(long isdAs, long nextIsdAs, long id0, long id1) { + this.as0 = isdAs; + this.as1 = nextIsdAs; + this.id0 = id0; + this.id1 = id1; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AsLink)) { + return false; + } + AsLink asLink = (AsLink) o; + return as0 == asLink.as0 && as1 == asLink.as1 && id0 == asLink.id0 && id1 == asLink.id1; + } + + @Override + public int hashCode() { + return Objects.hash(as0, as1, id0, id1); + } + } + + private static void analyze(List paths) throws IOException { + Map asMap = new HashMap<>(); + Set asLinks = new HashSet<>(); + for (Path p : paths) { + PathMetadata pm = p.getMetadata(); + int nInterfaces = pm.getInterfacesList().size(); + AsInfo asPrev = null; + long idPrev = -1; + + for (int i = 0; i < nInterfaces; i++) { + PathMetadata.PathInterface pIf = pm.getInterfacesList().get(i); + + if (i % 2 == 0) { + long isdAs = pIf.getIsdAs(); + asPrev = asMap.computeIfAbsent(isdAs, l -> l > 0 ? new AsInfo(l) : null); + idPrev = pIf.getId(); + // sb.append(ScionUtil.toStringIA(pIf.getIsdAs())).append(" "); + // sb.append(pIf.getId()).append(">"); + } else { + long isdAs = pIf.getIsdAs(); + long id1 = pIf.getId(); + AsLink link = new AsLink(asPrev.isdAs, isdAs, idPrev, id1); + asLinks.add(link); + // sb.append(pIf.getId()).append(" "); + } + } + } + + write(asMap, asLinks); + } + + private static void write(Map asMap, Set asLinks) throws IOException { + // write + FileWriter writer = new FileWriter("mytopo.topo"); + + String NL = System.lineSeparator(); + writer.append("--- # My Topology").append(NL); + writer.append("ASes:").append(NL); + for (AsInfo as : asMap.values()) { + writer.append(" \"").append(ScionUtil.toStringIA(as.isdAs)).append("\":").append(NL); + if (coreMap.contains(as.isdAs)) { + writer.append(" core: true").append(NL); + writer.append(" voting: true").append(NL); + writer.append(" authoritative: true").append(NL); + } + if (issuingMap.contains(as.isdAs)) { + writer.append(" issuing: true").append(NL); + } else { + writer.append(" cert_issuer: 1-ff00:0:210").append(NL); // TODO + } + } + writer.append("links:").append(NL); + // - {a: "1-ff00:0:1001#21", b: "1-ff00:0:1002#11", linkAtoB: CORE} + for (AsLink l : asLinks) { + writer.append(" - {a: \"").append(ScionUtil.toStringIA(l.as0)).append("#").append(String.valueOf(l.id0)); + writer.append("\", b: \"").append(ScionUtil.toStringIA(l.as1)).append("#").append(String.valueOf(l.id1)); + writer.append("\", linkAtoB: CORE}").append(NL); + } + + writer.flush(); + writer.close(); + } + + private static final HashSet coreMap = new HashSet<>(); + private static final HashSet issuingMap = new HashSet<>(); + + static { +// 64 - 559 // SWITCH CH Core +// 64 - 3303 // Swisscom CH Core, Issuing +// 64 - 6730 // Sunrise CH Core +// 64 - 12350 // VTX CH Core +// 64 - 13030 // Init7 CH Core +// 64 - 15623 // Cyberlink Core +// 64 - 2:0:13 // Anapaya CONNECT Zurich Core, Issuing +// 64 - 2:0:23 // InterCloud CH Zurich Core +// 64 - 2:0:56 // Armasuisse Andermatt Core + coreMap.add(ScionUtil.parseIA("64-559")); // SWITCH CH Core + coreMap.add(ScionUtil.parseIA("64-3303")); // Swisscom CH Core, Issuing + issuingMap.add(ScionUtil.parseIA("64-3303")); // Swisscom CH Core, Issuing + coreMap.add(ScionUtil.parseIA("64-6730")); // Sunrise CH Core + coreMap.add(ScionUtil.parseIA("64-12350")); // VTX CH Core + coreMap.add(ScionUtil.parseIA("64-13030")); // Init7 CH Core + coreMap.add(ScionUtil.parseIA("64-15623")); // Cyberlink Core + coreMap.add(ScionUtil.parseIA("64-2:0:13")); // Anapaya CONNECT Zurich Core, Issuing + issuingMap.add(ScionUtil.parseIA("64-2:0:13")); // Anapaya CONNECT Zurich Core, Issuing + coreMap.add(ScionUtil.parseIA("64-2:0:23")); // InterCloud CH Zurich Core + coreMap.add(ScionUtil.parseIA("64-2:0:56")); // Armasuisse Andermatt Core + + } +} From 2792b8565a50e04c93fe462e5175d88d131827e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Tue, 8 Oct 2024 16:27:05 +0200 Subject: [PATCH 17/18] Fixes --- mytopo.topo | 45 +- .../scion/jpan/demo/TopologyMapperDemo.java | 449 ++++++++++-------- 2 files changed, 255 insertions(+), 239 deletions(-) diff --git a/mytopo.topo b/mytopo.topo index 269a68b5..f4004604 100644 --- a/mytopo.topo +++ b/mytopo.topo @@ -4,14 +4,14 @@ ASes: core: true voting: true authoritative: true - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 "64-2:0:13": core: true voting: true authoritative: true issuing: true "64-0:0:e816": - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 "64-0:0:ce7": core: true voting: true @@ -21,91 +21,76 @@ ASes: core: true voting: true authoritative: true - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 "64-0:0:1a4a": core: true voting: true authoritative: true - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 "64-2:0:9": - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 "64-0:0:303e": core: true voting: true authoritative: true - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 "64-0:0:22f": core: true voting: true authoritative: true - cert_issuer: 1-ff00:0:210 + cert_issuer: 64-2:0:13 links: - {a: "64-0:0:ce7#19", b: "64-0:0:3d07#5", linkAtoB: CORE} - {a: "64-0:0:303e#5", b: "64-0:0:3d07#1", linkAtoB: CORE} - {a: "64-0:0:ce7#22", b: "64-0:0:303e#7", linkAtoB: CORE} - - {a: "64-2:0:13#11", b: "64-0:0:1a4a#3", linkAtoB: CORE} - {a: "64-0:0:ce7#10", b: "64-0:0:1a4a#8", linkAtoB: CORE} - {a: "64-0:0:3d07#2", b: "64-2:0:13#24", linkAtoB: CORE} - - {a: "64-2:0:13#23", b: "64-0:0:3d07#20", linkAtoB: CORE} - - {a: "64-2:0:13#33", b: "64-0:0:e816#8", linkAtoB: CORE} - - {a: "64-0:0:1a4a#8", b: "64-0:0:ce7#10", linkAtoB: CORE} - {a: "64-0:0:3d07#11", b: "64-2:0:13#29", linkAtoB: CORE} - - {a: "64-0:0:3d07#27", b: "64-2:0:13#46", linkAtoB: CORE} - {a: "64-0:0:3d07#3", b: "64-2:0:13#22", linkAtoB: CORE} + - {a: "64-0:0:3d07#27", b: "64-2:0:13#46", linkAtoB: CORE} - {a: "64-0:0:1a4a#22", b: "64-0:0:3d07#13", linkAtoB: CORE} - - {a: "64-0:0:3d07#5", b: "64-0:0:ce7#19", linkAtoB: CORE} - - {a: "64-2:0:13#7", b: "64-0:0:ce7#2", linkAtoB: CORE} - {a: "64-0:0:22f#17", b: "64-0:0:ce7#1", linkAtoB: CORE} - - {a: "64-2:0:23#7", b: "64-2:0:13#30", linkAtoB: CORE} + - {a: "64-2:0:13#19", b: "64-2:0:23#2", linkAtoB: CORE} - {a: "64-0:0:e816#35", b: "64-2:0:28#4", linkAtoB: CORE} - {a: "64-0:0:3d07#17", b: "64-2:0:28#1", linkAtoB: CORE} + - {a: "64-0:0:e816#8", b: "64-2:0:13#33", linkAtoB: CORE} - {a: "64-0:0:22f#26", b: "64-0:0:303e#4", linkAtoB: CORE} - {a: "64-0:0:22f#22", b: "64-0:0:3d07#9", linkAtoB: CORE} - {a: "64-0:0:3d07#20", b: "64-2:0:13#23", linkAtoB: CORE} - - {a: "64-0:0:3d07#13", b: "64-0:0:1a4a#22", linkAtoB: CORE} - {a: "64-0:0:3d07#24", b: "64-0:0:e816#3", linkAtoB: CORE} - {a: "64-0:0:ce7#20", b: "64-0:0:3d07#12", linkAtoB: CORE} - {a: "64-0:0:ce7#11", b: "64-0:0:1a4a#11", linkAtoB: CORE} - {a: "64-0:0:22f#31", b: "64-2:0:13#31", linkAtoB: CORE} - {a: "64-0:0:1a4a#3", b: "64-2:0:13#11", linkAtoB: CORE} - - {a: "64-2:0:9#1", b: "64-0:0:22f#5", linkAtoB: CORE} - {a: "64-0:0:22f#20", b: "64-2:0:13#16", linkAtoB: CORE} - - {a: "64-0:0:303e#7", b: "64-0:0:ce7#22", linkAtoB: CORE} - - {a: "64-0:0:3d07#12", b: "64-0:0:ce7#20", linkAtoB: CORE} - {a: "64-0:0:3d07#28", b: "64-2:0:13#44", linkAtoB: CORE} - {a: "64-0:0:3d07#18", b: "64-2:0:28#2", linkAtoB: CORE} - {a: "64-0:0:1a4a#35", b: "64-0:0:e816#9", linkAtoB: CORE} - {a: "64-0:0:ce7#2", b: "64-2:0:13#7", linkAtoB: CORE} - {a: "64-0:0:22f#21", b: "64-0:0:3d07#8", linkAtoB: CORE} - - {a: "64-2:0:13#22", b: "64-0:0:3d07#3", linkAtoB: CORE} - - {a: "64-2:0:23#4", b: "64-2:0:13#21", linkAtoB: CORE} - - {a: "64-0:0:3d07#16", b: "64-0:0:1a4a#27", linkAtoB: CORE} - {a: "64-0:0:22f#4", b: "64-2:0:13#15", linkAtoB: CORE} - {a: "64-0:0:1a4a#34", b: "64-0:0:e816#4", linkAtoB: CORE} - {a: "64-0:0:3d07#23", b: "64-0:0:e816#1", linkAtoB: CORE} - - {a: "64-2:0:13#9", b: "64-0:0:1a4a#1", linkAtoB: CORE} - - {a: "64-0:0:1a4a#11", b: "64-0:0:ce7#11", linkAtoB: CORE} + - {a: "64-2:0:13#30", b: "64-2:0:23#7", linkAtoB: CORE} - {a: "64-0:0:22f#35", b: "64-0:0:303e#20003", linkAtoB: CORE} - - {a: "64-2:0:9#2", b: "64-0:0:22f#6", linkAtoB: CORE} - {a: "64-0:0:303e#2", b: "64-2:0:13#28", linkAtoB: CORE} - {a: "64-0:0:22f#19", b: "64-0:0:ce7#9", linkAtoB: CORE} + - {a: "64-0:0:22f#5", b: "64-2:0:9#1", linkAtoB: CORE} + - {a: "64-2:0:13#21", b: "64-2:0:23#4", linkAtoB: CORE} - {a: "64-0:0:3d07#29", b: "64-2:0:13#45", linkAtoB: CORE} - {a: "64-0:0:22f#34", b: "64-0:0:e816#5", linkAtoB: CORE} - {a: "64-0:0:22f#16", b: "64-0:0:1a4a#10", linkAtoB: CORE} - - {a: "64-2:0:13#29", b: "64-0:0:3d07#11", linkAtoB: CORE} - {a: "64-0:0:303e#6", b: "64-0:0:3d07#10", linkAtoB: CORE} - {a: "64-0:0:3d07#22", b: "64-0:0:e816#2", linkAtoB: CORE} - - {a: "64-2:0:13#18", b: "64-0:0:ce7#4", linkAtoB: CORE} - {a: "64-0:0:22f#36", b: "64-0:0:303e#20004", linkAtoB: CORE} - {a: "64-0:0:303e#1", b: "64-2:0:13#26", linkAtoB: CORE} - {a: "64-0:0:1a4a#1", b: "64-2:0:13#9", linkAtoB: CORE} - {a: "64-0:0:ce7#4", b: "64-2:0:13#18", linkAtoB: CORE} + - {a: "64-0:0:22f#6", b: "64-2:0:9#2", linkAtoB: CORE} - {a: "64-0:0:1a4a#27", b: "64-0:0:3d07#16", linkAtoB: CORE} - - {a: "64-2:0:13#34", b: "64-0:0:e816#7", linkAtoB: CORE} - {a: "64-0:0:e816#34", b: "64-2:0:28#3", linkAtoB: CORE} - {a: "64-0:0:22f#15", b: "64-0:0:1a4a#9", linkAtoB: CORE} + - {a: "64-0:0:e816#7", b: "64-2:0:13#34", linkAtoB: CORE} - {a: "64-0:0:22f#25", b: "64-0:0:303e#3", linkAtoB: CORE} - - {a: "64-2:0:13#24", b: "64-0:0:3d07#2", linkAtoB: CORE} - {a: "64-0:0:ce7#16", b: "64-2:0:23#5", linkAtoB: CORE} - {a: "64-0:0:22f#33", b: "64-0:0:e816#6", linkAtoB: CORE} - - {a: "64-2:0:23#2", b: "64-2:0:13#19", linkAtoB: CORE} diff --git a/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java b/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java index ad253e79..218f63d3 100644 --- a/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java +++ b/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java @@ -39,237 +39,268 @@ */ public class TopologyMapperDemo { - public static boolean PRINT = true; - private static Network NETWORK = Network.PRODUCTION; - private final int localPort; - - public enum Network { - JUNIT_MOCK, // SCION Java JUnit mock network - SCION_PROTO, // Try to connect to scionproto networks, e.g. "tiny" - PRODUCTION // production network + public static boolean SIMPLIFY = true; + public static boolean PRINT = true; + private static Network NETWORK = Network.PRODUCTION; + private final int localPort; + + public enum Network { + JUNIT_MOCK, // SCION Java JUnit mock network + SCION_PROTO, // Try to connect to scionproto networks, e.g. "tiny" + PRODUCTION // production network + } + + public static void init(boolean print, TopologyMapperDemo.Network network) { + PRINT = print; + NETWORK = network; + } + + public TopologyMapperDemo() { + this(12345); // Any port is fine unless we connect to a dispatcher network + } + + public TopologyMapperDemo(int localPort) { + this.localPort = localPort; + } + + public static void main(String[] args) throws IOException { + switch (NETWORK) { + case JUNIT_MOCK: + { + DemoTopology.configureMock(); + MockDNS.install("1-ff00:0:112", "ip6-localhost", "::1"); + TopologyMapperDemo demo = new TopologyMapperDemo(); + demo.runDemo(DemoConstants.ia110); + DemoTopology.shutDown(); + break; + } + case SCION_PROTO: + { + // ./bazel-bin/scion/cmd/scion/scion_/scion showpaths 2-ff00:0:222 --sciond + // 127.0.0.100:30255 + + // Use scenario builder to get access to relevant IP addresses + Scenario scenario = Scenario.readFrom("topologies/scionproto-default"); + // long srcIsdAs = ScionUtil.parseIA("2-ff00:0:212"); + // long srcIsdAs = ScionUtil.parseIA("1-ff00:0:132"); // TODO FIX!!! + long srcIsdAs = ScionUtil.parseIA("1-ff00:0:133"); + long dstIsdAs = ScionUtil.parseIA("2-ff00:0:222"); + + if (false) { + // Alternative #1: Bootstrap from topo file + System.setProperty( + Constants.PROPERTY_BOOTSTRAP_TOPO_FILE, + "topologies/scionproto-default/ASff00_0_212/topology.json"); + } else { + // Alternative #2: Bootstrap from SCION daemon + System.setProperty(Constants.PROPERTY_DAEMON, scenario.getDaemon(srcIsdAs)); + } + + // // System.setProperty(Constants.PROPERTY_BOOTSTRAP_TOPO_FILE, + // // "topologies/minimal/ASff00_0_1111/topology.json"); + // //System.setProperty(Constants.PROPERTY_DAEMON, + // "[fd00:f00d:cafe::7f00:33]:31060"); // 0;132 + // System.setProperty(Constants.PROPERTY_DAEMON, "127.0.0.99:31066"); // 0:133 + TopologyMapperDemo demo = new TopologyMapperDemo(); + // demo.runDemo(ScionUtil.parseIA("2-ff00:0:211")); + demo.runDemo(ScionUtil.parseIA("2-ff00:0:222")); + break; + } + case PRODUCTION: + { + // Local port must be 30041 for networks that expect a dispatcher + TopologyMapperDemo demo = new TopologyMapperDemo(Constants.DISPATCHER_PORT); + demo.runDemo(ScionUtil.parseIA("64-2:0:28")); + // demo.runDemo(DemoConstants.iaAnapayaHK); + // demo.runDemo(DemoConstants.iaOVGU); + break; + } } - - public static void init(boolean print, TopologyMapperDemo.Network network) { - PRINT = print; - NETWORK = network; + Scion.closeDefault(); + } + + private void runDemo(long destinationIA) throws IOException { + ScionService service = Scion.defaultService(); + // dummy address + InetSocketAddress destinationAddress = + new InetSocketAddress(InetAddress.getLoopbackAddress(), 12345); + List paths = service.getPaths(destinationIA, destinationAddress); + if (paths.isEmpty()) { + String src = ScionUtil.toStringIA(service.getLocalIsdAs()); + String dst = ScionUtil.toStringIA(destinationIA); + throw new IOException("No path found from " + src + " to " + dst); } - public TopologyMapperDemo() { - this(12345); // Any port is fine unless we connect to a dispatcher network - } + println("Listening on port " + localPort + " ..."); + println("Available paths to " + ScionUtil.toStringIA(destinationIA)); - public TopologyMapperDemo(int localPort) { - this.localPort = localPort; + int id = 0; + for (Path path : paths) { + PathMetadata meta = path.getMetadata(); + println("[" + id++ + "] Hops: " + ScionUtil.toStringPath(meta)); } + analyze(paths); + } - public static void main(String[] args) throws IOException { - switch (NETWORK) { - case JUNIT_MOCK: { - DemoTopology.configureMock(); - MockDNS.install("1-ff00:0:112", "ip6-localhost", "::1"); - TopologyMapperDemo demo = new TopologyMapperDemo(); - demo.runDemo(DemoConstants.ia110); - DemoTopology.shutDown(); - break; - } - case SCION_PROTO: { - // ./bazel-bin/scion/cmd/scion/scion_/scion showpaths 2-ff00:0:222 --sciond 127.0.0.100:30255 - - // Use scenario builder to get access to relevant IP addresses - Scenario scenario = Scenario.readFrom("topologies/scionproto-default"); - // long srcIsdAs = ScionUtil.parseIA("2-ff00:0:212"); - //long srcIsdAs = ScionUtil.parseIA("1-ff00:0:132"); // TODO FIX!!! - long srcIsdAs = ScionUtil.parseIA("1-ff00:0:133"); - long dstIsdAs = ScionUtil.parseIA("2-ff00:0:222"); - - if (!true) { - // Alternative #1: Bootstrap from topo file - System.setProperty(Constants.PROPERTY_BOOTSTRAP_TOPO_FILE, "topologies/scionproto-default/ASff00_0_212/topology.json"); - } else { - // Alternative #2: Bootstrap from SCION daemon - System.setProperty(Constants.PROPERTY_DAEMON, scenario.getDaemon(srcIsdAs)); - } - -// // System.setProperty(Constants.PROPERTY_BOOTSTRAP_TOPO_FILE, -// // "topologies/minimal/ASff00_0_1111/topology.json"); -// //System.setProperty(Constants.PROPERTY_DAEMON, "[fd00:f00d:cafe::7f00:33]:31060"); // 0;132 -// System.setProperty(Constants.PROPERTY_DAEMON, "127.0.0.99:31066"); // 0:133 - TopologyMapperDemo demo = new TopologyMapperDemo(); - //demo.runDemo(ScionUtil.parseIA("2-ff00:0:211")); - demo.runDemo(ScionUtil.parseIA("2-ff00:0:222")); - break; - } - case PRODUCTION: { - // Local port must be 30041 for networks that expect a dispatcher - TopologyMapperDemo demo = new TopologyMapperDemo(Constants.DISPATCHER_PORT); - demo.runDemo(ScionUtil.parseIA("64-2:0:28")); - // demo.runDemo(DemoConstants.iaAnapayaHK); - // demo.runDemo(DemoConstants.iaOVGU); - break; - } - } - Scion.closeDefault(); + private static void println(String msg) { + if (PRINT) { + System.out.println(msg); } + } - private void runDemo(long destinationIA) throws IOException { - ScionService service = Scion.defaultService(); - // dummy address - InetSocketAddress destinationAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 12345); - List paths = service.getPaths(destinationIA, destinationAddress); - if (paths.isEmpty()) { - String src = ScionUtil.toStringIA(service.getLocalIsdAs()); - String dst = ScionUtil.toStringIA(destinationIA); - throw new IOException("No path found from " + src + " to " + dst); - } + private static class AsInfo { + final long isdAs; + final Map links = new HashMap<>(); - println("Listening on port " + localPort + " ..."); - println("Available paths to " + ScionUtil.toStringIA(destinationIA)); - - int id = 0; - for (Path path : paths) { - PathMetadata meta = path.getMetadata(); - println("[" + id++ + "] Hops: " + ScionUtil.toStringPath(meta)); - } - analyze(paths); + AsInfo(long isdAs) { + this.isdAs = isdAs; } - private static void println(String msg) { - if (PRINT) { - System.out.println(msg); - } + public void addLink(long id, AsLink link) { + links.put(id, link); + } + } + + private static class AsLink { + private final long as0; + private final long as1; + private final long id0; + private final long id1; + + public AsLink(long isdAs0, long isdAs1, long id0, long id1) { + if (isdAs0 < isdAs1) { + this.as0 = isdAs0; + this.as1 = isdAs1; + this.id0 = id0; + this.id1 = id1; + } else { + this.as0 = isdAs1; + this.as1 = isdAs0; + this.id0 = id1; + this.id1 = id0; + } } - private static class AsInfo { - final long isdAs; - final Map links = new HashMap<>(); - - AsInfo(long isdAs) { - this.isdAs = isdAs; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AsLink)) { + return false; + } + AsLink asLink = (AsLink) o; + return as0 == asLink.as0 && as1 == asLink.as1 && id0 == asLink.id0 && id1 == asLink.id1; + } - public void addLink(long id, AsLink link) { - links.put(id, link); + @Override + public int hashCode() { + return Objects.hash(as0, as1, id0, id1); + } + } + + private static void analyze(List paths) throws IOException { + Map asMap = new HashMap<>(); + Set asLinks = new HashSet<>(); + for (Path p : paths) { + PathMetadata pm = p.getMetadata(); + int nInterfaces = pm.getInterfacesList().size(); + AsInfo asPrev = null; + long idPrev = -1; + + for (int i = 0; i < nInterfaces; i++) { + PathMetadata.PathInterface pIf = pm.getInterfacesList().get(i); + + if (i % 2 == 0) { + long isdAs = pIf.getIsdAs(); + asPrev = asMap.computeIfAbsent(isdAs, l -> l > 0 ? new AsInfo(l) : null); + idPrev = pIf.getId(); + // sb.append(ScionUtil.toStringIA(pIf.getIsdAs())).append(" "); + // sb.append(pIf.getId()).append(">"); + } else { + long isdAs = pIf.getIsdAs(); + long id1 = pIf.getId(); + AsLink link = new AsLink(asPrev.isdAs, isdAs, idPrev, id1); + asLinks.add(link); + // sb.append(pIf.getId()).append(" "); } + } } - private static class AsLink { - private final long as0; - private final long as1; - private final long id0; - private final long id1; - - public AsLink(long isdAs, long nextIsdAs, long id0, long id1) { - this.as0 = isdAs; - this.as1 = nextIsdAs; - this.id0 = id0; - this.id1 = id1; - } + write(asMap, asLinks); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof AsLink)) { - return false; - } - AsLink asLink = (AsLink) o; - return as0 == asLink.as0 && as1 == asLink.as1 && id0 == asLink.id0 && id1 == asLink.id1; - } + private static void write(Map asMap, Set asLinks) throws IOException { + // write + FileWriter writer = new FileWriter("mytopo.topo"); - @Override - public int hashCode() { - return Objects.hash(as0, as1, id0, id1); - } + String issuer = "1-ff00:0:210"; + for (AsInfo as : asMap.values()) { + if (issuingMap.contains(as.isdAs)) { + issuer = ScionUtil.toStringIA(as.isdAs); + break; + } } - private static void analyze(List paths) throws IOException { - Map asMap = new HashMap<>(); - Set asLinks = new HashSet<>(); - for (Path p : paths) { - PathMetadata pm = p.getMetadata(); - int nInterfaces = pm.getInterfacesList().size(); - AsInfo asPrev = null; - long idPrev = -1; - - for (int i = 0; i < nInterfaces; i++) { - PathMetadata.PathInterface pIf = pm.getInterfacesList().get(i); - - if (i % 2 == 0) { - long isdAs = pIf.getIsdAs(); - asPrev = asMap.computeIfAbsent(isdAs, l -> l > 0 ? new AsInfo(l) : null); - idPrev = pIf.getId(); - // sb.append(ScionUtil.toStringIA(pIf.getIsdAs())).append(" "); - // sb.append(pIf.getId()).append(">"); - } else { - long isdAs = pIf.getIsdAs(); - long id1 = pIf.getId(); - AsLink link = new AsLink(asPrev.isdAs, isdAs, idPrev, id1); - asLinks.add(link); - // sb.append(pIf.getId()).append(" "); - } - } - } - - write(asMap, asLinks); + String NL = System.lineSeparator(); + writer.append("--- # My Topology").append(NL); + writer.append("ASes:").append(NL); + for (AsInfo as : asMap.values()) { + writer.append(" \"").append(ScionUtil.toStringIA(as.isdAs)).append("\":").append(NL); + if (coreMap.contains(as.isdAs)) { + writer.append(" core: true").append(NL); + writer.append(" voting: true").append(NL); + writer.append(" authoritative: true").append(NL); + } + if (issuingMap.contains(as.isdAs)) { + writer.append(" issuing: true").append(NL); + } else { + writer.append(" cert_issuer: ").append(issuer).append(NL); // TODO + } } - - private static void write(Map asMap, Set asLinks) throws IOException { - // write - FileWriter writer = new FileWriter("mytopo.topo"); - - String NL = System.lineSeparator(); - writer.append("--- # My Topology").append(NL); - writer.append("ASes:").append(NL); - for (AsInfo as : asMap.values()) { - writer.append(" \"").append(ScionUtil.toStringIA(as.isdAs)).append("\":").append(NL); - if (coreMap.contains(as.isdAs)) { - writer.append(" core: true").append(NL); - writer.append(" voting: true").append(NL); - writer.append(" authoritative: true").append(NL); - } - if (issuingMap.contains(as.isdAs)) { - writer.append(" issuing: true").append(NL); - } else { - writer.append(" cert_issuer: 1-ff00:0:210").append(NL); // TODO - } - } - writer.append("links:").append(NL); - // - {a: "1-ff00:0:1001#21", b: "1-ff00:0:1002#11", linkAtoB: CORE} - for (AsLink l : asLinks) { - writer.append(" - {a: \"").append(ScionUtil.toStringIA(l.as0)).append("#").append(String.valueOf(l.id0)); - writer.append("\", b: \"").append(ScionUtil.toStringIA(l.as1)).append("#").append(String.valueOf(l.id1)); - writer.append("\", linkAtoB: CORE}").append(NL); - } - - writer.flush(); - writer.close(); + writer.append("links:").append(NL); + // - {a: "1-ff00:0:1001#21", b: "1-ff00:0:1002#11", linkAtoB: CORE} + for (AsLink l : asLinks) { + writer + .append(" - {a: \"") + .append(ScionUtil.toStringIA(l.as0)) + .append("#") + .append(String.valueOf(l.id0)); + writer + .append("\", b: \"") + .append(ScionUtil.toStringIA(l.as1)) + .append("#") + .append(String.valueOf(l.id1)); + writer.append("\", linkAtoB: CORE}").append(NL); } - private static final HashSet coreMap = new HashSet<>(); - private static final HashSet issuingMap = new HashSet<>(); - - static { -// 64 - 559 // SWITCH CH Core -// 64 - 3303 // Swisscom CH Core, Issuing -// 64 - 6730 // Sunrise CH Core -// 64 - 12350 // VTX CH Core -// 64 - 13030 // Init7 CH Core -// 64 - 15623 // Cyberlink Core -// 64 - 2:0:13 // Anapaya CONNECT Zurich Core, Issuing -// 64 - 2:0:23 // InterCloud CH Zurich Core -// 64 - 2:0:56 // Armasuisse Andermatt Core - coreMap.add(ScionUtil.parseIA("64-559")); // SWITCH CH Core - coreMap.add(ScionUtil.parseIA("64-3303")); // Swisscom CH Core, Issuing - issuingMap.add(ScionUtil.parseIA("64-3303")); // Swisscom CH Core, Issuing - coreMap.add(ScionUtil.parseIA("64-6730")); // Sunrise CH Core - coreMap.add(ScionUtil.parseIA("64-12350")); // VTX CH Core - coreMap.add(ScionUtil.parseIA("64-13030")); // Init7 CH Core - coreMap.add(ScionUtil.parseIA("64-15623")); // Cyberlink Core - coreMap.add(ScionUtil.parseIA("64-2:0:13")); // Anapaya CONNECT Zurich Core, Issuing - issuingMap.add(ScionUtil.parseIA("64-2:0:13")); // Anapaya CONNECT Zurich Core, Issuing - coreMap.add(ScionUtil.parseIA("64-2:0:23")); // InterCloud CH Zurich Core - coreMap.add(ScionUtil.parseIA("64-2:0:56")); // Armasuisse Andermatt Core - - } + writer.flush(); + writer.close(); + } + + private static final HashSet coreMap = new HashSet<>(); + private static final HashSet issuingMap = new HashSet<>(); + + static { + // 64 - 559 // SWITCH CH Core + // 64 - 3303 // Swisscom CH Core, Issuing + // 64 - 6730 // Sunrise CH Core + // 64 - 12350 // VTX CH Core + // 64 - 13030 // Init7 CH Core + // 64 - 15623 // Cyberlink Core + // 64 - 2:0:13 // Anapaya CONNECT Zurich Core, Issuing + // 64 - 2:0:23 // InterCloud CH Zurich Core + // 64 - 2:0:56 // Armasuisse Andermatt Core + coreMap.add(ScionUtil.parseIA("64-559")); // SWITCH CH Core + coreMap.add(ScionUtil.parseIA("64-3303")); // Swisscom CH Core, Issuing + issuingMap.add(ScionUtil.parseIA("64-3303")); // Swisscom CH Core, Issuing + coreMap.add(ScionUtil.parseIA("64-6730")); // Sunrise CH Core + coreMap.add(ScionUtil.parseIA("64-12350")); // VTX CH Core + coreMap.add(ScionUtil.parseIA("64-13030")); // Init7 CH Core + coreMap.add(ScionUtil.parseIA("64-15623")); // Cyberlink Core + coreMap.add(ScionUtil.parseIA("64-2:0:13")); // Anapaya CONNECT Zurich Core, Issuing + issuingMap.add(ScionUtil.parseIA("64-2:0:13")); // Anapaya CONNECT Zurich Core, Issuing + coreMap.add(ScionUtil.parseIA("64-2:0:23")); // InterCloud CH Zurich Core + coreMap.add(ScionUtil.parseIA("64-2:0:56")); // Armasuisse Andermatt Core + } } From 0701a4d7c7274d24c3b3a8a453a0e712b1dd93b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilmann=20Z=C3=A4schke?= Date: Tue, 8 Oct 2024 16:27:33 +0200 Subject: [PATCH 18/18] Fixes --- src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java b/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java index 218f63d3..e2adddb3 100644 --- a/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java +++ b/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java @@ -19,7 +19,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.*; - import org.scion.jpan.*; import org.scion.jpan.testutil.MockDNS; import org.scion.jpan.testutil.Scenario; @@ -242,7 +241,7 @@ private static void write(Map asMap, Set asLinks) throws I } } - String NL = System.lineSeparator(); + String NL = System.lineSeparator(); writer.append("--- # My Topology").append(NL); writer.append("ASes:").append(NL); for (AsInfo as : asMap.values()) {

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 literal 0 HcmV?d00001 diff --git a/mytopo.topo b/mytopo.topo index 92475db1..269a68b5 100644 --- a/mytopo.topo +++ b/mytopo.topo @@ -1,35 +1,111 @@ --- # My Topology ASes: - "1-ff00:0:130": + "64-2:0:23": core: true voting: true authoritative: true - issuing: true - "1-ff00:0:120": + cert_issuer: 1-ff00:0:210 + "64-2:0:13": core: true voting: true authoritative: true issuing: true - "1-ff00:0:110": + "64-0:0:e816": + cert_issuer: 1-ff00:0:210 + "64-0:0:ce7": core: true voting: true authoritative: true issuing: true - "2-ff00:0:220": + "64-0:0:3d07": core: true voting: true authoritative: true - issuing: true - "2-ff00:0:210": + cert_issuer: 1-ff00:0:210 + "64-0:0:1a4a": core: true voting: true authoritative: true - issuing: true + cert_issuer: 1-ff00:0:210 + "64-2:0:9": + cert_issuer: 1-ff00:0:210 + "64-0:0:303e": + core: true + voting: true + authoritative: true + cert_issuer: 1-ff00:0:210 + "64-0:0:22f": + core: true + voting: true + authoritative: true + cert_issuer: 1-ff00:0:210 links: - - {a: "1-ff00:0:120#6", b: "1-ff00:0:110#1", linkAtoB: CORE} - - {a: "1-ff00:0:120#1", b: "1-ff00:0:130#105", linkAtoB: CORE} - - {a: "1-ff00:0:130#104", b: "1-ff00:0:110#2", linkAtoB: CORE} - - {a: "2-ff00:0:220#501", b: "1-ff00:0:120#2", linkAtoB: CORE} - - {a: "2-ff00:0:220#502", b: "1-ff00:0:120#3", linkAtoB: CORE} - - {a: "2-ff00:0:210#450", b: "2-ff00:0:220#503", linkAtoB: CORE} - - {a: "2-ff00:0:210#453", b: "1-ff00:0:110#3", linkAtoB: CORE} + - {a: "64-0:0:ce7#19", b: "64-0:0:3d07#5", linkAtoB: CORE} + - {a: "64-0:0:303e#5", b: "64-0:0:3d07#1", linkAtoB: CORE} + - {a: "64-0:0:ce7#22", b: "64-0:0:303e#7", linkAtoB: CORE} + - {a: "64-2:0:13#11", b: "64-0:0:1a4a#3", linkAtoB: CORE} + - {a: "64-0:0:ce7#10", b: "64-0:0:1a4a#8", linkAtoB: CORE} + - {a: "64-0:0:3d07#2", b: "64-2:0:13#24", linkAtoB: CORE} + - {a: "64-2:0:13#23", b: "64-0:0:3d07#20", linkAtoB: CORE} + - {a: "64-2:0:13#33", b: "64-0:0:e816#8", linkAtoB: CORE} + - {a: "64-0:0:1a4a#8", b: "64-0:0:ce7#10", linkAtoB: CORE} + - {a: "64-0:0:3d07#11", b: "64-2:0:13#29", linkAtoB: CORE} + - {a: "64-0:0:3d07#27", b: "64-2:0:13#46", linkAtoB: CORE} + - {a: "64-0:0:3d07#3", b: "64-2:0:13#22", linkAtoB: CORE} + - {a: "64-0:0:1a4a#22", b: "64-0:0:3d07#13", linkAtoB: CORE} + - {a: "64-0:0:3d07#5", b: "64-0:0:ce7#19", linkAtoB: CORE} + - {a: "64-2:0:13#7", b: "64-0:0:ce7#2", linkAtoB: CORE} + - {a: "64-0:0:22f#17", b: "64-0:0:ce7#1", linkAtoB: CORE} + - {a: "64-2:0:23#7", b: "64-2:0:13#30", linkAtoB: CORE} + - {a: "64-0:0:e816#35", b: "64-2:0:28#4", linkAtoB: CORE} + - {a: "64-0:0:3d07#17", b: "64-2:0:28#1", linkAtoB: CORE} + - {a: "64-0:0:22f#26", b: "64-0:0:303e#4", linkAtoB: CORE} + - {a: "64-0:0:22f#22", b: "64-0:0:3d07#9", linkAtoB: CORE} + - {a: "64-0:0:3d07#20", b: "64-2:0:13#23", linkAtoB: CORE} + - {a: "64-0:0:3d07#13", b: "64-0:0:1a4a#22", linkAtoB: CORE} + - {a: "64-0:0:3d07#24", b: "64-0:0:e816#3", linkAtoB: CORE} + - {a: "64-0:0:ce7#20", b: "64-0:0:3d07#12", linkAtoB: CORE} + - {a: "64-0:0:ce7#11", b: "64-0:0:1a4a#11", linkAtoB: CORE} + - {a: "64-0:0:22f#31", b: "64-2:0:13#31", linkAtoB: CORE} + - {a: "64-0:0:1a4a#3", b: "64-2:0:13#11", linkAtoB: CORE} + - {a: "64-2:0:9#1", b: "64-0:0:22f#5", linkAtoB: CORE} + - {a: "64-0:0:22f#20", b: "64-2:0:13#16", linkAtoB: CORE} + - {a: "64-0:0:303e#7", b: "64-0:0:ce7#22", linkAtoB: CORE} + - {a: "64-0:0:3d07#12", b: "64-0:0:ce7#20", linkAtoB: CORE} + - {a: "64-0:0:3d07#28", b: "64-2:0:13#44", linkAtoB: CORE} + - {a: "64-0:0:3d07#18", b: "64-2:0:28#2", linkAtoB: CORE} + - {a: "64-0:0:1a4a#35", b: "64-0:0:e816#9", linkAtoB: CORE} + - {a: "64-0:0:ce7#2", b: "64-2:0:13#7", linkAtoB: CORE} + - {a: "64-0:0:22f#21", b: "64-0:0:3d07#8", linkAtoB: CORE} + - {a: "64-2:0:13#22", b: "64-0:0:3d07#3", linkAtoB: CORE} + - {a: "64-2:0:23#4", b: "64-2:0:13#21", linkAtoB: CORE} + - {a: "64-0:0:3d07#16", b: "64-0:0:1a4a#27", linkAtoB: CORE} + - {a: "64-0:0:22f#4", b: "64-2:0:13#15", linkAtoB: CORE} + - {a: "64-0:0:1a4a#34", b: "64-0:0:e816#4", linkAtoB: CORE} + - {a: "64-0:0:3d07#23", b: "64-0:0:e816#1", linkAtoB: CORE} + - {a: "64-2:0:13#9", b: "64-0:0:1a4a#1", linkAtoB: CORE} + - {a: "64-0:0:1a4a#11", b: "64-0:0:ce7#11", linkAtoB: CORE} + - {a: "64-0:0:22f#35", b: "64-0:0:303e#20003", linkAtoB: CORE} + - {a: "64-2:0:9#2", b: "64-0:0:22f#6", linkAtoB: CORE} + - {a: "64-0:0:303e#2", b: "64-2:0:13#28", linkAtoB: CORE} + - {a: "64-0:0:22f#19", b: "64-0:0:ce7#9", linkAtoB: CORE} + - {a: "64-0:0:3d07#29", b: "64-2:0:13#45", linkAtoB: CORE} + - {a: "64-0:0:22f#34", b: "64-0:0:e816#5", linkAtoB: CORE} + - {a: "64-0:0:22f#16", b: "64-0:0:1a4a#10", linkAtoB: CORE} + - {a: "64-2:0:13#29", b: "64-0:0:3d07#11", linkAtoB: CORE} + - {a: "64-0:0:303e#6", b: "64-0:0:3d07#10", linkAtoB: CORE} + - {a: "64-0:0:3d07#22", b: "64-0:0:e816#2", linkAtoB: CORE} + - {a: "64-2:0:13#18", b: "64-0:0:ce7#4", linkAtoB: CORE} + - {a: "64-0:0:22f#36", b: "64-0:0:303e#20004", linkAtoB: CORE} + - {a: "64-0:0:303e#1", b: "64-2:0:13#26", linkAtoB: CORE} + - {a: "64-0:0:1a4a#1", b: "64-2:0:13#9", linkAtoB: CORE} + - {a: "64-0:0:ce7#4", b: "64-2:0:13#18", linkAtoB: CORE} + - {a: "64-0:0:1a4a#27", b: "64-0:0:3d07#16", linkAtoB: CORE} + - {a: "64-2:0:13#34", b: "64-0:0:e816#7", linkAtoB: CORE} + - {a: "64-0:0:e816#34", b: "64-2:0:28#3", linkAtoB: CORE} + - {a: "64-0:0:22f#15", b: "64-0:0:1a4a#9", linkAtoB: CORE} + - {a: "64-0:0:22f#25", b: "64-0:0:303e#3", linkAtoB: CORE} + - {a: "64-2:0:13#24", b: "64-0:0:3d07#2", linkAtoB: CORE} + - {a: "64-0:0:ce7#16", b: "64-2:0:23#5", linkAtoB: CORE} + - {a: "64-0:0:22f#33", b: "64-0:0:e816#6", linkAtoB: CORE} + - {a: "64-2:0:23#2", b: "64-2:0:13#19", linkAtoB: CORE} diff --git a/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java b/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java index 8835da1e..14c28036 100644 --- a/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java +++ b/src/test/java/org/scion/jpan/ProtobufSegmentMapperDemo.java @@ -51,11 +51,16 @@ public static void main(String[] args) throws IOException { // // demo.getSegments(toWildcard(ia121), ia121); // // demo.getSegments(toWildcard(ia120), toWildcard(ia210)); - ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("[fd00:f00d:cafe::7f00:14]:31000"); - demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:110"), ScionUtil.parseIA("2-ff00:0:210")); + // ProtobufSegmentMapperDemo demoLab = + // new ProtobufSegmentMapperDemo("[fd00:f00d:cafe::7f00:14]:31000"); + // demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:110"), ScionUtil.parseIA("2-ff00:0:210")); // ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("127.0.0.71:31000"); // demoLab.getSegments(ScionUtil.parseIA("1-ff00:0:1001"), ScionUtil.parseIA("1-ff00:0:1007")); + + // 64-2:0:28 Cyberlink Cloud Test AS + ProtobufSegmentMapperDemo demoLab = new ProtobufSegmentMapperDemo("192.168.53.20:30252"); + demoLab.getSegments(ScionUtil.parseIA("64-0:0:0"), ScionUtil.parseIA("64-0:0:0")); } public ProtobufSegmentMapperDemo(String csAddress) { @@ -131,8 +136,12 @@ public AsLink(long isdAs, long nextIsdAs, long id0, long id1) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof AsLink)) return false; + if (this == o) { + return true; + } + if (!(o instanceof AsLink)) { + return false; + } AsLink asLink = (AsLink) o; return as0 == asLink.as0 && as1 == asLink.as1 && id0 == asLink.id0 && id1 == asLink.id1; } diff --git a/src/test/java/org/scion/jpan/demo/ShowpathsDemo.java b/src/test/java/org/scion/jpan/demo/ShowpathsDemo.java index e610909d..25da3390 100644 --- a/src/test/java/org/scion/jpan/demo/ShowpathsDemo.java +++ b/src/test/java/org/scion/jpan/demo/ShowpathsDemo.java @@ -82,7 +82,8 @@ public static void main(String[] args) throws IOException { { // Local port must be 30041 for networks that expect a dispatcher ShowpathsDemo demo = new ShowpathsDemo(Constants.DISPATCHER_PORT); - demo.runDemo(DemoConstants.iaAnapayaHK); + demo.runDemo(ScionUtil.parseIA("64-2:0:28")); + // demo.runDemo(DemoConstants.iaAnapayaHK); // demo.runDemo(DemoConstants.iaOVGU); break; } diff --git a/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java b/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java new file mode 100644 index 00000000..ad253e79 --- /dev/null +++ b/src/test/java/org/scion/jpan/demo/TopologyMapperDemo.java @@ -0,0 +1,275 @@ +// Copyright 2023 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 org.scion.jpan.demo; + +import java.io.FileWriter; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.*; + +import org.scion.jpan.*; +import org.scion.jpan.testutil.MockDNS; +import org.scion.jpan.testutil.Scenario; + +/** + * This demo mimics the "scion ping" command available in scionproto (...). This demo also demonstrates different ways + * of connecting to a network:
+ * - JUNIT_MOCK shows how to use the mock network in this library (for JUnit tests)
+ * - SCION_PROTO shows how to connect to a local topology from the scionproto go implementation such + * as "tiny". Note that the constants for "minimal" differ somewhat from the scionproto topology. + *
+ * - PRODUCTION shows different ways how to connect to the production network. Note: While the + * production network uses the dispatcher, the demo needs to use port 30041. + * + *