/* * 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 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.incubator.net.intf.InterfaceService; import org.onosproject.net.EncapsulationType; import org.onosproject.vpls.api.VplsData; import org.onosproject.vpls.api.Vpls; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.stream.Collectors; 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\n" + "State: %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 + "."; protected static Vpls vpls; protected static InterfaceService interfaceService; @Argument(index = 0, name = "command", description = "Command name (add-if|" + "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() { if (vpls == null) { vpls = get(Vpls.class); } if (interfaceService == null) { interfaceService = get(InterfaceService.class); } VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command); if (enumCommand != null) { switch (enumCommand) { case ADD_IFACE: addIface(vplsName, optArg); 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; case CLEAN: cleanVpls(); 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 */ protected void addIface(String vplsName, String ifaceName) { if (vplsName == null) { print(INSERT_VPLS_NAME); return; } if (ifaceName == null) { print(INSERT_INTERFACE); return; } Interface iface = getInterface(ifaceName); VplsData vplsData = vpls.getVpls(vplsName); if (vplsData == null) { print(VPLS_NOT_FOUND, vplsName); return; } if (iface == null) { print(IFACE_NOT_FOUND, ifaceName); return; } if (isIfaceAssociated(iface)) { print(IFACE_ALREADY_ASSOCIATED, ifaceName, getVplsByInterface(iface).name()); return; } vpls.addInterface(vplsData, iface); } /** * Creates a new VPLS. * * @param vplsName the name of the VLPS */ protected void create(String vplsName) { if (vplsName == null || vplsName.isEmpty()) { print(INSERT_VPLS_NAME); return; } VplsData vplsData = vpls.getVpls(vplsName); if (vplsData != null) { print(VPLS_ALREADY_EXISTS, vplsName); return; } vpls.createVpls(vplsName, EncapsulationType.NONE); } /** * Deletes a VPLS. * * @param vplsName the name of the VLPS */ protected void delete(String vplsName) { if (vplsName == null) { print(INSERT_VPLS_NAME); return; } VplsData vplsData = vpls.getVpls(vplsName); if (vplsData == null) { print(VPLS_NOT_FOUND, vplsName); return; } vpls.removeVpls(vplsData); } /** * Lists the configured VPLSs. */ protected void list() { List<String> vplsNames = vpls.getAllVpls().stream() .map(VplsData::name) .collect(Collectors.toList()); 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 */ protected void removeIface(String vplsName, String ifaceName) { if (vplsName == null) { print(INSERT_VPLS_NAME); return; } if (ifaceName == null) { print(INSERT_INTERFACE); return; } VplsData vplsData = vpls.getVpls(vplsName); Interface iface = getInterface(ifaceName); if (vplsData == null) { print(VPLS_NOT_FOUND, vplsName); return; } if (iface == null) { print(IFACE_NOT_FOUND, ifaceName); return; } if (!vplsData.interfaces().contains(iface)) { print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName); return; } vpls.removeInterface(vplsData, iface); } /** * Sets the encapsulation type for a VPLS. * * @param vplsName the name of the VPLS * @param encap the encapsulation type */ protected void setEncap(String vplsName, String encap) { if (vplsName == null) { print(INSERT_VPLS_NAME); return; } if (encap == null) { print(INSERT_ENCAP_TYPE); return; } VplsData vplsData = vpls.getVpls(vplsName); if (vplsData == null) { 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; } vpls.setEncapsulationType(vplsData, encapType); } /** * Shows the details of one or more VPLSs. * * @param vplsName the name of the VPLS */ protected void show(String vplsName) { if (!isNullOrEmpty(vplsName)) { // A VPLS name is provided. Check first if the VPLS exists VplsData vplsData = vpls.getVpls(vplsName); if (vplsData != null) { Set<String> ifaceNames = vplsData.interfaces().stream() .map(Interface::name) .collect(Collectors.toSet()); print(VPLS_DISPLAY, vplsName, ifaceNames, vplsData.encapsulationType().toString(), vplsData.state()); } else { print(VPLS_NOT_FOUND, vplsName); } } else { Collection<VplsData> vplses = vpls.getAllVpls(); // No VPLS names are provided. Display all VPLSs configured print(SEPARATOR); vplses.forEach(vplsData -> { Set<String> ifaceNames = vplsData.interfaces().stream() .map(Interface::name) .collect(Collectors.toSet()); print(VPLS_DISPLAY, vplsData.name(), ifaceNames, vplsData.encapsulationType().toString(), vplsData.state()); print(SEPARATOR); }); } } /** * Remove all VPLS. */ protected void cleanVpls() { vpls.removeAllVpls(); } /** * States if an interface is already associated to a VPLS. * * @param iface the interface * @return true if the interface is already associated to a VPLS; false * otherwise */ private static boolean isIfaceAssociated(Interface iface) { return vpls.getAllVpls() .stream() .map(VplsData::interfaces) .flatMap(Collection::stream) .anyMatch(iface::equals); } /** * Gets a network interface by given interface name. * * @param interfaceName the interface name * @return the network interface */ private Interface getInterface(String interfaceName) { // FIXME: only returns first interface it found // multiple interface with same name not support return interfaceService.getInterfaces().stream() .filter(iface -> iface.name().equals(interfaceName)) .findFirst() .orElse(null); } /** * Gets a VPLS related to the network interface. * * @param iface the network interface * @return the VPLS related to the network interface */ private VplsData getVplsByInterface(Interface iface) { return vpls.getAllVpls().stream() .filter(vplsData -> vplsData.interfaces().contains(iface)) .findFirst() .orElse(null); } }