[AETHER-76] Impelentation of a new Trellis Troubleshoot Tool (T3) for offline mode
- For the performance improvement, T3 offline mode uses snapshots of the network states
called Network Information Base (NIB) instead of runtime interactions with ONOS core
during troubleshooting a Trellis system.
- Partially tested with some mininet topos for trellis
(https://github.com/opennetworkinglab/routing/tree/master/trellis).
- Usage instruction docs (https://docs.trellisfabric.org/troubleshooting.html).
Change-Id: Ice608f77aa96bfbcadfff34991c4a1b6d93125b6
(cherry picked from commit eaa6329aba67c2577fdca7d3ddf230611e82f9f7)
diff --git a/core/common/BUILD b/core/common/BUILD
index 9abdc58..be6cac4 100644
--- a/core/common/BUILD
+++ b/core/common/BUILD
@@ -1,4 +1,6 @@
-COMPILE_DEPS = CORE_DEPS + JACKSON + METRICS
+COMPILE_DEPS = CORE_DEPS + JACKSON + METRICS + KRYO + [
+ "//core/store/serializers:onos-core-serializers",
+]
TEST_DEPS = TEST + ["//core/api:onos-api-tests"]
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
index 24b749c..93cfe5d 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
@@ -82,6 +82,7 @@
static final String PI_MATCH_MASK = "mask";
static final String PI_MATCH_HIGH_VALUE = "highValue";
static final String PI_MATCH_LOW_VALUE = "lowValue";
+ static final String EXTENSION = "extension";
@Override
public ObjectNode encode(Criterion criterion, CodecContext context) {
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
index f690d5d..9516ed3 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.codec.impl;
+import com.esotericsoftware.kryo.io.Input;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.packet.Ip6Address;
@@ -33,20 +34,28 @@
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.ExtensionCriterion;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.pi.model.PiMatchFieldId;
import org.onosproject.net.pi.model.PiMatchType;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.slf4j.Logger;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Decode portion of the criterion codec.
*/
public final class DecodeCriterionCodecHelper {
+ private static final Logger log = getLogger(DecodeCriterionCodecHelper.class);
+
private final ObjectNode json;
protected static final String MISSING_MEMBER_MESSAGE =
@@ -114,6 +123,7 @@
decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder());
decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder());
decoderMap.put(Criterion.Type.PROTOCOL_INDEPENDENT.name(), new PiDecoder());
+ decoderMap.put(Criterion.Type.EXTENSION.name(), new ExtensionDecoder());
}
private class EthTypeDecoder implements CriterionDecoder {
@@ -130,6 +140,7 @@
return Criteria.matchEthType(ethType);
}
}
+
private class EthDstDecoder implements CriterionDecoder {
@Override
public Criterion decodeCriterion(ObjectNode json) {
@@ -139,6 +150,7 @@
return Criteria.matchEthDst(mac);
}
}
+
private class EthDstMaskedDecoder implements CriterionDecoder {
@Override
public Criterion decodeCriterion(ObjectNode json) {
@@ -149,6 +161,7 @@
return Criteria.matchEthDstMasked(mac, macMask);
}
}
+
private class EthSrcDecoder implements CriterionDecoder {
@Override
public Criterion decodeCriterion(ObjectNode json) {
@@ -669,6 +682,24 @@
}
}
+ private class ExtensionDecoder implements CriterionDecoder {
+ @Override
+ public Criterion decodeCriterion(ObjectNode json) {
+ try {
+ byte[] buffer = nullIsIllegal(json.get(CriterionCodec.EXTENSION),
+ CriterionCodec.EXTENSION + MISSING_MEMBER_MESSAGE).binaryValue();
+ Input input = new Input(new ByteArrayInputStream(buffer));
+ ExtensionCriterion extensionCriterion =
+ KryoNamespaces.API.borrow().readObject(input, ExtensionCriterion.class);
+ input.close();
+ return extensionCriterion;
+ } catch (IOException e) {
+ log.warn("Cannot convert the {} field into byte array", CriterionCodec.EXTENSION);
+ return null;
+ }
+ }
+ }
+
/**
* Decodes the JSON into a criterion object.
*
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index 2933ca9..cfe5447 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -137,7 +137,10 @@
long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID),
InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong();
return Instructions.modTunnelId(tunnelId);
+ } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_BOS.name())) {
+ return Instructions.modMplsBos(json.get("bos").asBoolean());
}
+
throw new IllegalArgumentException("L2 Instruction subtype "
+ subType + " is not supported");
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java
index d34092a..c42dcfd 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java
@@ -20,6 +20,7 @@
import org.onlab.packet.ChassisId;
import org.onosproject.codec.CodecContext;
import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.Device;
import org.onosproject.net.Device.Type;
@@ -99,4 +100,26 @@
return new DefaultDevice(pid, id, type, mfr, hw, sw, serial,
chassisId, annotations);
}
+
+ /**
+ * Extracts annotations of given Object.
+ *
+ * @param deviceNode annotated JSON object node representing a device
+ * @param context decode context
+ * @return extracted Annotations
+ */
+ @Override
+ protected Annotations extractAnnotations(ObjectNode deviceNode, CodecContext context) {
+ ObjectNode annotationsNode = get(deviceNode, "annotations");
+ if (annotationsNode != null) {
+ // add needed fields to the annotations of the Device object
+ if (deviceNode.get(AVAILABLE) != null) {
+ annotationsNode.put(AVAILABLE, deviceNode.get(AVAILABLE).asText());
+ }
+ return context.codec(Annotations.class).decode(annotationsNode, context);
+ } else {
+ return DefaultAnnotations.EMPTY;
+ }
+ }
+
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
index 067a99a..c99e353 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.codec.impl;
+import com.esotericsoftware.kryo.io.Output;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.util.HexString;
@@ -57,7 +58,9 @@
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
+import org.onosproject.store.serializers.KryoNamespaces;
+import java.io.ByteArrayOutputStream;
import java.util.EnumMap;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -133,6 +136,7 @@
formatMap.put(Criterion.Type.ODU_SIGID, new FormatOduSignalId());
formatMap.put(Criterion.Type.ODU_SIGTYPE, new FormatOduSignalType());
formatMap.put(Criterion.Type.PROTOCOL_INDEPENDENT, new FormatProtocolIndependent());
+ formatMap.put(Criterion.Type.EXTENSION, new FormatExtension());
// Currently unimplemented
formatMap.put(Criterion.Type.ARP_OP, new FormatUnknown());
formatMap.put(Criterion.Type.ARP_SPA, new FormatUnknown());
@@ -146,7 +150,6 @@
formatMap.put(Criterion.Type.TCP_FLAGS, new FormatUnknown());
formatMap.put(Criterion.Type.ACTSET_OUTPUT, new FormatUnknown());
formatMap.put(Criterion.Type.PACKET_TYPE, new FormatUnknown());
- formatMap.put(Criterion.Type.EXTENSION, new FormatUnknown());
formatMap.put(Criterion.Type.ETH_SRC_MASKED, new FormatUnknown());
formatMap.put(Criterion.Type.TCP_SRC_MASKED, new FormatUnknown());
formatMap.put(Criterion.Type.TCP_DST_MASKED, new FormatUnknown());
@@ -579,6 +582,19 @@
}
}
+ private class FormatExtension implements CriterionTypeFormatter {
+ @Override
+ public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
+ Output output = new Output(new ByteArrayOutputStream());
+ KryoNamespaces.API.borrow().writeObject(output, criterion);
+ root.put(CriterionCodec.EXTENSION, output.toBytes());
+ output.flush();
+ output.close();
+
+ return root;
+ }
+ }
+
private class FormatDummyType implements CriterionTypeFormatter {
@Override
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
index a30068e..589a386 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
@@ -309,6 +309,8 @@
}
if (device.is(ExtensionTreatmentCodec.class)) {
+ // for extension instructions, encoding device id is needed for the corresponding decoder
+ result.put("deviceId", deviceId.toString());
ExtensionTreatmentCodec treatmentCodec = device.as(ExtensionTreatmentCodec.class);
ObjectNode node = treatmentCodec.encode(extensionInstruction.extensionInstruction(), context);
result.set(InstructionCodec.EXTENSION, node);