blob: d4bfa8d2db6aa7c1009006573151f6468fdc7f90 [file] [log] [blame]
Luca Pretedce16f82016-11-22 13:11:56 -08001/*
Luca Prete99f6f282016-12-05 15:33:36 -08002 * Copyright 2015-present Open Networking Laboratory
Luca Pretedce16f82016-11-22 13:11:56 -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
Luca Prete99f6f282016-12-05 15:33:36 -080014 * limitations under the License.
Luca Pretedce16f82016-11-22 13:11:56 -080015 */
16package org.onosproject.vpls.cli;
17
18import com.google.common.collect.Lists;
19import com.google.common.collect.SetMultimap;
20import com.google.common.collect.Sets;
21import org.apache.karaf.shell.commands.Argument;
22import org.apache.karaf.shell.commands.Command;
23import org.onosproject.cli.AbstractShellCommand;
24import org.onosproject.incubator.net.intf.Interface;
Luca Pretedce16f82016-11-22 13:11:56 -080025import org.onosproject.net.EncapsulationType;
26import org.onosproject.vpls.config.VplsConfigService;
27
28import java.util.Collections;
29import java.util.List;
30import java.util.Map;
31import java.util.Optional;
32import java.util.Set;
33
34import static com.google.common.base.Strings.isNullOrEmpty;
35
36/**
37 * CLI to interact with the VPLS application.
38 */
39@Command(scope = "onos", name = "vpls",
40 description = "Manages the VPLS application")
41public class VplsCommand extends AbstractShellCommand {
42
43 // Color codes and style
44 private static final String BOLD = "\u001B[1m";
45 private static final String COLOR_ERROR = "\u001B[31m";
46 private static final String RESET = "\u001B[0m";
47
48 // Messages and string formatter
49 private static final String ENCAP_NOT_FOUND =
50 COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET +
51 COLOR_ERROR + " not found" + RESET;
52
53 private static final String IFACE_NOT_FOUND =
54 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
55 " not found" + RESET;
56
57 private static final String IFACE_ALREADY_ASSOCIATED =
58 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
59 " already associated to VPLS " + BOLD + "%s" + RESET +
60 COLOR_ERROR + "" + RESET;
61
Luca Prete8dbbea82016-12-07 18:10:10 -080062 private static final String INSERT_VPLS_NAME =
63 COLOR_ERROR + "Missing the " + BOLD + "VPLS name." + RESET +
64 COLOR_ERROR + " Specifying a VPLS name is mandatory." +
65 RESET;
66
67 private static final String INSERT_ENCAP_TYPE =
68 COLOR_ERROR + "Missing the " + BOLD + "encapsulation type." +
69 RESET + COLOR_ERROR + " Encapsulation type is mandatory." +
70 RESET;
71
72 private static final String INSERT_INTERFACE =
73 COLOR_ERROR + "Missing the " + BOLD + "interface name." +
74 RESET + COLOR_ERROR + " Specifying an interface name is" +
75 " mandatory." + RESET;
76
Luca Pretedce16f82016-11-22 13:11:56 -080077 private static final String SEPARATOR = "----------------";
78
79 private static final String VPLS_ALREADY_EXISTS =
80 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
81 " already exists" + RESET;
82
83 private static final String VPLS_COMMAND_NOT_FOUND =
84 COLOR_ERROR + "VPLS command " + BOLD + "%s" + RESET + COLOR_ERROR +
85 " not found" + RESET;
86
87 private static final String VPLS_DISPLAY = "VPLS name: " + BOLD +
88 "%s" + RESET + "\nAssociated interfaces: %s\nEncapsulation: %s";
89
Luca Pretedce16f82016-11-22 13:11:56 -080090 private static final String VPLS_NOT_FOUND =
91 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
92 " not found" + RESET;
93
94 private static final String IFACE_NOT_ASSOCIATED =
95 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
96 " cannot be removed from VPLS " + BOLD + "%s" + RESET +
97 COLOR_ERROR + ". The interface is associated to another" +
98 "VPLS (" + BOLD + "%s" + RESET + COLOR_ERROR + ")" + RESET;
99
100 private static VplsConfigService vplsConfigService =
101 get(VplsConfigService.class);
Luca Pretedce16f82016-11-22 13:11:56 -0800102
Luca Prete8dbbea82016-12-07 18:10:10 -0800103 @Argument(index = 0, name = "command", description = "Command name (add-if|" +
104 "clean|create|delete|list|rem-if|set-encap|show)",
Luca Pretedce16f82016-11-22 13:11:56 -0800105 required = true, multiValued = false)
106 String command = null;
107
108 @Argument(index = 1, name = "vplsName", description = "The name of the VPLS",
109 required = false, multiValued = false)
110 String vplsName = null;
111
Luca Prete8dbbea82016-12-07 18:10:10 -0800112 @Argument(index = 2, name = "optArg", description = "The interface name or" +
113 " the encapsulation type for set-encap",
Luca Pretedce16f82016-11-22 13:11:56 -0800114 required = false, multiValued = false)
115 String optArg = null;
116
117 @Override
118 protected void execute() {
119 VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command);
120 if (enumCommand != null) {
121 switch (enumCommand) {
122 case ADD_IFACE:
123 addIface(vplsName, optArg);
124 break;
125 case CLEAN:
126 clean();
127 break;
128 case CREATE:
129 create(vplsName);
130 break;
131 case DELETE:
132 delete(vplsName);
133 break;
134 case LIST:
135 list();
136 break;
137 case REMOVE_IFACE:
138 removeIface(vplsName, optArg);
139 break;
140 case SET_ENCAP:
141 setEncap(vplsName, optArg);
142 break;
143 case SHOW:
144 show(vplsName);
145 break;
146 default:
147 print(VPLS_COMMAND_NOT_FOUND, command);
148 }
Luca Prete8dbbea82016-12-07 18:10:10 -0800149 } else {
150 print(VPLS_COMMAND_NOT_FOUND, command);
Luca Pretedce16f82016-11-22 13:11:56 -0800151 }
152 }
153
154 /**
155 * Adds an inteterface to a VPLS.
156 *
157 * @param vplsName the name of the VLPS
158 * @param ifaceName the name of the interface to add
159 */
160 private void addIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800161 if (vplsName == null) {
162 print(INSERT_VPLS_NAME);
163 return;
164 }
165 if (ifaceName == null) {
166 print(INSERT_INTERFACE);
167 return;
168 }
Luca Pretedce16f82016-11-22 13:11:56 -0800169 if (!vplsExists(vplsName)) {
170 print(VPLS_NOT_FOUND, vplsName);
171 return;
172 }
Luca Pretedce16f82016-11-22 13:11:56 -0800173 if (!ifaceExists(ifaceName)) {
174 print(IFACE_NOT_FOUND, ifaceName);
175 return;
176 }
Luca Pretedce16f82016-11-22 13:11:56 -0800177 if (isIfaceAssociated(ifaceName)) {
178 print(IFACE_ALREADY_ASSOCIATED,
179 ifaceName, vplsNameFromIfaceName(ifaceName));
180 return;
181 }
182
183 vplsConfigService.addIface(vplsName, ifaceName);
184 }
185
186 /**
187 * Cleans the VPLS configuration.
188 */
189 private void clean() {
190 vplsConfigService.cleanVplsConfig();
191 }
192
193 /**
194 * Creates a new VPLS.
195 *
196 * @param vplsName the name of the VLPS
197 */
198 private void create(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800199 if (vplsName == null || vplsName.isEmpty()) {
200 print(INSERT_VPLS_NAME);
201 return;
202 }
Luca Pretedce16f82016-11-22 13:11:56 -0800203 if (vplsExists(vplsName)) {
204 print(VPLS_ALREADY_EXISTS, vplsName);
205 return;
206 }
207 vplsConfigService.addVpls(vplsName, Sets.newHashSet(), null);
208 }
209
210 /**
211 * Deletes a VPLS.
212 *
213 * @param vplsName the name of the VLPS
214 */
215 private void delete(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800216 if (vplsName == null) {
217 print(INSERT_VPLS_NAME);
218 return;
219 }
Luca Pretedce16f82016-11-22 13:11:56 -0800220 if (!vplsExists(vplsName)) {
221 print(VPLS_NOT_FOUND, vplsName);
222 return;
223 }
224 vplsConfigService.removeVpls(vplsName);
225 }
226
227 /**
228 * Lists the configured VPLSs.
229 */
230 private void list() {
231 List<String> vplsNames = Lists.newArrayList(vplsConfigService.vplsNames());
232 Collections.sort(vplsNames);
233
Luca Pretedce16f82016-11-22 13:11:56 -0800234 vplsNames.forEach(vpls -> {
235 print(vpls);
236 });
237 }
238
239 /**
240 * Removes an interface from a VPLS.
241 *
242 * @param vplsName the name of the VLPS
243 * @param ifaceName the name of the interface to remove
244 */
245 private void removeIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800246 if (vplsName == null) {
247 print(INSERT_VPLS_NAME);
248 return;
249 }
250 if (ifaceName == null) {
251 print(INSERT_INTERFACE);
252 return;
253 }
Luca Pretedce16f82016-11-22 13:11:56 -0800254 if (!vplsExists(vplsName)) {
255 print(VPLS_NOT_FOUND, vplsName);
256 return;
257 }
258 if (!ifaceExists(ifaceName)) {
259 print(IFACE_NOT_FOUND, ifaceName);
260 return;
261 }
262 String vplsNameFromIfaceName = vplsNameFromIfaceName(ifaceName);
263 if (!vplsNameFromIfaceName.equals(vplsName)) {
264 print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName, vplsNameFromIfaceName);
265 return;
266 }
267 vplsConfigService.removeIface(ifaceName);
268 }
269
270 /**
271 * Sets the encapsulation type for a VPLS.
272 *
273 * @param vplsName the name of the VPLS
274 * @param encap the encapsulation type
275 */
276 private void setEncap(String vplsName, String encap) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800277 if (vplsName == null) {
278 print(INSERT_VPLS_NAME);
279 return;
280 }
281 if (encap == null) {
282 print(INSERT_ENCAP_TYPE);
283 return;
284 }
Luca Pretedce16f82016-11-22 13:11:56 -0800285 if (!vplsExists(vplsName)) {
286 print(VPLS_NOT_FOUND, vplsName);
287 return;
288 }
289 EncapsulationType encapType = EncapsulationType.enumFromString(encap);
290 if (encapType.equals(EncapsulationType.NONE) &&
291 !encapType.toString().equals(encap)) {
292 print(ENCAP_NOT_FOUND, encap);
293 return;
294 }
295 vplsConfigService.setEncap(vplsName, encap);
296 }
297
298 /**
299 * Shows the details of one or more VPLSs.
300 *
301 * @param vplsName the name of the VPLS
302 */
303 private void show(String vplsName) {
304 List<String> vplsNames = Lists.newArrayList(vplsConfigService.vplsNames());
305 Collections.sort(vplsNames);
306
307 Map<String, EncapsulationType> encapByVplsName =
308 vplsConfigService.encapByVplsName();
309
Luca Pretedce16f82016-11-22 13:11:56 -0800310 if (!isNullOrEmpty(vplsName)) {
311 // A VPLS name is provided. Check first if the VPLS exists
312 if (vplsExists(vplsName)) {
313 print(VPLS_DISPLAY,
314 vplsName,
315 ifacesFromVplsName(vplsName).toString(),
316 encapByVplsName.get(vplsName).toString());
317 } else {
318 print(VPLS_NOT_FOUND, vplsName);
319 }
320 } else {
321 // No VPLS names are provided. Display all VPLSs configured
Luca Prete8dbbea82016-12-07 18:10:10 -0800322 print(SEPARATOR);
Luca Pretedce16f82016-11-22 13:11:56 -0800323 vplsNames.forEach(v -> {
324 print(VPLS_DISPLAY,
325 v,
326 ifacesFromVplsName(v).toString(),
327 encapByVplsName.get(v).toString());
328 print(SEPARATOR);
329 });
330 }
331 }
332
333 /**
334 * States if a VPLS exists or not.
335 *
336 * @param vplsName the name of the VPLS
337 * @return true if the VPLS exists; false otherwise
338 */
339 private static boolean vplsExists(String vplsName) {
340 return vplsConfigService.vplsNames().contains(vplsName);
341 }
342
343 /**
344 * States if an interface is defined or not in the system.
345 *
346 * @param ifaceName the name of the interface
347 * @return true if the interface is defined; false otherwise
348 */
349 private static boolean ifaceExists(String ifaceName) {
350 return vplsConfigService.allIfaces()
351 .stream()
352 .anyMatch(iface -> iface.name().equals(ifaceName));
353 }
354
355 /**
356 * States if an interface is already associated to a VPLS.
357 *
358 * @param ifaceName the name of the interface
359 * @return true if the interface is already associated to a VPLS; false
360 * otherwise
361 */
362 private static boolean isIfaceAssociated(String ifaceName) {
363 return vplsConfigService.ifaces()
364 .stream()
365 .anyMatch(iface -> iface.name().equals(ifaceName));
366 }
367
368 /**
369 * Returns the name of a VPLS, given the name of an interface associated to
370 * it.
371 *
372 * @param ifaceName the name of the interface
373 * @return the name of the VPLS that has the interface configured; null if
374 * the interface does not exist or is not associated to any VPLS
375 */
376 private static String vplsNameFromIfaceName(String ifaceName) {
377 String vplsName = null;
378
379 Optional<String> optVplsName = vplsConfigService.ifacesByVplsName()
380 .entries()
381 .stream()
382 .filter((entry -> entry.getValue().name().equals(ifaceName)))
383 .map(Map.Entry::getKey)
384 .findFirst();
385
386 if (optVplsName.isPresent()) {
387 vplsName = optVplsName.get();
388 }
389
390 return vplsName;
391 }
392
393 /**
394 * Returns a list of interfaces associated to a VPLS, given a VPLS name.
395 *
396 * @param vplsName the name of the VPLS
397 * @return the set of interfaces associated to the given VPLS; null if the
398 * VPLS is not found
399 */
400 private static Set<String> ifacesFromVplsName(String vplsName) {
401 if (!vplsExists(vplsName)) {
402 return null;
403 }
404 SetMultimap<String, Interface> ifacesByVplsName =
405 vplsConfigService.ifacesByVplsName();
406 Set<String> ifaceNames = Sets.newHashSet();
407
408 ifacesByVplsName.get(vplsName).forEach(iface -> ifaceNames.add(iface.name()));
409
410 return ifaceNames;
411 }
412}