blob: 3160ec7dbcc987cd6093e88bf01c4b7c1da418a8 [file] [log] [blame]
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -07003 *
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.ui.impl;
18
Simon Hunt8f057ee2017-07-19 14:05:26 -070019import com.fasterxml.jackson.databind.node.ArrayNode;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070020import com.fasterxml.jackson.databind.node.ObjectNode;
Simon Huntabd16f62015-05-01 13:14:40 -070021import com.google.common.base.Strings;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070022import com.google.common.collect.ImmutableSet;
cansu.toprak409289d2017-10-27 10:04:05 +030023import com.google.common.collect.Lists;
Simon Hunt36b658d2017-07-14 16:20:11 -070024import org.onosproject.app.ApplicationService;
25import org.onosproject.core.Application;
Viswanath KSPd1212c72016-10-21 01:03:35 +053026import org.onosproject.core.ApplicationId;
Thomas Vachuska3da62122017-10-04 13:49:12 -070027import org.onosproject.core.CoreService;
Viswanath KSPd1212c72016-10-21 01:03:35 +053028import org.onosproject.core.DefaultApplicationId;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070029import org.onosproject.net.DeviceId;
30import org.onosproject.net.flow.FlowEntry;
Viswanath KSPd1212c72016-10-21 01:03:35 +053031import org.onosproject.net.flow.FlowRule;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070032import org.onosproject.net.flow.FlowRuleService;
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +053033import org.onosproject.net.flow.TrafficTreatment;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070034import org.onosproject.net.flow.criteria.Criterion;
35import org.onosproject.net.flow.instructions.Instruction;
Simon Hunt8f057ee2017-07-19 14:05:26 -070036import org.onosproject.net.flow.instructions.Instructions;
Simon Huntd2747a02015-04-30 22:41:16 -070037import org.onosproject.ui.RequestHandler;
Simon Hunta0ddb022015-05-01 09:53:01 -070038import org.onosproject.ui.UiMessageHandler;
Bri Prebilic Cole9467a232015-05-06 16:59:05 -070039import org.onosproject.ui.table.CellFormatter;
Simon Hunt3d1b0652015-05-05 17:27:24 -070040import org.onosproject.ui.table.TableModel;
Simon Huntabd16f62015-05-01 13:14:40 -070041import org.onosproject.ui.table.TableRequestHandler;
Yi Tseng18177a52017-09-08 01:26:59 -070042import org.onosproject.ui.table.cell.DefaultCellFormatter;
Bri Prebilic Cole9467a232015-05-06 16:59:05 -070043import org.onosproject.ui.table.cell.EnumFormatter;
Simon Hunt3e4ccaf2016-01-12 19:59:54 -080044import org.onosproject.ui.table.cell.HexLongFormatter;
Simon Huntbe60dde2016-01-13 12:26:56 -080045import org.onosproject.ui.table.cell.NumberFormatter;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070046
Simon Huntd2747a02015-04-30 22:41:16 -070047import java.util.Collection;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070048import java.util.List;
Simon Hunt36b658d2017-07-14 16:20:11 -070049import java.util.Map;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070050import java.util.Set;
Simon Hunt36b658d2017-07-14 16:20:11 -070051import java.util.stream.Collectors;
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070052
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +053053
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070054/**
55 * Message handler for flow view related messages.
56 */
Simon Hunta0ddb022015-05-01 09:53:01 -070057public class FlowViewMessageHandler extends UiMessageHandler {
Simon Huntd2747a02015-04-30 22:41:16 -070058
59 private static final String FLOW_DATA_REQ = "flowDataRequest";
Simon Huntabd16f62015-05-01 13:14:40 -070060 private static final String FLOW_DATA_RESP = "flowDataResponse";
61 private static final String FLOWS = "flows";
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070062
Viswanath KSPd1212c72016-10-21 01:03:35 +053063 private static final String FLOW_DETAILS_REQ = "flowDetailsRequest";
64 private static final String FLOW_DETAILS_RESP = "flowDetailsResponse";
65 private static final String DETAILS = "details";
66 private static final String FLOW_PRIORITY = "priority";
67
Simon Hunt8f057ee2017-07-19 14:05:26 -070068 private static final String DEV_ID = "devId";
69
Simon Huntabd16f62015-05-01 13:14:40 -070070 private static final String ID = "id";
Viswanath KSPd1212c72016-10-21 01:03:35 +053071 private static final String FLOW_ID = "flowId";
Simon Huntabd16f62015-05-01 13:14:40 -070072 private static final String APP_ID = "appId";
Simon Hunt36b658d2017-07-14 16:20:11 -070073 private static final String APP_NAME = "appName";
Simon Huntabd16f62015-05-01 13:14:40 -070074 private static final String GROUP_ID = "groupId";
Yi Tseng18177a52017-09-08 01:26:59 -070075 private static final String TABLE_NAME = "tableName";
Simon Huntabd16f62015-05-01 13:14:40 -070076 private static final String PRIORITY = "priority";
Simon Hunt9bff5952017-07-13 14:05:09 -070077 private static final String SELECTOR_C = "selector_c"; // for table column
Simon Huntabd16f62015-05-01 13:14:40 -070078 private static final String SELECTOR = "selector";
Simon Hunt9bff5952017-07-13 14:05:09 -070079 private static final String TREATMENT_C = "treatment_c"; // for table column
Simon Huntabd16f62015-05-01 13:14:40 -070080 private static final String TREATMENT = "treatment";
Thomas Vachuska3da62122017-10-04 13:49:12 -070081 private static final String IDLE_TIMEOUT = "idleTimeout";
82 private static final String HARD_TIMEOUT = "hardTimeout";
Simon Huntabd16f62015-05-01 13:14:40 -070083 private static final String PERMANENT = "permanent";
84 private static final String STATE = "state";
Bri Prebilic Cole641b97b2015-05-05 14:47:40 -070085 private static final String PACKETS = "packets";
Simon Hunt9bff5952017-07-13 14:05:09 -070086 private static final String DURATION = "duration";
Bri Prebilic Cole641b97b2015-05-05 14:47:40 -070087 private static final String BYTES = "bytes";
Simon Huntabd16f62015-05-01 13:14:40 -070088
89 private static final String COMMA = ", ";
Viswanath KSP70e0d142016-10-28 21:58:32 +053090 private static final String OX = "0x";
91 private static final String EMPTY = "";
Simon Hunt8f057ee2017-07-19 14:05:26 -070092 private static final String SPACE = " ";
93 private static final String COLON = ":";
94 private static final String ANGLE_O = "<";
95 private static final String ANGLE_C = ">";
96 private static final String SQUARE_O = "[";
97 private static final String SQUARE_C = "]";
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070098
Simon Hunt36b658d2017-07-14 16:20:11 -070099 private static final String ONOS_PREFIX = "org.onosproject.";
100 private static final String ONOS_MARKER = "*";
101
Simon Huntf257a962017-08-25 18:58:47 -0700102 // json structure keys
103 private static final String IMMED = "immed";
104 private static final String DEFER = "defer";
105 private static final String METER = "meter";
106 private static final String TABLE = "table";
107 private static final String META = "meta";
108 private static final String CLEARDEF = "clearDef";
109
Simon Hunt8f057ee2017-07-19 14:05:26 -0700110 // TODO: replace the use of the following constants with localized text
111 private static final String MSG_NO_SELECTOR =
112 "(No traffic selector criteria for this flow)";
113 private static final String MSG_NO_TREATMENT =
114 "(No traffic treatment instructions for this flow)";
115 private static final String NO_ROWS_NO_FLOWS = "No flows found";
116
117 private static final String CRITERIA = "Criteria";
118 private static final String TREATMENT_INSTRUCTIONS = "Treatment Instructions";
119 private static final String IMM = "imm";
120 private static final String DEF = "def";
121 private static final String METERED = "metered";
122 private static final String TRANSITION = "transition";
123 private static final String METADATA = "metadata";
124 private static final String CLEARED = "cleared";
125 private static final String UNKNOWN = "Unknown";
126
127
Simon Hunt3d1b0652015-05-05 17:27:24 -0700128 private static final String[] COL_IDS = {
Simon Hunt9bff5952017-07-13 14:05:09 -0700129 ID,
130 STATE,
131 BYTES,
132 PACKETS,
133 DURATION,
134 PRIORITY,
Yi Tseng18177a52017-09-08 01:26:59 -0700135 TABLE_NAME,
Simon Hunt9bff5952017-07-13 14:05:09 -0700136 APP_ID,
Simon Hunt36b658d2017-07-14 16:20:11 -0700137 APP_NAME,
Simon Hunt9bff5952017-07-13 14:05:09 -0700138
139 GROUP_ID,
Thomas Vachuska3da62122017-10-04 13:49:12 -0700140 IDLE_TIMEOUT,
Simon Hunt9bff5952017-07-13 14:05:09 -0700141 PERMANENT,
142
143 SELECTOR_C,
144 SELECTOR,
145 TREATMENT_C,
146 TREATMENT,
Simon Hunt3d1b0652015-05-05 17:27:24 -0700147 };
148
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700149 @Override
Simon Huntda580882015-05-12 20:58:18 -0700150 protected Collection<RequestHandler> createRequestHandlers() {
Viswanath KSPd1212c72016-10-21 01:03:35 +0530151 return ImmutableSet.of(
152 new FlowDataRequest(),
153 new DetailRequestHandler()
154 );
Simon Huntd2747a02015-04-30 22:41:16 -0700155 }
156
Simon Hunt8f057ee2017-07-19 14:05:26 -0700157 private void removeTrailingComma(StringBuilder sb) {
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530158 int pos = sb.lastIndexOf(COMMA);
159 sb.delete(pos, sb.length());
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530160 }
161
Simon Hunt36b658d2017-07-14 16:20:11 -0700162 // Generate a map of shorts->application IDs
163 // (working around deficiency(?) in Application Service API)
164 private Map<Short, ApplicationId> appShortMap() {
165 Set<Application> apps =
166 get(ApplicationService.class).getApplications();
167
168 return apps.stream()
169 .collect(Collectors.toMap(a -> a.id().id(), Application::id));
170 }
171
172 // Return an application name, based on a lookup of the internal short ID
173 private String makeAppName(short id, Map<Short, ApplicationId> lookup) {
174 ApplicationId appId = lookup.get(id);
175 if (appId == null) {
Thomas Vachuska3da62122017-10-04 13:49:12 -0700176 appId = get(CoreService.class).getAppId(id);
177 if (appId == null) {
178 return UNKNOWN + SPACE + ANGLE_O + id + ANGLE_C;
179 }
180 lookup.put(id, appId);
Simon Hunt36b658d2017-07-14 16:20:11 -0700181 }
182 String appName = appId.name();
183 return appName.startsWith(ONOS_PREFIX)
184 ? appName.replaceFirst(ONOS_PREFIX, ONOS_MARKER) : appName;
185 }
186
Simon Huntabd16f62015-05-01 13:14:40 -0700187 // handler for flow table requests
188 private final class FlowDataRequest extends TableRequestHandler {
Simon Huntd2747a02015-04-30 22:41:16 -0700189
190 private FlowDataRequest() {
Simon Huntabd16f62015-05-01 13:14:40 -0700191 super(FLOW_DATA_REQ, FLOW_DATA_RESP, FLOWS);
Simon Huntd2747a02015-04-30 22:41:16 -0700192 }
193
194 @Override
Simon Hunt3d1b0652015-05-05 17:27:24 -0700195 protected String[] getColumnIds() {
196 return COL_IDS;
Simon Hunt44aa2f82015-04-30 15:01:35 -0700197 }
Simon Hunt44aa2f82015-04-30 15:01:35 -0700198
Simon Hunt3d1b0652015-05-05 17:27:24 -0700199 @Override
Jian Li8baf4472016-01-15 15:08:09 -0800200 protected String noRowsMessage(ObjectNode payload) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700201 return NO_ROWS_NO_FLOWS;
Jian Li69f66632016-01-15 12:27:42 -0800202 }
203
204 @Override
Simon Hunt3d1b0652015-05-05 17:27:24 -0700205 protected TableModel createTableModel() {
206 TableModel tm = super.createTableModel();
Simon Hunt3e4ccaf2016-01-12 19:59:54 -0800207 tm.setFormatter(ID, HexLongFormatter.INSTANCE);
Simon Huntbe60dde2016-01-13 12:26:56 -0800208 tm.setFormatter(STATE, EnumFormatter.INSTANCE);
Simon Huntbe60dde2016-01-13 12:26:56 -0800209 tm.setFormatter(BYTES, NumberFormatter.INTEGER);
Simon Hunt9bff5952017-07-13 14:05:09 -0700210 tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
211 tm.setFormatter(DURATION, NumberFormatter.INTEGER);
212
213 tm.setFormatter(SELECTOR_C, new SelectorShortFormatter());
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700214 tm.setFormatter(SELECTOR, new SelectorFormatter());
Simon Hunt9bff5952017-07-13 14:05:09 -0700215 tm.setFormatter(TREATMENT_C, new TreatmentShortFormatter());
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700216 tm.setFormatter(TREATMENT, new TreatmentFormatter());
Yi Tseng18177a52017-09-08 01:26:59 -0700217 tm.setFormatter(TABLE_NAME, DefaultCellFormatter.INSTANCE);
Simon Hunt3d1b0652015-05-05 17:27:24 -0700218 return tm;
219 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700220
Simon Hunt3d1b0652015-05-05 17:27:24 -0700221 @Override
222 protected void populateTable(TableModel tm, ObjectNode payload) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700223 String uri = string(payload, DEV_ID);
Simon Hunt3d1b0652015-05-05 17:27:24 -0700224 if (!Strings.isNullOrEmpty(uri)) {
225 DeviceId deviceId = DeviceId.deviceId(uri);
Simon Hunt36b658d2017-07-14 16:20:11 -0700226 Map<Short, ApplicationId> lookup = appShortMap();
Simon Hunt3d1b0652015-05-05 17:27:24 -0700227 FlowRuleService frs = get(FlowRuleService.class);
Simon Hunt36b658d2017-07-14 16:20:11 -0700228
Simon Hunt3d1b0652015-05-05 17:27:24 -0700229 for (FlowEntry flow : frs.getFlowEntries(deviceId)) {
Simon Hunt36b658d2017-07-14 16:20:11 -0700230 populateRow(tm.addRow(), flow, lookup);
Simon Hunt3d1b0652015-05-05 17:27:24 -0700231 }
232 }
233 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700234
Simon Hunt36b658d2017-07-14 16:20:11 -0700235 private void populateRow(TableModel.Row row, FlowEntry flow,
236 Map<Short, ApplicationId> lookup) {
Simon Hunt3d1b0652015-05-05 17:27:24 -0700237 row.cell(ID, flow.id().value())
Simon Hunt9bff5952017-07-13 14:05:09 -0700238 .cell(STATE, flow.state())
239 .cell(BYTES, flow.bytes())
240 .cell(PACKETS, flow.packets())
241 .cell(DURATION, flow.life())
Simon Hunt8a0429a2017-01-06 16:52:47 -0800242 .cell(PRIORITY, flow.priority())
Yi Tseng18177a52017-09-08 01:26:59 -0700243 .cell(TABLE_NAME, flow.table())
Simon Hunt9bff5952017-07-13 14:05:09 -0700244 .cell(APP_ID, flow.appId())
Simon Hunt36b658d2017-07-14 16:20:11 -0700245 .cell(APP_NAME, makeAppName(flow.appId(), lookup))
Simon Hunt9bff5952017-07-13 14:05:09 -0700246
247 .cell(GROUP_ID, flow.groupId().id())
Thomas Vachuska3da62122017-10-04 13:49:12 -0700248 .cell(IDLE_TIMEOUT, flow.timeout())
Simon Hunt8a0429a2017-01-06 16:52:47 -0800249 .cell(PERMANENT, flow.isPermanent())
Simon Hunt9bff5952017-07-13 14:05:09 -0700250
251 .cell(SELECTOR_C, flow)
Simon Hunt8a0429a2017-01-06 16:52:47 -0800252 .cell(SELECTOR, flow)
Simon Hunt9bff5952017-07-13 14:05:09 -0700253 .cell(TREATMENT_C, flow)
Simon Hunt8a0429a2017-01-06 16:52:47 -0800254 .cell(TREATMENT, flow);
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700255 }
256
Simon Hunt9bff5952017-07-13 14:05:09 -0700257 private class InternalSelectorFormatter implements CellFormatter {
258 private final boolean shortFormat;
259
260 InternalSelectorFormatter(boolean shortFormat) {
261 this.shortFormat = shortFormat;
262 }
263
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700264 @Override
265 public String format(Object value) {
266 FlowEntry flow = (FlowEntry) value;
267 Set<Criterion> criteria = flow.selector().criteria();
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700268
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700269 if (criteria.isEmpty()) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700270 return MSG_NO_SELECTOR;
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700271 }
Simon Hunt9bff5952017-07-13 14:05:09 -0700272
273 StringBuilder sb = new StringBuilder();
274 if (!shortFormat) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700275 sb.append(CRITERIA).append(COLON).append(SPACE);
Simon Hunt9bff5952017-07-13 14:05:09 -0700276 }
277
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700278 for (Criterion c : criteria) {
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700279 sb.append(c).append(COMMA);
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700280 }
281 removeTrailingComma(sb);
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700282
283 return sb.toString();
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700284 }
285 }
286
Simon Hunt9bff5952017-07-13 14:05:09 -0700287 private final class SelectorShortFormatter extends InternalSelectorFormatter {
288 SelectorShortFormatter() {
289 super(true);
290 }
291 }
292
293 private final class SelectorFormatter extends InternalSelectorFormatter {
294 SelectorFormatter() {
295 super(false);
296 }
297 }
298
299 private class InternalTreatmentFormatter implements CellFormatter {
300 private final boolean shortFormat;
301
302 InternalTreatmentFormatter(boolean shortFormat) {
303 this.shortFormat = shortFormat;
304 }
305
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700306 @Override
307 public String format(Object value) {
308 FlowEntry flow = (FlowEntry) value;
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530309 TrafficTreatment treatment = flow.treatment();
310 List<Instruction> imm = treatment.immediate();
311 List<Instruction> def = treatment.deferred();
312 if (imm.isEmpty() &&
313 def.isEmpty() &&
314 treatment.metered() == null &&
Simon Hunt8f057ee2017-07-19 14:05:26 -0700315 treatment.tableTransition() == null &&
316 treatment.writeMetadata() == null) {
317 return MSG_NO_TREATMENT;
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700318 }
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530319
Simon Hunt9bff5952017-07-13 14:05:09 -0700320 StringBuilder sb = new StringBuilder();
321
322 if (!shortFormat) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700323 sb.append(TREATMENT_INSTRUCTIONS).append(COLON).append(SPACE);
Simon Hunt9bff5952017-07-13 14:05:09 -0700324 }
325
Simon Hunt8f057ee2017-07-19 14:05:26 -0700326 formatInstructs(sb, imm, IMM);
327 formatInstructs(sb, def, DEF);
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530328
cansu.toprak409289d2017-10-27 10:04:05 +0300329 treatment.meters().forEach(meterInstruction ->
330 addLabVal(sb, METERED, meterInstruction)
331 );
Simon Hunt8f057ee2017-07-19 14:05:26 -0700332 addLabVal(sb, TRANSITION, treatment.tableTransition());
333 addLabVal(sb, METADATA, treatment.writeMetadata());
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530334
Simon Hunt8f057ee2017-07-19 14:05:26 -0700335 sb.append(CLEARED).append(COLON)
336 .append(treatment.clearedDeferred());
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700337
338 return sb.toString();
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700339 }
Simon Hunt8f057ee2017-07-19 14:05:26 -0700340
341 private void addLabVal(StringBuilder sb, String label, Instruction value) {
342 if (value != null) {
343 sb.append(label).append(COLON).append(value).append(COMMA);
344 }
345 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700346 }
347
Simon Hunt9bff5952017-07-13 14:05:09 -0700348 private final class TreatmentShortFormatter extends InternalTreatmentFormatter {
349 TreatmentShortFormatter() {
350 super(true);
351 }
352 }
353
354 private final class TreatmentFormatter extends InternalTreatmentFormatter {
355 TreatmentFormatter() {
356 super(false);
357 }
358 }
359
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530360 private void formatInstructs(StringBuilder sb,
361 List<Instruction> instructs,
362 String type) {
363 if (!instructs.isEmpty()) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700364 sb.append(type).append(SQUARE_O);
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530365 for (Instruction i : instructs) {
Simon Huntf257a962017-08-25 18:58:47 -0700366 sb.append(renderInstructionForDisplay(i)).append(COMMA);
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530367 }
Simon Hunt8f057ee2017-07-19 14:05:26 -0700368 removeTrailingComma(sb);
369 sb.append(SQUARE_C).append(COMMA);
Deepa Vaddireddyf3932c02017-02-09 17:32:28 +0530370 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700371 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700372 }
Viswanath KSPd1212c72016-10-21 01:03:35 +0530373
374 private final class DetailRequestHandler extends RequestHandler {
375 private DetailRequestHandler() {
376 super(FLOW_DETAILS_REQ);
377 }
378
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530379 private FlowEntry findFlowById(String appIdText, String flowId) {
Viswanath KSP70e0d142016-10-28 21:58:32 +0530380 String strippedFlowId = flowId.replaceAll(OX, EMPTY);
Viswanath KSPd1212c72016-10-21 01:03:35 +0530381 FlowRuleService fs = get(FlowRuleService.class);
382 int appIdInt = Integer.parseInt(appIdText);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530383 ApplicationId appId = new DefaultApplicationId(appIdInt, DETAILS);
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530384 Iterable<FlowEntry> entries = fs.getFlowEntriesById(appId);
Viswanath KSPd1212c72016-10-21 01:03:35 +0530385
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530386 for (FlowEntry entry : entries) {
387 if (entry.id().toString().equals(strippedFlowId)) {
388 return entry;
Viswanath KSPd1212c72016-10-21 01:03:35 +0530389 }
390 }
391
392 return null;
393 }
394
Viswanath KSP70e0d142016-10-28 21:58:32 +0530395 private String decorateFlowId(FlowRule flow) {
396 return OX + flow.id();
397 }
398
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530399 private String decorateGroupId(FlowRule flow) {
400 return OX + flow.groupId().id();
401 }
402
Viswanath KSPd1212c72016-10-21 01:03:35 +0530403 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800404 public void process(ObjectNode payload) {
Viswanath KSPd1212c72016-10-21 01:03:35 +0530405
406 String flowId = string(payload, FLOW_ID);
407 String appId = string(payload, APP_ID);
Simon Hunt9bff5952017-07-13 14:05:09 -0700408
409 FlowEntry flow = findFlowById(appId, flowId);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530410 if (flow != null) {
411 ObjectNode data = objectNode();
Viswanath KSPd1212c72016-10-21 01:03:35 +0530412
Viswanath KSP70e0d142016-10-28 21:58:32 +0530413 data.put(FLOW_ID, decorateFlowId(flow));
Simon Hunt9bff5952017-07-13 14:05:09 -0700414
Simon Hunt8f057ee2017-07-19 14:05:26 -0700415 data.put(STATE, EnumFormatter.INSTANCE.format(flow.state()));
416 data.put(BYTES, NumberFormatter.INTEGER.format(flow.bytes()));
417 data.put(PACKETS, NumberFormatter.INTEGER.format(flow.packets()));
418 data.put(DURATION, NumberFormatter.INTEGER.format(flow.life()));
Simon Hunt9bff5952017-07-13 14:05:09 -0700419
Viswanath KSP70e0d142016-10-28 21:58:32 +0530420 data.put(FLOW_PRIORITY, flow.priority());
Yi Tseng18177a52017-09-08 01:26:59 -0700421 data.put(TABLE_NAME, flow.table().toString());
Simon Hunt9bff5952017-07-13 14:05:09 -0700422 data.put(APP_ID, flow.appId());
Simon Hunt36b658d2017-07-14 16:20:11 -0700423 // NOTE: horribly inefficient... make a map and retrieve a single value...
424 data.put(APP_NAME, makeAppName(flow.appId(), appShortMap()));
Simon Hunt9bff5952017-07-13 14:05:09 -0700425
426 data.put(GROUP_ID, decorateGroupId(flow));
Thomas Vachuska3da62122017-10-04 13:49:12 -0700427 data.put(IDLE_TIMEOUT, flow.timeout());
428 data.put(HARD_TIMEOUT, flow.hardTimeout());
Simon Hunt8f057ee2017-07-19 14:05:26 -0700429 data.put(PERMANENT, flow.isPermanent());
Simon Hunt9bff5952017-07-13 14:05:09 -0700430
Simon Hunt8f057ee2017-07-19 14:05:26 -0700431 data.set(SELECTOR, jsonCriteria(flow));
432 data.set(TREATMENT, jsonTreatment(flow));
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530433
Viswanath KSP70e0d142016-10-28 21:58:32 +0530434 ObjectNode rootNode = objectNode();
435 rootNode.set(DETAILS, data);
436 sendMessage(FLOW_DETAILS_RESP, rootNode);
437 }
Viswanath KSPd1212c72016-10-21 01:03:35 +0530438 }
Simon Hunt8f057ee2017-07-19 14:05:26 -0700439
440 private ArrayNode jsonCriteria(FlowEntry flow) {
441 ArrayNode crits = arrayNode();
442 for (Criterion c : flow.selector().criteria()) {
443 crits.add(c.toString());
444 }
445 return crits;
446 }
447
448 private ObjectNode jsonTreatment(FlowEntry flow) {
449 ObjectNode treat = objectNode();
450 TrafficTreatment treatment = flow.treatment();
cansu.toprak409289d2017-10-27 10:04:05 +0300451 List<Instruction> imm = Lists.newArrayList(treatment.immediate());
Simon Hunt8f057ee2017-07-19 14:05:26 -0700452 List<Instruction> def = treatment.deferred();
cansu.toprak409289d2017-10-27 10:04:05 +0300453 Set<Instructions.MeterInstruction> meter = treatment.meters();
Simon Hunt8f057ee2017-07-19 14:05:26 -0700454 Instructions.TableTypeTransition table = treatment.tableTransition();
455 Instructions.MetadataInstruction meta = treatment.writeMetadata();
456
457 if (!imm.isEmpty()) {
458 treat.set(IMMED, jsonInstrList(imm));
459 }
460 if (!def.isEmpty()) {
461 treat.set(DEFER, jsonInstrList(def));
462 }
cansu.toprak409289d2017-10-27 10:04:05 +0300463 if (!meter.isEmpty()) {
464 treat.set(METER, jsonInstrList(Lists.newArrayList(meter)));
Simon Hunt8f057ee2017-07-19 14:05:26 -0700465 }
466 if (table != null) {
467 treat.put(TABLE, table.toString());
468 }
469 if (meta != null) {
470 treat.put(META, meta.toString());
471 }
472 treat.put(CLEARDEF, treatment.clearedDeferred());
473 return treat;
474 }
475
476 private ArrayNode jsonInstrList(List<Instruction> instructions) {
477 ArrayNode array = arrayNode();
478 for (Instruction i : instructions) {
Simon Huntf257a962017-08-25 18:58:47 -0700479 array.add(renderInstructionForDisplay(i));
Simon Hunt8f057ee2017-07-19 14:05:26 -0700480 }
481 return array;
482 }
Viswanath KSPd1212c72016-10-21 01:03:35 +0530483 }
Simon Hunt8f057ee2017-07-19 14:05:26 -0700484
Simon Huntf257a962017-08-25 18:58:47 -0700485 // package private to allow unit test access...
486 String renderInstructionForDisplay(Instruction instr) {
487
488 // special handling for Extension Instruction Wrappers...
489 if (instr instanceof Instructions.ExtensionInstructionWrapper) {
490 Instructions.ExtensionInstructionWrapper wrap =
491 (Instructions.ExtensionInstructionWrapper) instr;
492 return wrap.type() + COLON + wrap.extensionInstruction();
493 }
494
495 // special handling of other instruction classes could be placed here
496
497 // default to the natural string representation otherwise
498 return instr.toString();
499 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700500}