blob: 0fe76748c821c234c6e404f6c37c3adbe098029f [file] [log] [blame]
psneha3adf3652018-06-25 10:08:35 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.t3.rest;
18
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
22
23import org.onlab.packet.EthType;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.HostId;
26import org.onosproject.net.flow.FlowEntry;
27import org.onosproject.net.flow.criteria.Criterion;
28import org.onosproject.net.group.Group;
29import org.onosproject.rest.AbstractWebResource;
30import org.onosproject.t3.api.GroupsInDevice;
31import org.onosproject.t3.api.StaticPacketTrace;
32import org.onosproject.t3.api.TroubleshootService;
33import org.slf4j.Logger;
34
35import javax.ws.rs.GET;
36import javax.ws.rs.Path;
37import javax.ws.rs.PathParam;
38import javax.ws.rs.Produces;
39import javax.ws.rs.core.MediaType;
40import javax.ws.rs.core.Response;
41
42import java.util.List;
43import java.util.Set;
44
45import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * Trellis Troubleshooting Tool REST API.
49 */
50@Path("t3")
51public class T3WebResource extends AbstractWebResource {
52 private final ObjectMapper mapper = new ObjectMapper();
53 private static final Logger LOG = getLogger(T3WebResource.class);
54
55 /**
56 * Returns the trace non verbose result for the given source and destination ips.
57 *
58 * @param srcHost source ip identifier
59 * @param dstHost destination ip identifier
60 * @param ethType ethernet type identifier
61 * @return 200 OK with component properties of given component and variable
62 */
63 @GET
64 @Produces(MediaType.APPLICATION_JSON)
65 @Path("simple/{srcHost}/{dstHost}/{ethType}")
66 public Response getT3Simple(@PathParam("srcHost") String srcHost, @PathParam("dstHost") String dstHost,
67 @PathParam("ethType") String ethType) {
68
69 ObjectNode node;
70 try {
71 node = getT3JsonOutput(srcHost, dstHost, ethType, false);
72 } catch (IllegalArgumentException e) {
73 throw new IllegalArgumentException(e);
74 }
75 return Response.status(200).entity(node).build();
76
77 }
78
79 /**
80 * Returns the trace verbose result for the given source and destination ips.
81 *
82 * @param srcHost source ip identifier
83 * @param dstHost destination ip identifier
84 * @param ethType ethernet type identifier
85 * @return 200 OK with component properties of given component and variable
86 */
87 @GET
88 @Produces(MediaType.APPLICATION_JSON)
89 @Path("simple/{srcHost}/{dstHost}/{ethType}/verbose")
90 public Response getT3SimpleVerbose(@PathParam("srcHost") String srcHost, @PathParam("dstHost") String dstHost,
91 @PathParam("ethType") String ethType) {
92
93 ObjectNode node;
94 try {
95 node = getT3JsonOutput(srcHost, dstHost, ethType, true);
96 } catch (IllegalArgumentException e) {
97 throw new IllegalArgumentException(e);
98 }
99 return Response.status(200).entity(node).build();
100 }
101
102 /**
103 * Returns trace verbose or non verbose json output for the given trace.
104 *
105 * @param srcHost source ip identifier
106 * @param dstHost destination ip identifier
107 * @param ethType the ethernet Type
108 * @param verbose based on verbosity level
109 * @return a json representing the trace.
110 */
111 private ObjectNode getT3JsonOutput(String srcHost, String dstHost, String ethType, Boolean verbose) {
112 TroubleshootService troubleshootService = get(TroubleshootService.class);
113 final ObjectNode nodeOutput = mapper.createObjectNode();
114 //Tracing between host ips
115 ArrayNode ipList = mapper.createArrayNode();
116 ipList.add(srcHost);
117 ipList.add(dstHost);
118 nodeOutput.set("hostIps ", ipList);
119 EthType.EtherType type = EthType.EtherType.valueOf(ethType.toUpperCase());
120
121 //Build the traces
122 Set<StaticPacketTrace> traces = troubleshootService.trace(HostId.hostId(srcHost), HostId.hostId(dstHost), type);
123 traces.forEach(trace -> {
124
125 if (trace.getInitialPacket() != null) {
126 ArrayNode node = mapper.createArrayNode();
127 for (Criterion packet : trace.getInitialPacket().criteria()) {
128 node.add(packet.toString());
129 }
130 nodeOutput.set("input packet", node);
131 nodeOutput.set("trace", getTraceJson(trace, verbose));
132 } else {
133 LOG.debug("cannot obtain trace between: ", srcHost, dstHost);
134 nodeOutput.set("failed trace", ipList);
135 nodeOutput.put("reason", trace.resultMessage());
136 }
137 });
138 return nodeOutput;
139 }
140
141 /**
142 * Returns verbose or non verbose json output for the given trace. *
143 *
144 * @param trace the trace
145 * @param verbosity based on verbosity level
146 * @return a json representing the trace.
147 */
148 public ObjectNode getTraceJson(StaticPacketTrace trace, boolean verbosity) {
149 ObjectNode nodeOutput = mapper.createObjectNode();
150 if (verbosity) {
151 nodeOutput.set("trace", getTrace(trace, verbosity));
152 } else {
153 ArrayNode nodePath = mapper.createArrayNode();
154 for (List<ConnectPoint> listPaths : trace.getCompletePaths()) {
155 ArrayNode node = mapper.createArrayNode();
156 for (ConnectPoint path : listPaths) {
157 node.add(path.toString());
158 }
159 nodePath.add(node);
160 }
161 nodeOutput.set("paths", nodePath);
162 }
163
164 nodeOutput.put("result", trace.resultMessage());
165 return nodeOutput;
166 }
167
168 /**
169 * Returns verbose json output for the given trace. *
170 *
171 * @param trace the trace
172 * @return a json representing the trace.
173 */
174 private ObjectNode getTrace(StaticPacketTrace trace, boolean verbose) {
175
176 ObjectNode nodeOutput = mapper.createObjectNode();
177
178 List<List<ConnectPoint>> paths = trace.getCompletePaths();
179 ArrayNode nodePath = mapper.createArrayNode();
180 for (List<ConnectPoint> path : paths) {
181 ArrayNode pathNode = mapper.createArrayNode();
182 for (ConnectPoint pathItr : path) {
183 pathNode.add(pathItr.toString());
184 }
185 nodePath.add(pathNode);
186
187 ConnectPoint previous = null;
188
189 if (path.size() == 1) {
190 ConnectPoint connectPoint = path.get(0);
191 nodeOutput.put("device", connectPoint.deviceId().toString());
192 nodeOutput.put("input", connectPoint.toString());
193 nodeOutput.put("flowCount", trace.getFlowsForDevice(connectPoint.deviceId()).size());
194 nodeOutput.set("flows", getFlowArray(trace, connectPoint, verbose));
195
196 List<GroupsInDevice> groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());
197
198 if (groupsInDevice != null) {
199 groupsInDevice.forEach(output -> {
200 nodeOutput.set("groups", getGroupObj(connectPoint, output, verbose));
201 });
202 }
203
204 } else {
205 for (ConnectPoint connectPoint : path) {
206 if (previous == null || !previous.deviceId().equals(connectPoint.deviceId())) {
207 nodeOutput.put("device", connectPoint.deviceId().toString());
208 nodeOutput.put("input", connectPoint.toString());
209 nodeOutput.put("flows", trace.getFlowsForDevice(connectPoint.deviceId()).size());
210 nodeOutput.put("verbose", verbose);
211 nodeOutput.set("flows", getFlowArray(trace, connectPoint, verbose));
212 } else {
213 List<GroupsInDevice> groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());
214 if (groupsInDevice != null) {
215 groupsInDevice.forEach(output -> {
216 nodeOutput.set("groups", getGroupObj(connectPoint, output, verbose));
217 });
218
219 }
220
221 }
222 previous = connectPoint;
223 }
224 }
225 }
226 nodeOutput.set("path", nodePath);
227 return nodeOutput;
228 }
229
230 //Return groups Object for a given trace and a specified level of verbosity
231 private ObjectNode getGroupObj(ConnectPoint connectPoint, GroupsInDevice output, boolean verbose) {
232 ArrayNode groupArray = mapper.createArrayNode();
233 ObjectNode groupsObj = mapper.createObjectNode();
234 if (output.getOutput().equals(connectPoint)) {
235 output.getGroups().forEach(group -> {
236 ObjectNode groups = mapper.createObjectNode();
237 if (verbose) {
238 groups = codec(Group.class).encode(group, this);
239 } else {
240 groups.put("groupId", group.id().toString());
241 }
242 groupArray.add(groups);
243 });
244 ArrayNode node = mapper.createArrayNode();
245 for (Criterion packet : output.getFinalPacket().criteria()) {
246 node.add(packet.toString());
247 }
248 groupsObj.set("outgoing packet", node);
249 }
250 groupsObj.set("groups", groupArray);
251 return groupsObj;
252 }
253
254 //Return flows Object for a given trace and a specified level of verbosity
255 private ArrayNode getFlowArray(StaticPacketTrace trace, ConnectPoint connectPoint, boolean verbose) {
256 ArrayNode flowArray = mapper.createArrayNode();
257 trace.getFlowsForDevice(connectPoint.deviceId()).forEach(f -> {
258 ObjectNode flows = mapper.createObjectNode();
259 if (verbose) {
260 flows = codec(FlowEntry.class).encode(f, this);
261 } else {
262 flows.put("flowId: ", f.id().toString());
263 flows.put("table: ", f.table().toString());
264 flows.put("selector: ", f.selector().criteria().toString());
265 }
266 flowArray.add(flows);
267 });
268 return flowArray;
269 }
270
271}