| /* |
| * Copyright 2015-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.vpls.cli; |
| |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.SetMultimap; |
| import com.google.common.collect.Sets; |
| import org.apache.karaf.shell.commands.Argument; |
| import org.apache.karaf.shell.commands.Command; |
| import org.onosproject.cli.AbstractShellCommand; |
| import org.onosproject.incubator.net.intf.Interface; |
| import org.onosproject.net.EncapsulationType; |
| import org.onosproject.vpls.config.VplsConfigService; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Set; |
| |
| import static com.google.common.base.Strings.isNullOrEmpty; |
| |
| /** |
| * CLI to interact with the VPLS application. |
| */ |
| @Command(scope = "onos", name = "vpls", |
| description = "Manages the VPLS application") |
| public class VplsCommand extends AbstractShellCommand { |
| |
| // Color codes and style |
| private static final String BOLD = "\u001B[1m"; |
| private static final String COLOR_ERROR = "\u001B[31m"; |
| private static final String RESET = "\u001B[0m"; |
| |
| // Messages and string formatter |
| private static final String ENCAP_NOT_FOUND = |
| COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET + |
| COLOR_ERROR + " not found" + RESET; |
| |
| private static final String IFACE_NOT_FOUND = |
| COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR + |
| " not found" + RESET; |
| |
| private static final String IFACE_ALREADY_ASSOCIATED = |
| COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR + |
| " already associated to VPLS " + BOLD + "%s" + RESET + |
| COLOR_ERROR + "" + RESET; |
| |
| private static final String INSERT_VPLS_NAME = |
| COLOR_ERROR + "Missing the " + BOLD + "VPLS name." + RESET + |
| COLOR_ERROR + " Specifying a VPLS name is mandatory." + |
| RESET; |
| |
| private static final String INSERT_ENCAP_TYPE = |
| COLOR_ERROR + "Missing the " + BOLD + "encapsulation type." + |
| RESET + COLOR_ERROR + " Encapsulation type is mandatory." + |
| RESET; |
| |
| private static final String INSERT_INTERFACE = |
| COLOR_ERROR + "Missing the " + BOLD + "interface name." + |
| RESET + COLOR_ERROR + " Specifying an interface name is" + |
| " mandatory." + RESET; |
| |
| private static final String SEPARATOR = "----------------"; |
| |
| private static final String VPLS_ALREADY_EXISTS = |
| COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR + |
| " already exists" + RESET; |
| |
| private static final String VPLS_COMMAND_NOT_FOUND = |
| COLOR_ERROR + "VPLS command " + BOLD + "%s" + RESET + COLOR_ERROR + |
| " not found" + RESET; |
| |
| private static final String VPLS_DISPLAY = "VPLS name: " + BOLD + |
| "%s" + RESET + "\nAssociated interfaces: %s\nEncapsulation: %s"; |
| |
| private static final String VPLS_NOT_FOUND = |
| COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR + |
| " not found" + RESET; |
| |
| private static final String IFACE_NOT_ASSOCIATED = |
| COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR + |
| " cannot be removed from VPLS " + BOLD + "%s" + RESET + |
| COLOR_ERROR + ". The interface is associated to another" + |
| "VPLS (" + BOLD + "%s" + RESET + COLOR_ERROR + ")" + RESET; |
| |
| private static VplsConfigService vplsConfigService = |
| get(VplsConfigService.class); |
| |
| @Argument(index = 0, name = "command", description = "Command name (add-if|" + |
| "clean|create|delete|list|rem-if|set-encap|show)", |
| required = true, multiValued = false) |
| String command = null; |
| |
| @Argument(index = 1, name = "vplsName", description = "The name of the VPLS", |
| required = false, multiValued = false) |
| String vplsName = null; |
| |
| @Argument(index = 2, name = "optArg", description = "The interface name or" + |
| " the encapsulation type for set-encap", |
| required = false, multiValued = false) |
| String optArg = null; |
| |
| @Override |
| protected void execute() { |
| VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command); |
| if (enumCommand != null) { |
| switch (enumCommand) { |
| case ADD_IFACE: |
| addIface(vplsName, optArg); |
| break; |
| case CLEAN: |
| clean(); |
| break; |
| case CREATE: |
| create(vplsName); |
| break; |
| case DELETE: |
| delete(vplsName); |
| break; |
| case LIST: |
| list(); |
| break; |
| case REMOVE_IFACE: |
| removeIface(vplsName, optArg); |
| break; |
| case SET_ENCAP: |
| setEncap(vplsName, optArg); |
| break; |
| case SHOW: |
| show(vplsName); |
| break; |
| default: |
| print(VPLS_COMMAND_NOT_FOUND, command); |
| } |
| } else { |
| print(VPLS_COMMAND_NOT_FOUND, command); |
| } |
| } |
| |
| /** |
| * Adds an inteterface to a VPLS. |
| * |
| * @param vplsName the name of the VLPS |
| * @param ifaceName the name of the interface to add |
| */ |
| private void addIface(String vplsName, String ifaceName) { |
| if (vplsName == null) { |
| print(INSERT_VPLS_NAME); |
| return; |
| } |
| if (ifaceName == null) { |
| print(INSERT_INTERFACE); |
| return; |
| } |
| if (!vplsExists(vplsName)) { |
| print(VPLS_NOT_FOUND, vplsName); |
| return; |
| } |
| if (!ifaceExists(ifaceName)) { |
| print(IFACE_NOT_FOUND, ifaceName); |
| return; |
| } |
| if (isIfaceAssociated(ifaceName)) { |
| print(IFACE_ALREADY_ASSOCIATED, |
| ifaceName, vplsNameFromIfaceName(ifaceName)); |
| return; |
| } |
| |
| vplsConfigService.addIface(vplsName, ifaceName); |
| } |
| |
| /** |
| * Cleans the VPLS configuration. |
| */ |
| private void clean() { |
| vplsConfigService.cleanVplsConfig(); |
| } |
| |
| /** |
| * Creates a new VPLS. |
| * |
| * @param vplsName the name of the VLPS |
| */ |
| private void create(String vplsName) { |
| if (vplsName == null || vplsName.isEmpty()) { |
| print(INSERT_VPLS_NAME); |
| return; |
| } |
| if (vplsExists(vplsName)) { |
| print(VPLS_ALREADY_EXISTS, vplsName); |
| return; |
| } |
| vplsConfigService.addVpls(vplsName, Sets.newHashSet(), null); |
| } |
| |
| /** |
| * Deletes a VPLS. |
| * |
| * @param vplsName the name of the VLPS |
| */ |
| private void delete(String vplsName) { |
| if (vplsName == null) { |
| print(INSERT_VPLS_NAME); |
| return; |
| } |
| if (!vplsExists(vplsName)) { |
| print(VPLS_NOT_FOUND, vplsName); |
| return; |
| } |
| vplsConfigService.removeVpls(vplsName); |
| } |
| |
| /** |
| * Lists the configured VPLSs. |
| */ |
| private void list() { |
| List<String> vplsNames = Lists.newArrayList(vplsConfigService.vplsNames()); |
| Collections.sort(vplsNames); |
| |
| vplsNames.forEach(vpls -> { |
| print(vpls); |
| }); |
| } |
| |
| /** |
| * Removes an interface from a VPLS. |
| * |
| * @param vplsName the name of the VLPS |
| * @param ifaceName the name of the interface to remove |
| */ |
| private void removeIface(String vplsName, String ifaceName) { |
| if (vplsName == null) { |
| print(INSERT_VPLS_NAME); |
| return; |
| } |
| if (ifaceName == null) { |
| print(INSERT_INTERFACE); |
| return; |
| } |
| if (!vplsExists(vplsName)) { |
| print(VPLS_NOT_FOUND, vplsName); |
| return; |
| } |
| if (!ifaceExists(ifaceName)) { |
| print(IFACE_NOT_FOUND, ifaceName); |
| return; |
| } |
| String vplsNameFromIfaceName = vplsNameFromIfaceName(ifaceName); |
| if (!vplsNameFromIfaceName.equals(vplsName)) { |
| print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName, vplsNameFromIfaceName); |
| return; |
| } |
| vplsConfigService.removeIface(ifaceName); |
| } |
| |
| /** |
| * Sets the encapsulation type for a VPLS. |
| * |
| * @param vplsName the name of the VPLS |
| * @param encap the encapsulation type |
| */ |
| private void setEncap(String vplsName, String encap) { |
| if (vplsName == null) { |
| print(INSERT_VPLS_NAME); |
| return; |
| } |
| if (encap == null) { |
| print(INSERT_ENCAP_TYPE); |
| return; |
| } |
| if (!vplsExists(vplsName)) { |
| print(VPLS_NOT_FOUND, vplsName); |
| return; |
| } |
| EncapsulationType encapType = EncapsulationType.enumFromString(encap); |
| if (encapType.equals(EncapsulationType.NONE) && |
| !encapType.toString().equals(encap)) { |
| print(ENCAP_NOT_FOUND, encap); |
| return; |
| } |
| vplsConfigService.setEncap(vplsName, encap); |
| } |
| |
| /** |
| * Shows the details of one or more VPLSs. |
| * |
| * @param vplsName the name of the VPLS |
| */ |
| private void show(String vplsName) { |
| List<String> vplsNames = Lists.newArrayList(vplsConfigService.vplsNames()); |
| Collections.sort(vplsNames); |
| |
| Map<String, EncapsulationType> encapByVplsName = |
| vplsConfigService.encapByVplsName(); |
| |
| if (!isNullOrEmpty(vplsName)) { |
| // A VPLS name is provided. Check first if the VPLS exists |
| if (vplsExists(vplsName)) { |
| print(VPLS_DISPLAY, |
| vplsName, |
| ifacesFromVplsName(vplsName).toString(), |
| encapByVplsName.get(vplsName).toString()); |
| } else { |
| print(VPLS_NOT_FOUND, vplsName); |
| } |
| } else { |
| // No VPLS names are provided. Display all VPLSs configured |
| print(SEPARATOR); |
| vplsNames.forEach(v -> { |
| print(VPLS_DISPLAY, |
| v, |
| ifacesFromVplsName(v).toString(), |
| encapByVplsName.get(v).toString()); |
| print(SEPARATOR); |
| }); |
| } |
| } |
| |
| /** |
| * States if a VPLS exists or not. |
| * |
| * @param vplsName the name of the VPLS |
| * @return true if the VPLS exists; false otherwise |
| */ |
| private static boolean vplsExists(String vplsName) { |
| return vplsConfigService.vplsNames().contains(vplsName); |
| } |
| |
| /** |
| * States if an interface is defined or not in the system. |
| * |
| * @param ifaceName the name of the interface |
| * @return true if the interface is defined; false otherwise |
| */ |
| private static boolean ifaceExists(String ifaceName) { |
| return vplsConfigService.allIfaces() |
| .stream() |
| .anyMatch(iface -> iface.name().equals(ifaceName)); |
| } |
| |
| /** |
| * States if an interface is already associated to a VPLS. |
| * |
| * @param ifaceName the name of the interface |
| * @return true if the interface is already associated to a VPLS; false |
| * otherwise |
| */ |
| private static boolean isIfaceAssociated(String ifaceName) { |
| return vplsConfigService.ifaces() |
| .stream() |
| .anyMatch(iface -> iface.name().equals(ifaceName)); |
| } |
| |
| /** |
| * Returns the name of a VPLS, given the name of an interface associated to |
| * it. |
| * |
| * @param ifaceName the name of the interface |
| * @return the name of the VPLS that has the interface configured; null if |
| * the interface does not exist or is not associated to any VPLS |
| */ |
| private static String vplsNameFromIfaceName(String ifaceName) { |
| String vplsName = null; |
| |
| Optional<String> optVplsName = vplsConfigService.ifacesByVplsName() |
| .entries() |
| .stream() |
| .filter((entry -> entry.getValue().name().equals(ifaceName))) |
| .map(Map.Entry::getKey) |
| .findFirst(); |
| |
| if (optVplsName.isPresent()) { |
| vplsName = optVplsName.get(); |
| } |
| |
| return vplsName; |
| } |
| |
| /** |
| * Returns a list of interfaces associated to a VPLS, given a VPLS name. |
| * |
| * @param vplsName the name of the VPLS |
| * @return the set of interfaces associated to the given VPLS; null if the |
| * VPLS is not found |
| */ |
| private static Set<String> ifacesFromVplsName(String vplsName) { |
| if (!vplsExists(vplsName)) { |
| return null; |
| } |
| SetMultimap<String, Interface> ifacesByVplsName = |
| vplsConfigService.ifacesByVplsName(); |
| Set<String> ifaceNames = Sets.newHashSet(); |
| |
| ifacesByVplsName.get(vplsName).forEach(iface -> ifaceNames.add(iface.name())); |
| |
| return ifaceNames; |
| } |
| } |