All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onosproject.t3.rest.T3WebResource Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Copyright 2018-present Open Networking Foundation
 *
 * 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.onosproject.t3.rest;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import org.onlab.packet.EthType;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.HostId;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.group.Group;
import org.onosproject.rest.AbstractWebResource;
import org.onosproject.t3.api.GroupsInDevice;
import org.onosproject.t3.api.StaticPacketTrace;
import org.onosproject.t3.api.TroubleshootService;
import org.slf4j.Logger;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Trellis Troubleshooting Tool REST API.
 */
@Path("t3")
public class T3WebResource extends AbstractWebResource {
    private final ObjectMapper mapper = new ObjectMapper();
    private static final Logger LOG = getLogger(T3WebResource.class);

    /**
     * Returns the trace non verbose result for the given source and destination ips.
     *
     * @param srcHost source ip identifier
     * @param dstHost destination ip identifier
     * @param ethType ethernet type identifier
     * @return 200 OK with component properties of given component and variable
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("simple/{srcHost}/{dstHost}/{ethType}")
    public Response getT3Simple(@PathParam("srcHost") String srcHost, @PathParam("dstHost") String dstHost,
                                @PathParam("ethType") String ethType) {

        ObjectNode node;
        try {
            node = getT3JsonOutput(srcHost, dstHost, ethType, false);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e);
        }
        return Response.status(200).entity(node).build();

    }

    /**
     * Returns the trace verbose result for the given source and destination ips.
     *
     * @param srcHost source ip identifier
     * @param dstHost destination ip identifier
     * @param ethType ethernet type identifier
     * @return 200 OK with component properties of given component and variable
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("simple/{srcHost}/{dstHost}/{ethType}/verbose")
    public Response getT3SimpleVerbose(@PathParam("srcHost") String srcHost, @PathParam("dstHost") String dstHost,
                                       @PathParam("ethType") String ethType) {

        ObjectNode node;
        try {
            node = getT3JsonOutput(srcHost, dstHost, ethType, true);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e);
        }
        return Response.status(200).entity(node).build();
    }

    /**
     * Returns the mcast trace non verbose result.
     *
     * @return 200 OK
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("mcast")
    public Response getT3Mcast() {
        ObjectNode node = null;
        try {
            node = getT3McastJsonOutput(false);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e);
        }
        return Response.status(200).entity(node).build();
    }

    /**
     * Returns the mcast trace verbose result.
     *
     * @return 200 OK
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("mcast/verbose")
    public Response getT3McastVerbose() {
        ObjectNode node;
        try {
            node = getT3McastJsonOutput(true);

        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e);
        }
        return Response.status(200).entity(node).build();
    }

    /**
     * Returns trace verbose or non verbose json output for the given trace.
     *
     * @param verbose based on verbosity level
     * @return a json representing the trace.
     */
    private ObjectNode getT3McastJsonOutput(boolean verbose) {
        TroubleshootService troubleshootService = get(TroubleshootService.class);
        final ObjectNode nodeOutput = mapper.createObjectNode();
        nodeOutput.put("title", "Tracing all Multicast routes in the System");

        //Create the generator for the list of traces.
        List> generator = troubleshootService.getMulitcastTrace(VlanId.vlanId("None"));
        int totalTraces = 0;
        List failedTraces = new ArrayList<>();
        StaticPacketTrace previousTrace = null;
        ArrayNode traceArray = mapper.createArrayNode();
        for (Set traces : generator) {
            ObjectNode genNode = mapper.createObjectNode();
            totalTraces++;
            //Print also Route if possible or packet
            ArrayNode traceOutput = mapper.createArrayNode();
            if (verbose) {
                traces.forEach(trace -> {
                    ObjectNode traceObj = mapper.createObjectNode();
                    ArrayNode node = mapper.createArrayNode();
                    for (Criterion packet : trace.getInitialPacket().criteria()) {
                        node.add(packet.toString());
                    }
                    traceObj.set("input packet", node);
                    traceObj.set("trace", getTraceJson(trace, verbose));
                    traceOutput.add(traceObj);
                });
            } else {
                for (StaticPacketTrace trace : traces) {
                    ObjectNode traceObject = mapper.createObjectNode();
                    traceObject.set("trace", traceNode(previousTrace, trace));
                    if (previousTrace == null || !previousTrace.equals(trace)) {
                        previousTrace = trace;
                    }
                    traceObject.put("result", trace.isSuccess());
                    if (!trace.isSuccess()) {
                        traceObject.put("reason", trace.resultMessage());
                        failedTraces.add(trace);
                    }
                    traceOutput.add(traceObject);
                }
            }
            genNode.set("traces", traceOutput);
            traceArray.add(genNode);
        }
        nodeOutput.set("tracing packet", traceArray);

        if (!verbose) {
            if (failedTraces.size() != 0) {
                nodeOutput.put("failed traces", failedTraces.size());
            }
            previousTrace = null;
            for (StaticPacketTrace trace : failedTraces) {
                if (previousTrace == null || !previousTrace.equals(trace)) {
                    previousTrace = trace;
                }
                nodeOutput.set("trace", traceNode(previousTrace, trace));
                if (trace != null) {
                    nodeOutput.put("failure", trace.resultMessage());
                }
            }
            nodeOutput.put("total traces", totalTraces);
            nodeOutput.put("errors", failedTraces.size());
        }
        return nodeOutput;
    }

