blob: ddbdb3848a0834f03488f55c06231f08d19a64c5 [file] [log] [blame]
Andrea Campanellaaf34b7c2018-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 Campanella7cb4fd82018-02-27 12:36:00 +010019import org.apache.commons.lang.StringUtils;
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +010020import org.onosproject.net.ConnectPoint;
21import org.onosproject.net.flow.TrafficTreatment;
22import org.onosproject.net.group.GroupBucket;
23import org.onosproject.t3.api.GroupsInDevice;
24import org.onosproject.t3.api.StaticPacketTrace;
25
26import java.util.List;
27
28/**
29 * Class containing utility methods for T3 cli.
30 */
31final class T3CliUtils {
32
33 private T3CliUtils() {
34 //banning construction
35 }
36
37 private static final String FLOW_SHORT_FORMAT = " %s, bytes=%s, packets=%s, "
38 + "table=%s, priority=%s, selector=%s, treatment=%s";
39
40 private static final String GROUP_FORMAT =
41 " id=0x%s, state=%s, type=%s, bytes=%s, packets=%s, appId=%s, referenceCount=%s";
42 private static final String GROUP_BUCKET_FORMAT =
43 " id=0x%s, bucket=%s, bytes=%s, packets=%s, actions=%s";
44
Seyeon Jeongac129562020-02-28 01:17:34 -080045 public static final String NIB_AUTOFILLED =
46 "*** NIB is invalid. Snapshots for the NIB have been auto-filled: ***";
47 public static final String NIB_TERMINATE =
48 "*** NIB is still invalid. You can manually load it via CLI commands for T3 load and try again ***";
49
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +010050 /**
51 * Builds a string output for the given trace for a specific level of verbosity.
52 *
53 * @param trace the trace
54 * @param verbosity1 middle verbosity level
55 * @param verbosity2 high verbosity level
56 * @return a string representing the trace.
57 */
58 static String printTrace(StaticPacketTrace trace, boolean verbosity1, boolean verbosity2) {
59 StringBuilder tracePrint = new StringBuilder();
60 //Print based on verbosity
61 if (verbosity1) {
62 tracePrint = printTrace(trace, false, tracePrint);
63 } else if (verbosity2) {
64 tracePrint = printTrace(trace, true, tracePrint);
65 } else {
66 tracePrint.append("Paths");
67 tracePrint.append("\n");
68 List<List<ConnectPoint>> paths = trace.getCompletePaths();
69 for (List<ConnectPoint> path : paths) {
70 tracePrint.append(path);
71 tracePrint.append("\n");
72 }
73 }
74 tracePrint.append("Result: \n" + trace.resultMessage());
75 return tracePrint.toString();
76 }
77
78 //prints the trace
79 private static StringBuilder printTrace(StaticPacketTrace trace, boolean verbose, StringBuilder tracePrint) {
80 List<List<ConnectPoint>> paths = trace.getCompletePaths();
81 for (List<ConnectPoint> path : paths) {
82 tracePrint.append("Path " + path);
83 tracePrint.append("\n");
84 ConnectPoint previous = null;
85 if (path.size() == 1) {
86 ConnectPoint connectPoint = path.get(0);
87 tracePrint.append("Device " + connectPoint.deviceId());
88 tracePrint.append("\n");
89 tracePrint.append("Input from " + connectPoint);
90 tracePrint.append("\n");
91 tracePrint = printFlows(trace, verbose, connectPoint, tracePrint);
92 tracePrint = printGroups(trace, verbose, connectPoint, tracePrint);
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +010093 tracePrint.append("\n");
94 } else {
95 for (ConnectPoint connectPoint : path) {
96 if (previous == null || !previous.deviceId().equals(connectPoint.deviceId())) {
97 tracePrint.append("Device " + connectPoint.deviceId());
98 tracePrint.append("\n");
Andrea Campanellae5e3c122018-03-08 11:12:05 -080099 tracePrint.append(" Input from " + connectPoint);
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100100 tracePrint.append("\n");
101 tracePrint = printFlows(trace, verbose, connectPoint, tracePrint);
102 } else {
103 tracePrint = printGroups(trace, verbose, connectPoint, tracePrint);
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800104 tracePrint.append(" Output through " + connectPoint);
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100105 tracePrint.append("\n");
106 }
107 previous = connectPoint;
108 }
109 }
Andrea Campanella7cb4fd82018-02-27 12:36:00 +0100110 tracePrint.append(StringUtils.leftPad("\n", 100, '-'));
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100111 }
112 return tracePrint;
113 }
114
115
116 //Prints the flows for a given trace and a specified level of verbosity
117 private static StringBuilder printFlows(StaticPacketTrace trace, boolean verbose, ConnectPoint connectPoint,
118 StringBuilder tracePrint) {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800119 tracePrint.append(" Flows ");
Andrea Campanella04924b92018-01-17 16:34:51 +0100120 tracePrint.append(trace.getFlowsForDevice(connectPoint.deviceId()).size());
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800121 tracePrint.append(" \n");
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100122 trace.getFlowsForDevice(connectPoint.deviceId()).forEach(f -> {
123 if (verbose) {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800124 tracePrint.append(" " + String.format(FLOW_SHORT_FORMAT, f.state(), f.bytes(), f.packets(),
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100125 f.table(), f.priority(), f.selector().criteria(),
126 printTreatment(f.treatment())));
127 tracePrint.append("\n");
128 } else {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800129 tracePrint.append(String.format(" flowId=%s, table=%s, selector=%s", f.id(), f.table(),
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100130 f.selector().criteria()));
131 tracePrint.append("\n");
132 }
133 });
134 return tracePrint;
135 }
136
137 //Prints the groups for a given trace and a specified level of verbosity
138 private static StringBuilder printGroups(StaticPacketTrace trace, boolean verbose, ConnectPoint connectPoint,
139 StringBuilder tracePrint) {
140 List<GroupsInDevice> groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());
141 if (groupsInDevice != null) {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800142 tracePrint.append(" Groups");
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100143 tracePrint.append("\n");
144 groupsInDevice.forEach(output -> {
145 if (output.getOutput().equals(connectPoint)) {
146 output.getGroups().forEach(group -> {
147 if (verbose) {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800148 tracePrint.append(" " + String.format(GROUP_FORMAT, Integer.toHexString(group.id().id()),
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100149 group.state(), group.type(), group.bytes(), group.packets(),
150 group.appId().name(), group.referenceCount()));
151 tracePrint.append("\n");
152 int i = 0;
153 for (GroupBucket bucket : group.buckets().buckets()) {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800154 tracePrint.append(" " + String.format(GROUP_BUCKET_FORMAT,
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100155 Integer.toHexString(group.id().id()),
156 ++i, bucket.bytes(), bucket.packets(),
157 bucket.treatment().allInstructions()));
158 tracePrint.append("\n");
159 }
160 } else {
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800161 tracePrint.append(" groupId=" + group.id());
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100162 tracePrint.append("\n");
163 }
164 });
Andrea Campanellae5e3c122018-03-08 11:12:05 -0800165 tracePrint.append(" Outgoing Packet " + output.getFinalPacket());
Andrea Campanellaaf34b7c2018-02-08 17:10:11 +0100166 tracePrint.append("\n");
167 }
168 });
169 }
170 return tracePrint;
171 }
172
173 private static String printTreatment(TrafficTreatment treatment) {
174 final String delimiter = ", ";
175 StringBuilder builder = new StringBuilder("[");
176 if (!treatment.immediate().isEmpty()) {
177 builder.append("immediate=" + treatment.immediate() + delimiter);
178 }
179 if (!treatment.deferred().isEmpty()) {
180 builder.append("deferred=" + treatment.deferred() + delimiter);
181 }
182 if (treatment.clearedDeferred()) {
183 builder.append("clearDeferred" + delimiter);
184 }
185 if (treatment.tableTransition() != null) {
186 builder.append("transition=" + treatment.tableTransition() + delimiter);
187 }
188 if (treatment.metered() != null) {
189 builder.append("meter=" + treatment.metered() + delimiter);
190 }
191 if (treatment.writeMetadata() != null) {
192 builder.append("metadata=" + treatment.writeMetadata() + delimiter);
193 }
194 // Chop off last delimiter
195 builder.replace(builder.length() - delimiter.length(), builder.length(), "");
196 builder.append("]");
197 return builder.toString();
198 }
199}