Andreas Papazois
Committed by Gerrit Code Review

Command using VlanQuery behavior on device.

Change-Id: Ifef86810d1f8bf8b59a1e9ba2735cd79bfb890f7
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
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 +package org.onosproject.cli.net;
17 +
18 +import org.apache.karaf.shell.commands.Argument;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onlab.packet.VlanId;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.net.ConnectPoint;
23 +import org.onosproject.net.Device;
24 +import org.onosproject.net.DeviceId;
25 +import org.onosproject.net.Port;
26 +import org.onosproject.net.PortNumber;
27 +import org.onosproject.net.behaviour.VlanQuery;
28 +import org.onosproject.net.device.DeviceService;
29 +import org.onosproject.net.driver.DriverHandler;
30 +import org.onosproject.net.driver.DriverService;
31 +
32 +import java.util.ArrayList;
33 +import java.util.Arrays;
34 +import java.util.Set;
35 +
36 +/**
37 + * Command to show the list of unused vlan-ids.
38 + */
39 +@Command(scope = "onos", name = "port-query-vlans",
40 + description = "Lists all unused VLAN-IDs on port")
41 +public class PortQueryVlansCommand extends AbstractShellCommand {
42 +
43 + private static final String AVAIL_VLANS = "VLAN-ID: %s";
44 + private static final String VLAN_NOT_AVAILABLE = "No unused VLAN-ID";
45 + private static final String FMT = "port=%s, state=%s, type=%s, speed=%s%s";
46 + private static final String NO_SUPPORT = "Device not supporting VLAN-ID retrieval";
47 + private static final String FAILURE = "Failed to retrieve VLAN information: ";
48 +
49 + @Argument(index = 0, name = "port",
50 + description = "Port Description",
51 + required = true, multiValued = true)
52 + private String[] ports;
53 +
54 +
55 + @Override
56 + protected void execute() {
57 + DeviceService service = get(DeviceService.class);
58 + for (String portStr : ports) {
59 + ConnectPoint connectPoint = ConnectPoint.deviceConnectPoint(portStr);
60 + Port port = service.getPort(connectPoint.deviceId(), connectPoint.port());
61 + printPort(port);
62 + printVlans(port);
63 + }
64 + }
65 +
66 + private void printPort(Port port) {
67 + String portName = portName(port.number());
68 + Object portIsEnabled = port.isEnabled() ? "enabled" : "disabled";
69 + String portType = port.type().toString().toLowerCase();
70 + String annotations = annotations(port.annotations());
71 + print(FMT, portName, portIsEnabled, portType, port.portSpeed(), annotations);
72 + }
73 +
74 + private String portName(PortNumber port) {
75 + return port.equals(PortNumber.LOCAL) ? "local" : port.toString();
76 + }
77 +
78 + private void printVlans(Port port) {
79 + DeviceService deviceService = get(DeviceService.class);
80 + DriverService driverService = get(DriverService.class);
81 +
82 + DeviceId deviceId = (DeviceId) port.element().id();
83 + Device device = deviceService.getDevice(deviceId);
84 +
85 + if (!device.is(VlanQuery.class)) {
86 + // The relevant behavior is not supported by the device.
87 + print(NO_SUPPORT);
88 + return;
89 + }
90 +
91 + DriverHandler h = driverService.createHandler(deviceId);
92 + VlanQuery vlanQuery = h.behaviour(VlanQuery.class);
93 +
94 + try {
95 + Set<VlanId> vlanIds = vlanQuery.queryVlanIds(port.number());
96 +
97 + if (vlanIds.isEmpty()) {
98 + print(VLAN_NOT_AVAILABLE);
99 + } else {
100 + print(AVAIL_VLANS, getRanges(vlanIds).toString());
101 + }
102 + } catch (Exception e) {
103 + print(FAILURE + e.getMessage());
104 + }
105 + }
106 +
107 + private static ArrayList getRanges(Set<VlanId> vlans) {
108 + short i = 0;
109 + short[] vlanArray = new short[vlans.size()];
110 + for (VlanId vlanId : vlans) {
111 + vlanArray[i++] = vlanId.toShort();
112 + }
113 + Arrays.sort(vlanArray);
114 +
115 + ArrayList ranges = new ArrayList();
116 + short rStart = 0;
117 + short rEnd = 0;
118 +
119 + for (i = 2; i < vlanArray.length; i++) {
120 + if (vlanArray[i] == vlanArray[i - 1] + 1 &&
121 + vlanArray[i] == vlanArray[i - 2] + 2) {
122 + // Three consecutive VLAN-IDs found, so range exists.
123 + if (rEnd == vlanArray[i - 1]) {
124 + // Range already exists, so step the end.
125 + rEnd = vlanArray[i];
126 + } else {
127 + // Setup a new range.
128 + rStart = vlanArray[i - 2];
129 + rEnd = vlanArray[i];
130 + }
131 + } else {
132 + // Not in a range.
133 + if (rEnd == vlanArray[i - 1]) {
134 + // Previous range is discontinued and is stored.
135 + ranges.add(rStart + "-" + rEnd);
136 + } else {
137 + // No previous range.
138 + if (vlanArray[i] != vlanArray[i - 1] + 1) {
139 + // Current VLAN-ID is not 2nd consecutive.
140 + if (vlanArray[i - 1] == vlanArray[i - 2] + 1) {
141 + // The 2 previous VLAN-IDs were consequetive, so 2nd
142 + // last is stored separately.
143 + ranges.add(vlanArray[i - 2]);
144 + }
145 + // Previous is stored, when current is not consequetive.
146 + ranges.add(vlanArray[i - 1]);
147 + }
148 + }
149 + }
150 + }
151 + if (rEnd == vlanArray[vlanArray.length - 1]) {
152 + // Array finished with a range.
153 + ranges.add(rStart + "-" + rEnd);
154 + } else {
155 + if (vlanArray[vlanArray.length - 1] == vlanArray[vlanArray.length - 2] + 1) {
156 + // Previous is stored, when current is consequetive.
157 + ranges.add(vlanArray[vlanArray.length - 2]);
158 + }
159 + // Last item is stored
160 + ranges.add(vlanArray[vlanArray.length - 1]);
161 + }
162 + return ranges;
163 + }
164 +}
...@@ -463,6 +463,13 @@ ...@@ -463,6 +463,13 @@
463 </command> 463 </command>
464 464
465 <command> 465 <command>
466 + <action class="org.onosproject.cli.net.PortQueryVlansCommand"/>
467 + <completers>
468 + <ref component-id="connectPointCompleter"/>
469 + </completers>
470 + </command>
471 +
472 + <command>
466 <action class="org.onosproject.cli.net.TableStatisticsCommand"/> 473 <action class="org.onosproject.cli.net.TableStatisticsCommand"/>
467 </command> 474 </command>
468 475
......