    /**
     * Returns verbose or non verbose json output for the given trace.      *
     *
     * @param previousTrace the trace
     * @param trace         based on verbosity level
     * @return a json representing the trace.
     */
    private ObjectNode traceNode(StaticPacketTrace previousTrace, StaticPacketTrace trace) {
        ObjectNode obj = mapper.createObjectNode();
        if (previousTrace == null || !previousTrace.equals(trace)) {
            previousTrace = trace;
            ConnectPoint initialConnectPoint = trace.getInitialConnectPoint();
            TrafficSelector initialPacket = trace.getInitialPacket();
            boolean isIPv4 = ((EthTypeCriterion) initialPacket.getCriterion(Criterion.Type.ETH_TYPE))
                    .ethType().equals(EthType.EtherType.IPV4.ethType()
                    );
            IpPrefix group = ((IPCriterion) (isIPv4 ? trace.getInitialPacket()
                    .getCriterion(Criterion.Type.IPV4_DST) : trace.getInitialPacket()
                    .getCriterion(Criterion.Type.IPV6_DST))).ip();
            obj.put("source", initialConnectPoint.toString());
            obj.put("group", group.toString());
        }
        ArrayNode nodePath = mapper.createArrayNode();
        for (List listPaths : trace.getCompletePaths()) {
            nodePath.add(listPaths.get(listPaths.size() - 1).toString());
        }
        if (trace.getCompletePaths().size() > 1) {
            obj.set("sinks", nodePath);
        } else {
            obj.set("sink", nodePath);
        }
        return obj;
    }

    /**
     * Returns trace verbose or non verbose json output for the given trace.
     *
     * @param srcHost source ip identifier
     * @param dstHost destination ip identifier
     * @param ethType the ethernet Type
     * @param verbose based on verbosity level
     * @return a json representing the trace.
     */
    private ObjectNode getT3JsonOutput(String srcHost, String dstHost, String ethType, Boolean verbose) {
        TroubleshootService troubleshootService = get(TroubleshootService.class);
        final ObjectNode nodeOutput = mapper.createObjectNode();
        //Tracing between host ips
        ArrayNode ipList = mapper.createArrayNode();
        ipList.add(srcHost);
        ipList.add(dstHost);
        nodeOutput.set("hostIps ", ipList);
        EthType.EtherType type = EthType.EtherType.valueOf(ethType.toUpperCase());

        //Build the traces
        Set traces = troubleshootService.trace(HostId.hostId(srcHost), HostId.hostId(dstHost), type);
        traces.forEach(trace -> {

            if (trace.getInitialPacket() != null) {
                ArrayNode node = mapper.createArrayNode();
                for (Criterion packet : trace.getInitialPacket().criteria()) {
                    node.add(packet.toString());
                }
                nodeOutput.set("input packet", node);
                nodeOutput.set("trace", getTraceJson(trace, verbose));
            } else {
                LOG.debug("cannot obtain trace between: ", srcHost, dstHost);
                nodeOutput.set("failed trace", ipList);
                nodeOutput.put("reason", trace.resultMessage());
            }
        });
        return nodeOutput;
    }

