blob: 477298c4bc03f0ba9cb70800ceb15a84221946f2 [file] [log] [blame]
Andrea Campanella55c3f422018-02-08 17:10:11 +01001/*
2 * Copyright 2015-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.cli;
18
Andrea Campanella94dfb9e2018-02-27 12:36:00 +010019import org.apache.commons.lang.StringUtils;
Andrea Campanella55c3f422018-02-08 17:10:11 +010020import org.onosproject.net.ConnectPoint;
pierventrefe57fda2020-08-04 22:52:02 +020021import org.onosproject.net.DataPlaneEntity;
pierventre4fd3b462020-10-15 17:31:44 +020022import org.onosproject.net.PipelineTraceableHitChain;
pierventrefe57fda2020-08-04 22:52:02 +020023import org.onosproject.net.flow.FlowEntry;
Andrea Campanella55c3f422018-02-08 17:10:11 +010024import org.onosproject.net.flow.TrafficTreatment;
pierventrefe57fda2020-08-04 22:52:02 +020025import org.onosproject.net.group.Group;
Andrea Campanella55c3f422018-02-08 17:10:11 +010026import org.onosproject.net.group.GroupBucket;
Andrea Campanella55c3f422018-02-08 17:10:11 +010027import org.onosproject.t3.api.StaticPacketTrace;
28
29import java.util.List;
30
31/**
32 * Class containing utility methods for T3 cli.
33 */
34final class T3CliUtils {
35
36 private T3CliUtils() {
37 //banning construction
38 }
39
40 private static final String FLOW_SHORT_FORMAT = " %s, bytes=%s, packets=%s, "
41 + "table=%s, priority=%s, selector=%s, treatment=%s";
42
43 private static final String GROUP_FORMAT =
44 " id=0x%s, state=%s, type=%s, bytes=%s, packets=%s, appId=%s, referenceCount=%s";
45 private static final String GROUP_BUCKET_FORMAT =
46 " id=0x%s, bucket=%s, bytes=%s, packets=%s, actions=%s";
47
Seyeon Jeong5018bdd2020-02-28 01:17:34 -080048 public static final String NIB_AUTOFILLED =
49 "*** NIB is invalid. Snapshots for the NIB have been auto-filled: ***";
50 public static final String NIB_TERMINATE =
51 "*** NIB is still invalid. You can manually load it via CLI commands for T3 load and try again ***";
52
Andrea Campanella55c3f422018-02-08 17:10:11 +010053 /**
54 * Builds a string output for the given trace for a specific level of verbosity.
55 *
56 * @param trace the trace
57 * @param verbosity1 middle verbosity level
58 * @param verbosity2 high verbosity level
59 * @return a string representing the trace.
60 */
61 static String printTrace(StaticPacketTrace trace, boolean verbosity1, boolean verbosity2) {
62 StringBuilder tracePrint = new StringBuilder();
63 //Print based on verbosity
64 if (verbosity1) {
65 tracePrint = printTrace(trace, false, tracePrint);
66 } else if (verbosity2) {
67 tracePrint = printTrace(trace, true, tracePrint);
68 } else {
69 tracePrint.append("Paths");
70 tracePrint.append("\n");
71 List<List<ConnectPoint>> paths = trace.getCompletePaths();
72 for (List<ConnectPoint> path : paths) {
73 tracePrint.append(path);
74 tracePrint.append("\n");
75 }
76 }
77 tracePrint.append("Result: \n" + trace.resultMessage());
78 return tracePrint.toString();
79 }
80
81 //prints the trace
82 private static StringBuilder printTrace(StaticPacketTrace trace, boolean verbose, StringBuilder tracePrint) {
83 List<List<ConnectPoint>> paths = trace.getCompletePaths();
84 for (List<ConnectPoint> path : paths) {
85 tracePrint.append("Path " + path);
86 tracePrint.append("\n");
87 ConnectPoint previous = null;
88 if (path.size() == 1) {
89 ConnectPoint connectPoint = path.get(0);
90 tracePrint.append("Device " + connectPoint.deviceId());
91 tracePrint.append("\n");
92 tracePrint.append("Input from " + connectPoint);
93 tracePrint.append("\n");
pierventre4fd3b462020-10-15 17:31:44 +020094 tracePrint = printHitChains(trace, verbose, connectPoint, tracePrint);
Andrea Campanella55c3f422018-02-08 17:10:11 +010095 tracePrint.append("\n");
96 } else {
97 for (ConnectPoint connectPoint : path) {
98 if (previous == null || !previous.deviceId().equals(connectPoint.deviceId())) {
99 tracePrint.append("Device " + connectPoint.deviceId());
100 tracePrint.append("\n");
Andrea Campanellaf8b53192018-03-08 11:12:05 -0800101 tracePrint.append(" Input from " + connectPoint);
Andrea Campanella55c3f422018-02-08 17:10:11 +0100102 tracePrint.append("\n");
pierventre4fd3b462020-10-15 17:31:44 +0200103 } else {
104 tracePrint = printHitChains(trace, verbose, connectPoint, tracePrint);
Andrea Campanella55c3f422018-02-08 17:10:11 +0100105 }
106 previous = connectPoint;
107 }
108 }
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100109 tracePrint.append(StringUtils.leftPad("\n", 100, '-'));
Andrea Campanella55c3f422018-02-08 17:10:11 +0100110 }
pierventre4fd3b462020-10-15 17:31:44 +0200111 // Once we have printed all the paths - we print the dropped traceable chains
112 List<PipelineTraceableHitChain> droppedHitChains = trace.getDroppedHitChains();
113 if (droppedHitChains.size() == 0) {
114 return tracePrint;
115 }
116 tracePrint.append(" Dropped Hit chains ");
117 tracePrint.append(droppedHitChains.size());
Andrea Campanellaf8b53192018-03-08 11:12:05 -0800118 tracePrint.append(" \n");
pierventrefe57fda2020-08-04 22:52:02 +0200119 tracePrint.append(" \n");
120 int[] index = {1};
pierventre4fd3b462020-10-15 17:31:44 +0200121 for (PipelineTraceableHitChain hitChain : droppedHitChains) {
pierventrefe57fda2020-08-04 22:52:02 +0200122 tracePrint.append(" Hit chain " + index[0]++);
123 tracePrint.append(" \n");
pierventre4fd3b462020-10-15 17:31:44 +0200124 printHitChain(verbose, hitChain, tracePrint);
125 tracePrint.append(StringUtils.leftPad("\n", 100, '-'));
126 }
Andrea Campanella55c3f422018-02-08 17:10:11 +0100127 return tracePrint;
128 }
129
pierventre4fd3b462020-10-15 17:31:44 +0200130 private static StringBuilder printHitChains(StaticPacketTrace trace, boolean verbose, ConnectPoint outputPort,
131 StringBuilder tracePrint) {
132 tracePrint.append(" Hit chains ");
133 List<PipelineTraceableHitChain> hitChainsByDevice = trace.getHitChains(outputPort.deviceId());
134 tracePrint.append(hitChainsByDevice == null ? 0 : trace.getHitChains(outputPort.deviceId()).size());
135 tracePrint.append(" \n");
136 tracePrint.append(" \n");
137 // Do not go further
138 if (hitChainsByDevice == null) {
139 return tracePrint;
140 }
141 int[] index = {1};
142 hitChainsByDevice.forEach(hitChain -> {
143 // Do not print other hit chains
144 if (!outputPort.equals(hitChain.outputPort()) || (hitChain.isDropped())) {
145 return;
146 }
147 tracePrint.append(" Hit chain " + index[0]++);
148 tracePrint.append(" \n");
149 printHitChain(verbose, hitChain, tracePrint);
150 });
151 return tracePrint;
152 }
153
154 private static void printHitChain(boolean verbose, PipelineTraceableHitChain hitChain, StringBuilder tracePrint) {
155 // Print for each chain the matchable entities first
156 hitChain.hitChain().forEach(dataPlaneEntity -> {
157 if (dataPlaneEntity.getType() == DataPlaneEntity.Type.FLOWRULE) {
158 printFlow(dataPlaneEntity.getFlowEntry(), verbose, tracePrint);
159 } else if (dataPlaneEntity.getType() == DataPlaneEntity.Type.GROUP) {
160 printGroup(dataPlaneEntity.getGroupEntry(), verbose, tracePrint);
161 }
162 });
163 // Then the output packet of the current chain
164 tracePrint.append(" Outgoing Packet " + hitChain.egressPacket());
165 tracePrint.append("\n");
166 // The output port of the current chain
167 tracePrint.append(" Output through " + hitChain.outputPort());
168 tracePrint.append("\n");
169 // Dropped during the processing ?
170 tracePrint.append(" Dropped " + hitChain.isDropped());
171 tracePrint.append("\n");
172 tracePrint.append("\n");
173 }
174
pierventrefe57fda2020-08-04 22:52:02 +0200175 // Prints the flows for a given trace and a specified level of verbosity
176 private static void printFlow(FlowEntry f, boolean verbose, StringBuilder tracePrint) {
177 if (verbose) {
178 tracePrint.append(" " + String.format(FLOW_SHORT_FORMAT, f.state(), f.bytes(), f.packets(),
179 f.table(), f.priority(), f.selector().criteria(),
180 printTreatment(f.treatment())));
181 } else {
182 tracePrint.append(String.format(" flowId=%s, table=%s, selector=%s", f.id(), f.table(),
183 f.selector().criteria()));
Andrea Campanella55c3f422018-02-08 17:10:11 +0100184 }
pierventrefe57fda2020-08-04 22:52:02 +0200185 tracePrint.append("\n");
186 }
187
188 // Prints the groups for a given trace and a specified level of verbosity
189 private static void printGroup(Group group, boolean verbose, StringBuilder tracePrint) {
190 if (verbose) {
191 tracePrint.append(" " + String.format(GROUP_FORMAT, Integer.toHexString(group.id().id()),
192 group.state(), group.type(), group.bytes(), group.packets(),
193 group.appId().name(), group.referenceCount()));
194 tracePrint.append("\n");
195 int i = 0;
196 for (GroupBucket bucket : group.buckets().buckets()) {
197 tracePrint.append(" " + String.format(GROUP_BUCKET_FORMAT,
198 Integer.toHexString(group.id().id()),
199 ++i, bucket.bytes(), bucket.packets(),
200 bucket.treatment().allInstructions()));
201 tracePrint.append("\n");
202 }
203 } else {
204 tracePrint.append(" groupId=" + group.id());
205 tracePrint.append("\n");
206 }
Andrea Campanella55c3f422018-02-08 17:10:11 +0100207 }
208
209 private static String printTreatment(TrafficTreatment treatment) {
210 final String delimiter = ", ";
211 StringBuilder builder = new StringBuilder("[");
212 if (!treatment.immediate().isEmpty()) {
213 builder.append("immediate=" + treatment.immediate() + delimiter);
214 }
215 if (!treatment.deferred().isEmpty()) {
216 builder.append("deferred=" + treatment.deferred() + delimiter);
217 }
218 if (treatment.clearedDeferred()) {
219 builder.append("clearDeferred" + delimiter);
220 }
221 if (treatment.tableTransition() != null) {
222 builder.append("transition=" + treatment.tableTransition() + delimiter);
223 }
224 if (treatment.metered() != null) {
225 builder.append("meter=" + treatment.metered() + delimiter);
226 }
227 if (treatment.writeMetadata() != null) {
228 builder.append("metadata=" + treatment.writeMetadata() + delimiter);
229 }
230 // Chop off last delimiter
231 builder.replace(builder.length() - delimiter.length(), builder.length(), "");
232 builder.append("]");
233 return builder.toString();
234 }
235}