Enable checkstyle for neutronvpn
[netvirt.git] / vpnservice / neutronvpn / neutronvpn-impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronRouterChangeListener.java
index 6afc600a97e9c4a7c522745d77c92bef88f170be..8163ae83c86b2c4f2caca55b7772e7fd0d3a0edb 100644 (file)
  */
 package org.opendaylight.netvirt.neutronvpn;
 
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
 
-public class NeutronRouterChangeListener extends AbstractDataChangeListener<Router> implements AutoCloseable {
+public class NeutronRouterChangeListener extends AsyncDataTreeChangeListenerBase<Router, NeutronRouterChangeListener>
+        implements AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterChangeListener.class);
+    private final DataBroker dataBroker;
+    private final NeutronvpnManager nvpnManager;
+    private final NeutronvpnNatManager nvpnNatManager;
+    private final NeutronSubnetGwMacResolver gwMacResolver;
 
-    private ListenerRegistration<DataChangeListener> listenerRegistration;
-    private final DataBroker broker;
-    private NeutronvpnManager nvpnManager;
-
+    public NeutronRouterChangeListener(final DataBroker dataBroker, final NeutronvpnManager neutronvpnManager,
+                                       final NeutronvpnNatManager neutronvpnNatManager,
+                                       NeutronSubnetGwMacResolver gwMacResolver) {
+        super(Router.class, NeutronRouterChangeListener.class);
+        this.dataBroker = dataBroker;
+        nvpnManager = neutronvpnManager;
+        nvpnNatManager = neutronvpnNatManager;
+        this.gwMacResolver = gwMacResolver;
+    }
 
-    public NeutronRouterChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr) {
-        super(Router.class);
-        broker = db;
-        nvpnManager = nVpnMgr;
-        registerListener(db);
+    public void start() {
+        LOG.info("{} start", getClass().getSimpleName());
+        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
     }
 
     @Override
-    public void close() throws Exception {
-        if (listenerRegistration != null) {
-            try {
-                listenerRegistration.close();
-            } catch (final Exception e) {
-                LOG.error("Error when cleaning up DataChangeListener.", e);
-            }
-            listenerRegistration = null;
-        }
-        LOG.info("N_Router listener Closed");
+    protected InstanceIdentifier<Router> getWildCardPath() {
+        return InstanceIdentifier.create(Neutron.class).child(Routers.class).child(Router.class);
     }
 
-
-    private void registerListener(final DataBroker db) {
-        try {
-            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                    InstanceIdentifier.create(Neutron.class).child(Routers.class).child(Router.class),
-                    NeutronRouterChangeListener.this, DataChangeScope.SUBTREE);
-        } catch (final Exception e) {
-            LOG.error("Neutron Manager Router DataChange listener registration fail!", e);
-            throw new IllegalStateException("Neutron Manager Router DataChange listener registration failed.", e);
-        }
+    @Override
+    protected NeutronRouterChangeListener getDataTreeChangeListener() {
+        return NeutronRouterChangeListener.this;
     }
 
+
     @Override
     protected void add(InstanceIdentifier<Router> identifier, Router input) {
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Adding Router : key: " + identifier + ", value=" + input);
-        }
+        LOG.trace("Adding Router : key: {}, value={}", identifier, input);
+        NeutronvpnUtils.addToRouterCache(input);
         // Create internal VPN
-        nvpnManager.createL3Vpn(input.getUuid(), null, null, null, null, null, input.getUuid(), null);
+        nvpnManager.createL3InternalVpn(input.getUuid(), null, null, null, null, null, input.getUuid(), null);
+        nvpnNatManager.handleExternalNetworkForRouter(null, input);
+        gwMacResolver.sendArpRequestsToExtGateways(input);
     }
 
     @Override
     protected void remove(InstanceIdentifier<Router> identifier, Router input) {
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Removing router : key: " + identifier + ", value=" + input);
-        }
+        LOG.trace("Removing router : key: {}, value={}", identifier, input);
         Uuid routerId = input.getUuid();
-        // fetch subnets associated to router
-        List<Interfaces> routerInterfaces = input.getInterfaces();
-        List<Uuid> routerSubnetIds = new ArrayList<Uuid>();
-        if (routerInterfaces != null) {
-            for (Interfaces rtrIf : routerInterfaces) {
-                routerSubnetIds.add(rtrIf.getSubnetId());
-            }
-        }
+        //NOTE: Pass an empty routerSubnetIds list, as router interfaces
+        //will be removed from VPN by invocations from NeutronPortChangeListener
+        List<Uuid> routerSubnetIds = new ArrayList<>();
         nvpnManager.handleNeutronRouterDeleted(routerId, routerSubnetIds);
+
+        // Handle router deletion for the NAT service
+        if (input.getExternalGatewayInfo() != null) {
+            Uuid extNetId = input.getExternalGatewayInfo().getExternalNetworkId();
+            nvpnNatManager.removeExternalNetworkFromRouter(extNetId, input);
+        }
+        NeutronvpnUtils.removeFromRouterCache(input);
     }
 
     @Override
     protected void update(InstanceIdentifier<Router> identifier, Router original, Router update) {
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Updating Router : key: " + identifier + ", original value=" + original + ", update value=" +
-                    update);
-        }
+        LOG.trace("Updating Router : key: {}, original value={}, update value={}", identifier, original, update);
+        NeutronvpnUtils.addToRouterCache(update);
         Uuid routerId = update.getUuid();