    /**
     * Returns verbose or non verbose json output for the given trace.      *
     *
     * @param trace     the trace
     * @param verbosity based on verbosity level
     * @return a json representing the trace.
     */
    public ObjectNode getTraceJson(StaticPacketTrace trace, boolean verbosity) {
        ObjectNode nodeOutput = mapper.createObjectNode();
        if (verbosity) {
            nodeOutput.set("trace", getTrace(trace, verbosity));
        } else {
            ArrayNode nodePath = mapper.createArrayNode();
            for (List listPaths : trace.getCompletePaths()) {
                ArrayNode node = mapper.createArrayNode();
                for (ConnectPoint path : listPaths) {
                    node.add(path.toString());
                }
                nodePath.add(node);
            }
            nodeOutput.set("paths", nodePath);
        }

        nodeOutput.put("result", trace.resultMessage());
        return nodeOutput;
    }

    /**
     * Returns verbose json output for the given trace.      *
     *
     * @param trace the trace
     * @return a json representing the trace.
     */
    private ObjectNode getTrace(StaticPacketTrace trace, boolean verbose) {

        ObjectNode nodeOutput = mapper.createObjectNode();

        List> paths = trace.getCompletePaths();
        ArrayNode nodePath = mapper.createArrayNode();
        for (List path : paths) {
            ArrayNode pathNode = mapper.createArrayNode();
            for (ConnectPoint pathItr : path) {
                pathNode.add(pathItr.toString());
            }
            nodePath.add(pathNode);

            ConnectPoint previous = null;

            if (path.size() == 1) {
                ConnectPoint connectPoint = path.get(0);
                nodeOutput.put("device", connectPoint.deviceId().toString());
                nodeOutput.put("input", connectPoint.toString());
                nodeOutput.put("flowCount", trace.getFlowsForDevice(connectPoint.deviceId()).size());
                nodeOutput.set("flows", getFlowArray(trace, connectPoint, verbose));

                List groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());

                if (groupsInDevice != null) {
                    groupsInDevice.forEach(output -> {
                        nodeOutput.set("groups", getGroupObj(connectPoint, output, verbose));
                    });
                }

            } else {
                for (ConnectPoint connectPoint : path) {
                    if (previous == null || !previous.deviceId().equals(connectPoint.deviceId())) {
                        nodeOutput.put("device", connectPoint.deviceId().toString());
                        nodeOutput.put("input", connectPoint.toString());
                        nodeOutput.put("flows", trace.getFlowsForDevice(connectPoint.deviceId()).size());
                        nodeOutput.put("verbose", verbose);
                        nodeOutput.set("flows", getFlowArray(trace, connectPoint, verbose));
                    } else {
                        List groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());
                        if (groupsInDevice != null) {
                            groupsInDevice.forEach(output -> {
                                nodeOutput.set("groups", getGroupObj(connectPoint, output, verbose));
                            });

                        }

                    }
                    previous = connectPoint;
                }
            }
        }
        nodeOutput.set("path", nodePath);
        return nodeOutput;
    }

    //Return groups Object for a given trace and a specified level of verbosity
    private ObjectNode getGroupObj(ConnectPoint connectPoint, GroupsInDevice output, boolean verbose) {
        ArrayNode groupArray = mapper.createArrayNode();
        ObjectNode groupsObj = mapper.createObjectNode();
        if (output.getOutput().equals(connectPoint)) {
            output.getGroups().forEach(group -> {
                ObjectNode groups = mapper.createObjectNode();
                if (verbose) {
                    groups = codec(Group.class).encode(group, this);
                } else {
                    groups.put("groupId", group.id().toString());
                }
                groupArray.add(groups);
            });
            ArrayNode node = mapper.createArrayNode();
            for (Criterion packet : output.getFinalPacket().criteria()) {
                node.add(packet.toString());
            }
            groupsObj.set("outgoing packet", node);
        }
        groupsObj.set("groups", groupArray);
        return groupsObj;
    }

    //Return flows Object for a given trace and a specified level of verbosity
    private ArrayNode getFlowArray(StaticPacketTrace trace, ConnectPoint connectPoint, boolean verbose) {
        ArrayNode flowArray = mapper.createArrayNode();
        trace.getFlowsForDevice(connectPoint.deviceId()).forEach(f -> {
            ObjectNode flows = mapper.createObjectNode();
            if (verbose) {
                flows = codec(FlowEntry.class).encode(f, this);
            } else {
                flows.put("flowId: ", f.id().toString());
                flows.put("table: ", f.table().toString());
                flows.put("selector: ", f.selector().criteria().toString());
            }
            flowArray.add(flows);
        });
        return flowArray;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy