blob: 8568775fb02c34eb9a879c5861a35dc05cff4e17 [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;
22import org.onosproject.net.DeviceId;
23import 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");
pierventrefe57fda2020-08-04 22:52:02 +020094 tracePrint = printHitChains(trace, verbose, connectPoint.deviceId(), 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");
pierventrefe57fda2020-08-04 22:52:02 +0200103 tracePrint = printHitChains(trace, verbose, connectPoint.deviceId(), tracePrint);
Andrea Campanella55c3f422018-02-08 17:10:11 +0100104 }
105 previous = connectPoint;
106 }
107 }
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100108 tracePrint.append(StringUtils.leftPad("\n", 100, '-'));
Andrea Campanella55c3f422018-02-08 17:10:11 +0100109 }
110 return tracePrint;
111 }
112
pierventrefe57fda2020-08-04 22:52:02 +0200113 private static StringBuilder printHitChains(StaticPacketTrace trace, boolean verbose, DeviceId deviceId,
114 StringBuilder tracePrint) {
115 tracePrint.append(" Hit chains ");
116 tracePrint.append(trace.getHitChains(deviceId).size());
Andrea Campanellaf8b53192018-03-08 11:12:05 -0800117 tracePrint.append(" \n");
pierventrefe57fda2020-08-04 22:52:02 +0200118 tracePrint.append(" \n");
119 int[] index = {1};
120 trace.getHitChains(deviceId).forEach(hitChain -> {
121 tracePrint.append(" Hit chain " + index[0]++);
122 tracePrint.append(" \n");
123 // Print for each chain the matchable entities first
124 hitChain.getHitChain().forEach(dataPlaneEntity -> {
125 if (dataPlaneEntity.getType() == DataPlaneEntity.Type.FLOWRULE) {
126 printFlow(dataPlaneEntity.getFlowEntry(), verbose, tracePrint);
127 } else if (dataPlaneEntity.getType() == DataPlaneEntity.Type.GROUP) {
128 printGroup(dataPlaneEntity.getGroupEntry(), verbose, tracePrint);
129 }
130 });
131 // Then the output packet of the current chain
132 tracePrint.append(" Outgoing Packet " + hitChain.getEgressPacket());
133 tracePrint.append("\n");
134 // The output port of the current chain
135 tracePrint.append(" Output through " + hitChain.getOutputPort());
136 tracePrint.append("\n");
137 // Dropped during the processing ?
138 tracePrint.append(" Dropped " + hitChain.isDropped());
139 tracePrint.append("\n");
140 tracePrint.append("\n");
Andrea Campanella55c3f422018-02-08 17:10:11 +0100141 });
pierventrefe57fda2020-08-04 22:52:02 +0200142
Andrea Campanella55c3f422018-02-08 17:10:11 +0100143 return tracePrint;
144 }
145
pierventrefe57fda2020-08-04 22:52:02 +0200146 // Prints the flows for a given trace and a specified level of verbosity
147 private static void printFlow(FlowEntry f, boolean verbose, StringBuilder tracePrint) {
148 if (verbose) {
149 tracePrint.append(" " + String.format(FLOW_SHORT_FORMAT, f.state(), f.bytes(), f.packets(),
150 f.table(), f.priority(), f.selector().criteria(),
151 printTreatment(f.treatment())));
152 } else {
153 tracePrint.append(String.format(" flowId=%s, table=%s, selector=%s", f.id(), f.table(),
154 f.selector().criteria()));
Andrea Campanella55c3f422018-02-08 17:10:11 +0100155 }
pierventrefe57fda2020-08-04 22:52:02 +0200156 tracePrint.append("\n");
157 }
158
159 // Prints the groups for a given trace and a specified level of verbosity
160 private static void printGroup(Group group, boolean verbose, StringBuilder tracePrint) {
161 if (verbose) {
162 tracePrint.append(" " + String.format(GROUP_FORMAT, Integer.toHexString(group.id().id()),
163 group.state(), group.type(), group.bytes(), group.packets(),
164 group.appId().name(), group.referenceCount()));
165 tracePrint.append("\n");
166 int i = 0;
167 for (GroupBucket bucket : group.buckets().buckets()) {
168 tracePrint.append(" " + String.format(GROUP_BUCKET_FORMAT,
169 Integer.toHexString(group.id().id()),
170 ++i, bucket.bytes(), bucket.packets(),
171 bucket.treatment().allInstructions()));
172 tracePrint.append("\n");
173 }
174 } else {
175 tracePrint.append(" groupId=" + group.id());
176 tracePrint.append("\n");
177 }
Andrea Campanella55c3f422018-02-08 17:10:11 +0100178 }
179
180 private static String printTreatment(TrafficTreatment treatment) {
181 final String delimiter = ", ";
182 StringBuilder builder = new StringBuilder("[");
183 if (!treatment.immediate().isEmpty()) {
184 builder.append("immediate=" + treatment.immediate() + delimiter);
185 }
186 if (!treatment.deferred().isEmpty()) {
187 builder.append("deferred=" + treatment.deferred() + delimiter);
188 }
189 if (treatment.clearedDeferred()) {
190 builder.append("clearDeferred" + delimiter);
191 }
192 if (treatment.tableTransition() != null) {
193 builder.append("transition=" + treatment.tableTransition() + delimiter);
194 }
195 if (treatment.metered() != null) {
196 builder.append("meter=" + treatment.metered() + delimiter);
197 }
198 if (treatment.writeMetadata() != null) {
199 builder.append("metadata=" + treatment.writeMetadata() + delimiter);
200 }
201 // Chop off last delimiter
202 builder.replace(builder.length() - delimiter.length(), builder.length(), "");
203 builder.append("]");
204 return builder.toString();
205 }
206}