-        Uuid vpnId = NeutronvpnUtils.getVpnForRouter(broker, routerId, true);
+        NeutronvpnUtils.addToRouterCache(update);
+        Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
         // internal vpn always present in case external vpn not found
         if (vpnId == null) {
             vpnId = routerId;
         }
-        List<Interfaces> oldInterfaces = (original.getInterfaces() != null) ? original.getInterfaces() : new
-                ArrayList<Interfaces>();
-        List<Interfaces> newInterfaces = (update.getInterfaces() != null) ? update.getInterfaces() : new
-                ArrayList<Interfaces>();
         List<Routes> oldRoutes = (original.getRoutes() != null) ? original.getRoutes() : new ArrayList<Routes>();
         List<Routes> newRoutes = (update.getRoutes() != null) ? update.getRoutes() : new ArrayList<Routes>();
-        if (!oldInterfaces.equals(newInterfaces)) {
-            for (Interfaces intrf : newInterfaces) {
-                if (!oldInterfaces.remove(intrf)) {
-                    // add new subnet
-                    nvpnManager.addSubnetToVpn(vpnId, intrf.getSubnetId());
-                }
-            }
-            //clear remaining old subnets
-            for (Interfaces intrf : oldInterfaces) {
-                nvpnManager.removeSubnetFromVpn(vpnId, intrf.getSubnetId());
-            }
-        }
         if (!oldRoutes.equals(newRoutes)) {
             Iterator<Routes> iterator = newRoutes.iterator();
             while (iterator.hasNext()) {
@@ -131,10 +109,49 @@ public class NeutronRouterChangeListener extends AbstractDataChangeListener<Rout
                     iterator.remove();
                 }
             }
-            nvpnManager.addAdjacencyforExtraRoute(newRoutes, true, null);
+
+            handleChangedRoutes(vpnId, newRoutes, NwConstants.ADD_FLOW);
+
             if (!oldRoutes.isEmpty()) {
-                nvpnManager.removeAdjacencyforExtraRoute(oldRoutes);
+                handleChangedRoutes(vpnId, oldRoutes, NwConstants.DEL_FLOW);
             }
         }
+
+        nvpnNatManager.handleExternalNetworkForRouter(original, update);
+        gwMacResolver.sendArpRequestsToExtGateways(update);
+    }
+
+    private void handleChangedRoutes(Uuid vpnName, List<Routes> routes, int addedOrRemoved) {
+        // Some routes may point to an InterVpnLink's endpoint, lets treat them differently
+        List<Routes> interVpnLinkRoutes = new ArrayList<Routes>();
+        List<Routes> otherRoutes = new ArrayList<Routes>();
+        HashMap<String, InterVpnLink> nexthopsXinterVpnLinks = new HashMap<String, InterVpnLink>();
+        for ( Routes route : routes ) {
+            String nextHop = String.valueOf(route.getNexthop().getValue());
+            // Nexthop is another VPN?
+            Optional<InterVpnLink> interVpnLink = NeutronvpnUtils.getInterVpnLinkByEndpointIp(dataBroker, nextHop);
+            if ( interVpnLink.isPresent() ) {
+                Optional<InterVpnLinkState> interVpnLinkState =
+                        NeutronvpnUtils.getInterVpnLinkState(dataBroker, interVpnLink.get().getName());
+                if ( interVpnLinkState.isPresent()
+                    && interVpnLinkState.get().getState() == InterVpnLinkState.State.Active) {
+                    interVpnLinkRoutes.add(route);
+                    nexthopsXinterVpnLinks.put(nextHop, interVpnLink.get());
+                } else {
+                    LOG.warn("Failed installing route to {}. Reason: InterVPNLink {} is not Active",
+                            String.valueOf(route.getDestination().getValue()), interVpnLink.get().getName());
+                }
+            } else {
+                otherRoutes.add(route);
+            }
+        }
+
+        if ( addedOrRemoved == NwConstants.ADD_FLOW ) {
+            nvpnManager.addInterVpnRoutes(vpnName, interVpnLinkRoutes, nexthopsXinterVpnLinks);
+            nvpnManager.updateVpnInterfaceWithExtraRouteAdjacency(vpnName, otherRoutes);
+        } else {
+            nvpnManager.removeAdjacencyforExtraRoute(vpnName, otherRoutes);
+            nvpnManager.removeInterVpnRoutes(vpnName, interVpnLinkRoutes, nexthopsXinterVpnLinks);
+        }
     }
 }