diff --git a/apps/evpnopenflow/BUCK b/apps/evpnopenflow/BUCK new file mode 100755 index 0000000000..6554cc7cac --- /dev/null +++ b/apps/evpnopenflow/BUCK @@ -0,0 +1,27 @@ +COMPILE_DEPS = [ + '//lib:CORE_DEPS', + '//lib:org.apache.karaf.shell.console', + '//cli:onos-cli', + '//incubator/api:onos-incubator-api', + '//core/store/serializers:onos-core-serializers', + '//apps/gluon:onos-apps-gluon', + '//apps/vtn/vtnrsc:onos-apps-vtn-vtnrsc', +] + +TEST_DEPS = [ + '//lib:TEST_ADAPTERS', + '//lib:TEST', +] + +osgi_jar_with_tests( + deps = COMPILE_DEPS, + test_deps = TEST_DEPS, +) + +onos_app( + title = 'Evpn-openflow App', + category = 'Traffic Steering', + url = 'http://onosproject.org', + description = 'Ethernet VPN (EVPN) introduces a new model for Ethernet services delivery.' + + 'It enables integrated Layer 2 service over Ethernet with multihoming.', +) diff --git a/apps/evpnopenflow/pom.xml b/apps/evpnopenflow/pom.xml new file mode 100755 index 0000000000..aa4aab7b45 --- /dev/null +++ b/apps/evpnopenflow/pom.xml @@ -0,0 +1,109 @@ + + + + 4.0.0 + + org.onosproject + onos-apps + 1.11.0-SNAPSHOT + + + onos-app-evpnopenflow + bundle + + ONOS EVPN application + + + org.onosproject.evpnopenflow + ONOS EVPN openflow App + Traffic steering + http://onosproject.org + ONOS EVPN openflow application. + + + + + org.onosproject + onlab-osgi + + + org.onosproject + onos-api + + + org.onosproject + onos-cli + ${project.version} + + + org.apache.karaf.shell + org.apache.karaf.shell.console + + + org.onosproject + onos-core-serializers + ${project.version} + + + org.onosproject + onlab-junit + test + + + junit + junit + 4.12 + + + org.onosproject + onlab-osgi + tests + test + + + org.onosproject + onos-api + test + tests + + + org.easymock + easymock + test + + + org.onosproject + onos-incubator-api + ${project.version} + test + tests + + + org.onosproject + onos-app-gluon + ${project.version} + + + org.onosproject + onos-app-vtn-rsc + ${project.version} + + + diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java new file mode 100755 index 0000000000..560b96e971 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java @@ -0,0 +1,76 @@ +/* + * Copyright 2017-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.evpnopenflow.manager; + +import org.onosproject.evpnopenflow.rsc.VpnPort; +import org.onosproject.incubator.net.routing.EvpnRoute; +import org.onosproject.net.Host; + +/** + * Service for interacting with the route and host events. + */ +public interface EvpnService { + /** + * Transfer remote route to private route and set mpls flows out when + * BgpRoute update. + * + * @param route evpn route + */ + void onBgpEvpnRouteUpdate(EvpnRoute route); + + /** + * Transfer remote route to private route and delete mpls flows out when + * BgpRoute delete. + * + * @param route evpn route + */ + void onBgpEvpnRouteDelete(EvpnRoute route); + + /** + * Get VPN info from EVPN app store and create route, set flows when host + * detected. + * + * @param host host information + */ + void onHostDetected(Host host); + + /** + * Get VPN info from EVPN app store and delete route, set flows when + * host + * vanished. + * + * @param host host information + */ + void onHostVanished(Host host); + + /** + * Get VPN info from EVPN app store and create route, set flows when + * host + * detected. + * + * @param vpnPort vpnPort information + */ + void onVpnPortSet(VpnPort vpnPort); + + /** + * Get VPN info from EVPN app store and delete route, set flows when host + * vanished. + * + * @param vpnPort vpnPort information + */ + void onVpnPortDelete(VpnPort vpnPort); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java new file mode 100755 index 0000000000..7f7314b465 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java @@ -0,0 +1,1132 @@ +/* + * Copyright 2017-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.evpnopenflow.manager.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.Sets; +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.onlab.osgi.DefaultServiceDirectory; +import org.onlab.packet.EthType; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MplsLabel; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.evpnopenflow.manager.EvpnService; +import org.onosproject.evpnopenflow.rsc.VpnAfConfig; +import org.onosproject.evpnopenflow.rsc.VpnInstance; +import org.onosproject.evpnopenflow.rsc.VpnInstanceId; +import org.onosproject.evpnopenflow.rsc.VpnPort; +import org.onosproject.evpnopenflow.rsc.VpnPortId; +import org.onosproject.evpnopenflow.rsc.baseport.BasePortService; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigEvent; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigListener; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService; +import org.onosproject.evpnopenflow.rsc.vpninstance.VpnInstanceService; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortEvent; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortListener; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortService; +import org.onosproject.gluon.rsc.GluonConfig; +import org.onosproject.incubator.net.resource.label.LabelResource; +import org.onosproject.incubator.net.resource.label.LabelResourceAdminService; +import org.onosproject.incubator.net.resource.label.LabelResourceId; +import org.onosproject.incubator.net.resource.label.LabelResourceService; +import org.onosproject.incubator.net.routing.EvpnInstanceName; +import org.onosproject.incubator.net.routing.EvpnInstanceNextHop; +import org.onosproject.incubator.net.routing.EvpnInstancePrefix; +import org.onosproject.incubator.net.routing.EvpnInstanceRoute; +import org.onosproject.incubator.net.routing.EvpnNextHop; +import org.onosproject.incubator.net.routing.EvpnRoute; +import org.onosproject.incubator.net.routing.EvpnRoute.Source; +import org.onosproject.incubator.net.routing.EvpnRouteAdminService; +import org.onosproject.incubator.net.routing.EvpnRouteEvent; +import org.onosproject.incubator.net.routing.EvpnRouteListener; +import org.onosproject.incubator.net.routing.EvpnRouteService; +import org.onosproject.incubator.net.routing.EvpnRouteSet; +import org.onosproject.incubator.net.routing.EvpnRouteStore; +import org.onosproject.incubator.net.routing.Label; +import org.onosproject.incubator.net.routing.RouteDistinguisher; +import org.onosproject.incubator.net.routing.VpnRouteTarget; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.ExtensionTreatmentResolver; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigService; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.Objective.Operation; +import org.onosproject.net.host.HostEvent; +import org.onosproject.net.host.HostListener; +import org.onosproject.net.host.HostService; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type.Reference; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ARP_PRIORITY; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ARP_RESPONSE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BASEPORT; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BGP_EVPN_ROUTE_DELETE_START; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BGP_EVPN_ROUTE_UPDATE_START; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BOTH; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANNOT_FIND_TUNNEL_PORT_DEVICE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANT_FIND_CONTROLLER_DEVICE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANT_FIND_VPN_INSTANCE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANT_FIND_VPN_PORT; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_OPENFLOW_START; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_OPENFLOW_STOP; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EXPORT_EXTCOMMUNITY; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.FAILED_TO_SET_TUNNEL_DST; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.GET_PRIVATE_LABEL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.HOST_DETECT; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.HOST_VANISHED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IFACEID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IFACEID_OF_HOST_IS_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IMPORT_EXTCOMMUNITY; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_EVENT_RECEIVED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_ROUTE_TARGET_TYPE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_TARGET_RECEIVED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.MPLS_OUT_FLOWS; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.NETWORK_CONFIG_EVENT_IS_RECEIVED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.NOT_MASTER_FOR_SPECIFIC_DEVICE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RELEASE_LABEL_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_ADD_ARP_RULES; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_REMOVE_ARP_RULES; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SWITCH_CHANNEL_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.TUNNEL_DST; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_TARGET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_TARGET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_BIND; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_TARGET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_UNBIND; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VXLAN; +import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Implementation of the EVPN service. + */ +@Component(immediate = true) +@Service +public class EvpnManager implements EvpnService { + private final Logger log = getLogger(getClass()); + private static final EthType.EtherType ARP_TYPE = EthType.EtherType.ARP; + + protected ApplicationId appId; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EvpnRouteService evpnRouteService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EvpnRouteStore evpnRouteStore; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EvpnRouteAdminService evpnRouteAdminService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipService mastershipService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LabelResourceAdminService labelAdminService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LabelResourceService labelService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected VpnInstanceService vpnInstanceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowObjectiveService flowObjectiveService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected VpnPortService vpnPortService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected VpnAfConfigService vpnAfConfigService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigService configService; + + public Set evpnInstanceRoutes = new HashSet<>(); + private final HostListener hostListener = new InnerHostListener(); + private final VpnPortListener vpnPortListner = new InnerVpnPortListener(); + private final VpnAfConfigListener vpnAfConfigListener = new + InnerVpnAfConfigListener(); + private final InternalRouteEventListener routeListener = new + InternalRouteEventListener(); + + private final NetworkConfigListener configListener = new + InternalNetworkConfigListener(); + + @Activate + public void activate() { + appId = coreService.registerApplication(APP_ID); + hostService.addListener(hostListener); + vpnPortService.addListener(vpnPortListner); + vpnAfConfigService.addListener(vpnAfConfigListener); + configService.addListener(configListener); + evpnRouteService.addListener(routeListener); + + labelAdminService + .createGlobalPool(LabelResourceId.labelResourceId(1), + LabelResourceId.labelResourceId(1000)); + log.info(EVPN_OPENFLOW_START); + } + + @Deactivate + public void deactivate() { + hostService.removeListener(hostListener); + vpnPortService.removeListener(vpnPortListner); + vpnAfConfigService.removeListener(vpnAfConfigListener); + configService.removeListener(configListener); + log.info(EVPN_OPENFLOW_STOP); + } + + @Override + public void onBgpEvpnRouteUpdate(EvpnRoute route) { + if (EvpnRoute.Source.LOCAL.equals(route.source())) { + return; + } + log.info(BGP_EVPN_ROUTE_UPDATE_START, route); + // deal with public route and transfer to private route + if (vpnInstanceService.getInstances().isEmpty()) { + log.info("unable to get instnaces from vpninstance"); + return; + } + + vpnInstanceService.getInstances().forEach(vpnInstance -> { + log.info("got instnaces from vpninstance but not entered here"); + List vpnImportRouteRt = new + LinkedList<>(vpnInstance.getImportRouteTargets()); + List expRt = route.exportRouteTarget(); + List similar = new LinkedList<>(expRt); + similar.retainAll(vpnImportRouteRt); + + if (!similar.isEmpty()) { + EvpnInstancePrefix evpnPrefix = EvpnInstancePrefix + .evpnPrefix(route.prefixMac(), route.prefixIp()); + + EvpnInstanceNextHop evpnNextHop = EvpnInstanceNextHop + .evpnNextHop(route.ipNextHop(), route.label()); + + EvpnInstanceRoute evpnPrivateRoute = new + EvpnInstanceRoute(vpnInstance.vpnInstanceName(), + route.routeDistinguisher(), + vpnImportRouteRt, + route.exportRouteTarget(), + evpnPrefix, + evpnNextHop, + route.prefixIp(), + route.ipNextHop(), + route.label()); + + //update route in route subsystem + //TODO: added by shahid + evpnInstanceRoutes.add(evpnPrivateRoute); + + } + }); + + deviceService.getAvailableDevices(Device.Type.SWITCH) + .forEach(device -> { + log.info("switch device is found"); + Set hosts = getHostsByVpn(device, route); + for (Host h : hosts) { + addArpFlows(device.id(), + route, + Objective.Operation.ADD, + h); + ForwardingObjective.Builder objective = + getMplsOutBuilder(device.id(), + route, + h); + log.info(MPLS_OUT_FLOWS, h); + flowObjectiveService.forward(device.id(), + objective.add()); + } + }); + log.info("no switch device is found"); + } + + @Override + public void onBgpEvpnRouteDelete(EvpnRoute route) { + if (EvpnRoute.Source.LOCAL.equals(route.source())) { + return; + } + log.info(BGP_EVPN_ROUTE_DELETE_START, route); + // deal with public route deleted and transfer to private route + vpnInstanceService.getInstances().forEach(vpnInstance -> { + List vpnRouteRt = new + LinkedList<>(vpnInstance.getImportRouteTargets()); + List localRt = route.exportRouteTarget(); + List similar = new LinkedList<>(localRt); + similar.retainAll(vpnRouteRt); + + if (!similar.isEmpty()) { + EvpnInstancePrefix evpnPrefix = EvpnInstancePrefix + .evpnPrefix(route.prefixMac(), route.prefixIp()); + + EvpnInstanceNextHop evpnNextHop = EvpnInstanceNextHop + .evpnNextHop(route.ipNextHop(), route.label()); + + EvpnInstanceRoute evpnPrivateRoute = new + EvpnInstanceRoute(vpnInstance.vpnInstanceName(), + route.routeDistinguisher(), + vpnRouteRt, + route.exportRouteTarget(), + evpnPrefix, + evpnNextHop, + route.prefixIp(), + route.ipNextHop(), + route.label()); + //TODO: Added by Shahid + //evpnRouteAdminService.withdraw(Sets.newHashSet + // (evpnPrivateRoute)); + + } + }); + deviceService.getAvailableDevices(Device.Type.SWITCH) + .forEach(device -> { + Set hosts = getHostsByVpn(device, route); + for (Host h : hosts) { + addArpFlows(device.id(), + route, + Objective.Operation.REMOVE, + h); + ForwardingObjective.Builder objective + = getMplsOutBuilder(device.id(), + route, + h); + flowObjectiveService.forward(device.id(), + objective.remove()); + } + }); + } + + private void addArpFlows(DeviceId deviceId, + EvpnRoute route, + Operation type, + Host host) { + DriverHandler handler = driverService.createHandler(deviceId); + TrafficSelector selector = DefaultTrafficSelector.builder() + .matchEthType(ARP_TYPE.ethType().toShort()) + .matchArpTpa(route.prefixIp().address().getIp4Address()) + .matchInPort(host.location().port()).build(); + + ExtensionTreatmentResolver resolver = handler + .behaviour(ExtensionTreatmentResolver.class); + ExtensionTreatment ethSrcToDst = resolver + .getExtensionInstruction(ExtensionTreatmentType + .ExtensionTreatmentTypes + .NICIRA_MOV_ETH_SRC_TO_DST + .type()); + ExtensionTreatment arpShaToTha = resolver + .getExtensionInstruction(ExtensionTreatmentType + .ExtensionTreatmentTypes + .NICIRA_MOV_ARP_SHA_TO_THA + .type()); + ExtensionTreatment arpSpaToTpa = resolver + .getExtensionInstruction(ExtensionTreatmentType + .ExtensionTreatmentTypes + .NICIRA_MOV_ARP_SPA_TO_TPA + .type()); + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .extension(ethSrcToDst, deviceId).setEthSrc(route.prefixMac()) + .setArpOp(ARP_RESPONSE).extension(arpShaToTha, deviceId) + .extension(arpSpaToTpa, deviceId).setArpSha(route.prefixMac()) + .setArpSpa(route.prefixIp().address().getIp4Address()) + .setOutput(PortNumber.IN_PORT) + .build(); + + ForwardingObjective.Builder objective = DefaultForwardingObjective + .builder().withTreatment(treatment).withSelector(selector) + .fromApp(appId).withFlag(ForwardingObjective.Flag.SPECIFIC) + .withPriority(ARP_PRIORITY); + if (type.equals(Objective.Operation.ADD)) { + log.info(ROUTE_ADD_ARP_RULES); + flowObjectiveService.forward(deviceId, objective.add()); + } else { + log.info(ROUTE_REMOVE_ARP_RULES); + flowObjectiveService.forward(deviceId, objective.remove()); + } + } + + private Set getHostsByVpn(Device device, EvpnRoute route) { + Set vpnHosts = Sets.newHashSet(); + Set hosts = hostService.getConnectedHosts(device.id()); + for (Host h : hosts) { + String ifaceId = h.annotations().value(IFACEID); + if (!vpnPortService.exists(VpnPortId.vpnPortId(ifaceId))) { + continue; + } + + VpnPort vpnPort = vpnPortService + .getPort(VpnPortId.vpnPortId(ifaceId)); + VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId(); + + VpnInstance vpnInstance = vpnInstanceService + .getInstance(vpnInstanceId); + + List expRt = route.exportRouteTarget(); + List similar = new LinkedList<>(expRt); + similar.retainAll(vpnInstance.getImportRouteTargets()); + //TODO: currently checking for RT comparision. + //TODO: Need to check about RD comparision is really required. + //if (route.routeDistinguisher() + //.equals(vpnInstance.routeDistinguisher())) { + if (!similar.isEmpty()) { + vpnHosts.add(h); + } + } + return vpnHosts; + } + + private ForwardingObjective.Builder getMplsOutBuilder(DeviceId deviceId, + EvpnRoute route, + Host h) { + DriverHandler handler = driverService.createHandler(deviceId); + ExtensionTreatmentResolver resolver = handler + .behaviour(ExtensionTreatmentResolver.class); + ExtensionTreatment treatment = resolver + .getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type()); + try { + treatment.setPropertyValue(TUNNEL_DST, route.ipNextHop()); + } catch (Exception e) { + log.error(FAILED_TO_SET_TUNNEL_DST, deviceId); + } + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); + builder.extension(treatment, deviceId); + TrafficSelector selector = DefaultTrafficSelector.builder() + .matchInPort(h.location().port()).matchEthSrc(h.mac()) + .matchEthDst(route.prefixMac()).build(); + + TrafficTreatment build = builder.pushMpls() + .setMpls(MplsLabel.mplsLabel(route.label().getLabel())) + .setOutput(getTunnlePort(deviceId)).build(); + + return DefaultForwardingObjective + .builder().withTreatment(build).withSelector(selector) + .fromApp(appId).withFlag(ForwardingObjective.Flag.SPECIFIC) + .withPriority(60000); + + } + + private ForwardingObjective.Builder getMplsInBuilder(DeviceId deviceId, + Host host, + Label label) { + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); + TrafficSelector selector = DefaultTrafficSelector.builder() + .matchInPort(getTunnlePort(deviceId)) + .matchEthType(EthType.EtherType.MPLS_UNICAST.ethType() + .toShort()) + .matchMplsBos(true) + .matchMplsLabel(MplsLabel.mplsLabel(label.getLabel())).build(); + TrafficTreatment treatment = builder.popMpls(EthType + .EtherType + .IPV4.ethType()) + .setOutput(host.location().port()).build(); + return DefaultForwardingObjective + .builder().withTreatment(treatment).withSelector(selector) + .fromApp(appId).withFlag(ForwardingObjective.Flag.SPECIFIC) + .withPriority(60000); + } + + /** + * Get local tunnel ports. + * + * @param ports Iterable of Port + * @return Collection of PortNumber + */ + private Collection getLocalTunnelPorts(Iterable + ports) { + Collection localTunnelPorts = new ArrayList<>(); + if (ports != null) { + log.info("port value is not null {}", ports); + Sets.newHashSet(ports).stream() + .filter(p -> !p.number().equals(PortNumber.LOCAL)) + .forEach(p -> { + log.info("number is not matched but no vxlan port"); + if (p.annotations().value(AnnotationKeys.PORT_NAME) + .startsWith(VXLAN)) { + localTunnelPorts.add(p.number()); + } + }); + } + return localTunnelPorts; + } + + private PortNumber getTunnlePort(DeviceId deviceId) { + Iterable ports = deviceService.getPorts(deviceId); + Collection localTunnelPorts = getLocalTunnelPorts(ports); + if (localTunnelPorts.isEmpty()) { + log.error(CANNOT_FIND_TUNNEL_PORT_DEVICE, deviceId); + return null; + } + return localTunnelPorts.iterator().next(); + } + + private void setFlows(DeviceId deviceId, Host host, Label label, + List rtImport, + Operation type) { + log.info("Set the flows to OVS"); + ForwardingObjective.Builder objective = getMplsInBuilder(deviceId, + host, + label); + if (type.equals(Objective.Operation.ADD)) { + flowObjectiveService.forward(deviceId, objective.add()); + } else { + flowObjectiveService.forward(deviceId, objective.remove()); + } + + // download remote flows if and only routes are present. + evpnRouteStore.getRouteTables().forEach(routeTableId -> { + Collection routes + = evpnRouteStore.getRoutes(routeTableId); + if (routes != null) { + routes.forEach(route -> { + Collection evpnRoutes = route.routes(); + for (EvpnRoute evpnRoute : evpnRoutes) { + EvpnRoute evpnRouteTem = evpnRoute; + Set hostByMac = hostService + .getHostsByMac(evpnRouteTem + .prefixMac()); + + if (!hostByMac.isEmpty() + || (!(compareLists(rtImport, evpnRouteTem + .exportRouteTarget())))) { + log.info("Route target import/export is not matched"); + continue; + } + log.info("Set the ARP flows"); + addArpFlows(deviceId, evpnRouteTem, type, host); + ForwardingObjective.Builder build = getMplsOutBuilder(deviceId, + evpnRouteTem, + host); + log.info("Set the MPLS flows"); + if (type.equals(Objective.Operation.ADD)) { + flowObjectiveService.forward(deviceId, build.add()); + } else { + flowObjectiveService.forward(deviceId, build.remove()); + } + } + }); + } + }); + } + + /** + * comparison for tow lists. + * + * @param list1 import list + * @param list2 export list + * @return true or false + */ + public static boolean compareLists(List list1, + List list2) { + if (list1 == null && list2 == null) { + return true; + } + + if (list1 != null && list2 != null) { + if (list1.size() == list2.size()) { + for (VpnRouteTarget li1Long : list1) { + boolean isEqual = false; + for (VpnRouteTarget li2Long : list2) { + if (li1Long.equals(li2Long)) { + isEqual = true; + break; + } + } + if (!isEqual) { + return false; + } + } + } else { + return false; + } + } else { + return false; + } + return true; + } + + @Override + public void onHostDetected(Host host) { + log.info(HOST_DETECT, host); + DeviceId deviceId = host.location().deviceId(); + if (!mastershipService.isLocalMaster(deviceId)) { + log.info(NOT_MASTER_FOR_SPECIFIC_DEVICE); + return; + } + + String ifaceId = host.annotations().value(IFACEID); + if (ifaceId == null) { + log.error(IFACEID_OF_HOST_IS_NULL); + return; + } + VpnPortId vpnPortId = VpnPortId.vpnPortId(ifaceId); + // Get VPN port id from EVPN app store + if (!vpnPortService.exists(vpnPortId)) { + log.info(CANT_FIND_VPN_PORT, ifaceId); + return; + } + + VpnPort vpnPort = vpnPortService.getPort(vpnPortId); + VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId(); + if (!vpnInstanceService.exists(vpnInstanceId)) { + log.info(CANT_FIND_VPN_INSTANCE, vpnInstanceId); + return; + } + + Label privateLabel = applyLabel(); + // create private route and get label + setPrivateRoute(host, vpnInstanceId, privateLabel, + Objective.Operation.ADD); + VpnInstance vpnInstance = vpnInstanceService.getInstance(vpnInstanceId); + + List rtImport + = new LinkedList<>(vpnInstance.getImportRouteTargets()); + List rtExport + = new LinkedList<>(vpnInstance.getExportRouteTargets()); + //download flows + setFlows(deviceId, host, privateLabel, rtImport, + Objective.Operation.ADD); + } + + /** + * update or withdraw evpn route from route admin service. + * + * @param host host + * @param vpnInstanceId vpn instance id + * @param privateLabel private label + * @param type operation type + */ + private void setPrivateRoute(Host host, VpnInstanceId vpnInstanceId, + Label privateLabel, + Operation type) { + DeviceId deviceId = host.location().deviceId(); + Device device = deviceService.getDevice(deviceId); + VpnInstance vpnInstance = vpnInstanceService.getInstance(vpnInstanceId); + RouteDistinguisher rd = vpnInstance.routeDistinguisher(); + Set importRouteTargets + = vpnInstance.getImportRouteTargets(); + Set exportRouteTargets + = vpnInstance.getExportRouteTargets(); + EvpnInstanceName instanceName = vpnInstance.vpnInstanceName(); + String url = device.annotations().value(SWITCH_CHANNEL_ID); + String controllerIp = url.substring(0, url.lastIndexOf(":")); + + if (controllerIp == null) { + log.error(CANT_FIND_CONTROLLER_DEVICE, device.id().toString()); + return; + } + IpAddress ipAddress = IpAddress.valueOf(controllerIp); + // create private route + EvpnInstanceNextHop evpnNextHop = EvpnInstanceNextHop + .evpnNextHop(ipAddress, privateLabel); + EvpnInstancePrefix evpnPrefix = EvpnInstancePrefix + .evpnPrefix(host.mac(), IpPrefix.valueOf(host.ipAddresses() + .iterator() + .next() + .getIp4Address(), 32)); + EvpnInstanceRoute evpnPrivateRoute + = new EvpnInstanceRoute(instanceName, + rd, + new LinkedList<>(importRouteTargets), + new LinkedList<>(exportRouteTargets), + evpnPrefix, + evpnNextHop, + IpPrefix.valueOf(host.ipAddresses() + .iterator() + .next() + .getIp4Address(), 32), + ipAddress, + privateLabel); + + // change to public route + EvpnRoute evpnRoute + = new EvpnRoute(Source.LOCAL, + host.mac(), + IpPrefix.valueOf(host.ipAddresses() + .iterator() + .next() + .getIp4Address(), 32), + ipAddress, + rd, + new LinkedList<>(importRouteTargets), + new LinkedList<>(exportRouteTargets), + privateLabel); + if (type.equals(Objective.Operation.ADD)) { + //evpnRouteAdminService.update(Sets.newHashSet(evpnPrivateRoute)); + evpnInstanceRoutes.add(evpnPrivateRoute); + evpnRouteAdminService.update(Sets.newHashSet(evpnRoute)); + + } else { + //evpnRouteAdminService.withdraw(Sets.newHashSet(evpnPrivateRoute)); + evpnInstanceRoutes.remove(evpnPrivateRoute); + evpnRouteAdminService.withdraw(Sets.newHashSet(evpnRoute)); + } + } + + /** + * Generate the label for evpn route from global pool. + */ + private Label applyLabel() { + Collection privateLabels = labelService + .applyFromGlobalPool(1); + Label privateLabel = Label.label(0); + if (!privateLabels.isEmpty()) { + privateLabel = Label.label(Integer.parseInt( + privateLabels.iterator().next() + .labelResourceId().toString())); + } + log.info(GET_PRIVATE_LABEL, privateLabel); + return privateLabel; + } + + @Override + public void onHostVanished(Host host) { + log.info(HOST_VANISHED, host); + DeviceId deviceId = host.location().deviceId(); + if (!mastershipService.isLocalMaster(deviceId)) { + return; + } + String ifaceId = host.annotations().value(IFACEID); + if (ifaceId == null) { + log.error(IFACEID_OF_HOST_IS_NULL); + return; + } + // Get info from Gluon Shim + VpnPort vpnPort = vpnPortService.getPort(VpnPortId.vpnPortId(ifaceId)); + VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId(); + if (!vpnInstanceService.exists(vpnInstanceId)) { + log.info(CANT_FIND_VPN_INSTANCE, vpnInstanceId); + return; + } + VpnInstance vpnInstance = vpnInstanceService.getInstance(vpnInstanceId); + + Label label = releaseLabel(vpnInstance, host); + // create private route and get label + setPrivateRoute(host, vpnInstanceId, label, Objective.Operation.REMOVE); + // download flows + List rtImport + = new LinkedList<>(vpnInstance.getImportRouteTargets()); + List rtExport + = new LinkedList<>(vpnInstance.getExportRouteTargets()); + setFlows(deviceId, host, label, rtImport, + Objective.Operation.REMOVE); + } + + /** + * Release the label from the evpn route. + * + * @param vpnInstance vpn instance + * @param host host + */ + private Label releaseLabel(VpnInstance vpnInstance, Host host) { + EvpnInstanceName instanceName = vpnInstance.vpnInstanceName(); + + //Get all vpn-instance routes and check for label. + Label label = null; + for (EvpnInstanceRoute evpnInstanceRoute : evpnInstanceRoutes) { + if (evpnInstanceRoute.evpnInstanceName().equals(instanceName)) { + label = evpnInstanceRoute.getLabel(); + // delete private route and get label ,change to public route + boolean isRelease + = labelService + .releaseToGlobalPool( + Sets.newHashSet( + LabelResourceId + .labelResourceId(label.getLabel()))); + if (!isRelease) { + log.error(RELEASE_LABEL_FAILED, label.getLabel()); + } + break; + } + } + return label; + } + + private class InternalRouteEventListener implements EvpnRouteListener { + + @Override + public void event(EvpnRouteEvent event) { + if (!(event.subject() instanceof EvpnRoute)) { + return; + } + EvpnRoute route = (EvpnRoute) event.subject(); + if (EvpnRouteEvent.Type.ROUTE_ADDED == event.type()) { + onBgpEvpnRouteUpdate(route); + } else if (EvpnRouteEvent.Type.ROUTE_REMOVED == event.type()) { + onBgpEvpnRouteDelete(route); + } + } + } + + private class InnerHostListener implements HostListener { + + @Override + public void event(HostEvent event) { + Host host = event.subject(); + if (HostEvent.Type.HOST_ADDED == event.type()) { + onHostDetected(host); + } else if (HostEvent.Type.HOST_REMOVED == event.type()) { + onHostVanished(host); + } + } + + } + + private class InnerVpnPortListener implements VpnPortListener { + + @Override + public void event(VpnPortEvent event) { + VpnPort vpnPort = event.subject(); + if (VpnPortEvent.Type.VPN_PORT_DELETE == event.type()) { + onVpnPortDelete(vpnPort); + } else if (VpnPortEvent.Type.VPN_PORT_SET == event.type()) { + onVpnPortSet(vpnPort); + } + } + } + + @Override + public void onVpnPortDelete(VpnPort vpnPort) { + // delete the flows of this vpn + hostService.getHosts().forEach(host -> { + VpnPortId vpnPortId = vpnPort.id(); + VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId(); + if (!vpnInstanceService.exists(vpnInstanceId)) { + log.error(CANT_FIND_VPN_INSTANCE, vpnInstanceId); + return; + } + VpnInstance vpnInstance = vpnInstanceService + .getInstance(vpnInstanceId); + List rtImport + = new LinkedList<>(vpnInstance.getImportRouteTargets()); + List rtExport + = new LinkedList<>(vpnInstance.getExportRouteTargets()); + + if (vpnPortId.vpnPortId() + .equals(host.annotations().value(IFACEID))) { + log.info(VPN_PORT_UNBIND); + Label label = releaseLabel(vpnInstance, host); + // create private route and get label + DeviceId deviceId = host.location().deviceId(); + setPrivateRoute(host, vpnInstanceId, label, + Objective.Operation.REMOVE); + // download flows + setFlows(deviceId, host, label, rtImport, + Objective.Operation.REMOVE); + } + }); + } + + @Override + public void onVpnPortSet(VpnPort vpnPort) { + // delete the flows of this vpn + hostService.getHosts().forEach(host -> { + VpnPortId vpnPortId = vpnPort.id(); + VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId(); + VpnInstance vpnInstance = vpnInstanceService + .getInstance(vpnInstanceId); + if (vpnInstance == null) { + log.info("why vpn instance is null"); + return; + } + List rtImport + = new LinkedList<>(vpnInstance.getImportRouteTargets()); +/* List rtExport + = new LinkedList<>(vpnInstance.getExportRouteTargets());*/ + + if (!vpnInstanceService.exists(vpnInstanceId)) { + log.error(CANT_FIND_VPN_INSTANCE, vpnInstanceId); + return; + } + + if (vpnPortId.vpnPortId() + .equals(host.annotations().value(IFACEID))) { + log.info(VPN_PORT_BIND); + Label label = applyLabel(); + // create private route and get label + DeviceId deviceId = host.location().deviceId(); + setPrivateRoute(host, vpnInstanceId, label, + Objective.Operation.ADD); + // download flows + setFlows(deviceId, host, label, rtImport, + Objective.Operation.ADD); + } + }); + } + + /** + * process the gluon configuration and will update the configuration into + * vpn port service. + * + * @param action action + * @param key key + * @param value json node + */ + private void processEtcdResponse(String action, String key, JsonNode + value) { + String[] list = key.split(SLASH); + String target = list[list.length - 2]; + switch (target) { + case VPN_INSTANCE_TARGET: + VpnInstanceService vpnInstanceService + = DefaultServiceDirectory + .getService(VpnInstanceService.class); + vpnInstanceService.processGluonConfig(action, key, value); + break; + case VPN_PORT_TARGET: + VpnPortService vpnPortService = DefaultServiceDirectory + .getService(VpnPortService.class); + vpnPortService.processGluonConfig(action, key, value); + break; + case VPN_AF_TARGET: + VpnAfConfigService vpnAfConfigService = + DefaultServiceDirectory.getService(VpnAfConfigService + .class); + vpnAfConfigService.processGluonConfig(action, key, value); + break; + case BASEPORT: + BasePortService basePortService = + DefaultServiceDirectory.getService(BasePortService + .class); + basePortService.processGluonConfig(action, key, value); + break; + default: + log.info("why target type is invalid {}", target); + log.info(INVALID_TARGET_RECEIVED); + break; + } + } + + /** + * parse the gluon configuration received from network config system. + * + * @param jsonNode json node + * @param key key + * @param action action + */ + private void parseEtcdResponse(JsonNode jsonNode, + String key, + String action) { + JsonNode modifyValue = null; + if (action.equals(SET)) { + modifyValue = jsonNode.get(key); + } + processEtcdResponse(action, key, modifyValue); + } + + /** + * Listener for network config events. + */ + private class InternalNetworkConfigListener implements + NetworkConfigListener { + + @Override + public void event(NetworkConfigEvent event) { + String subject; + log.info(NETWORK_CONFIG_EVENT_IS_RECEIVED, event.type()); + if (!event.configClass().equals(GluonConfig.class)) { + return; + } + log.info("Event is received from network configuration {}", event + .type()); + switch (event.type()) { + case CONFIG_UPDATED: + subject = (String) event.subject(); + GluonConfig gluonConfig = configService + .getConfig(subject, GluonConfig.class); + JsonNode jsonNode = gluonConfig.node(); + parseEtcdResponse(jsonNode, subject, SET); + break; + case CONFIG_REMOVED: + subject = (String) event.subject(); + parseEtcdResponse(null, subject, DELETE); + break; + default: + log.info(INVALID_EVENT_RECEIVED); + break; + } + } + } + + /** + * update import and export route target information in route admin service. + * + * @param evpnInstanceName evpn instance name + * @param exportRouteTargets export route targets + * @param importRouteTargets import route targets + * @param action action holds update or delete + */ + private void updateImpExpRtInRoute(EvpnInstanceName evpnInstanceName, + Set exportRouteTargets, + Set importRouteTargets, + String action) { + + for (EvpnInstanceRoute evpnInstanceRoute : evpnInstanceRoutes) { + if (evpnInstanceRoute.evpnInstanceName().equals(evpnInstanceName)) { + evpnInstanceRoute + .setExportRtList(new LinkedList<>(exportRouteTargets)); + evpnInstanceRoute + .setImportRtList(new LinkedList<>(importRouteTargets)); + if (action.equals(UPDATE)) { + evpnInstanceRoutes.add(evpnInstanceRoute); + } else if (action.equals(DELETE)) { + evpnInstanceRoutes.remove(evpnInstanceRoute); + } + //Get the public route and update route targets. + EvpnNextHop evpnNextHop = EvpnNextHop + .evpnNextHop(evpnInstanceRoute.getNextHopl(), + evpnInstanceRoute.importRouteTarget(), + evpnInstanceRoute.exportRouteTarget(), + evpnInstanceRoute.getLabel()); + Collection evpnPublicRoutes + = evpnRouteStore.getRoutesForNextHop(evpnNextHop.nextHop()); + for (EvpnRoute pubRoute : evpnPublicRoutes) { + EvpnRoute evpnPubRoute = pubRoute; + if (evpnPubRoute.label().equals(evpnInstanceRoute + .getLabel())) { + evpnPubRoute + .setExportRtList(new LinkedList<>(exportRouteTargets)); + evpnPubRoute + .setImportRtList(new LinkedList<>(importRouteTargets)); + if (action.equals(UPDATE)) { + evpnRouteAdminService.update(Sets.newHashSet(evpnPubRoute)); + } else if (action.equals(DELETE)) { + evpnRouteAdminService + .withdraw(Sets.newHashSet(evpnPubRoute)); + } + } + } + } + } + } + + /** + * update or withdraw evpn route based on vpn af configuration. + * + * @param vpnAfConfig vpn af configuration + * @param action action holds update or delete + */ + + private void processEvpnRouteUpdate(VpnAfConfig vpnAfConfig, + String action) { + Collection instances + = vpnInstanceService.getInstances(); + for (VpnInstance vpnInstance : instances) { + Set configRouteTargets + = vpnInstance.getConfigRouteTargets(); + for (VpnRouteTarget vpnRouteTarget : configRouteTargets) { + if (vpnRouteTarget.equals(vpnAfConfig.routeTarget())) { + Set exportRouteTargets + = vpnInstance.getExportRouteTargets(); + Set importRouteTargets + = vpnInstance.getImportRouteTargets(); + String routeTargetType = vpnAfConfig.routeTargetType(); + if (action.equals(UPDATE)) { + vpnInstanceService + .updateImpExpRouteTargets(routeTargetType, + exportRouteTargets, + importRouteTargets, + vpnRouteTarget); + } else if (action.equals(DELETE)) { + switch (routeTargetType) { + case EXPORT_EXTCOMMUNITY: + exportRouteTargets.remove(vpnRouteTarget); + break; + case IMPORT_EXTCOMMUNITY: + importRouteTargets.remove(vpnRouteTarget); + break; + case BOTH: + exportRouteTargets.remove(vpnRouteTarget); + importRouteTargets.remove(vpnRouteTarget); + break; + default: + log.info(INVALID_ROUTE_TARGET_TYPE); + break; + } + } + updateImpExpRtInRoute(vpnInstance.vpnInstanceName(), + exportRouteTargets, + importRouteTargets, + action); + } + } + } + } + + private class InnerVpnAfConfigListener implements VpnAfConfigListener { + + @Override + public void event(VpnAfConfigEvent event) { + VpnAfConfig vpnAfConfig = event.subject(); + if (VpnAfConfigEvent.Type.VPN_AF_CONFIG_DELETE == event.type()) { + processEvpnRouteUpdate(vpnAfConfig, DELETE); + } else if (VpnAfConfigEvent.Type.VPN_AF_CONFIG_SET + == event.type() || VpnAfConfigEvent.Type + .VPN_AF_CONFIG_UPDATE == event.type()) { + processEvpnRouteUpdate(vpnAfConfig, UPDATE); + } + } + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/package-info.java new file mode 100755 index 0000000000..8f831614ae --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2017-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. + */ + +/** + * EVPN application that process configuration and host, vpn-port, route + * events. + */ +package org.onosproject.evpnopenflow.manager.impl; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/package-info.java new file mode 100755 index 0000000000..d93de24c8f --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2017-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. + */ + +/** + * EVPN application that process configuration and host, vpn-port, route + * events. + */ +package org.onosproject.evpnopenflow.manager; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/BasePort.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/BasePort.java new file mode 100755 index 0000000000..1b2455a44c --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/BasePort.java @@ -0,0 +1,163 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onlab.packet.MacAddress; +import org.onosproject.net.DeviceId; +import org.onosproject.vtnrsc.AllowedAddressPair; +import org.onosproject.vtnrsc.BindingHostId; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.SecurityGroup; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetworkId; + +import java.util.Collection; +import java.util.Set; + +/** + * Representation of a Base port. + */ +public interface BasePort { + /** + * Coarse classification of the type of the virtual port. + */ + enum State { + /** + * Signifies that a basePort is currently active,This state mean that + * this basePort is available. + */ + ACTIVE, + /** + * Signifies that a basePort is currently unavailable. + */ + DOWN; + } + + /** + * Returns the basePort identifier. + * + * @return basePort identifier + */ + BasePortId portId(); + + /** + * Returns the network identifier. + * + * @return tenantNetwork identifier + */ + TenantNetworkId networkId(); + + /** + * Returns the symbolic name for the basePort. + * + * @return basePort name + */ + String name(); + + /** + * Returns the administrative status of the port,which is up(true) or + * down(false). + * + * @return true if the administrative status of the port is up + */ + boolean adminStateUp(); + + /** + * Returns the state. + * + * @return state + */ + String state(); + + /** + * Returns the MAC address. + * + * @return MAC Address + */ + MacAddress macAddress(); + + /** + * Returns the port tenantId. + * + * @return port tenantId + */ + TenantId tenantId(); + + /** + * Returns the device identifier. + * + * @return deviceId + */ + DeviceId deviceId(); + + /** + * Returns the identifier of the entity that uses this port. + * + * @return deviceOwner + */ + String deviceOwner(); + + /** + * Returns the basePort allowedAddressPairs. + * + * @return basePort allowedAddressPairs + */ + Collection allowedAddressPairs(); + + /** + * Returns set of IP addresses for the port, include the IP addresses and subnet + * identity. + * + * @return FixedIps Set of fixedIp + */ + Set fixedIps(); + + /** + * Returns the basePort bindinghostId. + * + * @return basePort bindinghostId + */ + BindingHostId bindingHostId(); + + /** + * Returns the basePort bindingVnicType. + * + * @return basePort bindingVnicType + */ + String bindingVnicType(); + + /** + * Returns the basePort bindingVifType. + * + * @return basePort bindingVifType + */ + String bindingVifType(); + + /** + * Returns the basePort bindingvifDetail. + * + * @return basePort bindingvifDetail + */ + String bindingVifDetails(); + + /** + * Returns the security groups. + * + * @return port security groups + */ + Iterable securityGroups(); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/BasePortId.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/BasePortId.java new file mode 100755 index 0000000000..4eb120a2cc --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/BasePortId.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onlab.util.Identifier; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Immutable representation of a base port identifier. + */ +public final class BasePortId extends Identifier { + // Public construction is prohibited + private BasePortId(String basePortId) { + super(checkNotNull(basePortId, "BasePortId cannot be null")); + } + + public String portId() { + return identifier; + } + + /** + * Creates a virtualPort id using the supplied portId. + * + * @param portId baseport identifier + * @return BasePortId + */ + public static BasePortId portId(String portId) { + return new BasePortId(portId); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultBasePort.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultBasePort.java new file mode 100755 index 0000000000..ec9e59ec5f --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultBasePort.java @@ -0,0 +1,236 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onlab.packet.MacAddress; +import org.onosproject.net.DeviceId; +import org.onosproject.vtnrsc.AllowedAddressPair; +import org.onosproject.vtnrsc.BindingHostId; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.SecurityGroup; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetworkId; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of Base port. + */ +public final class DefaultBasePort implements BasePort { + private final BasePortId id; + private final TenantNetworkId networkId; + private final Boolean adminStateUp; + private final String name; + private final String state; + private final MacAddress macAddress; + private final TenantId tenantId; + private final String deviceOwner; + private final DeviceId deviceId; + private final Set fixedIps; + private final BindingHostId bindingHostId; + private final String bindingVnicType; + private final String bindingVifType; + private final String bindingVifDetails; + private final Set allowedAddressPairs; + private final Set securityGroups; + + /** + * Creates a BasePort object. + * + * @param id the base port identifier + * @param networkId the network identifier + * @param adminStateUp adminStateup true or false + * @param strMap the map of properties of base port + * @param state base port state + * @param macAddress the MAC address + * @param tenantId the tenant identifier + * @param deviceId the device identifier + * @param fixedIps set of fixed IP + * @param bindingHostId the binding host identifier + * @param allowedAddressPairs the collection of allowdeAddressPairs + * @param securityGroups the collection of securityGroups + */ + public DefaultBasePort(BasePortId id, + TenantNetworkId networkId, + Boolean adminStateUp, + Map strMap, + String state, + MacAddress macAddress, + TenantId tenantId, + DeviceId deviceId, + Set fixedIps, + BindingHostId bindingHostId, + Set allowedAddressPairs, + Set securityGroups) { + this.id = id; + this.networkId = networkId; + this.adminStateUp = adminStateUp; + this.name = strMap.get("name"); + this.state = state; + this.macAddress = macAddress; + this.tenantId = tenantId; + this.deviceOwner = strMap.get("deviceOwner"); + this.deviceId = deviceId; + this.fixedIps = fixedIps; + this.bindingHostId = bindingHostId; + this.bindingVnicType = strMap.get("bindingVnicType"); + this.bindingVifType = strMap.get("bindingVifType"); + this.bindingVifDetails = strMap.get("bindingVifDetails"); + this.allowedAddressPairs = allowedAddressPairs; + this.securityGroups = securityGroups; + } + + @Override + public BasePortId portId() { + return id; + } + + @Override + public TenantNetworkId networkId() { + return networkId; + } + + @Override + public String name() { + return name; + } + + @Override + public boolean adminStateUp() { + return adminStateUp; + } + + @Override + public String state() { + return state; + } + + @Override + public MacAddress macAddress() { + return macAddress; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public String deviceOwner() { + return deviceOwner; + } + + @Override + public Collection allowedAddressPairs() { + return allowedAddressPairs; + } + + @Override + public Set fixedIps() { + return fixedIps; + } + + @Override + public BindingHostId bindingHostId() { + return bindingHostId; + } + + @Override + public String bindingVnicType() { + return bindingVifType; + } + + @Override + public String bindingVifType() { + return bindingVifType; + } + + @Override + public String bindingVifDetails() { + return bindingVifDetails; + } + + @Override + public Collection securityGroups() { + return securityGroups; + } + + @Override + public int hashCode() { + return Objects.hash(id, networkId, adminStateUp, name, state, + macAddress, tenantId, deviceId, deviceOwner, + allowedAddressPairs, fixedIps, bindingHostId, + bindingVnicType, bindingVifType, bindingVifDetails, + securityGroups); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultBasePort) { + final DefaultBasePort that = (DefaultBasePort) obj; + return Objects.equals(this.id, that.id) + && Objects.equals(this.networkId, that.networkId) + && Objects.equals(this.adminStateUp, that.adminStateUp) + && Objects.equals(this.state, that.state) + && Objects.equals(this.name, that.name) + && Objects.equals(this.tenantId, that.tenantId) + && Objects.equals(this.macAddress, that.macAddress) + && Objects.equals(this.deviceId, that.deviceId) + && Objects.equals(this.deviceOwner, that.deviceOwner) + && Objects.equals(this.allowedAddressPairs, + that.allowedAddressPairs) + && Objects.equals(this.fixedIps, that.fixedIps) + && Objects.equals(this.bindingHostId, that.bindingHostId) + && Objects.equals(this.bindingVifDetails, + that.bindingVifDetails) + && Objects.equals(this.bindingVifType, that.bindingVifType) + && Objects.equals(this.bindingVnicType, + that.bindingVnicType) + && Objects.equals(this.securityGroups, that.securityGroups); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("id", id).add("network_id", networkId) + .add("adminStateUp", adminStateUp).add("state", state) + .add("name", name).add("state", state) + .add("macAddress", macAddress).add("tenantId", tenantId) + .add("deviced", deviceId).add("deviceOwner", deviceOwner) + .add("allowedAddressPairs", allowedAddressPairs) + .add("fixedIp", fixedIps).add("bindingHostId", bindingHostId) + .add("bindingVnicType", bindingVnicType) + .add("bindingVifDetails", bindingVifDetails) + .add("bindingVifType", bindingVifType) + .add("securityGroups", securityGroups).toString(); + } + +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java new file mode 100755 index 0000000000..2481830d14 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java @@ -0,0 +1,87 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onosproject.incubator.net.routing.VpnRouteTarget; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RT_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RT_TYPE_CANNOT_BE_NULL; + +/** + * Default implementation of VPN AF configuration. + */ +public class DefaultVpnAfConfig implements VpnAfConfig { + + private final String exportRoutePolicy; + private final String importRoutePolicy; + private final VpnRouteTarget routeTarget; + private final String routeTargetType; + + /** + * creates vpn af configuration object. + * + * @param exportRoutePolicy export route policy + * @param importRoutePolicy import route policy + * @param routeTarget route target value + * @param routeTargetType route target type + */ + public DefaultVpnAfConfig(String exportRoutePolicy, + String importRoutePolicy, + VpnRouteTarget routeTarget, + String routeTargetType) { + this.exportRoutePolicy = checkNotNull(exportRoutePolicy, + ID_CANNOT_BE_NULL); + this.importRoutePolicy = checkNotNull(importRoutePolicy, + ID_CANNOT_BE_NULL); + this.routeTarget = checkNotNull(routeTarget, RT_CANNOT_BE_NULL); + this.routeTargetType = checkNotNull(routeTargetType, + RT_TYPE_CANNOT_BE_NULL); + } + + @Override + public String exportRoutePolicy() { + return exportRoutePolicy; + } + + @Override + public String importRoutePolicy() { + return importRoutePolicy; + } + + @Override + public VpnRouteTarget routeTarget() { + return routeTarget; + } + + @Override + public String routeTargetType() { + return routeTargetType; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("exportRoutePolicy", exportRoutePolicy) + .add("importRoutePolicy", importRoutePolicy) + .add("routeTarget", routeTarget) + .add("routeTargetType", routeTargetType) + .toString(); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java new file mode 100755 index 0000000000..e7f9c5d52b --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java @@ -0,0 +1,153 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onosproject.incubator.net.routing.EvpnInstanceName; +import org.onosproject.incubator.net.routing.RouteDistinguisher; +import org.onosproject.incubator.net.routing.VpnRouteTarget; + +import java.util.Objects; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CONFIG_RT_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DESCRIPTION; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DESCRIPTION_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EXPORT_RT_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IMPORT_RT_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INSTANCE_NAME_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RD_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_DISTINGUISHER; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPNINSTANCE_NAME; + +/** + * Default implementation of VPN instance. + */ +public class DefaultVpnInstance implements VpnInstance { + private final VpnInstanceId id; + private final String description; + private final EvpnInstanceName name; + private final RouteDistinguisher routeDistinguisher; + private final Set exportRtSet; + private final Set importRtSet; + private final Set configRtSet; + + + /** + * creates vpn instance object. + * + * @param id vpn instance identifier + * @param instanceName the name of vpn instance + * @param description the description of vpn instance + * @param routeDistinguisher the routeDistinguisher of vpn instance + * @param exportRtSet the export route target information + * @param importRtSet the import route target information + * @param configRtSet the config route target information + */ + public DefaultVpnInstance(VpnInstanceId id, EvpnInstanceName instanceName, + String description, + RouteDistinguisher routeDistinguisher, + Set exportRtSet, + Set importRtSet, + Set configRtSet) { + this.id = checkNotNull(id, ID_CANNOT_BE_NULL); + this.name = checkNotNull(instanceName, INSTANCE_NAME_CANNOT_BE_NULL); + this.description = checkNotNull(description, + DESCRIPTION_CANNOT_BE_NULL); + this.routeDistinguisher = checkNotNull(routeDistinguisher, + RD_CANNOT_BE_NULL); + this.exportRtSet = checkNotNull(exportRtSet, EXPORT_RT_CANNOT_BE_NULL); + this.importRtSet = checkNotNull(importRtSet, IMPORT_RT_CANNOT_BE_NULL); + this.configRtSet = checkNotNull(configRtSet, CONFIG_RT_CANNOT_BE_NULL); + } + + @Override + public VpnInstanceId id() { + return id; + } + + @Override + public String description() { + return description; + } + + @Override + public RouteDistinguisher routeDistinguisher() { + return routeDistinguisher; + } + + @Override + public EvpnInstanceName vpnInstanceName() { + return name; + } + + @Override + public Set getExportRouteTargets() { + return exportRtSet; + } + + @Override + public Set getImportRouteTargets() { + return importRtSet; + } + + @Override + public Set getConfigRouteTargets() { + return configRtSet; + } + + @Override + public int hashCode() { + return Objects.hash(id, name, description, routeDistinguisher, + exportRtSet, importRtSet, configRtSet); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultVpnInstance) { + final DefaultVpnInstance that = (DefaultVpnInstance) obj; + return Objects.equals(this.id, that.id) + && Objects.equals(this.name, that.name) + && Objects.equals(this.description, that.description) + && Objects.equals(this.routeDistinguisher, + that.routeDistinguisher) + && Objects.equals(this.exportRtSet, that.exportRtSet) + && Objects.equals(this.importRtSet, that.importRtSet) + && Objects.equals(this.configRtSet, that.configRtSet); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add(ID, id) + .add(DESCRIPTION, description) + .add(VPNINSTANCE_NAME, name) + .add(ROUTE_DISTINGUISHER, routeDistinguisher) + .add("exportRtSet", exportRtSet) + .add("importRtSet", importRtSet) + .add("configRtSet", configRtSet) + .toString(); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnPort.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnPort.java new file mode 100755 index 0000000000..c036a5f36b --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnPort.java @@ -0,0 +1,81 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID_CANNOT_BE_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_ID_CANNOT_BE_NULL; + +/** + * Default implementation of VPN port. + */ +public class DefaultVpnPort implements VpnPort { + + private final VpnPortId id; + private final VpnInstanceId vpnInstanceId; + + /** + * creates vpn port object. + * + * @param id vpn port id + * @param vpnInstanceId vpn instance id + */ + public DefaultVpnPort(VpnPortId id, VpnInstanceId vpnInstanceId) { + this.id = checkNotNull(id, ID_CANNOT_BE_NULL); + this.vpnInstanceId = checkNotNull(vpnInstanceId, + VPN_INSTANCE_ID_CANNOT_BE_NULL); + } + + @Override + public VpnPortId id() { + return id; + } + + @Override + public VpnInstanceId vpnInstanceId() { + return vpnInstanceId; + } + + @Override + public int hashCode() { + return Objects.hash(id, vpnInstanceId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultVpnPort) { + final DefaultVpnPort that = (DefaultVpnPort) obj; + return Objects.equals(this.id, that.id) + && Objects.equals(this.vpnInstanceId, that.vpnInstanceId); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add(ID, id) + .add(VPN_INSTANCE_ID, vpnInstanceId).toString(); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/EvpnConstants.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/EvpnConstants.java new file mode 100755 index 0000000000..3bb692ca50 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/EvpnConstants.java @@ -0,0 +1,186 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +/** + * Provides constants used in EVPN openflow application. + */ +public final class EvpnConstants { + private EvpnConstants() { + } + + public static final String APP_ID = "org.onosproject.evpnopenflow"; + public static final String EVPN_OPENFLOW_START = "evpn-openflow app is " + + "started"; + public static final String EVPN_OPENFLOW_STOP = "evpn-openflow app is " + + "stopped"; + public static final String EVPN_VPN_PORT_START = "EVPN port started"; + public static final String EVPN_VPN_PORT_STOP = "EVPN port stopped"; + public static final String EVPN_VPN_INSTANCE_START = "EVPN instance " + + "started"; + public static final String EVPN_VPN_INSTANCE_STOP = "EVPN instance " + + "stopped"; + public static final String HOST_DETECT = "Host detected {}"; + public static final String HOST_VANISHED = "Host vanished {}"; + public static final String IFACEID = "ifaceid"; + public static final String IFACEID_OF_HOST_IS_NULL = + "The ifaceId of host is null"; + public static final String CANT_FIND_VPN_PORT = "Can't find vpnport {}"; + public static final String CANT_FIND_VPN_INSTANCE = "EVPN instance {} is " + + "not exist"; + public static final String CANT_FIND_CONTROLLER_DEVICE = "Can't find " + + "controller of device: {}"; + public static final String GET_PRIVATE_LABEL = "Get private label {}"; + public static final String RELEASE_LABEL_FAILED = "Release resoure label " + + "{} failed"; + public static final String VPN_PORT_UNBIND = "On EVPN port unbind"; + public static final String VPN_PORT_BIND = "On EVPN port bind"; + public static final String SLASH = "/"; + public static final String COMMA = ","; + public static final String VPN_INSTANCE_TARGET = "VpnService"; + public static final String VPN_PORT_TARGET = "VpnBinding"; + public static final String BASEPORT = "Port"; + public static final String VPN_AF_TARGET = "VpnAfConfig"; + public static final String BGP_PEERING = "BGPPeering"; + public static final String DATA_PLANE_TUNNEL = "DataplaneTunnel"; + public static final String VPN_PORT_STORE = "evpn-port-store"; + public static final String BASE_PORT_STORE = "evpn-baseport-store"; + public static final String VPN_INSTANCE_STORE = + "evpn-instance-store"; + public static final String VPN_PORT_ID_NOT_NULL = "EVPN port ID cannot be" + + " null"; + public static final String VPN_PORT_NOT_NULL = "EVPN port cannot be null"; + public static final String RESPONSE_NOT_NULL = "JsonNode can not be null"; + public static final String LISTENER_NOT_NULL = "Listener cannot be null"; + public static final String EVENT_NOT_NULL = "Event cannot be null"; + public static final String DELETE = "delete"; + public static final String SET = "set"; + public static final String UPDATE = "update"; + public static final String VPN_PORT_ID = "EVPN port ID is {} "; + public static final String VPN_PORT_CREATION_FAILED = "The EVPN port " + + "creation is failed whose identifier is {} "; + public static final String VPN_PORT_IS_NOT_EXIST = "The EVPN port is not " + + "exist whose identifier is {}"; + public static final String VPN_PORT_UPDATE_FAILED = "The EVPN port update" + + " is failed whose identifier is {}"; + public static final String VPN_PORT_DELETE_FAILED = + "The EVPN port delete is failed whose identifier is {}"; + public static final String INTERFACE_ID = "interface_id"; + public static final String ID = "id"; + public static final String VPN_INSTANCE = "service_id"; + public static final String VPN_INSTANCE_ID_NOT_NULL = "EVPN instance ID " + + "cannot be null"; + public static final String VPN_INSTANCE_NOT_NULL = "EVPN instance cannot " + + "be null"; + public static final String JSON_NOT_NULL = "JsonNode can not be null"; + public static final String INSTANCE_ID = "EVPN instance ID is {} "; + public static final String VPN_INSTANCE_CREATION_FAILED = "The " + + "EVPN instance creation is failed whose identifier is {} "; + public static final String VPN_INSTANCE_IS_NOT_EXIST = "The EVPN instance" + + " is not exist whose identifier is {}"; + public static final String VPN_INSTANCE_UPDATE_FAILED = "The EVPN " + + "instance update is failed whose identifier is {}"; + public static final String VPN_INSTANCE_DELETE_FAILED = "The EVPN " + + "instance delete is failed whose identifier is {}"; + public static final String VPN_INSTANCE_NAME = "name"; + public static final String DESCRIPTION = "description"; + public static final String ROUTE_DISTINGUISHERS = "route_distinguishers"; + public static final String IPV4_FAMILY = "ipv4_family"; + static final String ID_CANNOT_BE_NULL = "ID cannot be null"; + static final String INSTANCE_NAME_CANNOT_BE_NULL = "Instance name cannot " + + "be null"; + static final String DESCRIPTION_CANNOT_BE_NULL = "Description cannot be " + + "null"; + static final String RD_CANNOT_BE_NULL = "RouteDistinguisher cannot be null"; + static final String RT_CANNOT_BE_NULL = "RouteTarget cannot be null"; + static final String VPNINSTANCE_NAME = "vpnInstanceName"; + static final String ROUTE_DISTINGUISHER = "routeDistinguisher"; + static final String VPN_INSTANCE_ID_CANNOT_BE_NULL = "EVPN instance ID " + + "cannot be null"; + static final String VPN_INSTANCE_ID = "vpnInstanceId"; + public static final String FORMAT_VPN_INSTANCE = "Id=%s, description=%s," + + " name=%s, routeDistinguisher=%s, routeTarget=%s"; + public static final String FORMAT_VPN_PORT = " EVPN port id=%-32s, " + + "EVPN instance id=%-18s"; + public static final String FORMAT_PRIVATE_ROUTE = " %-18s %-15s %-10s"; + public static final String FORMAT_PUBLIC_ROUTE = " %-18s %-18s %-10s"; + public static final String SWITCH_CHANNEL_ID = "channelId"; + public static final String NOT_MASTER_FOR_SPECIFIC_DEVICE = "The local " + + "controller is not master for the specified deviceId"; + public static final String VPN_AF_CONFIG_STORE = + "evpn-vpn-af-config-store"; + public static final String EVPN_VPN_AF_CONFIG_START = "EVPN af config" + + " started"; + public static final String EVPN_VPN_AF_CONFIG_STOP = "EVPN af config" + + " stopped"; + static final String RT_TYPE_CANNOT_BE_NULL = "Route target type " + + "cannot be null"; + public static final String VPN_AF_CONFIG_NOT_NULL = "EVPN af config be " + + "null"; + public static final String ROUTE_TARGET_VALUE = "Route target value is {} "; + public static final String VPN_AF_CONFIG_CREATION_FAILED = "The " + + "EVPN af config creation is failed whose route target is {} "; + public static final String VPN_AF_CONFIG_UPDATE_FAILED = "The EVPN af " + + "config update is failed whose identifier is {}"; + public static final String VPN_AF_CONFIG_IS_NOT_EXIST = "The EVPN AF " + + "config is not exist whose identifier is {}"; + public static final String ROUTE_TARGET_CANNOT_NOT_NULL = "Route target " + + "value cannot be null"; + public static final String ROUTE_TARGET_DELETE_FAILED = "The route target" + + " delete is failed whose route target value is {}"; + static final String EXPORT_RT_CANNOT_BE_NULL = "export route " + + "target set cannot be null"; + static final String IMPORT_RT_CANNOT_BE_NULL = "import route " + + "target set cannot be null"; + static final String CONFIG_RT_CANNOT_BE_NULL = "import route " + + "target set cannot be null"; + public static final String EXPORT_EXTCOMMUNITY = "export_extcommunity"; + public static final String IMPORT_EXTCOMMUNITY = "import_extcommunity"; + public static final String BOTH = "both"; + public static final String INVALID_ROUTE_TARGET_TYPE + = "Invalid route target type has received"; + public static final String INVALID_EVENT_RECEIVED + = "Invalid event is received while processing network " + + "configuration event"; + public static final String NETWORK_CONFIG_EVENT_IS_RECEIVED + = "Event is received from network configuration {}"; + public static final int ARP_PRIORITY = 0xffff; + public static final short ARP_RESPONSE = 0x2; + public static final String INVALID_TARGET_RECEIVED + = "Invalid target type has received"; + public static final String INVALID_ACTION_VPN_AF_CONFIG + = "Invalid action is received while processing VPN af" + + " configuration"; + public static final String EXPORT_ROUTE_POLICY = "export_route_policy"; + public static final String IMPORT_ROUTE_POLICY = "import_route_policy"; + public static final String VRF_RT_TYPE = "vrf_rt_type"; + public static final String VRF_RT_VALUE = "vrf_rt_value"; + public static final String BGP_EVPN_ROUTE_UPDATE_START + = "bgp evpn route update start {}"; + public static final String MPLS_OUT_FLOWS = "mpls out flows --> {}"; + public static final String BGP_EVPN_ROUTE_DELETE_START + = "bgp route delete start {}"; + public static final String ROUTE_ADD_ARP_RULES = "Route ARP Rules-->ADD"; + public static final String ROUTE_REMOVE_ARP_RULES + = "Route ARP Rules-->REMOVE"; + public static final String TUNNEL_DST = "tunnelDst"; + public static final String FAILED_TO_SET_TUNNEL_DST + = "Failed to get extension instruction to set tunnel dst {}"; + public static final String VXLAN = "vxlan"; + public static final String CANNOT_FIND_TUNNEL_PORT_DEVICE = + "Can't find tunnel port in device {}"; +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java new file mode 100755 index 0000000000..e9bd0681c3 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java @@ -0,0 +1,53 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onosproject.incubator.net.routing.VpnRouteTarget; + +/** + * Representation of a VPN af configuration. + */ +public interface VpnAfConfig { + + /** + * Returns the export route policy information. + * + * @return export route policy + */ + String exportRoutePolicy(); + + /** + * Returns the import route policy information. + * + * @return export route policy + */ + String importRoutePolicy(); + + /** + * Returns the route target value. + * + * @return route target value + */ + VpnRouteTarget routeTarget(); + + /** + * Returns the route target type. + * + * @return route target type + */ + String routeTargetType(); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java new file mode 100755 index 0000000000..d49027b2bc --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java @@ -0,0 +1,78 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onosproject.incubator.net.routing.EvpnInstanceName; +import org.onosproject.incubator.net.routing.RouteDistinguisher; +import org.onosproject.incubator.net.routing.VpnRouteTarget; + +import java.util.Set; + +/** + * Representation of a VPN instance. + */ +public interface VpnInstance { + + /** + * Returns the VPN instance identifier. + * + * @return VPN instance identifier + */ + VpnInstanceId id(); + + /** + * Returns the VPN instance description. + * + * @return VPN instance description + */ + String description(); + + /** + * Returns the VPN instance route distinguishes. + * + * @return VPN instance route distinguishes + */ + RouteDistinguisher routeDistinguisher(); + + /** + * Returns the VPN instance name. + * + * @return VPN instance name + */ + EvpnInstanceName vpnInstanceName(); + + /** + * Returns the export route target information. + * + * @return export route target information + */ + Set getExportRouteTargets(); + + /** + * Returns the import route target information. + * + * @return VPN instance ipv4 family + */ + Set getImportRouteTargets(); + + /** + * Returns the config route target information. + * + * @return config route target information. + */ + Set getConfigRouteTargets(); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstanceId.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstanceId.java new file mode 100755 index 0000000000..03399ed7bf --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstanceId.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onlab.util.Identifier; + +/** + * Immutable representation of a VPN instance identity. + */ +public final class VpnInstanceId extends Identifier { + // Public construction is prohibited + private VpnInstanceId(String vpnInstanceId) { + super(vpnInstanceId); + } + + /** + * Creates a VPN instance identifier. + * + * @param vpnInstanceId VPN instance identify string + * @return VPN instance identifier + */ + public static VpnInstanceId vpnInstanceId(String vpnInstanceId) { + return new VpnInstanceId(vpnInstanceId); + } + + /** + * Returns VPN instance identifier. + * + * @return the VPN instance identifier + */ + public String vpnInstanceId() { + return identifier; + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnPort.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnPort.java new file mode 100755 index 0000000000..82f5336fe5 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnPort.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +/** + * Representation of a VPN port. + */ +public interface VpnPort { + + /** + * Returns the VPN port identifier. + * + * @return VPN port identifier + */ + VpnPortId id(); + + /** + * Returns the VPN instance identifier. + * + * @return VPN instance identifier + */ + VpnInstanceId vpnInstanceId(); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnPortId.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnPortId.java new file mode 100755 index 0000000000..f900830643 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnPortId.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc; + +import org.onlab.util.Identifier; + +/** + * Immutable representation of a VPN port identity. + */ +public final class VpnPortId extends Identifier { + // Public construction is prohibited + private VpnPortId(String vpnPortId) { + super(vpnPortId); + } + + /** + * Creates a VPN port identifier. + * + * @param vpnPortId VPN port identifier + * @return VPN port identifier + */ + public static VpnPortId vpnPortId(String vpnPortId) { + return new VpnPortId(vpnPortId); + } + + /** + * Returns VPN port identifier. + * + * @return the VPN port identifier + */ + public String vpnPortId() { + return identifier; + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortEvent.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortEvent.java new file mode 100755 index 0000000000..acb762aa25 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortEvent.java @@ -0,0 +1,65 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.baseport; + +import org.onosproject.event.AbstractEvent; +import org.onosproject.evpnopenflow.rsc.BasePort; + +/** + * Describes base port event. + */ +public class BasePortEvent extends AbstractEvent { + /** + * Type of base port events. + */ + public enum Type { + /** + * Signifies that base port has been created. + */ + BASE_PORT_PUT, + /** + * Signifies that base port has been deleted. + */ + BASE_PORT_DELETE, + /** + * Signifies that base port has been updated. + */ + BASE_PORT_UPDATE + } + + /** + * Creates an event of a given type and for the specified base port. + * + * @param type base port event type + * @param basePort base port subject + */ + public BasePortEvent(Type type, BasePort basePort) { + super(type, basePort); + } + + /** + * Creates an event of a given type and for the specified base port. + * + * @param type base port event type + * @param basePort base port subject + * @param time occurrence time + */ + public BasePortEvent(Type type, BasePort basePort, long time) { + super(type, basePort, time); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortListener.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortListener.java new file mode 100755 index 0000000000..2822bb36fd --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortListener.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.baseport; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of base port related events. + */ +public interface BasePortListener extends EventListener { + +} \ No newline at end of file diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortService.java new file mode 100755 index 0000000000..c3bdb2b74f --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/BasePortService.java @@ -0,0 +1,155 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.baseport; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.evpnopenflow.rsc.BasePort; +import org.onosproject.evpnopenflow.rsc.BasePortId; +import org.onosproject.net.DeviceId; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetworkId; + +import java.util.Collection; + + +/** + * Service for interacting with the inventory of basePort. + */ +public interface BasePortService { + /** + * Returns if the basePort is existed. + * + * @param basePortId basePort identifier + * @return true or false if one with the given identifier is not existed. + */ + boolean exists(BasePortId basePortId); + + /** + * Returns the basePort with the identifier. + * + * @param basePortId basePort ID + * @return BasePort or null if one with the given ID is not know. + */ + BasePort getPort(BasePortId basePortId); + + /** + * Returns the basePort associated with the fixedIP. + * + * @param fixedIP the fixedIP identifier + * @return basePort. + */ + BasePort getPort(FixedIp fixedIP); + + /** + * Returns the basePort associated with the mac address. + * + * @param mac the mac address + * @return basePort. + */ + BasePort getPort(MacAddress mac); + + /** + * Returns the basePort associated with the networkId and ip. + * + * @param networkId the TenantNetworkId identifier + * @param ip the ip identifier + * @return basePort. + */ + BasePort getPort(TenantNetworkId networkId, IpAddress ip); + + /** + * Returns the collection of the currently known basePort. + * + * @return collection of BasePort. + */ + Collection getPorts(); + + /** + * Returns the collection of the basePorts associated with the networkId. + * + * @param networkId the network identifer + * @return collection of basePort. + */ + Collection getPorts(TenantNetworkId networkId); + + /** + * Returns the collection of the basePorts associated with the tenantId. + * + * @param tenantId the tenant identifier + * @return collection of basePorts. + */ + Collection getPorts(TenantId tenantId); + + /** + * Returns the collection of the basePorts associated with the deviceId. + * + * @param deviceId the device identifier + * @return collection of basePort. + */ + Collection getPorts(DeviceId deviceId); + + /** + * Creates basePorts by basePorts. + * + * @param basePorts the iterable collection of basePorts + * @return true if all given identifiers created successfully. + */ + boolean createPorts(Iterable basePorts); + + /** + * Updates basePorts by basePorts. + * + * @param basePorts the iterable collection of basePorts + * @return true if all given identifiers updated successfully. + */ + boolean updatePorts(Iterable basePorts); + + /** + * Deletes basePortIds by basePortIds. + * + * @param basePortIds the iterable collection of basePort identifiers + * @return true or false if one with the given identifier to delete is + * successfully. + */ + boolean removePorts(Iterable basePortIds); + + /** + * process gluon config for vpn port information. + * + * @param action can be either update or delete + * @param key can contain the id and also target information + * @param value content of the vpn port configuration + */ + void processGluonConfig(String action, String key, JsonNode value); + + /** + * Adds the specified listener to Vpn Port manager. + * + * @param listener Vpn Port listener + */ + void addListener(BasePortListener listener); + + /** + * Removes the specified listener to Vpn Port manager. + * + * @param listener Vpn Port listener + */ + void removeListener(BasePortListener listener); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/impl/BasePortManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/impl/BasePortManager.java new file mode 100755 index 0000000000..29c4d66001 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/impl/BasePortManager.java @@ -0,0 +1,439 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.baseport.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.Sets; +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.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.util.KryoNamespace; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.evpnopenflow.rsc.BasePort; +import org.onosproject.evpnopenflow.rsc.BasePortId; +import org.onosproject.evpnopenflow.rsc.DefaultBasePort; +import org.onosproject.evpnopenflow.rsc.baseport.BasePortEvent; +import org.onosproject.evpnopenflow.rsc.baseport.BasePortListener; +import org.onosproject.evpnopenflow.rsc.baseport.BasePortService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.MultiValuedTimestamp; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.WallClockTimestamp; +import org.onosproject.vtnrsc.AllowedAddressPair; +import org.onosproject.vtnrsc.BindingHostId; +import org.onosproject.vtnrsc.DefaultFloatingIp; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.FloatingIp; +import org.onosproject.vtnrsc.FloatingIpId; +import org.onosproject.vtnrsc.RouterId; +import org.onosproject.vtnrsc.SecurityGroup; +import org.onosproject.vtnrsc.SubnetId; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetwork; +import org.onosproject.vtnrsc.TenantNetworkId; +import org.onosproject.vtnrsc.TenantRouter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BASE_PORT_STORE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.LISTENER_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL; + +/** + * Provides implementation of the BasePort APIs. + */ +@Component(immediate = true) +@Service +public class BasePortManager implements BasePortService { + + private final Set listeners = Sets + .newCopyOnWriteArraySet(); + private final Logger log = LoggerFactory.getLogger(getClass()); + private static final String BASEPORT_ID_NULL = "BasePort ID cannot be " + + "null"; + private static final String BASEPORT_NOT_NULL = "BasePort cannot be " + + "null"; + private static final String TENANTID_NOT_NULL = "TenantId cannot be null"; + private static final String NETWORKID_NOT_NULL = "NetworkId cannot be null"; + private static final String DEVICEID_NOT_NULL = "DeviceId cannot be null"; + private static final String FIXEDIP_NOT_NULL = "FixedIp cannot be null"; + private static final String MAC_NOT_NULL = "Mac address cannot be null"; + private static final String IP_NOT_NULL = "Ip cannot be null"; + private static final String EVENT_NOT_NULL = "event cannot be null"; + private static final String SET = "set"; + private static final String UPDATE = "update"; + private static final String DELETE = "delete"; + private static final String SLASH = "/"; + private static final String PROTON_BASE_PORT = "Port"; + private static final String JSON_NOT_NULL = "JsonNode can not be null"; + + protected EventuallyConsistentMap vPortStore; + protected ApplicationId appId; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Activate + public void activate() { + + appId = coreService.registerApplication(APP_ID); + + KryoNamespace.Builder serializer = KryoNamespace.newBuilder() + .register(KryoNamespaces.API) + .register(MultiValuedTimestamp.class) + .register(TenantNetworkId.class) + .register(Host.class) + .register(TenantNetwork.class) + .register(TenantNetworkId.class) + .register(TenantId.class) + .register(SubnetId.class) + .register(BasePortId.class) + .register(BasePort.State.class) + .register(AllowedAddressPair.class) + .register(FixedIp.class) + .register(FloatingIp.class) + .register(FloatingIpId.class) + .register(FloatingIp.Status.class) + .register(UUID.class) + .register(DefaultFloatingIp.class) + .register(BindingHostId.class) + .register(SecurityGroup.class) + .register(IpAddress.class) + .register(DefaultBasePort.class) + .register(RouterId.class) + .register(TenantRouter.class) + .register(BasePort.class); + vPortStore = storageService + .eventuallyConsistentMapBuilder() + .withName(BASE_PORT_STORE).withSerializer(serializer) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + vPortStore.destroy(); + log.info("Stoppped"); + } + + @Override + public boolean exists(BasePortId vPortId) { + checkNotNull(vPortId, BASEPORT_ID_NULL); + return vPortStore.containsKey(vPortId); + } + + @Override + public BasePort getPort(BasePortId vPortId) { + checkNotNull(vPortId, BASEPORT_ID_NULL); + return vPortStore.get(vPortId); + } + + @Override + public BasePort getPort(FixedIp fixedIP) { + checkNotNull(fixedIP, FIXEDIP_NOT_NULL); + List vPorts = new ArrayList<>(); + vPortStore.values().forEach(p -> { + for (FixedIp fixedIp : p.fixedIps()) { + if (fixedIp.equals(fixedIP)) { + vPorts.add(p); + break; + } + } + }); + if (vPorts.size() == 0) { + return null; + } + return vPorts.get(0); + } + + @Override + public BasePort getPort(MacAddress mac) { + checkNotNull(mac, MAC_NOT_NULL); + List vPorts = new ArrayList<>(); + vPortStore.values().forEach(p -> { + if (p.macAddress().equals(mac)) { + vPorts.add(p); + } + }); + if (vPorts.size() == 0) { + return null; + } + return vPorts.get(0); + } + + @Override + public BasePort getPort(TenantNetworkId networkId, IpAddress ip) { + checkNotNull(networkId, NETWORKID_NOT_NULL); + checkNotNull(ip, IP_NOT_NULL); + List vPorts = new ArrayList<>(); + vPortStore.values().stream().filter(p -> p.networkId().equals(networkId)) + .forEach(p -> { + for (FixedIp fixedIp : p.fixedIps()) { + if (fixedIp.ip().equals(ip)) { + vPorts.add(p); + break; + } + } + }); + if (vPorts.size() == 0) { + return null; + } + return vPorts.get(0); + } + + @Override + public Collection getPorts() { + return Collections.unmodifiableCollection(vPortStore.values()); + } + + @Override + public Collection getPorts(TenantNetworkId networkId) { + checkNotNull(networkId, NETWORKID_NOT_NULL); + return vPortStore.values().stream().filter(d -> d.networkId().equals(networkId)) + .collect(Collectors.toList()); + } + + @Override + public Collection getPorts(TenantId tenantId) { + checkNotNull(tenantId, TENANTID_NOT_NULL); + return vPortStore.values().stream().filter(d -> d.tenantId().equals(tenantId)) + .collect(Collectors.toList()); + } + + @Override + public Collection getPorts(DeviceId deviceId) { + checkNotNull(deviceId, DEVICEID_NOT_NULL); + return vPortStore.values().stream().filter(d -> d.deviceId().equals(deviceId)) + .collect(Collectors.toList()); + } + + @Override + public boolean createPorts(Iterable vPorts) { + checkNotNull(vPorts, BASEPORT_NOT_NULL); + for (BasePort vPort : vPorts) { + log.info("vPortId is {} ", vPort.portId().toString()); + vPortStore.put(vPort.portId(), vPort); + if (!vPortStore.containsKey(vPort.portId())) { + log.info("The basePort is created failed whose identifier is" + + " {} ", + vPort.portId().toString()); + return false; + } + } + return true; + } + + @Override + public boolean updatePorts(Iterable vPorts) { + checkNotNull(vPorts, BASEPORT_NOT_NULL); + for (BasePort vPort : vPorts) { + vPortStore.put(vPort.portId(), vPort); + if (!vPortStore.containsKey(vPort.portId())) { + log.info("The basePort is not exist whose identifier is {}", + vPort.portId().toString()); + return false; + } + + vPortStore.put(vPort.portId(), vPort); + + if (!vPort.equals(vPortStore.get(vPort.portId()))) { + log.info("The basePort is updated failed whose identifier " + + "is {}", + vPort.portId().toString()); + return false; + } + } + return true; + } + + @Override + public boolean removePorts(Iterable vPortIds) { + checkNotNull(vPortIds, BASEPORT_ID_NULL); + for (BasePortId vPortId : vPortIds) { + vPortStore.remove(vPortId); + if (vPortStore.containsKey(vPortId)) { + log.info("The basePort is removed failed whose identifier is" + + " {}", + vPortId.toString()); + return false; + } + } + return true; + } + + /** + * Returns a collection of basePorts from subnetNodes. + * + * @param vPortNodes the basePort json node + * @return BasePort collection of vpn ports + */ + private Collection changeJsonToSub(JsonNode vPortNodes) { + checkNotNull(vPortNodes, JSON_NOT_NULL); + Set fixedIps = null; + TenantNetworkId tenantNetworkId = null; + Map vportMap = new HashMap<>(); + Map strMap = new HashMap<>(); + BasePortId basePortId = BasePortId.portId(vPortNodes.get("id").asText()); + String name = vPortNodes.get("name").asText(); + TenantId tenantId = TenantId + .tenantId(vPortNodes.get("tenant_id").asText()); + Boolean adminStateUp = vPortNodes.get("admin_state_up").asBoolean(); + String state = vPortNodes.get("status").asText(); + MacAddress macAddress = MacAddress + .valueOf(vPortNodes.get("mac_address").asText()); + DeviceId deviceId = DeviceId + .deviceId(vPortNodes.get("device_id").asText()); + String deviceOwner = vPortNodes.get("device_owner").asText(); + BindingHostId bindingHostId = BindingHostId + .bindingHostId(vPortNodes.get("host_id").asText()); + String bindingVnicType = vPortNodes.get("vnic_type").asText(); + String bindingVifType = vPortNodes.get("vif_type").asText(); + String bindingVifDetails = vPortNodes.get("vif_details").asText(); + strMap.put("name", name); + strMap.put("deviceOwner", deviceOwner); + strMap.put("bindingVnicType", bindingVnicType); + strMap.put("bindingVifType", bindingVifType); + strMap.put("bindingVifDetails", bindingVifDetails); + BasePort prevBasePort = getPort(basePortId); + if (prevBasePort != null) { + fixedIps = prevBasePort.fixedIps(); + tenantNetworkId = prevBasePort.networkId(); + } + BasePort vPort = new DefaultBasePort(basePortId, + tenantNetworkId, + adminStateUp, + strMap, state, + macAddress, tenantId, + deviceId, fixedIps, + bindingHostId, + null, + null); + vportMap.put(basePortId, vPort); + + return Collections.unmodifiableCollection(vportMap.values()); + } + + /** + * Returns BasePort State. + * + * @param state the base port state + * @return the basePort state + */ + private BasePort.State isState(String state) { + if (state.equals("ACTIVE")) { + return BasePort.State.ACTIVE; + } else { + return BasePort.State.DOWN; + } + + } + + /** + * process Etcd response for port information. + * + * @param action can be either update or delete + * @param key can contain the id and also target information + * @param value content of the port configuration + */ + @Override + public void processGluonConfig(String action, String key, JsonNode value) { + Collection basePorts; + switch (action) { + case DELETE: + String[] list = key.split(SLASH); + BasePortId basePortId + = BasePortId.portId(list[list.length - 1]); + Set basePortIds = Sets.newHashSet(basePortId); + removePorts(basePortIds); + break; + case SET: + checkNotNull(value, RESPONSE_NOT_NULL); + basePorts = changeJsonToSub(value); + createPorts(basePorts); + break; + case UPDATE: + checkNotNull(value, RESPONSE_NOT_NULL); + basePorts = changeJsonToSub(value); + updatePorts(basePorts); + break; + default: + log.info("Invalid action is received while processing VPN " + + "port configuration"); + } + } + + private void parseEtcdResponse(JsonNode jsonNode, + String key, + String action) { + JsonNode modifyValue = null; + if (action.equals(SET)) { + modifyValue = jsonNode.get(key); + } + String[] list = key.split(SLASH); + String target = list[list.length - 2]; + if (target.equals(PROTON_BASE_PORT)) { + processGluonConfig(action, key, modifyValue); + } + } + + @Override + public void addListener(BasePortListener listener) { + checkNotNull(listener, LISTENER_NOT_NULL); + listeners.add(listener); + } + + @Override + public void removeListener(BasePortListener listener) { + checkNotNull(listener, LISTENER_NOT_NULL); + listeners.remove(listener); + } + + /** + * Notifies specify event to all listeners. + * + * @param event vpn af config event + */ + private void notifyListeners(BasePortEvent event) { + checkNotNull(event, EVENT_NOT_NULL); + listeners.forEach(listener -> listener.event(event)); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/impl/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/impl/package-info.java new file mode 100755 index 0000000000..366dc00cbd --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN resources that used by l3vpn. + */ +package org.onosproject.evpnopenflow.rsc.baseport.impl; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/package-info.java new file mode 100755 index 0000000000..52f5d0c861 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/baseport/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN resources that used by l3vpn. + */ +package org.onosproject.evpnopenflow.rsc.baseport; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java new file mode 100755 index 0000000000..21223205dc --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java @@ -0,0 +1,53 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.evpnopenflow.manager.EvpnService; +import org.onosproject.evpnopenflow.manager.impl.EvpnManager; +import org.onosproject.incubator.net.routing.EvpnInstanceRoute; + +import java.util.Collection; + +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.FORMAT_PRIVATE_ROUTE; + +/** + * Support for displaying EVPN private routes. + */ +@Command(scope = "onos", name = "evpn-private-routes", description = "Lists" + + " all EVPN private routes") +public class EvpnPrivateRouteListCommand extends AbstractShellCommand { + private static final String FORMAT_HEADER = + " VPN name Prefix Next Hop"; + + @Override + protected void execute() { + EvpnService service = AbstractShellCommand.get(EvpnService.class); + EvpnManager evpnManager = (EvpnManager) service; + Collection evpnRoutes = evpnManager.evpnInstanceRoutes; + if (evpnRoutes != null) { + print(FORMAT_HEADER); + evpnRoutes.forEach(evpnInstanceRoute -> { + print(FORMAT_PRIVATE_ROUTE, evpnInstanceRoute.evpnInstanceName(), + evpnInstanceRoute.prefix().address().getIp4Address(), evpnInstanceRoute + .getNextHopl()); + }); + } + } + +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java new file mode 100755 index 0000000000..3067257960 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java @@ -0,0 +1,58 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.routing.EvpnRoute; +import org.onosproject.incubator.net.routing.EvpnRouteSet; +import org.onosproject.incubator.net.routing.EvpnRouteStore; + +import java.util.Collection; + +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.FORMAT_PUBLIC_ROUTE; + +/** + * Support for displaying EVPN public routes. + */ +@Command(scope = "onos", name = "evpn-public-routes", description = "Lists" + + " all EVPN public routes") +public class EvpnPublicRouteListCommand extends AbstractShellCommand { + private static final String FORMAT_HEADER = + " MAC Prefix Next Hop"; + + @Override + protected void execute() { + EvpnRouteStore evpnRouteStore = AbstractShellCommand.get(EvpnRouteStore.class); + + evpnRouteStore.getRouteTables().forEach(routeTableId -> { + Collection routes + = evpnRouteStore.getRoutes(routeTableId); + if (routes != null) { + routes.forEach(route -> { + Collection evpnRoutes = route.routes(); + print(FORMAT_HEADER); + evpnRoutes.forEach(evpnRoute -> { + print(FORMAT_PUBLIC_ROUTE, evpnRoute.prefixMac(), + evpnRoute.prefixIp().address().getIp4Address(), + evpnRoute.ipNextHop()); + }); + }); + } + }); + } +} \ No newline at end of file diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/VpnInstListCommand.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/VpnInstListCommand.java new file mode 100755 index 0000000000..320c848aa7 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/VpnInstListCommand.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.evpnopenflow.rsc.EvpnConstants; +import org.onosproject.evpnopenflow.rsc.VpnInstance; +import org.onosproject.evpnopenflow.rsc.vpninstance.VpnInstanceService; + +import java.util.Collection; + +/** + * Support for displaying EVPN VPN instances. + */ +@Command(scope = "onos", name = "evpn-instance-list", description = "Lists " + + "all EVPN instances") +public class VpnInstListCommand extends AbstractShellCommand { + + @Override + protected void execute() { + VpnInstanceService service = get(VpnInstanceService.class); + Collection vpnInstances = service + .getInstances(); + vpnInstances.forEach(vpnInstance -> { + print(EvpnConstants.FORMAT_VPN_INSTANCE, vpnInstance.id(), + vpnInstance.description(), + vpnInstance.vpnInstanceName(), + vpnInstance.routeDistinguisher(), + vpnInstance.getExportRouteTargets(), + vpnInstance.getImportRouteTargets()); + }); + } + +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/VpnPortListCommand.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/VpnPortListCommand.java new file mode 100755 index 0000000000..366ead5df6 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/VpnPortListCommand.java @@ -0,0 +1,44 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.evpnopenflow.rsc.VpnPort; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortService; + +import java.util.Collection; + +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.FORMAT_VPN_PORT; + +/** + * Support for displaying EVPN VPN ports. + */ +@Command(scope = "onos", name = "evpn-port-list", description = "Lists all" + + "EVPN ports") +public class VpnPortListCommand extends AbstractShellCommand { + + @Override + protected void execute() { + VpnPortService portService = get(VpnPortService.class); + Collection ports = portService.getPorts(); + ports.forEach(port -> { + print(FORMAT_VPN_PORT, port.id(), port.vpnInstanceId()); + }); + } + +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/package-info.java new file mode 100755 index 0000000000..3bc47c8370 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * Implementation CLI for EVPN services. + */ +package org.onosproject.evpnopenflow.rsc.cli; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/package-info.java new file mode 100755 index 0000000000..c37dc81bd4 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * EVPN resource package. + */ +package org.onosproject.evpnopenflow.rsc; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigEvent.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigEvent.java new file mode 100755 index 0000000000..944698c1e4 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigEvent.java @@ -0,0 +1,65 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnafconfig; + +import org.onosproject.event.AbstractEvent; +import org.onosproject.evpnopenflow.rsc.VpnAfConfig; + +/** + * Describes network VPN af config event. + */ +public class VpnAfConfigEvent extends AbstractEvent { + + /** + * Type of VPN port events. + */ + public enum Type { + /** + * Signifies that VPN af config has been set. + */ + VPN_AF_CONFIG_SET, + /** + * Signifies that VPN af config has been deleted. + */ + VPN_AF_CONFIG_DELETE, + /** + * Signifies that VPN af config has been updated. + */ + VPN_AF_CONFIG_UPDATE + } + + /** + * Creates an event of a given type and for the specified VPN af config. + * + * @param type VPN af config type + * @param vpnAfConfig VPN af config subject + */ + public VpnAfConfigEvent(Type type, VpnAfConfig vpnAfConfig) { + super(type, vpnAfConfig); + } + + /** + * Creates an event of a given type and for the specified VPN af config. + * + * @param type VPN af config type + * @param vpnAfConfig VPN af config subject + * @param time occurrence time + */ + public VpnAfConfigEvent(Type type, VpnAfConfig vpnAfConfig, long time) { + super(type, vpnAfConfig, time); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigListener.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigListener.java new file mode 100755 index 0000000000..42db841b91 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigListener.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnafconfig; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of VPN af config related events. + */ +public interface VpnAfConfigListener extends EventListener { +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java new file mode 100755 index 0000000000..31714ad61f --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java @@ -0,0 +1,100 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnafconfig; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onosproject.evpnopenflow.rsc.VpnAfConfig; +import org.onosproject.incubator.net.routing.VpnRouteTarget; + +import java.util.Collection; + +/** + * Service for interacting with the inventory of VPN af config instance. + */ +public interface VpnAfConfigService { + /** + * Returns if the route target is existed. + * + * @param routeTarget route target + * @return true or false if one with the given route target is not existed. + */ + boolean exists(VpnRouteTarget routeTarget); + + /** + * Returns the VPN af config with the route target. + * + * @param routeTarget route target + * @return VPN af config or null if one with the given route target is not + * know. + */ + VpnAfConfig getVpnAfConfig(VpnRouteTarget routeTarget); + + /** + * Returns the collection of the currently known VPN af configurations. + * + * @return collection of VPN af configurations. + */ + Collection getVpnAfConfigs(); + + /** + * Creates VPN af configurations by vpnAfConfigs. + * + * @param vpnAfConfigs the iterable collection of vpnAfConfigs + * @return true if all given VPN af configs created successfully + */ + boolean createVpnAfConfigs(Iterable vpnAfConfigs); + + /** + * Updates VPN af configurations by vpnAfConfigs. + * + * @param vpnAfConfigs the iterable collection of vpnAfConfigs + * @return true if all given VPN af configs created successfully. + */ + boolean updateVpnAfConfigs(Iterable vpnAfConfigs); + + /** + * Deletes vpnAfConfigs by route target. + * + * @param routeTarget the iterable collection of vpnAFConfigs + * @return true or false if one with the given route target to delete is + * successfully + */ + boolean removeVpnAfConfigs(Iterable routeTarget); + + /** + * process gluon config for vpn af configuration. + * + * @param action can be either update or delete + * @param key can contain the id and also target information + * @param value content of the route targets configuration + */ + void processGluonConfig(String action, String key, JsonNode value); + + /** + * Adds the specified listener to Vpn Port manager. + * + * @param listener vpn af config listener + */ + void addListener(VpnAfConfigListener listener); + + /** + * Removes the specified listener to vpn af config manager. + * + * @param listener vpn af config listener + */ + void removeListener(VpnAfConfigListener listener); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java new file mode 100755 index 0000000000..fafd5d8598 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java @@ -0,0 +1,268 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnafconfig.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.Sets; +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.onlab.util.KryoNamespace; +import org.onosproject.core.CoreService; +import org.onosproject.evpnopenflow.rsc.DefaultVpnAfConfig; +import org.onosproject.evpnopenflow.rsc.VpnAfConfig; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigEvent; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigListener; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService; +import org.onosproject.incubator.net.routing.VpnRouteTarget; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.WallClockTimestamp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVENT_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_AF_CONFIG_START; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_AF_CONFIG_STOP; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EXPORT_ROUTE_POLICY; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IMPORT_ROUTE_POLICY; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_ACTION_VPN_AF_CONFIG; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.JSON_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.LISTENER_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_TARGET_CANNOT_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_TARGET_DELETE_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_TARGET_VALUE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_CREATION_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_IS_NOT_EXIST; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_STORE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_UPDATE_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_ID_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VRF_RT_TYPE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VRF_RT_VALUE; + +/** + * Provides implementation of the VPN af config APIs. + */ +@Component(immediate = true) +@Service +public class VpnAfConfigManager implements VpnAfConfigService { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Set listeners = Sets + .newCopyOnWriteArraySet(); + + protected EventuallyConsistentMap + vpnAfConfigStore; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Activate + public void activate() { + coreService.registerApplication(APP_ID); + KryoNamespace.Builder serializer = KryoNamespace.newBuilder() + .register(KryoNamespaces.API).register(VpnAfConfig.class) + .register(VpnRouteTarget.class); + vpnAfConfigStore = storageService + .eventuallyConsistentMapBuilder() + .withName(VPN_AF_CONFIG_STORE).withSerializer(serializer) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + log.info(EVPN_VPN_AF_CONFIG_START); + } + + @Deactivate + public void deactivate() { + vpnAfConfigStore.destroy(); + log.info(EVPN_VPN_AF_CONFIG_STOP); + } + + @Override + public boolean exists(VpnRouteTarget routeTarget) { + checkNotNull(routeTarget, ROUTE_TARGET_CANNOT_NOT_NULL); + return vpnAfConfigStore.containsKey(routeTarget); + } + + @Override + public VpnAfConfig getVpnAfConfig(VpnRouteTarget routeTarget) { + checkNotNull(routeTarget, ROUTE_TARGET_CANNOT_NOT_NULL); + return vpnAfConfigStore.get(routeTarget); + } + + @Override + public Collection getVpnAfConfigs() { + return Collections.unmodifiableCollection(vpnAfConfigStore.values()); + } + + @Override + public boolean createVpnAfConfigs(Iterable vpnAfConfigs) { + checkNotNull(vpnAfConfigs, VPN_AF_CONFIG_NOT_NULL); + for (VpnAfConfig vpnAfConfig : vpnAfConfigs) { + log.info(ROUTE_TARGET_VALUE, vpnAfConfig + .routeTarget().getRouteTarget()); + vpnAfConfigStore.put(vpnAfConfig.routeTarget(), vpnAfConfig); + if (!vpnAfConfigStore.containsKey(vpnAfConfig.routeTarget())) { + log.info(VPN_AF_CONFIG_CREATION_FAILED, + vpnAfConfig.routeTarget().getRouteTarget()); + return false; + } + notifyListeners(new VpnAfConfigEvent(VpnAfConfigEvent + .Type + .VPN_AF_CONFIG_SET, + vpnAfConfig)); + } + return true; + } + + @Override + public boolean updateVpnAfConfigs(Iterable vpnAfConfigs) { + checkNotNull(vpnAfConfigs, VPN_AF_CONFIG_NOT_NULL); + for (VpnAfConfig vpnAfConfig : vpnAfConfigs) { + if (!vpnAfConfigStore.containsKey(vpnAfConfig.routeTarget())) { + log.info(VPN_AF_CONFIG_IS_NOT_EXIST, + vpnAfConfig.routeTarget().getRouteTarget()); + return false; + } + vpnAfConfigStore.put(vpnAfConfig.routeTarget(), vpnAfConfig); + if (!vpnAfConfig.equals(vpnAfConfigStore + .get(vpnAfConfig.routeTarget()))) { + log.info(VPN_AF_CONFIG_UPDATE_FAILED, + vpnAfConfig.routeTarget().getRouteTarget()); + return false; + } + notifyListeners(new VpnAfConfigEvent(VpnAfConfigEvent + .Type + .VPN_AF_CONFIG_UPDATE, + vpnAfConfig)); + } + return true; + } + + @Override + public boolean removeVpnAfConfigs(Iterable routeTargets) { + checkNotNull(routeTargets, VPN_INSTANCE_ID_NOT_NULL); + for (VpnRouteTarget routeTarget : routeTargets) { + VpnAfConfig vpnAfConfig = vpnAfConfigStore.get(routeTarget); + vpnAfConfigStore.remove(routeTarget); + if (vpnAfConfigStore.containsKey(routeTarget)) { + log.info(ROUTE_TARGET_DELETE_FAILED, + routeTarget.getRouteTarget()); + return false; + } + notifyListeners(new VpnAfConfigEvent(VpnAfConfigEvent + .Type + .VPN_AF_CONFIG_DELETE, + vpnAfConfig)); + } + return true; + } + + @Override + public void processGluonConfig(String action, String key, JsonNode value) { + Collection vpnAfConfigs; + switch (action) { + case DELETE: + String[] list = key.split(SLASH); + VpnRouteTarget routeTarget = VpnRouteTarget + .routeTarget(list[list.length - 1]); + Set routeTargets + = Sets.newHashSet(routeTarget); + removeVpnAfConfigs(routeTargets); + break; + case SET: + checkNotNull(value, RESPONSE_NOT_NULL); + vpnAfConfigs = changeJsonToSub(value); + createVpnAfConfigs(vpnAfConfigs); + break; + case UPDATE: + checkNotNull(value, RESPONSE_NOT_NULL); + vpnAfConfigs = changeJsonToSub(value); + updateVpnAfConfigs(vpnAfConfigs); + break; + default: + log.info(INVALID_ACTION_VPN_AF_CONFIG); + break; + } + } + + /** + * Returns a collection of vpn af configuration. + * + * @param vpnAfConfigNode the vpn af configuration json node + * @return returns the collection of vpn af configuration + */ + private Collection changeJsonToSub(JsonNode vpnAfConfigNode) { + checkNotNull(vpnAfConfigNode, JSON_NOT_NULL); + Map vpnAfConfigMap = new HashMap<>(); + String exportRoutePolicy + = vpnAfConfigNode.get(EXPORT_ROUTE_POLICY).asText(); + String importRoutePolicy + = vpnAfConfigNode.get(IMPORT_ROUTE_POLICY).asText(); + String routeTargetType = vpnAfConfigNode.get(VRF_RT_TYPE).asText(); + VpnRouteTarget routeTarget = VpnRouteTarget + .routeTarget(vpnAfConfigNode.get(VRF_RT_VALUE).asText()); + + VpnAfConfig vpnAfConfig = new DefaultVpnAfConfig(exportRoutePolicy, + importRoutePolicy, + routeTarget, + routeTargetType); + vpnAfConfigMap.put(routeTarget, vpnAfConfig); + + return Collections.unmodifiableCollection(vpnAfConfigMap.values()); + } + + @Override + public void addListener(VpnAfConfigListener listener) { + checkNotNull(listener, LISTENER_NOT_NULL); + listeners.add(listener); + } + + @Override + public void removeListener(VpnAfConfigListener listener) { + checkNotNull(listener, LISTENER_NOT_NULL); + listeners.remove(listener); + } + + /** + * Notifies specify event to all listeners. + * + * @param event vpn af config event + */ + private void notifyListeners(VpnAfConfigEvent event) { + checkNotNull(event, EVENT_NOT_NULL); + listeners.forEach(listener -> listener.event(event)); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/package-info.java new file mode 100755 index 0000000000..f2dd128674 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN af configuration that used by l3vpn. + */ +package org.onosproject.evpnopenflow.rsc.vpnafconfig.impl; \ No newline at end of file diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/package-info.java new file mode 100755 index 0000000000..7c2e4f4cc3 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN resources that used by Evpn. + */ +package org.onosproject.evpnopenflow.rsc.vpnafconfig; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java new file mode 100755 index 0000000000..f233f2938c --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java @@ -0,0 +1,100 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpninstance; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onosproject.evpnopenflow.rsc.VpnInstance; +import org.onosproject.evpnopenflow.rsc.VpnInstanceId; +import org.onosproject.incubator.net.routing.VpnRouteTarget; + +import java.util.Collection; +import java.util.Set; + +/** + * Service for interacting with the inventory of VPN instance. + */ +public interface VpnInstanceService { + /** + * Returns if the vpnInstance is existed. + * + * @param vpnInstanceId vpnInstance identifier + * @return true or false if one with the given identifier is not existed. + */ + boolean exists(VpnInstanceId vpnInstanceId); + + /** + * Returns the vpnInstance with the identifier. + * + * @param vpnInstanceId vpnInstance ID + * @return VpnInstance or null if one with the given ID is not know. + */ + VpnInstance getInstance(VpnInstanceId vpnInstanceId); + + /** + * Returns the collection of the currently known vpnInstance. + * + * @return collection of VpnInstance. + */ + Collection getInstances(); + + /** + * Creates vpnInstances by vpnInstances. + * + * @param vpnInstances the iterable collection of vpnInstances + * @return true if all given identifiers created successfully. + */ + boolean createInstances(Iterable vpnInstances); + + /** + * Updates vpnInstances by vpnInstances. + * + * @param vpnInstances the iterable collection of vpnInstances + * @return true if all given identifiers updated successfully. + */ + boolean updateInstances(Iterable vpnInstances); + + /** + * Deletes vpnInstanceIds by vpnInstanceIds. + * + * @param vpnInstanceIds the iterable collection of vpnInstance identifiers + * @return true or false if one with the given identifier to delete is + * successfully. + */ + boolean removeInstances(Iterable vpnInstanceIds); + + /** + * process gluon config for vpn instance information. + * + * @param action can be either update or delete + * @param key can contain the id and also target information + * @param value content of the vpn instance configuration + */ + void processGluonConfig(String action, String key, JsonNode value); + + /** + * process Etcd response for vpn instance information. + * + * @param routeTargetType route target type + * @param exportRouteTargets export route targets + * @param importRouteTargets import route targets + * @param vpnRouteTarget vpn route target + */ + void updateImpExpRouteTargets(String routeTargetType, + Set exportRouteTargets, + Set importRouteTargets, + VpnRouteTarget vpnRouteTarget); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java new file mode 100755 index 0000000000..361bad4ec6 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java @@ -0,0 +1,290 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpninstance.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.Sets; +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.onlab.util.KryoNamespace; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.evpnopenflow.rsc.DefaultVpnInstance; +import org.onosproject.evpnopenflow.rsc.VpnAfConfig; +import org.onosproject.evpnopenflow.rsc.VpnInstance; +import org.onosproject.evpnopenflow.rsc.VpnInstanceId; +import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService; +import org.onosproject.evpnopenflow.rsc.vpninstance.VpnInstanceService; +import org.onosproject.incubator.net.routing.EvpnInstanceName; +import org.onosproject.incubator.net.routing.RouteAdminService; +import org.onosproject.incubator.net.routing.RouteDistinguisher; +import org.onosproject.incubator.net.routing.VpnRouteTarget; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.WallClockTimestamp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.COMMA; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DESCRIPTION; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_INSTANCE_START; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_INSTANCE_STOP; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INSTANCE_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IPV4_FAMILY; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.JSON_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_DISTINGUISHERS; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_CREATION_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_DELETE_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_ID_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_IS_NOT_EXIST; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_NAME; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_STORE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_UPDATE_FAILED; + + +/** + * Provides implementation of the VpnInstance APIs. + */ +@Component(immediate = true) +@Service +public class VpnInstanceManager implements VpnInstanceService { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + protected EventuallyConsistentMap vpnInstanceStore; + protected ApplicationId appId; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected RouteAdminService routeService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected VpnAfConfigService vpnAfConfigService; + + @Activate + public void activate() { + appId = coreService.registerApplication(APP_ID); + KryoNamespace.Builder serializer = KryoNamespace.newBuilder() + .register(KryoNamespaces.API).register(VpnInstance.class) + .register(VpnInstanceId.class); + vpnInstanceStore = storageService + .eventuallyConsistentMapBuilder() + .withName(VPN_INSTANCE_STORE).withSerializer(serializer) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + log.info(EVPN_VPN_INSTANCE_START); + } + + @Deactivate + public void deactivate() { + vpnInstanceStore.destroy(); + log.info(EVPN_VPN_INSTANCE_STOP); + } + + @Override + public boolean exists(VpnInstanceId vpnInstanceId) { + checkNotNull(vpnInstanceId, VPN_INSTANCE_ID_NOT_NULL); + return vpnInstanceStore.containsKey(vpnInstanceId); + } + + @Override + public VpnInstance getInstance(VpnInstanceId vpnInstanceId) { + checkNotNull(vpnInstanceId, VPN_INSTANCE_ID_NOT_NULL); + return vpnInstanceStore.get(vpnInstanceId); + } + + @Override + public Collection getInstances() { + return Collections.unmodifiableCollection(vpnInstanceStore.values()); + } + + @Override + public boolean createInstances(Iterable vpnInstances) { + checkNotNull(vpnInstances, VPN_INSTANCE_NOT_NULL); + for (VpnInstance vpnInstance : vpnInstances) { + log.info(INSTANCE_ID, vpnInstance.id().toString()); + vpnInstanceStore.put(vpnInstance.id(), vpnInstance); + if (!vpnInstanceStore.containsKey(vpnInstance.id())) { + log.info(VPN_INSTANCE_CREATION_FAILED, + vpnInstance.id().toString()); + return false; + } + } + return true; + } + + @Override + public boolean updateInstances(Iterable vpnInstances) { + checkNotNull(vpnInstances, VPN_INSTANCE_NOT_NULL); + for (VpnInstance vpnInstance : vpnInstances) { + if (!vpnInstanceStore.containsKey(vpnInstance.id())) { + log.info(VPN_INSTANCE_IS_NOT_EXIST, + vpnInstance.id().toString()); + return false; + } + vpnInstanceStore.put(vpnInstance.id(), vpnInstance); + if (!vpnInstance.equals(vpnInstanceStore.get(vpnInstance.id()))) { + log.info(VPN_INSTANCE_UPDATE_FAILED, + vpnInstance.id().toString()); + return false; + } + } + return true; + } + + @Override + public boolean removeInstances(Iterable vpnInstanceIds) { + checkNotNull(vpnInstanceIds, VPN_INSTANCE_ID_NOT_NULL); + for (VpnInstanceId vpnInstanceId : vpnInstanceIds) { + vpnInstanceStore.remove(vpnInstanceId); + if (vpnInstanceStore.containsKey(vpnInstanceId)) { + log.info(VPN_INSTANCE_DELETE_FAILED, vpnInstanceId.toString()); + return false; + } + } + return true; + } + + @Override + public void processGluonConfig(String action, String key, JsonNode value) { + Collection vpnInstances; + switch (action) { + case DELETE: + String[] list = key.split(SLASH); + VpnInstanceId vpnInstanceId = VpnInstanceId + .vpnInstanceId(list[list.length - 1]); + Set vpnInstanceIds + = Sets.newHashSet(vpnInstanceId); + removeInstances(vpnInstanceIds); + break; + case SET: + checkNotNull(value, RESPONSE_NOT_NULL); + vpnInstances = changeJsonToSub(value); + createInstances(vpnInstances); + break; + case UPDATE: + checkNotNull(value, RESPONSE_NOT_NULL); + vpnInstances = changeJsonToSub(value); + updateInstances(vpnInstances); + break; + default: + log.info("Invalid action is received while processing VPN " + + "instance configuration"); + } + } + + @Override + public void updateImpExpRouteTargets(String routeTargetType, + Set exportRouteTargets, + Set importRouteTargets, + VpnRouteTarget vpnRouteTarget) { + switch (routeTargetType) { + case "export_extcommunity": + exportRouteTargets.add(vpnRouteTarget); + break; + case "import_extcommunity": + importRouteTargets.add(vpnRouteTarget); + break; + case "both": + exportRouteTargets.add(vpnRouteTarget); + importRouteTargets.add(vpnRouteTarget); + break; + default: + log.info("Invalid route target type has received"); + break; + } + } + + /** + * Returns a collection of vpnInstances from subnetNodes. + * + * @param vpnInstanceNodes the vpnInstance json node + * @return returns the collection of vpn instances + */ + private Collection changeJsonToSub(JsonNode vpnInstanceNodes) { + checkNotNull(vpnInstanceNodes, JSON_NOT_NULL); + + Set exportRouteTargets = new HashSet<>(); + Set importRouteTargets = new HashSet<>(); + Set configRouteTargets = new HashSet<>(); + + Map vpnInstanceMap = new HashMap<>(); + VpnInstanceId id = VpnInstanceId + .vpnInstanceId(vpnInstanceNodes.get(ID).asText()); + EvpnInstanceName name = EvpnInstanceName + .evpnName(vpnInstanceNodes.get(VPN_INSTANCE_NAME).asText()); + String description = vpnInstanceNodes.get(DESCRIPTION).asText(); + RouteDistinguisher routeDistinguisher = RouteDistinguisher + .routeDistinguisher(vpnInstanceNodes.get(ROUTE_DISTINGUISHERS) + .asText()); + String routeTargets = vpnInstanceNodes.get(IPV4_FAMILY).asText(); + String[] list = routeTargets.split(COMMA); + + for (String routeTarget : list) { + // Converting route target string into route target object and + // then storing into configuration route target set. + VpnRouteTarget vpnRouteTarget + = VpnRouteTarget.routeTarget(routeTarget); + configRouteTargets.add(vpnRouteTarget); + VpnAfConfig vpnAfConfig + = vpnAfConfigService.getVpnAfConfig(vpnRouteTarget); + if (vpnAfConfig == null) { + log.info("Not able to find vpn af config for the give vpn " + + "route target"); + break; + } + updateImpExpRouteTargets(vpnAfConfig.routeTargetType(), + exportRouteTargets, + importRouteTargets, + vpnRouteTarget); + } + + VpnInstance vpnInstance = new DefaultVpnInstance(id, name, description, + routeDistinguisher, + exportRouteTargets, + importRouteTargets, + configRouteTargets); + vpnInstanceMap.put(id, vpnInstance); + return Collections.unmodifiableCollection(vpnInstanceMap.values()); + } +} \ No newline at end of file diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/package-info.java new file mode 100755 index 0000000000..6cfc75ecf5 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN resources that used by l3vpn. + */ +package org.onosproject.evpnopenflow.rsc.vpninstance.impl; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/package-info.java new file mode 100755 index 0000000000..b68dbd06de --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * EVPN VPN instance implementation. + */ +package org.onosproject.evpnopenflow.rsc.vpninstance; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortEvent.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortEvent.java new file mode 100755 index 0000000000..acc28db1c2 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortEvent.java @@ -0,0 +1,65 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnport; + +import org.onosproject.event.AbstractEvent; +import org.onosproject.evpnopenflow.rsc.VpnPort; + +/** + * Describes network VPN port event. + */ +public class VpnPortEvent extends AbstractEvent { + + /** + * Type of VPN port events. + */ + public enum Type { + /** + * Signifies that VPN port has been set. + */ + VPN_PORT_SET, + /** + * Signifies that VPN port has been deleted. + */ + VPN_PORT_DELETE, + /** + * Signifies that VPN port has been updated. + */ + VPN_PORT_UPDATE + } + + /** + * Creates an event of a given type and for the specified VPN port. + * + * @param type VPN port type + * @param vpnPort VPN port subject + */ + public VpnPortEvent(Type type, VpnPort vpnPort) { + super(type, vpnPort); + } + + /** + * Creates an event of a given type and for the specified VPN port. + * + * @param type VPN port type + * @param vpnPort VPN port subject + * @param time occurrence time + */ + public VpnPortEvent(Type type, VpnPort vpnPort, long time) { + super(type, vpnPort, time); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortListener.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortListener.java new file mode 100755 index 0000000000..95eb797192 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortListener.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnport; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of VPN port related events. + */ +public interface VpnPortListener extends EventListener { +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortService.java new file mode 100755 index 0000000000..c7bce1b77d --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/VpnPortService.java @@ -0,0 +1,100 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnport; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onosproject.evpnopenflow.rsc.VpnPort; +import org.onosproject.evpnopenflow.rsc.VpnPortId; + +import java.util.Collection; + + +/** + * Service for interacting with the inventory of VPN port. + */ +public interface VpnPortService { + /** + * Returns if the vpnPort is existed. + * + * @param vpnPortId vpnPort identifier + * @return true or false if one with the given identifier is not existed. + */ + boolean exists(VpnPortId vpnPortId); + + /** + * Returns the vpnPort with the identifier. + * + * @param vpnPortId vpnPort ID + * @return VpnPort or null if one with the given ID is not know. + */ + VpnPort getPort(VpnPortId vpnPortId); + + /** + * Returns the collection of the currently known vpnPort. + * + * @return collection of VpnPort. + */ + Collection getPorts(); + + /** + * Creates vpnPorts by vpnPorts. + * + * @param vpnPorts the iterable collection of vpnPorts + * @return true if all given identifiers created successfully. + */ + boolean createPorts(Iterable vpnPorts); + + /** + * Updates vpnPorts by vpnPorts. + * + * @param vpnPorts the iterable collection of vpnPorts + * @return true if all given identifiers updated successfully. + */ + boolean updatePorts(Iterable vpnPorts); + + /** + * Deletes vpnPortIds by vpnPortIds. + * + * @param vpnPortIds the iterable collection of vpnPort identifiers + * @return true or false if one with the given identifier to delete is + * successfully. + */ + boolean removePorts(Iterable vpnPortIds); + + /** + * process gluon config for vpn port information. + * + * @param action can be either update or delete + * @param key can contain the id and also target information + * @param value content of the vpn port configuration + */ + void processGluonConfig(String action, String key, JsonNode value); + + /** + * Adds the specified listener to Vpn Port manager. + * + * @param listener Vpn Port listener + */ + void addListener(VpnPortListener listener); + + /** + * Removes the specified listener to Vpn Port manager. + * + * @param listener Vpn Port listener + */ + void removeListener(VpnPortListener listener); +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/impl/VpnPortManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/impl/VpnPortManager.java new file mode 100755 index 0000000000..18ff172710 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/impl/VpnPortManager.java @@ -0,0 +1,431 @@ +/* + * Copyright 2017-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.evpnopenflow.rsc.vpnport.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.Sets; +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.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.util.KryoNamespace; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.evpnopenflow.rsc.BasePort; +import org.onosproject.evpnopenflow.rsc.BasePortId; +import org.onosproject.evpnopenflow.rsc.DefaultVpnPort; +import org.onosproject.evpnopenflow.rsc.VpnInstanceId; +import org.onosproject.evpnopenflow.rsc.VpnPort; +import org.onosproject.evpnopenflow.rsc.VpnPortId; +import org.onosproject.evpnopenflow.rsc.baseport.BasePortService; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortEvent; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortListener; +import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortService; +import org.onosproject.net.DeviceId; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.WallClockTimestamp; +import org.onosproject.vtnrsc.AllocationPool; +import org.onosproject.vtnrsc.BindingHostId; +import org.onosproject.vtnrsc.DefaultSubnet; +import org.onosproject.vtnrsc.DefaultTenantNetwork; +import org.onosproject.vtnrsc.DefaultVirtualPort; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.HostRoute; +import org.onosproject.vtnrsc.PhysicalNetwork; +import org.onosproject.vtnrsc.SegmentationId; +import org.onosproject.vtnrsc.Subnet; +import org.onosproject.vtnrsc.SubnetId; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetwork; +import org.onosproject.vtnrsc.TenantNetworkId; +import org.onosproject.vtnrsc.VirtualPort; +import org.onosproject.vtnrsc.VirtualPortId; +import org.onosproject.vtnrsc.subnet.SubnetService; +import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService; +import org.onosproject.vtnrsc.virtualport.VirtualPortService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVENT_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_PORT_START; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_PORT_STOP; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INTERFACE_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.JSON_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.LISTENER_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_CREATION_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_DELETE_FAILED; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_ID; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_ID_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_IS_NOT_EXIST; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_NOT_NULL; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_STORE; +import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_UPDATE_FAILED; + +/** + * Provides implementation of the VpnPort service. + */ +@Component(immediate = true) +@Service +public class VpnPortManager implements VpnPortService { + + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Set listeners = Sets + .newCopyOnWriteArraySet(); + + protected EventuallyConsistentMap vpnPortStore; + protected ApplicationId appId; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected BasePortService basePortService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected VirtualPortService virtualPortService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TenantNetworkService tenantNetworkService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected SubnetService subnetService; + + @Activate + + public void activate() { + appId = coreService.registerApplication(APP_ID); + KryoNamespace.Builder serializer = KryoNamespace.newBuilder() + .register(KryoNamespaces.API).register(VpnPort.class) + .register(VpnPortId.class); + vpnPortStore = storageService + .eventuallyConsistentMapBuilder() + .withName(VPN_PORT_STORE).withSerializer(serializer) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + log.info(EVPN_VPN_PORT_START); + } + + @Deactivate + public void deactivate() { + vpnPortStore.destroy(); + log.info(EVPN_VPN_PORT_STOP); + } + + @Override + public boolean exists(VpnPortId vpnPortId) { + checkNotNull(vpnPortId, VPN_PORT_ID_NOT_NULL); + return vpnPortStore.containsKey(vpnPortId); + } + + @Override + public VpnPort getPort(VpnPortId vpnPortId) { + checkNotNull(vpnPortId, VPN_PORT_ID_NOT_NULL); + return vpnPortStore.get(vpnPortId); + } + + @Override + public Collection getPorts() { + return Collections.unmodifiableCollection(vpnPortStore.values()); + } + + @Override + public boolean createPorts(Iterable vpnPorts) { + checkNotNull(vpnPorts, VPN_PORT_NOT_NULL); + for (VpnPort vpnPort : vpnPorts) { + log.info(VPN_PORT_ID, vpnPort.id().toString()); + vpnPortStore.put(vpnPort.id(), vpnPort); + if (!vpnPortStore.containsKey(vpnPort.id())) { + log.info(VPN_PORT_CREATION_FAILED, vpnPort.id().toString()); + return false; + } + notifyListeners(new VpnPortEvent(VpnPortEvent.Type.VPN_PORT_SET, + vpnPort)); + } + return true; + } + + @Override + public boolean updatePorts(Iterable vpnPorts) { + checkNotNull(vpnPorts, VPN_PORT_NOT_NULL); + for (VpnPort vpnPort : vpnPorts) { + if (!vpnPortStore.containsKey(vpnPort.id())) { + log.info(VPN_PORT_IS_NOT_EXIST, vpnPort.id().toString()); + return false; + } + vpnPortStore.put(vpnPort.id(), vpnPort); + if (!vpnPort.equals(vpnPortStore.get(vpnPort.id()))) { + log.info(VPN_PORT_UPDATE_FAILED, vpnPort.id().toString()); + return false; + } + notifyListeners(new VpnPortEvent(VpnPortEvent.Type.VPN_PORT_UPDATE, + vpnPort)); + } + return true; + } + + @Override + public boolean removePorts(Iterable vpnPortIds) { + checkNotNull(vpnPortIds, VPN_PORT_NOT_NULL); + for (VpnPortId vpnPortid : vpnPortIds) { + VpnPort vpnPort = vpnPortStore.get(vpnPortid); + vpnPortStore.remove(vpnPortid); + if (vpnPortStore.containsKey(vpnPortid)) { + log.info(VPN_PORT_DELETE_FAILED, vpnPortid.toString()); + return false; + } + notifyListeners(new VpnPortEvent(VpnPortEvent.Type.VPN_PORT_DELETE, + vpnPort)); + } + return true; + } + + @Override + public void processGluonConfig(String action, String key, JsonNode value) { + Collection vpnPorts; + switch (action) { + case DELETE: + String[] list = key.split(SLASH); + VpnPortId vpnPortId + = VpnPortId.vpnPortId(list[list.length - 1]); + Set vpnPortIds = Sets.newHashSet(vpnPortId); + removePorts(vpnPortIds); + // After removing vpn port and also remove virtual port from vtn + VirtualPortId virtualPortId + = VirtualPortId.portId(list[list.length - 1]); + Set virtualPortIds + = Sets.newHashSet(virtualPortId); + virtualPortService.removePorts(virtualPortIds); + break; + case SET: + checkNotNull(value, RESPONSE_NOT_NULL); + vpnPorts = changeJsonToSub(value); + createPorts(vpnPorts); + break; + case UPDATE: + checkNotNull(value, RESPONSE_NOT_NULL); + vpnPorts = changeJsonToSub(value); + updatePorts(vpnPorts); + break; + default: + log.info("Invalid action is received while processing VPN " + + "port configuration"); + } + } + + /** + * Creates dummy gluon network to the VTN. + * + * @param state the base port state + * @param adminStateUp the base port admin status + * @param tenantID the base port tenant ID + */ + private void createDummyGluonNetwork(boolean adminStateUp, String state, + TenantId tenantID) { + String id = "11111111-1111-1111-1111-111111111111"; + String name = "GluonNetwork"; + String segmentationID = "50"; + String physicalNetwork = "None"; + + TenantNetwork network = new DefaultTenantNetwork(TenantNetworkId.networkId(id), name, + adminStateUp, + TenantNetwork.State.valueOf(state), + false, tenantID, + false, + TenantNetwork.Type.LOCAL, + PhysicalNetwork.physicalNetwork(physicalNetwork), + SegmentationId.segmentationId(segmentationID)); + + Set networksSet = Sets.newHashSet(network); + tenantNetworkService.createNetworks(networksSet); + } + + + /** + * Creates dummy gluon subnet to the VTN. + * + * @param tenantId the base port tenant ID + */ + public void createDummySubnet(TenantId tenantId) { + String id = "22222222-2222-2222-2222-222222222222"; + String subnetName = "GluonSubnet"; + String cidr = "0.0.0.0/0"; + String gatewayIp = "0.0.0.0"; + Set hostRoutes = Sets.newHashSet(); + String ipV6AddressMode = null; + String ipV6RaMode = null; + TenantNetworkId tenantNetworkId = null; + Set allocationPools = Sets.newHashSet(); + Iterable networks + = tenantNetworkService.getNetworks(); + + for (TenantNetwork tenantNetwork : networks) { + if (tenantNetwork.name().equals("GluonNetwork")) { + tenantNetworkId = tenantNetwork.id(); + break; + } + } + Subnet subnet = new DefaultSubnet(SubnetId.subnetId(id), subnetName, + tenantNetworkId, + tenantId, IpAddress.Version.INET, + cidr == null ? null : IpPrefix.valueOf(cidr), + gatewayIp == null ? null : IpAddress.valueOf(gatewayIp), + false, false, hostRoutes, + ipV6AddressMode == null ? null : Subnet.Mode.valueOf(ipV6AddressMode), + ipV6RaMode == null ? null : Subnet.Mode.valueOf(ipV6RaMode), + allocationPools); + + Set subnetsSet = Sets.newHashSet(subnet); + subnetService.createSubnets(subnetsSet); + } + + /** + * Returns a collection of vpnPort from subnetNodes. + * + * @param vpnPortNodes the vpnPort json node + * @return list of vpnports + */ + private Collection changeJsonToSub(JsonNode vpnPortNodes) { + checkNotNull(vpnPortNodes, JSON_NOT_NULL); + Map vpnPortMap = new HashMap<>(); + String interfaceId = vpnPortNodes.get(INTERFACE_ID).asText(); + VpnPortId vpnPortId = VpnPortId.vpnPortId(interfaceId); + VpnInstanceId vpnInstanceId = VpnInstanceId + .vpnInstanceId(vpnPortNodes.get(VPN_INSTANCE).asText()); + VpnPort vpnPort = new DefaultVpnPort(vpnPortId, vpnInstanceId); + vpnPortMap.put(vpnPortId, vpnPort); + // update ip address and tenant network information in vtn + TenantNetworkId tenantNetworkId = null; + Map vPortMap = new HashMap<>(); + BasePortId basePortId = BasePortId.portId(interfaceId); + VirtualPortId virtualPortId = VirtualPortId.portId(interfaceId); + BasePort bPort = basePortService.getPort(basePortId); + if (bPort != null) { + FixedIp fixedIp = FixedIp.fixedIp(SubnetId.subnetId(basePortId.toString()), + IpAddress.valueOf(vpnPortNodes + .get("ipaddress").asText())); + Set fixedIps = new HashSet<>(); + fixedIps.add(fixedIp); + Map strMap = new HashMap<>(); + boolean adminStateUp = bPort.adminStateUp(); + strMap.put("name", bPort.name()); + strMap.put("deviceOwner", bPort.deviceOwner()); + strMap.put("bindingVnicType", bPort.bindingVnicType()); + strMap.put("bindingVifType", bPort.bindingVifType()); + strMap.put("bindingVifDetails", bPort.bindingVifDetails()); + String state = bPort.state(); + MacAddress macAddress = bPort.macAddress(); + TenantId tenantId = bPort.tenantId(); + DeviceId deviceId = bPort.deviceId(); + BindingHostId bindingHostId = bPort.bindingHostId(); + // Creates Dummy Gluon Network and Subnet + createDummyGluonNetwork(adminStateUp, state, tenantId); + createDummySubnet(tenantId); + + Iterable networks + = tenantNetworkService.getNetworks(); + + for (TenantNetwork tenantNetwork : networks) { + if (tenantNetwork.name().equals("GluonNetwork")) { + tenantNetworkId = tenantNetwork.id(); + break; + } + } + if (tenantNetworkId != null) { + + DefaultVirtualPort vPort = new DefaultVirtualPort(virtualPortId, + tenantNetworkId, + adminStateUp, + strMap, isState(state), + macAddress, tenantId, + deviceId, fixedIps, + bindingHostId, + null, + null); + vPortMap.put(virtualPortId, vPort); + Collection virtualPorts + = Collections.unmodifiableCollection(vPortMap.values()); + virtualPortService.createPorts(virtualPorts); + } + } + + return Collections.unmodifiableCollection(vpnPortMap.values()); + } + + /** + * Returns BasePort State. + * + * @param state the base port state + * @return the basePort state + */ + private VirtualPort.State isState(String state) { + if (state.equals("ACTIVE")) { + return VirtualPort.State.ACTIVE; + } else { + return VirtualPort.State.DOWN; + } + + } + + @Override + public void addListener(VpnPortListener listener) { + checkNotNull(listener, LISTENER_NOT_NULL); + listeners.add(listener); + } + + @Override + public void removeListener(VpnPortListener listener) { + checkNotNull(listener, LISTENER_NOT_NULL); + listeners.remove(listener); + } + + /** + * Notifies specify event to all listeners. + * + * @param event Vpn Port event + */ + private void notifyListeners(VpnPortEvent event) { + checkNotNull(event, EVENT_NOT_NULL); + listeners.forEach(listener -> { + listener.event(event); + }); + } +} diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/impl/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/impl/package-info.java new file mode 100755 index 0000000000..5dc98e9947 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN resources that used by l3vpn. + */ +package org.onosproject.evpnopenflow.rsc.vpnport.impl; diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/package-info.java new file mode 100755 index 0000000000..aadae584b6 --- /dev/null +++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnport/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * VPN resources that used by evpn. + */ +package org.onosproject.evpnopenflow.rsc.vpnport; diff --git a/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100755 index 0000000000..bb558583cc --- /dev/null +++ b/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/apps/pom.xml b/apps/pom.xml index 3351e399cb..bdefb5ee0f 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -90,6 +90,7 @@ openroadm netconf/client gluon + evpnopenflow diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java index 06ab18a264..555634ed60 100644 --- a/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java +++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java @@ -62,7 +62,6 @@ public class EvpnRoute { * @param source route source * @param prefixMac mac address * @param prefix ip address - * @param prefix * @param nextHop evpn nexthop * @param rd route distinguisher * @param importRtList import route targets @@ -104,7 +103,6 @@ public class EvpnRoute { * @param importRtList import route targets * @param exportRtList export route targets * @param labelToInt evpn route label - * @param prefix */ public EvpnRoute(Source source, MacAddress prefixMac, diff --git a/modules.defs b/modules.defs index 350fc38130..616bf2b6b0 100644 --- a/modules.defs +++ b/modules.defs @@ -209,6 +209,7 @@ ONOS_APPS = [ '//apps/openroadm:onos-apps-openroadm-oar', '//apps/artemis:onos-apps-artemis-oar', '//apps/gluon:onos-apps-gluon-oar', + '//apps/evpnopenflow:onos-apps-evpnopenflow-oar', ] PROTOCOL_APPS = [