| /* |
| * Copyright 2015-present Open Networking Foundation |
| * |
| * 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; |
| |
| import com.google.common.collect.ImmutableSet; |
| import org.apache.felix.scr.annotations.Activate; |
| import org.apache.felix.scr.annotations.Component; |
| import org.apache.felix.scr.annotations.Deactivate; |
| import org.apache.felix.scr.annotations.Reference; |
| import org.apache.felix.scr.annotations.ReferenceCardinality; |
| import org.apache.felix.scr.annotations.Service; |
| import org.onosproject.net.intf.Interface; |
| import org.onosproject.net.intf.InterfaceService; |
| import org.onosproject.net.EncapsulationType; |
| import org.onosproject.net.Host; |
| import org.onosproject.net.host.HostEvent; |
| import org.onosproject.net.host.HostListener; |
| import org.onosproject.net.host.HostService; |
| import org.onosproject.store.StoreDelegate; |
| import org.onosproject.vpls.api.VplsData; |
| import org.onosproject.vpls.api.VplsOperationService; |
| import org.onosproject.vpls.api.VplsOperation; |
| import org.onosproject.vpls.api.Vpls; |
| import org.onosproject.vpls.api.VplsStore; |
| import org.onosproject.vpls.store.VplsStoreEvent; |
| import org.slf4j.Logger; |
| |
| import java.util.Collection; |
| import java.util.Set; |
| |
| import static java.util.Objects.*; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Application to create L2 broadcast overlay networks using VLANs. |
| */ |
| @Component(immediate = true) |
| @Service |
| public class VplsManager implements Vpls { |
| public static final String VPLS_APP = "org.onosproject.vpls"; |
| private static final String UNSUPPORTED_STORE_EVENT_TYPE = |
| "Unsupported store event type {}."; |
| private final Logger log = getLogger(getClass()); |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected HostService hostService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected InterfaceService interfaceService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected VplsStore vplsStore; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected VplsOperationService operationService; |
| |
| private StoreDelegate<VplsStoreEvent> vplsStoreDelegate; |
| private HostListener vplsHostListener; |
| |
| @Activate |
| public void activate() { |
| vplsStoreDelegate = new VplsStoreDelegate(); |
| vplsHostListener = new VplsHostListener(); |
| |
| vplsStore.setDelegate(vplsStoreDelegate); |
| hostService.addListener(vplsHostListener); |
| } |
| |
| @Deactivate |
| public void deactivate() { |
| vplsStore.unsetDelegate(vplsStoreDelegate); |
| hostService.removeListener(vplsHostListener); |
| } |
| |
| @Override |
| public VplsData createVpls(String vplsName, EncapsulationType encapsulationType) { |
| requireNonNull(vplsName); |
| requireNonNull(encapsulationType); |
| |
| if (vplsStore.getVpls(vplsName) != null) { |
| return null; |
| } |
| |
| VplsData vplsData = VplsData.of(vplsName, encapsulationType); |
| vplsStore.addVpls(vplsData); |
| |
| return vplsData; |
| } |
| |
| @Override |
| public VplsData removeVpls(VplsData vplsData) { |
| requireNonNull(vplsData); |
| VplsData newData = VplsData.of(vplsData); |
| newData.state(VplsData.VplsState.REMOVING); |
| vplsStore.removeVpls(vplsData); |
| return vplsData; |
| } |
| |
| @Override |
| public void addInterfaces(VplsData vplsData, Collection<Interface> interfaces) { |
| requireNonNull(vplsData); |
| requireNonNull(interfaces); |
| VplsData newData = VplsData.of(vplsData); |
| newData.addInterfaces(interfaces); |
| updateVplsStatus(newData, VplsData.VplsState.UPDATING); |
| } |
| |
| @Override |
| public void addInterface(VplsData vplsData, Interface iface) { |
| requireNonNull(vplsData); |
| requireNonNull(iface); |
| VplsData newData = VplsData.of(vplsData); |
| newData.addInterface(iface); |
| updateVplsStatus(newData, VplsData.VplsState.UPDATING); |
| } |
| |
| @Override |
| public void setEncapsulationType(VplsData vplsData, EncapsulationType encapsulationType) { |
| requireNonNull(vplsData); |
| requireNonNull(encapsulationType); |
| VplsData newData = VplsData.of(vplsData); |
| if (newData.encapsulationType().equals(encapsulationType)) { |
| // Encap type not changed. |
| return; |
| } |
| newData.encapsulationType(encapsulationType); |
| updateVplsStatus(newData, VplsData.VplsState.UPDATING); |
| } |
| |
| @Override |
| public VplsData getVpls(String vplsName) { |
| requireNonNull(vplsName); |
| return vplsStore.getVpls(vplsName); |
| } |
| |
| @Override |
| public Collection<Interface> removeInterfaces(VplsData vplsData, Collection<Interface> interfaces) { |
| requireNonNull(vplsData); |
| requireNonNull(interfaces); |
| VplsData newData = VplsData.of(vplsData); |
| newData.removeInterfaces(interfaces); |
| updateVplsStatus(newData, VplsData.VplsState.UPDATING); |
| return interfaces; |
| } |
| |
| @Override |
| public Interface removeInterface(VplsData vplsData, Interface iface) { |
| requireNonNull(vplsData); |
| requireNonNull(iface); |
| VplsData newData = VplsData.of(vplsData); |
| newData.removeInterface(iface); |
| updateVplsStatus(newData, VplsData.VplsState.UPDATING); |
| return iface; |
| } |
| |
| @Override |
| public void removeAllVpls() { |
| Set<VplsData> allVplses = ImmutableSet.copyOf(vplsStore.getAllVpls()); |
| allVplses.forEach(this::removeVpls); |
| } |
| |
| @Override |
| public Collection<VplsData> getAllVpls() { |
| return ImmutableSet.copyOf(vplsStore.getAllVpls()); |
| } |
| |
| /** |
| * Updates VPLS status to the store. |
| * |
| * @param vplsData the VPLS |
| * @param vplsState the new state to the VPLS |
| */ |
| private void updateVplsStatus(VplsData vplsData, VplsData.VplsState vplsState) { |
| vplsData.state(vplsState); |
| vplsStore.updateVpls(vplsData); |
| } |
| |
| /** |
| * A listener for host events. |
| * Updates a VPLS if host added or removed. |
| */ |
| class VplsHostListener implements HostListener { |
| @Override |
| public void event(HostEvent event) { |
| Host host = event.subject(); |
| Interface iface = getHostInterface(host); |
| if (iface == null) { |
| return; |
| } |
| VplsData vplsData = vplsStore.getAllVpls().stream() |
| .filter(v -> v.interfaces().contains(iface)) |
| .findFirst() |
| .orElse(null); |
| if (vplsData == null) { |
| // the host does not related to any vpls |
| return; |
| } |
| updateVplsStatus(vplsData, VplsData.VplsState.UPDATING); |
| } |
| |
| /** |
| * Gets the network interface of the host. |
| * |
| * @param host the host |
| * @return the network interface of the host; null if no network |
| * interface found |
| */ |
| private Interface getHostInterface(Host host) { |
| Set<Interface> interfaces = interfaceService.getInterfaces(); |
| return interfaces.stream() |
| .filter(iface -> iface.connectPoint().equals(host.location()) && |
| iface.vlan().equals(host.vlan())) |
| .findFirst() |
| .orElse(null); |
| } |
| } |
| |
| /** |
| * Store delegate for VPLS store. |
| * Handles VPLS store event and generate VPLS operation according to event |
| * type. |
| */ |
| class VplsStoreDelegate implements StoreDelegate<VplsStoreEvent> { |
| |
| @Override |
| public void notify(VplsStoreEvent event) { |
| VplsOperation vplsOperation; |
| VplsOperation.Operation op; |
| VplsData vplsData = event.subject(); |
| switch (event.type()) { |
| case ADD: |
| op = VplsOperation.Operation.ADD; |
| break; |
| case REMOVE: |
| op = VplsOperation.Operation.REMOVE; |
| break; |
| case UPDATE: |
| if (vplsData.state() == VplsData.VplsState.FAILED || |
| vplsData.state() == VplsData.VplsState.ADDED || |
| vplsData.state() == VplsData.VplsState.REMOVED) { |
| // Update the state only. Nothing to do if it is updated |
| // to ADDED, REMOVED or FAILED |
| op = null; |
| } else { |
| op = VplsOperation.Operation.UPDATE; |
| } |
| break; |
| default: |
| log.warn(UNSUPPORTED_STORE_EVENT_TYPE, event.type()); |
| return; |
| } |
| if (op != null) { |
| vplsOperation = VplsOperation.of(vplsData, op); |
| operationService.submit(vplsOperation); |
| } |
| } |
| } |
| } |