Adding EVPN App code

Change-Id: Id3b2192f56f054cadcd8384092245b8757a781a9
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 0000000..18ff172
--- /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<VpnPortListener> listeners = Sets
+            .newCopyOnWriteArraySet();
+
+    protected EventuallyConsistentMap<VpnPortId, VpnPort> 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
+                .<VpnPortId, VpnPort>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<VpnPort> getPorts() {
+        return Collections.unmodifiableCollection(vpnPortStore.values());
+    }
+
+    @Override
+    public boolean createPorts(Iterable<VpnPort> 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<VpnPort> 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<VpnPortId> 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<VpnPort> vpnPorts;
+        switch (action) {
+            case DELETE:
+                String[] list = key.split(SLASH);
+                VpnPortId vpnPortId
+                        = VpnPortId.vpnPortId(list[list.length - 1]);
+                Set<VpnPortId> 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<VirtualPortId> 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<TenantNetwork> 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<HostRoute> hostRoutes = Sets.newHashSet();
+        String ipV6AddressMode = null;
+        String ipV6RaMode = null;
+        TenantNetworkId tenantNetworkId = null;
+        Set<AllocationPool> allocationPools = Sets.newHashSet();
+        Iterable<TenantNetwork> 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<Subnet> 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<VpnPort> changeJsonToSub(JsonNode vpnPortNodes) {
+        checkNotNull(vpnPortNodes, JSON_NOT_NULL);
+        Map<VpnPortId, VpnPort> 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<VirtualPortId, VirtualPort> 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<FixedIp> fixedIps = new HashSet<>();
+            fixedIps.add(fixedIp);
+            Map<String, String> 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<TenantNetwork> 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<VirtualPort> 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);
+        });
+    }
+}