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