blob: c0224443c78466beba41cf0634c0c703951e6c6e [file] [log] [blame]
Claudine Chiu1f036b82017-03-09 16:45:56 -05001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Claudine Chiu1f036b82017-03-09 16:45:56 -05003 *
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.cli.net.vnet;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
21import com.fasterxml.jackson.databind.node.ArrayNode;
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;
26import org.apache.karaf.shell.api.action.Option;
Claudine Chiu1f036b82017-03-09 16:45:56 -050027import org.onlab.packet.Ip6Address;
28import org.onlab.packet.IpPrefix;
29import org.onlab.packet.MacAddress;
30import org.onlab.packet.TpPort;
31import org.onlab.packet.VlanId;
32import org.onosproject.cli.AbstractShellCommand;
33import org.onosproject.cli.net.EthType;
Ray Milkey0068fd02018-10-11 15:45:39 -070034import org.onosproject.cli.net.EthTypeCompleter;
Claudine Chiu1f036b82017-03-09 16:45:56 -050035import org.onosproject.cli.net.ExtHeader;
Ray Milkey0068fd02018-10-11 15:45:39 -070036import org.onosproject.cli.net.ExtHeaderCompleter;
Claudine Chiu1f036b82017-03-09 16:45:56 -050037import org.onosproject.cli.net.Icmp6Code;
Ray Milkey0068fd02018-10-11 15:45:39 -070038import org.onosproject.cli.net.Icmp6CodeCompleter;
Claudine Chiu1f036b82017-03-09 16:45:56 -050039import org.onosproject.cli.net.Icmp6Type;
Ray Milkey0068fd02018-10-11 15:45:39 -070040import org.onosproject.cli.net.Icmp6TypeCompleter;
Claudine Chiu1f036b82017-03-09 16:45:56 -050041import org.onosproject.cli.net.IpProtocol;
Ray Milkey0068fd02018-10-11 15:45:39 -070042import org.onosproject.cli.net.IpProtocolCompleter;
Claudine Chiu1f036b82017-03-09 16:45:56 -050043import org.onosproject.incubator.net.virtual.NetworkId;
44import org.onosproject.incubator.net.virtual.VirtualNetworkService;
45import org.onosproject.net.DeviceId;
46import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.packet.PacketPriority;
49import org.onosproject.net.packet.PacketRequest;
50import org.onosproject.net.packet.PacketService;
51
52import java.util.List;
53import java.util.Optional;
54
55import static com.google.common.base.Strings.isNullOrEmpty;
56
57/**
58 * Tests virtual network packet requests.
59 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060@Service
Claudine Chiu1f036b82017-03-09 16:45:56 -050061@Command(scope = "onos", name = "vnet-packet",
62 description = "Tests virtual network packet requests")
63public class VirtualNetworkPacketRequestCommand extends AbstractShellCommand {
64
65 @Argument(index = 0, name = "command",
66 description = "Command name (requestPackets|getRequests|cancelPackets)",
67 required = true, multiValued = false)
68 private String command = null;
69
70 @Argument(index = 1, name = "networkId", description = "Network ID",
71 required = true, multiValued = false)
72 private Long networkId = null;
73
74 @Option(name = "--deviceId", description = "Device ID",
75 required = false, multiValued = false)
76 private String deviceIdString = null;
77
78 // Traffic selector
79 @Option(name = "-s", aliases = "--ethSrc", description = "Source MAC Address",
80 required = false, multiValued = false)
81 private String srcMacString = null;
82
83 @Option(name = "-d", aliases = "--ethDst", description = "Destination MAC Address",
84 required = false, multiValued = false)
85 private String dstMacString = null;
86
87 @Option(name = "-t", aliases = "--ethType", description = "Ethernet Type",
88 required = false, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070089 @Completion(EthTypeCompleter.class)
Claudine Chiu1f036b82017-03-09 16:45:56 -050090 private String ethTypeString = null;
91
92 @Option(name = "-v", aliases = "--vlan", description = "VLAN ID",
93 required = false, multiValued = false)
94 private String vlanString = null;
95
96 @Option(name = "--ipProto", description = "IP Protocol",
97 required = false, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070098 @Completion(IpProtocolCompleter.class)
Claudine Chiu1f036b82017-03-09 16:45:56 -050099 private String ipProtoString = null;
100
101 @Option(name = "--ipSrc", description = "Source IP Prefix",
102 required = false, multiValued = false)
103 private String srcIpString = null;
104
105 @Option(name = "--ipDst", description = "Destination IP Prefix",
106 required = false, multiValued = false)
107 private String dstIpString = null;
108
109 @Option(name = "--fLabel", description = "IPv6 Flow Label",
110 required = false, multiValued = false)
111 private String fLabelString = null;
112
113 @Option(name = "--icmp6Type", description = "ICMPv6 Type",
114 required = false, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -0700115 @Completion(Icmp6TypeCompleter.class)
Claudine Chiu1f036b82017-03-09 16:45:56 -0500116 private String icmp6TypeString = null;
117
118 @Option(name = "--icmp6Code", description = "ICMPv6 Code",
119 required = false, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -0700120 @Completion(Icmp6CodeCompleter.class)
Claudine Chiu1f036b82017-03-09 16:45:56 -0500121 private String icmp6CodeString = null;
122
123 @Option(name = "--ndTarget", description = "IPv6 Neighbor Discovery Target Address",
124 required = false, multiValued = false)
125 private String ndTargetString = null;
126
127 @Option(name = "--ndSLL", description = "IPv6 Neighbor Discovery Source Link-Layer",
128 required = false, multiValued = false)
129 private String ndSllString = null;
130
131 @Option(name = "--ndTLL", description = "IPv6 Neighbor Discovery Target Link-Layer",
132 required = false, multiValued = false)
133 private String ndTllString = null;
134
135 @Option(name = "--tcpSrc", description = "Source TCP Port",
136 required = false, multiValued = false)
137 private String srcTcpString = null;
138
139 @Option(name = "--tcpDst", description = "Destination TCP Port",
140 required = false, multiValued = false)
141 private String dstTcpString = null;
142
143 @Option(name = "--extHdr", description = "IPv6 Extension Header Pseudo-field",
144 required = false, multiValued = true)
Ray Milkey0068fd02018-10-11 15:45:39 -0700145 @Completion(ExtHeaderCompleter.class)
Claudine Chiu1f036b82017-03-09 16:45:56 -0500146 private List<String> extHdrStringList = null;
147
148 @Override
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 protected void doExecute() {
Claudine Chiu1f036b82017-03-09 16:45:56 -0500150 VirtualNetworkService service = get(VirtualNetworkService.class);
151 PacketService virtualPacketService = service.get(NetworkId.networkId(networkId), PacketService.class);
152
153 if (command == null) {
154 print("Command is not defined");
155 return;
156 }
157
158 if (command.equals("getRequests")) {
159 getRequests(virtualPacketService);
160 return;
161 }
162
163 TrafficSelector selector = buildTrafficSelector();
164 PacketPriority packetPriority = PacketPriority.CONTROL; //TODO allow user to specify
165 Optional<DeviceId> optionalDeviceId = null;
166 if (!isNullOrEmpty(deviceIdString)) {
167 optionalDeviceId = Optional.of(DeviceId.deviceId(deviceIdString));
168 }
169
170 if (command.equals("requestPackets")) {
171 if (optionalDeviceId != null) {
172 virtualPacketService.requestPackets(selector, packetPriority, appId(), optionalDeviceId);
173 } else {
174 virtualPacketService.requestPackets(selector, packetPriority, appId());
175 }
176 print("Virtual packet requested:\n%s", selector);
177 return;
178 }
179
180 if (command.equals("cancelPackets")) {
181 if (optionalDeviceId != null) {
182 virtualPacketService.cancelPackets(selector, packetPriority, appId(), optionalDeviceId);
183 } else {
184 virtualPacketService.cancelPackets(selector, packetPriority, appId());
185 }
186 print("Virtual packet cancelled:\n%s", selector);
187 return;
188 }
189
190 print("Unsupported command %s", command);
191 }
192
193 private void getRequests(PacketService packetService) {
194 List<PacketRequest> packetRequests = packetService.getRequests();
195 if (outputJson()) {
196 print("%s", json(packetRequests));
197 } else {
198 packetRequests.forEach(packetRequest -> print(packetRequest.toString()));
199 }
200 }
201
202 private JsonNode json(List<PacketRequest> packetRequests) {
203 ObjectMapper mapper = new ObjectMapper();
204 ArrayNode result = mapper.createArrayNode();
205 packetRequests.forEach(packetRequest ->
206 result.add(jsonForEntity(packetRequest, PacketRequest.class)));
207 return result;
208 }
209
210 /**
211 * Constructs a traffic selector based on the command line arguments
212 * presented to the command.
213 * @return traffic selector
214 */
215 private TrafficSelector buildTrafficSelector() {
216 IpPrefix srcIpPrefix = null;
217 IpPrefix dstIpPrefix = null;
218
219 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
220
221 if (!isNullOrEmpty(srcIpString)) {
222 srcIpPrefix = IpPrefix.valueOf(srcIpString);
223 if (srcIpPrefix.isIp4()) {
224 selectorBuilder.matchIPSrc(srcIpPrefix);
225 } else {
226 selectorBuilder.matchIPv6Src(srcIpPrefix);
227 }
228 }
229
230 if (!isNullOrEmpty(dstIpString)) {
231 dstIpPrefix = IpPrefix.valueOf(dstIpString);
232 if (dstIpPrefix.isIp4()) {
233 selectorBuilder.matchIPDst(dstIpPrefix);
234 } else {
235 selectorBuilder.matchIPv6Dst(dstIpPrefix);
236 }
237 }
238
239 if ((srcIpPrefix != null) && (dstIpPrefix != null) &&
240 (srcIpPrefix.version() != dstIpPrefix.version())) {
241 // ERROR: IP src/dst version mismatch
242 throw new IllegalArgumentException(
243 "IP source and destination version mismatch");
244 }
245
246 //
247 // Set the default EthType based on the IP version if the matching
248 // source or destination IP prefixes.
249 //
250 Short ethType = null;
251 if ((srcIpPrefix != null) && srcIpPrefix.isIp6()) {
252 ethType = EthType.IPV6.value();
253 }
254 if ((dstIpPrefix != null) && dstIpPrefix.isIp6()) {
255 ethType = EthType.IPV6.value();
256 }
257 if (!isNullOrEmpty(ethTypeString)) {
258 ethType = EthType.parseFromString(ethTypeString);
259 }
260 if (ethType != null) {
261 selectorBuilder.matchEthType(ethType);
262 }
263 if (!isNullOrEmpty(vlanString)) {
264 selectorBuilder.matchVlanId(VlanId.vlanId(Short.parseShort(vlanString)));
265 }
266 if (!isNullOrEmpty(srcMacString)) {
267 selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString));
268 }
269
270 if (!isNullOrEmpty(dstMacString)) {
271 selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString));
272 }
273
274 if (!isNullOrEmpty(ipProtoString)) {
275 short ipProtoShort = IpProtocol.parseFromString(ipProtoString);
276 selectorBuilder.matchIPProtocol((byte) ipProtoShort);
277 }
278
279 if (!isNullOrEmpty(fLabelString)) {
280 selectorBuilder.matchIPv6FlowLabel(Integer.parseInt(fLabelString));
281 }
282
283 if (!isNullOrEmpty(icmp6TypeString)) {
284 byte icmp6Type = Icmp6Type.parseFromString(icmp6TypeString);
285 selectorBuilder.matchIcmpv6Type(icmp6Type);
286 }
287
288 if (!isNullOrEmpty(icmp6CodeString)) {
289 byte icmp6Code = Icmp6Code.parseFromString(icmp6CodeString);
290 selectorBuilder.matchIcmpv6Code(icmp6Code);
291 }
292
293 if (!isNullOrEmpty(ndTargetString)) {
294 selectorBuilder.matchIPv6NDTargetAddress(Ip6Address.valueOf(ndTargetString));
295 }
296
297 if (!isNullOrEmpty(ndSllString)) {
298 selectorBuilder.matchIPv6NDSourceLinkLayerAddress(MacAddress.valueOf(ndSllString));
299 }
300
301 if (!isNullOrEmpty(ndTllString)) {
302 selectorBuilder.matchIPv6NDTargetLinkLayerAddress(MacAddress.valueOf(ndTllString));
303 }
304
305 if (!isNullOrEmpty(srcTcpString)) {
306 selectorBuilder.matchTcpSrc(TpPort.tpPort(Integer.parseInt(srcTcpString)));
307 }
308
309 if (!isNullOrEmpty(dstTcpString)) {
310 selectorBuilder.matchTcpDst(TpPort.tpPort(Integer.parseInt(dstTcpString)));
311 }
312
313 if (extHdrStringList != null) {
314 short extHdr = 0;
315 for (String extHdrString : extHdrStringList) {
316 extHdr = (short) (extHdr | ExtHeader.parseFromString(extHdrString));
317 }
318 selectorBuilder.matchIPv6ExthdrFlags(extHdr);
319 }
320
321 return selectorBuilder.build();
322 }
323}