blob: ddab53a462297fd0adb893656d03b50bbe29812b [file] [log] [blame]
Brian O'Connor66cfbfa2015-02-17 18:17:32 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Brian O'Connor66cfbfa2015-02-17 18:17:32 -08003 *
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 */
16package org.onosproject.cli.net;
17
Ray Milkey3e3ec5f2015-03-17 17:00:38 -070018import java.util.EnumSet;
19import java.util.List;
Ray Milkey3e3ec5f2015-03-17 17:00:38 -070020import java.util.concurrent.atomic.AtomicLong;
21
Ray Milkeyd84f89b2018-08-17 14:54:17 -070022import org.apache.karaf.shell.api.action.Argument;
23import org.apache.karaf.shell.api.action.Command;
Ray Milkey0068fd02018-10-11 15:45:39 -070024import org.apache.karaf.shell.api.action.Completion;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070025import org.apache.karaf.shell.api.action.lifecycle.Service;
Ray Milkey0068fd02018-10-11 15:45:39 -070026import org.apache.karaf.shell.support.completers.NullCompleter;
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080027import org.onlab.packet.Ethernet;
28import org.onlab.packet.MacAddress;
29import org.onosproject.cli.AbstractShellCommand;
30import org.onosproject.net.ConnectPoint;
31import org.onosproject.net.DeviceId;
Ray Milkeya2cf3a12018-02-15 16:13:56 -080032import org.onosproject.net.FilteredConnectPoint;
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080033import org.onosproject.net.PortNumber;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
38import org.onosproject.net.intent.Intent;
39import org.onosproject.net.intent.IntentEvent;
40import org.onosproject.net.intent.IntentEvent.Type;
41import org.onosproject.net.intent.IntentListener;
42import org.onosproject.net.intent.IntentService;
43import org.onosproject.net.intent.Key;
44import org.onosproject.net.intent.PointToPointIntent;
45
Ray Milkey3e3ec5f2015-03-17 17:00:38 -070046import com.google.common.collect.Lists;
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080047
48import static org.onlab.util.Tools.delay;
49import static org.onosproject.net.DeviceId.deviceId;
50import static org.onosproject.net.PortNumber.portNumber;
51
52/**
53 * Installs point-to-point connectivity intents.
54 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055@Service
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080056@Command(scope = "onos", name = "cycle-intents",
57 description = "Installs random intents to test throughput")
58public class IntentCycleCommand extends AbstractShellCommand
59 implements IntentListener {
60
61 @Argument(index = 0, name = "ingressDevice",
62 description = "Ingress Device/Port Description",
63 required = true, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070064 @Completion(ConnectPointCompleter.class)
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080065 String ingressDeviceString = null;
66
67 @Argument(index = 1, name = "egressDevice",
68 description = "Egress Device/Port Description",
69 required = true, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070070 @Completion(ConnectPointCompleter.class)
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080071 String egressDeviceString = null;
72
73 @Argument(index = 2, name = "numberOfIntents",
74 description = "Number of intents to install/withdraw",
75 required = true, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070076 @Completion(NullCompleter.class)
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080077 String numberOfIntents = null;
78
79 @Argument(index = 3, name = "keyOffset",
80 description = "Starting point for first key (default: 1)",
81 required = false, multiValued = false)
82 String keyOffsetStr = null;
83
84 private IntentService service;
HelloONOS0b5b35d2017-04-05 18:47:47 +090085 private volatile long start;
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080086 private int count;
87 private int keyOffset;
88 private long submitCounter = 0;
89 private AtomicLong eventCounter = new AtomicLong(0);
90 private boolean add;
91
92 @Override
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 protected void doExecute() {
Brian O'Connor66cfbfa2015-02-17 18:17:32 -080094 service = get(IntentService.class);
95
96
97 DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
98 PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
99 ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
100
101 DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
102 PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
103 ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
104
105 count = Integer.parseInt(numberOfIntents);
106 keyOffset = (keyOffsetStr != null) ? Integer.parseInt(keyOffsetStr) : 1;
107
108 service.addListener(this);
109
110 List<Intent> operations = generateIntents(ingress, egress);
111
112 add = true;
113 start = System.currentTimeMillis();
114 while (start + 10000 > System.currentTimeMillis()) {
115 submitIntents(operations);
116 }
117 delay(5000);
118 printResults();
119
120 add = false;
121 submitIntents(operations);
122
123 service.removeListener(this);
124 }
125
126 private List<Intent> generateIntents(ConnectPoint ingress, ConnectPoint egress) {
127 TrafficSelector.Builder selectorBldr = DefaultTrafficSelector.builder()
128 .matchEthType(Ethernet.TYPE_IPV4);
Brian O'Connor6b528132015-03-10 16:39:52 -0700129 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
Brian O'Connor66cfbfa2015-02-17 18:17:32 -0800130
131 List<Intent> intents = Lists.newArrayList();
Ray Milkey3717e602018-02-01 13:49:47 -0800132 for (long i = 0; i < count; i++) {
Brian O'Connor66cfbfa2015-02-17 18:17:32 -0800133 TrafficSelector selector = selectorBldr
134 .matchEthSrc(MacAddress.valueOf(i + keyOffset))
135 .build();
Ray Milkey3e3ec5f2015-03-17 17:00:38 -0700136 intents.add(
137 PointToPointIntent.builder()
138 .appId(appId())
139 .key(Key.of(i + keyOffset, appId()))
140 .selector(selector)
141 .treatment(treatment)
Ray Milkeya2cf3a12018-02-15 16:13:56 -0800142 .filteredIngressPoint(new FilteredConnectPoint(ingress))
143 .filteredEgressPoint(new FilteredConnectPoint(egress))
Ray Milkey3e3ec5f2015-03-17 17:00:38 -0700144 .build());
145
Brian O'Connor66cfbfa2015-02-17 18:17:32 -0800146
147 }
148 return intents;
149 }
150
151 private void submitIntents(List<Intent> intents) {
152 for (Intent intent : intents) {
153 if (add) {
154 submitCounter++;
155 service.submit(intent);
156 } else {
157 service.withdraw(intent);
158 }
159 }
160 }
161
162 private void printResults() {
Brian O'Connor66cfbfa2015-02-17 18:17:32 -0800163 print("count: %s / %s", eventCounter, Long.valueOf(submitCounter));
Brian O'Connor66cfbfa2015-02-17 18:17:32 -0800164 }
165
166 /**
167 * Extracts the port number portion of the ConnectPoint.
168 *
169 * @param deviceString string representing the device/port
170 * @return port number as a string, empty string if the port is not found
171 */
172 private String getPortNumber(String deviceString) {
173 int slash = deviceString.indexOf('/');
174 if (slash <= 0) {
175 return "";
176 }
177 return deviceString.substring(slash + 1, deviceString.length());
178 }
179
180 /**
181 * Extracts the device ID portion of the ConnectPoint.
182 *
183 * @param deviceString string representing the device/port
184 * @return device ID string
185 */
186 private String getDeviceId(String deviceString) {
187 int slash = deviceString.indexOf('/');
188 if (slash <= 0) {
189 return "";
190 }
191 return deviceString.substring(0, slash);
192 }
193
194 private static final EnumSet<Type> IGNORE_EVENT
195 = EnumSet.of(Type.INSTALL_REQ, Type.WITHDRAW_REQ);
196 @Override
197 public synchronized void event(IntentEvent event) {
198 if (!appId().equals(event.subject().appId())) {
199 // not my event, ignore
200 return;
201 }
202 Type expected = add ? Type.INSTALLED : Type.WITHDRAWN;
203 if (event.type() == expected) {
204 eventCounter.getAndIncrement();
205 } else if (IGNORE_EVENT.contains(event.type())) {
206 log.info("Unexpected intent event: {}", event);
207 }
208 }
209}